Browse Source

Merge pull request #780 from Areloch/UINavigation

Implements a more standardized way to format usual UI pages by having the ability to utilize the UINavigation namespace for page stack navigation
Brian Roberts 3 years ago
parent
commit
81b4cc92b6
23 changed files with 1140 additions and 1211 deletions
  1. 6 0
      Templates/BaseGame/game/core/gui/scripts/profiles.tscript
  2. 9 0
      Templates/BaseGame/game/data/UI/UI.tscript
  3. 5 0
      Templates/BaseGame/game/data/UI/guis/MainMenuButtons.asset.taml
  4. 78 0
      Templates/BaseGame/game/data/UI/guis/MainMenuButtons.gui
  5. 116 0
      Templates/BaseGame/game/data/UI/guis/MainMenuButtons.tscript
  6. 4 212
      Templates/BaseGame/game/data/UI/guis/chooseLevelDlg.gui
  7. 16 19
      Templates/BaseGame/game/data/UI/guis/chooseLevelDlg.tscript
  8. 3 403
      Templates/BaseGame/game/data/UI/guis/joinServerMenu.gui
  9. 9 28
      Templates/BaseGame/game/data/UI/guis/joinServerMenu.tscript
  10. 55 214
      Templates/BaseGame/game/data/UI/guis/mainMenu.gui
  11. 38 57
      Templates/BaseGame/game/data/UI/guis/mainMenu.tscript
  12. 74 69
      Templates/BaseGame/game/data/UI/guis/optionsMenu.gui
  13. 66 63
      Templates/BaseGame/game/data/UI/guis/optionsMenu.tscript
  14. 87 102
      Templates/BaseGame/game/data/UI/guis/pauseMenu.gui
  15. 10 17
      Templates/BaseGame/game/data/UI/guis/pauseMenu.tscript
  16. BIN
      Templates/BaseGame/game/data/UI/images/Inputs/Keyboard & Mouse/Keyboard_Black_Mouse_Left.png
  17. BIN
      Templates/BaseGame/game/data/UI/images/Inputs/Keyboard & Mouse/Keyboard_Black_Mouse_Middle.png
  18. BIN
      Templates/BaseGame/game/data/UI/images/Inputs/Keyboard & Mouse/Keyboard_Black_Mouse_Right.png
  19. 203 26
      Templates/BaseGame/game/data/UI/scripts/menuInputHandling.tscript
  20. 283 0
      Templates/BaseGame/game/data/UI/scripts/menuNavigation.tscript
  21. 61 0
      Templates/BaseGame/game/data/UI/tools/creator.tscript
  22. 7 0
      Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript
  23. 10 1
      Templates/BaseGame/game/tools/assetBrowser/scripts/creator.tscript

+ 6 - 0
Templates/BaseGame/game/core/gui/scripts/profiles.tscript

@@ -81,6 +81,12 @@ new GuiControlProfile (GuiDefaultProfile)
    cursorColor = "0 0 0 255";
 };
 
+if(!isObject(GuiNonModalDefaultProfile))
+new GuiControlProfile (GuiNonModalDefaultProfile : GuiDefaultProfile)
+{
+   modal = false;
+};
+
 if(!isObject(GuiToolTipProfile))
 new GuiControlProfile (GuiToolTipProfile)
 {

+ 9 - 0
Templates/BaseGame/game/data/UI/UI.tscript

@@ -35,12 +35,18 @@ function UI::initClient(%this)
    //Profiles
    %this.queueExec("./scripts/profiles");
    
+   //Navigation Utility Scripts
+   %this.queueExec("./scripts/menuNavigation");
+   
    //Now gui files
    %this.queueExec("./scripts/menuInputHandling");
    
    %this.queueExec("./guis/mainMenu");
    %this.queueExec("./guis/mainMenu.gui");
    
+   %this.queueExec("./guis/mainMenuButtons");
+   %this.queueExec("./guis/mainMenuButtons.gui");
+   
    %this.queueExec("./guis/chooseLevelDlg");
    %this.queueExec("./guis/chooseLevelDlg.gui");
    
@@ -79,6 +85,9 @@ function UI::initClient(%this)
    %this.queueExec("./scripts/help");
    %this.queueExec("./scripts/cursors");
    %this.queueExec("./scripts/utility");
+   
+   if(isToolBuild())
+      %this.queueExec("./tools/creator.tscript");
 }
 
 function UI::onCreateClientConnection(%this){}

+ 5 - 0
Templates/BaseGame/game/data/UI/guis/MainMenuButtons.asset.taml

@@ -0,0 +1,5 @@
+<GUIAsset
+    AssetName="MainMenuButtons"
+    scriptFile="@assetFile=MainMenuButtons.tscript"
+    GUIFile="@assetFile=MainMenuButtons.gui"
+    VersionId="1"/>

+ 78 - 0
Templates/BaseGame/game/data/UI/guis/MainMenuButtons.gui

@@ -0,0 +1,78 @@
+//--- OBJECT WRITE BEGIN ---
+$guiContent = new GuiControl(MainMenuButtons) {
+   extent = "1024 768";
+   profile = "GuiNonModalDefaultProfile";
+   tooltipProfile = "GuiToolTipProfile";
+   isContainer = "1";
+   canSaveDynamicFields = "1";
+      originalAssetName = "MainMenuButtons";
+
+   new GuiStackControl(MainMenuButtonList) {
+      padding = "15";
+      dynamicSize = "0";
+      position = "312 145";
+      extent = "400 477";
+      horizSizing = "center";
+      vertSizing = "center";
+      profile = "GuiDefaultProfile";
+      tooltipProfile = "GuiToolTipProfile";
+      superClass = "MenuList";
+
+      new GuiButtonCtrl(MainMenuSinglePlayerBtn) {
+         text = "Single Player";
+         extent = "400 55";
+         profile = "GuiMenuButtonProfile";
+         command = "openSinglePlayerMenu();";
+         tooltipProfile = "GuiToolTipProfile";
+      };
+      new GuiButtonCtrl(MainMenuCreateSrvrBtn) {
+         text = "Create Server";
+         position = "0 70";
+         extent = "400 55";
+         profile = "GuiMenuButtonProfile";
+         command = "openMultiPlayerMenu();";
+         tooltipProfile = "GuiToolTipProfile";
+      };
+      new GuiButtonCtrl(MainMenuJoinSrvrBtn) {
+         text = "Join Server";
+         position = "0 140";
+         extent = "400 55";
+         profile = "GuiMenuButtonProfile";
+         command = "openJoinServerMenu();";
+         tooltipProfile = "GuiToolTipProfile";
+      };
+      new GuiButtonCtrl(MainMenuOptionBtn) {
+         text = "Options";
+         position = "0 210";
+         extent = "400 55";
+         profile = "GuiMenuButtonProfile";
+         command = "openOptionsMenu();";
+         tooltipProfile = "GuiToolTipProfile";
+      };
+      new GuiButtonCtrl(MainMenuWorldEditBtn) {
+         text = "Open World Editor";
+         position = "0 280";
+         extent = "400 55";
+         profile = "GuiMenuButtonProfile";
+         command = "openWorldEditorBtn();";
+         tooltipProfile = "GuiToolTipProfile";
+      };
+      new GuiButtonCtrl(MainMenuGuiEditBtn) {
+         text = "Open GUI Editor";
+         position = "0 350";
+         extent = "400 55";
+         profile = "GuiMenuButtonProfile";
+         command = "openGUIEditorBtn();";
+         tooltipProfile = "GuiToolTipProfile";
+      };
+      new GuiButtonCtrl(MainMenuExitBtn) {
+         text = "Exit";
+         position = "0 420";
+         extent = "400 55";
+         profile = "GuiMenuButtonProfile";
+         command = "quit();";
+         tooltipProfile = "GuiToolTipProfile";
+      };
+   };
+};
+//--- OBJECT WRITE END ---

+ 116 - 0
Templates/BaseGame/game/data/UI/guis/MainMenuButtons.tscript

@@ -0,0 +1,116 @@
+function MainMenuButtons::onWake(%this)
+{
+}
+
+function MainMenuButtons::onSleep(%this)
+{
+}
+
+//==============================================================================
+// This gets called by the MainMenuGUI beacuse it, being a UINavigation classed control
+// set MainMenuButtonList as it's root page. 
+// This is an optional function, but is called as part of the validation that the page
+// CAN be opened, so it's shown here as an example
+function MainMenuButtonList::canOpen(%this)
+{
+   return true;
+}
+
+//==============================================================================
+// This gets called by the MainMenuGUI beacuse it, being a UINavigation classed control
+// set MainMenuButtonList as it's root page. 
+// Once the page is added to the MainMenuGUI's UINavigation page stack, onOpen here is called
+// Which allows us to actually do the work we need to do for display
+function MainMenuButtonList::onOpen(%this)
+{
+   //Here, we set the MainMenuButtonList - a GuiStackControl with the MenuList class
+   // to be the active menu list.
+   // This means that when the MainMenuGUI's MainMenuInputHandler receives an input
+   // or we have one of the buttons in the MainMenuButtonHolder be actioned, we know
+   // we're working/navigating this list of buttons specifically
+   // In practice, it sets the $activeMenuList global variable so the various menu class code
+   // can reference it consistently
+   MainMenuButtonList.setAsActiveMenuList();
+   
+   //Because MainMenuGUI set it's MainMenuButtonHolder as the active button container, we can reference it
+   //by $activeMenuButtonContainer and set the menu button/accelerator prompts we need for the MainMenuButtonList
+   //specifically.
+   //In particular, being a simple list of buttons, the only one we NEED is a simple activate, so we'll
+   //disable all the other ones to keep them clear in case they were set by other pages at some point
+   $activeMenuButtonContainer-->button1.disable();
+   $activeMenuButtonContainer-->button2.disable();
+   $activeMenuButtonContainer-->button3.disable();
+   
+   //Here we set the 4th button in the container
+   //All the buttons have the MenuInputButton class, which, like the other classes
+   //help keep things accessible and consistent. Here we use that class's set function to
+   //configure the accelerator behavior
+   //The first parameter sets the gamepad button to the 'A' button
+   //The second sets the keyboard button to Enter or Return
+   //Third is what the displayed text will be
+   //And finally we set the command when the button is clicked, or either key inputs are caught by
+   //our MenuInputHandler
+   //The menu buttons automatically detect which input device you're using and swap the display between
+   //gamepad or keyboard for consistent behavior
+   $activeMenuButtonContainer-->button4.set("btn_a", "Return", "Go", "MainMenuButtonList.activate();");
+   $activeMenuButtonContainer-->button5.disable();
+}
+
+//Optional, as the check defaults to true, but here as an example case
+function MainMenuButtonList::canClose(%this)
+{
+   return true;
+}
+
+
+function MainMenuButtonList::onClose(%this)
+{
+}
+
+//Our actual commands when we activate the buttons
+function openSinglePlayerMenu()
+{
+   $pref::HostMultiPlayer=false;
+   MainMenuGui.pushPage(ChooseLevelDlg);
+}
+
+function openMultiPlayerMenu()
+{
+   $pref::HostMultiPlayer=true;
+   
+   //Here, like the other commands, we add a new page onto the stack
+   //In this case, we'll push the ChooseLevelDlg control onto the stack. This will
+   //invoke the canClose() and then onClose() functions for MainMenuButtonList
+   //before calling the onOpen() for ChooseLevelDlg then displaying.
+   MainMenuGui.pushPage(ChooseLevelDlg);
+}
+
+function openJoinServerMenu()
+{
+   //Here, like the other commands, we add a new page onto the stack
+   //In this case, we'll push the JoinServerMenu control onto the stack. This will
+   //invoke the canClose() and then onClose() functions for MainMenuButtonList
+   //before calling the onOpen() for JoinServerMenu then displaying.
+   MainMenuGui.pushPage(JoinServerMenu);
+}
+
+function openOptionsMenu()
+{
+   //Here, like the other commands, we add a new page onto the stack
+   //In this case, we'll push the OptionsMenu control onto the stack. This will
+   //invoke the canClose() and then onClose() functions for MainMenuButtonList
+   //before calling the onOpen() for OptionsMenu then displaying.
+   //The options menu additionally has an example of why we may want to capitalize on the
+   //canClose() call.
+   MainMenuGui.pushPage(OptionsMenu);
+}
+
+function openWorldEditorBtn()
+{
+   fastLoadWorldEdit(1);
+}
+
+function openGUIEditorBtn()
+{
+   fastLoadGUIEdit(1);
+}

+ 4 - 212
Templates/BaseGame/game/data/UI/guis/chooseLevelDlg.gui

