浏览代码

Adds proper documentation and explains some of the navigation/menu usage behavior via the BaseUI example menus

JeffR 3 年之前
父节点
当前提交
07b3e2789e

+ 50 - 1
Templates/BaseGame/game/data/UI/guis/MainMenuButtons.tscript

@@ -6,19 +6,52 @@ function MainMenuButtons::onSleep(%this)
 {
 }
 
-//Optional, as the check defaults to true, but here as an example case
+//==============================================================================
+// 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();
 }
@@ -34,6 +67,7 @@ function MainMenuButtonList::onClose(%this)
 {
 }
 
+//Our actual commands when we activate the buttons
 function openSinglePlayerMenu()
 {
    $pref::HostMultiPlayer=false;
@@ -43,16 +77,31 @@ function openSinglePlayerMenu()
 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);
 }
 

+ 0 - 2
Templates/BaseGame/game/data/UI/guis/chooseLevelDlg.tscript

@@ -102,8 +102,6 @@ function ChooseLevelDlg::onOpen(%this)
    else
       LevelSelectTitle.setText("CREATE SERVER");
    
-   ChooseLevelButtonHolder.setActive();
-
    $activeMenuButtonContainer-->button1.disable();
    $activeMenuButtonContainer-->button2.disable();
    $activeMenuButtonContainer-->button3.disable();

+ 28 - 1
Templates/BaseGame/game/data/UI/guis/mainMenu.tscript

@@ -5,17 +5,44 @@ function MainMenuGui::onAdd(%this)
 
 function MainMenuGui::onWake(%this)
 {
+   //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();
    
+   //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)
 {
-   //clean slate
+   //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();

+ 12 - 0
Templates/BaseGame/game/data/UI/guis/optionsMenu.tscript

@@ -116,8 +116,17 @@ function OptionsMenu::onOpen(%this)
    $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();
@@ -126,6 +135,9 @@ function OptionsMenu::canClose(%this)
    }
    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?", 

+ 107 - 1
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.
 ///
@@ -83,6 +97,9 @@ function MenuInputButton::set(%this, %gamepadButton, %keyboardButton, %text, %co
    %this.refresh();
 }
 
+//==============================================================================
+/// Summary:
+/// Disables the MenuInputButton, marking it as not to consume inputs or display
 function MenuInputButton::disable(%this)
 {
    %this.setText("");
@@ -91,6 +108,8 @@ function MenuInputButton::disable(%this)
    %this.setVisible(false);
 }
 
+//==============================================================================
+/// Summary:
 /// Refreshes the specific button, updating it's visbility status and the displayed input image
 function MenuInputButton::refresh(%this)
 {
@@ -203,6 +222,8 @@ function MenuInputButton::refresh(%this)
    return true;
 }
 
+//==============================================================================
+/// Summary:
 /// Refreshes a menu input container, updating the buttons inside it
 function MenuInputButtonContainer::refresh(%this)
 {
@@ -215,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)
@@ -227,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)
@@ -241,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
@@ -305,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
@@ -367,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
@@ -416,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")
@@ -432,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)
@@ -440,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 $= "")
@@ -456,7 +522,9 @@ function MenuList::setAsActiveMenuList(%this, %startPosition, %menuMode)
    %this.refresh();
 }
 
-
+//==============================================================================
+/// Summary:
+/// Activates the currently highlighted child object
 function MenuList::activate(%this)
 {
    //check for a highlighted element
@@ -467,6 +535,11 @@ function MenuList::activate(%this)
    }
 }
 
+//==============================================================================
+/// 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 = -1;
@@ -516,6 +589,10 @@ 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)
 {
    $activeMenuList.ListPosition.y -= 1;
@@ -525,6 +602,10 @@ function MenuList::navigateUp(%this)
    %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)
 {
    $activeMenuList.ListPosition.y += 1;
@@ -534,6 +615,10 @@ function MenuList::navigateDown(%this)
    %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
@@ -564,6 +649,10 @@ 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($activeMenuList.ListPosition.y);
@@ -590,13 +679,24 @@ function MenuList::navigateRight()
    }
 }
 
+//==============================================================================
+/// Summary:
+/// Gets the current vertical positionally selected child object
 function MenuList::getActiveRow(%this)
 {
    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")
    {
@@ -607,6 +707,7 @@ function MenuListButton::onHighlighted(%this, %state)
 	         %parentContainer.buttonPointerCtrl.setHidden(false);
 	         
 	         %buttonCenter = %this.getGlobalCenter();
+            echo("   - button center:" @ %buttonCenter);
 	         
 	         if(%parentContainer.centerButtonPointerCtrl)
 	         {
@@ -617,7 +718,12 @@ function MenuListButton::onHighlighted(%this, %state)
 	            //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);
+         }*/
       }
    }
 }

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

@@ -1,3 +1,12 @@
+//==============================================================================
+/// 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))
@@ -36,6 +45,25 @@ function UINavigation::setRootPage(%this, %rootPage)
       %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))
@@ -80,6 +108,24 @@ function UINavigation::pushPage(%this, %newPage, %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)
@@ -128,6 +174,12 @@ function UINavigation::popPage(%this, %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;
@@ -177,6 +229,10 @@ function UINavigation::popToRoot(%this, %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)
@@ -192,6 +248,10 @@ function UINavigation::getCurrentPage(%this)
    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)
@@ -207,6 +267,9 @@ function UINavigation::getPreviousPage(%this)
    return 0;
 }   
 
+//==============================================================================
+/// Summary:
+/// Gets the number of pages on the stack.
 function UINavigation::getPageCount(%this)
 {
    %count = 0;