2
0
Эх сурвалжийг харах

- Added logic to guiButtonBaseCtrl so if highlighted and is part of a group, will signal the siblings in the group as well
- Standardizes highlighting behavior between keybind and mouse highlighting of buttons
- Standardized onHighlighted callback for buttonBase
- Fixed handling of up/down nav with gamepad stick
- Added logic to make holding down nav keybinds iterate over buttons in menu lists

Areloch 1 жил өмнө
parent
commit
f5ab97242f

+ 182 - 158
Engine/source/gui/buttons/guiButtonBaseCtrl.cpp

@@ -31,14 +31,14 @@
 #include "sfx/sfxTrack.h"
 
 
-IMPLEMENT_CONOBJECT( GuiButtonBaseCtrl );
+IMPLEMENT_CONOBJECT(GuiButtonBaseCtrl);
 
-ConsoleDocClass( GuiButtonBaseCtrl,
+ConsoleDocClass(GuiButtonBaseCtrl,
    "@brief The base class for the various button controls.\n\n"
-   
+
    "This is the base class for the various types of button controls.  If no more specific functionality is required than "
    "offered by this class, then it can be instantiated and used directly.  Otherwise, its subclasses should be used:\n"
-   
+
    "- GuiRadioCtrl (radio buttons)\n"
    "- GuiCheckBoxCtrl (checkboxes)\n"
    "- GuiButtonCtrl (push buttons with text labels)\n"
@@ -47,51 +47,54 @@ ConsoleDocClass( GuiButtonBaseCtrl,
    "- GuiToggleButtonCtrl (toggle buttons, i.e. push buttons with \"sticky\" behavior)\n"
    "- GuiSwatchButtonCtrl (color swatch buttons)\n"
    "- GuiBorderButtonCtrl (push buttons for surrounding child controls)\n\n"
-   
+
    "@ingroup GuiButtons"
 );
 
-IMPLEMENT_CALLBACK( GuiButtonBaseCtrl, onMouseDown, void, (), (),
+IMPLEMENT_CALLBACK(GuiButtonBaseCtrl, onMouseDown, void, (), (),
    "If #useMouseEvents is true, this is called when the left mouse button is pressed on an (active) "
-   "button." );
+   "button.");
 
-IMPLEMENT_CALLBACK( GuiButtonBaseCtrl, onMouseUp, void, (), (),
+IMPLEMENT_CALLBACK(GuiButtonBaseCtrl, onMouseUp, void, (), (),
    "If #useMouseEvents is true, this is called when the left mouse button is release over an (active) "
    "button.\n\n"
    "@note To trigger actions, better use onClick() since onMouseUp() will also be called when the mouse was "
-      "not originally pressed on the button." );
+   "not originally pressed on the button.");
 
-IMPLEMENT_CALLBACK( GuiButtonBaseCtrl, onClick, void, (), (),
-   "Called when the primary action of the button is triggered (e.g. by a left mouse click)." );
+IMPLEMENT_CALLBACK(GuiButtonBaseCtrl, onClick, void, (), (),
+   "Called when the primary action of the button is triggered (e.g. by a left mouse click).");
 
-IMPLEMENT_CALLBACK( GuiButtonBaseCtrl, onDoubleClick, void, (), (),
-   "Called when the left mouse button is double-clicked on the button." );
+IMPLEMENT_CALLBACK(GuiButtonBaseCtrl, onDoubleClick, void, (), (),
+   "Called when the left mouse button is double-clicked on the button.");
 
-IMPLEMENT_CALLBACK( GuiButtonBaseCtrl, onRightClick, void, (), (),
-   "Called when the right mouse button is clicked on the button." );
+IMPLEMENT_CALLBACK(GuiButtonBaseCtrl, onRightClick, void, (), (),
+   "Called when the right mouse button is clicked on the button.");
 
-IMPLEMENT_CALLBACK( GuiButtonBaseCtrl, onMouseEnter, void, (), (),
+IMPLEMENT_CALLBACK(GuiButtonBaseCtrl, onMouseEnter, void, (), (),
    "If #useMouseEvents is true, this is called when the mouse cursor moves over the button (only if the button "
-   "is the front-most visible control, though)." );
+   "is the front-most visible control, though).");
 
-IMPLEMENT_CALLBACK( GuiButtonBaseCtrl, onMouseLeave, void, (), (),
+IMPLEMENT_CALLBACK(GuiButtonBaseCtrl, onMouseLeave, void, (), (),
    "If #useMouseEvents is true, this is called when the mouse cursor moves off the button (only if the button "
-   "had previously received an onMouseEvent() event)." );
+   "had previously received an onMouseEvent() event).");
 
-IMPLEMENT_CALLBACK( GuiButtonBaseCtrl, onMouseDragged, void, (), (),
+IMPLEMENT_CALLBACK(GuiButtonBaseCtrl, onMouseDragged, void, (), (),
    "If #useMouseEvents is true, this is called when a left mouse button drag is detected, i.e. when the user "
    "pressed the left mouse button on the control and then moves the mouse over a certain distance threshold with "
-   "the mouse button still pressed." );
+   "the mouse button still pressed.");
 
 IMPLEMENT_CALLBACK(GuiButtonBaseCtrl, onHighlighted, void, (bool highlighted), (highlighted),
-   "Called when the status of the button being highlighted changes.");
+   "This is called when the highlighted state of the button is changed.");
 
-ImplementEnumType( GuiButtonType,
+
+ImplementEnumType(GuiButtonType,
    "Type of button control.\n\n"
-   "@ingroup GuiButtons" )
-   { GuiButtonBaseCtrl::ButtonTypePush, "PushButton", "A button that triggers an action when clicked." },
-   { GuiButtonBaseCtrl::ButtonTypeCheck, "ToggleButton", "A button that is toggled between on and off state." },
-   { GuiButtonBaseCtrl::ButtonTypeRadio, "RadioButton", "A button placed in groups for presenting choices." },
+   "@ingroup GuiButtons")
+{
+   GuiButtonBaseCtrl::ButtonTypePush, "PushButton", "A button that triggers an action when clicked."
+},
+{ GuiButtonBaseCtrl::ButtonTypeCheck, "ToggleButton", "A button that is toggled between on and off state." },
+{ GuiButtonBaseCtrl::ButtonTypeRadio, "RadioButton", "A button placed in groups for presenting choices." },
 EndImplementEnumType;
 
 
@@ -102,7 +105,7 @@ GuiButtonBaseCtrl::GuiButtonBaseCtrl()
    mDepressed = false;
    mHighlighted = false;
    mActive = true;
-   static StringTableEntry sButton = StringTable->insert( "Button" );
+   static StringTableEntry sButton = StringTable->insert("Button");
    mButtonText = sButton;
    mButtonTextID = StringTable->EmptyString();
    mStateOn = false;
@@ -117,27 +120,27 @@ GuiButtonBaseCtrl::GuiButtonBaseCtrl()
 void GuiButtonBaseCtrl::initPersistFields()
 {
    docsURL;
-   addGroup( "Button" );
-   	
-      addField( "text", TypeCaseString, Offset(mButtonText, GuiButtonBaseCtrl),
-         "Text label to display on button (if button class supports text labels)." );
-      addField( "textID", TypeString, Offset(mButtonTextID, GuiButtonBaseCtrl),
-         "ID of string in string table to use for text label on button.\n\n"
-         "@see setTextID\n"
-         "@see GuiControl::langTableMod\n"
-         "@see LangTable\n\n" );
-      addField( "groupNum", TypeS32, Offset(mRadioGroup, GuiButtonBaseCtrl),
-         "Radio button toggle group number.  All radio buttons that are assigned the same #groupNum and that "
-         "are parented to the same control will synchronize their toggle state, i.e. if one radio button is toggled on "
-         "all other radio buttons in its group will be toggled off.\n\n" 
-         "The default group is -1." );
-      addField( "buttonType", TYPEID< ButtonType >(), Offset(mButtonType, GuiButtonBaseCtrl),
-         "Button behavior type.\n" );
-      addField( "useMouseEvents", TypeBool, Offset(mUseMouseEvents, GuiButtonBaseCtrl),
-         "If true, mouse events will be passed on to script.  Default is false.\n" );
-      
-   endGroup( "Button" );
-   
+   addGroup("Button");
+
+   addField("text", TypeCaseString, Offset(mButtonText, GuiButtonBaseCtrl),
+      "Text label to display on button (if button class supports text labels).");
+   addField("textID", TypeString, Offset(mButtonTextID, GuiButtonBaseCtrl),
+      "ID of string in string table to use for text label on button.\n\n"
+      "@see setTextID\n"
+      "@see GuiControl::langTableMod\n"
+      "@see LangTable\n\n");
+   addField("groupNum", TypeS32, Offset(mRadioGroup, GuiButtonBaseCtrl),
+      "Radio button toggle group number.  All radio buttons that are assigned the same #groupNum and that "
+      "are parented to the same control will synchronize their toggle state, i.e. if one radio button is toggled on "
+      "all other radio buttons in its group will be toggled off.\n\n"
+      "The default group is -1.");
+   addField("buttonType", TYPEID< ButtonType >(), Offset(mButtonType, GuiButtonBaseCtrl),
+      "Button behavior type.\n");
+   addField("useMouseEvents", TypeBool, Offset(mUseMouseEvents, GuiButtonBaseCtrl),
+      "If true, mouse events will be passed on to script.  Default is false.\n");
+
+   endGroup("Button");
+
    Parent::initPersistFields();
 }
 
@@ -145,70 +148,70 @@ void GuiButtonBaseCtrl::initPersistFields()
 
 bool GuiButtonBaseCtrl::onWake()
 {
-   if(!Parent::onWake())
+   if (!Parent::onWake())
       return false;
 
    // is we have a script variable, make sure we're in sync
-   if ( mConsoleVariable[0] )
-   	mStateOn = Con::getBoolVariable( mConsoleVariable );
-   if(mButtonTextID && *mButtonTextID != 0)
-	   setTextID(mButtonTextID);
+   if (mConsoleVariable[0])
+      mStateOn = Con::getBoolVariable(mConsoleVariable);
+   if (mButtonTextID && *mButtonTextID != 0)
+      setTextID(mButtonTextID);
 
    return true;
 }
 
 //-----------------------------------------------------------------------------
 
-void GuiButtonBaseCtrl::setText( const char* text )
+void GuiButtonBaseCtrl::setText(const char* text)
 {
    mButtonText = StringTable->insert(text, true);
 }
 
 //-----------------------------------------------------------------------------
 
-void GuiButtonBaseCtrl::setTextID(const char *id)
+void GuiButtonBaseCtrl::setTextID(const char* id)
 {
-	S32 n = Con::getIntVariable(id, -1);
-	if(n != -1)
-	{
-		mButtonTextID = StringTable->insert(id);
-		setTextID(n);
-	}
+   S32 n = Con::getIntVariable(id, -1);
+   if (n != -1)
+   {
+      mButtonTextID = StringTable->insert(id);
+      setTextID(n);
+   }
 }
 
 //-----------------------------------------------------------------------------
 
 void GuiButtonBaseCtrl::setTextID(S32 id)
 {
-	const UTF8 *str = getGUIString(id);
-	if(str)
-		setText((const char*)str);
-	//mButtonTextID = id;
+   const UTF8* str = getGUIString(id);
+   if (str)
+      setText((const char*)str);
+   //mButtonTextID = id;
 }
 
 //-----------------------------------------------------------------------------
 
-const char *GuiButtonBaseCtrl::getText()
+const char* GuiButtonBaseCtrl::getText()
 {
    return mButtonText;
 }
 
 //-----------------------------------------------------------------------------
 
-void GuiButtonBaseCtrl::setStateOn( bool bStateOn )
+void GuiButtonBaseCtrl::setStateOn(bool bStateOn)
 {
-   if(!mActive)
+   if (!mActive)
       return;
 
-   if(mButtonType == ButtonTypeCheck)
+   if (mButtonType == ButtonTypeCheck)
    {
       mStateOn = bStateOn;
    }
-   else if(mButtonType == ButtonTypeRadio)
+   else if (mButtonType == ButtonTypeRadio)
    {
       messageSiblings(mRadioGroup);
       mStateOn = bStateOn;
-   }		
+   }
    setUpdate();
 }
 