@@ -1,17 +1,12 @@
 //--- OBJECT WRITE BEGIN ---
 $guiContent = new GuiControl(ChooseLevelDlg) {
-   position = "0 0";
    extent = "1024 768";
    minExtent = "8 8";
    horizSizing = "width";
    vertSizing = "height";
-   profile = "GuiDefaultProfile";
-   visible = "1";
-   active = "1";
+   profile = "GuiNonModalDefaultProfile";
    tooltipProfile = "GuiToolTipProfile";
-   hovertime = "1000";
    isContainer = "1";
-   canSave = "1";
    canSaveDynamicFields = "1";
       Enabled = "1";
       launchInEditor = "0";
@@ -20,294 +15,91 @@ $guiContent = new GuiControl(ChooseLevelDlg) {
    new GuiControl(ChooseLevelWindow) {
       position = "48 56";
       extent = "928 655";
-      minExtent = "8 2";
       horizSizing = "center";
       vertSizing = "center";
       profile = "GuiDefaultProfile";
-      visible = "1";
-      active = "1";
       tooltipProfile = "GuiToolTipProfile";
-      hovertime = "1000";
       isContainer = "1";
-      canSave = "1";
-      canSaveDynamicFields = "0";
 
       new GuiBitmapBarCtrl() {
-         percent = "100";
-         vertical = "0";
-         flipClip = "0";
-         bitmapAsset = "UI:panel_image";
-         color = "255 255 255 255";
-         position = "0 0";
+         BitmapAsset = "UI:panel_image";
          extent = "927 40";
-         minExtent = "8 2";
          horizSizing = "width";
-         vertSizing = "bottom";
          profile = "GuiDefaultProfile";
-         visible = "1";
-         active = "1";
          tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "0";
-         canSave = "1";
-         canSaveDynamicFields = "0";
       };
       new GuiTextCtrl(LevelSelectTitle) {
          text = "SINGLE PLAYER";
-         maxLength = "1024";
-         margin = "0 0 0 0";
-         padding = "0 0 0 0";
-         anchorTop = "1";
-         anchorBottom = "0";
-         anchorLeft = "1";
-         anchorRight = "0";
          position = "22 10";
          extent = "307 28";
-         minExtent = "8 2";
-         horizSizing = "right";
-         vertSizing = "bottom";
          profile = "MenuHeaderText";
-         visible = "1";
-         active = "1";
          tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "1";
-         canSave = "1";
-         canSaveDynamicFields = "0";
       };
       new GuiBitmapBarCtrl() {
-         percent = "100";
-         vertical = "0";
-         flipClip = "0";
-         bitmapAsset = "UI:panel_low_image";
-         color = "255 255 255 255";
+         BitmapAsset = "UI:panel_low_image";
          position = "0 40";
          extent = "927 618";
-         minExtent = "8 2";
          horizSizing = "width";
-         vertSizing = "bottom";
          profile = "GuiDefaultProfile";
-         visible = "1";
-         active = "1";
          tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "0";
-         canSave = "1";
-         canSaveDynamicFields = "0";
       };
       new GuiBitmapCtrl() {
-         bitmapAsset = "UI:no_preview_image";
-         color = "255 255 255 255";
-         wrap = "0";
+         BitmapAsset = "Core_Rendering:missingTexture_image";
          position = "513 71";
          extent = "400 300";
-         minExtent = "8 2";
-         horizSizing = "right";
-         vertSizing = "bottom";
          profile = "GuiDefaultProfile";
-         visible = "1";
-         active = "1";
          tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "0";
          internalName = "CurrentPreview";
-         canSave = "1";
          canSaveDynamicFields = "1";
             Enabled = "1";
       };
       new GuiTextCtrl() {
          text = "Example Level";
          maxLength = "255";
-         margin = "0 0 0 0";
-         padding = "0 0 0 0";
-         anchorTop = "1";
-         anchorBottom = "0";
-         anchorLeft = "1";
-         anchorRight = "0";
          position = "514 375";
          extent = "398 27";
          minExtent = "8 8";
-         horizSizing = "right";
-         vertSizing = "bottom";
          profile = "MenuHeaderText";
-         visible = "1";
-         active = "1";
          tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
          isContainer = "0";
          internalName = "LevelName";
-         canSave = "1";
-         canSaveDynamicFields = "0";
       };
       new GuiTextCtrl() {
          text = "Description:";
          maxLength = "255";
-         margin = "0 0 0 0";
-         padding = "0 0 0 0";
-         anchorTop = "1";
-         anchorBottom = "0";
-         anchorLeft = "1";
-         anchorRight = "0";
          position = "522 410";
          extent = "91 18";
          minExtent = "8 8";
-         horizSizing = "right";
-         vertSizing = "bottom";
          profile = "MenuSubHeaderText";
-         visible = "1";
-         active = "1";
          tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
          isContainer = "0";
          internalName = "LevelDescriptionLabel";
-         canSave = "1";
-         canSaveDynamicFields = "0";
       };
       new GuiMLTextCtrl() {
-         lineSpacing = "2";
-         allowColorChars = "0";
-         maxChars = "-1";
          text = "This is placeholder text";
-         useURLMouseCursor = "0";
          position = "522 436";
          extent = "391 14";
          minExtent = "8 8";
-         horizSizing = "right";
-         vertSizing = "bottom";
          profile = "GuiMLWhiteTextProfile";
-         visible = "1";
-         active = "1";
          tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "0";
          internalName = "LevelDescription";
-         canSave = "1";
-         canSaveDynamicFields = "0";
       };
       new GuiScrollCtrl() {
-         willFirstRespond = "1";
          hScrollBar = "dynamic";
          vScrollBar = "dynamic";
-         lockHorizScroll = "0";
-         lockVertScroll = "0";
-         constantThumbHeight = "0";
-         childMargin = "0 0";
-         mouseWheelScrollSpeed = "-1";
-         margin = "0 0 0 0";
-         padding = "0 0 0 0";
-         anchorTop = "1";
-         anchorBottom = "0";
-         anchorLeft = "1";
-         anchorRight = "0";
          position = "0 40";
          extent = "450 580";
-         minExtent = "8 2";
-         horizSizing = "right";
-         vertSizing = "bottom";
          profile = "GuiMenuScrollProfile";
-         visible = "1";
-         active = "1";
          tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "1";
-         canSave = "1";
-         canSaveDynamicFields = "0";
 
          new GuiGameListMenuCtrl(LevelList) {
-            debugRender = "0";
             callbackOnInputs = "1";
             position = "1 1";
             extent = "450 90";
-            minExtent = "8 2";
-            horizSizing = "right";
-            vertSizing = "bottom";
             profile = "DefaultListMenuProfile";
-            visible = "1";
-            active = "1";
             tooltipProfile = "GuiToolTipProfile";
-            hovertime = "1000";
-            isContainer = "0";
             class = "UIMenuButtonList";
-            canSave = "1";
-            canSaveDynamicFields = "0";
-         };
-      };
    };
-   new GuiControl(ChooseLevelButtonHolder) {
-      position = "189 711";
-      extent = "646 40";
-      minExtent = "8 2";
-      horizSizing = "center";
-      vertSizing = "top";
-      profile = "GuiDefaultProfile";
-      visible = "1";
-      active = "1";
-      tooltipProfile = "GuiToolTipProfile";
-      hovertime = "1000";
-      isContainer = "1";
-      class = "MenuInputButtonContainer";
-      canSave = "1";
-      canSaveDynamicFields = "0";
-
-      new GuiIconButtonCtrl() {
-         buttonMargin = "4 4";
-         iconBitmap = "./";
-         iconLocation = "Left";
-         sizeIconToButton = "1";
-         makeIconSquare = "1";
-         textLocation = "Right";
-         textMargin = "4";
-         autoSize = "0";
-         text = "Go";
-         groupNum = "-1";
-         buttonType = "PushButton";
-         useMouseEvents = "0";
-         position = "363 0";
-         extent = "140 40";
-         minExtent = "8 2";
-         horizSizing = "right";
-         vertSizing = "bottom";
-         profile = "GuiMenuButtonProfile";
-         visible = "1";
-         active = "1";
-         command = "MainMenuButtonList.activateRow();";
-         tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "0";
-         internalName = "goButton";
-         class = "MenuInputButton";
-         canSave = "1";
-         canSaveDynamicFields = "0";
-      };
-      new GuiIconButtonCtrl() {
-         buttonMargin = "4 4";
-         iconBitmap = "./";
-         iconLocation = "Left";
-         sizeIconToButton = "1";
-         makeIconSquare = "1";
-         textLocation = "Right";
-         textMargin = "4";
-         autoSize = "0";
-         text = "Back";
-         groupNum = "-1";
-         buttonType = "PushButton";
-         useMouseEvents = "0";
-         position = "507 0";
-         extent = "140 40";
-         minExtent = "8 2";
-         horizSizing = "right";
-         vertSizing = "bottom";
-         profile = "GuiMenuButtonProfile";
-         visible = "1";
-         active = "1";
-         command = "MainMenuButtonList.activateRow();";
-         tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "0";
-         internalName = "backButton";
-         class = "MenuInputButton";
-         canSave = "1";
-         canSaveDynamicFields = "0";
       };
    };
 };

+ 16 - 19
Templates/BaseGame/game/data/UI/guis/chooseLevelDlg.tscript

@@ -26,6 +26,12 @@ function ChooseLevelDlg::onWake( %this )
    if(!isObject(LevelListEntries))
       new ArrayObject(LevelListEntries){};
       
+   if(!isObject(ChooseLevelAssetQuery))
+      new AssetQuery(ChooseLevelAssetQuery);
+}
+
+function ChooseLevelDlg::onOpen(%this)
+{
    LevelList.clearRows();
    LevelListEntries.empty();
    
@@ -33,10 +39,10 @@ function ChooseLevelDlg::onWake( %this )
    ChooseLevelWindow->LevelDescriptionLabel.visible = false;
    ChooseLevelWindow->LevelDescription.visible = false;
    
-   %assetQuery = new AssetQuery();
-   AssetDatabase.findAssetType(%assetQuery, "LevelAsset");
+   ChooseLevelAssetQuery.clear();
+   AssetDatabase.findAssetType(ChooseLevelAssetQuery, "LevelAsset");
       
-   %count = %assetQuery.getCount();
+   %count = ChooseLevelAssetQuery.getCount();
    
    if(%count == 0 && !IsDirectory("tools"))
    {
@@ -44,13 +50,13 @@ function ChooseLevelDlg::onWake( %this )
       MessageBoxOK("Error", "No levels were found in any modules. Please ensure you have modules loaded that contain gameplay code and level files.", 
          "Canvas.popDialog(ChooseLevelDlg); if(isObject(ChooseLevelDlg.returnGui) && ChooseLevelDlg.returnGui.isMethod(\"onReturnTo\")) ChooseLevelDlg.returnGui.onReturnTo();");
          
-      %assetQuery.delete();
+      ChooseLevelAssetQuery.delete();
       return;
    }
    
    for(%i=0; %i < %count; %i++)
 	{
-	   %assetId = %assetQuery.getAsset(%i);
+	   %assetId = ChooseLevelAssetQuery.getAsset(%i);
 	   
 	   if(AssetDatabase.getAssetModule(%assetId).ModuleId $= "ToolsModule")
 	      continue;
@@ -96,13 +102,11 @@ function ChooseLevelDlg::onWake( %this )
    else
       LevelSelectTitle.setText("CREATE SERVER");
    
-   ChooseLevelButtonHolder.setActive();
-}
-
-function ChooseLevelButtonHolder::onWake(%this)
-{
-   %this-->goButton.set("btn_a", "Return", "Start Level", "ChooseLevelDlg.beginLevel();");
-   %this-->backButton.set("btn_b", "Escape", "Back", "ChooseLevelDlg.backOut();");
+   $activeMenuButtonContainer-->button1.disable();
+   $activeMenuButtonContainer-->button2.disable();
+   $activeMenuButtonContainer-->button3.disable();
+   $activeMenuButtonContainer-->button4.set("btn_a", "Return", "Start Level", "ChooseLevelDlg.beginLevel();");
+   $activeMenuButtonContainer-->button5.set("btn_b", "Escape", "Back", %this @ ".navigation.popPage();");
 }
 
 function ChooseLevelDlg::onSleep( %this )
@@ -202,10 +206,3 @@ function ChooseLevelDlg::beginLevel(%this)
       StartGame(); 
    }
 }
-
-function ChooseLevelDlg::backOut(%this)
-{
-   Canvas.popDialog(ChooseLevelDlg);
-   if(isObject(ChooseLevelDlg.returnGui) && ChooseLevelDlg.returnGui.isMethod("onReturnTo"))    
-      ChooseLevelDlg.returnGui.onReturnTo();  
-}

+ 3 - 403
Templates/BaseGame/game/data/UI/guis/joinServerMenu.gui

