mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-04-22 21:05:39 +00:00
Initial pass to rework and cleanup the main UI interface
Implements interface buttons that react to input type and visually display keybinds Updates the T3D icon and splash screen
This commit is contained in:
parent
157b114ec7
commit
bc27125e90
188 changed files with 2553 additions and 758 deletions
|
|
@ -25,6 +25,9 @@
|
|||
#include "console/consoleTypes.h"
|
||||
#include "console/engineAPI.h"
|
||||
#include "gfx/gfxDrawUtil.h"
|
||||
#include "gui/containers/guiScrollCtrl.h"
|
||||
#include "sim\actionMap.h"
|
||||
#include "core\strings\stringUnit.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GuiGameListMenuCtrl
|
||||
|
|
@ -33,7 +36,8 @@
|
|||
GuiGameListMenuCtrl::GuiGameListMenuCtrl()
|
||||
: mSelected(NO_ROW),
|
||||
mDebugRender(false),
|
||||
mHighlighted(NO_ROW)
|
||||
mHighlighted(NO_ROW),
|
||||
mCallbackOnInputs(false)
|
||||
{
|
||||
VECTOR_SET_ASSOCIATION(mRows);
|
||||
|
||||
|
|
@ -93,7 +97,7 @@ void GuiGameListMenuCtrl::onRender(Point2I offset, const RectI &updateRect)
|
|||
U32 buttonTextureIndex;
|
||||
S32 iconIndex = (*row)->mIconIndex;
|
||||
bool useHighlightIcon = (*row)->mUseHighlightIcon;
|
||||
if (! (*row)->mEnabled)
|
||||
if (!(*row)->mEnabled)
|
||||
{
|
||||
buttonTextureIndex = Profile::TEX_DISABLED;
|
||||
fontColor = profile->mFontColorNA;
|
||||
|
|
@ -127,7 +131,7 @@ void GuiGameListMenuCtrl::onRender(Point2I offset, const RectI &updateRect)
|
|||
drawUtil->drawBitmapStretchSR(profile->mTextureObject, RectI(currentOffset, rowExtent), profile->getBitmapArrayRect(buttonTextureIndex));
|
||||
|
||||
// render the row icon if it has one
|
||||
if ((iconIndex != NO_ICON) && profileHasIcons && (! profile->getBitmapArrayRect((U32)iconIndex).extent.isZero()))
|
||||
if ((iconIndex != NO_ICON) && profileHasIcons && (!profile->getBitmapArrayRect((U32)iconIndex).extent.isZero()))
|
||||
{
|
||||
iconIndex += Profile::TEX_FIRST_ICON;
|
||||
drawUtil->clearBitmapModulation();
|
||||
|
|
@ -137,6 +141,11 @@ void GuiGameListMenuCtrl::onRender(Point2I offset, const RectI &updateRect)
|
|||
// render the row text
|
||||
drawUtil->setBitmapModulation(fontColor);
|
||||
renderJustifiedText(currentOffset + textOffset, textExtent, (*row)->mLabel);
|
||||
|
||||
if ((*row)->mMode == Row::Mode::OptionList)
|
||||
{
|
||||
onRenderOptionList((*row), currentOffset);
|
||||
}
|
||||
}
|
||||
|
||||
if (mDebugRender)
|
||||
|
|
@ -147,6 +156,92 @@ void GuiGameListMenuCtrl::onRender(Point2I offset, const RectI &updateRect)
|
|||
renderChildControls(offset, updateRect);
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::onRenderOptionList(Row* row, Point2I currentOffset)
|
||||
{
|
||||
GuiGameListMenuProfile* profile = (GuiGameListMenuProfile*)mProfile;
|
||||
|
||||
F32 xScale = (float)getWidth() / profile->getRowWidth();
|
||||
|
||||
S32 rowHeight = profile->getRowHeight();
|
||||
|
||||
bool profileHasArrows = profile->hasArrows();
|
||||
Point2I arrowExtent;
|
||||
S32 arrowOffsetY(0);
|
||||
if (profileHasArrows)
|
||||
{
|
||||
arrowExtent = profile->getArrowExtent();
|
||||
|
||||
// icon is centered vertically
|
||||
arrowOffsetY = (rowHeight - arrowExtent.y) >> 1;
|
||||
}
|
||||
|
||||
GFXDrawUtil* drawer = GFX->getDrawUtil();
|
||||
|
||||
Point2I arrowOffset;
|
||||
S32 columnSplit = profile->mColumnSplit * xScale;
|
||||
|
||||
S32 iconIndex;
|
||||
bool hasOptions = (row->mOptions.size() > 0) && row->mSelectedOption > -1;
|
||||
if (hasOptions)
|
||||
{
|
||||
bool isRowSelected = (getSelected() != NO_ROW) && (row == mRows[getSelected()]);
|
||||
bool isRowHighlighted = (getHighlighted() != NO_ROW) ? ((row == mRows[getHighlighted()]) && (row->mEnabled)) : false;
|
||||
if (profileHasArrows)
|
||||
{
|
||||
// render the left arrow
|
||||
bool arrowOnL = (isRowSelected || isRowHighlighted) && (row->mWrapOptions || (row->mSelectedOption > 0));
|
||||
iconIndex = (arrowOnL) ? Profile::TEX_L_ARROW_ON : Profile::TEX_L_ARROW_OFF;
|
||||
arrowOffset.x = currentOffset.x + columnSplit;
|
||||
arrowOffset.y = currentOffset.y + arrowOffsetY;
|
||||
|
||||
drawer->clearBitmapModulation();
|
||||
drawer->drawBitmapStretchSR(profile->mTextureObject, RectI(arrowOffset, arrowExtent), profile->getBitmapArrayRect((U32)iconIndex));
|
||||
|
||||
// render the right arrow
|
||||
bool arrowOnR = (isRowSelected || isRowHighlighted) && (row->mWrapOptions || (row->mSelectedOption < row->mOptions.size() - 1));
|
||||
iconIndex = (arrowOnR) ? Profile::TEX_R_ARROW_ON : Profile::TEX_R_ARROW_OFF;
|
||||
arrowOffset.x = currentOffset.x + (profile->mHitAreaLowerRight.x - profile->mRightPad) * xScale - arrowExtent.x;
|
||||
arrowOffset.y = currentOffset.y + arrowOffsetY;
|
||||
|
||||
drawer->clearBitmapModulation();
|
||||
drawer->drawBitmapStretchSR(profile->mTextureObject, RectI(arrowOffset, arrowExtent), profile->getBitmapArrayRect((U32)iconIndex));
|
||||
}
|
||||
|
||||
// get the appropriate font color
|
||||
ColorI fontColor;
|
||||
if (!row->mEnabled)
|
||||
{
|
||||
fontColor = profile->mFontColorNA;
|
||||
}
|
||||
else if (isRowSelected)
|
||||
{
|
||||
fontColor = profile->mFontColorSEL;
|
||||
}
|
||||
else if (isRowHighlighted)
|
||||
{
|
||||
fontColor = profile->mFontColorHL;
|
||||
}
|
||||
else
|
||||
{
|
||||
fontColor = profile->mFontColor;
|
||||
}
|
||||
|
||||
// calculate text to be at the center between the arrows
|
||||
GFont* font = profile->mFont;
|
||||
StringTableEntry text = row->mOptions[row->mSelectedOption];
|
||||
S32 textWidth = font->getStrWidth(text);
|
||||
S32 columnWidth = profile->mHitAreaLowerRight.x * xScale - profile->mRightPad - columnSplit;
|
||||
S32 columnCenter = columnSplit + (columnWidth >> 1);
|
||||
S32 textStartX = columnCenter - (textWidth >> 1);
|
||||
Point2I textOffset(textStartX, 0);
|
||||
|
||||
// render the option text itself
|
||||
Point2I textExtent(columnWidth, rowHeight);
|
||||
drawer->setBitmapModulation(fontColor);
|
||||
renderJustifiedText(currentOffset + textOffset, textExtent, text);
|
||||
}
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::onDebugRender(Point2I offset)
|
||||
{
|
||||
GuiGameListMenuProfile * profile = (GuiGameListMenuProfile *) mProfile;
|
||||
|
|
@ -197,13 +292,13 @@ void GuiGameListMenuCtrl::onDebugRender(Point2I offset)
|
|||
}
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::addRow(const char* label, const char* callback, S32 icon, S32 yPad, bool useHighlightIcon, bool enabled)
|
||||
void GuiGameListMenuCtrl::addRow(const char* label, const char* callback, S32 icon, S32 yPad, bool useHighlightIcon, bool enabled, S32 mode)
|
||||
{
|
||||
Row * row = new Row();
|
||||
addRow(row, label, callback, icon, yPad, useHighlightIcon, enabled);
|
||||
addRow(row, label, callback, icon, yPad, useHighlightIcon, enabled, mode);
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::addRow(Row * row, const char* label, const char* callback, S32 icon, S32 yPad, bool useHighlightIcon, bool enabled)
|
||||
void GuiGameListMenuCtrl::addRow(Row * row, const char* label, const char* callback, S32 icon, S32 yPad, bool useHighlightIcon, bool enabled, S32 mode)
|
||||
{
|
||||
row->mLabel = StringTable->insert(label, true);
|
||||
row->mScriptCallback = (dStrlen(callback) > 0) ? StringTable->insert(callback, true) : NULL;
|
||||
|
|
@ -211,6 +306,7 @@ void GuiGameListMenuCtrl::addRow(Row * row, const char* label, const char* callb
|
|||
row->mHeightPad = yPad;
|
||||
row->mUseHighlightIcon = useHighlightIcon;
|
||||
row->mEnabled = enabled;
|
||||
row->mMode = (Row::Mode)mode;
|
||||
|
||||
mRows.push_back(row);
|
||||
|
||||
|
|
@ -222,6 +318,24 @@ void GuiGameListMenuCtrl::addRow(Row * row, const char* label, const char* callb
|
|||
}
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::addRow(const char* label, const char* optionsList, bool wrapOptions, const char* callback, S32 icon, S32 yPad, bool enabled)
|
||||
{
|
||||
static StringTableEntry DELIM = StringTable->insert("\t", true);
|
||||
Row* row = new Row();
|
||||
Vector<StringTableEntry> options(__FILE__, __LINE__);
|
||||
S32 count = StringUnit::getUnitCount(optionsList, DELIM);
|
||||
for (S32 i = 0; i < count; ++i)
|
||||
{
|
||||
const char* option = StringUnit::getUnit(optionsList, i, DELIM);
|
||||
options.push_back(StringTable->insert(option, true));
|
||||
}
|
||||
row->mOptions = options;
|
||||
bool hasOptions = row->mOptions.size() > 0;
|
||||
row->mSelectedOption = (hasOptions) ? 0 : NO_OPTION;
|
||||
row->mWrapOptions = wrapOptions;
|
||||
addRow(row, label, callback, icon, yPad, true, (hasOptions) ? enabled : false, Row::Mode::OptionList);
|
||||
}
|
||||
|
||||
Point2I GuiGameListMenuCtrl::getMinExtent() const
|
||||
{
|
||||
Point2I parentMin = Parent::getMinExtent();
|
||||
|
|
@ -280,12 +394,12 @@ bool GuiGameListMenuCtrl::onWake()
|
|||
if( !hasValidProfile() )
|
||||
return false;
|
||||
|
||||
if( mRows.empty() )
|
||||
/*if( mRows.empty() )
|
||||
{
|
||||
Con::errorf( "GuiGameListMenuCtrl: %s can't be woken up without any rows. Please use \"addRow\" to add at least one row to the control before pushing it to the canvas.",
|
||||
getName() );
|
||||
return false;
|
||||
}
|
||||
}*/
|
||||
|
||||
enforceConstraints();
|
||||
|
||||
|
|
@ -349,7 +463,15 @@ void GuiGameListMenuCtrl::onMouseUp(const GuiEvent &event)
|
|||
S32 hitRow = getRow(event.mousePoint);
|
||||
if ((hitRow != NO_ROW) && isRowEnabled(hitRow) && (hitRow == getSelected()))
|
||||
{
|
||||
activateRow();
|
||||
if (mRows[hitRow]->mMode == Row::Mode::Default)
|
||||
{
|
||||
activateRow();
|
||||
}
|
||||
else if (mRows[hitRow]->mMode == Row::Mode::OptionList)
|
||||
{
|
||||
S32 xPos = globalToLocalCoord(event.mousePoint).x;
|
||||
clickOption((Row*)mRows[getSelected()], xPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -425,6 +547,13 @@ void GuiGameListMenuCtrl::setSelected(S32 index)
|
|||
}
|
||||
|
||||
mSelected = mClamp(index, 0, mRows.size() - 1);
|
||||
|
||||
//If we're childed to a scroll container, make sure us changing rows has our new position visible
|
||||
GuiScrollCtrl* scroll = dynamic_cast<GuiScrollCtrl*>(getParent());
|
||||
if (scroll)
|
||||
{
|
||||
scroll->scrollRectVisible(getRowBounds(mSelected));
|
||||
}
|
||||
}
|
||||
|
||||
bool GuiGameListMenuCtrl::isRowEnabled(S32 index) const
|
||||
|
|
@ -470,6 +599,63 @@ void GuiGameListMenuCtrl::selectFirstEnabledRow()
|
|||
}
|
||||
}
|
||||
|
||||
bool GuiGameListMenuCtrl::onInputEvent(const InputEventInfo& event)
|
||||
{
|
||||
if (mCallbackOnInputs)
|
||||
{
|
||||
char deviceString[32];
|
||||
if (!ActionMap::getDeviceName(event.deviceType, event.deviceInst, deviceString))
|
||||
return false;
|
||||
|
||||
if (event.action == SI_MAKE || event.action == SI_BREAK)
|
||||
{
|
||||
bool isModifier = false;
|
||||
|
||||
switch (event.objInst)
|
||||
{
|
||||
case KEY_LCONTROL:
|
||||
case KEY_RCONTROL:
|
||||
case KEY_LALT:
|
||||
case KEY_RALT:
|
||||
case KEY_LSHIFT:
|
||||
case KEY_RSHIFT:
|
||||
case KEY_MAC_LOPT:
|
||||
case KEY_MAC_ROPT:
|
||||
isModifier = true;
|
||||
}
|
||||
|
||||
if ((event.objType == SI_KEY) && isModifier)
|
||||
{
|
||||
char keyString[32];
|
||||
if (!ActionMap::getKeyString(event.objInst, keyString))
|
||||
return false;
|
||||
|
||||
onInputEvent_callback(deviceString, keyString, event.action);
|
||||
}
|
||||
else
|
||||
{
|
||||
const char* actionString = ActionMap::buildActionString(&event);
|
||||
onInputEvent_callback(deviceString, actionString, event.action);
|
||||
}
|
||||
}
|
||||
else if (event.objType == SI_AXIS || event.objType == SI_INT || event.objType == SI_FLOAT)
|
||||
{
|
||||
F32 fValue = event.fValue;
|
||||
if (event.objType == SI_INT)
|
||||
fValue = (F32)event.iValue;
|
||||
|
||||
if (!ActionMap::getDeviceName(event.deviceType, event.deviceInst, deviceString))
|
||||
return false;
|
||||
|
||||
const char* actionString = ActionMap::buildActionString(&event);
|
||||
|
||||
onAxisEvent_callback(deviceString, actionString, fValue);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GuiGameListMenuCtrl::onKeyDown(const GuiEvent &event)
|
||||
{
|
||||
switch (event.keyCode)
|
||||
|
|
@ -528,6 +714,18 @@ bool GuiGameListMenuCtrl::onGamepadAxisDown(const GuiEvent &event)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool GuiGameListMenuCtrl::onGamepadAxisLeft(const GuiEvent& event)
|
||||
{
|
||||
changeOption(-1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GuiGameListMenuCtrl::onGamepadAxisRight(const GuiEvent& event)
|
||||
{
|
||||
changeOption(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::doScriptCommand(StringTableEntry command)
|
||||
{
|
||||
if (command && command[0])
|
||||
|
|
@ -589,10 +787,179 @@ void GuiGameListMenuCtrl::setRowLabel(S32 rowIndex, const char * label)
|
|||
mRows[rowIndex]->mLabel = StringTable->insert(label, true);
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::clearRows()
|
||||
{
|
||||
mRows.clear();
|
||||
}
|
||||
|
||||
RectI GuiGameListMenuCtrl::getRowBounds(S32 rowIndex)
|
||||
{
|
||||
GuiGameListMenuProfile* profile = (GuiGameListMenuProfile*)mProfile;
|
||||
|
||||
F32 xScale = (float)getWidth() / profile->getRowWidth();
|
||||
S32 rowHeight = profile->getRowHeight();
|
||||
|
||||
Point2I currentOffset = Point2I::Zero;
|
||||
Point2I extent = getExtent();
|
||||
Point2I rowExtent(extent.x, rowHeight);
|
||||
|
||||
for (U32 i = 1; i <= rowIndex; i++)
|
||||
{
|
||||
//the top row can't pad, so we'll ignore it
|
||||
GuiGameListMenuCtrl::Row* row = mRows[i];
|
||||
|
||||
// rows other than the first can have padding above them
|
||||
currentOffset.y += row->mHeightPad;
|
||||
currentOffset.y += rowHeight;
|
||||
}
|
||||
|
||||
return RectI(currentOffset, rowExtent);
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// Console stuff (GuiGameListMenuCtrl)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
StringTableEntry GuiGameListMenuCtrl::getCurrentOption(S32 rowIndex) const
|
||||
{
|
||||
if (isValidRowIndex(rowIndex))
|
||||
{
|
||||
Row* row = (Row*)mRows[rowIndex];
|
||||
if (row->mSelectedOption != NO_OPTION)
|
||||
{
|
||||
return row->mOptions[row->mSelectedOption];
|
||||
}
|
||||
}
|
||||
return StringTable->insert("", false);
|
||||
}
|
||||
|
||||
bool GuiGameListMenuCtrl::selectOption(S32 rowIndex, const char* theOption)
|
||||
{
|
||||
if (!isValidRowIndex(rowIndex))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Row* row = (Row*)mRows[rowIndex];
|
||||
|
||||
for (Vector<StringTableEntry>::iterator anOption = row->mOptions.begin(); anOption < row->mOptions.end(); ++anOption)
|
||||
{
|
||||
if (dStrcmp(*anOption, theOption) == 0)
|
||||
{
|
||||
S32 newIndex = anOption - row->mOptions.begin();
|
||||
row->mSelectedOption = newIndex;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::setOptions(S32 rowIndex, const char* optionsList)
|
||||
{
|
||||
static StringTableEntry DELIM = StringTable->insert("\t", true);
|
||||
|
||||
if (!isValidRowIndex(rowIndex))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Row* row = (Row*)mRows[rowIndex];
|
||||
|
||||
S32 count = StringUnit::getUnitCount(optionsList, DELIM);
|
||||
row->mOptions.setSize(count);
|
||||
for (S32 i = 0; i < count; ++i)
|
||||
{
|
||||
const char* option = StringUnit::getUnit(optionsList, i, DELIM);
|
||||
row->mOptions[i] = StringTable->insert(option, true);
|
||||
}
|
||||
|
||||
if (row->mSelectedOption >= row->mOptions.size())
|
||||
{
|
||||
row->mSelectedOption = row->mOptions.size() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::clickOption(Row* row, S32 xPos)
|
||||
{
|
||||
GuiGameListMenuProfile* profile = (GuiGameListMenuProfile*)mProfile;
|
||||
if (!profile->hasArrows())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
F32 xScale = (float)getWidth() / profile->getRowWidth();
|
||||
|
||||
S32 bitmapArrowWidth = mProfile->getBitmapArrayRect(Profile::TEX_FIRST_ARROW).extent.x;
|
||||
|
||||
S32 leftArrowX1 = profile->mColumnSplit * xScale;
|
||||
S32 leftArrowX2 = leftArrowX1 + bitmapArrowWidth;
|
||||
|
||||
S32 rightArrowX2 = (profile->mHitAreaLowerRight.x - profile->mRightPad) * xScale;
|
||||
S32 rightArrowX1 = rightArrowX2 - bitmapArrowWidth;
|
||||
|
||||
if ((leftArrowX1 <= xPos) && (xPos <= leftArrowX2))
|
||||
{
|
||||
changeOption(row, -1);
|
||||
}
|
||||
else if ((rightArrowX1 <= xPos) && (xPos <= rightArrowX2))
|
||||
{
|
||||
changeOption(row, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::changeOption(S32 delta)
|
||||
{
|
||||
if (getSelected() != NO_ROW)
|
||||
{
|
||||
Row* row = (Row*)mRows[getSelected()];
|
||||
changeOption(row, delta);
|
||||
}
|
||||
}
|
||||
|
||||
void GuiGameListMenuCtrl::changeOption(Row* row, S32 delta)
|
||||
{
|
||||
S32 optionCount = row->mOptions.size();
|
||||
|
||||
S32 newSelection = row->mSelectedOption + delta;
|
||||
if (optionCount == 0)
|
||||
{
|
||||
newSelection = NO_OPTION;
|
||||
}
|
||||
else if (!row->mWrapOptions)
|
||||
{
|
||||
newSelection = mClamp(newSelection, 0, optionCount - 1);
|
||||
}
|
||||
else if (newSelection < 0)
|
||||
{
|
||||
newSelection = optionCount - 1;
|
||||
}
|
||||
else if (newSelection >= optionCount)
|
||||
{
|
||||
newSelection = 0;
|
||||
}
|
||||
row->mSelectedOption = newSelection;
|
||||
|
||||
static StringTableEntry LEFT = StringTable->insert("LEFT", true);
|
||||
static StringTableEntry RIGHT = StringTable->insert("RIGHT", true);
|
||||
|
||||
if (row->mScriptCallback != NULL)
|
||||
{
|
||||
setThisControl();
|
||||
StringTableEntry direction = NULL;
|
||||
if (delta < 0)
|
||||
{
|
||||
direction = LEFT;
|
||||
}
|
||||
else if (delta > 0)
|
||||
{
|
||||
direction = RIGHT;
|
||||
}
|
||||
if ((direction != NULL) && (Con::isFunction(row->mScriptCallback)))
|
||||
{
|
||||
Con::executef(row->mScriptCallback, direction);
|
||||
}
|
||||
}
|
||||
}
|
||||
IMPLEMENT_CONOBJECT(GuiGameListMenuCtrl);
|
||||
|
||||
ConsoleDocClass( GuiGameListMenuCtrl,
|
||||
|
|
@ -622,6 +989,20 @@ ConsoleDocClass( GuiGameListMenuCtrl,
|
|||
IMPLEMENT_CALLBACK( GuiGameListMenuCtrl, onChange, void, (), (),
|
||||
"Called when the selected row changes." );
|
||||
|
||||
IMPLEMENT_CALLBACK(GuiGameListMenuCtrl, onInputEvent, void, (const char* device, const char* action, bool state),
|
||||
(device, action, state),
|
||||
"@brief Callback that occurs when an input is triggered on this control\n\n"
|
||||
"@param device The device type triggering the input, such as keyboard, mouse, etc\n"
|
||||
"@param action The actual event occuring, such as a key or button\n"
|
||||
"@param state True if the action is being pressed, false if it is being release\n\n");
|
||||
|
||||
IMPLEMENT_CALLBACK(GuiGameListMenuCtrl, onAxisEvent, void, (const char* device, const char* action, F32 axisValue),
|
||||
(device, action, axisValue),
|
||||
"@brief Callback that occurs when an axis event is triggered on this control\n\n"
|
||||
"@param device The device type triggering the input, such as mouse, joystick, gamepad, etc\n"
|
||||
"@param action The ActionMap code for the axis\n"
|
||||
"@param axisValue The current value of the axis\n\n");
|
||||
|
||||
void GuiGameListMenuCtrl::initPersistFields()
|
||||
{
|
||||
addField("debugRender", TypeBool, Offset(mDebugRender, GuiGameListMenuCtrl),
|
||||
|
|
@ -639,21 +1020,25 @@ void GuiGameListMenuCtrl::initPersistFields()
|
|||
addField("callbackOnY", TypeString, Offset(mCallbackOnY, GuiGameListMenuCtrl),
|
||||
"Script callback when the 'Y' button is pressed. 'Y' inputs are Keyboard: Y; Gamepad: Y" );
|
||||
|
||||
addField("callbackOnInputs", TypeBool, Offset(mCallbackOnInputs, GuiGameListMenuCtrl),
|
||||
"Script callback when any inputs are detected, even if they aren't the regular 4 face buttons. Useful for secondary/speciality handling of menu navigation.");
|
||||
|
||||
Parent::initPersistFields();
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiGameListMenuCtrl, addRow, void,
|
||||
( const char* label, const char* callback, S32 icon, S32 yPad, bool useHighlightIcon, bool enabled ),
|
||||
( -1, 0, true, true ),
|
||||
( const char* label, const char* callback, S32 icon, S32 yPad, bool useHighlightIcon, bool enabled, int mode ),
|
||||
( -1, 0, true, true, 0 ),
|
||||
"Add a row to the list control.\n\n"
|
||||
"@param label The text to display on the row as a label.\n"
|
||||
"@param callback Name of a script function to use as a callback when this row is activated.\n"
|
||||
"@param icon [optional] Index of the icon to use as a marker.\n"
|
||||
"@param yPad [optional] An extra amount of height padding before the row. Does nothing on the first row.\n"
|
||||
"@param useHighlightIcon [optional] Does this row use the highlight icon?.\n"
|
||||
"@param enabled [optional] If this row is initially enabled." )
|
||||
"@param enabled [optional] If this row is initially enabled.\n"
|
||||
"@param mode [optional] What option mode the row is in. 0 = Default, 1 = OptionList, 2 == Keybind")
|
||||
{
|
||||
object->addRow( label, callback, icon, yPad, useHighlightIcon, enabled );
|
||||
object->addRow( label, callback, icon, yPad, useHighlightIcon, enabled, mode);
|
||||
}
|
||||
|
||||
DefineEngineMethod( GuiGameListMenuCtrl, isRowEnabled, bool, ( S32 row ),,
|
||||
|
|
@ -715,16 +1100,65 @@ DefineEngineMethod( GuiGameListMenuCtrl, getSelectedRow, S32, (),,
|
|||
return object->getSelected();
|
||||
}
|
||||
|
||||
DefineEngineMethod(GuiGameListMenuCtrl, clearRows, void, (), ,
|
||||
"Gets the index of the currently selected row.\n\n"
|
||||
"@return Index of the selected row.")
|
||||
{
|
||||
return object->clearRows();
|
||||
}
|
||||
|
||||
DefineEngineMethod(GuiGameListMenuCtrl, addOptionRow, void,
|
||||
(const char* label, const char* options, bool wrapOptions, const char* callback, S32 icon, S32 yPad, bool enabled),
|
||||
(-1, 0, true),
|
||||
"Add a row to the list control.\n\n"
|
||||
"@param label The text to display on the row as a label.\n"
|
||||
"@param options A tab separated list of options.\n"
|
||||
"@param wrapOptions Specify true to allow options to wrap at each end or false to prevent wrapping.\n"
|
||||
"@param callback Name of a script function to use as a callback when this row is activated.\n"
|
||||
"@param icon [optional] Index of the icon to use as a marker.\n"
|
||||
"@param yPad [optional] An extra amount of height padding before the row. Does nothing on the first row.\n"
|
||||
"@param enabled [optional] If this row is initially enabled.")
|
||||
{
|
||||
object->addRow(label, options, wrapOptions, callback, icon, yPad, enabled);
|
||||
}
|
||||
|
||||
DefineEngineMethod(GuiGameListMenuCtrl, getCurrentOption, const char*, (S32 row), ,
|
||||
"Gets the text for the currently selected option of the given row.\n\n"
|
||||
"@param row Index of the row to get the option from.\n"
|
||||
"@return A string representing the text currently displayed as the selected option on the given row. If there is no such displayed text then the empty string is returned.")
|
||||
{
|
||||
return object->getCurrentOption(row);
|
||||
}
|
||||
|
||||
DefineEngineMethod(GuiGameListMenuCtrl, selectOption, bool, (S32 row, const char* option), ,
|
||||
"Set the row's current option to the one specified\n\n"
|
||||
"@param row Index of the row to set an option on.\n"
|
||||
"@param option The option to be made active.\n"
|
||||
"@return True if the row contained the option and was set, false otherwise.")
|
||||
{
|
||||
return object->selectOption(row, option);
|
||||
}
|
||||
|
||||
DefineEngineMethod(GuiGameListMenuCtrl, setOptions, void, (S32 row, const char* optionsList), ,
|
||||
"Sets the list of options on the given row.\n\n"
|
||||
"@param row Index of the row to set options on."
|
||||
"@param optionsList A tab separated list of options for the control.")
|
||||
{
|
||||
object->setOptions(row, optionsList);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GuiGameListMenuProfile
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
GuiGameListMenuProfile::GuiGameListMenuProfile()
|
||||
: mHitAreaUpperLeft(0, 0),
|
||||
mHitAreaLowerRight(0, 0),
|
||||
mIconOffset(0, 0),
|
||||
mRowSize(0, 0),
|
||||
mRowScale(1.0f, 1.0f)
|
||||
: mHitAreaUpperLeft(0, 0),
|
||||
mHitAreaLowerRight(0, 0),
|
||||
mIconOffset(0, 0),
|
||||
mRowSize(0, 0),
|
||||
mRowScale(1.0f, 1.0f),
|
||||
mColumnSplit(0),
|
||||
mRightPad(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -775,6 +1209,12 @@ void GuiGameListMenuProfile::enforceConstraints()
|
|||
Point2I rowTexExtent = getBitmapArrayRect(TEX_NORMAL).extent;
|
||||
mRowScale.x = (float) getRowWidth() / rowTexExtent.x;
|
||||
mRowScale.y = (float) getRowHeight() / rowTexExtent.y;
|
||||
|
||||
if (mHitAreaUpperLeft.x > mColumnSplit || mColumnSplit > mHitAreaLowerRight.x)
|
||||
Con::errorf("GuiGameListOptionsProfile: You can't create %s with a ColumnSplit outside the hit area. You set the split to %d. Please change the ColumnSplit to be in the range [%d, %d].",
|
||||
getName(), mColumnSplit, mHitAreaUpperLeft.x, mHitAreaLowerRight.x);
|
||||
|
||||
mColumnSplit = mClamp(mColumnSplit, mHitAreaUpperLeft.x, mHitAreaLowerRight.x);
|
||||
}
|
||||
|
||||
Point2I GuiGameListMenuProfile::getIconExtent()
|
||||
|
|
@ -827,6 +1267,8 @@ ConsoleDocClass( GuiGameListMenuProfile,
|
|||
" hitAreaLowerRight = \"190 18\";\n"
|
||||
" iconOffset = \"10 2\";\n"
|
||||
" rowSize = \"200 20\";\n"
|
||||
" columnSplit = \"100\";\n"
|
||||
" rightPad = \"4\";\n"
|
||||
" //Properties not specific to this control have been omitted from this example.\n"
|
||||
"};\n"
|
||||
"@endtsexample\n\n"
|
||||
|
|
@ -848,6 +1290,12 @@ void GuiGameListMenuProfile::initPersistFields()
|
|||
addField( "rowSize", TypePoint2I, Offset(mRowSize, GuiGameListMenuProfile),
|
||||
"The base size (\"width height\") of a row" );
|
||||
|
||||
addField("columnSplit", TypeS32, Offset(mColumnSplit, GuiGameListMenuProfile),
|
||||
"Padding between the leftmost edge of the control, and the row's left arrow.");
|
||||
|
||||
addField("rightPad", TypeS32, Offset(mRightPad, GuiGameListMenuProfile),
|
||||
"Padding between the rightmost edge of the control and the row's right arrow.");
|
||||
|
||||
Parent::initPersistFields();
|
||||
|
||||
removeField("tab");
|
||||
|
|
|
|||
|
|
@ -47,6 +47,26 @@ protected:
|
|||
bool mUseHighlightIcon; ///< Toggle the use of the highlight icon
|
||||
bool mEnabled; ///< If this row is enabled or not (grayed out)
|
||||
|
||||
enum Mode
|
||||
{
|
||||
Default = 0,
|
||||
OptionList,
|
||||
Keybind
|
||||
};
|
||||
|
||||
Mode mMode;
|
||||
|
||||
//List options
|
||||
Vector<StringTableEntry> mOptions; ///< Collection of options available to display
|
||||
S32 mSelectedOption; ///< Index into mOptions pointing at the selected option
|
||||
bool mWrapOptions; ///< Determines if options should "wrap around" at the ends
|
||||
|
||||
Row() : mLabel(StringTable->EmptyString()), mScriptCallback(StringTable->EmptyString()), mIconIndex(-1), mHeightPad(0), mUseHighlightIcon(false), mEnabled(true),
|
||||
mSelectedOption(0), mWrapOptions(false), mMode(Mode::Default)
|
||||
{
|
||||
VECTOR_SET_ASSOCIATION(mOptions);
|
||||
}
|
||||
|
||||
virtual ~Row() {}
|
||||
};
|
||||
|
||||
|
|
@ -99,7 +119,43 @@ public:
|
|||
/// means no icon will be shown on this row.
|
||||
/// \param yPad [optional] An extra amount of height padding before the row.
|
||||
/// \param enabled [optional] If this row is initially enabled. Default true.
|
||||
virtual void addRow(const char* label, const char* callback, S32 icon = -1, S32 yPad = 0, bool useHighlightIcon = true, bool enabled = true);
|
||||
virtual void addRow(const char* label, const char* callback, S32 icon = -1, S32 yPad = 0, bool useHighlightIcon = true, bool enabled = true, S32 mode = 0);
|
||||
|
||||
/// Adds a row to the control.
|
||||
///
|
||||
/// \param label The text to display on the row as a label.
|
||||
/// \param optionsList A tab separated list of options for the control.
|
||||
/// \param wrapOptions Specify true to allow options to wrap at the ends or
|
||||
/// false to prevent wrapping.
|
||||
/// \param callback [optional] Name of a script function to use as a callback
|
||||
/// when this row is activated. Default NULL means no callback.
|
||||
/// \param icon [optional] Index of the icon to use as a marker. Default -1
|
||||
/// means no icon will be shown on this row.
|
||||
/// \param yPad [optional] An extra amount of height padding before the row.
|
||||
/// \param enabled [optional] If this row is initially enabled. Default true.
|
||||
void addRow(const char* label, const char* optionsList, bool wrapOptions, const char* callback, S32 icon, S32 yPad, bool enabled);
|
||||
|
||||
/// Gets the text for the currently selected option of the given row.
|
||||
///
|
||||
/// \param rowIndex Index of the row to get the option from.
|
||||
/// \return A string representing the text currently displayed as the selected
|
||||
/// option on the given row. If there is no such displayed text then the empty
|
||||
/// string is returned.
|
||||
StringTableEntry getCurrentOption(S32 rowIndex) const;
|
||||
|
||||
/// Attempts to set the given row to the specified selected option. The option
|
||||
/// will only be set if the option exists in the control.
|
||||
///
|
||||
/// \param rowIndex Index of the row to set an option on.
|
||||
/// \param option The option to be made active.
|
||||
/// \return True if the row contained the option and was set, false otherwise.
|
||||
bool selectOption(S32 rowIndex, StringTableEntry option);
|
||||
|
||||
/// Sets the list of options on the given row.
|
||||
///
|
||||
/// \param rowIndex Index of the row to set options on.
|
||||
/// \param optionsList A tab separated list of options for the control.
|
||||
void setOptions(S32 rowIndex, const char* optionsList);
|
||||
|
||||
/// Activates the current row. The script callback of the current row will
|
||||
/// be called (if it has one).
|
||||
|
|
@ -115,6 +171,8 @@ public:
|
|||
|
||||
void onRender(Point2I offset, const RectI &updateRect);
|
||||
|
||||
void onRenderOptionList(Row* row, Point2I currentOffset);
|
||||
|
||||
/// Callback when the object is registered with the sim.
|
||||
///
|
||||
/// \return True if the profile was successfully added, false otherwise.
|
||||
|
|
@ -158,6 +216,8 @@ public:
|
|||
/// \param event A reference to the event that triggered the callback.
|
||||
void onMouseUp(const GuiEvent &event);
|
||||
|
||||
virtual bool onInputEvent(const InputEventInfo& event);
|
||||
|
||||
/// Callback when the gamepad axis is activated.
|
||||
///
|
||||
/// \param event A reference to the event that triggered the callback.
|
||||
|
|
@ -168,6 +228,20 @@ public:
|
|||
/// \param event A reference to the event that triggered the callback.
|
||||
virtual bool onGamepadAxisDown(const GuiEvent & event);
|
||||
|
||||
/// Callback when the gamepad axis is activated.
|
||||
///
|
||||
/// \param event A reference to the event that triggered the callback.
|
||||
virtual bool onGamepadAxisLeft(const GuiEvent& event);
|
||||
|
||||
/// Callback when the gamepad axis is activated.
|
||||
///
|
||||
/// \param event A reference to the event that triggered the callback.
|
||||
virtual bool onGamepadAxisRight(const GuiEvent& event);
|
||||
|
||||
void clearRows();
|
||||
|
||||
RectI getRowBounds(S32 rowIndex);
|
||||
|
||||
DECLARE_CONOBJECT(GuiGameListMenuCtrl);
|
||||
DECLARE_CATEGORY( "Gui Game" );
|
||||
DECLARE_DESCRIPTION( "Base class for cross platform menu controls that are gamepad friendly." );
|
||||
|
|
@ -177,6 +251,7 @@ public:
|
|||
|
||||
static const S32 NO_ROW = -1; ///< Indicates a query result of no row found.
|
||||
static const S32 NO_ICON = -1; ///< Indicates a row has no extra icon available
|
||||
static const S32 NO_OPTION = -1; ///< Indicates there is no option
|
||||
|
||||
protected:
|
||||
/// Adds a row to the control.
|
||||
|
|
@ -189,7 +264,7 @@ protected:
|
|||
/// means no icon will be shown on this row.
|
||||
/// \param yPad [optional] An extra amount of height padding before the row.
|
||||
/// \param enabled [optional] If this row is initially enabled. Default true.
|
||||
virtual void addRow(Row * row, const char* label, const char* callback, S32 icon, S32 yPad, bool useHighlightIcon, bool enabled);
|
||||
virtual void addRow(Row * row, const char* label, const char* callback, S32 icon, S32 yPad, bool useHighlightIcon, bool enabled, S32 mode = 0);
|
||||
|
||||
/// Determines if the given index is a valid row index. Any index pointing at
|
||||
/// an existing row is valid.
|
||||
|
|
@ -224,6 +299,10 @@ protected:
|
|||
/// @name Callbacks
|
||||
/// @{
|
||||
DECLARE_CALLBACK( void, onChange, () );
|
||||
|
||||
DECLARE_CALLBACK(void, onInputEvent, (const char* device, const char* action, bool state));
|
||||
|
||||
DECLARE_CALLBACK(void, onAxisEvent, (const char* device, const char* action, F32 axisValue));
|
||||
/// @}
|
||||
|
||||
/// Evaluates some script. If the command is empty then nothing is evaluated.
|
||||
|
|
@ -239,6 +318,30 @@ protected:
|
|||
bool mDebugRender; ///< Determines when to show debug render lines
|
||||
Vector<Row *> mRows; ///< Holds data wrappers on all the rows we have
|
||||
|
||||
private:
|
||||
/// Performs a click on the current option row. The x position is used to
|
||||
/// determine if the left or right arrow were clicked. If one was clicked, the
|
||||
/// option will be changed. If neither was clicked, the option is unaffected.
|
||||
/// This method should only be called when there is an actively selected row.
|
||||
///
|
||||
/// \param row The row to perform the click on.
|
||||
/// \param xPos The x position of the the click, relative to the control.
|
||||
void clickOption(Row* row, S32 xPos);
|
||||
|
||||
/// Changes the option on the currently selected row. If there is no row
|
||||
/// selected, this method does nothing.
|
||||
///
|
||||
/// \param delta The amount to change the option selection by. Typically this
|
||||
/// will be 1 or -1.
|
||||
void changeOption(S32 delta);
|
||||
|
||||
/// Changes the option on the given row.
|
||||
///
|
||||
/// \param row The row to change the option on.
|
||||
/// \param delta The amount to change the option selection by. Typically this
|
||||
/// will be 1 or -1.
|
||||
void changeOption(Row* row, S32 delta);
|
||||
|
||||
private:
|
||||
/// Recalculates the height of this control based on the stored row height and
|
||||
/// and padding on the rows.
|
||||
|
|
@ -260,6 +363,8 @@ private:
|
|||
|
||||
S32 mSelected; ///< index of the currently selected row
|
||||
S32 mHighlighted; ///< index of the currently highlighted row
|
||||
|
||||
bool mCallbackOnInputs;
|
||||
};
|
||||
|
||||
/// \class GuiGameListMenuProfile
|
||||
|
|
@ -325,6 +430,9 @@ public:
|
|||
Point2I mIconOffset; ///< Offset for a row's extra icon
|
||||
Point2I mRowSize; ///< The base size of a row
|
||||
|
||||
S32 mColumnSplit; ///< Absolute position of the split between columns
|
||||
S32 mRightPad; ///< Extra padding between the right arrow and the hit area
|
||||
|
||||
GuiGameListMenuProfile();
|
||||
|
||||
DECLARE_CONOBJECT(GuiGameListMenuProfile);
|
||||
|
|
|
|||
|
|
@ -419,6 +419,11 @@ bool GuiGameListOptionsCtrl::selectOption(S32 rowIndex, const char * theOption)
|
|||
return false;
|
||||
}
|
||||
|
||||
void GuiGameListOptionsCtrl::clearRows()
|
||||
{
|
||||
mRows.clear();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Console stuff (GuiGameListOptionsCtrl)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -484,6 +489,15 @@ DefineEngineMethod( GuiGameListOptionsCtrl, setOptions, void, ( S32 row, const c
|
|||
object->setOptions( row, optionsList );
|
||||
}
|
||||
|
||||
DefineEngineMethod(GuiGameListOptionsCtrl, clearOptions, void, (), ,
|
||||
"Sets the list of options on the given row.\n\n"
|
||||
"@param row Index of the row to set options on."
|
||||
"@param optionsList A tab separated list of options for the control.")
|
||||
{
|
||||
object->clearRows();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GuiGameListOptionsProfile
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -41,7 +41,16 @@ protected:
|
|||
S32 mSelectedOption; ///< Index into mOptions pointing at the selected option
|
||||
bool mWrapOptions; ///< Determines if options should "wrap around" at the ends
|
||||
|
||||
Row() : mSelectedOption(0), mWrapOptions(false)
|
||||
enum Mode
|
||||
{
|
||||
Default = 0,
|
||||
OptionsList,
|
||||
Keybind
|
||||
};
|
||||
|
||||
Mode mMode;
|
||||
|
||||
Row() : mSelectedOption(0), mWrapOptions(false), mMode(Mode::Default)
|
||||
{
|
||||
VECTOR_SET_ASSOCIATION( mOptions );
|
||||
}
|
||||
|
|
@ -111,6 +120,8 @@ public:
|
|||
/// \param event A reference to the event that triggered the callback.
|
||||
virtual bool onGamepadAxisRight(const GuiEvent &event);
|
||||
|
||||
virtual void clearRows();
|
||||
|
||||
GuiGameListOptionsCtrl();
|
||||
~GuiGameListOptionsCtrl();
|
||||
|
||||
|
|
|
|||
|
|
@ -516,6 +516,39 @@ bool GuiTextListCtrl::onKeyDown( const GuiEvent &event )
|
|||
|
||||
}
|
||||
|
||||
bool GuiTextListCtrl::onGamepadAxisUp(const GuiEvent& event)
|
||||
{
|
||||
if (mSelectedCell.y < (mList.size() - 1))
|
||||
{
|
||||
S32 yDelta = 0;
|
||||
|
||||
mSelectedCell.y++;
|
||||
yDelta = mCellSize.y;
|
||||
|
||||
GuiScrollCtrl* parent = dynamic_cast<GuiScrollCtrl*>(getParent());
|
||||
if (parent)
|
||||
parent->scrollDelta(0, yDelta);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GuiTextListCtrl::onGamepadAxisDown(const GuiEvent& event)
|
||||
{
|
||||
if (mSelectedCell.y > 0)
|
||||
{
|
||||
S32 yDelta = 0;
|
||||
|
||||
mSelectedCell.y--;
|
||||
yDelta = -mCellSize.y;
|
||||
|
||||
GuiScrollCtrl* parent = dynamic_cast<GuiScrollCtrl*>(getParent());
|
||||
if (parent)
|
||||
parent->scrollDelta(0, yDelta);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Console Methods
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -104,6 +104,8 @@ class GuiTextListCtrl : public GuiArrayCtrl
|
|||
const char *getSelectedText();
|
||||
|
||||
bool onKeyDown(const GuiEvent &event);
|
||||
bool onGamepadAxisUp(const GuiEvent& event);
|
||||
bool onGamepadAxisDown(const GuiEvent& event);
|
||||
|
||||
virtual void onRenderCell(Point2I offset, Point2I cell, bool selected, bool mouseOver);
|
||||
|
||||
|
|
|
|||
|
|
@ -1082,7 +1082,7 @@ bool GuiCanvas::processGamepadEvent(InputEventInfo &inputEvent)
|
|||
case SI_YAXIS:
|
||||
case XI_THUMBLY:
|
||||
case XI_THUMBRY:
|
||||
if (negative)
|
||||
if (!negative)
|
||||
{
|
||||
return mFirstResponder->onGamepadAxisDown(mLastEvent);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue