// ==================================================================== // Class: Engine.GUIController // // The GUIController is a simple FILO menu stack. You have 3 things // you can do. You can Open a menu which adds the menu to the top of the // stack. You can Replace a menu which replaces the current menu with the // new menu. And you can close a menu, which returns you to the last menu // on the stack. // // Written by Joe Wilcox // (c) 2002, Epic Games, Inc. All Rights Reserved // ==================================================================== class GUIController extends BaseGUIController DependsOn(GUI) Config(User) Abstract Native; // if _RO_ // else //#exec OBJ LOAD FILE=InterfaceContent.utx // end if _RO_ cpptext { void GetCursorPos( INT& ptX, INT& ptY ); void NativeMessage(const FString Msg, FLOAT MsgLife); UBOOL NativeKeyType(BYTE& iKey, TCHAR Unicode ); UBOOL NativeKeyEvent(BYTE& iKey, BYTE& State, FLOAT Delta ); void NativeTick(FLOAT DeltaTime); void NativePreRender(UCanvas* Canvas); void NativePostRender(UCanvas* Canvas); void ResolutionChanged( INT NewX, INT NewY ); void ResetInput(); UBOOL DesignKeyEvent( BYTE iKey, BYTE State, FLOAT Delta ); void RenderDesignMode( UCanvas* Canvas ); virtual void LookUnderCursor(FLOAT dX, FLOAT dY); UGUIComponent* UnderCursor(FLOAT MouseX, FLOAT MouseY); UBOOL virtual MousePressed(UBOOL IsRepeat); UBOOL virtual MouseReleased(); UBOOL HasMouseMoved( FLOAT ErrorMargin = 0.f ); void PlayInterfaceSound(USound* sound); void PlayComponentSound(BYTE SoundNum); void Profile(FString& ProfileName); void Destroy(); // Design mode void CreatePropertyWindow(); void HidePropertyWindow(); void SetMoveControl( UGUIComponent* C ); UBOOL DesignerVisible(); UBOOL ShowProperties( UGUIComponent* Comp ); void ResetDesigner(); } const DoCounter = 1; var const int FONT_NUM; var const int STYLE_NUM; var const int CURSOR_NUM; struct native ProfileStruct { var string ProfileName; var float ProfileSeconds; }; struct native eOwnageMap { var int RLevel; var string MapName; var string MapDesc; var string MapURL; }; var array Profilers; var const floatbox MouseCursorBounds; var editinline Array MouseCursorOffset; // Only X,Y used, between 0 and 1. 'Hot Spot' of cursor material. var editinline export protected array MenuStack; // Holds the stack of menus var protected Array PersistentStack; // Holds the set of pages which are persistent across close/open var editinline protected Array FontStack; // Holds all the possible fonts var protected Array StyleStack; // Holds all of the possible styles var editinline protected Array MouseCursors; // Holds a list of all possible mouse var array ImageList; // List of various images struct native AutoLoadMenu { var string MenuClassName; var bool bPreInitialize; }; struct native init RestoreMenuItem { var() string MenuClassName; var() string Param1, Param2; }; var Array DefaultStyleNames; // Holds the name of all styles to use var Array StyleNames; // Holds the name of all styles to use var config array AutoLoad; // Any menu classes in here will be automatically loaded var array RestoreMenus; struct native DesignModeHint { var() localized string Key, Description; }; var array DesignModeHints; // List of commands for design mode var config float MenuMouseSens; var float MouseX,MouseY; // Where is the mouse currently located var float LastMouseX, LastMouseY; var float DblClickWindow; // How long do you have for a double click var float LastClickTime; // When did the last click occur var float ButtonRepeatDelay; // The amount of delay for faking button repeats var float RepeatDelta; // Data var var float RepeatTime; // How long until the next repeat; var float CursorFade; // How visible is the cursor var float FastCursorFade; // How visible is the cursor var globalconfig int MaxSimultaneousPings; // Upper limit to number of open connections (for server pinging only - not does include game channels) //ifdef _KF_ var globalconfig int MaxPingsPerSecond; //endif _KF_ var int FastCursorStep; // Are we fading in or out var const int ResX, ResY; // Current resolution var int LastClickX, LastClickY; // Who was the active component var int CursorStep; // Are we fading in or out var const private pointer Designer; // GUI design editor window reference // Sounds var sound MouseOverSound; var sound ClickSound; var sound EditSound; var sound UpSound; var sound DownSound; var sound DragSound; var sound FadeSound; var GUIPage ActivePage; // Points to the currently active page var GUIComponent FocusedControl; // Top most Focused control var GUIComponent ActiveControl; // Which control is currently active var deprecated GUIComponent SkipControl; // This control should be skipped over and drawn at the end var GUIComponent MoveControl; // Used for visual design // Drag - n - Drop support var GUIComponent DropSource; // Source component for a drag-n-drop operation currently in progress var GUIComponent DropTarget; // Target component for a drag-n-drop operation currently in progress var GUIContextMenu ContextMenu; // Used for Right Click menus var GUIToolTip MouseOver; var Material WhiteBorder; var string GameResolution; var transient string LastGameType; // Used for some places where we need to know the last gametype selected // Menu types var config string RequestDataMenu; // Menu for single item data entry var config string ArrayPropertyMenu; // Menu for editing static array playinfo properties var config string DynArrayPropertyMenu; // Menu for editing dynamic array playinfo properties // ifdef _KF_ var string FilterMenu; // Menu for configuring server browser filters // else //var config string FilterMenu; // Menu for configuring server browser filters // endif _KF_ var config string MapVotingMenu; // Menu that appears for map voting var config string KickVotingMenu; var config string MatchSetupMenu; var config string EditFavoriteMenu; var array MainMenuOptions; // Menu classes that will be displayed on the main menu var globalconfig string DesignerMenu; // Menu for in-game GUI designer var byte RepeatKey; // Used to determine what should repeat var bool bIgnoreNextRelease; // Used to make sure discard errant releases. var bool ShiftPressed; // Shift key is being held var bool AltPressed; // Alt key is being held var bool CtrlPressed; // Ctrl key is being held var bool bModulateStackedMenus; // If true, all menus except the topmost will be greyed var globalconfig bool bQuietMenu; var globalconfig bool bNoToolTips; // Do not display mouse-over tool-tips var globalconfig bool bDesignModeToolTips; // Whether tooltips are displayed while in design mode var globalconfig bool bAutoRefreshBrowser; // Auto refresh server browser when returning from the game or another menu var globalconfig bool bModAuthor; // Allows bDesign Mode var globalconfig bool bExpertMode; // Display all advanced settings var globalconfig bool bDesignMode; // Are we in design mode; var bool bInteractiveMode; // All input goes to design mode var globalconfig bool bHighlightCurrent; // Highlight the current control being edited var globalconfig bool bDrawFullPaths; // Display full menu paths in design mode var bool MainNotWanted; // Prevents main menu from being opened when last menu is closed and isn't bAllowedAsLast var bool bCurMenuInitialized; // Has the current Menu Finished initialization var bool bForceMouseCheck; // HACK var bool bIgnoreUntilPress; // HACK //??? var bool bSnapCursor; // Snap cursor to first component when page is opened var float RenderDelta, LastRenderTime; // Used for timing var config bool bFixedMouseSize; // Keep the mouse from scaling var const byte KeyDown[255]; // Bit mask of keys currently held down var array > RegisteredClasses; var bool bECEEdition; // Set to true if this is the ECE edition // G15 Support var texture LCDLogo; var font LCDTinyFont; var font LCDSmallFont; var font LCDMedFont; var font LCDLargeFont; // end G15 support delegate bool OnNeedRawKeyPress(byte NewKey); delegate AddBuddy( optional string NewBuddyName ); // ===================================================================================================================== // ===================================================================================================================== // Utility functions for the UI // ===================================================================================================================== // ===================================================================================================================== native event GUIFont GetMenuFont(string FontName); // Finds a given font in the FontStack native event GUIStyles GetStyle(string StyleName, out GUI.eFontScale FontScale); // Find a style on the stack native final function string GetCurrentRes(); // Returns the current res as a string // Attempts to set the render device to the class specified by NewRenderDevice - returns whether change was successful native final function bool SetRenderDevice( string NewRenderDevice ); native private final function ResetDesigner(); native final function ResetInput(); native final function GetProfileList(string Prefix, out array ProfileList); native final function ResetKeyboard(); native final function GetOGGList(out array OGGFiles); native final function PlayInterfaceSound( GUIComponent.EClickSound SoundType ); native final function SetMoveControl( GUIComponent C ); native function Profile(string ProfileName); // Used by a demo manager native function GetDEMList(out array DEMFiles); native function bool GetDEMHeader(string DemoName, out string MapName, out string GameType, out int ScoreLimit, out int TimeLimit, out int ClientSide, out string RecordedBy, out string Timestamp, out String ReqPackages); // Used by Ownage Maps native function GetOwnageList(out array RLevel, out array MNames, out array MDesc, out array mURL); native function SaveOwnageList(array Maps); // deprecated -- Use CacheManager/xUtil instead native final function GetWeaponList(out array > WeaponClass, out array WeaponDesc); native final function GetMapList( string Prefix, GUIList list, optional bool bDecoText ); // URL stuff native function LaunchURL(string URL); // Firewall stuff native function bool CheckFirewall(); native function bool AuthroizeFirewall(); native function bool CheckForECE(); //@ G15 Support // LCD Functions native function bool bLCDAvailable(); native function LCDDrawTile(Texture Tex, int X, int Y, int XL, int YL, int U, int V, int UL, int VL); native function LCDDrawText(string Text, int X, int Y, Font Font); native function LCDStrLen(string Text, Font Font, out int XL, out int YL); native function LCDCls(); native function LCDRepaint(); native function bool CheckSteam(); // Steam interface functions // _RO native function bool SteamRefreshLogin(string Password); native function string SteamGetUserName(); native function string SteamGetUserID(); simulated event ResolutionChanged(){} // end _RO_ function string LoadDecoText(string PackageName, string DecoTextName) { local int i; local DecoText Deco; local string DecoText; if (InStr(DecoTextName, ".") != -1) { if (PackageName == "") Divide(DecoTextName, ".", PackageName, DecoTextName); else DecoTextName = Mid(DecoTextName, InStr(DecoTextName, ".") + 1); } Deco = class'xUtil'.static.LoadDecoText(PackageName, DecoTextName); if (Deco == None) return ""; for (i = 0; i < Deco.Rows.Length; i++) { if (DecoText != "") DecoText $= "|"; DecoText $= Deco.Rows[i]; } return DecoText; } final function GetTeamSymbolList(out array SymbolNames, optional bool bNoSinglePlayer) { // Moved to CacheManager so GameInfo can access this class'CacheManager'.static.GetTeamSymbolList(SymbolNames, bNoSinglePlayer); } // -- deprecated function GUIPage TopPage() { return ActivePage; } // ===================================================================================================================== // ===================================================================================================================== // Initialization // ===================================================================================================================== // ===================================================================================================================== event InitializeController() { local int i; local class NewStyleClass; LCDDrawTile(LCDLogo,0,0,64,43,0,0,64,43); LCDDrawText("Loading...",55,10,LCDMedFont); LCDDrawText("Killing Floor",55,26,LCDMedFont); LCDRePaint(); PrecachePlayerRecords(); for (i=0;i(DynamicLoadObject(DefaultStyleNames[i],class'class')); if (NewStyleClass != None) if (!RegisterStyle(NewStyleClass)) log("Could not create requested style"@DefaultStyleNames[i]); } for (i=0;i(DynamicLoadObject(StyleNames[i],class'class')); if (NewStyleClass != None) if (!RegisterStyle(NewStyleClass)) log("Could not create requested style"@StyleNames[i]); } for (i=0;i StyleClass, optional bool bTemporary) { local GUIStyles NewStyle; local int i,index; Index = -1; if (StyleClass != None) { for (i = 0; i < StyleStack.Length; i++) { if (StyleStack[i].Class == StyleClass) { log("Style already registered '"$StyleClass$"'"); return true; } if (StyleStack[i].KeyName == StyleClass.Default.KeyName) Index = i; } NewStyle = new(None) StyleClass; if (NewStyle != None) { // Dynamic Array Auto Sizes StyleStack. if (Index<0) { // if ( bModAuthor ) // log("Registering Style"@NewStyle,'ModAuthor'); StyleStack[StyleStack.Length] = NewStyle; } else { if ( bModAuthor ) log("Replacing Style"@StyleStack[Index].KeyName@"with"@NewStyle,'ModAuthor'); StyleStack[Index].Controller = none; StyleStack[Index] = NewStyle; } NewStyle.Controller = self; NewStyle.Initialize(); NewStyle.bTemporary = bTemporary; return true; } } return false; } //event class AddComponentClass(string ClassName) { return None; } event class AddComponentClass(string ClassName) { local int i; local class Cls; for ( i = 0; i < RegisteredClasses.Length; i++ ) if ( string(RegisteredClasses[i]) ~= ClassName ) return RegisteredClasses[i]; Cls = class(DynamicLoadObject(ClassName,class'Class')); if ( Cls != None ) RegisteredClasses[RegisteredClasses.Length] = Cls; return Cls; } // ===================================================================================================================== // ===================================================================================================================== // Menu manipulation // ===================================================================================================================== // ===================================================================================================================== event GUIPage FindPersistentMenuByName( string MenuClass ) { local int i; if ( MenuClass == "" ) return None; for ( i = 0; i < PersistentStack.Length; i++ ) if ( MenuClass ~= string(PersistentStack[i].Class) ) return PersistentStack[i]; return None; } event int FindMenuIndexByName( string MenuClass ) { local int i; if ( MenuClass == "" ) return -1; for ( i = 0; i < MenuStack.Length; i++ ) if ( MenuClass ~= string(MenuStack[i].Class) ) return i; return -1; } event int FindMenuIndex( GUIPage Menu ) { local int i; if ( Menu == None ) return -1; for ( i = 0; i < MenuStack.Length; i++ ) if ( MenuStack[i] == Menu ) return i; return -1; } event int FindPersistentMenuIndex( GUIPage Menu ) { local int i; if ( Menu == None ) return -1; for ( i = 0; i < PersistentStack.Length; i++ ) if ( Menu == PersistentStack[i] ) return i; return -1; } function GUIPage FindPersistentMenuByClass( class PageClass ) { local int i; if ( PageClass == None ) return None; for ( i = 0; i < PersistentStack.Length; i++ ) if ( ClassIsChildOf(PersistentStack[i].Class, PageClass) ) return PersistentStack[i]; return None; } function GUIPage FindMenuByClass( class PageClass ) { local int i; if ( PageClass == None ) return None; for ( i = 0; i < MenuStack.Length; i++ ) if ( ClassIsChildOf(MenuStack[i].Class,PageClass) ) return MenuStack[i]; return None; } // CreateMenu - Attempts to Create a menu. Returns none if it can't event GUIPage CreateMenu(string NewMenuName) { local class NewMenuClass; local GUIPage NewMenu; local int i; // Big hack here - If the menu we are creating is XInterface.UT2MainMenu then // Pull the actual main menu from native code if (NewMenuName ~= "XInterface.UT2MainMenu") NewMenuName = GetMainMenuClass(); // Load the menu's package if needed NewMenuClass = class(AddComponentClass(NewMenuName)); if (NewMenuClass != None) { // If it's persistent, try to find an instance in the PersistentStack. if( NewMenuClass.default.bPersistent ) { for( i=0;i 0 ) { if ( bModAuthor ) log("Cannot open menu until menu initialization is complete!",'ModAuthor'); return false; } NewMenu = CreateMenu(NewMenuName); if (NewMenu!=None) { // do not allow the same menu to be duplicated in the stack if ( FindMenuIndex(NewMenu) != -1 ) { bCurMenuInitialized = True; return false; } NewMenu.ParentPage = ActivePage; ResetFocus(); PushMenu( MenuStack.Length, NewMenu, Param1, Param2 ); if ( NewMenu.bDisconnectOnOpen ) ConsoleCommand("DISCONNECT"); return true; } log("Could not open menu"@NewMenuName); return false; } event AutoLoadMenus() { local GUIPage NewMenu; local int i; super.AutoLoadMenus(); for ( i=0; i < AutoLoad.Length; i++ ) { NewMenu = CreateMenu(AutoLoad[i].MenuClassName); if ( NewMenu == None ) { log("Could not auto-load"@AutoLoad[i].MenuClassName); continue; } if ( AutoLoad[i].bPreInitialize ) NewMenu.InitComponent(Self, None); } } // ================================================ // Replaces a menu in the stack. returns true if success event bool ReplaceMenu(string NewMenuName, optional string Param1, optional string Param2, optional bool bCancelled) { local GUIPage NewMenu; if ( ActivePage == None || MenuStack.Length == 0 ) return OpenMenu(NewMenuName, Param1, Param2); if ( bModAuthor ) log(Class@"ReplaceMenu ["$NewMenuName$"] ("$Param1$") ("$Param2$")",'ModAuthor'); if ( !bCurMenuInitialized && MenuStack.Length > 0 ) { if ( bModAuthor ) log("Cannot replace menu until menu initialization is complete!",'ModAuthor'); return false; } NewMenu = CreateMenu(NewMenuName); if (NewMenu != None) { NewMenu.ParentPage = ActivePage.ParentPage; ResetFocus(); // Remove the old menu PopMenu( -1, ActivePage, bCancelled ); // Add this menu to the stack and give it focus PushMenu( MenuStack.Length - 1, NewMenu, Param1, Param2 ); return true; } return false; } // Initialize a new menu and add to the stack at the specified point. protected event PushMenu( int Index, GUIPage NewMenu, optional string Param1, optional string Param2 ) { if ( NewMenu == None ) { log("Call to GUIController.PushMenu() with invalid NewMenu!!!"); return; } SetControllerStatus(true); if ( Index >= 0 ) { MenuStack[Index] = NewMenu; ActivePage = NewMenu; } CloseOverlays(); ResetInput(); if (NewMenu.Controller == None) NewMenu.InitComponent(Self, None); NewMenu.CheckResolution(false,Self); // Pass along the event NewMenu.Opened(NewMenu); NewMenu.MenuState = MSAT_Focused; NewMenu.PlayOpenSound(); bCurMenuInitialized = true; NewMenu.HandleParameters(Param1, Param2); bForceMouseCheck = true; NewMenu.OnOpen(); } protected event PopMenu( int Index, GUIPage CurMenu, optional bool bCancelled ) { CloseOverlays(); // Close out the current page CurMenu.Closed( CurMenu, bCancelled ); if ( Index >= 0 && Index + 1 < MenuStack.Length && MenuStack[Index + 1] != None ) MenuStack[Index + 1].ParentPage = CurMenu.ParentPage; CurMenu.ParentPage = None; // Free all object references CurMenu.Free(); // Sanity check - something may have changed the order of the menustack between // now and the original call to CloseMenu()/RemoveMenu() if ( Index < 0 ) return; if ( Index >= MenuStack.Length || MenuStack[Index] != CurMenu ) Index = FindMenuIndex(CurMenu); if ( Index >= 0 && Index < MenuStack.Length ) MenuStack.Remove( Index, 1 ); } function bool RemoveMenuAt( int Index, optional bool bCancelled ) { if ( Index < 0 || Index >= MenuStack.Length ) return False; return RemoveMenu(MenuStack[Index], bCancelled); } // Close a menu that isn't the top menu event bool RemoveMenu( GUIPage Menu, optional bool bCancelled ) { if ( MenuStack.Length == 0 ) { log("GUIController.RemoveMenu() - Attempting to close a non-existing menu page"); return false; } if ( Menu == None || Menu == ActivePage ) return CloseMenu(bCancelled); if ( bModAuthor ) log(Class@"RemoveMenu ["$Menu.Name$"]",'ModAuthor'); if ( !bCurMenuInitialized ) { if ( bModAuthor ) log("Cannot remove menu until initialization is complete!",'ModAuthor'); return false; } if ( !Menu.OnCanClose(bCancelled) ) return false; ResetInput(); Menu.PlayCloseSound(); // Play the closing sound PopMenu( FindMenuIndex(Menu), Menu, bCancelled ); // Gab the next page on the stack if ( MenuStack.Length == 0 ) // Pass control back to the previous menu { if ( !Menu.bAllowedAsLast && !MainNotWanted ) return OpenMenu(GetMainMenuClass()); ActivePage = None; SetControllerStatus(false); } VerifyStack(); bForceMouseCheck = true; return true; } event bool CloseMenu( optional bool bCancelled ) // Close the top menu. returns true if success. { if ( MenuStack.Length == 0 || ActivePage == None ) { log("Attempting to close a non-existing menu page"); return false; } if ( bModAuthor ) log(Class@"CloseMenu ["$ActivePage.Name$"]",'ModAuthor'); if ( !bCurMenuInitialized ) { if ( bModAuthor ) log("Cannot close menu until initialization is complete!",'ModAuthor'); return false; } if ( !ActivePage.OnCanClose(bCancelled) ) return false; ResetInput(); ActivePage.PlayCloseSound(); // Play the closing sound PopMenu( FindMenuIndex(ActivePage), ActivePage, bCancelled ); ActivePage.CheckResolution(True,Self); // Gab the next page on the stack bCurMenuInitialized=false; if ( MenuStack.Length > 0 ) // Pass control back to the previous menu { ActivePage = MenuStack[MenuStack.Length-1]; ActivePage.MenuState = MSAT_Focused; ResetFocus(); ActivePage.FocusFirst(None); if ( !ActivePage.bNeverFocus ) ActivePage.OnActivate(); } else { if (!ActivePage.bAllowedAsLast && !MainNotWanted) { ActivePage = none; return OpenMenu(GetMainMenuClass()); } ActivePage = None; SetControllerStatus(false); } bCurMenuInitialized=true; if ( ActivePage != None ) ActivePage.OnReopen(); bForceMouseCheck = true; return true; } event CloseAll(bool bCancel, optional bool bForced) { local int i; if ( bModAuthor ) { log(Name@"CloseAll bCancel:"$bCancel@"Forced:"$bForced@"(Currently"@MenuStack.Length@"menus open)",'ModAuthor'); for ( i = 0; i < MenuStack.Length; i++ ) { if ( MenuStack[i] == None ) log(" Menu["$i$"]: None",'ModAuthor'); else log(" Menu["$i$"]:"$MenuStack[i].Name,'ModAuthor'); } } // Close the current menu manually before we clean up the stack. if ( bForced ) MainNotWanted = True; if ( MenuStack.Length > 0 ) SaveRestorePages(); if( MenuStack.Length >= 0 ) CloseMenu(bCancel); MainNotWanted = False; for ( i = MenuStack.Length - 1;i >= 0; i-- ) PopMenu(i, MenuStack[i], bCancel); //log("GUIController::CloseAll - After Menu closing "@GameResolution); if (GameResolution != "") { Console(Master.Console).DelayedConsoleCommand("SETRES"@GameResolution); GameResolution=""; } ActivePage=None; SetControllerStatus(false); } function int Count() { return MenuStack.Length; } function SaveRestorePages() { local int i; local string Param1, Param2, MenuClass; // First, clear any current entries RestoreMenus.Remove( 0, RestoreMenus.Length ); for ( i = MenuStack.Length - 1; i >= 0; i-- ) { if ( MenuStack[i] != None ) { if ( MenuStack[i].bRestorable ) { MenuClass = string(MenuStack[i].Class); Param1 = ""; Param2 = ""; if ( MenuStack[i].GetRestoreParams(Param1, Param2) ) { RestoreMenus.Insert(0, 1); RestoreMenus[0].MenuClassName = MenuClass; RestoreMenus[0].Param1 = Param1; RestoreMenus[0].Param2 = Param2; } } } } } function PerformRestore() { local int i, idx; if ( bModAuthor ) log("Restoring previously open menus ("$RestoreMenus.Length$" menus to restore)",'ModAuthor'); for ( i = 0; i < RestoreMenus.Length; i++ ) { idx = FindMenuIndexByName(RestoreMenus[i].MenuClassName); if ( idx == -1 ) OpenMenu(RestoreMenus[i].MenuClassName, RestoreMenus[i].Param1, RestoreMenus[i].Param2); } RestoreMenus.Remove(0, RestoreMenus.Length); } function SetControllerStatus(bool On) { local bool bWasActive; if ( bActive && !On && ViewportOwner != None && ViewportOwner.Actor != None ) ViewportOwner.Actor.UnpressButtons(); bWasActive = bActive; bActive = On; bVisible = On; bRequiresTick=On; if ( bActive && !bWasActive && ViewportOwner != None && ViewportOwner.Actor != None ) ViewportOwner.Actor.UnpressButtons(); ViewportOwner.bShowWindowsMouse = On && ViewportOwner.bWindowsMouseAvailable; if (On) bIgnoreUntilPress = true; else { ResetDesigner(); ViewportOwner.Actor.ConsoleCommand("toggleime 0"); } PurgeComponentClasses(); } event ChangeFocus(GUIComponent Who) { if ( Who != None ) Who.SetFocus(None); return; } function ResetFocus() { MoveControl = None; if (ActiveControl!=None) { ActiveControl.MenuStateChange(MSAT_Blurry); ActiveControl = None; } if ( FocusedControl != None ) FocusedControl.LoseFocus(None); RepeatKey=0; RepeatTime=0; } event MoveFocused(GUIComponent C, int bmLeft, int bmTop, int bmWidth, int bmHeight, float ClipX, float ClipY, float Val) { if ( C.bScaleToParent && C.MenuOwner != None ) { ClipX = C.MenuOwner.ActualWidth(); ClipY = C.MenuOwner.ActualHeight(); } if (bmLeft!=0) { if ( C.WinLeft < 2.0 && C.WinLeft > -2.0 && !C.bNeverScale ) C.WinLeft += (Val/ClipX) * bmLeft; else C.WinLeft += Val*bmLeft; } if (bmTop!=0) { if ( C.WinTop < 2.0 && C.WinTop > -2.0 && !C.bNeverScale ) C.WinTop += (Val/ClipY) * bmTop; else C.WinTop += Val*bmTop; } if (bmWidth!=0) { if (C.WinWidth < 2.0 && C.WinWidth > -2.0 && !C.bNeverScale) C.WinWidth += (Val/ClipX) * bmWidth; else C.WinWidth += Val*bmWidth; } if (bmHeight!=0) { if (C.WinHeight <= 2.0) C.WinHeight += (Val/ClipX) * bmHeight; else C.WinHeight += Val*bmHeight; } } function bool HasMouseMoved( optional float ErrorMargin ) { return Abs(MouseX - LastMouseX) > Abs(ErrorMargin) || Abs(MouseY - LastMouseY) > Abs(ErrorMargin); } event bool CanShowHints() { if ( bNoToolTips ) return false; if ( ActivePage != None && ActivePage.bCaptureMouse ) return false; if ( DropSource != None || DropTarget != None ) return false; if ( !bDesignModeToolTips && bDesignMode && bHighlightCurrent ) return false; return true; } event bool NeedsMenuResolution() { local int i; for ( i = MenuStack.Length - 1; i >= 0; i-- ) { if ( MenuStack[i] != None && MenuStack[i].bRequire640x480 ) return true; if ( !MenuStack[i].bRenderWorld ) break; } return false; } event SetRequiredGameResolution(string GameRes) { GameResolution = GameRes; } event NotifyLevelChange() { local int i; if ( bModAuthor ) log(Class@"NotifyLevelChange()",'ModAuthor'); ResetDesigner(); if ( bActive && ViewportOwner.Actor != None && ViewportOwner.Actor.Level != None && ViewportOwner.Actor.Level.IsPendingConnection() ) SaveRestorePages(); for (i = MenuStack.Length - 1; i >= 0 && MenuStack.Length != 0; i--) { // Menus might start closing other menus during NotifyLevelChange, so always check for None if (MenuStack[i] != None) { // If menu is in persistent stack, skip notification here. if ( MenuStack[i].bPersistent ) continue; if ( MenuStack[i].NotifyLevelChange() ) RemoveMenu(MenuStack[i], True); } } for (i = PersistentStack.Length - 1; i >= 0; i--) { if (PersistentStack[i] != None && PersistentStack[i].NotifyLevelChange()) { if ( PersistentStack[i].IsOpen() ) RemoveMenu( PersistentStack[i], True); else PersistentStack[i].Free(); if ( !PersistentStack[i].bPersistent ) PersistentStack.Remove(i,1); } } PurgeObjectReferences(); VerifyStack(); if ( MenuStack.Length > 0 ) RestoreMenus.Remove(0,RestoreMenus.Length); } // ===================================================================================================================== // ===================================================================================================================== // Menu-stack maintenance & cleanup // ===================================================================================================================== // ===================================================================================================================== function CloseOverlays() { MouseOver = None; ContextMenu = None; } function VerifyStack() { local int i; for ( i = 0; i < MenuStack.Length; i++ ) { if ( MenuStack[i] == None || (MenuStack[i].Controller == None && bCurMenuInitialized) ) { MenuStack.Remove(i--, 1); continue; } if ( i > 0 ) MenuStack[i].ParentPage = MenuStack[i-1]; } ConsolidateMenus(); } function PurgeObjectReferences() { local class OriginalStyle; local int i; // Remove any temporary (i.e. mod-defined) styles for ( i = 0; i < STYLE_NUM; i++ ) { if ( StyleStack[i] == None ) { OriginalStyle = class(DynamicLoadObject(DefaultStyleNames[i],class'Class')); if ( !RegisterStyle(OriginalStyle) ) { log("Could not restore default style "$i$" ("$DefaultStyleNames[i]$")"); continue; } } if ( StyleStack[i].bTemporary ) { OriginalStyle = class(DynamicLoadObject(DefaultStyleNames[i],class'Class')); if ( !RegisterStyle(OriginalStyle) ) { log("Could not restore default style "$i$" ("$DefaultStyleNames[i]$")"); StyleStack[i] = None; } } } if (StyleStack.Length > STYLE_NUM) StyleStack.Remove(STYLE_NUM, StyleStack.Length - STYLE_NUM); if (FontStack.Length > FONT_NUM) FontStack.Remove(FONT_NUM, FontStack.Length - FONT_NUM); if (MouseCursors.Length > CURSOR_NUM) MouseCursors.Remove(CURSOR_NUM, MouseCursors.Length - CURSOR_NUM); PurgeComponentClasses(); } // Should be overridden function PurgeComponentClasses(); // This is used to remove any duplicate clases from the menu stack (keeping the topmost one) function ConsolidateMenus() { local int i, j; for ( i = MenuStack.Length - 1; i >= 0; i-- ) { for ( j = 0; j < i; j++ ) { if ( MenuStack[i].Class == MenuStack[j].Class ) { MenuStack[j+1].ParentPage = MenuStack[j].ParentPage; MenuStack.Remove(j,1); break; } } } } // ===================================================================================================================== // ===================================================================================================================== // Main menu classes - should be overridden in child classes // ===================================================================================================================== // ===================================================================================================================== static event Validate(); native static final function string GetMainMenuClass(); // Returns GameEngine.MainMenuClass static function string GetSinglePlayerPage(); static function string GetServerBrowserPage(); static function string GetMultiplayerPage(); static function string GetInstantActionPage(); static function string GetModPage(); static function string GetSettingsPage(); static function string GetQuitPage(); // ===================================================================================================================== // ===================================================================================================================== // Keybind management // ===================================================================================================================== // ===================================================================================================================== // SetKeyBind( "Space", "Jump" ); return true if successful final function bool SetKeyBind( string BindKeyName, string BindKeyValue ) { ViewportOwner.Actor.ConsoleCommand("set Input" @ BindKeyName @ BindKeyValue ); return true; } final function bool KeyNameFromIndex( byte iKey, out string KeyName, out string LocalizedKeyName ) { KeyName = ViewportOwner.Actor.ConsoleCommand("KEYNAME" @ iKey); LocalizedKeyName = ViewportOwner.Actor.ConsoleCommand("LOCALIZEDKEYNAME" @ iKey); return KeyName != ""; } // GetCurrentBind( "Space", CommandBoundToSpace ); return true if successful final function bool GetCurrentBind( string BindKeyName, out string BindKeyValue ) { if ( BindKeyName != "" ) { BindKeyValue = ViewportOwner.Actor.ConsoleCommand("KEYBINDING" @ BindKeyName); return BindKeyValue != ""; } return false; } // GetAssignedKeys( "Jump", ArrayOfKeysThatPerformJump ); return true if successful final function bool GetAssignedKeys( string BindAlias, out array BindKeyNames, out array LocalizedBindKeyNames ) { local int i, iKey; local string s; BindKeyNames.Length = 0; LocalizedBindKeyNames.Length = 0; s = ViewportOwner.Actor.ConsoleCommand("BINDINGTOKEY" @ "\"" $ BindAlias $ "\""); if ( s != "" ) { Split(s, ",", BindKeyNames); for ( i = 0; i < BindKeyNames.Length; i++ ) { iKey = int(ViewportOwner.Actor.ConsoleCommand("KEYNUMBER" @ BindKeyNames[i])); if ( iKey != -1 ) LocalizedBindKeyNames[i] = ViewportOwner.Actor.ConsoleCommand("LOCALIZEDKEYNAME" @ iKey); } } return BindKeyNames.Length > 0; } // SearchBinds( "switchweapon ", ArrayofAliasesThatBeginWithSwitchWeapon ); return true if successful final function bool SearchBinds( string BindAliasMask, out array BindAliases ) { local string s; BindAliases.Length = 0; s = ViewportOwner.Actor.ConsoleCommand("FINDKEYBINDS" @ "\"" $ BindAliasMask $ "\""); if ( s != "" ) Split(s, ",", BindAliases); return BindAliases.Length > 0; } final function bool KeyPressed( EInputKey iKey ) { return KeyDown[iKey] != 0; } /** show a Question menu, when the page succesfully opens it returns the handle to it. by default the btnOk is used */ function GUIQuestionPage ShowQuestionDialog(string Question, optional byte Buttons, optional byte defButton) { local GUIQuestionPage QPage; if (Buttons == 0) Buttons = 1; if (OpenMenu(QuestionMenuClass)) { QPage = GUIQuestionPage(TopPage()); QPage.SetupQuestion(Question, Buttons, defButton); return QPage; } return none; } defaultproperties { Begin Object Class=UT2MenuFont Name=GUIMenuFont Name="UT2MenuFont" End Object FontStack(0)=UT2MenuFont'GUIMenuFont' Begin Object Class=UT2DefaultFont Name=GUIDefaultFont Name="GUIDefaultFont" End Object FontStack(1)=UT2DefaultFont'GUIDefaultFont' Begin Object Class=UT2LargeFont Name=GUILargeFont Name="GUILargeFont" End Object FontStack(2)=UT2LargeFont'GUILargeFont' Begin Object Class=UT2HeaderFont Name=GUIHeaderFont Name="GUIHeaderFont" End Object FontStack(3)=UT2HeaderFont'GUIHeaderFont' Begin Object Class=UT2SmallFont Name=GUISmallFont Name="GUISmallFont" End Object FontStack(4)=UT2SmallFont'GUISmallFont' Begin Object Class=UT2MidGameFont Name=GUIMidGameFont Name="GUIMidGameFont" End Object FontStack(5)=UT2MidGameFont'GUIMidGameFont' Begin Object Class=UT2SmallHeaderFont Name=GUISmallHeaderFont Name="GUISmallHeaderFont" End Object FontStack(6)=UT2SmallHeaderFont'GUISmallHeaderFont' Begin Object Class=UT2ServerListFont Name=GUIServerListFont Name="GUIServerListFont" End Object FontStack(7)=UT2ServerListFont'GUIServerListFont' Begin Object Class=UT2IRCFont Name=GUIIRCFont Name="GUIIRCFont" End Object FontStack(8)=UT2IRCFont'GUIIRCFont' FONT_NUM=9 DefaultStyleNames(0)="XInterface.STY_RoundButton" DefaultStyleNames(1)="XInterface.STY_RoundScaledButton" DefaultStyleNames(2)="XInterface.STY_SquareButton" DefaultStyleNames(3)="XInterface.STY_ListBox" DefaultStyleNames(4)="XInterface.STY_ScrollZone" DefaultStyleNames(5)="XInterface.STY_TextButton" DefaultStyleNames(6)="XInterface.STY_Page" DefaultStyleNames(7)="XInterface.STY_Header" DefaultStyleNames(8)="XInterface.STY_Footer" DefaultStyleNames(9)="XInterface.STY_TabButton" DefaultStyleNames(10)="XInterface.STY_CharButton" DefaultStyleNames(11)="XInterface.STY_ArrowLeft" DefaultStyleNames(12)="XInterface.STY_ArrowRight" DefaultStyleNames(13)="XInterface.STY_ServerBrowserGrid" DefaultStyleNames(14)="XInterface.STY_NoBackground" DefaultStyleNames(15)="XInterface.STY_ServerBrowserGridHeader" DefaultStyleNames(16)="XInterface.STY_SliderCaption" DefaultStyleNames(17)="XInterface.STY_LadderButton" DefaultStyleNames(18)="XInterface.STY_LadderButtonHi" DefaultStyleNames(19)="XInterface.STY_LadderButtonActive" DefaultStyleNames(20)="XInterface.STY_BindBox" DefaultStyleNames(21)="XInterface.STY_SquareBar" DefaultStyleNames(22)="XInterface.STY_MidGameButton" DefaultStyleNames(23)="XInterface.STY_TextLabel" DefaultStyleNames(24)="XInterface.STY_ComboListBox" DefaultStyleNames(25)="XInterface.STY_SquareMenuButton" DefaultStyleNames(26)="XInterface.STY_IRCText" DefaultStyleNames(27)="XInterface.STY_IRCEntry" DefaultStyleNames(28)="XInterface.STY_ListSelection" DefaultStyleNames(29)="XInterface.STY_EditBox" STYLE_NUM=30 // See Player.uc IDC_ definitions // if _RO_ /* // end if _RO_ MouseCursors(0)=material'InterfaceContent.MouseCursor' // Arrow MouseCursors(1)=material'InterfaceContent.SplitterCursor' // SizeAll MouseCursors(2)=material'InterfaceContent.SplitterCursor' // Size NE SW MouseCursors(3)=material'InterfaceContent.SplitterCursorVert' // Size NS MouseCursors(4)=material'InterfaceContent.SplitterCursor' // Size NW SE MouseCursors(5)=material'InterfaceContent.SplitterCursor' // Size WE MouseCursors(6)=material'InterfaceContent.MouseCursor' // Wait // if _RO_ */ // end if _RO_ CURSOR_NUM=7 MouseCursorOffset(0)=(X=0,Y=0,Z=0) MouseCursorOffset(1)=(X=0.5,Y=0.5,Z=0) MouseCursorOffset(2)=(X=0.5,Y=0.5,Z=0) MouseCursorOffset(3)=(X=0.5,Y=0.5,Z=0) MouseCursorOffset(4)=(X=0.5,Y=0.5,Z=0) MouseCursorOffset(5)=(X=0.5,Y=0.5,Z=0) MouseCursorOffset(6)=(X=0,Y=0,Z=0) ButtonRepeatDelay=0.25 CursorStep=1 FastCursorStep=1 // Design Mode stuff // if _RO WhiteBorder=Texture'InterfaceArt_tex.Menu.WhiteBorder' // else // WhiteBorder=Material'InterfaceContent.Menu.WhiteBorder' // end if _RO_ DblClickWindow=0.5 // Replaceme MouseOverSound=sound'KF_MenuSnd.msfxMouseOver'//msfxMouseOver ClickSound=sound'KF_MenuSnd.msfxMouseClick' EditSound=sound'KF_MenuSnd.msfxEdit' UpSound=sound'KF_MenuSnd.msfxUp' DownSound=sound'KF_MenuSnd.msfxDown' MenuMouseSens=1.0 bHighlightCurrent=true bModulateStackedMenus=true bCurMenuInitialized=True RequestDataMenu="GUI2K4.UT2K4GetDataMenu" ArrayPropertyMenu="GUI2K4.GUIArrayPropPage" DynArrayPropertyMenu="GUI2K4.GUIDynArrayPage" QuestionMenuClass="XInterface.GUIQuestionPage" FilterMenu="GUI2K4.UT2K4_FilterListPage" MapVotingMenu="xVoting.MapVotingPage" KickVotingMenu="xVoting.KickVotingPage" MatchSetupMenu="xVoting.MatchConfigPage" DesignerMenu="GUIDesigner.PropertyManager" EditFavoriteMenu="GUI2K4.EditFavoritePage" NetworkMsgMenu="GUI2K4.UT2K4NetworkStatusMsg" // items in parenthesis means 'while held' // items in brackets only required if NOT in interactive mode DesignModeHints(0)=(Key=" Key",Description=" Description") DesignModeHints(1)=(Key=" (F1)",Description=" View this help screen") DesignModeHints(2)=(Key=" Ctrl + Alt + D",Description=" Toggles design mode") DesignModeHints(3)=(Key=" Ctrl + Alt + E",Description=" Toggles property editor mode") DesignModeHints(4)=(Key=" [Ctrl +] H",Description=" Toggles active/focused info") DesignModeHints(5)=(Key=" [Ctrl +] I",Description=" Toggle interactive mode") DesignModeHints(6)=(Key=" [Ctrl +] P",Description=" Toggles full MenuOwner chains for active/focused") DesignModeHints(7)=(Key=" [Ctrl +] C",Description=" Copy MoveControl position to clipboard") DesignModeHints(8)=(Key=" [Ctrl +] X",Description=" Export MoveControl to clipboard") DesignModeHints(9)=(Key=" [Ctrl +] U",Description=" Refresh the property window in the designer") DesignModeHints(10)=(Key=" [Ctrl +] Up/Down/Left/Right",Description=" Reposition MoveControl using arrow keys") DesignModeHints(11)=(Key=" [Ctrl +] +/-",Description=" Resize MoveControl vertically") DesignModeHints(12)=(Key=" [Ctrl +] Num+/Num-",Description=" Resize selected component horizontally") DesignModeHints(13)=(Key=" [Ctrl +] WheelUp",Description=" Set MoveControl to MoveControl's menuowner") DesignModeHints(14)=(Key=" [Ctrl +] WheenDown",Description=" Set MoveControl to MoveControl's focused control") DesignModeHints(15)=(Key=" [(Ctrl + Alt) +] MouseX/Y+LMouse",Description=" Reposition MoveControl using mouse") DesignModeHints(16)=(Key=" (Shift)",Description=" Hides all design mode indicators") DesignModeHints(17)=(Key=" (Ctrl + Alt)",Description=" View focus chain") DesignModeHints(18)=(Key=" [Ctrl +] Tab",Description=" Select new MoveControl") DesignModeHints(19)=(Key=" [Ctrl +] LMouse",Description=" Select new MoveControl") LCDLogo=texture'G15LCD.Logos.BWLogoRGB8A' LCDTinyFont=font'Engine.Defaultfont' LCDSmallFont=font'G15LCDFonts.LCDSmallFont' LCDMedFont=font'G15LCDFonts.LCDMedFont' LCDLargeFont=font'G15LCDFonts.LCDLargeFont' MaxPingsPerSecond=0 }