@@ -1,559 +1,159 @@
 //--- OBJECT WRITE BEGIN ---
 $guiContent = new GuiControl(JoinServerMenu) {
-   position = "0 0";
    extent = "1024 768";
-   minExtent = "8 2";
-   horizSizing = "right";
-   vertSizing = "bottom";
-   profile = "GuiDefaultProfile";
-   visible = "1";
-   active = "1";
+   profile = "GuiNonModalDefaultProfile";
    tooltipProfile = "GuiToolTipProfile";
-   hovertime = "1000";
    isContainer = "1";
-   canSave = "1";
-   canSaveDynamicFields = "1";
-      returnGui = "MainMenuGui";
-
-   new GuiInputCtrl(JoinServerMenuInputHandler) {
-      sendAxisEvents = "1";
-      sendBreakEvents = "1";
-      sendModifierEvents = "0";
-      ignoreMouseEvents = "1";
-      lockMouse = "0";
-      position = "-10 0";
-      extent = "10 10";
-      minExtent = "8 2";
       horizSizing = "width";
       vertSizing = "height";
-      profile = "GuiInputCtrlProfile";
-      visible = "1";
-      active = "1";
-      tooltipProfile = "GuiToolTipProfile";
-      hovertime = "1000";
-      isContainer = "0";
-      canSave = "1";
       canSaveDynamicFields = "0";
-   };
+
    new GuiControl(JoinServerWindow) {
       position = "48 56";
       extent = "928 655";
-      minExtent = "8 2";
       horizSizing = "center";
       vertSizing = "center";
       profile = "GuiDefaultProfile";
-      visible = "1";
-      active = "1";
       tooltipProfile = "GuiToolTipProfile";
-      hovertime = "1000";
       isContainer = "1";
-      canSave = "1";
-      canSaveDynamicFields = "0";
 
       new GuiBitmapBarCtrl() {
-         percent = "100";
-         vertical = "0";
-         flipClip = "0";
          BitmapAsset = "UI:panel_image";
-         color = "255 255 255 255";
-         position = "0 0";
          extent = "927 40";
-         minExtent = "8 2";
          horizSizing = "width";
-         vertSizing = "bottom";
          profile = "GuiDefaultProfile";
-         visible = "1";
-         active = "1";
          tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "0";
-         canSave = "1";
-         canSaveDynamicFields = "0";
       };
       new GuiTextCtrl() {
          text = "JOIN SERVER";
-         maxLength = "1024";
-         margin = "0 0 0 0";
-         padding = "0 0 0 0";
-         anchorTop = "1";
-         anchorBottom = "0";
-         anchorLeft = "1";
-         anchorRight = "0";
          position = "22 10";
          extent = "207 28";
-         minExtent = "8 2";
-         horizSizing = "right";
-         vertSizing = "bottom";
          profile = "MenuHeaderText";
-         visible = "1";
-         active = "1";
          tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "1";
-         canSave = "1";
-         canSaveDynamicFields = "0";
       };
       new GuiBitmapBarCtrl() {
-         percent = "100";
-         vertical = "0";
-         flipClip = "0";
          BitmapAsset = "UI:panel_low_image";
-         color = "255 255 255 255";
          position = "0 40";
          extent = "927 618";
-         minExtent = "8 2";
          horizSizing = "width";
-         vertSizing = "bottom";
          profile = "GuiDefaultProfile";
-         visible = "1";
-         active = "1";
          tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "0";
-         canSave = "1";
-         canSaveDynamicFields = "0";
       };
       new GuiTextCtrl(JS_status) {
          text = "No servers found.";
          maxLength = "255";
-         margin = "0 0 0 0";
-         padding = "0 0 0 0";
-         anchorTop = "1";
-         anchorBottom = "0";
-         anchorLeft = "1";
-         anchorRight = "0";
          position = "392 47";
          extent = "148 18";
          minExtent = "8 8";
-         horizSizing = "right";
-         vertSizing = "bottom";
          profile = "MenuSubHeaderText";
-         visible = "1";
-         active = "1";
          tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "1";
-         canSave = "1";
-         canSaveDynamicFields = "0";
       };
       new GuiTextCtrl() {
          text = "Players";
          maxLength = "255";
-         margin = "0 0 0 0";
-         padding = "0 0 0 0";
-         anchorTop = "1";
-         anchorBottom = "0";
-         anchorLeft = "1";
-         anchorRight = "0";
          position = "269 67";
          extent = "36 18";
          minExtent = "8 8";
-         horizSizing = "right";
-         vertSizing = "bottom";
          profile = "GuiMLWhiteTextProfile";
-         visible = "1";
-         active = "1";
          tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
          isContainer = "0";
-         canSave = "1";
-         canSaveDynamicFields = "0";
       };
       new GuiTextCtrl() {
          text = "Version";
          maxLength = "255";
-         margin = "0 0 0 0";
-         padding = "0 0 0 0";
-         anchorTop = "1";
-         anchorBottom = "0";
-         anchorLeft = "1";
-         anchorRight = "0";
          position = "335 67";
          extent = "38 18";
          minExtent = "8 8";
-         horizSizing = "right";
-         vertSizing = "bottom";
          profile = "GuiMLWhiteTextProfile";
-         visible = "1";
-         active = "1";
          tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
          isContainer = "0";
-         canSave = "1";
-         canSaveDynamicFields = "0";
       };
       new GuiTextCtrl() {
          text = "Game";
          maxLength = "255";
-         margin = "0 0 0 0";
-         padding = "0 0 0 0";
-         anchorTop = "1";
-         anchorBottom = "0";
-         anchorLeft = "1";
-         anchorRight = "0";
          position = "412 67";
          extent = "28 18";
          minExtent = "8 8";
-         horizSizing = "right";
-         vertSizing = "bottom";
          profile = "GuiMLWhiteTextProfile";
-         visible = "1";
-         active = "1";
          tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
          isContainer = "0";
-         canSave = "1";
-         canSaveDynamicFields = "0";
       };
       new GuiTextCtrl() {
          text = "Ping";
          maxLength = "255";
-         margin = "0 0 0 0";
-         padding = "0 0 0 0";
-         anchorTop = "1";
-         anchorBottom = "0";
-         anchorLeft = "1";
-         anchorRight = "0";
          position = "212 67";
          extent = "20 18";
          minExtent = "8 8";
-         horizSizing = "right";
-         vertSizing = "bottom";
          profile = "GuiMLWhiteTextProfile";
-         visible = "1";
-         active = "1";
          tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
          isContainer = "0";
-         canSave = "1";
-         canSaveDynamicFields = "0";
       };
       new GuiTextCtrl() {
          text = "Server Name";
          maxLength = "255";
-         margin = "0 0 0 0";
-         padding = "0 0 0 0";
-         anchorTop = "1";
-         anchorBottom = "0";
-         anchorLeft = "1";
-         anchorRight = "0";
          position = "12 67";
          extent = "63 18";
          minExtent = "8 8";
-         horizSizing = "right";
-         vertSizing = "bottom";
          profile = "GuiMLWhiteTextProfile";
-         visible = "1";
-         active = "1";
          tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
          isContainer = "0";
-         canSave = "1";
-         canSaveDynamicFields = "0";
       };
       new GuiScrollCtrl() {
-         willFirstRespond = "1";
          hScrollBar = "dynamic";
          vScrollBar = "dynamic";
-         lockHorizScroll = "0";
-         lockVertScroll = "0";
-         constantThumbHeight = "0";
-         childMargin = "0 0";
-         mouseWheelScrollSpeed = "-1";
-         margin = "0 0 0 0";
-         padding = "0 0 0 0";
-         anchorTop = "1";
-         anchorBottom = "0";
-         anchorLeft = "1";
-         anchorRight = "0";
          position = "19 98";
          extent = "890 501";
          minExtent = "8 8";
-         horizSizing = "right";
-         vertSizing = "bottom";
          profile = "GuiMenuScrollProfile";
-         visible = "1";
-         active = "1";
          tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "1";
-         canSave = "1";
-         canSaveDynamicFields = "0";
 
          new GuiStackControl(JoinServerList) {
-            stackingType = "Vertical";
-            horizStacking = "Left to Right";
-            vertStacking = "Top to Bottom";
             padding = "10";
-            dynamicSize = "1";
-            dynamicNonStackExtent = "0";
-            dynamicPos = "0";
             changeChildSizeToFit = "0";
-            changeChildPosition = "1";
             position = "1 1";
             extent = "888 16";
-            minExtent = "16 16";
             horizSizing = "center";
             vertSizing = "center";
             profile = "GuiDefaultProfile";
-            visible = "1";
-            active = "1";
             tooltipProfile = "GuiToolTipProfile";
-            hovertime = "1000";
-            isContainer = "1";
-            canSave = "1";
-            canSaveDynamicFields = "0";
-            class = "MenuList";
+            superClass = "MenuList";
          };
       };
       new GuiControl(JS_queryStatus) {
          position = "16 615";
          extent = "900 35";
-         minExtent = "8 2";
-         horizSizing = "right";
-         vertSizing = "bottom";
          profile = "GuiDefaultProfile";
          visible = "0";
-         active = "1";
          tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
          isContainer = "1";
          hidden = "1";
-         canSave = "1";
-         canSaveDynamicFields = "0";
 
          new GuiProgressCtrl(JS_statusBar) {
-            maxLength = "1024";
-            margin = "0 0 0 0";
-            padding = "0 0 0 0";
-            anchorTop = "1";
-            anchorBottom = "0";
-            anchorLeft = "1";
-            anchorRight = "0";
             position = "84 0";
             extent = "695 35";
             minExtent = "8 8";
-            horizSizing = "right";
-            vertSizing = "bottom";
             profile = "GuiProgressProfile";
-            visible = "1";
-            active = "1";
             tooltipProfile = "GuiToolTipProfile";
-            hovertime = "1000";
             isContainer = "0";
-            canSave = "1";
-            canSaveDynamicFields = "0";
          };
          new GuiButtonCtrl(JS_cancelQuery) {
             text = "Cancel!";
-            groupNum = "-1";
-            buttonType = "PushButton";
-            useMouseEvents = "0";
-            position = "0 0";
             extent = "84 35";
             minExtent = "8 8";
-            horizSizing = "right";
-            vertSizing = "bottom";
             profile = "GuiMenuButtonProfile";
-            visible = "1";
-            active = "1";
             command = "JoinServerDlg.cancel();";
             tooltipProfile = "GuiToolTipProfile";
-            hovertime = "1000";
-            isContainer = "0";
-            canSave = "1";
-            canSaveDynamicFields = "0";
          };
          new GuiTextCtrl(JS_statusText) {
             text = "Querying master server";
             maxLength = "255";
-            margin = "0 0 0 0";
-            padding = "0 0 0 0";
-            anchorTop = "1";
-            anchorBottom = "0";
-            anchorLeft = "1";
-            anchorRight = "0";
             position = "84 0";
             extent = "695 35";
             minExtent = "8 8";
-            horizSizing = "right";
-            vertSizing = "bottom";
             profile = "GuiMenuButtonProfile";
-            visible = "1";
-            active = "1";
             tooltipProfile = "GuiToolTipProfile";
-            hovertime = "1000";
             isContainer = "0";
-            canSave = "1";
-            canSaveDynamicFields = "0";
-         };
-      };
    };
-   new GuiControl(JoinServerButtonHolder) {
-      position = "116 711";
-      extent = "791 40";
-      minExtent = "8 2";
-      horizSizing = "center";
-      vertSizing = "top";
-      profile = "GuiDefaultProfile";
-      visible = "1";
-      active = "1";
-      tooltipProfile = "GuiToolTipProfile";
-      hovertime = "1000";
-      isContainer = "1";
-      class = "MenuInputButtonContainer";
-      canSave = "1";
-      canSaveDynamicFields = "0";
-
-      new GuiIconButtonCtrl() {
-         buttonMargin = "4 4";
-         BitmapAsset = "UI:Keyboard_Black_Return_image";
-         iconLocation = "Left";
-         sizeIconToButton = "1";
-         makeIconSquare = "1";
-         textLocation = "Right";
-         textMargin = "4";
-         autoSize = "0";
-         text = "Join";
-         groupNum = "-1";
-         buttonType = "PushButton";
-         useMouseEvents = "0";
-         position = "507 0";
-         extent = "140 40";
-         minExtent = "8 2";
-         horizSizing = "right";
-         vertSizing = "bottom";
-         profile = "GuiMenuButtonProfile";
-         visible = "1";
-         active = "0";
-         command = "JoinServerMenu.join();";
-         tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "0";
-         internalName = "joinButton";
-         class = "MenuInputButton";
-         canSave = "1";
-         canSaveDynamicFields = "0";
-      };
-      new GuiIconButtonCtrl() {
-         buttonMargin = "4 4";
-         BitmapAsset = "UI:Keyboard_Black_Escape_image";
-         iconLocation = "Left";
-         sizeIconToButton = "1";
-         makeIconSquare = "1";
-         textLocation = "Right";
-         textMargin = "4";
-         autoSize = "0";
-         text = "Back";
-         groupNum = "-1";
-         buttonType = "PushButton";
-         useMouseEvents = "0";
-         position = "651 0";
-         extent = "140 40";
-         minExtent = "8 2";
-         horizSizing = "right";
-         vertSizing = "bottom";
-         profile = "GuiMenuButtonProfile";
-         visible = "1";
-         active = "1";
-         command = "JoinServerMenu.backOut();";
-         tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "0";
-         internalName = "backButton";
-         class = "MenuInputButton";
-         canSave = "1";
-         canSaveDynamicFields = "0";
-      };
-      new GuiIconButtonCtrl() {
-         buttonMargin = "4 4";
-         BitmapAsset = "UI:Keyboard_Black_Q_image";
-         iconLocation = "Left";
-         sizeIconToButton = "1";
-         makeIconSquare = "1";
-         textLocation = "Right";
-         textMargin = "4";
-         autoSize = "0";
-         text = "Query LAN";
-         groupNum = "-1";
-         buttonType = "PushButton";
-         useMouseEvents = "0";
-         position = "0 0";
-         extent = "140 40";
-         minExtent = "8 2";
-         horizSizing = "right";
-         vertSizing = "bottom";
-         profile = "GuiMenuButtonProfile";
-         visible = "1";
-         active = "1";
-         command = "JoinServerMenu.queryLan();";
-         tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "0";
-         internalName = "queryLANButton";
-         class = "MenuInputButton";
-         canSave = "1";
-         canSaveDynamicFields = "0";
-      };
-      new GuiIconButtonCtrl() {
-         buttonMargin = "4 4";
-         BitmapAsset = "UI:Keyboard_Black_E_image";
-         iconLocation = "Left";
-         sizeIconToButton = "1";
-         makeIconSquare = "1";
-         textLocation = "Right";
-         textMargin = "4";
-         autoSize = "0";
-         text = "Query Online";
-         groupNum = "-1";
-         buttonType = "PushButton";
-         useMouseEvents = "0";
-         position = "144 0";
-         extent = "140 40";
-         minExtent = "8 2";
-         horizSizing = "right";
-         vertSizing = "bottom";
-         profile = "GuiMenuButtonProfile";
-         visible = "1";
-         active = "1";
-         command = "JoinServerMenu.query();";
-         tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "0";
-         internalName = "queryInternetButton";
-         class = "MenuInputButton";
-         canSave = "1";
-         canSaveDynamicFields = "0";
-      };
-      new GuiIconButtonCtrl() {
-         buttonMargin = "4 4";
-         BitmapAsset = "UI:Keyboard_Black_R_image";
-         iconLocation = "Left";
-         sizeIconToButton = "1";
-         makeIconSquare = "1";
-         textLocation = "Right";
-         textMargin = "4";
-         autoSize = "0";
-         text = "Refresh";
-         groupNum = "-1";
-         buttonType = "PushButton";
-         useMouseEvents = "0";
-         position = "325 0";
-         extent = "140 40";
-         minExtent = "8 2";
-         horizSizing = "right";
-         vertSizing = "bottom";
-         profile = "GuiMenuButtonProfile";
-         visible = "1";
-         active = "1";
-         command = "JoinServerMenu.refresh();";
-         tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "0";
-         internalName = "refreshButton";
-         class = "MenuInputButton";
-         canSave = "1";
-         canSaveDynamicFields = "0";
       };
    };
 };

+ 9 - 28
Templates/BaseGame/game/data/UI/guis/joinServerMenu.tscript

@@ -1,26 +1,17 @@
 
 function JoinServerMenu::onWake(%this)
 {
-   JoinServerButtonHolder.setActive();
-   
-   JoinServerList.setAsActiveMenuList();
-   
-   JoinServerMenuInputHandler.setFirstResponder();
 }   
 
-function JoinServerButtonHolder::onWake(%this)
+function JoinServerMenu::onOpen(%this)
 {
-   %this-->joinButton.set("btn_start", "Return", "Join", "JoinServerMenu.join();");
-   %this-->backButton.set("btn_b", "Escape", "Back", "JoinServerMenu.backOut();");
-   %this-->refreshButton.set("btn_y", "R", "Refresh", "JoinServerMenu.refresh();");
-   %this-->queryLANButton.set("btn_a", "Q", "Query LAN", "JoinServerMenu.queryLan();");
-   %this-->queryInternetButton.set("btn_x", "E", "Query Online", "JoinServerMenu.query();");
-}
+   JoinServerList.setAsActiveMenuList();
 
-function JoinServerMenuInputHandler::onInputEvent(%this, %device, %action, %state)
-{
-   if(%state)
-      $activeMenuButtonContainer.processInputs(%device, %action);
+   $activeMenuButtonContainer-->button1.set("btn_y", "R", "Refresh", "JoinServerMenu.refresh();");
+   $activeMenuButtonContainer-->button2.set("btn_a", "Q", "Query LAN", "JoinServerMenu.queryLan();");
+   $activeMenuButtonContainer-->button3.set("btn_x", "E", "Query Online", "JoinServerMenu.query();");
+   $activeMenuButtonContainer-->button4.set("btn_start", "Return", "Join", "JoinServerMenu.join();");
+   $activeMenuButtonContainer-->button5.set("btn_b", "Escape", "Back", "cancelServerQuery(); " @ %this @ ".navigation.popPage();");
 }
 
 //----------------------------------------
