Class KF2GUIController extends Info transient; var() class DefaultStyle; var PlayerController PlayerOwner; var transient KF2GUIInput CustomInput; var transient PlayerInput BackupInput; var transient GameViewportClient ClientViewport; var array ActiveMenus,PersistentMenus; var transient KFGUI_Base MouseFocus,InputFocus,KeyboardFocus; var IntPoint MousePosition,ScreenSize,OldMousePos,LastClickPos[2]; var transient float MousePauseTime,MenuTime,LastClickTimes[2]; var transient GUIStyleBase CurrentStyle; var transient Console OrgConsole; var transient KFGUIConsoleHack HackConsole; var bool bMouseWasIdle,bIsInMenuState,bAbsorbInput,bIsInvalid; static function KF2GUIController GetGUIController(PlayerController PC) { local KF2GUIController G; if(PC.Player==None) return None; foreach PC.ChildActors(class'KF2GUIController',G) if(!G.bIsInvalid) break; if(G==None) G = PC.Spawn(class'KF2GUIController',PC); return G; } simulated function PostBeginPlay() { PlayerOwner = PlayerController(Owner); ClientViewport = LocalPlayer(PlayerOwner.Player).ViewportClient; CurrentStyle = new (None) DefaultStyle; CurrentStyle.InitStyle(); } simulated function Destroyed() { if(PlayerOwner!=None) SetMenuState(false); } simulated function HandleDrawMenu() { if(HackConsole==None) { HackConsole = new(ClientViewport)class'KFGUIConsoleHack'; HackConsole.OutputObject = Self; } if(HackConsole!=ClientViewport.ViewportConsole) { OrgConsole = ClientViewport.ViewportConsole; ClientViewport.ViewportConsole = HackConsole; // Make sure nothing overrides these settings while menu is being open. PlayerOwner.PlayerInput = CustomInput; if(!ClientViewport.bDisplayHardwareMouseCursor) { ClientViewport.bDisplayHardwareMouseCursor = true; ClientViewport.ForceUpdateMouseCursor(TRUE); } } } simulated function RenderMenu(Canvas C) { local int i; local float OrgX,OrgY,ClipX,ClipY; local vector2D V; ClientViewport.ViewportConsole = OrgConsole; ScreenSize.X = C.SizeX; ScreenSize.Y = C.SizeY; CurrentStyle.Canvas = C; CurrentStyle.PickDefaultFontSize(C.SizeY); V = ClientViewport.GetMousePosition(); MouseMove(V.X,V.Y); OrgX = C.OrgX; OrgY = C.OrgY; ClipX = C.ClipX; ClipY = C.ClipY; for(i=(ActiveMenus.Length-1); i>=0; --i) { ActiveMenus[i].bWindowFocused = (i==0); ActiveMenus[i].InputPos[0] = 0.f; ActiveMenus[i].InputPos[1] = 0.f; ActiveMenus[i].InputPos[2] = ScreenSize.X; ActiveMenus[i].InputPos[3] = ScreenSize.Y; ActiveMenus[i].Canvas = C; ActiveMenus[i].PreDraw(); } if(InputFocus!=None && InputFocus.bFocusedPostDrawItem) { InputFocus.InputPos[0] = 0.f; InputFocus.InputPos[1] = 0.f; InputFocus.InputPos[2] = ScreenSize.X; InputFocus.InputPos[3] = ScreenSize.Y; InputFocus.Canvas = C; InputFocus.PreDraw(); } C.SetOrigin(OrgX,OrgY); C.SetClip(ClipX,ClipY); if(OrgConsole!=None) OrgConsole.PostRender_Console(C); OrgConsole = None; } simulated final function SetMenuState(bool bActive) { if(PlayerOwner.PlayerInput==None) { NotifyLevelChange(); bActive = false; } if(bIsInMenuState==bActive) return; bIsInMenuState = bActive; if(bActive) { if(CustomInput==None) { CustomInput = new (KFPlayerController(PlayerOwner)) class'KF2GUIInput'; CustomInput.ControllerOwner = Self; CustomInput.OnReceivedNativeInputKey = ReceivedInputKey; CustomInput.BaseInput = PlayerOwner.PlayerInput; BackupInput = PlayerOwner.PlayerInput; PlayerOwner.Interactions.AddItem(CustomInput); } BackupInput.OnReceivedNativeInputKey = ReceivedInputKey; BackupInput.OnReceivedNativeInputChar = ReceivedInputChar; PlayerOwner.PlayerInput = CustomInput; ClientViewport.SetHardwareMouseCursorVisibility(true); } else { if(BackupInput!=None) { PlayerOwner.PlayerInput = BackupInput; BackupInput.OnReceivedNativeInputKey = BackupInput.OnReceivedNativeInputKey; BackupInput.OnReceivedNativeInputChar = BackupInput.OnReceivedNativeInputChar; } ClientViewport.SetHardwareMouseCursorVisibility(false); LastClickTimes[0] = 0; LastClickTimes[1] = 0; } } simulated function NotifyLevelChange() { local int i; if(bIsInvalid) return; bIsInvalid = true; if(InputFocus!=None) { InputFocus.LostInputFocus(); InputFocus = None; } for(i=(ActiveMenus.Length-1); i>=0; --i) ActiveMenus[i].NotifyLevelChange(); for(i=(PersistentMenus.Length-1); i>=0; --i) PersistentMenus[i].NotifyLevelChange(); SetMenuState(false); } simulated function MenuInput(float DeltaTime) { local int i; if(PlayerOwner.PlayerInput==None) { NotifyLevelChange(); return; } if(InputFocus!=None) InputFocus.MenuTick(DeltaTime); for(i=0; i5.f || Abs(MousePosition.Y-OldMousePos.Y)>5.f || (bMouseWasIdle && MousePauseTime<0.5f)) { if(bMouseWasIdle) { bMouseWasIdle = false; if(InputFocus!=None) InputFocus.InputMouseMoved(); } OldMousePos = MousePosition; MousePauseTime = 0.f; } else if(!bMouseWasIdle && (MousePauseTime+=DeltaTime)>0.5f) { bMouseWasIdle = true; if(MouseFocus!=None) MouseFocus.NotifyMousePaused(); } if(ActiveMenus.Length>0) MenuTime+=DeltaTime; } simulated function MouseMove(float MouseX, float MouseY) { local int i; local KFGUI_Base F; // Handle mouse MousePosition.X = Clamp(MouseX, 0, ScreenSize.X); MousePosition.Y = Clamp(MouseY, 0, ScreenSize.Y); // Capture mouse for GUI if(InputFocus!=None && InputFocus.bCanFocus) { if(InputFocus.CaptureMouse()) { F = InputFocus.GetMouseFocus(); if(F!=MouseFocus) { MousePauseTime = 0; if(MouseFocus!=None) MouseFocus.MouseLeave(); MouseFocus = F; F.MouseEnter(); } } else i = ActiveMenus.Length; } else { for(i=0; i MenuClass) { local int i; local KFGUI_Page M; if(MenuClass==None) return None; if(KeyboardFocus!=None) GrabInputFocus(None); if(InputFocus!=None) { InputFocus.LostInputFocus(); InputFocus = None; } // Enable mouse on UI if disabled. SetMenuState(true); // Check if should use pre-excisting menu. if(MenuClass.Default.bUnique) { for(i=0; i0 && ActiveMenus[i].BringPageToFront()) // Sort it upfront. { M = ActiveMenus[i]; ActiveMenus.Remove(i,1); i = GetFreeIndex(M.bAlwaysTop); ActiveMenus[i] = M; } return M; } if(MenuClass.Default.bPersistant) { for(i=0; i MenuClass, optional bool bCloseAll) { local int i; local KFGUI_Page M; if(!bCloseAll && MenuClass==None) return; if(KeyboardFocus!=None) GrabInputFocus(None); if(InputFocus!=None) { InputFocus.LostInputFocus(); InputFocus = None; } for(i=(ActiveMenus.Length-1); i>=0; --i) if(bCloseAll || ActiveMenus[i].Class==MenuClass) { M = ActiveMenus[i]; ActiveMenus.Remove(i,1); M.CloseMenu(); // Cache menu. if(M.bPersistant && M.bUnique) PersistentMenus[PersistentMenus.Length] = M; } if(ActiveMenus.Length==0) SetMenuState(false); } simulated function PopCloseMenu(KFGUI_Base Item) { local int i; local KFGUI_Page M; if(Item==None) return; if(KeyboardFocus!=None) GrabInputFocus(None); if(InputFocus!=None) { InputFocus.LostInputFocus(); InputFocus = None; } for(i=(ActiveMenus.Length-1); i>=0; --i) if(ActiveMenus[i]==Item) { M = ActiveMenus[i]; ActiveMenus.Remove(i,1); M.CloseMenu(); // Cache menu. if(M.bPersistant && M.bUnique) PersistentMenus[PersistentMenus.Length] = M; break; } if(ActiveMenus.Length==0) SetMenuState(false); } simulated function BringMenuToFront(KFGUI_Page Page) { local int i; if(ActiveMenus[0].bAlwaysTop && !Page.bAlwaysTop) return; // Can't override this menu. // Try to remove from current position at stack. for(i=(ActiveMenus.Length-1); i>=0; --i) if(ActiveMenus[i]==Page) { ActiveMenus.Remove(i,1); break; } if(i==-1) return; // Page isn't open. // Put on front of stack. ActiveMenus.Insert(0,1); ActiveMenus[0] = Page; } simulated final function bool MenuIsOpen(optional class MenuClass) { local int i; for(i=(ActiveMenus.Length-1); i>=0; --i) if(MenuClass==None || ActiveMenus[i].Class==MenuClass) return true; return false; } simulated final function GrabInputFocus(KFGUI_Base Comp, optional bool bForce) { if(Comp==KeyboardFocus && !bForce) return; if(KeyboardFocus!=None) KeyboardFocus.LostKeyFocus(); if(Comp==None) { OnInputKey = InternalInputKey; OnReceivedInputChar = InternalReceivedInputChar; } else if(KeyboardFocus==None) { OnInputKey = Comp.NotifyInputKey; OnReceivedInputChar = Comp.NotifyInputChar; } KeyboardFocus = Comp; } simulated final function GUI_InputMouse(bool bPressed, bool bRight) { local byte i; MousePauseTime = 0; if(bPressed) { if(KeyboardFocus!=None && KeyboardFocus!=MouseFocus) { GrabInputFocus(None); LastClickTimes[0] = 0; LastClickTimes[1] = 0; } if(MouseFocus!=None) { if(MouseFocus!=InputFocus && !MouseFocus.bClickable && !MouseFocus.IsTopMenu() && MouseFocus.BringPageToFront()) { BringMenuToFront(MouseFocus.GetPageTop()); LastClickTimes[0] = 0; LastClickTimes[1] = 0; } else { i = byte(bRight); if((MenuTime-LastClickTimes[i])<0.2 && Abs(LastClickPos[i].X-MousePosition.X)<5 && Abs(LastClickPos[i].Y-MousePosition.Y)<5) { LastClickTimes[i] = 0; MouseFocus.DoubleMouseClick(bRight); } else { MouseFocus.MouseClick(bRight); LastClickTimes[i] = MenuTime; LastClickPos[i] = MousePosition; } } } else if(InputFocus!=None) { InputFocus.LostInputFocus(); InputFocus = None; LastClickTimes[0] = 0; LastClickTimes[1] = 0; } } else { if(InputFocus!=None) InputFocus.MouseRelease(bRight); else if(MouseFocus!=None) MouseFocus.MouseRelease(bRight); } } simulated final function bool CheckMouse(name Key, EInputEvent Event) { if (Event == IE_Pressed) { switch(Key) { case 'LeftMouseButton': GUI_InputMouse(true,false); return true; case 'RightMouseButton': GUI_InputMouse(true,true); return true; } } else if (Event == IE_Released) { switch(Key) { case 'LeftMouseButton': GUI_InputMouse(false,false); return true; case 'RightMouseButton': GUI_InputMouse(false,true); return true; } } return false; } simulated function bool ReceivedInputKey(int ControllerId, name Key, EInputEvent Event, optional float AmountDepressed=1.f, optional bool bGamepad) { if(!bIsInMenuState) return false; if(!CheckMouse(Key,Event) && !OnInputKey(ControllerId,Key,Event,AmountDepressed,bGamepad)) { switch(Key) { case 'Escape': if(Event==IE_Pressed) ActiveMenus[0].UserPressedEsc(); // Pop top menu if possible. return true; case 'MouseScrollDown': case 'MouseScrollUp': if(Event==IE_Pressed && MouseFocus!=None) MouseFocus.ScrollMouseWheel(Key=='MouseScrollUp'); return true; } return bAbsorbInput; } return true; } simulated function bool ReceivedInputChar(int ControllerId, string Unicode) { if(!bIsInMenuState) return false; return OnReceivedInputChar(ControllerId,Unicode); } simulated Delegate bool OnInputKey(int ControllerId, name Key, EInputEvent Event, optional float AmountDepressed=1.f, optional bool bGamepad) { return false; } simulated Delegate bool OnReceivedInputChar(int ControllerId, string Unicode) { return false; } simulated Delegate bool InternalInputKey(int ControllerId, name Key, EInputEvent Event, optional float AmountDepressed=1.f, optional bool bGamepad) { return false; } simulated Delegate bool InternalReceivedInputChar(int ControllerId, string Unicode) { return false; } defaultproperties { DefaultStyle=class'KF2Style' bAbsorbInput=true }