610 lines
13 KiB
Ucode
610 lines
13 KiB
Ucode
Class KF2GUIController extends Info
|
|
transient;
|
|
|
|
var() class<GUIStyleBase> DefaultStyle;
|
|
|
|
var PlayerController PlayerOwner;
|
|
var transient KF2GUIInput CustomInput;
|
|
var transient PlayerInput BackupInput;
|
|
var transient GameViewportClient ClientViewport;
|
|
|
|
var array<KFGUI_Page> 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; i<ActiveMenus.Length; ++i)
|
|
ActiveMenus[i].MenuTick(DeltaTime);
|
|
|
|
// Check idle.
|
|
if (Abs(MousePosition.X-OldMousePos.X)>5.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<ActiveMenus.Length; ++i)
|
|
{
|
|
if (ActiveMenus[i].CaptureMouse())
|
|
{
|
|
F = ActiveMenus[i].GetMouseFocus();
|
|
if (F!=MouseFocus)
|
|
{
|
|
MousePauseTime = 0;
|
|
if (MouseFocus!=None)
|
|
MouseFocus.MouseLeave();
|
|
MouseFocus = F;
|
|
F.MouseEnter();
|
|
}
|
|
break;
|
|
}
|
|
else if (ActiveMenus[i].bOnlyThisFocus) // Discard any other menus after this one.
|
|
{
|
|
i = ActiveMenus.Length;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (MouseFocus!=None && i==ActiveMenus.Length) // Hovering over nothing.
|
|
{
|
|
MousePauseTime = 0;
|
|
if (MouseFocus!=None)
|
|
MouseFocus.MouseLeave();
|
|
MouseFocus = None;
|
|
}
|
|
}
|
|
|
|
simulated final function int GetFreeIndex(bool bNewAlwaysTop) // Find first allowed top index of the stack.
|
|
{
|
|
local int i;
|
|
|
|
for (i=0; i<ActiveMenus.Length; ++i)
|
|
if (bNewAlwaysTop || !ActiveMenus[i].bAlwaysTop)
|
|
{
|
|
ActiveMenus.Insert(i,1);
|
|
return i;
|
|
}
|
|
i = ActiveMenus.Length;
|
|
ActiveMenus.Length = i+1;
|
|
return i;
|
|
}
|
|
|
|
simulated function KFGUI_Page OpenMenu(class<KFGUI_Page> 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; i<ActiveMenus.Length; ++i)
|
|
if (ActiveMenus[i].Class==MenuClass)
|
|
{
|
|
if (i>0 && 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<PersistentMenus.Length; ++i)
|
|
if (PersistentMenus[i].Class==MenuClass)
|
|
{
|
|
M = PersistentMenus[i];
|
|
PersistentMenus.Remove(i,1);
|
|
i = GetFreeIndex(M.bAlwaysTop);
|
|
ActiveMenus[i] = M;
|
|
M.ShowMenu();
|
|
return M;
|
|
}
|
|
}
|
|
}
|
|
M = New(None)MenuClass;
|
|
|
|
if (M==None) // Probably abstract class.
|
|
return None;
|
|
|
|
i = GetFreeIndex(M.bAlwaysTop);
|
|
ActiveMenus[i] = M;
|
|
M.Owner = Self;
|
|
M.InitMenu();
|
|
M.ShowMenu();
|
|
return M;
|
|
}
|
|
|
|
simulated function CloseMenu(class<KFGUI_Page> 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<KFGUI_Page> 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
|
|
}
|