@@ -79,7 +70,7 @@ function JoinServerMenu::join(%this)
 function JoinServerMenu::refresh(%this)
 {
    cancelServerQuery();
-   %index= JS_serverList.getSelectedId();
+   %index= JoinServerList.getActiveRow();
 
    // The server info index is stored in the row along with the
    // rest of displayed info.
@@ -93,16 +84,6 @@ function JoinServerMenu::refreshSelectedServer( %this )
    querySingleServer( $JoinGameAddress, 0 );
 }
 
-//----------------------------------------
-function JoinServerMenu::backOut(%this)
-{
-   cancelServerQuery();
-   
-   Canvas.popDialog(JoinServerMenu);
-   if(isObject(JoinServerMenu.returnGui) && JoinServerMenu.returnGui.isMethod("onReturnTo"))    
-      JoinServerMenu.returnGui.onReturnTo();  
-}
-
 //----------------------------------------
 function JoinServerMenu::update(%this)
 {
@@ -124,7 +105,7 @@ function JoinServerMenu::update(%this)
       JoinServerList.add(%serverBtn);
    }
 
-   JoinServerButtonHolder-->joinButton.setActive(JoinServerList.getCount() > 0);
+   $activeMenuButtonContainer-->button4.setActive(JoinServerList.getCount() > 0);
 } 
 
 //----------------------------------------

+ 55 - 214
Templates/BaseGame/game/data/UI/guis/mainMenu.gui

