- 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
This commit is contained in:
Areloch 2023-12-27 11:42:43 -06:00
parent 36d00e09d3
commit f5ab97242f
4 changed files with 301 additions and 247 deletions

View file

@ -31,14 +31,14 @@
#include "sfx/sfxTrack.h" #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" "@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 " "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" "offered by this class, then it can be instantiated and used directly. Otherwise, its subclasses should be used:\n"
"- GuiRadioCtrl (radio buttons)\n" "- GuiRadioCtrl (radio buttons)\n"
"- GuiCheckBoxCtrl (checkboxes)\n" "- GuiCheckBoxCtrl (checkboxes)\n"
"- GuiButtonCtrl (push buttons with text labels)\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" "- GuiToggleButtonCtrl (toggle buttons, i.e. push buttons with \"sticky\" behavior)\n"
"- GuiSwatchButtonCtrl (color swatch buttons)\n" "- GuiSwatchButtonCtrl (color swatch buttons)\n"
"- GuiBorderButtonCtrl (push buttons for surrounding child controls)\n\n" "- GuiBorderButtonCtrl (push buttons for surrounding child controls)\n\n"
"@ingroup GuiButtons" "@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) " "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) " "If #useMouseEvents is true, this is called when the left mouse button is release over an (active) "
"button.\n\n" "button.\n\n"
"@note To trigger actions, better use onClick() since onMouseUp() will also be called when the mouse was " "@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, (), (), IMPLEMENT_CALLBACK(GuiButtonBaseCtrl, onClick, void, (), (),
"Called when the primary action of the button is triggered (e.g. by a left mouse click)." ); "Called when the primary action of the button is triggered (e.g. by a left mouse click).");
IMPLEMENT_CALLBACK( GuiButtonBaseCtrl, onDoubleClick, void, (), (), IMPLEMENT_CALLBACK(GuiButtonBaseCtrl, onDoubleClick, void, (), (),
"Called when the left mouse button is double-clicked on the button." ); "Called when the left mouse button is double-clicked on the button.");
IMPLEMENT_CALLBACK( GuiButtonBaseCtrl, onRightClick, void, (), (), IMPLEMENT_CALLBACK(GuiButtonBaseCtrl, onRightClick, void, (), (),
"Called when the right mouse button is clicked on the button." ); "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 " "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 " "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 " "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 " "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), 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" "Type of button control.\n\n"
"@ingroup GuiButtons" ) "@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::ButtonTypePush, "PushButton", "A button that triggers an action when clicked."
{ GuiButtonBaseCtrl::ButtonTypeRadio, "RadioButton", "A button placed in groups for presenting choices." }, },
{ 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; EndImplementEnumType;
@ -102,7 +105,7 @@ GuiButtonBaseCtrl::GuiButtonBaseCtrl()
mDepressed = false; mDepressed = false;
mHighlighted = false; mHighlighted = false;
mActive = true; mActive = true;
static StringTableEntry sButton = StringTable->insert( "Button" ); static StringTableEntry sButton = StringTable->insert("Button");
mButtonText = sButton; mButtonText = sButton;
mButtonTextID = StringTable->EmptyString(); mButtonTextID = StringTable->EmptyString();
mStateOn = false; mStateOn = false;
@ -117,27 +120,27 @@ GuiButtonBaseCtrl::GuiButtonBaseCtrl()
void GuiButtonBaseCtrl::initPersistFields() void GuiButtonBaseCtrl::initPersistFields()
{ {
docsURL; docsURL;
addGroup( "Button" ); addGroup("Button");
addField( "text", TypeCaseString, Offset(mButtonText, GuiButtonBaseCtrl), addField("text", TypeCaseString, Offset(mButtonText, GuiButtonBaseCtrl),
"Text label to display on button (if button class supports text labels)." ); "Text label to display on button (if button class supports text labels).");
addField( "textID", TypeString, Offset(mButtonTextID, GuiButtonBaseCtrl), addField("textID", TypeString, Offset(mButtonTextID, GuiButtonBaseCtrl),
"ID of string in string table to use for text label on button.\n\n" "ID of string in string table to use for text label on button.\n\n"
"@see setTextID\n" "@see setTextID\n"
"@see GuiControl::langTableMod\n" "@see GuiControl::langTableMod\n"
"@see LangTable\n\n" ); "@see LangTable\n\n");
addField( "groupNum", TypeS32, Offset(mRadioGroup, GuiButtonBaseCtrl), addField("groupNum", TypeS32, Offset(mRadioGroup, GuiButtonBaseCtrl),
"Radio button toggle group number. All radio buttons that are assigned the same #groupNum and that " "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 " "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" "all other radio buttons in its group will be toggled off.\n\n"
"The default group is -1." ); "The default group is -1.");
addField( "buttonType", TYPEID< ButtonType >(), Offset(mButtonType, GuiButtonBaseCtrl), addField("buttonType", TYPEID< ButtonType >(), Offset(mButtonType, GuiButtonBaseCtrl),
"Button behavior type.\n" ); "Button behavior type.\n");
addField( "useMouseEvents", TypeBool, Offset(mUseMouseEvents, GuiButtonBaseCtrl), addField("useMouseEvents", TypeBool, Offset(mUseMouseEvents, GuiButtonBaseCtrl),
"If true, mouse events will be passed on to script. Default is false.\n" ); "If true, mouse events will be passed on to script. Default is false.\n");
endGroup( "Button" ); endGroup("Button");
Parent::initPersistFields(); Parent::initPersistFields();
} }
@ -145,70 +148,70 @@ void GuiButtonBaseCtrl::initPersistFields()
bool GuiButtonBaseCtrl::onWake() bool GuiButtonBaseCtrl::onWake()
{ {
if(!Parent::onWake()) if (!Parent::onWake())
return false; return false;
// is we have a script variable, make sure we're in sync // is we have a script variable, make sure we're in sync
if ( mConsoleVariable[0] ) if (mConsoleVariable[0])
mStateOn = Con::getBoolVariable( mConsoleVariable ); mStateOn = Con::getBoolVariable(mConsoleVariable);
if(mButtonTextID && *mButtonTextID != 0) if (mButtonTextID && *mButtonTextID != 0)
setTextID(mButtonTextID); setTextID(mButtonTextID);
return true; return true;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void GuiButtonBaseCtrl::setText( const char* text ) void GuiButtonBaseCtrl::setText(const char* text)
{ {
mButtonText = StringTable->insert(text, true); mButtonText = StringTable->insert(text, true);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void GuiButtonBaseCtrl::setTextID(const char *id) void GuiButtonBaseCtrl::setTextID(const char* id)
{ {
S32 n = Con::getIntVariable(id, -1); S32 n = Con::getIntVariable(id, -1);
if(n != -1) if (n != -1)
{ {
mButtonTextID = StringTable->insert(id); mButtonTextID = StringTable->insert(id);
setTextID(n); setTextID(n);
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void GuiButtonBaseCtrl::setTextID(S32 id) void GuiButtonBaseCtrl::setTextID(S32 id)
{ {
const UTF8 *str = getGUIString(id); const UTF8* str = getGUIString(id);
if(str) if (str)
setText((const char*)str); setText((const char*)str);
//mButtonTextID = id; //mButtonTextID = id;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
const char *GuiButtonBaseCtrl::getText() const char* GuiButtonBaseCtrl::getText()
{ {
return mButtonText; return mButtonText;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void GuiButtonBaseCtrl::setStateOn( bool bStateOn ) void GuiButtonBaseCtrl::setStateOn(bool bStateOn)
{ {
if(!mActive) if (!mActive)
return; return;
if(mButtonType == ButtonTypeCheck) if (mButtonType == ButtonTypeCheck)
{ {
mStateOn = bStateOn; mStateOn = bStateOn;
} }
else if(mButtonType == ButtonTypeRadio) else if (mButtonType == ButtonTypeRadio)
{ {
messageSiblings(mRadioGroup); messageSiblings(mRadioGroup);
mStateOn = bStateOn; mStateOn = bStateOn;
} }
setUpdate(); setUpdate();
} }
@ -216,7 +219,7 @@ void GuiButtonBaseCtrl::setStateOn( bool bStateOn )
void GuiButtonBaseCtrl::acceleratorKeyPress(U32) void GuiButtonBaseCtrl::acceleratorKeyPress(U32)
{ {
if( !mActive ) if (!mActive)
return; return;
//set the bool //set the bool
@ -230,7 +233,7 @@ void GuiButtonBaseCtrl::acceleratorKeyPress(U32)
void GuiButtonBaseCtrl::acceleratorKeyRelease(U32) void GuiButtonBaseCtrl::acceleratorKeyRelease(U32)
{ {
if (! mActive) if (!mActive)
return; return;
if (mDepressed) 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; return;
if (mProfile->mCanKeyFocus) if (mProfile->mCanKeyFocus)
@ -257,19 +260,19 @@ void GuiButtonBaseCtrl::onMouseDown(const GuiEvent &event)
if (mProfile->isSoundButtonDownValid()) if (mProfile->isSoundButtonDownValid())
SFX->playOnce(mProfile->getSoundButtonDownProfile()); SFX->playOnce(mProfile->getSoundButtonDownProfile());
mMouseDownPoint = event.mousePoint; mMouseDownPoint = event.mousePoint;
mMouseDragged = false; mMouseDragged = false;
if( mUseMouseEvents ) if (mUseMouseEvents)
onMouseDown_callback(); onMouseDown_callback();
//lock the mouse //lock the mouse
mouseLock(); mouseLock();
mDepressed = true; mDepressed = true;
// If we have a double click then execute the alt command. // If we have a double click then execute the alt command.
if ( event.mouseClickCount == 2 ) if (event.mouseClickCount == 2)
{ {
onDoubleClick_callback(); onDoubleClick_callback();
execAltConsoleCallback(); execAltConsoleCallback();
@ -281,18 +284,18 @@ void GuiButtonBaseCtrl::onMouseDown(const GuiEvent &event)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void GuiButtonBaseCtrl::onMouseEnter(const GuiEvent &event) void GuiButtonBaseCtrl::onMouseEnter(const GuiEvent& event)
{ {
setUpdate(); setUpdate();
if( mUseMouseEvents ) if (mUseMouseEvents)
onMouseEnter_callback(); onMouseEnter_callback();
if(isMouseLocked()) if (isMouseLocked())
{ {
mDepressed = true; mDepressed = true;
mHighlighted = true; mHighlighted = true;
onHighlighted_callback(true); onHighlighted_callback(mHighlighted);
} }
else else
{ {
@ -300,40 +303,42 @@ void GuiButtonBaseCtrl::onMouseEnter(const GuiEvent &event)
SFX->playOnce(mProfile->getSoundButtonOverProfile()); SFX->playOnce(mProfile->getSoundButtonOverProfile());
mHighlighted = true; mHighlighted = true;
onHighlighted_callback(true); messageSiblings(mRadioGroup);
onHighlighted_callback(mHighlighted);
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void GuiButtonBaseCtrl::onMouseLeave(const GuiEvent &) void GuiButtonBaseCtrl::onMouseLeave(const GuiEvent&)
{ {
setUpdate(); setUpdate();
if( mUseMouseEvents ) if (mUseMouseEvents)
onMouseLeave_callback(); onMouseLeave_callback();
if( isMouseLocked() ) if (isMouseLocked())
mDepressed = false; mDepressed = false;
mHighlighted = false; mHighlighted = false;
onHighlighted_callback(false); onHighlighted_callback(mHighlighted);
messageSiblings(mRadioGroup);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void GuiButtonBaseCtrl::onMouseUp(const GuiEvent &event) void GuiButtonBaseCtrl::onMouseUp(const GuiEvent& event)
{ {
mouseUnlock(); mouseUnlock();
if( !mActive ) if (!mActive)
return; return;
setUpdate(); setUpdate();
if( mUseMouseEvents ) if (mUseMouseEvents)
onMouseUp_callback(); onMouseUp_callback();
//if we released the mouse within this control, perform the action //if we released the mouse within this control, perform the action
if( mDepressed ) if (mDepressed)
onAction(); onAction();
mDepressed = false; 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(); 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 // If we haven't started a drag yet, find whether we have moved past
// the tolerance value. // the tolerance value.
if( !mMouseDragged ) if (!mMouseDragged)
{ {
Point2I delta = mMouseDownPoint - event.mousePoint; 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; mMouseDragged = true;
} }
if( mMouseDragged ) if (mMouseDragged)
onMouseDragged_callback(); 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 the control is a dead end, kill the event
if (!mActive) if (!mActive)
@ -381,7 +386,7 @@ bool GuiButtonBaseCtrl::onKeyDown(const GuiEvent &event)
//see if the key down is a return or space or not //see if the key down is a return or space or not
if ((event.keyCode == KEY_RETURN || event.keyCode == KEY_SPACE) if ((event.keyCode == KEY_RETURN || event.keyCode == KEY_SPACE)
&& event.modifier == 0) && event.modifier == 0)
{ {
if (mProfile->isSoundButtonDownValid()) if (mProfile->isSoundButtonDownValid())
SFX->playOnce(mProfile->getSoundButtonDownProfile()); 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 the control is a dead end, kill the event
if (!mActive) 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: // Update the console variable:
if ( mConsoleVariable[0] ) if (mConsoleVariable[0])
Con::setBoolVariable( mConsoleVariable, mStateOn ); Con::setBoolVariable(mConsoleVariable, mStateOn);
setUpdate(); setUpdate();
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
const char *GuiButtonBaseCtrl::getScriptValue() const char* GuiButtonBaseCtrl::getScriptValue()
{ {
return mStateOn ? "1" : "0"; return mStateOn ? "1" : "0";
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void GuiButtonBaseCtrl::onAction() void GuiButtonBaseCtrl::onAction()
{ {
if(!mActive) if (!mActive)
return; return;
if(mButtonType == ButtonTypeCheck) if (mButtonType == ButtonTypeCheck)
{ {
mStateOn = mStateOn ? false : true; mStateOn = mStateOn ? false : true;
} }
else if(mButtonType == ButtonTypeRadio) else if (mButtonType == ButtonTypeRadio)
{ {
mStateOn = true; mStateOn = true;
messageSiblings(mRadioGroup); messageSiblings(mRadioGroup);
} }
setUpdate(); setUpdate();
// Update the console variable: // Update the console variable:
if ( mConsoleVariable[0] ) if (mConsoleVariable[0])
Con::setBoolVariable( mConsoleVariable, mStateOn ); Con::setBoolVariable(mConsoleVariable, mStateOn);
onClick_callback(); onClick_callback();
Parent::onAction(); Parent::onAction();
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void GuiButtonBaseCtrl::onMessage( GuiControl *sender, S32 msg ) void GuiButtonBaseCtrl::onMessage(GuiControl* sender, S32 msg)
{ {
Parent::onMessage(sender, msg); Parent::onMessage(sender, msg);
if( mRadioGroup == msg && mButtonType == ButtonTypeRadio ) if (mRadioGroup == msg)
{ {
setUpdate(); if (mButtonType == ButtonTypeRadio)
mStateOn = ( sender == this ); {
setUpdate();
mStateOn = (sender == this);
// Update the console variable: // Update the console variable:
if ( mConsoleVariable[0] ) if (mConsoleVariable[0])
Con::setBoolVariable( mConsoleVariable, mStateOn ); 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" "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 " "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(); 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" "Set the text displayed on the button's label.\n"
"@param text The text to display as the button's text label.\n" "@param text The text to display as the button's text label.\n"
"@note Not all buttons render text labels.\n\n" "@note Not all buttons render text labels.\n\n"
"@see getText\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 " "Set the text displayed on the button's label using a string from the string table "
"assigned to the control.\n\n" "assigned to the control.\n\n"
"@param id Name of the variable that contains the integer string ID. Used to look up " "@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" "@note Not all buttons render text labels.\n\n"
"@see setText\n" "@see setText\n"
"@see getText\n" "@see getText\n"
"@see GuiControl::langTableMod\n" "@see GuiControl::langTableMod\n"
"@see LangTable\n\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" "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, " "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" "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" "@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 " "@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" "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(); object->resetState();
} }
@ -556,7 +580,7 @@ DefineEngineMethod(GuiButtonBaseCtrl, setHighlighted, void, (bool highlighted),
object->setHighlighted(highlighted); object->setHighlighted(highlighted);
} }
DefineEngineMethod(GuiButtonBaseCtrl, isHighlighted, bool, (),, DefineEngineMethod(GuiButtonBaseCtrl, isHighlighted, bool, (), ,
"Reset the mousing state of the button.\n\n" "Reset the mousing state of the button.\n\n"
"This method should not generally be called.") "This method should not generally be called.")
{ {

View file

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

View file

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

View file

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