@@ -216,7 +219,7 @@ void GuiButtonBaseCtrl::setStateOn( bool bStateOn )
 
 void GuiButtonBaseCtrl::acceleratorKeyPress(U32)
 {
-   if( !mActive )
+   if (!mActive)
       return;
 
    //set the bool
@@ -230,7 +233,7 @@ void GuiButtonBaseCtrl::acceleratorKeyPress(U32)
 
 void GuiButtonBaseCtrl::acceleratorKeyRelease(U32)
 {
-   if (! mActive)
+   if (!mActive)
       return;
 
    if (mDepressed)
@@ -247,9 +250,9 @@ void GuiButtonBaseCtrl::acceleratorKeyRelease(U32)
 
 //-----------------------------------------------------------------------------
 
-void GuiButtonBaseCtrl::onMouseDown(const GuiEvent &event)
+void GuiButtonBaseCtrl::onMouseDown(const GuiEvent& event)
 {
-   if (! mActive)
+   if (!mActive)
       return;
 
    if (mProfile->mCanKeyFocus)
@@ -257,19 +260,19 @@ void GuiButtonBaseCtrl::onMouseDown(const GuiEvent &event)
 
    if (mProfile->isSoundButtonDownValid())
       SFX->playOnce(mProfile->getSoundButtonDownProfile());
-      
+
    mMouseDownPoint = event.mousePoint;
    mMouseDragged = false;
 
-   if( mUseMouseEvents )
-	  onMouseDown_callback();
+   if (mUseMouseEvents)
+      onMouseDown_callback();
 
    //lock the mouse
    mouseLock();
    mDepressed = true;
 
    // If we have a double click then execute the alt command.
-   if ( event.mouseClickCount == 2 )
+   if (event.mouseClickCount == 2)
    {
       onDoubleClick_callback();
       execAltConsoleCallback();
@@ -281,18 +284,18 @@ void GuiButtonBaseCtrl::onMouseDown(const GuiEvent &event)
 
 //-----------------------------------------------------------------------------
 
-void GuiButtonBaseCtrl::onMouseEnter(const GuiEvent &event)
+void GuiButtonBaseCtrl::onMouseEnter(const GuiEvent& event)
 {
    setUpdate();
 
-   if( mUseMouseEvents )
+   if (mUseMouseEvents)
       onMouseEnter_callback();
 
-   if(isMouseLocked())
+   if (isMouseLocked())
    {
       mDepressed = true;
       mHighlighted = true;
-      onHighlighted_callback(true);
+      onHighlighted_callback(mHighlighted);
    }
    else
    {
@@ -300,40 +303,42 @@ void GuiButtonBaseCtrl::onMouseEnter(const GuiEvent &event)
          SFX->playOnce(mProfile->getSoundButtonOverProfile());
 
       mHighlighted = true;
-      onHighlighted_callback(true);
+      messageSiblings(mRadioGroup);
+      onHighlighted_callback(mHighlighted);
    }
 }
 
 //-----------------------------------------------------------------------------
 
-void GuiButtonBaseCtrl::onMouseLeave(const GuiEvent &)
+void GuiButtonBaseCtrl::onMouseLeave(const GuiEvent&)
 {
    setUpdate();
 
-   if( mUseMouseEvents )
+   if (mUseMouseEvents)
       onMouseLeave_callback();
-   if( isMouseLocked() )
+   if (isMouseLocked())
       mDepressed = false;
    mHighlighted = false;
-   onHighlighted_callback(false);
+   onHighlighted_callback(mHighlighted);
+   messageSiblings(mRadioGroup);
 }
 
 //-----------------------------------------------------------------------------
 
-void GuiButtonBaseCtrl::onMouseUp(const GuiEvent &event)
+void GuiButtonBaseCtrl::onMouseUp(const GuiEvent& event)
 {
    mouseUnlock();
 
-   if( !mActive )
+   if (!mActive)
       return;
-   
+
    setUpdate();
 
-   if( mUseMouseEvents )
+   if (mUseMouseEvents)
       onMouseUp_callback();
 
    //if we released the mouse within this control, perform the action
-   if( mDepressed )
+   if (mDepressed)
       onAction();
 
    mDepressed = false;
@@ -342,38 +347,38 @@ void GuiButtonBaseCtrl::onMouseUp(const GuiEvent &event)
 
 //-----------------------------------------------------------------------------
 
-void GuiButtonBaseCtrl::onRightMouseUp(const GuiEvent &event)
+void GuiButtonBaseCtrl::onRightMouseUp(const GuiEvent& event)
 {
    onRightClick_callback();
-   Parent::onRightMouseUp( event );
+   Parent::onRightMouseUp(event);
 }
 
 //-----------------------------------------------------------------------------
 
-void GuiButtonBaseCtrl::onMouseDragged( const GuiEvent& event )
+void GuiButtonBaseCtrl::onMouseDragged(const GuiEvent& event)
 {
-   if( mUseMouseEvents )
+   if (mUseMouseEvents)
    {
       // If we haven't started a drag yet, find whether we have moved past
       // the tolerance value.
-      
-      if( !mMouseDragged )
+
+      if (!mMouseDragged)
       {
          Point2I delta = mMouseDownPoint - event.mousePoint;
-         if( mAbs( delta.x ) > 2 || mAbs( delta.y ) > 2 )
+         if (mAbs(delta.x) > 2 || mAbs(delta.y) > 2)
             mMouseDragged = true;
       }
-      
-      if( mMouseDragged )
+
+      if (mMouseDragged)
          onMouseDragged_callback();
    }
-      
-   Parent::onMouseDragged( event );
+
+   Parent::onMouseDragged(event);
 }
 
 //-----------------------------------------------------------------------------
 
-bool GuiButtonBaseCtrl::onKeyDown(const GuiEvent &event)
+bool GuiButtonBaseCtrl::onKeyDown(const GuiEvent& event)
 {
    //if the control is a dead end, kill the event
    if (!mActive)
@@ -381,7 +386,7 @@ bool GuiButtonBaseCtrl::onKeyDown(const GuiEvent &event)
 
    //see if the key down is a return or space or not
    if ((event.keyCode == KEY_RETURN || event.keyCode == KEY_SPACE)
-       && event.modifier == 0)
+      && event.modifier == 0)
    {
       if (mProfile->isSoundButtonDownValid())
          SFX->playOnce(mProfile->getSoundButtonDownProfile());
@@ -394,7 +399,7 @@ bool GuiButtonBaseCtrl::onKeyDown(const GuiEvent &event)
 
 //-----------------------------------------------------------------------------
 
-bool GuiButtonBaseCtrl::onKeyUp(const GuiEvent &event)
+bool GuiButtonBaseCtrl::onKeyUp(const GuiEvent& event)
 {
    //if the control is a dead end, kill the event
    if (!mActive)
@@ -415,64 +420,83 @@ bool GuiButtonBaseCtrl::onKeyUp(const GuiEvent &event)
 
 //-----------------------------------------------------------------------------
 
-void GuiButtonBaseCtrl::setScriptValue(const char *value)
+void GuiButtonBaseCtrl::setScriptValue(const char* value)
 {
-	mStateOn = dAtob(value);
+   mStateOn = dAtob(value);
 
-	// Update the console variable:
-	if ( mConsoleVariable[0] )
-		Con::setBoolVariable( mConsoleVariable, mStateOn );
+   // Update the console variable:
+   if (mConsoleVariable[0])
+      Con::setBoolVariable(mConsoleVariable, mStateOn);
 
    setUpdate();
 }
 
 //-----------------------------------------------------------------------------
 
-const char *GuiButtonBaseCtrl::getScriptValue()
+const char* GuiButtonBaseCtrl::getScriptValue()
 {
-	return mStateOn ? "1" : "0";
+   return mStateOn ? "1" : "0";
 }
 
 //-----------------------------------------------------------------------------
 
 void GuiButtonBaseCtrl::onAction()
 {
-    if(!mActive)
-        return;
+   if (!mActive)
+      return;
 
-    if(mButtonType == ButtonTypeCheck)
-    {
-        mStateOn = mStateOn ? false : true;
+   if (mButtonType == ButtonTypeCheck)
+   {
+      mStateOn = mStateOn ? false : true;
+   }
+   else if (mButtonType == ButtonTypeRadio)
+   {
+      mStateOn = true;
+      messageSiblings(mRadioGroup);
    }
-   else if(mButtonType == ButtonTypeRadio)
-    {
-        mStateOn = true;
-        messageSiblings(mRadioGroup);
-    }
-    setUpdate();
+   setUpdate();
 
    // Update the console variable:
-   if ( mConsoleVariable[0] )
-      Con::setBoolVariable( mConsoleVariable, mStateOn );
+   if (mConsoleVariable[0])
+      Con::setBoolVariable(mConsoleVariable, mStateOn);
 
-    onClick_callback();
-    Parent::onAction();
+   onClick_callback();
+   Parent::onAction();
 }
 
 //-----------------------------------------------------------------------------
 
-void GuiButtonBaseCtrl::onMessage( GuiControl *sender, S32 msg )
+void GuiButtonBaseCtrl::onMessage(GuiControl* sender, S32 msg)
 {
-	Parent::onMessage(sender, msg);
-	if( mRadioGroup == msg && mButtonType == ButtonTypeRadio )
-	{
-		setUpdate();
-		mStateOn = ( sender == this );
+   Parent::onMessage(sender, msg);
+   if (mRadioGroup == msg)
+   {
+      if (mButtonType == ButtonTypeRadio)
+      {
+         setUpdate();
+         mStateOn = (sender == this);
 
-		// Update the console variable:
-		if ( mConsoleVariable[0] )
-			Con::setBoolVariable( mConsoleVariable, mStateOn );
-	}
+         // Update the console variable:
+         if (mConsoleVariable[0])
+            Con::setBoolVariable(mConsoleVariable, mStateOn);
+      }
+      else if (mButtonType == ButtonTypePush)
+      {
+         mHighlighted = (sender == this);
+         onHighlighted_callback(mHighlighted);
+      }
+   }
+}
+
+void GuiButtonBaseCtrl::setHighlighted(bool highlighted)
+{
+   mHighlighted = highlighted;
+   onHighlighted_callback(mHighlighted);
+
+   if (mRadioGroup != -1)
+   {
+      messageSiblings(mRadioGroup);
+   }
 }
 
 //=============================================================================
@@ -482,69 +506,69 @@ void GuiButtonBaseCtrl::onMessage( GuiControl *sender, S32 msg )
 
 //-----------------------------------------------------------------------------
 
-DefineEngineMethod( GuiButtonBaseCtrl, performClick, void, (),,
+DefineEngineMethod(GuiButtonBaseCtrl, performClick, void, (), ,
    "Simulate a click on the button.\n"
    "This method will trigger the button's action just as if the button had been pressed by the "
-   "user.\n\n" )
+   "user.\n\n")
 {
    object->onAction();
 }
 
 //-----------------------------------------------------------------------------
 
-DefineEngineMethod( GuiButtonBaseCtrl, setText, void, ( const char* text ),,
+DefineEngineMethod(GuiButtonBaseCtrl, setText, void, (const char* text), ,
    "Set the text displayed on the button's label.\n"
    "@param text The text to display as the button's text label.\n"
    "@note Not all buttons render text labels.\n\n"
    "@see getText\n"
-   "@see setTextID\n" )
+   "@see setTextID\n")
 {
-   object->setText( text );
+   object->setText(text);
 }
 
 //-----------------------------------------------------------------------------
 
-DefineEngineMethod( GuiButtonBaseCtrl, setTextID, void, ( const char* id ),,
+DefineEngineMethod(GuiButtonBaseCtrl, setTextID, void, (const char* id), ,
    "Set the text displayed on the button's label using a string from the string table "
    "assigned to the control.\n\n"
    "@param id Name of the variable that contains the integer string ID.  Used to look up "
-      "string in table.\n\n"
+   "string in table.\n\n"
    "@note Not all buttons render text labels.\n\n"
    "@see setText\n"
    "@see getText\n"
    "@see GuiControl::langTableMod\n"
    "@see LangTable\n\n"
-   "@ref Gui_i18n" )
+   "@ref Gui_i18n")
 {
-	object->setTextID( id );
+   object->setTextID(id);
 }
 
 //-----------------------------------------------------------------------------
 
-DefineEngineMethod( GuiButtonBaseCtrl, getText, const char*, (),,
+DefineEngineMethod(GuiButtonBaseCtrl, getText, const char*, (), ,
    "Get the text display on the button's label (if any).\n\n"
-   "@return The button's label." )
+   "@return The button's label.")
 {
-   return object->getText( );
+   return object->getText();
 }
 
 //-----------------------------------------------------------------------------
 
-DefineEngineMethod( GuiButtonBaseCtrl, setStateOn, void, ( bool isOn ), ( true ),
+DefineEngineMethod(GuiButtonBaseCtrl, setStateOn, void, (bool isOn), (true),
    "For toggle or radio buttons, set whether the button is currently activated or not.  For radio buttons, "
    "toggling a button on will toggle all other radio buttons in its group to off.\n\n"
    "@param isOn If true, the button will be toggled on (if not already); if false, it will be toggled off.\n\n"
    "@note Toggling the state of a button with this method will <em>not</em> not trigger the action associated with the "
-      "button.  To do that, use performClick()." )
+   "button.  To do that, use performClick().")
 {
-   object->setStateOn( isOn );
+   object->setStateOn(isOn);
 }
 
 //-----------------------------------------------------------------------------
 
-DefineEngineMethod( GuiButtonBaseCtrl, resetState, void, (),,
+DefineEngineMethod(GuiButtonBaseCtrl, resetState, void, (), ,
    "Reset the mousing state of the button.\n\n"
-   "This method should not generally be called." )
+   "This method should not generally be called.")
 {
    object->resetState();
 }
@@ -556,7 +580,7 @@ DefineEngineMethod(GuiButtonBaseCtrl, setHighlighted, void, (bool highlighted),
    object->setHighlighted(highlighted);
 }
 
-DefineEngineMethod(GuiButtonBaseCtrl, isHighlighted, bool, (),,
+DefineEngineMethod(GuiButtonBaseCtrl, isHighlighted, bool, (), ,
    "Reset the mousing state of the button.\n\n"
    "This method should not generally be called.")
 {

+ 92 - 101
Engine/source/gui/buttons/guiButtonBaseCtrl.h

@@ -24,7 +24,7 @@
 #define _GUIBUTTONBASECTRL_H_
 
 #ifndef _GUICONTROL_H_
-   #include "gui/core/guiControl.h"
+#include "gui/core/guiControl.h"
 #endif
 
 
@@ -33,108 +33,99 @@
 ///
 class GuiButtonBaseCtrl : public GuiControl
 {
-   public:
-   
-      typedef GuiControl Parent;
-
-      enum ButtonType
-      {
-         ButtonTypePush,
-         ButtonTypeCheck,
-         ButtonTypeRadio,
-      };
-
-   protected:
-   
-      StringTableEntry mButtonText;
-      StringTableEntry mButtonTextID;
-      bool mDepressed;
-      bool mHighlighted;
-      bool mStateOn;
-      S32 mButtonType;
-      S32 mRadioGroup;
-      bool mUseMouseEvents;
-      
-      /// Point where left mouse button was pressed down.  Used to find when to start
-      /// a mouse drag.
-      Point2I mMouseDownPoint;
-      
-      ///
-      bool mMouseDragged;
-      
-	   /// @name Callbacks
-	   /// @{
-
-      DECLARE_CALLBACK( void, onMouseDown, () );   
-	   DECLARE_CALLBACK( void, onMouseUp, () );
-	   DECLARE_CALLBACK( void, onClick, () );
-	   DECLARE_CALLBACK( void, onRightClick, () );
-	   DECLARE_CALLBACK( void, onDoubleClick, () );    
-	   DECLARE_CALLBACK( void, onMouseEnter, () );   
-	   DECLARE_CALLBACK( void, onMouseLeave, () );      
-	   DECLARE_CALLBACK( void, onMouseDragged, () );   
-      DECLARE_CALLBACK( void, onHighlighted, (bool));
-
-      /// @}
-
-   public:
-
-      GuiButtonBaseCtrl();
-      bool onWake();
-
-      DECLARE_CONOBJECT( GuiButtonBaseCtrl );
-      DECLARE_CATEGORY( "Gui Buttons" );
-      DECLARE_DESCRIPTION( "A basic button control." );
-      
-      static void initPersistFields();
-
-      void setText(const char *text);
-      void setTextID(S32 id);
-      void setTextID(const char *id);
-      const char *getText();
-      void setStateOn( bool bStateOn );
-      bool getStateOn() const { return mStateOn; }
-
-      void setDepressed( bool depressed ) { mDepressed = depressed; }
-      void resetState()
-      {
-         mDepressed = false;
-         mHighlighted = false;
-         onHighlighted_callback(false);
-      }
-
-      void setHighlighted(bool highlighted)
-      {
-         mHighlighted = highlighted;
-         onHighlighted_callback(highlighted);
-      }
-      bool isHighlighted() { return mHighlighted; }
-
-      void acceleratorKeyPress(U32 index);
-      void acceleratorKeyRelease(U32 index);
-
-      void onMouseDown(const GuiEvent &);
-      void onMouseUp(const GuiEvent &);
-      void onMouseDragged( const GuiEvent& event );
-      void onRightMouseUp(const GuiEvent &);
-
-      void onMouseEnter(const GuiEvent &);
-      void onMouseLeave(const GuiEvent &);
-
-      bool onKeyDown(const GuiEvent &event);
-      bool onKeyUp(const GuiEvent &event);
-
-      void setScriptValue(const char *value);
-      const char *getScriptValue();
-
-      void onMessage(GuiControl *,S32 msg);
-      void onAction();
-      
-      bool usesMouseEvents() const { return mUseMouseEvents; }
-      void setUseMouseEvents( bool val ) { mUseMouseEvents = val; }
+public:
+
+   typedef GuiControl Parent;
+
+   enum ButtonType
+   {
+      ButtonTypePush,
+      ButtonTypeCheck,
+      ButtonTypeRadio,
+   };
+
+protected:
+
+   StringTableEntry mButtonText;
+   StringTableEntry mButtonTextID;
+   bool mDepressed;
+   bool mHighlighted;
+   bool mStateOn;
+   S32 mButtonType;
+   S32 mRadioGroup;
+   bool mUseMouseEvents;
+
+   /// Point where left mouse button was pressed down.  Used to find when to start
+   /// a mouse drag.
+   Point2I mMouseDownPoint;
+
+   ///
+   bool mMouseDragged;
+
+   /// @name Callbacks
+   /// @{
+
+   DECLARE_CALLBACK(void, onMouseDown, ());
+   DECLARE_CALLBACK(void, onMouseUp, ());
+   DECLARE_CALLBACK(void, onClick, ());
+   DECLARE_CALLBACK(void, onRightClick, ());
+   DECLARE_CALLBACK(void, onDoubleClick, ());
+   DECLARE_CALLBACK(void, onMouseEnter, ());
+   DECLARE_CALLBACK(void, onMouseLeave, ());
+   DECLARE_CALLBACK(void, onMouseDragged, ());
+   DECLARE_CALLBACK(void, onHighlighted, (bool));
+
+   /// @}
+
+public:
+
+   GuiButtonBaseCtrl();
+   bool onWake();
+
+   DECLARE_CONOBJECT(GuiButtonBaseCtrl);
+   DECLARE_CATEGORY("Gui Buttons");
+   DECLARE_DESCRIPTION("A basic button control.");
+
+   static void initPersistFields();
+
+   void setText(const char* text);
+   void setTextID(S32 id);
+   void setTextID(const char* id);
+   const char* getText();
+   void setStateOn(bool bStateOn);
+   bool getStateOn() const { return mStateOn; }
+
+   void setDepressed(bool depressed) { mDepressed = depressed; }
+   void resetState() { mDepressed = false; mHighlighted = false; }
+
+   void setHighlighted(bool highlighted);
+   bool isHighlighted() { return mHighlighted; }
+
+   void acceleratorKeyPress(U32 index);
+   void acceleratorKeyRelease(U32 index);
+
+   void onMouseDown(const GuiEvent&);
+   void onMouseUp(const GuiEvent&);
+   void onMouseDragged(const GuiEvent& event);
+   void onRightMouseUp(const GuiEvent&);
+
+   void onMouseEnter(const GuiEvent&);
+   void onMouseLeave(const GuiEvent&);
+
+   bool onKeyDown(const GuiEvent& event);
+   bool onKeyUp(const GuiEvent& event);
+
+   void setScriptValue(const char* value);
+   const char* getScriptValue();
+
+   void onMessage(GuiControl*, S32 msg);
+   void onAction();
+
+   bool usesMouseEvents() const { return mUseMouseEvents; }
+   void setUseMouseEvents(bool val) { mUseMouseEvents = val; }
 };
 
 typedef GuiButtonBaseCtrl::ButtonType GuiButtonType;
-DefineEnumType( GuiButtonType );
+DefineEnumType(GuiButtonType);
 
 #endif

+ 14 - 0
Templates/BaseGame/game/data/UI/guis/mainMenu.gui

@@ -83,6 +83,8 @@ $guiContent = new GuiControl(MainMenuGui) {
          profile = "GuiMenuButtonProfile";
          command = "$pref::HostMultiPlayer=false;\nCanvas.pushDialog(ChooseLevelMenu);";
          tooltipProfile = "GuiToolTipProfile";
+         class="MainMenuButton";
+         groupNum = 1;
       };
       new GuiButtonCtrl(MainMenuCreateSrvrBtn) {
          text = "Create Server";
@@ -91,6 +93,8 @@ $guiContent = new GuiControl(MainMenuGui) {
          profile = "GuiMenuButtonProfile";
          command = "$pref::HostMultiPlayer=true;Canvas.pushDialog(ChooseLevelMenu);";
          tooltipProfile = "GuiToolTipProfile";
+         class="MainMenuButton";
+         groupNum = 1;
       };
       new GuiButtonCtrl(MainMenuJoinSrvrBtn) {
          text = "Join Server";
@@ -99,6 +103,8 @@ $guiContent = new GuiControl(MainMenuGui) {
          profile = "GuiMenuButtonProfile";
          command = "Canvas.pushDialog(JoinServerMenu);";
          tooltipProfile = "GuiToolTipProfile";
+         class="MainMenuButton";
+         groupNum = 1;
       };
       new GuiButtonCtrl(MainMenuOptionBtn) {
          text = "Options";
@@ -107,6 +113,8 @@ $guiContent = new GuiControl(MainMenuGui) {
          profile = "GuiMenuButtonProfile";
          command = "Canvas.pushDialog(OptionsMenu);";
          tooltipProfile = "GuiToolTipProfile";
+         class="MainMenuButton";
+         groupNum = 1;
       };
       new GuiButtonCtrl(MainMenuWorldEditBtn) {
          text = "Open World Editor (F11)";
@@ -115,6 +123,8 @@ $guiContent = new GuiControl(MainMenuGui) {
          profile = "GuiMenuButtonProfile";
          command = "fastLoadWorldEdit(1);";
          tooltipProfile = "GuiToolTipProfile";
+         class="MainMenuButton";
+         groupNum = 1;
       };
       new GuiButtonCtrl(MainMenuGuiEditBtn) {
          text = "Open GUI Editor (F10)";
@@ -123,6 +133,8 @@ $guiContent = new GuiControl(MainMenuGui) {
          profile = "GuiMenuButtonProfile";
          command = "fastLoadGUIEdit(1);";
          tooltipProfile = "GuiToolTipProfile";
+         class="MainMenuButton";
+         groupNum = 1;
       };
       new GuiButtonCtrl(MainMenuExitBtn) {
          text = "Exit";
@@ -131,6 +143,8 @@ $guiContent = new GuiControl(MainMenuGui) {
          profile = "GuiMenuButtonProfile";
          command = "quit();";
          tooltipProfile = "GuiToolTipProfile";
+         class="MainMenuButton";
+         groupNum = 1;
       };
    };
 };

+ 29 - 4
Templates/BaseGame/game/data/UI/guis/mainMenu.tscript

@@ -1,3 +1,6 @@
+$BaseUI::scrollSpeedTimeMs = 250;
+$BaseUI::scrollSchedule = 0;
+
 function MainMenuGui::onAdd(%this)
 {
 }
@@ -38,6 +41,12 @@ function BaseUINavigatePrev(%val)
          $MenuList.listPosition = 0;
          
       $MenuList.syncGUI();
+      
+      $BaseUI::scrollSchedule = schedule($BaseUI::scrollSpeedTimeMs, 0, "BaseUINavigatePrev", 1);
+   }
+   else
+   {
+      cancel($BaseUI::scrollSchedule);
    }
 }
 
@@ -50,15 +59,25 @@ function BaseUINavigateNext(%val)
          $MenuList.listPosition = $MenuList.getCount()-1;
          
       $MenuList.syncGUI();
+      
+      $BaseUI::scrollSchedule = schedule($BaseUI::scrollSpeedTimeMs, 0, "BaseUINavigateNext", 1);
+   }
+   else
+   {
+      cancel($BaseUI::scrollSchedule);
    }
 }
 
 function BaseUIStickNavigate(%val)
 {
-   if(%val == -1)
+   if(%val == 1)
       BaseUINavigateNext(1);
-   else if(%val == 1)
-      mainMenuNavigateDown(1);
+   else if(%val == -1)
+      BaseUINavigatePrev(1);
+   else 
+   {
+      cancel($BaseUI::scrollSchedule);
+   }
 }
 
 function BaseUIBackOut(%val)
@@ -79,7 +98,7 @@ function BaseUIBackOut(%val)
 
 function MainMenuButtonList::syncGUI(%this)
 {
-   %this.callOnChildren("setHighlighted", false);
+   //%this.callOnChildren("setHighlighted", false);
    
    %btn = %this.getObject(%this.listPosition);
    %btn.setHighlighted(true);
@@ -93,6 +112,12 @@ function MainMenuButtonList::syncGUI(%this)
    MainMenuGoButton.setBitmap(BaseUIActionMap.getCommandButtonBitmap(%device, "BaseUIActivateSelected"));
 }
 
+function MainMenuButton::onHighlighted(%this, %highlighted)
+{
+   if(%highlighted)
+      $MenuList.listPosition = MainMenuButtonList.getObjectIndex(%this);
+}
+
 function BaseUIActivateSelected()
 {
    %btn = $MenuList.getObject($MenuList.listPosition);