@@ -1,41 +1,23 @@
 //--- OBJECT WRITE BEGIN ---
 $guiContent = new GuiChunkedBitmapCtrl(MainMenuGui) {
    BitmapAsset = "UI:backgrounddark_image";
-   useVariable = "0";
-   tile = "0";
-   position = "0 0";
    extent = "1024 768";
    minExtent = "8 8";
    horizSizing = "width";
    vertSizing = "height";
    profile = "GuiDefaultProfile";
-   visible = "1";
-   active = "1";
    tooltipProfile = "GuiToolTipProfile";
-   hovertime = "1000";
    isContainer = "1";
-   canSave = "1";
-   canSaveDynamicFields = "1";
-      Enabled = "1";
-      isDecoy = "0";
-      navigationIndex = "-1";
+   superClass = "UINavigation";
+   canSaveDynamicFields = "0";
 
    new GuiBitmapCtrl(MainMenuAppLogo) {
       BitmapAsset = "UI:Torque_3D_logo_alt_image";
-      color = "255 255 255 255";
-      wrap = "0";
       position = "550 30";
       extent = "443 139";
-      minExtent = "8 2";
       horizSizing = "left";
-      vertSizing = "bottom";
       profile = "GuiDefaultProfile";
-      visible = "1";
-      active = "1";
       tooltipProfile = "GuiToolTipProfile";
-      hovertime = "1000";
-      isContainer = "0";
-      canSave = "1";
       canSaveDynamicFields = "1";
          autoFitExtents = "0";
          bitmapMode = "Stretched";
@@ -45,239 +27,98 @@ $guiContent = new GuiChunkedBitmapCtrl(MainMenuGui) {
          useModifiers = "0";
          useStates = "1";
    };
-   new GuiStackControl(MainMenuButtonList) {
-      stackingType = "Vertical";
-      horizStacking = "Left to Right";
-      vertStacking = "Top to Bottom";
-      padding = "15";
-      dynamicSize = "0";
-      dynamicNonStackExtent = "0";
-      dynamicPos = "0";
-      changeChildSizeToFit = "1";
-      changeChildPosition = "1";
-      position = "312 111";
-      extent = "400 477";
-      minExtent = "16 16";
+   new GuiControl(MainMenuButtonHolder) {
+      position = "143 711";
+      extent = "736 40";
       horizSizing = "center";
-      vertSizing = "center";
+      vertSizing = "top";
       profile = "GuiDefaultProfile";
-      visible = "1";
-      active = "1";
       tooltipProfile = "GuiToolTipProfile";
-      hovertime = "1000";
       isContainer = "1";
-      canSave = "1";
-      canSaveDynamicFields = "0";
-      class = "MenuList";
+      class = "MenuInputButtonContainer";
 
-      new GuiButtonCtrl(MainMenuSinglePlayerBtn) {
-         text = "Single Player";
-         groupNum = "-1";
-         buttonType = "PushButton";
-         useMouseEvents = "0";
-         position = "0 0";
-         extent = "400 55";
-         minExtent = "8 2";
-         horizSizing = "right";
-         vertSizing = "bottom";
-         profile = "GuiMenuButtonProfile";
-         visible = "1";
-         active = "1";
-         command = "openSinglePlayerMenu();";
-         tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "0";
-         canSave = "1";
-         canSaveDynamicFields = "0";
-      };
-      new GuiButtonCtrl(MainMenuCreateSrvrBtn) {
-         text = "Create Server";
-         groupNum = "-1";
-         buttonType = "PushButton";
-         useMouseEvents = "0";
-         position = "0 70";
-         extent = "400 55";
-         minExtent = "8 2";
-         horizSizing = "right";
-         vertSizing = "bottom";
-         profile = "GuiMenuButtonProfile";
-         visible = "1";
-         active = "1";
-         command = "openMultiPlayerMenu();";
-         tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "0";
-         canSave = "1";
-         canSaveDynamicFields = "0";
-      };
-      new GuiButtonCtrl(MainMenuJoinSrvrBtn) {
-         text = "Join Server";
-         groupNum = "-1";
-         buttonType = "PushButton";
-         useMouseEvents = "0";
-         position = "0 140";
-         extent = "400 55";
-         minExtent = "8 2";
-         horizSizing = "right";
-         vertSizing = "bottom";
-         profile = "GuiMenuButtonProfile";
-         visible = "1";
-         active = "1";
-         command = "openJoinServerMenu();";
-         tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "0";
-         canSave = "1";
-         canSaveDynamicFields = "0";
-      };
-      new GuiButtonCtrl(MainMenuOptionBtn) {
-         text = "Options";
-         groupNum = "-1";
-         buttonType = "PushButton";
-         useMouseEvents = "0";
-         position = "0 210";
-         extent = "400 55";
-         minExtent = "8 2";
-         horizSizing = "right";
-         vertSizing = "bottom";
+      new GuiIconButtonCtrl() {
+         BitmapAsset = "UI:Keyboard_Black_Return_image";
+         sizeIconToButton = "1";
+         makeIconSquare = "1";
+         textLocation = "Right";
+         text = "Go";
+         position = "11 0";
+         extent = "140 40";
          profile = "GuiMenuButtonProfile";
-         visible = "1";
-         active = "1";
-         command = "openOptionsMenu();";
+         command = "MainMenuButtonList.activate();";
          tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "0";
-         canSave = "1";
-         canSaveDynamicFields = "0";
+         internalName = "button1";
+         class = "MenuInputButton";
       };
-      new GuiButtonCtrl(MainMenuWorldEditBtn) {
-         text = "Open World Editor";
-         groupNum = "-1";
-         buttonType = "PushButton";
-         useMouseEvents = "0";
-         position = "0 280";
-         extent = "400 55";
-         minExtent = "8 2";
-         horizSizing = "right";
-         vertSizing = "bottom";
+      new GuiIconButtonCtrl() {
+         BitmapAsset = "UI:Keyboard_Black_Return_image";
+         sizeIconToButton = "1";
+         makeIconSquare = "1";
+         textLocation = "Right";
+         text = "Go";
+         position = "155 0";
+         extent = "140 40";
          profile = "GuiMenuButtonProfile";
-         visible = "1";
-         active = "1";
-         command = "openWorldEditorBtn();";
+         command = "MainMenuButtonList.activate();";
          tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "0";
-         canSave = "1";
-         canSaveDynamicFields = "0";
+         internalName = "button2";
+         class = "MenuInputButton";
       };
-      new GuiButtonCtrl(MainMenuGuiEditBtn) {
-         text = "Open GUI Editor";
-         groupNum = "-1";
-         buttonType = "PushButton";
-         useMouseEvents = "0";
-         position = "0 350";
-         extent = "400 55";
-         minExtent = "8 2";
-         horizSizing = "right";
-         vertSizing = "bottom";
+      new GuiIconButtonCtrl() {
+         BitmapAsset = "UI:Keyboard_Black_Return_image";
+         sizeIconToButton = "1";
+         makeIconSquare = "1";
+         textLocation = "Right";
+         text = "Go";
+         position = "299 0";
+         extent = "140 40";
          profile = "GuiMenuButtonProfile";
-         visible = "1";
-         active = "1";
-         command = "openGUIEditorBtn();";
+         command = "MainMenuButtonList.activate();";
          tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "0";
-         canSave = "1";
-         canSaveDynamicFields = "0";
+         internalName = "button3";
+         class = "MenuInputButton";
       };
-      new GuiButtonCtrl(MainMenuExitBtn) {
-         text = "Exit";
-         groupNum = "-1";
-         buttonType = "PushButton";
-         useMouseEvents = "0";
-         position = "0 420";
-         extent = "400 55";
-         minExtent = "8 2";
-         horizSizing = "right";
-         vertSizing = "bottom";
+      new GuiIconButtonCtrl() {
+         BitmapAsset = "UI:Keyboard_Black_Return_image";
+         sizeIconToButton = "1";
+         makeIconSquare = "1";
+         textLocation = "Right";
+         text = "Go";
+         position = "443 0";
+         extent = "140 40";
          profile = "GuiMenuButtonProfile";
-         visible = "1";
-         active = "1";
-         command = "quit();";
+         command = "MainMenuButtonList.activate();";
          tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "0";
-         canSave = "1";
-         canSaveDynamicFields = "0";
-      };
+         internalName = "button4";
+         class = "MenuInputButton";
    };
-   new GuiControl(MainMenuButtonHolder) {
-      position = "189 711";
-      extent = "646 40";
-      minExtent = "8 2";
-      horizSizing = "center";
-      vertSizing = "top";
-      profile = "GuiDefaultProfile";
-      visible = "1";
-      active = "1";
-      tooltipProfile = "GuiToolTipProfile";
-      hovertime = "1000";
-      isContainer = "1";
-      class = "MenuInputButtonContainer";
-      canSave = "1";
-      canSaveDynamicFields = "0";
-
       new GuiIconButtonCtrl() {
-         buttonMargin = "4 4";
          BitmapAsset = "UI:Keyboard_Black_Return_image";
-         iconLocation = "Left";
          sizeIconToButton = "1";
          makeIconSquare = "1";
          textLocation = "Right";
-         textMargin = "4";
-         autoSize = "0";
          text = "Go";
-         groupNum = "-1";
-         buttonType = "PushButton";
-         useMouseEvents = "0";
-         position = "507 0";
+         position = "587 0";
          extent = "140 40";
-         minExtent = "8 2";
-         horizSizing = "right";
-         vertSizing = "bottom";
          profile = "GuiMenuButtonProfile";
-         visible = "1";
-         active = "1";
-         command = "MainMenuButtonList.activateRow();";
+         command = "MainMenuButtonList.activate();";
          tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "0";
-         internalName = "goButton";
+         internalName = "button5";
          class = "MenuInputButton";
-         canSave = "1";
-         canSaveDynamicFields = "0";
       };
    };
    new GuiInputCtrl(MainMenuInputHandler) {
-      class = "MenuInputHandler";
       sendAxisEvents = "1";
       sendBreakEvents = "1";
-      sendModifierEvents = "0";
       ignoreMouseEvents = "1";
-      lockMouse = "0";
       position = "-50 0";
       extent = "10 10";
-      minExtent = "8 2";
       horizSizing = "width";
       vertSizing = "height";
       profile = "GuiInputCtrlProfile";
-      visible = "1";
-      active = "1";
       tooltipProfile = "GuiToolTipProfile";
-      hovertime = "1000";
-      isContainer = "0";
-      canSave = "1";
-      canSaveDynamicFields = "0";
+      class = "MenuInputHandler";
    };
 };
 //--- OBJECT WRITE END ---

+ 38 - 57
Templates/BaseGame/game/data/UI/guis/mainMenu.tscript

@@ -5,66 +5,47 @@ function MainMenuGui::onAdd(%this)
 
 function MainMenuGui::onWake(%this)
 {
-   MainMenuButtonList.setAsActiveMenuList();
+   //In the BaseUI example case, the MainMenuGUI acts as our background
+   //So it's a logical control to set as our UINavigation as well. So we 
+   //set the MainMenuGUI's superClass to UINavigation to integrate it into
+   //that namespace to open up page navigation
+   
+   //At the same time, the MainMenuGUI control has the button holder, set to
+   //the MenuInputButtonContainer class, allowing us to set it as the active button
+   //holder here, prepping it for catching any button inputs to active commands
+   //Specifically, it sets the $activeMenuButtonContainer to be this, which allows
+   //other controls to manage what the behavior of the buttons is consistently
+   //without needing to worry about hardcoded names
    MainMenuButtonHolder.setActive();
+   
+   //We also have the MainMenuInputHandler, a GuiInputCtrl with the MenuInputHandler class
+   //This allows us to catch any input/axis event and pass it along to the active menuList
+   //or button containers to navigate the menus
+   //We set up this catch by making said control our first responder, here
    MainMenuInputHandler.setFirstResponder();
-}
-
-function MainMenuGui::onSleep(%this)
-{
-   MainMenuButtonHolder.hidden = true;
+   
+   //Lastly, we go ahead and display some actual navigable content up on our main menu here
+   //In this case, we set the MainMenuButtonList as our root page, so we always come back
+   //to having the main menu buttons on screen if every other page is closed.
+   //This will ultimately call MainMenuButtonList::onOpen(), so to see where the navigation
+   //chain continues, see that function.
+   %this.setRootPage(MainMenuButtonList);
+   
+   //We also go ahead and mark for any future pages being added to the UINavigation's page stack
+   //to be prompted to resize when added. This isn't required, but helps keep pages formated to 
+   //the current size of the UINavigation, which is useful when dealing with aspect ratio or resolution
+   //changes.
+   %this.resizePages = true;
 }
 
 function MainMenuButtonHolder::onWake(%this)
 {
-   %this-->goButton.set("btn_a", "Return", "Go", "MainMenuButtonList.activate();");
-}
-
-function openSinglePlayerMenu()
-{
-   $pref::HostMultiPlayer=false;
-   Canvas.pushDialog(ChooseLevelDlg);
-   ChooseLevelDlg.returnGui = MainMenuGui; 
-   MainMenuButtonList.hidden = true; 
-   MainMenuButtonHolder.hidden = true;
-}
-
-function openMultiPlayerMenu()
-{
-   $pref::HostMultiPlayer=true;
-   Canvas.pushDialog(ChooseLevelDlg);
-   ChooseLevelDlg.returnGui = MainMenuGui; 
-   MainMenuButtonList.hidden = true; 
-}
-
-function openJoinServerMenu()
-{
-   Canvas.pushDialog(JoinServerMenu);
-   JoinServerMenu.returnGui = MainMenuGui; 
-   MainMenuButtonList.hidden = true; 
-}
-
-function openOptionsMenu()
-{
-   Canvas.pushDialog(OptionsMenu);
-   OptionsMenu.returnGui = MainMenuGui; 
-   MainMenuButtonList.hidden = true; 
-}
-
-function openWorldEditorBtn()
-{
-   fastLoadWorldEdit(1);
-}
-
-function openGUIEditorBtn()
-{
-   fastLoadGUIEdit(1);
-}
-
-function MainMenuGui::onReturnTo(%this)
-{
-   MainMenuButtonList.hidden = false;
-   MainMenuButtonList.setFirstResponder();
-   MainMenuButtonHolder.setActive();
-   MainMenuButtonList.setAsActiveMenuList();
-}
+   //Because the blan slate MainMenuGUI doesn't have anything we need to bother with inputs on
+   //we just go ahead and disable all the buttons in our MainMenuButtonHolder to have
+   // a clean slate
+   %this-->button1.disable();
+   %this-->button2.disable();
+   %this-->button3.disable();
+   %this-->button4.disable();
+   %this-->button5.disable();
+}

+ 74 - 69
Templates/BaseGame/game/data/UI/guis/optionsMenu.gui

@@ -1,12 +1,14 @@
 //--- OBJECT WRITE BEGIN ---
 $guiContent = new GuiControl(OptionsMenu) {
    extent = "1024 768";
-   profile = "GuiDefaultProfile";
+   profile = "GuiNonModalDefaultProfile";
    tooltipProfile = "GuiToolTipProfile";
    isContainer = "1";
+   horizSizing = "width";
+   vertSizing = "height";
    canSaveDynamicFields = "0";
 
-   new GuiControl() {
+   new GuiControl(OptionsMenuContainer) {
       position = "48 56";
       extent = "928 655";
       horizSizing = "aspectCenter";
@@ -33,7 +35,7 @@ $guiContent = new GuiControl(OptionsMenu) {
       new GuiTextCtrl() {
          text = "OPTIONS";
          position = "22 7";
-         extent = "120 28";
+         extent = "220 28";
          profile = "MenuHeaderText";
          tooltipProfile = "GuiToolTipProfile";
       };
@@ -77,7 +79,7 @@ $guiContent = new GuiControl(OptionsMenu) {
                vertSizing = "height";
                profile = "GuiDefaultProfile";
                tooltipProfile = "GuiToolTipProfile";
-               class = "MenuList";
+               superClass = "MenuList";
 
                new GuiButtonCtrl() {
                   text = "Display";
@@ -118,6 +120,14 @@ $guiContent = new GuiControl(OptionsMenu) {
                   command = "populateGamepadSettingsList();";
                   tooltipProfile = "GuiToolTipProfile";
                };
+               new GuiButtonCtrl() {
+                  text = "Example Options";
+                  position = "0 225";
+                  extent = "248 35";
+                  profile = "GuiMenuButtonProfile";
+                  command = "testExampleOptions();";
+                  tooltipProfile = "GuiToolTipProfile";
+               };
             };
          };
          new GuiPanel() {
@@ -141,81 +151,76 @@ $guiContent = new GuiControl(OptionsMenu) {
                   padding = "5";
                   changeChildSizeToFit = "0";
                   position = "1 1";
-                  extent = "661 30";
+                  extent = "661 170";
                   horizSizing = "width";
                   vertSizing = "height";
                   profile = "GuiDefaultProfile";
                   tooltipProfile = "GuiToolTipProfile";
-                  class = "MenuList";
+                  superClass = "MenuList";
+                  new GuiGameSettingsCtrl() {
+                     PreviousBitmapAsset = "UI:previousOption_n_image";
+                     NextBitmapAsset = "UI:nextOption_n_image";
+                     columnSplit = "198";
+                     useMouseEvents = "1";
+                     extent = "661 30";
+                     horizSizing = "width";
+                     profile = "GuiMenuButtonProfile";
+                     tooltipProfile = "GuiToolTipProfile";
+                     class = "MenuOptionsButton";
+                  };
+                  new GuiGameSettingsCtrl() {
+                     PreviousBitmapAsset = "UI:previousOption_n_image";
+                     NextBitmapAsset = "UI:nextOption_n_image";
+                     columnSplit = "198";
+                     useMouseEvents = "1";
+                     position = "0 35";
+                     extent = "661 30";
+                     horizSizing = "width";
+                     profile = "GuiMenuButtonProfile";
+                     tooltipProfile = "GuiToolTipProfile";
+                     class = "MenuOptionsButton";
+                  };
+                  new GuiGameSettingsCtrl() {
+                     PreviousBitmapAsset = "UI:previousOption_n_image";
+                     NextBitmapAsset = "UI:nextOption_n_image";
+                     columnSplit = "198";
+                     useMouseEvents = "1";
+                     position = "0 70";
+                     extent = "661 30";
+                     horizSizing = "width";
+                     profile = "GuiMenuButtonProfile";
+                     tooltipProfile = "GuiToolTipProfile";
+                     class = "MenuOptionsButton";
+                  };
+                  new GuiGameSettingsCtrl() {
+                     PreviousBitmapAsset = "UI:previousOption_n_image";
+                     NextBitmapAsset = "UI:nextOption_n_image";
+                     columnSplit = "198";
+                     useMouseEvents = "1";
+                     position = "0 105";
+                     extent = "661 30";
+                     horizSizing = "width";
+                     profile = "GuiMenuButtonProfile";
+                     tooltipProfile = "GuiToolTipProfile";
+                     class = "MenuOptionsButton";
+                  };
+                  new GuiGameSettingsCtrl() {
+                     PreviousBitmapAsset = "UI:previousOption_n_image";
+                     NextBitmapAsset = "UI:nextOption_n_image";
+                     columnSplit = "198";
+                     useMouseEvents = "1";
+                     position = "0 140";
+                     extent = "661 30";
+                     horizSizing = "width";
+                     profile = "GuiMenuButtonProfile";
+                     tooltipProfile = "GuiToolTipProfile";
+                     class = "MenuOptionsButton";
                };
             };
          };
       };
    };
-   new GuiControl(OptionsButtonHolder) {
-      position = "116 711";
-      extent = "791 40";
-      horizSizing = "center";
-      vertSizing = "top";
-      profile = "GuiDefaultProfile";
-      tooltipProfile = "GuiToolTipProfile";
-      isContainer = "1";
-      class = "MenuInputButtonContainer";
 
-      new GuiIconButtonCtrl() {
-         BitmapAsset = "UI:Keyboard_Black_R_image";
-         sizeIconToButton = "1";
-         makeIconSquare = "1";
-         textLocation = "Right";
-         text = "Reset";
-         position = "173 0";
-         extent = "140 40";
-         profile = "GuiMenuButtonProfile";
-         command = "OptionsMenu.resetToDefaults();";
-         tooltipProfile = "GuiToolTipProfile";
-         internalName = "resetButton";
-         class = "MenuInputButton";
-      };
-      new GuiIconButtonCtrl(OptionsMenuSelectButton) {
-         BitmapAsset = "UI:Keyboard_Black_Return_image";
-         sizeIconToButton = "1";
-         makeIconSquare = "1";
-         textLocation = "Right";
-         text = "Select";
-         position = "507 0";
-         extent = "140 40";
-         profile = "GuiMenuButtonProfile";
-         command = "";
-         tooltipProfile = "GuiToolTipProfile";
-         internalName = "SelectButton";
-         class = "MenuInputButton";
-      };
-      new GuiIconButtonCtrl() {
-         BitmapAsset = "UI:Keyboard_Black_Escape_image";
-         sizeIconToButton = "1";
-         makeIconSquare = "1";
-         textLocation = "Right";
-         text = "Back";
-         position = "651 0";
-         extent = "140 40";
-         profile = "GuiMenuButtonProfile";
-         command = "OptionsMenu.backOut();";
-         tooltipProfile = "GuiToolTipProfile";
-         internalName = "backButton";
-         class = "MenuInputButton";
-      };
-   };
-   new GuiInputCtrl(OptionsMenuInputHandler) {
-      sendAxisEvents = "1";
-      sendBreakEvents = "1";
-      ignoreMouseEvents = "1";
-      position = "-50 0";
-      extent = "10 10";
-      horizSizing = "left";
-      vertSizing = "top";
-      profile = "GuiInputCtrlProfile";
-      tooltipProfile = "GuiToolTipProfile";
-      class = "MenuInputHandler";
    };
 };
 //--- OBJECT WRITE END ---

+ 66 - 63
Templates/BaseGame/game/data/UI/guis/optionsMenu.tscript

@@ -72,16 +72,7 @@ function OptionsMenu::onAdd(%this)
    callOnModules("populateOptionsMenuCategories", "Game");
 }
 
-function OptionsMenuSettingsList::onAdd(%this)
-{
-}
-
-function OptionsMenuSettingsList::getOptionsList(%this, %index)
-{
-     
-}
-
-function OptionsMenu::onWake(%this)
+function OptionsMenu::onOpen(%this)
 {
    OptionsMenuCategoryList.clear(); 
    
@@ -116,22 +107,60 @@ function OptionsMenu::onWake(%this)
    
    %this.unappliedChanges.empty();
    
-   MainMenuButtonList.hidden = true;
+   OptionsMenuCategoryList.setAsActiveMenuList();
+   
+   $activeMenuButtonContainer-->button1.set("btn_back", "R", "Reset", "OptionsMenu.resetToDefaults();");
+   $activeMenuButtonContainer-->button1.disable();
+   $activeMenuButtonContainer-->button3.set("", "Space", "Apply", "OptionsMenu.apply();");
+   $activeMenuButtonContainer-->button4.set("btn_a", "", "Select", "OptionsMenu.select();");
+   $activeMenuButtonContainer-->button5.set("btn_b", "Escape", "Back", %this @ ".navigation.popPage();");
+}
    
+//We capitalize on the canClose test here, because we want to prompt for unapplied options changes before
+//backing out. So when the UINavigation test canClose, we can see if we have unapplied settings and prompt
+//that via the message box and return false.
+//This gives the user a chance to choose how they wish to proceed before we allow the 
+//UINavigation to move away from the options menu
+function OptionsMenu::canClose(%this)
+{
+   //Another special case is us catching the 'back/pop' action by just shifting from one
+   //menu list to another. In this case, we check if we were on the settings list as our active MenuList
+   //if so, then the back/pop just moves us to the Category list as our active and we inform the 
+   //UINavigation to not close the page
+   if(OptionsMenuSettingsList.isActiveMenuList())
+   {
    OptionsMenuCategoryList.setAsActiveMenuList();
+      %this.updateSelectButton();
+      return false;
+   }
+   else
+   {
+      //Here, we're on the category list as our active, so we're actually trying to leae the page
+      //If we have unapplied changes, we want to prompt about them before closing the page and navigating away
+      //If we don't, then we can process the popPage as normal and let the OptionsMenu close
+      if(%this.unappliedChanges.count() != 0)
+      {
+         MessageBoxOKCancel("Discard Changes?", "You have unapplied changes to your settings, do you wish to apply or discard them?", 
+                        "OptionsMenu.apply(); MainMenuGUI.popPage();", "%this.unappliedChanges.empty(); " @ %this @ ".navigation.popPage();", 
+                        "Apply", "Discard");
+         return false;
+      }
+   }
    
-   OptionsButtonHolder.setActive();
+   return true;
+}
+
+function OptionsMenu::onClose(%this)
+{
    
-   OptionsMenuInputHandler.setFirstResponder();
 }
 
-function OptionsButtonHolder::onWake(%this)
+function OptionsMenuSettingsList::onAdd(%this)
 {
-   %this-->resetButton.set("btn_back", "R", "Reset", "OptionsMenu.resetToDefaults();");
-   %this-->selectButton.set("btn_a", "Return", "Select", "OptionsMenu.select();", true);
-   %this-->backButton.set("btn_b", "Escape", "Back", "OptionsMenu.backOut();");
+}
    
-   //OptionsMenuCategoryList.getObject(0).performClick();
+function OptionsMenuSettingsList::getOptionsList(%this, %index)
+{
 }
 
 function OptionsMenu::select(%this)
@@ -281,9 +310,6 @@ function OptionsMenu::apply(%this)
    export("$pref::*", %prefPath @ "/clientPrefs." @ $TorqueScriptFileExtension, false);
    
    OptionsMenu.unappliedChanges.empty();
-   
-   //Now we can back out of the options menu
-   OptionsMenu.doOptionsMenuBackOut();
 }
 
 function OptionsMenu::resetToDefaults(%this)
@@ -346,7 +372,9 @@ function populateDisplaySettingsList()
    
    OptionsMenu.currentCategory = "Display";
    
+   if(isObject(OptionName))
    OptionName.setText("");
+   if(isObject(OptionDescription))
    OptionDescription.setText("");
    
    %apiList = "";
@@ -433,7 +461,9 @@ function populateGraphicsSettingsList()
    
    OptionsMenu.currentCategory = "Graphics";
    
+   if(isObject(OptionName))
    OptionName.setText("");
+   if(isObject(OptionDescription))
    OptionDescription.setText("");
    
    %yesNoList = "No\tYes";
@@ -598,7 +628,9 @@ function populateAudioSettingsList()
    
    OptionsMenu.currentCategory = "Audio";
    
+   if(isObject(OptionName))
    OptionName.setText("");
+   if(isObject(OptionDescription))
    OptionDescription.setText("");
    
    %buffer = sfxGetAvailableDevices();
@@ -691,7 +723,9 @@ function populateKeyboardMouseSettingsList()
    
    OptionsMenu.currentCategory = "Keyboard & Mouse";
    
+   if(isObject(OptionName))
    OptionName.setText("");
+   if(isObject(OptionDescription))
    OptionDescription.setText("");
    
    $remapListDevice = "keyboard";
@@ -706,7 +740,9 @@ function populateGamepadSettingsList()
    
    OptionsMenu.currentCategory = "Gamepad";
    
+   if(isObject(OptionName))
    OptionName.setText("");
+   if(isObject(OptionDescription))
    OptionDescription.setText("");
    
    $remapListDevice = "gamepad";
@@ -723,48 +759,6 @@ function OptionsMenuList::activateRow(%this)
    OptionsMenuSettingsList.setFirstResponder();
 }
 
-function OptionsMenu::backOut(%this)
-{
-   if(OptionsMenuSettingsList.isActiveMenuList())
-   {
-      OptionsMenuCategoryList.setAsActiveMenuList();
-      %this.updateSelectButton();
-   }
-   else
-   {
-      if(%this.unappliedChanges.count() != 0)
-      {
-         MessageBoxOKCancel("Discard Changes?", "You have unapplied changes to your settings, do you wish to apply or discard them?", "OptionsMenu.apply();", "OptionsMenu.doOptionsMenuBackOut();", "Apply", "Discard");
-      }
-      else
-      {
-         %this.doOptionsMenuBackOut();
-      }
-   }
-}
-
-function OptionsMenu::doOptionsMenuBackOut(%this)
-{
-   //save the settings and then back out
-   if(OptionsMain.hidden == false)
-   {
-      //we're not in a specific menu, so we're actually exiting
-      Canvas.popDialog(OptionsMenu);
-
-      if(isObject(OptionsMenu.returnGui) && OptionsMenu.returnGui.isMethod("onReturnTo"))
-         OptionsMenu.returnGui.onReturnTo();
-   }
-   else
-   {
-      OptionsMain.hidden = false;
-      ControlsMenu.hidden = true;
-      GraphicsMenu.hidden = true;
-      CameraMenu.hidden = true;
-      AudioMenu.hidden = true;
-      ScreenBrightnessMenu.hidden = true;
-   }
-}
-
 function OptionsMenuSettingsList::setRowEnabled(%this, %row, %status)
 {
    %option = %this.getObject(%row);
@@ -955,16 +949,25 @@ function getDisplayDeviceName()
 //
 function MenuOptionsButton::onMouseEnter(%this)
 {
+   if(isObject(OptionName))
    OptionName.setText(%this.getLabel());
+   if(isObject(OptionDescription))
    OptionDescription.setText(%this.getToolTip());
 }
 
 function MenuOptionsButton::onMouseLeave(%this)
 {
+   if(isObject(OptionName))
    OptionName.setText("");
+   if(isObject(OptionDescription))
    OptionDescription.setText("");
 }
 
+function MenuOptionsButton::onHighlighted(%this, %state)
+{
+   MenuListButton::onHighlighted(%this, %state);
+}
+
 function MenuOptionsButton::onChange(%this)
 {
    %optionMode = %this.getMode();

+ 87 - 102
Templates/BaseGame/game/data/UI/guis/pauseMenu.gui

@@ -1,178 +1,163 @@
 //--- OBJECT WRITE BEGIN ---
 $guiContent = new GuiControl(PauseMenu) {
-   position = "0 0";
    extent = "1024 768";
-   minExtent = "8 2";
-   horizSizing = "right";
-   vertSizing = "bottom";
    profile = "GuiDefaultProfile";
-   visible = "1";
-   active = "1";
    tooltipProfile = "GuiToolTipProfile";
-   hovertime = "1000";
    isContainer = "1";
-   canSave = "1";
+   superClass = "UINavigation";
    canSaveDynamicFields = "1";
-      tamlReader = "19772";
-      tile = "0";
-      useVariable = "0";
 
    new GuiChunkedBitmapCtrl(PauseMenuBG) {
-      bitmapAsset = "UI:hudfill_image";
-      useVariable = "0";
-      tile = "0";
-      position = "0 0";
+      BitmapAsset = "UI:hudfill_image";
       extent = "1024 768";
-      minExtent = "8 2";
       horizSizing = "width";
       vertSizing = "height";
       profile = "GuiDefaultProfile";
-      visible = "1";
-      active = "1";
       tooltipProfile = "GuiToolTipProfile";
-      hovertime = "1000";
       isContainer = "1";
-      canSave = "1";
       canSaveDynamicFields = "1";
    };
    new GuiControl() {
       position = "162 125";
       extent = "700 518";
-      minExtent = "8 2";
       horizSizing = "center";
       vertSizing = "center";
       profile = "GuiDefaultProfile";
-      visible = "1";
-      active = "1";
       tooltipProfile = "GuiToolTipProfile";
-      hovertime = "1000";
       isContainer = "1";
-      canSave = "1";
-      canSaveDynamicFields = "0";
       
       new GuiStackControl(PauseMenuList) {
-         stackingType = "Vertical";
-         horizStacking = "Left to Right";
-         vertStacking = "Top to Bottom";
          padding = "15";
          dynamicSize = "0";
-         dynamicNonStackExtent = "0";
-         dynamicPos = "0";
-         changeChildSizeToFit = "1";
-         changeChildPosition = "1";
-         position = "0 0";
          extent = "700 320";
-         minExtent = "16 16";
          horizSizing = "center";
          vertSizing = "center";
          profile = "GuiDefaultProfile";
-         visible = "1";
-         active = "1";
          tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "1";
-         canSave = "1";
-         canSaveDynamicFields = "0";
-         class = "MenuList";
+         superClass = "MenuList";
+
+         new GuiButtonCtrl() {
+            text = "Options";
+            extent = "700 55";
+            profile = "GuiMenuButtonProfile";
+            command = "openPauseMenuOptions();";
+            tooltipProfile = "GuiToolTipProfile";
+         };
+         new GuiButtonCtrl() {
+            text = "Exit to Menu";
+            position = "0 70";
+            extent = "700 55";
+            profile = "GuiMenuButtonProfile";
+            command = "pauseMenuExitToMenu();";
+            tooltipProfile = "GuiToolTipProfile";
+         };
+         new GuiButtonCtrl() {
+            text = "Exit to Desktop";
+            position = "0 140";
+            extent = "700 55";
+            profile = "GuiMenuButtonProfile";
+            command = "pauseMenuExitToDesktop();";
+            tooltipProfile = "GuiToolTipProfile";
+         };
       };
    };
    new GuiControl(PauseButtonHolder) {
-      position = "189 711";
-      extent = "646 40";
-      minExtent = "8 2";
+      position = "144 711";
+      extent = "736 40";
       horizSizing = "center";
       vertSizing = "top";
       profile = "GuiDefaultProfile";
-      visible = "1";
-      active = "1";
       tooltipProfile = "GuiToolTipProfile";
-      hovertime = "1000";
       isContainer = "1";
       class = "MenuInputButtonContainer";
-      canSave = "1";
-      canSaveDynamicFields = "0";
 
       new GuiIconButtonCtrl() {
-         buttonMargin = "4 4";
-         iconBitmap = "data/ui/images/Inputs/Keyboard & Mouse/Keyboard_Black_Enter";
-         iconLocation = "Left";
+         BitmapAsset = "UI:Keyboard_Black_Return_image";
+         sizeIconToButton = "1";
+         makeIconSquare = "1";
+         textLocation = "Right";
+         position = "11 0";
+         extent = "140 40";
+         profile = "GuiMenuButtonProfile";
+         visible = "0";
+         active = "0";
+         tooltipProfile = "GuiToolTipProfile";
+         internalName = "button1";
+         class = "MenuInputButton";
+         hidden = "1";
+      };
+      new GuiIconButtonCtrl() {
+         BitmapAsset = "UI:Keyboard_Black_Return_image";
+         sizeIconToButton = "1";
+         makeIconSquare = "1";
+         textLocation = "Right";
+         position = "155 0";
+         extent = "140 40";
+         profile = "GuiMenuButtonProfile";
+         visible = "0";
+         active = "0";
+         tooltipProfile = "GuiToolTipProfile";
+         internalName = "button2";
+         class = "MenuInputButton";
+         hidden = "1";
+      };
+      new GuiIconButtonCtrl() {
+         BitmapAsset = "UI:Keyboard_Black_Return_image";
          sizeIconToButton = "1";
          makeIconSquare = "1";
          textLocation = "Right";
-         textMargin = "4";
-         autoSize = "0";
-         text = "OK";
-         groupNum = "-1";
-         buttonType = "PushButton";
-         useMouseEvents = "0";
-         position = "363 0";
+         position = "299 0";
          extent = "140 40";
-         minExtent = "8 2";
-         horizSizing = "right";
-         vertSizing = "bottom";
          profile = "GuiMenuButtonProfile";
-         visible = "1";
-         active = "1";
-         command = "PauseMenuList.activateRow();";
+         visible = "0";
+         active = "0";
          tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "0";
-         internalName = "goButton";
+         internalName = "button3";
          class = "MenuInputButton";
-         canSave = "1";
-         canSaveDynamicFields = "0";
+         hidden = "1";
       };
       new GuiIconButtonCtrl() {
-         buttonMargin = "4 4";
-         iconBitmap = "data/ui/images/Inputs/Keyboard & Mouse/Keyboard_Black_Esc";
-         iconLocation = "Left";
+         BitmapAsset = "UI:Keyboard_Black_Return_image";
          sizeIconToButton = "1";
          makeIconSquare = "1";
          textLocation = "Right";
-         textMargin = "4";
-         autoSize = "0";
-         text = "Back";
-         groupNum = "-1";
-         buttonType = "PushButton";
-         useMouseEvents = "0";
-         position = "507 0";
+         position = "443 0";
          extent = "140 40";
-         minExtent = "8 2";
-         horizSizing = "right";
-         vertSizing = "bottom";
          profile = "GuiMenuButtonProfile";
-         visible = "1";
-         active = "1";
-         command = "Canvas.popDialog();";
+         visible = "0";
+         active = "0";
          tooltipProfile = "GuiToolTipProfile";
-         hovertime = "1000";
-         isContainer = "0";
-         internalName = "backButton";
+         internalName = "button4";
          class = "MenuInputButton";
-         canSave = "1";
-         canSaveDynamicFields = "0";
+         hidden = "1";
+      };
+      new GuiIconButtonCtrl() {
+         BitmapAsset = "UI:Keyboard_Black_Return_image";
+         sizeIconToButton = "1";
+         makeIconSquare = "1";
+         textLocation = "Right";
+         position = "587 0";
+         extent = "140 40";
+         profile = "GuiMenuButtonProfile";
+         visible = "0";
+         active = "0";
+         tooltipProfile = "GuiToolTipProfile";
+         internalName = "button5";
+         class = "MenuInputButton";
+         hidden = "1";
       };
    };
    new GuiInputCtrl(PauseMenuInputHandler) {
-      class = "MenuInputHandler";
       sendAxisEvents = "1";
       sendBreakEvents = "1";
-      sendModifierEvents = "0";
       ignoreMouseEvents = "1";
-      lockMouse = "0";
       position = "-50 0";
       extent = "10 10";
-      minExtent = "8 2";
       horizSizing = "width";
       vertSizing = "height";
       profile = "GuiInputCtrlProfile";
-      visible = "1";
-      active = "1";
       tooltipProfile = "GuiToolTipProfile";
-      hovertime = "1000";
-      isContainer = "0";
-      canSave = "1";
-      canSaveDynamicFields = "0";
+      class = "MenuInputHandler";
    };
 };
 //--- OBJECT WRITE END ---

+ 10 - 17
Templates/BaseGame/game/data/UI/guis/pauseMenu.tscript

@@ -23,6 +23,8 @@ function PauseMenu::onWake(%this)
    PauseMenuList.setAsActiveMenuList();
    PauseButtonHolder.setActive();
    PauseMenuInputHandler.setFirstResponder();
+   
+   %this.resizePages = true;
 }
 
 
@@ -35,37 +37,28 @@ function PauseMenu::onSleep(%this)
    }
 }
 
-function PauseMenu::onReturnTo(%this)
-{
-   PauseMenuList.hidden = false;
-   PauseMenuList.setAsActiveMenuList();
-   PauseButtonHolder.setActive();
-   PauseMenuInputHandler.setFirstResponder();
-}
-
 function openPauseMenuOptions()
 {
-   Canvas.pushDialog(OptionsMenu);
-   OptionsMenu.returnGui = PauseMenu; 
-   PauseMenuList.hidden = true;
+   PauseMenu.pushPage(OptionsMenu);
 }
 
 function pauseMenuExitToMenu()
 {
-   PauseMenuList.hidden = true;
-   MessageBoxOKCancel("Exit?", "Do you wish to exit to the Main Menu?", "escapeFromGame();", "PauseMenu.onReturnTo();");
+   MessageBoxOKCancel("Exit?", "Do you wish to exit to the Main Menu?", "escapeFromGame();", "");
 }
 
 function pauseMenuExitToDesktop()
 {
-   PauseMenuList.hidden = true;
-   MessageBoxOKCancel("Exit?", "Do you wish to exit to the desktop?", "quit();", "PauseMenu.onReturnTo();");
+   MessageBoxOKCancel("Exit?", "Do you wish to exit to the desktop?", "quit();", "");
 }
 
 function PauseButtonHolder::onWake(%this)
 {
-   %this-->goButton.set("btn_a", "Return", "OK", "PauseMenuList.activate();", true);
-   %this-->backButton.set("btn_b", "Escape", "Back", "Canvas.popDialog();");
+   %this-->button1.disable();
+   %this-->button2.disable();
+   %this-->button3.disable();
+   %this-->button4.set("btn_a", "", "OK", "PauseMenuList.activate();");
+   %this-->button4.set("btn_b", "Escape", "Back", "Canvas.popDialog();");
 }
 
 function PauseMenu::addPauseMenuButton(%this, %buttonText, %buttonCallback)

BIN
Templates/BaseGame/game/data/UI/images/Inputs/Keyboard & Mouse/Keyboard_Black_Mouse_Left.png


BIN
Templates/BaseGame/game/data/UI/images/Inputs/Keyboard & Mouse/Keyboard_Black_Mouse_Middle.png


BIN
Templates/BaseGame/game/data/UI/images/Inputs/Keyboard & Mouse/Keyboard_Black_Mouse_Right.png


+ 203 - 26
Templates/BaseGame/game/data/UI/scripts/menuInputHandling.tscript

@@ -26,18 +26,30 @@ btn_start = Start
 btn_back = Back/Select
 */
 
+//==============================================================================
+/// Summary:
 /// This is used with the main UI menu lists, when a non-axis input event is called
 /// such as pressing a button
 /// It is called from the engine
+/// 
+/// \param %device (string) The name of the device the input event is coming fromt
+/// \param %action (string) The specific key/input action
+/// \param %state (bool) The down/up state of the event sent
 function UIMenuButtonList::onInputEvent(%this, %device, %action, %state)
 {
    if(%state)
       $activeMenuButtonContainer.processInputs(%device, %action);
 }
 
+//==============================================================================
+/// Summary:
 /// This is used with the main UI menu lists, when an axis input event is called
 /// such as moving a joystick
 /// It is called from the engine
+/// 
+/// \param %device (string) The name of the device the input event is coming fromt
+/// \param %action (string) The specific key/input action
+/// \param %axisVal (float) The float value of the axis event
 function UIMenuButtonList::onAxisEvent(%this, %device, %action, %axisVal)
 {
    //Skip out of the value is too low as it could just be noise or miscalibrated defaults
@@ -47,6 +59,8 @@ function UIMenuButtonList::onAxisEvent(%this, %device, %action, %axisVal)
    $activeMenuButtonContainer.processAxisEvent(%device, %action);
 }
 
+//==============================================================================
+/// Summary:
 /// Sets the command and text for the specified button. If %text and %command
 /// are left empty, the button will be disabled and hidden.
 ///
@@ -54,32 +68,57 @@ function UIMenuButtonList::onAxisEvent(%this, %device, %action, %axisVal)
 /// \param %keyboardButton (string) The button to set for when using keyboard/mouse input.
 /// \param %text (string) The text to display next to the A button graphic.
 /// \param %command (string) The command executed when the A button is pressed.
-/// \param %gamepadOnly (bool) If true, will only show the button when working in the gamepad input mode
-function MenuInputButton::set(%this, %gamepadButton, %keyboardButton, %text, %command, %gamepadOnly)
+function MenuInputButton::set(%this, %gamepadButton, %keyboardButton, %text, %command)
 {
+   %this.setHidden(false);
+   
    %set = (! ((%text $= "") && (%command $= "")));
-   %this.setText(%text);
-   %this.setActive(%set);
-   %this.setVisible(%set);
    
    %this.gamepadButton = %gamepadButton;
    %this.keyboardButton = %keyboardButton;
    
-   if(%gamepadOnly $= "")
-      %gamepadOnly = false;
+   if(%gamepadButton $= "")
+      %this.gamepadValid = false;
+   else
+      %this.gamepadValid = true;
       
-   %this.gamepadOnly = %gamepadOnly;
+   if(%keyboardButton $= "")
+      %this.kbmValid = false;
+   else
+      %this.kbmValid = true;
 
+   if((!%this.kbmValid && $activeControllerType !$= "gamepad") ||
+      (!%this.gamepadValid && $activeControllerType $= "gamepad"))
+      %set = false;
+      
+   %this.setText(%text);
    %this.Command = %command;
+   
+   %this.refresh();
+}
+
+//==============================================================================
+/// Summary:
+/// Disables the MenuInputButton, marking it as not to consume inputs or display
+function MenuInputButton::disable(%this)
+{
+   %this.setText("");
+   %this.Command = "";
+   %this.setActive(false);
+   %this.setVisible(false);
 }
 
+//==============================================================================
+/// Summary:
 /// Refreshes the specific button, updating it's visbility status and the displayed input image
 function MenuInputButton::refresh(%this)
 {
    %set = (! ((%this.text $= "") && (%this.command $= "")));
    
-   //Special-case of where we're in keyboard+mouse mode, but the menubutton is gamepad only mode, so we early out
-   if(%this.gamepadOnly && $activeControllerType !$= "gamepad")
+   //Do a check so if a MenuInput is selectively bound and we're not using the
+   //matched input type, then we skip
+   if((!%this.kbmValid && $activeControllerType !$= "gamepad") ||
+      (!%this.gamepadValid && $activeControllerType $= "gamepad"))
       %set = false;
       
    %this.setActive(%set);
@@ -183,6 +222,8 @@ function MenuInputButton::refresh(%this)
    return true;
 }
 
+//==============================================================================
+/// Summary:
 /// Refreshes a menu input container, updating the buttons inside it
 function MenuInputButtonContainer::refresh(%this)
 {
@@ -195,6 +236,8 @@ function MenuInputButtonContainer::refresh(%this)
    }
 }
 
+//==============================================================================
+/// Summary:
 /// Sets the given MenuInputButtonContainer as the active one. This directs input events
 /// to it's buttons, ensures it's visible, and auto-hides the old active container if it was set
 function MenuInputButtonContainer::setActive(%this)
@@ -207,6 +250,8 @@ function MenuInputButtonContainer::setActive(%this)
    $activeMenuButtonContainer.refresh();
 }
 
