diff --git a/Engine/source/gui/controls/guiGameSettingsCtrl.cpp b/Engine/source/gui/controls/guiGameSettingsCtrl.cpp new file mode 100644 index 000000000..1b6516e4a --- /dev/null +++ b/Engine/source/gui/controls/guiGameSettingsCtrl.cpp @@ -0,0 +1,1121 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#include "guiGameSettingsCtrl.h" + +#include "console/consoleTypes.h" +#include "console/engineAPI.h" +#include "gfx/gfxDrawUtil.h" +#include "gui/containers/guiScrollCtrl.h" +#include "core/strings/stringUnit.h" +#include "gui/core/guiDefaultControlRender.h" + +//----------------------------------------------------------------------------- +// GuiGameSettingsCtrl +//----------------------------------------------------------------------------- + +GuiGameSettingsCtrl::GuiGameSettingsCtrl() : + mLabel(StringTable->EmptyString()), + mScriptCallback(StringTable->EmptyString()), + mTooltip(StringTable->EmptyString()), + mEnabled(true), + mSelected(false), + mSelectedOption(0), + mWrapOptions(false), + mMode(Mode::Default), + mValue(0), + mStepSize(1), + mRange(Point2F(0, 1)), + mCallbackOnInputs(false), + mConsumeKeyInputEvents(false), + mArrowSize(30), + mColumnSplit(250), + mRightPad(20) +{ + VECTOR_SET_ASSOCIATION(mOptions); + + // initialize the control callbacks + mCallbackOnA = StringTable->EmptyString(); + mCallbackOnB = mCallbackOnA; + mCallbackOnX = mCallbackOnA; + mCallbackOnY = mCallbackOnA; + + INIT_ASSET(KeybindBitmap); + INIT_ASSET(PreviousBitmap); + INIT_ASSET(NextBitmap); +} + +GuiGameSettingsCtrl::~GuiGameSettingsCtrl() +{ + mOptions.clear(); +} + +void GuiGameSettingsCtrl::onMouseMove(const GuiEvent& event) +{ + //check if we're inside an arrow/slider/etc and kick a highlight action + Parent::onMouseMove(event); +} + +void GuiGameSettingsCtrl::onMouseUp(const GuiEvent& event) +{ + Parent::onMouseUp(event); + + if (isEnabled()) + { + if (mMode == Mode::Default) + { + activate(); + } + else if (mMode == Mode::OptionList) + { + S32 xPos = globalToLocalCoord(event.mousePoint).x; + clickOption(xPos); + } + else if (mMode == Mode::Slider) + { + S32 xPos = globalToLocalCoord(event.mousePoint).x; + clickSlider(xPos); + } + else if (mMode == Mode::Keybind) + { + S32 xPos = globalToLocalCoord(event.mousePoint).x; + clickKeybind(xPos); + } + } +} + +void GuiGameSettingsCtrl::onRender(Point2I offset, const RectI &updateRect) +{ + GFXDrawUtil* drawUtil = GFX->getDrawUtil(); + + F32 xScale = (float) getWidth(); + + S32 height = getHeight(); + + Point2I currentOffset = offset; + Point2I extent = getExtent(); + Point2I textOffset(mProfile->mTextOffset.x * xScale, mProfile->mTextOffset.y); + Point2I textExtent(mColumnSplit, height); + Point2I iconExtent, iconOffset(0.0f, 0.0f); + + bool highlight = mHighlighted; + bool depressed = mDepressed; + + ColorI fontColor = mActive ? (highlight ? mProfile->mFontColorHL : mProfile->mFontColor) : mProfile->mFontColorNA; + ColorI fillColor = mActive ? (highlight ? mProfile->mFillColorHL : mProfile->mFillColor) : mProfile->mFillColorNA; + ColorI borderColor = mActive ? (highlight ? mProfile->mBorderColorHL : mProfile->mBorderColor) : mProfile->mBorderColorNA; + + RectI boundsRect(offset, getExtent()); + + if (!mHasTheme) + { + if (mProfile->mBorder != 0) + renderFilledBorder(boundsRect, borderColor, fillColor, mProfile->mBorderThickness); + else + GFX->getDrawUtil()->drawRectFill(boundsRect, fillColor); + } + else + { + S32 indexMultiplier = 1; + + if (!mActive) + indexMultiplier = 4; + else if (mDepressed || mStateOn) + indexMultiplier = 2; + else if (mHighlighted) + indexMultiplier = 3; + + renderSizableBitmapBordersFilled(boundsRect, indexMultiplier, mProfile); + } + + // render the text + drawUtil->setBitmapModulation(fontColor); + renderJustifiedText(currentOffset + textOffset, textExtent, mLabel); + + if (mMode == Mode::OptionList) + { + onRenderListOption(currentOffset); + } + else if (mMode == Mode::Slider) + { + onRenderSliderOption(currentOffset); + } + else if (mMode == Mode::Keybind) + { + onRenderKeybindOption(currentOffset); + } + + renderChildControls(offset, updateRect); +} + +void GuiGameSettingsCtrl::onRenderListOption(Point2I currentOffset) +{ + F32 xScale = (float)getWidth(); + + S32 height = getHeight(); + + GFXDrawUtil* drawer = GFX->getDrawUtil(); + + Point2I arrowOffset; + + S32 arrowOffsetY = 0; + + bool hasOptions = (mOptions.size() > 0) && mSelectedOption > -1; + if (hasOptions) + { + if (mPreviousBitmapAsset.notNull()) + { + // render the left arrow + bool arrowOnL = (isSelected() || isHighlighted()) && (mWrapOptions || (mSelectedOption > 0)); + arrowOffset.x = currentOffset.x + mColumnSplit; + arrowOffset.y = currentOffset.y + arrowOffsetY; + + drawer->clearBitmapModulation(); + drawer->drawBitmapStretch(mPreviousBitmap, RectI(arrowOffset, Point2I(mArrowSize, mArrowSize)), GFXBitmapFlip_None, GFXTextureFilterLinear, false); + } + else + { + // render the left arrow + bool arrowOnL = (isSelected() || isHighlighted()) && (mWrapOptions || (mSelectedOption > 0)); + arrowOffset.x = currentOffset.x + mColumnSplit; + arrowOffset.y = currentOffset.y + height/2; + + drawer->clearBitmapModulation(); + + drawer->drawLine(arrowOffset, Point2I(arrowOffset.x + mArrowSize, currentOffset.y), ColorI::WHITE); + drawer->drawLine(arrowOffset, Point2I(arrowOffset.x + mArrowSize, currentOffset.y + height), ColorI::WHITE); + } + + if (mNextBitmapAsset.notNull()) + { + // render the right arrow + bool arrowOnR = (isSelected() || isHighlighted()) && (mWrapOptions || (mSelectedOption < mOptions.size() - 1)); + arrowOffset.x = currentOffset.x + getWidth() - mRightPad - mArrowSize; + arrowOffset.y = currentOffset.y + arrowOffsetY; + + drawer->clearBitmapModulation(); + drawer->drawBitmapStretch(mNextBitmap, RectI(arrowOffset, Point2I(mArrowSize, mArrowSize)), GFXBitmapFlip_None, GFXTextureFilterLinear, false); + } + else + { + // render the left arrow + bool arrowOnL = (isSelected() || isHighlighted()) && (mWrapOptions || (mSelectedOption > 0)); + arrowOffset.x = currentOffset.x + getWidth() - mRightPad; + arrowOffset.y = currentOffset.y + height / 2; + + drawer->clearBitmapModulation(); + + drawer->drawLine(arrowOffset, Point2I(arrowOffset.x - mArrowSize, currentOffset.y), ColorI::WHITE); + drawer->drawLine(arrowOffset, Point2I(arrowOffset.x - mArrowSize, currentOffset.y + height), ColorI::WHITE); + } + + // get the appropriate font color + ColorI fontColor; + if (!mEnabled) + { + fontColor = mProfile->mFontColorNA; + } + else if (isSelected()) + { + fontColor = mProfile->mFontColorSEL; + } + else if (isHighlighted()) + { + fontColor = mProfile->mFontColorHL; + } + else + { + fontColor = mProfile->mFontColor; + } + + // calculate text to be at the center between the arrows + GFont* font = mProfile->mFont; + StringTableEntry text = mOptions[mSelectedOption].mDisplayText; + S32 textWidth = font->getStrWidth(text); + S32 columnWidth = xScale - mRightPad - mColumnSplit; + S32 columnCenter = mColumnSplit + (columnWidth >> 1); + S32 textStartX = columnCenter - (textWidth >> 1); + Point2I textOffset(textStartX, 0); + + // render the option text itself + Point2I textExtent(columnWidth, height); + drawer->setBitmapModulation(fontColor); + renderJustifiedText(currentOffset + Point2I(mColumnSplit, 0), textExtent, text); + } +} + +void GuiGameSettingsCtrl::onRenderSliderOption(Point2I currentOffset) +{ + F32 xScale = (float)getWidth(); + + S32 height = getHeight(); + + S32 arrowOffsetY = 0; + + GFXDrawUtil* drawer = GFX->getDrawUtil(); + + Point2I arrowOffset; + S32 columnSplit = mColumnSplit; + + + + /*if (mPreviousBitmapAsset.notNull()) + { + // render the left arrow + bool arrowOnL = (isSelected() || isHighlighted()) && (mWrapOptions || (mSelectedOption > 0)); + arrowOffset.x = currentOffset.x + columnSplit; + arrowOffset.y = currentOffset.y + arrowOffsetY; + + drawer->clearBitmapModulation(); + drawer->drawBitmapStretch(mPreviousBitmap, RectI(arrowOffset, Point2I(mArrowSize, mArrowSize)), GFXBitmapFlip_None, GFXTextureFilterLinear, false); + } + else + { + // render the left arrow + bool arrowOnL = (isSelected() || isHighlighted()) && (mWrapOptions || (mSelectedOption > 0)); + arrowOffset.x = currentOffset.x + mColumnSplit; + arrowOffset.y = currentOffset.y + height / 2; + + drawer->clearBitmapModulation(); + + drawer->drawLine(arrowOffset, Point2I(arrowOffset.x + mArrowSize, currentOffset.y), ColorI::WHITE); + drawer->drawLine(arrowOffset, Point2I(arrowOffset.x + mArrowSize, currentOffset.y + height), ColorI::WHITE); + } + + if (mNextBitmapAsset.notNull()) + { + // render the right arrow + bool arrowOnR = (isSelected() || isHighlighted()) && (mWrapOptions || (mSelectedOption < mOptions.size() - 1)); + arrowOffset.x = currentOffset.x + mRightPad * xScale - mArrowSize; + arrowOffset.y = currentOffset.y + arrowOffsetY; + + drawer->clearBitmapModulation(); + drawer->drawBitmapStretch(mNextBitmap, RectI(arrowOffset, Point2I(mArrowSize, mArrowSize)), GFXBitmapFlip_None, GFXTextureFilterLinear, false); + } + else + { + // render the left arrow + bool arrowOnL = (isSelected() || isHighlighted()) && (mWrapOptions || (mSelectedOption > 0)); + arrowOffset.x = currentOffset.x + getWidth() - mRightPad; + arrowOffset.y = currentOffset.y + height / 2; + + drawer->clearBitmapModulation(); + + drawer->drawLine(arrowOffset, Point2I(arrowOffset.x - mArrowSize, currentOffset.y), ColorI::WHITE); + drawer->drawLine(arrowOffset, Point2I(arrowOffset.x - mArrowSize, currentOffset.y + height), ColorI::WHITE); + }*/ + + //Draw the slider bar + + RectI sliderRect; + + S32 sliderOffset = 5; + + RectI optionRect; + + sliderRect.point.x = currentOffset.x + columnSplit + mArrowSize; + sliderRect.point.y = currentOffset.y + sliderOffset; + + sliderRect.extent.x = (currentOffset.x + getWidth() - mRightPad - mArrowSize) - sliderRect.point.x; + sliderRect.extent.y = height - sliderOffset*2; + + optionRect = sliderRect; + + S32 textWidth = sliderRect.extent.x * 0.3; + sliderRect.extent.x -= textWidth; + + //Now adjust the bar to match-to our value + + S32 barStart = sliderRect.point.x; + S32 barEnd = sliderRect.point.x + sliderRect.extent.x; + + S32 xPosFill = (((mValue - mRange.x) * (barEnd - barStart)) / (mRange.y - mRange.x)) + barStart; + + RectI fillRect = sliderRect; + fillRect.extent.x = xPosFill - sliderRect.point.x; + + ColorI barColor; + ColorI barOutlineColor; + if (isSelected()) + { + barColor = mProfile->mFontColor; + barOutlineColor = mProfile->mFontColorSEL; + } + else + { + barColor = mProfile->mFontColor; + barOutlineColor = mProfile->mFontColorHL; + } + + drawer->drawRectFill(fillRect, barColor); + + drawer->drawRect(sliderRect, barOutlineColor); + + // get the appropriate font color + ColorI fontColor; + if (!mEnabled) + { + fontColor = mProfile->mFontColorNA; + } + else if (isSelected()) + { + fontColor = mProfile->mFontColorSEL; + } + else if (isHighlighted()) + { + fontColor = mProfile->mFontColorHL; + } + else + { + fontColor = mProfile->mFontColor; + } + + // calculate text to be at the center between the arrows + GFont* font = mProfile->mFont; + + char stringVal[32]; + dSprintf(stringVal, 32, "%f", mValue); + + S32 stringWidth = font->getStrWidth(stringVal); + Point2I textOffset(sliderRect.point.x + sliderRect.extent.x, 0); + + // render the option text itself + Point2I textExtent(textWidth, height); + + RectI textRect = optionRect; + textRect.point.x = sliderRect.point.x + sliderRect.extent.x; + textRect.extent.x = optionRect.extent.x * 0.3; + + drawer->setBitmapModulation(fontColor); + renderJustifiedText(textRect.point, textRect.extent, stringVal); + + //drawer->drawRectFill(textRect, ColorI::RED); +} + +void GuiGameSettingsCtrl::onRenderKeybindOption(Point2I currentOffset) +{ + F32 xScale = (float)getWidth(); + S32 columnSplit = mColumnSplit; + + S32 height = getHeight(); + + GFXDrawUtil* drawer = GFX->getDrawUtil(); + //drawer->drawBitmap(mBitmap, ) + + Point2I button; + button.x = currentOffset.x + columnSplit + (columnSplit / 2.5)/* + (optionWidth / 2)*/; + button.y = currentOffset.y; + + Point2I buttonSize; + buttonSize.x = height; + buttonSize.y = height; + + if (mKeybindBitmapAsset.notNull()) + { + RectI rect(button, buttonSize); + drawer->clearBitmapModulation(); + drawer->drawBitmapStretch(mKeybindBitmap, rect, GFXBitmapFlip_None, GFXTextureFilterLinear, false); + } + + //drawer->drawRectFill(button, ColorI::BLUE); +} + +void GuiGameSettingsCtrl::set(const char* label, const char* callback, bool useHighlightIcon, bool enabled, S32 mode, const char* tooltip) +{ + mScriptCallback = (dStrlen(callback) > 0) ? StringTable->insert(callback, true) : NULL; + mEnabled = enabled; + mMode = (Mode)mode; + mTooltip = StringTable->insert(tooltip); + mLabel = StringTable->insert(label, true); +} + +void GuiGameSettingsCtrl::setListSetting(const char* label, const char* optionsList, bool wrapOptions, const char* callback, bool enabled, const char* tooltip, const char* defaultValue) +{ + static StringTableEntry DELIM = StringTable->insert("\t", true); + + Vector options(__FILE__, __LINE__); + + S32 defaultOption = 0; + + S32 count = StringUnit::getUnitCount(optionsList, DELIM); + for (S32 i = 0; i < count; ++i) + { + OptionEntry e; + const char* option = StringUnit::getUnit(optionsList, i, DELIM); + e.mDisplayText = StringTable->insert(option, true); + e.mKeyString = e.mDisplayText; + options.push_back(e); + + if (String::compare(option, defaultValue) == 0) + defaultOption = options.size() - 1; + } + mOptions = options; + bool hasOptions = mOptions.size() > 0; + mSelectedOption = (hasOptions) ? defaultOption : NO_OPTION; + mWrapOptions = wrapOptions; + set(label, callback, true, (hasOptions) ? enabled : false, Mode::OptionList, tooltip); +} + +void GuiGameSettingsCtrl::setSliderSetting(const char* label, F32 defaultValue, F32 increments, Point2F range, const char* callback, bool enabled, const char* tooltip) +{ + static StringTableEntry DELIM = StringTable->insert("\t", true); + + mValue = defaultValue; + mStepSize = increments; + mRange = range; + + set(label, callback, true, enabled, Mode::Slider, tooltip); +} + +void GuiGameSettingsCtrl::setKeybindSetting(const char* label, const char* bitmapName, const char* callback, bool enabled, const char* tooltip) +{ + static StringTableEntry DELIM = StringTable->insert("\t", true); + + _setKeybindBitmap(StringTable->insert(bitmapName)); + + //if(mBitmap != StringTable->EmptyString()) + // mBitmapTex.set(mBitmap, &GFXDefaultGUIProfile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__)); + + set(label, callback, true, enabled, Mode::Keybind, tooltip); +} + +bool GuiGameSettingsCtrl::onAdd() +{ + if( !Parent::onAdd() ) + return false; + + return true; +} + +bool GuiGameSettingsCtrl::onWake() +{ + if( !Parent::onWake() ) + return false; + + return true; +} +void GuiGameSettingsCtrl::activate() +{ + if(isSelected() && isEnabled() && (mScriptCallback != StringTable->EmptyString())) + { + setThisControl(); + if (Con::isFunction(mScriptCallback)) + { + Con::executef(mScriptCallback); + } + } +} + +void GuiGameSettingsCtrl::setSelected() +{ + if (!isEnabled()) + return; + + mSelected = true; +} + +bool GuiGameSettingsCtrl::isEnabled() const +{ + return mEnabled; +} + +void GuiGameSettingsCtrl::setEnabled(bool enabled) +{ + mEnabled = enabled; +} + +void GuiGameSettingsCtrl::doScriptCommand(StringTableEntry command) +{ + if (command && command[0]) + { + setThisControl(); + Con::evaluate(command, false, __FILE__); + } +} + +void GuiGameSettingsCtrl::setThisControl() +{ + smThisControl = this; +} + +StringTableEntry GuiGameSettingsCtrl::getLabel() const +{ + return mLabel; +} + +void GuiGameSettingsCtrl::setLabel( const char * label) +{ + mLabel = StringTable->insert(label, true); +} + +void GuiGameSettingsCtrl::clear() +{ + mOptions.clear(); +} + +//----------------------------------------------------------------------------- +// Console stuff (GuiGameSettingsCtrl) +//----------------------------------------------------------------------------- + +StringTableEntry GuiGameSettingsCtrl::getCurrentOption() const +{ + if (mSelectedOption != NO_OPTION && !mOptions.empty()) + { + return mOptions[mSelectedOption].mDisplayText; + } + + return StringTable->insert("", false); +} + +StringTableEntry GuiGameSettingsCtrl::getCurrentOptionKey() const +{ + if (mSelectedOption != NO_OPTION) + { + return mOptions[mSelectedOption].mKeyString; + } + + return StringTable->insert("", false); +} + +S32 GuiGameSettingsCtrl::getCurrentOptionIndex() const +{ + if (mSelectedOption != NO_OPTION) + { + return mSelectedOption; + } + + return S32(-1); +} + +bool GuiGameSettingsCtrl::selectOption(const char* theOption) +{ + for (Vector::iterator anOption = mOptions.begin(); anOption < mOptions.end(); ++anOption) + { + if (String::compare((*anOption).mDisplayText, theOption) == 0) + { + S32 newIndex = anOption - mOptions.begin(); + mSelectedOption = newIndex; + return true; + } + } + + return false; +} + +bool GuiGameSettingsCtrl::selectOptionByKey(const char* optionKey) +{ + for (Vector::iterator anOption = mOptions.begin(); anOption < mOptions.end(); ++anOption) + { + if (String::compare((*anOption).mKeyString, optionKey) == 0) + { + S32 newIndex = anOption - mOptions.begin(); + mSelectedOption = newIndex; + return true; + } + } + + return false; +} + +bool GuiGameSettingsCtrl::selectOptionByIndex(S32 optionIndex) +{ + if (optionIndex < mOptions.size() && optionIndex >= 0) + { + mSelectedOption = optionIndex; + return true; + } + + return false; +} + +void GuiGameSettingsCtrl::setOptions(const char* optionsList) +{ + static StringTableEntry DELIM = StringTable->insert("\t", true); + + S32 count = StringUnit::getUnitCount(optionsList, DELIM); + mOptions.setSize(count); + for (S32 i = 0; i < count; ++i) + { + const char* option = StringUnit::getUnit(optionsList, i, DELIM); + OptionEntry e; + e.mDisplayText = StringTable->insert(option, true); + e.mKeyString = e.mDisplayText; + mOptions[i] = e; + } + + if (mSelectedOption >= mOptions.size()) + { + mSelectedOption = mOptions.size() - 1; + } +} + +void GuiGameSettingsCtrl::addOption(const char* displayText, const char* keyText) +{ + OptionEntry e; + e.mDisplayText = StringTable->insert(displayText, true); + e.mKeyString = (keyText[0] == '\0') ? e.mDisplayText : StringTable->insert(keyText, true); + + mOptions.push_back(e); +} + +void GuiGameSettingsCtrl::clickOption(S32 xPos) +{ + F32 xScale = (float)getWidth(); + + S32 leftArrowX1 = mColumnSplit; + S32 leftArrowX2 = leftArrowX1 + mArrowSize; + + S32 rightArrowX2 = getWidth() - mRightPad; + S32 rightArrowX1 = rightArrowX2 - mArrowSize; + + if ((leftArrowX1 <= xPos) && (xPos <= leftArrowX2)) + { + changeOption(-1); + } + else if ((rightArrowX1 <= xPos) && (xPos <= rightArrowX2)) + { + changeOption(1); + } +} + +void GuiGameSettingsCtrl::changeOption(S32 delta) +{ + S32 optionCount = mOptions.size(); + + S32 newSelection = mSelectedOption + delta; + if (optionCount == 0) + { + newSelection = NO_OPTION; + } + else if (!mWrapOptions) + { + newSelection = mClamp(newSelection, 0, optionCount - 1); + } + else if (newSelection < 0) + { + newSelection = optionCount - 1; + } + else if (newSelection >= optionCount) + { + newSelection = 0; + } + mSelectedOption = newSelection; + + if (mMode == GuiGameSettingsCtrl::Slider) + { + mValue += mStepSize * delta; + + mValue = mRound(mValue / mStepSize) * mStepSize; + + if (mValue < mRange.x) + mValue = mRange.x; + if (mValue > mRange.y) + mValue = mRange.y; + } + + static StringTableEntry LEFT = StringTable->insert("LEFT", true); + static StringTableEntry RIGHT = StringTable->insert("RIGHT", true); + + onChange_callback(); + + if (mScriptCallback != NULL && (mSelectedOption != NO_OPTION && mMode != GuiGameSettingsCtrl::Slider)) + { + setThisControl(); + StringTableEntry direction = NULL; + if (delta < 0) + { + direction = LEFT; + } + else if (delta > 0) + { + direction = RIGHT; + } + if ((direction != NULL) && (Con::isFunction(mScriptCallback))) + { + Con::executef(mScriptCallback, direction); + } + } +} +IMPLEMENT_CONOBJECT(GuiGameSettingsCtrl); + +void GuiGameSettingsCtrl::clickSlider(S32 xPos) +{ + F32 xScale = (float)getWidth(); + + S32 leftArrowX1 = mColumnSplit; + S32 leftArrowX2 = leftArrowX1 + mArrowSize; + + S32 rightArrowX2 = getWidth() - mRightPad; + S32 rightArrowX1 = rightArrowX2 - mArrowSize; + + S32 sliderWidth = rightArrowX1 - leftArrowX2; + sliderWidth *= 0.6; //remove the number text spacing + + /*if ((leftArrowX1 <= xPos) && (xPos <= leftArrowX2)) + { + mValue -= mStepSize; + + mValue = mRound(mValue / mStepSize) * mStepSize; + + if (mValue < mRange.x) + mValue = mRange.x; + + } + else if ((rightArrowX1 <= xPos) && (xPos <= rightArrowX2)) + { + //F32 snap = mValue % mStepSize; + //mValue.y -= snap; + + mValue += mStepSize; + + mValue = mRound(mValue / mStepSize) * mStepSize; + + if (mValue > mRange.y) + mValue = mRange.y; + } + else + {*/ + //see if we clicked on the sliderbar itself + S32 barStart = leftArrowX2; + S32 barEnd = barStart + sliderWidth; + + if (xPos >= barStart && xPos <= barEnd) + { + //find the position + F32 newValue = (((xPos - barStart) * (mRange.y - mRange.x)) / (barEnd - barStart)) + mRange.x; + + newValue = mRound(newValue / mStepSize) * mStepSize; + + mValue = newValue; + } + //} + + onChange_callback(); +} + +void GuiGameSettingsCtrl::clickKeybind(S32 xPos) +{ + S32 columnSplit = mColumnSplit; + + S32 height = getHeight(); + + Point2I button; + button.x = columnSplit + (columnSplit / 2.5)/* + (optionWidth / 2)*/; + button.y = 0; + + Point2I buttonSize; + buttonSize.x = height; + buttonSize.y = height; + + RectI rect(button, buttonSize); + + onChange_callback(); + + if (rect.pointInRect(Point2I(xPos, getHeight()/2))) + { + if (mScriptCallback != StringTable->EmptyString()) + { + Con::executef(mScriptCallback, this); + } + } +} + +F32 GuiGameSettingsCtrl::getValue() +{ + return mValue; +} + +void GuiGameSettingsCtrl::setValue(F32 value) +{ + mValue = value; +} + +const char* GuiGameSettingsCtrl::getTooltip() +{ + return mTooltip; +} + +ConsoleDocClass( GuiGameSettingsCtrl, + "@brief A base class for cross platform menu controls that are gamepad friendly.\n\n" + + "This class is used to build row-based menu GUIs that can be easily navigated " + "using the keyboard, mouse or gamepad. The desired row can be selected using " + "the mouse, or by navigating using the Up and Down buttons.\n\n" + + "@tsexample\n\n" + "new GuiGameSettingsCtrl()\n" + "{\n" + " debugRender = \"0\";\n" + " callbackOnA = \"applyOptions();\";\n" + " callbackOnB = \"Canvas.setContent(MainMenuGui);\";\n" + " callbackOnX = \"\";\n" + " callbackOnY = \"revertOptions();\";\n" + " //Properties not specific to this control have been omitted from this example.\n" + "};\n" + "@endtsexample\n\n" + + "@see GuiGameSettingsProfile\n\n" + + "@ingroup GuiGame" +); + +IMPLEMENT_CALLBACK( GuiGameSettingsCtrl, onChange, void, (), (), + "Called when the setting's value changes." ); + +IMPLEMENT_CALLBACK(GuiGameSettingsCtrl, 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(GuiGameSettingsCtrl, 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 GuiGameSettingsCtrl::initPersistFields() +{ + INITPERSISTFIELD_IMAGEASSET(KeybindBitmap, GuiGameSettingsCtrl, "Bitmap used to display the bound key for this keybind option."); + INITPERSISTFIELD_IMAGEASSET(PreviousBitmap, GuiGameSettingsCtrl, "Bitmap used for the previous button when in list mode."); + INITPERSISTFIELD_IMAGEASSET(NextBitmap, GuiGameSettingsCtrl, "Bitmap used for the next button when in list mode."); + + addField("arrowSize", TypeS32, Offset(mArrowSize, GuiGameSettingsCtrl), + "Size of the arrow buttons' extents"); + + addField("columnSplit", TypeS32, Offset(mColumnSplit, GuiGameSettingsCtrl), + "Position of the split between the leftside label and the rightside setting parts"); + + addField("rightPad", TypeS32, Offset(mRightPad, GuiGameSettingsCtrl), + "Padding between the rightmost edge of the control and right arrow."); + + addField("callbackOnA", TypeString, Offset(mCallbackOnA, GuiGameSettingsCtrl), + "Script callback when the 'A' button is pressed. 'A' inputs are Keyboard: A, Return, Space; Gamepad: A, Start" ); + + addField("callbackOnB", TypeString, Offset(mCallbackOnB, GuiGameSettingsCtrl), + "Script callback when the 'B' button is pressed. 'B' inputs are Keyboard: B, Esc, Backspace, Delete; Gamepad: B, Back" ); + + addField("callbackOnX", TypeString, Offset(mCallbackOnX, GuiGameSettingsCtrl), + "Script callback when the 'X' button is pressed. 'X' inputs are Keyboard: X; Gamepad: X" ); + + addField("callbackOnY", TypeString, Offset(mCallbackOnY, GuiGameSettingsCtrl), + "Script callback when the 'Y' button is pressed. 'Y' inputs are Keyboard: Y; Gamepad: Y" ); + + addField("callbackOnInputs", TypeBool, Offset(mCallbackOnInputs, GuiGameSettingsCtrl), + "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."); + + addField("consumeKeyInputEvents", TypeBool, Offset(mConsumeKeyInputEvents, GuiGameSettingsCtrl), + "When callbackOnInputs is active, this indicates if the input event should be consumed, or allowed 'through' to let other things respond to the event as well."); + + + Parent::initPersistFields(); +} + +DefineEngineMethod( GuiGameSettingsCtrl, isEnabled, bool, (),, + "Determines if the control is enabled or disabled.\n\n" + "@return True if the control is enabled. False if the control is not enabled." ) +{ + return object->isEnabled(); +} + +DefineEngineMethod( GuiGameSettingsCtrl, setEnabled, void, ( bool enabled ),, + "Sets the control's enabled status according to the given parameters.\n\n" + "@param enabled Indicate true to enable the control or false to disable it." ) +{ + object->setEnabled( enabled ); +} + +DefineEngineMethod( GuiGameSettingsCtrl, activate, void, (),, + "Activates the control. The script callback of the control will be called (if it has one)." ) +{ + object->activate(); +} + +DefineEngineMethod(GuiGameSettingsCtrl, getLabel, const char *, (),, + "Gets the label displayed.\n\n" + "@return The label." ) +{ + return object->getLabel(); +} + +DefineEngineMethod(GuiGameSettingsCtrl, setLabel, void, ( const char* label ),, + "Sets the label.\n\n" + "@param label Text to set as the label.\n" ) +{ + object->setLabel(label ); +} + +DefineEngineMethod( GuiGameSettingsCtrl, setSelected, void, (),, + "Sets the control as selected. Can only select enabled controls." ) +{ + object->setSelected(); +} + +DefineEngineMethod( GuiGameSettingsCtrl, getSelected, bool, (),, + "Gets if the control is currently selected.\n\n" + "@return if the control is selected." ) +{ + return object->isSelected(); +} + +DefineEngineMethod(GuiGameSettingsCtrl, clear, void, (), , + "Clears the current options.\n\n") +{ + return object->clear(); +} + +DefineEngineMethod(GuiGameSettingsCtrl, getMode, S32, (), , + "Gets this control's options mode.\n\n") +{ + GuiGameSettingsCtrl::Mode mode = object->getMode(); + if (mode == GuiGameSettingsCtrl::Mode::OptionList) + return 0; + else if (mode == GuiGameSettingsCtrl::Mode::Slider) + return 1; + else if (mode == GuiGameSettingsCtrl::Mode::Keybind) + return 2; + else + return -1; +} + +DefineEngineMethod(GuiGameSettingsCtrl, setListSetting, void, + (const char* label, const char* options, bool wrapOptions, const char* callback, bool enabled, const char* tooltip, const char* defaultValue), + (true, "", ""), + "Sets this setting to a list.\n\n" + "@param label The text to display 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 control is activated.\n" + "@param enabled [optional] If this control is initially enabled.") +{ + object->setListSetting(label, options, wrapOptions, callback, enabled, tooltip, defaultValue); +} + +DefineEngineMethod(GuiGameSettingsCtrl, setSliderSetting, void, +(const char* label, F32 defaultValue, F32 increment, Point2F range, const char* callback, bool enabled, const char* tooltip), +(true, ""), +"Sets this setting to a slider.\n\n" +"@param label The text to display 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 control is activated.\n" +"@param enabled [optional] If this control is initially enabled.") +{ + object->setSliderSetting(label, defaultValue, increment, range, callback, enabled, tooltip); +} + +DefineEngineMethod(GuiGameSettingsCtrl, setKeybindSetting, void, +(const char* label, const char* bitmapName, const char* callback, bool enabled, const char* tooltip), +(true, ""), +"Sets this setting to a keybind.\n\n" +"@param label The text to display 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 control is activated.\n" +"@param enabled [optional] If this control is initially enabled.") +{ + object->setKeybindSetting(label, bitmapName, callback, enabled, tooltip); +} + +DefineEngineMethod(GuiGameSettingsCtrl, getCurrentOption, const char*, (), , + "Gets the text for the currently selected option .\n\n" + "@return A string representing the text currently displayed as the selected option. If there is no such displayed text then the empty string is returned.") +{ + return object->getCurrentOption(); +} + +DefineEngineMethod(GuiGameSettingsCtrl, getCurrentOptionKey, const char*, (), , + "Gets the key string for the currently selected option.\n\n" + "@return The key (or id) that was assigned to the selected option. If there is no selected option then the empty string is returned.") +{ + return object->getCurrentOptionKey(); +} + +DefineEngineMethod(GuiGameSettingsCtrl, getCurrentOptionIndex, S32, (), , + "Gets the index into the option list for the currently selected option.\n\n" + "@return The index of the selected option. If there is no selected option then -1 is returned.") +{ + return object->getCurrentOptionIndex(); +} + +DefineEngineMethod(GuiGameSettingsCtrl, selectOption, bool, (const char* option), , + "Set the control's current option to the one specified\n\n" + "@param option The option to be made active.\n" + "@return True if the control contained the option and was set, false otherwise.") +{ + return object->selectOption(option); +} + +DefineEngineMethod(GuiGameSettingsCtrl, selectOptionByKey, bool, (const char* optionKey), , + "Set the control's current option to the one with the specified key.\n\n" + "@param optionKey The key string that was assigned to the option to be made active.\n" + "@return True if the control contained the key and the option and was set, false otherwise.") +{ + return object->selectOptionByKey(optionKey); +} + +DefineEngineMethod(GuiGameSettingsCtrl, selectOptionByIndex, bool, (S32 optionIndex), , + "Set the control's current option to the one at the specified index.\n\n" + "@param optionIndex The index of the option to be made active.\n" + "@return True if the index was valid and the option and was set, false otherwise.") +{ + return object->selectOptionByIndex(optionIndex); +} + +DefineEngineMethod(GuiGameSettingsCtrl, setOptions, void, (const char* optionsList), , + "Sets the list of options on the given control.\n\n" + "@param optionsList A tab separated list of options for the control.") +{ + object->setOptions(optionsList); +} + +DefineEngineMethod(GuiGameSettingsCtrl, addOption, void, (const char* displayText, const char* keyText), (""), + "Adds an option to the list of options on the given control.\n\n" + "@param displayText The text to display for this option.\n" + "@param keyText [Optional] The id string to associate with this value. " + "If unset, the id will be the same as the display text.\n") +{ + object->addOption(displayText, keyText); +} + +DefineEngineMethod(GuiGameSettingsCtrl, getValue, F32, (), , + "Sets the list of options on the given control.\n\n" + "@param optionsList A tab separated list of options for the control.") +{ + return object->getValue(); +} + +DefineEngineMethod(GuiGameSettingsCtrl, setValue, void, (F32 value), , + "Sets the list of options on the given control.\n\n" + "@param optionsList A tab separated list of options for the control.") +{ + object->setValue(value); +} + +DefineEngineMethod(GuiGameSettingsCtrl, getTooltip, const char*, (), , + "Sets the list of options on the given control.\n\n" + "@param optionsList A tab separated list of options for the control.") +{ + return object->getTooltip(); +} diff --git a/Engine/source/gui/controls/guiGameSettingsCtrl.h b/Engine/source/gui/controls/guiGameSettingsCtrl.h new file mode 100644 index 000000000..d8aac95e8 --- /dev/null +++ b/Engine/source/gui/controls/guiGameSettingsCtrl.h @@ -0,0 +1,313 @@ +//----------------------------------------------------------------------------- +// Copyright (c) 2012 GarageGames, LLC +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +//----------------------------------------------------------------------------- + +#ifndef _GuiGameSettingsCtrl_H_ +#define _GuiGameSettingsCtrl_H_ + +#include "gui/buttons/guiButtonCtrl.h" +#include "T3D/assets/ImageAsset.h" + +/// \class GuiGameSettingsCtrl +/// A base class for cross platform menu controls that are gamepad friendly. +class GuiGameSettingsCtrl : public GuiButtonCtrl +{ +public: + typedef GuiButtonCtrl Parent; + + enum Mode + { + Default = 0, + OptionList, + Slider, + Keybind, + Text + }; + +protected: + + /// \struct OptionEntry + /// Display text and ID key for each entry in an option. + struct OptionEntry + { + StringTableEntry mDisplayText; ///< The text that is displayed for the option + StringTableEntry mKeyString; ///< Key value that is associated with this option + OptionEntry() : mDisplayText(StringTable->EmptyString()), mKeyString(StringTable->EmptyString()) {} + virtual ~OptionEntry() {} + }; + + + StringTableEntry mLabel; ///< Text to display in the control as a label + StringTableEntry mScriptCallback; ///< Script callback when control is activated + StringTableEntry mTooltip; ///< A descriptive tooltip message for what the control is + + Mode mMode; + + //List options + Vector 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 + + //Slider option + F32 mValue; ///< When working as a slider, this contains the value + F32 mStepSize; ///< When working as a slider, this is the increment levels in the range + Point2F mRange; ///< When working as a slider, this sets our min/max range + + //Keybind option + DECLARE_IMAGEASSET(GuiGameSettingsCtrl, KeybindBitmap, changeBitmap, GFXDefaultGUIProfile); + DECLARE_ASSET_SETGET(GuiGameSettingsCtrl, KeybindBitmap); + + DECLARE_IMAGEASSET(GuiGameSettingsCtrl, PreviousBitmap, changeBitmap, GFXDefaultGUIProfile); + DECLARE_ASSET_SETGET(GuiGameSettingsCtrl, PreviousBitmap); + + DECLARE_IMAGEASSET(GuiGameSettingsCtrl, NextBitmap, changeBitmap, GFXDefaultGUIProfile); + DECLARE_ASSET_SETGET(GuiGameSettingsCtrl, NextBitmap); + + S32 mArrowSize; + S32 mColumnSplit; //Padding between the leftmost edge of the control, and the left side of the 'option'. + S32 mRightPad; + + bool mEnabled; + bool mSelected; + +public: + void changeBitmap() {} + + /// Sets the control as selected . Only controls that are enabled can be selected. + virtual void setSelected(); + + /// Determines if the specified control is enabled or disabled. + /// + /// \return True if the specified control is enabled. False if the control is not + /// enabled + virtual bool isEnabled() const; + + /// Sets a control's enabled status according to the given parameters. + /// + /// \param enabled Indicate true to enable the control or false to disable it. + virtual void setEnabled(bool enabled); + + /// Gets the label displayed on the control. + /// + /// \return The label for the control. + virtual StringTableEntry getLabel() const; + + /// Sets the label on the control. + /// + /// \param label Text to set as the label. + virtual void setLabel(const char * label); + + /// Sets the control to a List setting. + /// + /// \param label The text to display on the control 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 control is activated. Default NULL means no callback. + /// \param enabled [optional] If this control is initially enabled. Default true. + void setListSetting(const char* label, const char* optionsList, bool wrapOptions, const char* callback,bool enabled, const char* tooltip = "", const char* defaultValue = ""); + + /// Sets the control to a Slider setting + /// + /// \param label The text to display on the control as a label. + /// \param defaultValue A float indicating the slider's default value + /// \param increments A float indicating the incremental values the slider snaps along between it's range + /// \param range A Point2F that indicates the minimum and maximum value range + /// \param callback [optional] Name of a script function to use as a callback + /// when this control is activated. Default NULL means no callback. + /// \param enabled [optional] If this control is initially enabled. Default true. + void setSliderSetting(const char* label, F32 defaultValue, F32 increments, Point2F range, const char* callback, bool enabled, const char* tooltip = ""); + + /// Sets the control to a Keybind setting + /// + /// \param label The text to display on the control as a label. + /// \param bitmapAssetId The assetId for the button display image + /// \param range A Point2F that indicates the minimum and maximum value range + /// \param callback [optional] Name of a script function to use as a callback + /// when this control is activated. Default NULL means no callback. + /// \param enabled [optional] If this control is initially enabled. Default true. + void setKeybindSetting(const char* label, const char* bitmapAssetId, const char* callback, bool enabled, const char* tooltip); + + /// Gets the text for the currently selected option of the control. + /// + /// \return A string representing the text currently displayed as the selected + /// option on the control. If there is no such displayed text then the empty + /// string is returned. + StringTableEntry getCurrentOption() const; + + /// Gets the key string for the currently selected option of the control + /// + /// \return The key (or id) that was assigned to the selected option on the + /// control. If there is no selected option then the empty string is returned. + StringTableEntry getCurrentOptionKey() const; + + /// Gets the index into the option list for the currently selected option of the control. + /// + /// \return The index of the selected option on the control. If there is no + /// selected option then -1 is returned. + S32 getCurrentOptionIndex() const; + + /// Attempts to set the control to the specified selected option. The option + /// will only be set if the option exists in the control. + /// + /// \param option The option to be made active. + /// \return True if the control contained the option and was set, false otherwise. + bool selectOption(const char* option); + + /// Attempts to set the control to the option with the specified key. The + /// option will only be set if the key exists in the control. + /// + /// \param optionKey The key string that was assigned to the option to be made active. + /// \return True if the control contained the key and the option and was set, false otherwise. + bool selectOptionByKey(const char* optionKey); + + /// Attempts to set the control to the option at the specified index. The option + /// will only be set if the index is valid. + /// + /// \param optionIndex The index of the option to be made active. + /// \return True if the index was valid and the option and was set, false otherwise. + bool selectOptionByIndex(S32 optionIndex); + + /// Sets the list of options on the control. + /// + /// \param optionsList A tab separated list of options for the control. + void setOptions(const char* optionsList); + + /// Adds an option to the list of options on the control. + /// + /// \param displayText The text to display for this option. + /// \param keyText The id string to associate with this value. If NULL the + /// id will be the same as the display text. + void addOption(const char* displayText, const char* keyText); + + /// Activates the control. The script callback of the control will + /// be called (if it has one). + virtual void activate(); + + /// Gets the value + /// + F32 getValue(); + + /// Sets the value + /// + /// \param value The new value to be set. + void setValue(F32 value); + + Mode getMode() { return mMode; } + + /// Gets the tooltip + const char* getTooltip(); + + GuiGameSettingsCtrl(); + ~GuiGameSettingsCtrl(); + + void onRender(Point2I offset, const RectI &updateRect); + + void onRenderListOption(Point2I currentOffset); + void onRenderSliderOption(Point2I currentOffset); + + void onRenderKeybindOption(Point2I currentOffset); + + /// Callback when the object is registered with the sim. + /// + /// \return True if the profile was successfully added, false otherwise. + bool onAdd(); + + /// Callback when the control wakes up. + bool onWake(); + + void clear(); + + virtual void onMouseMove(const GuiEvent& event); + virtual void onMouseUp(const GuiEvent& event); + + DECLARE_CONOBJECT(GuiGameSettingsCtrl); + DECLARE_CATEGORY( "Gui Game" ); + DECLARE_DESCRIPTION( "Base class for cross platform menu controls that are gamepad friendly." ); + + /// Initializes fields accessible through the console. + static void initPersistFields(); + + static const S32 NO_OPTION = -1; ///< Indicates there is no option + +protected: + /// Sets up the option + /// + /// \param label The text to display on the control as a label. + /// \param callback Name of a script function to use as a callback when this + /// control is activated. + /// \param enabled [optional] If this control is initially enabled. Default true. + virtual void set(const char* label, const char* callback, bool useHighlightIcon = true, bool enabled = true, S32 mode = 0, const char* tooltip = ""); + + /// Sets the script variable $ThisControl to reflect this control. + virtual void setThisControl(); + + /// @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. + /// + /// \param command The script to evaluate. + void doScriptCommand(StringTableEntry command); + + StringTableEntry mCallbackOnA; ///< Script callback when the 'A' button is pressed + StringTableEntry mCallbackOnB; ///< Script callback when the 'B' button is pressed + StringTableEntry mCallbackOnX; ///< Script callback when the 'X' button is pressed + StringTableEntry mCallbackOnY; ///< Script callback when the 'Y' button is pressed + +private: + /// Performs a click on the current option. 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 control. + /// + /// \param xPos The x position of the the click, relative to the control. + void clickOption(S32 xPos); + + /// Changes the option on the currently selected control. + /// + /// \param delta The amount to change the option selection by. Typically this + /// will be 1 or -1. + void changeOption(S32 delta); + + /// Performs a click on the current slider control. The x position is used to + /// determine if the left or right arrow were clicked, or if it landed somewhere on the sliderbar. + /// 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 control. + /// + /// \param xPos The x position of the the click, relative to the control. + void clickSlider(S32 xPos); + + void clickKeybind(S32 xPos); + +private: + bool mCallbackOnInputs; + bool mConsumeKeyInputEvents; +}; + +#endif diff --git a/Templates/BaseGame/game/data/UI/guis/NetGraphGui.asset.taml b/Templates/BaseGame/game/data/UI/guis/NetGraphGui.asset.taml new file mode 100644 index 000000000..c73e44804 --- /dev/null +++ b/Templates/BaseGame/game/data/UI/guis/NetGraphGui.asset.taml @@ -0,0 +1,4 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/Torque_3D_logo.png b/Templates/BaseGame/game/data/UI/images/Torque_3D_logo.png new file mode 100644 index 000000000..e31d42a68 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/Torque_3D_logo.png differ diff --git a/Templates/BaseGame/game/data/UI/images/Torque_3D_logo_alt.png b/Templates/BaseGame/game/data/UI/images/Torque_3D_logo_alt.png new file mode 100644 index 000000000..3836f1e7f Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/Torque_3D_logo_alt.png differ diff --git a/Templates/BaseGame/game/data/UI/images/Torque_3D_logo_shortcut.png b/Templates/BaseGame/game/data/UI/images/Torque_3D_logo_shortcut.png new file mode 100644 index 000000000..d993d4893 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/Torque_3D_logo_shortcut.png differ diff --git a/Templates/BaseGame/game/data/UI/images/Torque_3D_logo_w.png b/Templates/BaseGame/game/data/UI/images/Torque_3D_logo_w.png new file mode 100644 index 000000000..ec197dda3 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/Torque_3D_logo_w.png differ diff --git a/Templates/BaseGame/game/data/UI/images/backgrounddark.png b/Templates/BaseGame/game/data/UI/images/backgrounddark.png new file mode 100644 index 000000000..13b4bda55 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/backgrounddark.png differ diff --git a/Templates/BaseGame/game/data/UI/images/backgrounddark_image.asset.taml b/Templates/BaseGame/game/data/UI/images/backgrounddark_image.asset.taml new file mode 100644 index 000000000..185cd6577 --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/backgrounddark_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/clearbtn_d.png b/Templates/BaseGame/game/data/UI/images/clearbtn_d.png new file mode 100644 index 000000000..229c71e8b Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/clearbtn_d.png differ diff --git a/Templates/BaseGame/game/data/UI/images/clearbtn_d_image.asset.taml b/Templates/BaseGame/game/data/UI/images/clearbtn_d_image.asset.taml new file mode 100644 index 000000000..ef78852ae --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/clearbtn_d_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/clearbtn_h.png b/Templates/BaseGame/game/data/UI/images/clearbtn_h.png new file mode 100644 index 000000000..5e67cb13b Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/clearbtn_h.png differ diff --git a/Templates/BaseGame/game/data/UI/images/clearbtn_h_image.asset.taml b/Templates/BaseGame/game/data/UI/images/clearbtn_h_image.asset.taml new file mode 100644 index 000000000..882f3eb59 --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/clearbtn_h_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/clearbtn_n.png b/Templates/BaseGame/game/data/UI/images/clearbtn_n.png new file mode 100644 index 000000000..ecb13a8d6 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/clearbtn_n.png differ diff --git a/Templates/BaseGame/game/data/UI/images/clearbtn_n_image.asset.taml b/Templates/BaseGame/game/data/UI/images/clearbtn_n_image.asset.taml new file mode 100644 index 000000000..343f47f6a --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/clearbtn_n_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/collapsetoolbar_d.png b/Templates/BaseGame/game/data/UI/images/collapsetoolbar_d.png new file mode 100644 index 000000000..984a63853 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/collapsetoolbar_d.png differ diff --git a/Templates/BaseGame/game/data/UI/images/collapsetoolbar_d_image.asset.taml b/Templates/BaseGame/game/data/UI/images/collapsetoolbar_d_image.asset.taml new file mode 100644 index 000000000..38f99f874 --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/collapsetoolbar_d_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/collapsetoolbar_h.png b/Templates/BaseGame/game/data/UI/images/collapsetoolbar_h.png new file mode 100644 index 000000000..7e3de8387 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/collapsetoolbar_h.png differ diff --git a/Templates/BaseGame/game/data/UI/images/collapsetoolbar_h_image.asset.taml b/Templates/BaseGame/game/data/UI/images/collapsetoolbar_h_image.asset.taml new file mode 100644 index 000000000..231201217 --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/collapsetoolbar_h_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/collapsetoolbar_n.png b/Templates/BaseGame/game/data/UI/images/collapsetoolbar_n.png new file mode 100644 index 000000000..b36de3ae0 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/collapsetoolbar_n.png differ diff --git a/Templates/BaseGame/game/data/UI/images/collapsetoolbar_n_image.asset.taml b/Templates/BaseGame/game/data/UI/images/collapsetoolbar_n_image.asset.taml new file mode 100644 index 000000000..9e7afd9c4 --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/collapsetoolbar_n_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/dropdownbuttonarrow.png b/Templates/BaseGame/game/data/UI/images/dropdownbuttonarrow.png new file mode 100644 index 000000000..8c420ab85 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/dropdownbuttonarrow.png differ diff --git a/Templates/BaseGame/game/data/UI/images/dropdownbuttonarrow_image.asset.taml b/Templates/BaseGame/game/data/UI/images/dropdownbuttonarrow_image.asset.taml new file mode 100644 index 000000000..24976a2d6 --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/dropdownbuttonarrow_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/dropdowntextEdit.png b/Templates/BaseGame/game/data/UI/images/dropdowntextEdit.png new file mode 100644 index 000000000..3966efbb5 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/dropdowntextEdit.png differ diff --git a/Templates/BaseGame/game/data/UI/images/dropdowntextEdit_image.asset.taml b/Templates/BaseGame/game/data/UI/images/dropdowntextEdit_image.asset.taml new file mode 100644 index 000000000..7006d8448 --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/dropdowntextEdit_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/expandtoolbar_d.png b/Templates/BaseGame/game/data/UI/images/expandtoolbar_d.png new file mode 100644 index 000000000..462929e95 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/expandtoolbar_d.png differ diff --git a/Templates/BaseGame/game/data/UI/images/expandtoolbar_d_image.asset.taml b/Templates/BaseGame/game/data/UI/images/expandtoolbar_d_image.asset.taml new file mode 100644 index 000000000..45a7de130 --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/expandtoolbar_d_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/expandtoolbar_h.png b/Templates/BaseGame/game/data/UI/images/expandtoolbar_h.png new file mode 100644 index 000000000..c33bcad69 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/expandtoolbar_h.png differ diff --git a/Templates/BaseGame/game/data/UI/images/expandtoolbar_h_image.asset.taml b/Templates/BaseGame/game/data/UI/images/expandtoolbar_h_image.asset.taml new file mode 100644 index 000000000..003d65496 --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/expandtoolbar_h_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/expandtoolbar_n.png b/Templates/BaseGame/game/data/UI/images/expandtoolbar_n.png new file mode 100644 index 000000000..0af2f1bd1 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/expandtoolbar_n.png differ diff --git a/Templates/BaseGame/game/data/UI/images/expandtoolbar_n_image.asset.taml b/Templates/BaseGame/game/data/UI/images/expandtoolbar_n_image.asset.taml new file mode 100644 index 000000000..f3b62bd23 --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/expandtoolbar_n_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/groupborder.png b/Templates/BaseGame/game/data/UI/images/groupborder.png new file mode 100644 index 000000000..61234ae1f Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/groupborder.png differ diff --git a/Templates/BaseGame/game/data/UI/images/groupborder_image.asset.taml b/Templates/BaseGame/game/data/UI/images/groupborder_image.asset.taml new file mode 100644 index 000000000..2038044f6 --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/groupborder_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/inactiveoverlay.png b/Templates/BaseGame/game/data/UI/images/inactiveoverlay.png new file mode 100644 index 000000000..feab83209 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/inactiveoverlay.png differ diff --git a/Templates/BaseGame/game/data/UI/images/inactiveoverlay_image.asset.taml b/Templates/BaseGame/game/data/UI/images/inactiveoverlay_image.asset.taml new file mode 100644 index 000000000..f992cbfb6 --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/inactiveoverlay_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/menubutton.png b/Templates/BaseGame/game/data/UI/images/menubutton.png new file mode 100644 index 000000000..3cfa036d8 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/menubutton.png differ diff --git a/Templates/BaseGame/game/data/UI/images/menubutton_image.asset.taml b/Templates/BaseGame/game/data/UI/images/menubutton_image.asset.taml new file mode 100644 index 000000000..467c7443f --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/menubutton_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/nextOption_n.png b/Templates/BaseGame/game/data/UI/images/nextOption_n.png new file mode 100644 index 000000000..ba710b061 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/nextOption_n.png differ diff --git a/Templates/BaseGame/game/data/UI/images/nextOption_n_image.asset.taml b/Templates/BaseGame/game/data/UI/images/nextOption_n_image.asset.taml new file mode 100644 index 000000000..55cce3fdb --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/nextOption_n_image.asset.taml @@ -0,0 +1,8 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/nextbutton_d.png b/Templates/BaseGame/game/data/UI/images/nextbutton_d.png new file mode 100644 index 000000000..76c3ec0ff Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/nextbutton_d.png differ diff --git a/Templates/BaseGame/game/data/UI/images/nextbutton_d_image.asset.taml b/Templates/BaseGame/game/data/UI/images/nextbutton_d_image.asset.taml new file mode 100644 index 000000000..6c616a75a --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/nextbutton_d_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/nextbutton_h.png b/Templates/BaseGame/game/data/UI/images/nextbutton_h.png new file mode 100644 index 000000000..f52f5fb42 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/nextbutton_h.png differ diff --git a/Templates/BaseGame/game/data/UI/images/nextbutton_h_image.asset.taml b/Templates/BaseGame/game/data/UI/images/nextbutton_h_image.asset.taml new file mode 100644 index 000000000..b084a05a2 --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/nextbutton_h_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/nextbutton_n.png b/Templates/BaseGame/game/data/UI/images/nextbutton_n.png new file mode 100644 index 000000000..203133732 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/nextbutton_n.png differ diff --git a/Templates/BaseGame/game/data/UI/images/nextbutton_n_image.asset.taml b/Templates/BaseGame/game/data/UI/images/nextbutton_n_image.asset.taml new file mode 100644 index 000000000..24619f279 --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/nextbutton_n_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/nopreview.png b/Templates/BaseGame/game/data/UI/images/nopreview.png new file mode 100644 index 000000000..fccdc858b Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/nopreview.png differ diff --git a/Templates/BaseGame/game/data/UI/images/nopreview_image.asset.taml b/Templates/BaseGame/game/data/UI/images/nopreview_image.asset.taml new file mode 100644 index 000000000..cda718e30 --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/nopreview_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/previousOption_n.png b/Templates/BaseGame/game/data/UI/images/previousOption_n.png new file mode 100644 index 000000000..3a9df0efa Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/previousOption_n.png differ diff --git a/Templates/BaseGame/game/data/UI/images/previousOption_n_image.asset.taml b/Templates/BaseGame/game/data/UI/images/previousOption_n_image.asset.taml new file mode 100644 index 000000000..9b7fb0568 --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/previousOption_n_image.asset.taml @@ -0,0 +1,8 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/previousbutton_d.png b/Templates/BaseGame/game/data/UI/images/previousbutton_d.png new file mode 100644 index 000000000..688b30345 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/previousbutton_d.png differ diff --git a/Templates/BaseGame/game/data/UI/images/previousbutton_d_image.asset.taml b/Templates/BaseGame/game/data/UI/images/previousbutton_d_image.asset.taml new file mode 100644 index 000000000..94d3a330f --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/previousbutton_d_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/previousbutton_h.png b/Templates/BaseGame/game/data/UI/images/previousbutton_h.png new file mode 100644 index 000000000..26cf0e8c6 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/previousbutton_h.png differ diff --git a/Templates/BaseGame/game/data/UI/images/previousbutton_h_image.asset.taml b/Templates/BaseGame/game/data/UI/images/previousbutton_h_image.asset.taml new file mode 100644 index 000000000..9289ba64e --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/previousbutton_h_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/previousbutton_n.png b/Templates/BaseGame/game/data/UI/images/previousbutton_n.png new file mode 100644 index 000000000..c0b9f4662 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/previousbutton_n.png differ diff --git a/Templates/BaseGame/game/data/UI/images/previousbutton_n_image.asset.taml b/Templates/BaseGame/game/data/UI/images/previousbutton_n_image.asset.taml new file mode 100644 index 000000000..0c793bc45 --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/previousbutton_n_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/selectorbutton.png b/Templates/BaseGame/game/data/UI/images/selectorbutton.png new file mode 100644 index 000000000..cd0780068 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/selectorbutton.png differ diff --git a/Templates/BaseGame/game/data/UI/images/selectorbutton_image.asset.taml b/Templates/BaseGame/game/data/UI/images/selectorbutton_image.asset.taml new file mode 100644 index 000000000..f53884267 --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/selectorbutton_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/selectorbuttonblank.png b/Templates/BaseGame/game/data/UI/images/selectorbuttonblank.png new file mode 100644 index 000000000..e965b3af6 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/selectorbuttonblank.png differ diff --git a/Templates/BaseGame/game/data/UI/images/selectorbuttonblank_image.asset.taml b/Templates/BaseGame/game/data/UI/images/selectorbuttonblank_image.asset.taml new file mode 100644 index 000000000..c3f212a24 --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/selectorbuttonblank_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/selectorbuttondark.png b/Templates/BaseGame/game/data/UI/images/selectorbuttondark.png new file mode 100644 index 000000000..84ee7e6f3 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/selectorbuttondark.png differ diff --git a/Templates/BaseGame/game/data/UI/images/selectorbuttondark_image.asset.taml b/Templates/BaseGame/game/data/UI/images/selectorbuttondark_image.asset.taml new file mode 100644 index 000000000..4a24af201 --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/selectorbuttondark_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/selectorbuttonhighlightonly.png b/Templates/BaseGame/game/data/UI/images/selectorbuttonhighlightonly.png new file mode 100644 index 000000000..77e01fc74 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/selectorbuttonhighlightonly.png differ diff --git a/Templates/BaseGame/game/data/UI/images/selectorbuttonhighlightonly_image.asset.taml b/Templates/BaseGame/game/data/UI/images/selectorbuttonhighlightonly_image.asset.taml new file mode 100644 index 000000000..e359450c4 --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/selectorbuttonhighlightonly_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/separatorh.png b/Templates/BaseGame/game/data/UI/images/separatorh.png new file mode 100644 index 000000000..339c0fbe0 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/separatorh.png differ diff --git a/Templates/BaseGame/game/data/UI/images/separatorh_image.asset.taml b/Templates/BaseGame/game/data/UI/images/separatorh_image.asset.taml new file mode 100644 index 000000000..213addd3a --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/separatorh_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/separatorv.png b/Templates/BaseGame/game/data/UI/images/separatorv.png new file mode 100644 index 000000000..6a0f87361 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/separatorv.png differ diff --git a/Templates/BaseGame/game/data/UI/images/separatorv_image.asset.taml b/Templates/BaseGame/game/data/UI/images/separatorv_image.asset.taml new file mode 100644 index 000000000..6a14f9e54 --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/separatorv_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/sliderwbox.png b/Templates/BaseGame/game/data/UI/images/sliderwbox.png new file mode 100644 index 000000000..d9ef04961 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/sliderwbox.png differ diff --git a/Templates/BaseGame/game/data/UI/images/sliderwbox_image.asset.taml b/Templates/BaseGame/game/data/UI/images/sliderwbox_image.asset.taml new file mode 100644 index 000000000..14abf8088 --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/sliderwbox_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/images/tabborder.png b/Templates/BaseGame/game/data/UI/images/tabborder.png new file mode 100644 index 000000000..6703924d4 Binary files /dev/null and b/Templates/BaseGame/game/data/UI/images/tabborder.png differ diff --git a/Templates/BaseGame/game/data/UI/images/tabborder_image.asset.taml b/Templates/BaseGame/game/data/UI/images/tabborder_image.asset.taml new file mode 100644 index 000000000..0e3102520 --- /dev/null +++ b/Templates/BaseGame/game/data/UI/images/tabborder_image.asset.taml @@ -0,0 +1,3 @@ + diff --git a/Templates/BaseGame/game/data/UI/scripts/menuInputHandling.tscript b/Templates/BaseGame/game/data/UI/scripts/menuInputHandling.tscript new file mode 100644 index 000000000..074bb3675 --- /dev/null +++ b/Templates/BaseGame/game/data/UI/scripts/menuInputHandling.tscript @@ -0,0 +1,510 @@ +//============================================================================== +// Menu Input Buttons +// This file manages the Menu Input Buttons stuff +// Any time you have a GUI button that should be clickable AND map to a key input +// such as a gamepad button, or enter, etc, this stuff can be used +//============================================================================== +/* +Gamepad input reference for 360 controller +btn_a = A +btn_b = B +btn_x = X +btn_y = Y +btn_r = Right Bumper +btn_l = Right Bumper +upov = Dpad Up +dpov = Dpad Down +lpov = Dpad Left +rpov = Dpad Right +xaxis = Left Stick | + values = up, - values = down +yaxis = Left Stick | + values = up, - values = down +rxaxis = Right Stick | + values = up, - values = down +ryaxis = Right Stick | + values = up, - values = down +zaxis = Left Trigger +rzaxis = Right Trigger +btn_start = Start +btn_back = Back/Select +*/ + +/// This is used with the main UI menu lists, when a non-axis input event is called +/// such as pressing a button +/// It is called from the engine +function UIMenuButtonList::onInputEvent(%this, %device, %action, %state) +{ + if(%state) + $activeMenuButtonContainer.processInputs(%device, %action); +} + +/// This is used with the main UI menu lists, when an axis input event is called +/// such as moving a joystick +/// It is called from the engine +function UIMenuButtonList::onAxisEvent(%this, %device, %action, %axisVal) +{ + //Skip out of the value is too low as it could just be noise or miscalibrated defaults + if(%axisVal < 0.02) + return; + + $activeMenuButtonContainer.processAxisEvent(%device, %action); +} + +/// Sets the command and text for the specified button. If %text and %command +/// are left empty, the button will be disabled and hidden. +/// +/// \param %gamepadButton (string) The button to set for when using gamepad input. See the input map reference comment at the top of the file +/// \param %keyboardButton (string) The button to set for when using keyboard/mouse input. +/// \param %text (string) The text to display next to the A button graphic. +/// \param %command (string) The command executed when the A button is pressed. +/// \param %gamepadOnly (bool) If true, will only show the button when working in the gamepad input mode +function MenuInputButton::set(%this, %gamepadButton, %keyboardButton, %text, %command, %gamepadOnly) +{ + %set = (! ((%text $= "") && (%command $= ""))); + %this.setText(%text); + %this.setActive(%set); + %this.setVisible(%set); + + %this.gamepadButton = %gamepadButton; + %this.keyboardButton = %keyboardButton; + + if(%gamepadOnly $= "") + %gamepadOnly = false; + + %this.gamepadOnly = %gamepadOnly; + + %this.Command = %command; +} + +/// Refreshes the specific button, updating it's visbility status and the displayed input image +function MenuInputButton::refresh(%this) +{ + %set = (! ((%this.text $= "") && (%this.command $= ""))); + + //Special-case of where we're in keyboard+mouse mode, but the menubutton is gamepad only mode, so we early out + if(%this.gamepadOnly && $activeControllerType !$= "gamepad") + %set = false; + + %this.setActive(%set); + %this.setVisible(%set); + + if(!%this.isActive()) + return; + + if($activeControllerType $= "gamepad") + { + if(%this.gamepadButton !$= "") + { + %assetId = ""; + if($activeControllerName $= "PS4 Controller") + { + %assetId = "UI:PS4_"; + + if(%this.gamepadButton $= "btn_a") + %assetId = %assetId @ "Cross"; + else if(%this.gamepadButton $= "btn_b") + %assetId = %assetId @ "Circle"; + else if(%this.gamepadButton $= "btn_x") + %assetId = %assetId @ "Square"; + else if(%this.gamepadButton $= "btn_y") + %assetId = %assetId @ "Triangle"; + else if(%this.gamepadButton $= "btn_l") + %assetId = %assetId @ "L1"; + else if(%this.gamepadButton $= "zaxis") + %assetId = %assetId @ "L2"; + else if(%this.gamepadButton $= "btn_r") + %assetId = %assetId @ "R1"; + else if(%this.gamepadButton $= "rzaxis") + %assetId = %assetId @ "R2"; + else if(%this.gamepadButton $= "btn_start") + %assetId = %assetId @ "Options"; + else if(%this.gamepadButton $= "btn_back") + %assetId = %assetId @ "Share"; + } + else if($activeControllerName $= "Nintendo Switch Pro Controller") + { + %assetId = "UI:Switch_"; + + if(%this.gamepadButton $= "btn_a") + %assetId = %assetId @ "B"; + else if(%this.gamepadButton $= "btn_b") + %assetId = %assetId @ "A"; + else if(%this.gamepadButton $= "btn_x") + %assetId = %assetId @ "Y"; + else if(%this.gamepadButton $= "btn_y") + %assetId = %assetId @ "X"; + else if(%this.gamepadButton $= "btn_l") + %assetId = %assetId @ "LB"; + else if(%this.gamepadButton $= "zaxis") + %assetId = %assetId @ "LT"; + else if(%this.gamepadButton $= "btn_r") + %assetId = %assetId @ "RB"; + else if(%this.gamepadButton $= "rzaxis") + %assetId = %assetId @ "RT"; + else if(%this.gamepadButton $= "btn_start") + %assetId = %assetId @ "Plus"; + else if(%this.gamepadButton $= "btn_back") + %assetId = %assetId @ "Minus"; + } + else if($activeControllerName !$= "") + { + %assetId = "UI:Xbox_"; + + if(%this.gamepadButton $= "btn_a") + %assetId = %assetId @ "A"; + else if(%this.gamepadButton $= "btn_b") + %assetId = %assetId @ "B"; + else if(%this.gamepadButton $= "btn_x") + %assetId = %assetId @ "X"; + else if(%this.gamepadButton $= "btn_y") + %assetId = %assetId @ "Y"; + else if(%this.gamepadButton $= "btn_l") + %assetId = %assetId @ "LB"; + else if(%this.gamepadButton $= "zaxis") + %assetId = %assetId @ "LT"; + else if(%this.gamepadButton $= "btn_r") + %assetId = %assetId @ "RB"; + else if(%this.gamepadButton $= "rzaxis") + %assetId = %assetId @ "RT"; + else if(%this.gamepadButton $= "btn_start") + %assetId = %assetId @ "Menu"; + else if(%this.gamepadButton $= "btn_back") + %assetId = %assetId @ "Windows"; + } + } + } + else + { + if(%this.keyboardButton !$= "") + { + %assetId = "UI:Keyboard_Black_" @ %this.keyboardButton; + } + } + + %this.setBitmap(%assetId @ "_image"); + + return true; +} + +/// Refreshes a menu input container, updating the buttons inside it +function MenuInputButtonContainer::refresh(%this) +{ + %count = %this.getCount(); + for(%i=0; %i < %count; %i++) + { + %btn = %this.getObject(%i); + + %btn.refresh(); + } +} + +/// Sets the given MenuInputButtonContainer as the active one. This directs input events +/// to it's buttons, ensures it's visible, and auto-hides the old active container if it was set +function MenuInputButtonContainer::setActive(%this) +{ + if(isObject($activeMenuButtonContainer)) + $activeMenuButtonContainer.hidden = true; + + $activeMenuButtonContainer = %this; + $activeMenuButtonContainer.hidden = false; + $activeMenuButtonContainer.refresh(); +} + +/// Checks the input manager for if we have a gamepad active and gets it's name +/// If we have one, also sets the active input type to gamepad +function MenuInputButtonContainer::checkGamepad(%this) +{ + %controllerName = SDLInputManager::JoystickNameForIndex(0); + + $activeControllerName = %controllerName; + + if($activeControllerName $= "") + $activeControllerType = "K&M"; + else + $activeControllerType = "gamepad"; +} + +/// This is called by the earlier inputs callback that comes from the menu list +/// this allows us to first check what the input type is, and if the device is different +/// (such as going from keyboard and mouse to gamepad) we can refresh the buttons to update +/// the display +/// Then we process the input to see if it matches to any of the button maps for our +/// MenuInputButtons. If we have a match, we execute it's command. +function MenuInputButtonContainer::processInputs(%this, %device, %action) +{ + //check to see if our status has changed + %changed = false; + + %oldDevice = $activeControllerName; + + %deviceName = stripTrailingNumber(%device); + + if(%deviceName $= "keyboard" || %deviceName $= "mouse") + { + if($activeControllerName !$= "K&M") + %changed = true; + + $activeControllerName = "K&M"; + $activeControllerType = "K&M"; + Canvas.showCursor(); + } + else + { + if(%this.checkGamepad()) + { + Canvas.hideCursor(); + } + + if($activeControllerType !$= %oldDevice) + %changed = true; + } + + if(%changed) + %this.refresh(); + + //Now process the input for the button accelerator, if applicable + //Set up our basic buttons + for(%i=0; %i < %this.getCount(); %i++) + { + %btn = %this.getObject(%i); + + if(!%btn.isActive()) + continue; + + if($activeControllerType !$= "K&M") + { + if(%btn.gamepadButton $= %action) + { + eval(%btn.command); + } + } + else + { + if(%btn.keyboardButton $= %action) + { + eval(%btn.command); + } + } + } +} + +/// This is called by the earlier inputs callback that comes from the menu list +/// this allows us to first check what the input type is, and if the device is different +/// (such as going from keyboard and mouse to gamepad) we can refresh the buttons to update +/// the display +function MenuInputButtonContainer::processAxisEvent(%this, %device, %action, %axisVal) +{ + //check to see if our status has changed + %changed = false; + + %oldDevice = $activeControllerName; + + %deviceName = stripTrailingNumber(%device); + + if(%deviceName $= "mouse") + { + if($activeControllerName !$= "K&M") + %changed = true; + + $activeControllerName = "K&M"; + $activeControllerType = "K&M"; + Canvas.showCursor(); + } + else + { + if(%this.checkGamepad()) + { + Canvas.hideCursor(); + } + + if($activeControllerType !$= %oldDevice) + %changed = true; + } + + if(%changed) + %this.refresh(); +} + +// +// +function onSDLDeviceConnected(%sdlIndex, %deviceName, %deviceType) +{ + /*if(GamepadButtonsGui.checkGamepad()) + { + GamepadButtonsGui.hidden = false; + }*/ +} + +function onSDLDeviceDisconnected(%sdlIndex) +{ + /*if(!GamepadButtonsGui.checkGamepad()) + { + GamepadButtonsGui.hidden = true; + }*/ +} + +//============================================================================== +// Menu Input processing +// These functions manage the Menu input processing in general +// Whenever a MenuInputHandler consumes an input event, it'll process them here +// This'll let the active menu list be navigated, as well as buttons be processed +// and ultimately handled by the Input Buttons above +//============================================================================== +function MenuInputHandler::onAxisEvent(%this, %device, %action, %value) +{ + //this is to force a refresh of the menu + if(%value == 1 || %value == -1) + $activeMenuButtonContainer.processInputs(%device, %action); + + if(startsWith(%device, "mouse")) + return; + + if((%action $= "upov" && %value > 0) || (%action $= "yaxis" && %value == -1)) + { + $activeMenuList.navigateUp(); + } + + if((%action $= "dpov" && %value > 0) || (%action $= "yaxis" && %value == 1)) + { + $activeMenuList.navigateDown(); + } + + //How we deal with the left and right navigation is dependant on the mode of the + //menu list + if($activeMenuListMode $= "Settings") + { + if((%action $= "lpov" && %value > 0) || (%action $= "xaxis" && %value == -1)) + { + echo("Options menu nudged left!"); + //$activeMenuList.navigateLeft(); + } + + if((%action $= "rpov" && %value > 0) || (%action $= "xaxis" && %value == -1)) + { + echo("Options menu nudged right!"); + //$activeMenuList.navigateRight(); + } + } + else + { + if((%action $= "lpov" && %value > 0) || (%action $= "xaxis" && %value == -1)) + { + $activeMenuList.navigateLeft(); + } + + if((%action $= "rpov" && %value > 0) || (%action $= "xaxis" && %value == -1)) + { + $activeMenuList.navigateRight(); + } + } +} + +function MenuInputHandler::onInputEvent(%this, %device, %action, %state) +{ + if(%action $= "upov" || %action $= "dpov" || %action $= "lpov" || %action $= "rpov") + { + %this.onAxisEvent(%device, %action, %state); + return; + } + + if(%state) + $activeMenuButtonContainer.processInputs(%device, %action); +} + +//============================================================================== +// Menu List processing +// These functions manage the navigation and activation of the Menu Lists +//============================================================================== + +function MenuList::setAsActiveMenuList(%this, %startPosition, %menuMode) +{ + if(%startPosition $= "") + %startPosition = "0 0"; + + if(%menuMode $= "") + %menuMode = "Menu"; + + $activeMenuList = %this; + $activeMenuList.hidden = false; + $activeMenuListPosition = %startPosition; + $activeMenuListMode = %menuMode; + + %this.refresh(); +} + + +function MenuList::activate(%this) +{ + //check for a highlighted element + if($activeMenuListPosition.y > -1 && $activeMenuListPosition < $activeMenuList.getCount()) + { + %btn = $activeMenuList.getObject($activeMenuListPosition.y); + %btn.performClick(); + } +} + +function MenuList::refresh(%this) +{ + %selectedObject = 0; + for(%i=0; %i < $activeMenuList.getCount(); %i++) + { + %btn = $activeMenuList.getObject(%i); + + %isSelected = %i == $activeMenuListPosition.y; + + %btn.setHighlighted(%isSelected); + + if(%isSelected) + %selectedObject = %i; + } + + if($activeMenuList.isMethod("onNavigate")) + $activeMenuList.onNavigate($activeMenuListPosition.y); + + %parent = $activeMenuList.getParent(); + if(%parent.getClassName() $= "GuiScrollCtrl") + { + %parent.scrollToObject(%selectedObject); + } +} + +function MenuList::navigateUp(%this) +{ + $activeMenuListPosition.y -= 1; + if($activeMenuListPosition.y < 0) + $activeMenuListPosition.y = 0; + + %this.refresh(); +} + +function MenuList::navigateDown(%this) +{ + $activeMenuListPosition.y += 1; + if($activeMenuListPosition.y >= $activeMenuList.getCount()) + $activeMenuListPosition.y = $activeMenuList.getCount()-1; + + %this.refresh(); +} + +function MenuList::navigateLeft() +{ + echo("Menu list navigated left!"); + + //Atm, we're only handling specific control types, namely options entries, but + //this could readily be expanded upon to handle grids like for inventory screens + //or the like + + %btn = $activeMenuList.getObject($activeMenuListPosition.y); + if(%btn.getClassName() $= "GuiGameSettingsCtrl" && %btn.isEnabled()) + { + warnf("MenuList::navigateLeft() - actioned the option" @ %btn @ " to the left"); + } +} + +function MenuList::navigateRight() +{ + echo("Menu list navigated right!"); + + %btn = $activeMenuList.getObject($activeMenuListPosition.y); + if(%btn.getClassName() $= "GuiGameSettingsCtrl" && %btn.isEnabled()) + { + warnf("MenuList::navigateLeft() - actioned the option" @ %btn @ " to the left"); + } +}