+//==============================================================================
+/// Summary:
 /// Checks the input manager for if we have a gamepad active and gets it's name
 /// If we have one, also sets the active input type to gamepad
 function MenuInputButtonContainer::checkGamepad(%this)
@@ -221,12 +266,17 @@ function MenuInputButtonContainer::checkGamepad(%this)
       $activeControllerType = "gamepad";     
 }
    
+   //==============================================================================
+/// Summary:
 /// This is called by the earlier inputs callback that comes from the menu list
 /// this allows us to first check what the input type is, and if the device is different
 /// (such as going from keyboard and mouse to gamepad) we can refresh the buttons to update
 /// the display
 /// Then we process the input to see if it matches to any of the button maps for our 
 /// MenuInputButtons. If we have a match, we execute it's command.
+///
+/// \param %device (string) The device that is causing the input event
+/// \param %action (string) The name of the input action
 function MenuInputButtonContainer::processInputs(%this, %device, %action)
 {
    //check to see if our status has changed
@@ -285,10 +335,16 @@ function MenuInputButtonContainer::processInputs(%this, %device, %action)
    }
 }
 
+//==============================================================================
+/// Summary:
 /// This is called by the earlier inputs callback that comes from the menu list
 /// this allows us to first check what the input type is, and if the device is different
 /// (such as going from keyboard and mouse to gamepad) we can refresh the buttons to update
 /// the display
+/// 
+/// \param %device (string) The name of the device the input event is coming fromt
+/// \param %action (string) The specific key/input action
+/// \param %axisVal (float) The float value of the axis event
 function MenuInputButtonContainer::processAxisEvent(%this, %device, %action, %axisVal)
 {
    //check to see if our status has changed
@@ -347,6 +403,15 @@ function onSDLDeviceDisconnected(%sdlIndex)
 // This'll let the active menu list be navigated, as well as buttons be processed
 // and ultimately handled by the Input Buttons above
 //==============================================================================
+//==============================================================================
+/// Summary:
+/// This is used with the main UI menu lists, when an axis input event is called
+/// such as moving a joystick
+/// It is called from the engine
+/// 
+/// \param %device (string) The name of the device the input event is coming fromt
+/// \param %action (string) The specific key/input action
+/// \param %axisVal (float) The float value of the axis event
 function MenuInputHandler::onAxisEvent(%this, %device, %action, %value)
 {
    //this is to force a refresh of the menu
@@ -396,6 +461,15 @@ function MenuInputHandler::onAxisEvent(%this, %device, %action, %value)
    } 
 }
 
+//==============================================================================
+/// Summary:
+/// This is used with the main UI menu lists, when a non-axis input event is called
+/// such as pressing a button
+/// It is called from the engine
+/// 
+/// \param %device (string) The name of the device the input event is coming fromt
+/// \param %action (string) The specific key/input action
+/// \param %state (bool) The down/up state of the event sent
 function MenuInputHandler::onInputEvent(%this, %device, %action, %state)
 {
    if(%action $= "upov" || %action $= "dpov" || %action $= "lpov" || %action $= "rpov")
@@ -412,6 +486,10 @@ function MenuInputHandler::onInputEvent(%this, %device, %action, %state)
 // Menu List processing
 // These functions manage the navigation and activation of the Menu Lists
 //==============================================================================
+//==============================================================================
+/// Summary:
+/// Is the GUIContainer with this MenuList namespace the 'active' menulist as far
+/// as UI interfaces is concerned?
 function MenuList::isActiveMenuList(%this)
 {
    if($activeMenuList == %this)
@@ -420,6 +498,14 @@ function MenuList::isActiveMenuList(%this)
    return false;
 }
 
+//==============================================================================
+/// Summary:
+/// Sets the GUIContainer with this MenuList namespace as the active menulist.
+/// This means that any input events caught in MenuInputHandlers is directed at
+/// this menu list to navigate it
+///
+/// \param %startPosition (Point2F) The X and Y starting positions of the selection for this menuList
+/// \param %menuMode (string) Indicates the mode/type of menuList, allowing for special behaviors depending on type
 function MenuList::setAsActiveMenuList(%this, %startPosition, %menuMode)
 {
    if(%startPosition $= "")
@@ -430,31 +516,38 @@ function MenuList::setAsActiveMenuList(%this, %startPosition, %menuMode)
          
    $activeMenuList = %this;
    $activeMenuList.hidden = false; 
-   $activeMenuListPosition = %startPosition;
+   $activeMenuList.ListPosition = %startPosition;
    $activeMenuListMode = %menuMode;
    
    %this.refresh();
 }
 
-
+//==============================================================================
+/// Summary:
+/// Activates the currently highlighted child object
 function MenuList::activate(%this)
 {
    //check for a highlighted element
-   if($activeMenuListPosition.y > -1 && $activeMenuListPosition < $activeMenuList.getCount())
+   if($activeMenuList.ListPosition.y > -1 && $activeMenuList.ListPosition < $activeMenuList.getCount())
    {
-      %btn = $activeMenuList.getObject($activeMenuListPosition.y);
+      %btn = $activeMenuList.getObject($activeMenuList.ListPosition.y);
       %btn.performClick();
    }
 }
 
+//==============================================================================
+/// Summary:
+/// refreshes the menuList, updating children highlight status and if there is
+/// a button pointer control defined on our list, we update it's position as 
+/// needed
 function MenuList::refresh(%this)
 {
-   %selectedObject = 0;
+   %selectedObject = -1;
    for(%i=0; %i < $activeMenuList.getCount(); %i++)
    {
       %btn = $activeMenuList.getObject(%i);
       
-      %isSelected = %i == $activeMenuListPosition.y;
+      %isSelected = %i == $activeMenuList.ListPosition.y;
       
       %btn.setHighlighted(%isSelected);
       
@@ -462,8 +555,32 @@ function MenuList::refresh(%this)
          %selectedObject = %i;
    }
    
+   if(isObject(%this.buttonPointerCtrl))
+   {
+      if(%selectedObject != -1)
+      {
+         %this.buttonPointerCtrl.setHidden(false);
+         
+         %buttonCenter = $activeMenuList.getObject(%selectedObject).getGlobalCenter();
+         
+         if(%this.centerButtonPointerCtrl)
+         {
+            %this.buttonPointerCtrl.setCenter(%buttonCenter.x, %buttonCenter.y);
+         }
+         else
+         {
+            //if we're not centering, then left-justify
+            %this.buttonPointerCtrl.setCenter(%buttonCenter.x - $activeMenuList.getObject(%selectedObject).extent.x / 2, %buttonCenter.y);  
+         }
+      }
+      else
+      {
+         %this.buttonPointerCtrl.setHidden(true);
+      }
+   }
+   
    if($activeMenuList.isMethod("onNavigate"))
-      $activeMenuList.onNavigate($activeMenuListPosition.y);
+      $activeMenuList.onNavigate($activeMenuList.ListPosition.y);
    
    %parent = $activeMenuList.getParent();
    if(%parent.getClassName() $= "GuiScrollCtrl")
@@ -472,31 +589,43 @@ function MenuList::refresh(%this)
    }
 }
 
+//==============================================================================
+/// Summary:
+/// Selects the next 'up' child item in the menuList. If the current is the topmost
+/// then nothing happens
 function MenuList::navigateUp(%this)
 {
-   $activeMenuListPosition.y -= 1;
-   if($activeMenuListPosition.y < 0)
-      $activeMenuListPosition.y = 0;
+   $activeMenuList.ListPosition.y -= 1;
+   if($activeMenuList.ListPosition.y < 0)
+      $activeMenuList.ListPosition.y = 0;
       
    %this.refresh();
 }
 
+//==============================================================================
+/// Summary:
+/// Selects the next 'down' child item in the menuList. If the current is the bottommost
+/// then nothing happens
 function MenuList::navigateDown(%this)
 {
-   $activeMenuListPosition.y += 1;
-   if($activeMenuListPosition.y >= $activeMenuList.getCount())
-      $activeMenuListPosition.y = $activeMenuList.getCount()-1;
+   $activeMenuList.ListPosition.y += 1;
+   if($activeMenuList.ListPosition.y >= $activeMenuList.getCount())
+      $activeMenuList.ListPosition.y = $activeMenuList.getCount()-1;
       
    %this.refresh();
 }
 
+//==============================================================================
+/// Summary:
+/// Selects the next 'left' child item in the menuList. If the current item is the leftmost
+/// then nothing happens
 function MenuList::navigateLeft()
 {
    //Atm, we're only handling specific control types, namely options entries, but
    //this could readily be expanded upon to handle grids like for inventory screens
    //or the like
     
-   %btn = $activeMenuList.getObject($activeMenuListPosition.y);
+   %btn = $activeMenuList.getObject($activeMenuList.ListPosition.y);
    if(%btn.getClassName() $= "GuiGameSettingsCtrl" && %btn.isEnabled())
    {
       %mode = %btn.getMode();
@@ -520,9 +649,13 @@ function MenuList::navigateLeft()
    }
 }
 
+//==============================================================================
+/// Summary:
+/// Selects the next 'right' child item in the menuList. If the current item is the rightmost
+/// then nothing happens
 function MenuList::navigateRight()
 {
-   %btn = $activeMenuList.getObject($activeMenuListPosition.y);
+   %btn = $activeMenuList.getObject($activeMenuList.ListPosition.y);
    if(%btn.getClassName() $= "GuiGameSettingsCtrl" && %btn.isEnabled())
    {
       %mode = %btn.getMode();
@@ -546,7 +679,51 @@ function MenuList::navigateRight()
    }
 }
 
+//==============================================================================
+/// Summary:
+/// Gets the current vertical positionally selected child object
 function MenuList::getActiveRow(%this)
 {
-   return $activeMenuListPosition.y;
+   return $activeMenuList.ListPosition.y;
+}
+
+//==============================================================================
+/// Summary:
+/// Called from the engine when a GUIButtonBase-derived class with MenuListButton namespace class
+/// has its highlighting status changed. Allows us to react to this change of state and trigger refreshse
+/// or other events to keep the navigation tracking up to date
+///
+/// \param %state (bool) The on/off state of the button being highlighted
+function MenuListButton::onHighlighted(%this, %state)
+{
+   echo("MenuListButton::onHighlighted() - " @ %this.internalName @ " was " @ %state @ " highlighted");
+   %parentContainer = %this.getParent();
+   if(%parentContainer.class $= "MenuList" || %parentContainer.superClass $= "MenuList")
+   {
+      if(isObject(%parentContainer.buttonPointerCtrl))
+      {
+         if(%state)
+         {
+	         %parentContainer.buttonPointerCtrl.setHidden(false);
+	         
+	         %buttonCenter = %this.getGlobalCenter();
+            echo("   - button center:" @ %buttonCenter);
+	         
+	         if(%parentContainer.centerButtonPointerCtrl)
+	         {
+	               %parentContainer.buttonPointerCtrl.setGlobalCenter(%buttonCenter.x, %buttonCenter.y);
+	         }
+	         else
+	         {
+	            //if we're not centering, then left-justify
+	            %parentContainer.buttonPointerCtrl.setGlobalCenter(%buttonCenter.x - %this.extent.x / 2, %buttonCenter.y);  
+	         }
+            echo("   - pointer position:" @ %parentContainer.buttonPointerCtrl.getPosition());
+	      }
+         /*else
+      {
+         %parentContainer.buttonPointerCtrl.setHidden(true);
+         }*/
+      }
+   }
 }

+ 283 - 0
Templates/BaseGame/game/data/UI/scripts/menuNavigation.tscript

@@ -0,0 +1,283 @@
+//==============================================================================
+/// Summary:
+/// This function sets the root page for the navigation stack. The root page is 'below'
+/// all other normal pages and cannot be popped like a normal page.
+/// When we set a new root page, we first check if we have an existing root page.
+/// If we do, we run the usual canClose() then onClose() function pair, then we 
+/// set it and call the onOpen() for the new root page.
+/// 
+/// \param %rootPage (guiControl) The new guiControl that is being set as the root page of the navigation stack
+function UINavigation::setRootPage(%this, %rootPage)
+{
+   if(!isObject(%this.pageStack))
+   {
+      %this.pageStack = new ArrayObject();  
+   }
+   
+   if(isObject(%this.rootPage))
+   {
+      %canClose = true;
+      if(%this.rootPage.isMethod("canClose"))
+         %canClose = %this.rootPage.call("canClose");
+         
+      if(!%canClose)
+         return; //if we're not allowed to close, just bail out wholesale because clearly 
+                  //something is blocking changes to pages
+         
+      %this.remove(%this.rootPage);
+      if(%this.rootPage.isMethod("onClose"))
+         %this.rootPage.call("onClose");
+         
+      %this.rootPage.navigation = "";
+   }
+      
+   %this.rootPage = %rootPage;
+   
+   %this.add(%rootPage);
+   if(%this.resizePages)
+   {
+      %rootPage.resize(%this.position.x, %this.position.y, 
+         %this.extent.x, %this.extent.y);
+   }
+   %rootPage.navigation = %this;
+   
+   if(%rootPage.isMethod("onOpen"))
+      %rootPage.call("onOpen");
+}
+
+//==============================================================================
+/// Summary:
+/// This function pushes a page onto the given UINavigation-classed GUIContainer's stack
+/// The order of operations is thus:
+/// 1) check to see if the new page being pushed says it can open via the canOpen() function. 
+///    If this method is not defined, it defaults to true, as there's no impediment to continuing
+///    If this check returns false, the pushPage event cancels.
+/// 2) check to see if the current page on the stack says it can close. Similar to 
+///    the canOpen() check on the new page, we default to true
+///    If this check returns false, the pushPage event cancels.
+/// 3) Call - if defined - onClose() on the current top page of the stack
+/// 4) Add the new page onto the stack
+/// 5) Call - if defined - onOpen() on the new page
+/// 6) Finally, if we defined a callback, call that.
+/// With this all run, the previous top page has done any cleanup work it needed to
+/// and the new top page has been opened successfully.
+/// 
+/// \param %newPage (guiControl) The new guiControl that is being added onto the page stack
+/// \param %callback[optional]: (Evaluable string) A evalable statement to invoke when the push has been completed
+function UINavigation::pushPage(%this, %newPage, %callback)
+{
+   if(!isObject(%this.pageStack))
+   {
+      %this.pageStack = new ArrayObject();
+   }
+   
+   %canChange = true;
+   if(%newPage.isMethod("canOpen"))
+      %canChange = %newPage.call("canOpen");
+      
+   if(!%canChange)
+      return;
+      
+   %currentPage = %this.getCurrentPage();
+   if(isObject(%currentPage))
+   {
+      if(%currentPage.isMethod("canClose"))
+         %canChange = %currentPage.call("canClose");
+         
+      if(!%canChange)
+         return;
+         
+      if(%currentPage.isMethod("onClose"))
+         %currentPage.call("onClose");
+   }
+   
+   %this.pageStack.push_back(%newPage);
+   %this.add(%newPage);
+   if(%this.resizePages)
+   {
+      %newPage.resize(%this.position.x, %this.position.y, 
+         %this.extent.x, %this.extent.y);
+   }
+   
+   if(%newPage.isMethod("onOpen"))
+      %newPage.call("onOpen");
+   
+   %newPage.navigation = %this;
+   
+   if(%callback !$= "")
+   eval(%callback);
+}
+
+//==============================================================================
+/// Summary:
+/// This function pops the topmost page off the given UINavigation-classed GUIContainer's stack
+/// The order of operations is thus:
+/// 1) check to see if the top page being popped says it can close via the canClose() function. 
+///    If this method is not defined, it defaults to true, as there's no impediment to continuing
+///    If this check returns false, the popPage event cancels.
+/// 2) check to see if the previous page on the stack says it can open. Similar to 
+///    the canClose() check on the new page, we default to true
+///    If this check returns false, the popPage event cancels.
+/// 3) Call - if defined - onClose() on the current top page of the stack
+/// 4) Remove the top page
+/// 5) Call - if defined - onOpen() on the now topmost page
+/// 6) Finally, if we defined a callback, call that.
+/// With this all run, the previous top page has done any cleanup work it needed to
+/// and the new top page has been opened successfully.
+/// 
+/// \param %callback[optional] (Evaluable string) A evalable statement to invoke when the pop has been completed
+function UINavigation::popPage(%this, %callback)
+{
+   if(%this.pageStack.count() == 0)
+      return;
+      
+   %currentPage = %this.getCurrentPage();
+   if(isObject(%currentPage))
+   {
+      %canChange = true;
+      if(%currentPage.isMethod("canClose"))
+         %canChange = %currentPage.call("canClose");
+         
+      if(!%canChange)
+         return;
+   }
+   
+   %prevPage = %this.getPreviousPage();
+   if(isObject(%prevPage))
+   {
+      %canChange = true;
+      if(%prevPage.isMethod("canOpen"))
+         %canChange = %prevPage.call("canOpen");
+         
+      if(!%canChange)
+         return;
+   }
+      
+   if(isObject(%currentPage))
+   {
+      if(%currentPage.isMethod("onClose"))
+      {
+         %currentPage.call("onClose");
+      }    
+      
+      %this.pageStack.pop_back();
+      %this.remove(%currentPage);
+      
+      %currentPage.navigation = "";
+   }
+   
+   %newTopPage = %this.getCurrentPage();
+   if(%newTopPage.isMethod("onOpen"))
+      %newTopPage.call("onOpen");
+   
+   if(%callback !$= "")
+   eval(%callback);
+}
+
+//==============================================================================
+/// Summary:
+/// In order tops the topmost page in a loop until it has closed the entire stack,
+/// leaving only the root page
+/// 
+/// \param %callback[optional] (Evaluable String) A evalable statement to invoke when the pop has been completed
+function UINavigation::popToRoot(%this, %callback)
+{
+   %pageChanged = false;
+   while(%this.getPageCount() != 0)
+   {
+      %currentPage = %this.getCurrentPage();
+      if(isObject(%currentPage))
+      {
+         if(%currentPage.isMethod("canClose"))
+            %canChange = %currentPage.call("canClose");
+            
+         if(!%canChange)
+            return;
+      }
+      
+      %prevPage = %this.getPreviousPage();
+      if(isObject(%prevPage))
+      {
+         if(%prevPage.isMethod("canOpen"))
+            %canChange = %prevPage.call("canOpen");
+            
+         if(!%canChange)
+            return;
+      }
+         
+      if(isObject(%currentPage))
+      {
+         if(%currentPage.isMethod("onClose"))
+         {
+            %currentPage.call("onClose");
+         }    
+
+         %this.pageStack.pop_back();
+         %this.remove(%currentPage);
+         
+         %currentPage.navigation = "";
+      }
+      
+      %newTopPage = %this.getCurrentPage();
+      if(%newTopPage.isMethod("onOpen"))
+         %newTopPage.call("onOpen");
+         
+      %pageChanged = true;
+   }
+   
+   if(%pageChanged && %callback !$= "")
+      eval(%callback);
+}
+
+//==============================================================================
+/// Summary:
+/// Gets the current, topmost page on the stack. If no non-root pages are on the stack
+/// the root page is returned
+function UINavigation::getCurrentPage(%this)
+{
+   if(isObject(%this.pageStack) && %this.pageStack.count() != 0)
+   {
+      return %this.pageStack.getKey(%this.pageStack.count()-1);
+   }
+   else
+   {
+      if(isObject(%this.rootPage))
+         return %this.rootPage;
+   }
+   
+   return 0;
+}
+
+//==============================================================================
+/// Summary:
+/// Gets the page just under the topmost page in the stack. If there is no previous page
+/// then the root page is returned
+function UINavigation::getPreviousPage(%this)
+{
+   if(isObject(%this.pageStack) && %this.pageStack.count() > 1)
+   {
+      return %this.pageStack.getKey(%this.pageStack.count()-2);
+   }
+   else
+   {
+      if(isObject(%this.rootPage))
+         return %this.rootPage;
+   }
+   
+   return 0;
+}   
+
+//==============================================================================
+/// Summary:
+/// Gets the number of pages on the stack.
+function UINavigation::getPageCount(%this)
+{
+   %count = 0;
+   if(isObject(%this.pageStack))
+      %count = %this.pageStack.count();
+      
+   if(isObject(%this.rootPage))
+      %count++;
+      
+   return %count;
+}

+ 61 - 0
Templates/BaseGame/game/data/UI/tools/creator.tscript

@@ -0,0 +1,61 @@
+function UI::loadModuleCreatorClasses(%this)
+{
+   AssetBrowser.beginCreatorGroup( "BaseUI", "GuiEditor" );
+      AssetBrowser.addCreatorClass("GuiContainer",  "UINavigation Container", "UINavContainer" );
+      AssetBrowser.addCreatorClass("GuiContainer",  "Menu List", "GUIMenuList" );
+      AssetBrowser.addCreatorClass("GuiStackControl",  "Stack Menu List", "GuiStackMenuList" );
+      AssetBrowser.addCreatorClass("GuiContainer",  "Menu Input Button Handler", "MenuInputBtnHandler" );
+      AssetBrowser.addCreatorClass("GuiIconButtonCtrl",  "Menu Input Button", "MenuInputBtn" );
+   AssetBrowser.endCreatorGroup();
+}
+
+
+function ObjectBuilderGui::buildUINavContainer(%this)
+{
+   %ctrl = new GuiContainer()
+   {
+      superClass = "UINavigation";
+   };
+   
+   return %ctrl;
+}
+
+function ObjectBuilderGui::buildGUIMenuList(%this)
+{
+   %ctrl = new GuiContainer()
+   {
+      superClass = "MenuList";
+   };
+   
+   return %ctrl;
+}
+
+function ObjectBuilderGui::builduiStackMenuList(%this)
+{
+   %ctrl = new GuiStackControl()
+   {
+      superClass = "MenuList";
+   };
+   
+   return %ctrl;
+}
+
+function ObjectBuilderGui::buildMenuInputBtnHandler(%this)
+{
+   %ctrl = new GuiContainer()
+   {
+      class = "MenuInputButtonContainer";
+   };
+   
+   return %ctrl;
+}
+
+function ObjectBuilderGui::buildMenuInputBtn(%this)
+{
+   %ctrl = new GuiIconButtonCtrl()
+   {
+      class = "MenuInputButton";
+   };
+   
+   return %ctrl;
+}

+ 7 - 0
Templates/BaseGame/game/tools/assetBrowser/scripts/assetBrowser.tscript

@@ -2517,7 +2517,14 @@ function GuiEditor::onControlDropped(%this, %payload, %position)
    else
    {
       %className = %payload.assetName;
+      if(%payload.altCommand !$= "")
+      {
+         %cmd = %payload.altCommand;
+      }
+      else
+      {
       %cmd = "return new " @ %className @ "();";
+      }
       %ctrl = eval( %cmd );
    }
 

+ 10 - 1
Templates/BaseGame/game/tools/assetBrowser/scripts/creator.tscript

@@ -130,6 +130,8 @@ function AssetBrowser::loadCreatorClasses(%this)
    %this.creatorClassArray.sort(true);
    
    %guiClasses.delete();
+   
+   callOnModules("loadModuleCreatorClasses");
 }
 
 function AssetBrowser::beginCreatorGroup(%this, %group, %editor)
@@ -185,7 +187,14 @@ function AssetBrowser::addCreatorClass(%this, %class, %name, %buildfunc)
       %cmd = "ObjectBuilderGui.build" @ %buildfunc @ "();";
    }
 
-   %buildfunc = "ObjectBuilderGui.newObjectCallback = \"AssetBrowser.onFinishCreateObject\"; ObjectCreator.createObject( \"" @ %cmd @ "\" );";
+   if(GuiEditorIsActive())
+   {
+      %buildfunc = "return " @ %cmd;
+   }
+   else
+   {
+      %buildfunc = "ObjectBuilderGui.newObjectCallback = \"AssetBrowser.onFinishCreateObject\"; ObjectCreator.createObject( \"" @ %cmd @ "\" );";
+   }
    
    %args = new ScriptObject();
    %args.val[0] = %class;