From 3b47d41da2441a63ac16400fb6b77cb95255ca48 Mon Sep 17 00:00:00 2001 From: Areloch Date: Mon, 25 May 2020 00:51:33 -0500 Subject: [PATCH] Majority of options menu integration completed Implemented keybind option type Updated Pause menu to comply with new style --- .../gui/controls/guiGameListMenuCtrl.cpp | 436 +++++++++++- .../source/gui/controls/guiGameListMenuCtrl.h | 72 +- Templates/BaseGame/game/data/ui/UI.cs | 26 +- .../BaseGame/game/data/ui/guis/FileDialog.cs | 306 --------- .../BaseGame/game/data/ui/guis/FileDialog.gui | 293 -------- .../ui/guis/graphicsMenuSettingsCtrl.taml | 123 ---- .../ui/guis/graphicsMenuSettingsSlider.taml | 142 ---- .../BaseGame/game/data/ui/guis/mainMenu.cs | 1 - .../game/data/ui/guis/messageBoxOK.gui | 60 -- .../game/data/ui/guis/messageBoxYesNo.gui | 75 --- .../BaseGame/game/data/ui/guis/optionsMenu.cs | 626 +++++++----------- .../game/data/ui/guis/optionsMenu.gui | 307 --------- .../BaseGame/game/data/ui/guis/pauseMenu.cs | 63 +- .../BaseGame/game/data/ui/guis/pauseMenu.gui | 118 +--- .../Keyboard & Mouse/Keyboard_Black_Blank.png | Bin 0 -> 1162 bytes .../game/data/ui/scripts/displayMenu.cs | 2 +- .../game/data/ui/scripts/keybindEdit.cs | 401 +++++++++++ .../game/data/ui/scripts/optionsList.cs | 0 .../BaseGame/game/data/ui/scripts/utility.cs | 65 ++ 19 files changed, 1293 insertions(+), 1823 deletions(-) delete mode 100644 Templates/BaseGame/game/data/ui/guis/FileDialog.cs delete mode 100644 Templates/BaseGame/game/data/ui/guis/FileDialog.gui delete mode 100644 Templates/BaseGame/game/data/ui/guis/graphicsMenuSettingsCtrl.taml delete mode 100644 Templates/BaseGame/game/data/ui/guis/graphicsMenuSettingsSlider.taml delete mode 100644 Templates/BaseGame/game/data/ui/guis/messageBoxOK.gui delete mode 100644 Templates/BaseGame/game/data/ui/guis/messageBoxYesNo.gui create mode 100644 Templates/BaseGame/game/data/ui/images/Inputs/Keyboard & Mouse/Keyboard_Black_Blank.png create mode 100644 Templates/BaseGame/game/data/ui/scripts/keybindEdit.cs delete mode 100644 Templates/BaseGame/game/data/ui/scripts/optionsList.cs create mode 100644 Templates/BaseGame/game/data/ui/scripts/utility.cs diff --git a/Engine/source/gui/controls/guiGameListMenuCtrl.cpp b/Engine/source/gui/controls/guiGameListMenuCtrl.cpp index 64a44b3c0..02a42d32f 100644 --- a/Engine/source/gui/controls/guiGameListMenuCtrl.cpp +++ b/Engine/source/gui/controls/guiGameListMenuCtrl.cpp @@ -144,7 +144,15 @@ void GuiGameListMenuCtrl::onRender(Point2I offset, const RectI &updateRect) if ((*row)->mMode == Row::Mode::OptionList) { - onRenderOptionList((*row), currentOffset); + onRenderListOption((*row), currentOffset); + } + else if ((*row)->mMode == Row::Mode::Slider) + { + onRenderSliderOption((*row), currentOffset); + } + else if ((*row)->mMode == Row::Mode::Keybind) + { + onRenderKeybindOption((*row), currentOffset); } } @@ -156,7 +164,7 @@ void GuiGameListMenuCtrl::onRender(Point2I offset, const RectI &updateRect) renderChildControls(offset, updateRect); } -void GuiGameListMenuCtrl::onRenderOptionList(Row* row, Point2I currentOffset) +void GuiGameListMenuCtrl::onRenderListOption(Row* row, Point2I currentOffset) { GuiGameListMenuProfile* profile = (GuiGameListMenuProfile*)mProfile; @@ -242,6 +250,165 @@ void GuiGameListMenuCtrl::onRenderOptionList(Row* row, Point2I currentOffset) } } +void GuiGameListMenuCtrl::onRenderSliderOption(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 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->mValue > row->mRange.x); + 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->mValue < row->mRange.y); + 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)); + } + + //Draw the slider bar + if (row->mEnabled) + { + RectI sliderRect; + + sliderRect.point.x = currentOffset.x + columnSplit + arrowExtent.x; + sliderRect.point.y = currentOffset.y + arrowOffsetY; + + sliderRect.extent.x = (currentOffset.x + (profile->mHitAreaLowerRight.x - profile->mRightPad) * xScale - arrowExtent.x) - sliderRect.point.x; + sliderRect.extent.y = arrowExtent.y; + + //Now adjust the bar to match-to our value + + S32 barStart = sliderRect.point.x; + S32 barEnd = sliderRect.point.x + sliderRect.extent.x; + + S32 xPosFill = (((row->mValue - row->mRange.x) * (barEnd - barStart)) / (row->mRange.y - row->mRange.x)) + barStart; + + RectI fillRect = sliderRect; + fillRect.extent.x = xPosFill - sliderRect.point.x; + + ColorI barColor; + ColorI barOutlineColor; + if (isRowSelected) + { + barColor = profile->mFillColorHL; + barOutlineColor = profile->mFillColor; + } + else + { + barColor = profile->mFillColor; + barOutlineColor = profile->mFillColorHL; + } + + drawer->drawRectFill(fillRect, barColor); + + drawer->drawRect(sliderRect, barOutlineColor); + } + + // 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; + + ConsoleValue val; + val.setFloatValue(row->mValue); + + const char* stringVal = val.getStringValue(); + + S32 textWidth = font->getStrWidth(stringVal); + 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, stringVal); +} + +void GuiGameListMenuCtrl::onRenderKeybindOption(Row* row, Point2I currentOffset) +{ + GuiGameListMenuProfile* profile = (GuiGameListMenuProfile*)mProfile; + F32 xScale = (float)getWidth() / profile->getRowWidth(); + S32 columnSplit = profile->mColumnSplit * xScale; + + S32 rowHeight = profile->getRowHeight(); + + S32 optionWidth = xScale - columnSplit; + + GFXDrawUtil* drawer = GFX->getDrawUtil(); + //drawer->drawBitmap(row->mBitmap, ) + + Point2I button; + button.x = currentOffset.x + columnSplit + (columnSplit / 2)/* + (optionWidth / 2)*/; + button.y = currentOffset.y + (rowHeight / 4); + + Point2I buttonSize; + buttonSize.x = rowHeight / 2; + buttonSize.y = rowHeight / 2; + + if (row->mBitmapTex.isValid()) + { + GFXTextureObject* texture = row->mBitmapTex; + RectI rect(button, buttonSize); + drawer->clearBitmapModulation(); + drawer->drawBitmapStretch(texture, rect, GFXBitmapFlip_None, GFXTextureFilterLinear, false); + } + + //drawer->drawRectFill(button, ColorI::BLUE); +} + void GuiGameListMenuCtrl::onDebugRender(Point2I offset) { GuiGameListMenuProfile * profile = (GuiGameListMenuProfile *) mProfile; @@ -292,13 +459,13 @@ void GuiGameListMenuCtrl::onDebugRender(Point2I offset) } } -void GuiGameListMenuCtrl::addRow(const char* label, const char* callback, S32 icon, S32 yPad, bool useHighlightIcon, bool enabled, S32 mode) +void GuiGameListMenuCtrl::addRow(const char* label, const char* callback, S32 icon, S32 yPad, bool useHighlightIcon, bool enabled, S32 mode, const char* tooltip) { Row * row = new Row(); - addRow(row, label, callback, icon, yPad, useHighlightIcon, enabled, mode); + addRow(row, label, callback, icon, yPad, useHighlightIcon, enabled, mode, tooltip); } -void GuiGameListMenuCtrl::addRow(Row * row, const char* label, const char* callback, S32 icon, S32 yPad, bool useHighlightIcon, bool enabled, S32 mode) +void GuiGameListMenuCtrl::addRow(Row * row, const char* label, const char* callback, S32 icon, S32 yPad, bool useHighlightIcon, bool enabled, S32 mode, const char* tooltip) { row->mLabel = StringTable->insert(label, true); row->mScriptCallback = (dStrlen(callback) > 0) ? StringTable->insert(callback, true) : NULL; @@ -307,6 +474,7 @@ void GuiGameListMenuCtrl::addRow(Row * row, const char* label, const char* callb row->mUseHighlightIcon = useHighlightIcon; row->mEnabled = enabled; row->mMode = (Row::Mode)mode; + row->mTooltip = StringTable->insert(tooltip); mRows.push_back(row); @@ -318,22 +486,51 @@ 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) +void GuiGameListMenuCtrl::addRow(const char* label, const char* optionsList, bool wrapOptions, const char* callback, S32 icon, S32 yPad, bool enabled, const char* tooltip, const char* defaultValue) { static StringTableEntry DELIM = StringTable->insert("\t", true); Row* row = new Row(); Vector options(__FILE__, __LINE__); + + S32 defaultOption = 0; + 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)); + + if (dStrcmp(option, defaultValue) == 0) + defaultOption = options.size() - 1; } row->mOptions = options; bool hasOptions = row->mOptions.size() > 0; - row->mSelectedOption = (hasOptions) ? 0 : NO_OPTION; + row->mSelectedOption = (hasOptions) ? defaultOption : NO_OPTION; row->mWrapOptions = wrapOptions; - addRow(row, label, callback, icon, yPad, true, (hasOptions) ? enabled : false, Row::Mode::OptionList); + addRow(row, label, callback, icon, yPad, true, (hasOptions) ? enabled : false, Row::Mode::OptionList, tooltip); +} + +void GuiGameListMenuCtrl::addRow(const char* label, F32 defaultValue, F32 increments, Point2F range, const char* callback, S32 icon, S32 yPad, bool enabled, const char* tooltip) +{ + static StringTableEntry DELIM = StringTable->insert("\t", true); + Row* row = new Row(); + row->mValue = defaultValue; + row->mStepSize = increments; + row->mRange = range; + + addRow(row, label, callback, icon, yPad, true, enabled, Row::Mode::Slider, tooltip); +} + +void GuiGameListMenuCtrl::addRow(const char* label, const char* bitmapName, const char* callback, S32 icon, S32 yPad, bool enabled, const char* tooltip) +{ + static StringTableEntry DELIM = StringTable->insert("\t", true); + Row* row = new Row(); + row->mBitmap = StringTable->insert(bitmapName); + + if(row->mBitmap != StringTable->EmptyString()) + row->mBitmapTex.set(row->mBitmap, &GFXDefaultGUIProfile, avar("%s() - mTextureObject (line %d)", __FUNCTION__, __LINE__)); + + addRow(row, label, callback, icon, yPad, true, enabled, Row::Mode::Keybind, tooltip); } Point2I GuiGameListMenuCtrl::getMinExtent() const @@ -472,6 +669,16 @@ void GuiGameListMenuCtrl::onMouseUp(const GuiEvent &event) S32 xPos = globalToLocalCoord(event.mousePoint).x; clickOption((Row*)mRows[getSelected()], xPos); } + else if (mRows[hitRow]->mMode == Row::Mode::Slider) + { + S32 xPos = globalToLocalCoord(event.mousePoint).x; + clickSlider((Row*)mRows[getSelected()], xPos); + } + else if (mRows[hitRow]->mMode == Row::Mode::Keybind) + { + S32 xPos = globalToLocalCoord(event.mousePoint).x; + clickKeybind((Row*)mRows[getSelected()], xPos); + } } } @@ -789,7 +996,20 @@ void GuiGameListMenuCtrl::setRowLabel(S32 rowIndex, const char * label) void GuiGameListMenuCtrl::clearRows() { + for (U32 i = 0; i < mRows.size(); i++) + { + if (mRows[i]->mBitmap != StringTable->EmptyString()) + mRows[i]->mBitmapTex = nullptr; + } + mRows.clear(); + setSelected(-1); + setHeight(mMinExtent.y); +} + +void GuiGameListMenuCtrl::refresh() +{ + enforceConstraints(); } RectI GuiGameListMenuCtrl::getRowBounds(S32 rowIndex) @@ -962,6 +1182,139 @@ void GuiGameListMenuCtrl::changeOption(Row* row, S32 delta) } IMPLEMENT_CONOBJECT(GuiGameListMenuCtrl); +void GuiGameListMenuCtrl::clickSlider(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)) + { + row->mValue -= row->mStepSize; + + row->mValue = mRound(row->mValue / row->mStepSize) * row->mStepSize; + + if (row->mValue < row->mRange.x) + row->mValue = row->mRange.x; + + } + else if ((rightArrowX1 <= xPos) && (xPos <= rightArrowX2)) + { + //F32 snap = row->mValue % row->mStepSize; + //row->mValue.y -= snap; + + row->mValue += row->mStepSize; + + row->mValue = mRound(row->mValue / row->mStepSize) * row->mStepSize; + + if (row->mValue > row->mRange.y) + row->mValue = row->mRange.y; + } + else + { + //see if we clicked on the sliderbar itself + S32 barStart = leftArrowX2; + S32 barEnd = rightArrowX1; + + if (xPos >= barStart && xPos <= barEnd) + { + //Yep, we clicked in it + Con::printf("CLICKED A SLIDERBAR"); + + //find the position + F32 newValue = (((xPos - barStart) * (row->mRange.y - row->mRange.x)) / (barEnd - barStart)) + row->mRange.x; + + newValue = mRound(newValue / row->mStepSize) * row->mStepSize; + + Con::printf("New value is %f", newValue); + + row->mValue = newValue; + } + } +} + +void GuiGameListMenuCtrl::clickKeybind(Row* row, S32 xPos) +{ + GuiGameListMenuProfile* profile = (GuiGameListMenuProfile*)mProfile; + F32 xScale = (float)getWidth() / profile->getRowWidth(); + S32 columnSplit = profile->mColumnSplit * xScale; + + S32 rowHeight = profile->getRowHeight(); + + S32 optionWidth = xScale - columnSplit; + + GFXDrawUtil* drawer = GFX->getDrawUtil(); + //drawer->drawBitmap(row->mBitmap, ) + + Point2I button; + button.x = columnSplit + (columnSplit / 2)/* + (optionWidth / 2)*/; + button.y = rowHeight / 4; + + Point2I buttonSize; + buttonSize.x = rowHeight / 2; + buttonSize.y = rowHeight / 2; + + GFXTextureObject* texture = row->mBitmapTex; + RectI rect(button, buttonSize); + + if (rect.pointInRect(Point2I(xPos, rowHeight / 2))) + { + if (row->mScriptCallback != StringTable->EmptyString()) + { + S32 rowId = getSelected(); + Con::executef(row->mScriptCallback, rowId); + } + } +} + +F32 GuiGameListMenuCtrl::getValue(S32 rowIndex) +{ + if (!isValidRowIndex(rowIndex)) + { + return 0; + } + + Row* row = (Row*)mRows[rowIndex]; + + return row->mValue; +} + +void GuiGameListMenuCtrl::setValue(S32 rowIndex, F32 value) +{ + if (!isValidRowIndex(rowIndex)) + { + return; + } + + Row* row = (Row*)mRows[rowIndex]; + + row->mValue = value; +} + +const char* GuiGameListMenuCtrl::getTooltip(S32 rowIndex) +{ + if (!isValidRowIndex(rowIndex)) + { + return ""; + } + + Row* row = (Row*)mRows[rowIndex]; + + return row->mTooltip; +} + ConsoleDocClass( GuiGameListMenuCtrl, "@brief A base class for cross platform menu controls that are gamepad friendly.\n\n" @@ -1107,9 +1460,16 @@ DefineEngineMethod(GuiGameListMenuCtrl, clearRows, void, (), , return object->clearRows(); } +DefineEngineMethod(GuiGameListMenuCtrl, refresh, void, (), , + "Gets the index of the currently selected row.\n\n" + "@return Index of the selected row.") +{ + return object->refresh(); +} + DefineEngineMethod(GuiGameListMenuCtrl, addOptionRow, void, - (const char* label, const char* options, bool wrapOptions, const char* callback, S32 icon, S32 yPad, bool enabled), - (-1, 0, true), + (const char* label, const char* options, bool wrapOptions, const char* callback, S32 icon, S32 yPad, bool enabled, const char* tooltip, const char* defaultValue), + (-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" @@ -1119,7 +1479,37 @@ DefineEngineMethod(GuiGameListMenuCtrl, addOptionRow, void, "@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); + object->addRow(label, options, wrapOptions, callback, icon, yPad, enabled, tooltip, defaultValue); +} + +DefineEngineMethod(GuiGameListMenuCtrl, addSliderRow, void, +(const char* label, F32 defaultValue, F32 increment, Point2F range, const char* callback, S32 icon, S32 yPad, bool enabled, const char* tooltip), +(-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, defaultValue, increment, range, callback, icon, yPad, enabled, tooltip); +} + +DefineEngineMethod(GuiGameListMenuCtrl, addKeybindRow, void, +(const char* label, const char* bitmapName, const char* callback, S32 icon, S32 yPad, bool enabled, const char* tooltip), +(-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, bitmapName, callback, icon, yPad, enabled, tooltip); } DefineEngineMethod(GuiGameListMenuCtrl, getCurrentOption, const char*, (S32 row), , @@ -1147,6 +1537,30 @@ DefineEngineMethod(GuiGameListMenuCtrl, setOptions, void, (S32 row, const char* object->setOptions(row, optionsList); } +DefineEngineMethod(GuiGameListMenuCtrl, getValue, void, (S32 row), , + "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->getValue(row); +} + +DefineEngineMethod(GuiGameListMenuCtrl, setValue, void, (S32 row, F32 value), , + "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->setValue(row, value); +} + +DefineEngineMethod(GuiGameListMenuCtrl, getTooltip, const char*, (S32 row), , + "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.") +{ + return object->getTooltip(row); +} + //----------------------------------------------------------------------------- // GuiGameListMenuProfile //----------------------------------------------------------------------------- diff --git a/Engine/source/gui/controls/guiGameListMenuCtrl.h b/Engine/source/gui/controls/guiGameListMenuCtrl.h index 289be60d9..0ec0ec81a 100644 --- a/Engine/source/gui/controls/guiGameListMenuCtrl.h +++ b/Engine/source/gui/controls/guiGameListMenuCtrl.h @@ -24,6 +24,7 @@ #define _GuiGameListMenuCtrl_H_ #include "gui/core/guiControl.h" +#include "gui/controls/guiBitmapCtrl.h" class GuiGameListMenuProfile; @@ -42,6 +43,7 @@ protected: { StringTableEntry mLabel; ///< Text to display in the row as a label StringTableEntry mScriptCallback; ///< Script callback when row is activated + StringTableEntry mTooltip; ///< A descriptive tooltip message for what the row is S32 mIconIndex; ///< Index of the icon to display on the row (-1 = no icon) S32 mHeightPad; ///< Extra amount to pad above this row bool mUseHighlightIcon; ///< Toggle the use of the highlight icon @@ -51,6 +53,7 @@ protected: { Default = 0, OptionList, + Slider, Keybind }; @@ -61,8 +64,17 @@ protected: 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) + //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 + StringTableEntry mBitmap; + GFXTexHandle mBitmapTex; + + Row() : mLabel(StringTable->EmptyString()), mScriptCallback(StringTable->EmptyString()), mTooltip(StringTable->EmptyString()), mIconIndex(-1), mHeightPad(0), mUseHighlightIcon(false), mEnabled(true), + mSelectedOption(0), mWrapOptions(false), mMode(Mode::Default), mValue(0), mStepSize(1), mRange(Point2F(0, 1)), mBitmap(StringTable->EmptyString()), mBitmapTex(nullptr) { VECTOR_SET_ASSOCIATION(mOptions); } @@ -119,7 +131,7 @@ 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, S32 mode = 0); + virtual void addRow(const char* label, const char* callback, S32 icon = -1, S32 yPad = 0, bool useHighlightIcon = true, bool enabled = true, S32 mode = 0, const char* tooltip = ""); /// Adds a row to the control. /// @@ -133,7 +145,23 @@ 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. - void addRow(const char* label, const char* optionsList, bool wrapOptions, const char* callback, S32 icon, S32 yPad, bool enabled); + void addRow(const char* label, const char* optionsList, bool wrapOptions, const char* callback, S32 icon, S32 yPad, bool enabled, const char* tooltip = "", const char* defaultValue = ""); + + /// Adds a row to the control. + /// + /// \param label The text to display on the row 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 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, F32 defaultValue, F32 increments, Point2F range, const char* callback, S32 icon, S32 yPad, bool enabled, const char* tooltip = ""); + + void addRow(const char* label, const char* bitmapName, const char* callback, S32 icon, S32 yPad, bool enabled, const char* tooltip); /// Gets the text for the currently selected option of the given row. /// @@ -166,12 +194,31 @@ public: /// \return The number of rows in this control. virtual S32 getRowCount() const { return mRows.size(); } + /// Gets the value of a row + /// + /// \param rowIndex Index of the row to get the value of. + F32 getValue(S32 rowIndex); + + /// Sets the value of a row + /// + /// \param rowIndex Index of the row to set the value of. + /// \param value The new value to be set. + void setValue(S32 rowIndex, F32 value); + + /// Gets the tooltip of a row + /// + /// \param rowIndex Index of the row to get the tooltip of. + const char* getTooltip(S32 rowIndex); + GuiGameListMenuCtrl(); ~GuiGameListMenuCtrl(); void onRender(Point2I offset, const RectI &updateRect); - void onRenderOptionList(Row* row, Point2I currentOffset); + void onRenderListOption(Row* row, Point2I currentOffset); + void onRenderSliderOption(Row* row, Point2I currentOffset); + + void onRenderKeybindOption(Row* row, Point2I currentOffset); /// Callback when the object is registered with the sim. /// @@ -240,6 +287,8 @@ public: void clearRows(); + void refresh(); + RectI getRowBounds(S32 rowIndex); DECLARE_CONOBJECT(GuiGameListMenuCtrl); @@ -264,7 +313,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, S32 mode = 0); + virtual void addRow(Row * row, const char* label, const char* callback, S32 icon, S32 yPad, bool useHighlightIcon, bool enabled, S32 mode = 0, const char* tooltip = ""); /// Determines if the given index is a valid row index. Any index pointing at /// an existing row is valid. @@ -342,6 +391,17 @@ private: /// will be 1 or -1. void changeOption(Row* row, S32 delta); + /// Performs a click on the current slider row. 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 row. + /// + /// \param row The row to perform the click on. + /// \param xPos The x position of the the click, relative to the control. + void clickSlider(Row* row, S32 xPos); + + void clickKeybind(Row* row, S32 xPos); + private: /// Recalculates the height of this control based on the stored row height and /// and padding on the rows. diff --git a/Templates/BaseGame/game/data/ui/UI.cs b/Templates/BaseGame/game/data/ui/UI.cs index e704f8e28..1f0fc89e6 100644 --- a/Templates/BaseGame/game/data/ui/UI.cs +++ b/Templates/BaseGame/game/data/ui/UI.cs @@ -35,8 +35,6 @@ function UI::initClient(%this) //Profiles exec("./scripts/profiles.cs"); - exec("./scripts/menu.keybinds.cs"); - //Now gui files exec("./guis/guiGamepadButton.cs"); exec("./guis/guiGamepadButton.gui"); @@ -44,37 +42,34 @@ function UI::initClient(%this) exec("./guis/mainMenu.cs"); exec("./guis/mainMenu.gui"); - exec("./guis/chooseLevelDlg.gui"); exec("./guis/chooseLevelDlg.cs"); + exec("./guis/chooseLevelDlg.gui"); - exec("./guis/joinServerMenu.gui"); exec("./guis/joinServerMenu.cs"); + exec("./guis/joinServerMenu.gui"); exec("./guis/loadingGui.gui"); exec("./guis/optionsMenu.cs"); exec("./guis/optionsMenu.gui"); - exec("./guis/pauseMenu.gui"); exec("./guis/pauseMenu.cs"); + exec("./guis/pauseMenu.gui"); exec("./guis/remapDlg.gui"); exec("./guis/remapConfirmDlg.gui"); - exec("./guis/profiler.gui"); exec("./guis/profiler.cs"); + exec("./guis/profiler.gui"); exec("./guis/netGraphGui.gui"); exec("./guis/RecordingsDlg.gui"); - //exec("./guis/FileDialog.gui"); - //exec("./guis/FileDialog.cs"); - - exec("./guis/guiMusicPlayer.gui"); exec("./guis/guiMusicPlayer.cs"); + exec("./guis/guiMusicPlayer.gui"); - exec("./guis/startupGui.gui"); exec("./guis/startupGui.cs"); + exec("./guis/startupGui.gui"); // Load Editor Dialogs exec("./guis/messageBoxDlg.gui"); @@ -88,17 +83,14 @@ function UI::initClient(%this) exec("./scripts/messageBoxes.cs"); exec("./scripts/help.cs"); exec("./scripts/cursors.cs"); + exec("./scripts/utility.cs"); + + exec("./scripts/keybindEdit.cs"); exec("./guis/menuGraphics.gui"); exec("./guis/menuGraphics.cs"); - //exec("./scripts/menu.keybinds.cs"); - - //exec("./scripts/GuiTreeViewCtrl.cs"); - loadStartup(); - - //menuMoveMap.push(); } function UI::onCreateClientConnection(%this){} diff --git a/Templates/BaseGame/game/data/ui/guis/FileDialog.cs b/Templates/BaseGame/game/data/ui/guis/FileDialog.cs deleted file mode 100644 index 4d67fd969..000000000 --- a/Templates/BaseGame/game/data/ui/guis/FileDialog.cs +++ /dev/null @@ -1,306 +0,0 @@ -function PlatformFileDialog::buildFilters(%this) -{ - %str = strreplace( %this.data.filters, "|", "\t"); - %this.filterCount = getFieldCount( %str ) / 2; - //echo( "Filter count: " @ %str ); - for( %i = 0; %i < %this.filterCount; %i++ ) - { - %this.filterName[%i] = GetField( %str, (%i*2) + 0 ); - %this.filter[%i] = strreplace( GetField( %str, (%i*2) + 1 ), ";", "\t"); - //echo( "Filter: " @ %this.filterName[%i] @ " - " @ %this.filter[%i]); - } -} - -function PlatformFileDialog::handleFlags(%this, %flags) -{ - %this.FDS_OPEN = false; - %this.FDS_SAVE = false; - %this.FDS_OVERWRITEPROMPT = false; - %this.FDS_MUSTEXIST = false; - %this.FDS_BROWSEFOLDER = false; - - %flagCount = getFieldCount( %flags ); - - //echo( "flag count: " @ %flagCount ); - - for( %i = 0; %i < %flagCount; %i++ ) - { - %flag = GetField( %flags, %i ); - //echo(%flag); - if( %flag $= "FDS_OPEN" ) - { - %this.FDS_OPEN = true; - %this-->Button.setText( "OPEN" ); - %this-->Button.command = "PlatformFileDialog.tryFile();"; - %this-->window.text = "Select file to OPEN"; - } - else if( %flag $= "FDS_SAVE" ) - { - %this.FDS_SAVE = true; - %this-->Button.setText( "SAVE" ); - %this-->Button.command = "PlatformFileDialog.tryFile();"; - %this-->window.text = "Select file to Save"; - } - else if( %flag $= "FDS_OVERWRITEPROMPT" ) - { - %this.FDS_OVERWRITEPROMPT = true; - } - else if( %flag $= "FDS_MUSTEXIST" ) - { - %this.FDS_MUSTEXIST = true; - } - else if( %flag $= "FDS_BROWSEFOLDER" ) - { - %this.FDS_BROWSEFOLDER = true; - %this-->window.text = "Select folder to OPEN"; - } - } -} - -function OpenPlatformFileDialog(%data, %flags) -{ - PlatformFileDialog.searchDir = ""; - PlatformFileDialog-->fileNameEdit.setText( "" ); - PlatformFileDialog.data = %data; - PlatformFileDialog.data.finished = 0; - - PlatformFileDialog.handleFlags( %flags ); - - if( !isObject(PlatformFileDialog.freeItemSet) ) - { - PlatformFileDialog.freeItemSet = new SimGroup(); - } - - PlatformFileDialog.buildFilters(); - - Canvas.pushDialog(PlatformFileDialog); -} - -function PlatformFileDialog::changeDir( %this, %newDir ) -{ - %this.searchDir = %newDir; - %this.update(); -} - -function PlatformFileDialog::navigateUp( %this ) -{ - //echo( "PlatformFileDialog::navigateUp " @ %this.searchDir ); - if( %this.searchDir !$= "" ) - { - %str = strreplace( %this.searchDir, "/", "\t"); - %count = getFieldCount( %str ); - - if ( %count == 0 ) - return; - - if ( %count == 1 ) - %address = ""; - else - %address = getFields( %str, 0, %count - 2 ); - - %newDir = strreplace( %address, "\t", "/" ); - - if( %newDir !$= "" ) - %newDir = %newDir @ "/"; - - %this.changeDir( %newDir ); - - } -} - -function PlatformFileDialog::cancel( %this ) -{ - %this.data.files[0] = ""; - %this.data.fileCount = 0; - %this.data.finished = 1; - - Canvas.popDialog(%this); -} - -function FileDialogItem::onClick( %this ) -{ - PlatformFileDialog-->fileNameEdit.setText( "" ); - - if( %this.isDir && %this.FDS_BROWSEFOLDER) - { - PlatformFileDialog-->fileNameEdit.setText( %this.text ); - } - else if( !%this.isDir && !%this.FDS_BROWSEFOLDER ) - { - PlatformFileDialog-->fileNameEdit.setText( %this.text ); - } -} - -function FileDialogItem::onDoubleClick( %this ) -{ - PlatformFileDialog-->fileNameEdit.setText( "" ); - - if( %this.isDir ) - { - PlatformFileDialog.changeDir( PlatformFileDialog.searchDir @ %this.text @ "/" ); - } -} - -function PlatformFileDialog::tryFile( %this ) -{ - %file = %this-->fileNameEdit.getText(); - if( %file $= "" ) - return; - - if( %this.FDS_OVERWRITEPROMPT ) - { - %callback = "PlatformFileDialog.onFile( \"" @ %file @ "\" );"; - MessageBoxOKCancel("Confirm overwrite", "Confirm overwrite", %callback, ""); - return; - } - - %this.onFile( %file ); -} - -function PlatformFileDialog::onFile( %this, %file ) -{ - %this.data.files[0] = ""; - %this.data.fileCount = 0; - - if( %file !$= "" ) - { - %file = %this.searchDir @ %file; - %this.data.fileCount = 1; - } - - if( %this.FDS_BROWSEFOLDER && !isDirectory( %file ) ) - { - echo("Select a directory"); - return; - } - else if( !%this.FDS_BROWSEFOLDER && !isFile( %file ) ) - { - echo("Select a file"); - return; - } - - if( %this.FDS_MUSTEXIST ) - { - if( !isFile( %file ) && !isDirectory( %file ) ) - { - echo("Target must exist: " @ %file ); - return; - } - } - - %this.data.finished = 1; - %this.data.files[0] = %file; - - Canvas.popDialog(%this); - - %this-->fileNameEdit.setText( "" ); -} - -function PlatformFileDialog::clear( %this ) -{ - %itemArray = %this-->itemArray; - - while( %itemArray.getCount() ) - { - %item = %itemArray.getObject( 0 ); - %this.freeItem( %item ); - } -} - -function PlatformFileDialog::getNewItem( %this ) -{ - if( %this.freeItemSet.getCount() ) - %item = %this.freeItemSet.getObject( 0 ); - - if( isObject(%item) ) - { - %this.freeItemSet.remove( %item ); - } - else - { - //create new - %item = new GuiIconButtonCtrl(); - %item.className = "FileDialogItem"; - %item.profile = "ToolsGuiIconButtonProfile"; - %item.textLocation = "left"; - %item.iconLocation = "left"; - %item.iconBitmap = ""; - %item.text = ""; - } - - return %item; -} - -function PlatformFileDialog::freeItem( %this, %item ) -{ - %this-->itemArray.remove( %item ); - - //clear - %item.setText( "" ); - %item.iconBitmap = ""; - %item.textMargin = 0; - %item.textLocation = "left"; - %item.iconLocation = "left"; - %item.resetState(); - - PlatformFileDialog.freeItemSet.add( %item ); -} - -function PlatformFileDialog::addDir( %this, %dir ) -{ - //echo( "Dir: " @ %dir ); - %item = %this.getNewItem(); - %item.setText( %dir ); - %item.isDir = true; - %item.iconBitmap = "core/art/gui/images/folder"; - %item.textLocation = "left"; - %item.iconLocation = "left"; - %item.textMargin = 24; - %this-->itemArray.add( %item ); -} - -function PlatformFileDialog::addFile( %this, %file ) -{ - //echo( "File: " @ %file ); - %item = %this.getNewItem(); - %item.text = strreplace( %file, %this.searchDir, "" ); - %item.isDir = false; - %this-->itemArray.add( %item ); -} - -function PlatformFileDialog::onWake( %this ) -{ - %this.update(); -} - -function PlatformFileDialog::onSleep( %this ) -{ - %this.data.finished = 1; -} - -function PlatformFileDialog::update( %this ) -{ - %this.clear(); - - %this-->popUpMenu.text = %this.searchDir; - - // dirs - %dirList = getDirectoryList( %this.searchDir, 0 ); - %wordCount = getFieldCount( %dirList ); - for( %i = 0; %i < %wordCount; %i++ ) - { - %dirItem = GetField( %dirList, %i ); - %this.addDir( %dirItem ); - } - - //files - %pattern = %this.filter[0]; - //echo( %pattern ); - %file = findFirstFileMultiExpr( %this.searchDir @ %pattern, false); - - while( %file !$= "" ) - { - %this.addFile( %file ); - %file = findNextFileMultiExpr( %pattern ); - } -} \ No newline at end of file diff --git a/Templates/BaseGame/game/data/ui/guis/FileDialog.gui b/Templates/BaseGame/game/data/ui/guis/FileDialog.gui deleted file mode 100644 index e855636f0..000000000 --- a/Templates/BaseGame/game/data/ui/guis/FileDialog.gui +++ /dev/null @@ -1,293 +0,0 @@ -//--- OBJECT WRITE BEGIN --- -%guiContent = new GuiControl(PlatformFileDialog) { - position = "0 0"; - extent = "1024 768"; - minExtent = "8 2"; - horizSizing = "right"; - vertSizing = "bottom"; - profile = "GuiDefaultProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "1"; - canSave = "1"; - canSaveDynamicFields = "1"; - - new GuiWindowCtrl() { - text = ""; - resizeWidth = "1"; - resizeHeight = "1"; - canMove = "1"; - canClose = "1"; - canMinimize = "1"; - canMaximize = "1"; - canCollapse = "0"; - closeCommand = "PlatformFileDialog.cancel();"; - edgeSnap = "1"; - margin = "0 0 0 0"; - padding = "0 0 0 0"; - anchorTop = "1"; - anchorBottom = "0"; - anchorLeft = "1"; - anchorRight = "0"; - position = "135 113"; - extent = "727 623"; - minExtent = "8 2"; - horizSizing = "right"; - vertSizing = "bottom"; - profile = "GuiWindowProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "1"; - internalName = "window"; - canSave = "1"; - canSaveDynamicFields = "0"; - - new GuiControl() { - position = "2 16"; - extent = "717 37"; - minExtent = "8 2"; - horizSizing = "width"; - vertSizing = "bottom"; - profile = "ToolsGuiDefaultProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "ToolsGuiToolTipProfile"; - hovertime = "1000"; - isContainer = "1"; - canSave = "1"; - canSaveDynamicFields = "0"; - - new GuiBitmapButtonCtrl() { - bitmap = "tools/gui/images/folderUp"; - bitmapMode = "Stretched"; - autoFitExtents = "0"; - useModifiers = "0"; - useStates = "1"; - groupNum = "0"; - buttonType = "PushButton"; - useMouseEvents = "0"; - position = "9 9"; - extent = "20 19"; - minExtent = "8 2"; - horizSizing = "right"; - vertSizing = "bottom"; - profile = "ToolsGuiButtonProfile"; - visible = "1"; - active = "1"; - command = "PlatformFileDialog.navigateUp();"; - tooltipProfile = "ToolsGuiToolTipProfile"; - hovertime = "1000"; - isContainer = "0"; - internalName = "folderUpButton"; - canSave = "1"; - canSaveDynamicFields = "0"; - }; - new GuiPopUpMenuCtrl() { - maxPopupHeight = "200"; - sbUsesNAColor = "0"; - reverseTextList = "0"; - bitmapBounds = "16 16"; - maxLength = "1024"; - margin = "0 0 0 0"; - padding = "0 0 0 0"; - anchorTop = "1"; - anchorBottom = "0"; - anchorLeft = "1"; - anchorRight = "0"; - position = "36 9"; - extent = "666 18"; - minExtent = "8 2"; - horizSizing = "width"; - vertSizing = "bottom"; - profile = "ToolsGuiPopUpMenuProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "ToolsGuiToolTipProfile"; - hovertime = "1000"; - isContainer = "0"; - internalName = "PopupMenu"; - canSave = "1"; - canSaveDynamicFields = "0"; - }; - }; - new GuiScrollCtrl() { - willFirstRespond = "1"; - hScrollBar = "dynamic"; - vScrollBar = "alwaysOff"; - lockHorizScroll = "0"; - lockVertScroll = "1"; - constantThumbHeight = "0"; - childMargin = "0 0"; - mouseWheelScrollSpeed = "-1"; - docking = "None"; - margin = "0 0 0 0"; - padding = "0 0 0 0"; - anchorTop = "0"; - anchorBottom = "1"; - anchorLeft = "1"; - anchorRight = "0"; - position = "7 64"; - extent = "712 509"; - minExtent = "8 2"; - horizSizing = "width"; - vertSizing = "height"; - profile = "GuiScrollProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "ToolsGuiToolTipProfile"; - hovertime = "1000"; - isContainer = "1"; - canSave = "1"; - canSaveDynamicFields = "0"; - - new GuiDynamicCtrlArrayControl() { - colCount = "1"; - colSize = "64"; - rowCount = "1"; - rowSize = "258"; - rowSpacing = "4"; - colSpacing = "4"; - frozen = "0"; - autoCellSize = "1"; - fillRowFirst = "0"; - dynamicSize = "1"; - padding = "0 0 0 0"; - position = "1 1"; - extent = "666 507"; - minExtent = "8 2"; - horizSizing = "width"; - vertSizing = "height"; - profile = "ToolsGuiTransparentProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "ToolsGuiToolTipProfile"; - hovertime = "1000"; - isContainer = "1"; - internalName = "itemArray"; - canSave = "1"; - canSaveDynamicFields = "0"; - }; - }; - new GuiContainer() { - docking = "Bottom"; - margin = "0 0 0 0"; - padding = "0 0 0 0"; - anchorTop = "0"; - anchorBottom = "1"; - anchorLeft = "1"; - anchorRight = "1"; - position = "1 583"; - extent = "725 37"; - minExtent = "8 2"; - horizSizing = "width"; - vertSizing = "bottom"; - profile = "GuiDefaultProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "1"; - canSave = "1"; - canSaveDynamicFields = "0"; - - new GuiTextCtrl() { - text = "File Name"; - maxLength = "1024"; - margin = "0 0 0 0"; - padding = "0 0 0 0"; - anchorTop = "1"; - anchorBottom = "0"; - anchorLeft = "1"; - anchorRight = "0"; - position = "10 -1"; - extent = "51 30"; - minExtent = "8 2"; - horizSizing = "right"; - vertSizing = "bottom"; - profile = "GuiTextProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "1"; - canSave = "1"; - canSaveDynamicFields = "0"; - }; - new GuiTextEditCtrl() { - historySize = "0"; - tabComplete = "0"; - sinkAllKeyEvents = "0"; - password = "0"; - passwordMask = "*"; - maxLength = "1024"; - margin = "0 0 0 0"; - padding = "0 0 0 0"; - anchorTop = "1"; - anchorBottom = "0"; - anchorLeft = "1"; - anchorRight = "0"; - position = "58 5"; - extent = "561 18"; - minExtent = "8 2"; - horizSizing = "width"; - vertSizing = "bottom"; - profile = "GuiTextEditProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "1"; - internalName = "fileNameEdit"; - canSave = "1"; - canSaveDynamicFields = "0"; - }; - new GuiContainer() { - docking = "Right"; - margin = "0 0 0 0"; - padding = "0 0 0 0"; - anchorTop = "0"; - anchorBottom = "0"; - anchorLeft = "0"; - anchorRight = "0"; - position = "630 0"; - extent = "95 37"; - minExtent = "8 2"; - horizSizing = "right"; - vertSizing = "bottom"; - profile = "GuiDefaultProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "1"; - canSave = "1"; - canSaveDynamicFields = "0"; - - new GuiButtonCtrl() { - groupNum = "-1"; - buttonType = "PushButton"; - useMouseEvents = "1"; - position = "6 1"; - extent = "81 24"; - minExtent = "8 2"; - horizSizing = "right"; - vertSizing = "bottom"; - profile = "GuiButtonProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "0"; - internalName = "Button"; - canSave = "1"; - canSaveDynamicFields = "0"; - }; - }; - }; - }; -}; -//--- OBJECT WRITE END --- diff --git a/Templates/BaseGame/game/data/ui/guis/graphicsMenuSettingsCtrl.taml b/Templates/BaseGame/game/data/ui/guis/graphicsMenuSettingsCtrl.taml deleted file mode 100644 index 7472ae9d5..000000000 --- a/Templates/BaseGame/game/data/ui/guis/graphicsMenuSettingsCtrl.taml +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - diff --git a/Templates/BaseGame/game/data/ui/guis/graphicsMenuSettingsSlider.taml b/Templates/BaseGame/game/data/ui/guis/graphicsMenuSettingsSlider.taml deleted file mode 100644 index 56ba7d027..000000000 --- a/Templates/BaseGame/game/data/ui/guis/graphicsMenuSettingsSlider.taml +++ /dev/null @@ -1,142 +0,0 @@ - - - - - - - - - diff --git a/Templates/BaseGame/game/data/ui/guis/mainMenu.cs b/Templates/BaseGame/game/data/ui/guis/mainMenu.cs index b609502d8..2f0e914aa 100644 --- a/Templates/BaseGame/game/data/ui/guis/mainMenu.cs +++ b/Templates/BaseGame/game/data/ui/guis/mainMenu.cs @@ -10,7 +10,6 @@ function MainMenuGui::onWake(%this) function MainMenuGui::onSleep(%this) { - menuMoveMap.pop(); } function MainMenuButtonHolder::onWake(%this) diff --git a/Templates/BaseGame/game/data/ui/guis/messageBoxOK.gui b/Templates/BaseGame/game/data/ui/guis/messageBoxOK.gui deleted file mode 100644 index 52e119ea6..000000000 --- a/Templates/BaseGame/game/data/ui/guis/messageBoxOK.gui +++ /dev/null @@ -1,60 +0,0 @@ -//--- OBJECT WRITE BEGIN --- -%guiContent = new GuiControl(MessageBoxOKDlg) { - profile = "GuiOverlayProfile"; - horizSizing = "width"; - vertSizing = "height"; - position = "0 0"; - extent = "640 480"; - minExtent = "8 8"; - visible = "1"; - helpTag = "0"; - - new GuiWindowCtrl(MBOKFrame) { - profile = "GuiWindowProfile"; - horizSizing = "center"; - vertSizing = "center"; - position = "170 175"; - extent = "300 107"; - minExtent = "48 95"; - visible = "1"; - helpTag = "0"; - maxLength = "255"; - resizeWidth = "1"; - resizeHeight = "1"; - canMove = "1"; - canClose = "0"; - canMinimize = "0"; - canMaximize = "0"; - minSize = "50 50"; - text = ""; - - new GuiMLTextCtrl(MBOKText) { - profile = "GuiMLTextProfile"; - horizSizing = "center"; - vertSizing = "bottom"; - position = "9 35"; - extent = "281 24"; - minExtent = "8 8"; - visible = "1"; - helpTag = "0"; - lineSpacing = "2"; - allowColorChars = "0"; - maxChars = "-1"; - }; - new GuiButtonCtrl() { - profile = "GuiButtonProfile"; - horizSizing = "right"; - vertSizing = "top"; - position = "111 75"; - extent = "80 24"; - minExtent = "8 8"; - visible = "1"; - command = "MessageCallback(MessageBoxOKDlg,MessageBoxOKDlg.callback);"; - accelerator = "return"; - helpTag = "0"; - text = "Ok"; - simpleStyle = "0"; - }; - }; -}; -//--- OBJECT WRITE END --- diff --git a/Templates/BaseGame/game/data/ui/guis/messageBoxYesNo.gui b/Templates/BaseGame/game/data/ui/guis/messageBoxYesNo.gui deleted file mode 100644 index 3cd7d18ef..000000000 --- a/Templates/BaseGame/game/data/ui/guis/messageBoxYesNo.gui +++ /dev/null @@ -1,75 +0,0 @@ -//--- OBJECT WRITE BEGIN --- -%guiContent = new GuiControl(MessageBoxYesNoDlg) { - profile = "GuiOverlayProfile"; - horizSizing = "width"; - vertSizing = "height"; - position = "0 0"; - extent = "640 480"; - minExtent = "8 8"; - visible = "1"; - helpTag = "0"; - - new GuiWindowCtrl(MBYesNoFrame) { - profile = "GuiWindowProfile"; - horizSizing = "center"; - vertSizing = "center"; - position = "170 175"; - extent = "300 100"; - minExtent = "48 92"; - visible = "1"; - helpTag = "0"; - maxLength = "255"; - resizeWidth = "1"; - resizeHeight = "1"; - canMove = "1"; - canClose = "1"; - canMinimize = "0"; - canMaximize = "0"; - minSize = "50 50"; - text = ""; - closeCommand = "MessageCallback(MessageBoxYesNoDlg,MessageBoxYesNoDlg.noCallback);"; - - new GuiMLTextCtrl(MBYesNoText) { - profile = "GuiMLTextProfile"; - horizSizing = "center"; - vertSizing = "bottom"; - position = "11 38"; - extent = "280 14"; - minExtent = "8 8"; - visible = "1"; - helpTag = "0"; - lineSpacing = "2"; - allowColorChars = "0"; - maxChars = "-1"; - }; - new GuiButtonCtrl() { - profile = "GuiButtonProfile"; - horizSizing = "right"; - vertSizing = "top"; - position = "70 68"; - extent = "80 22"; - minExtent = "8 8"; - visible = "1"; - command = "MessageCallback(MessageBoxYesNoDlg,MessageBoxYesNoDlg.yesCallback);"; - accelerator = "return"; - helpTag = "0"; - text = "Yes"; - simpleStyle = "0"; - }; - new GuiButtonCtrl() { - profile = "GuiButtonProfile"; - horizSizing = "right"; - vertSizing = "top"; - position = "167 68"; - extent = "80 22"; - minExtent = "8 8"; - visible = "1"; - command = "MessageCallback(MessageBoxYesNoDlg,MessageBoxYesNoDlg.noCallback);"; - accelerator = "escape"; - helpTag = "0"; - text = "No"; - simpleStyle = "0"; - }; - }; -}; -//--- OBJECT WRITE END --- diff --git a/Templates/BaseGame/game/data/ui/guis/optionsMenu.cs b/Templates/BaseGame/game/data/ui/guis/optionsMenu.cs index 56709caa8..4c738e81d 100644 --- a/Templates/BaseGame/game/data/ui/guis/optionsMenu.cs +++ b/Templates/BaseGame/game/data/ui/guis/optionsMenu.cs @@ -48,27 +48,6 @@ function OptionsMenuSettingsList::onAdd(%this) { - %yesNoList = "No\tYes"; - %onOffList = "Off\tOn"; - %highMedLow = "Low\tMedium\tHigh"; - %anisoFilter = "Off\t4\t8\t16"; - OptionsMenuSettingsList.addOptionRow("Shadow Quality", "High\tMedium\tLow\tNone", false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Soft Shadow Quality", %highMedLow, false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Mesh Quality", %highMedLow, false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Texture Quality", %highMedLow, false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Terrain Quality", %highMedLow, false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Decal Lifetime", %highMedLow, false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Ground Cover Density", %highMedLow, false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Shader Quality", %highMedLow, false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Anisotropic Filtering", %anisoFilter, false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Anti-Aliasing", "4\t2\t1\tOff", false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Refresh Rate", "75\t60\t30", false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Parallax", %onOffList, false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Water Reflections", %onOffList, false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("SSAO", %onOffList, false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Depth of Field", %onOffList, false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Vignette", %onOffList, false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Light Rays", %onOffList, false, "", -1, -30); } function OptionsMenu::onWake(%this) @@ -95,13 +74,30 @@ function OptionsButtonHolder::refresh(%this) GamepadButtonsGui.setButton(1, "RB", "", "Next Tab", "OptionsMenu.nextTab();", true); GamepadButtonsGui.setButton(2, "Start", "Enter", "Apply", "OptionsMenu.apply();"); GamepadButtonsGui.setButton(3, "B", "Esc", "Back", "OptionsMenu.backOut();"); - GamepadButtonsGui.setButton(7, "Back", "R", "Reset", "OptionsMenu.backOut();"); + GamepadButtonsGui.setButton(7, "Back", "R", "Reset", "OptionsMenu.resetToDefaults();"); GamepadButtonsGui.refreshButtons(); } +function OptionsMenu::apply(%this) +{ + if(%this.pageTabIndex == 0) + { + %this.applyDisplaySettings(); + } + else if(%this.pageTabIndex == 1) + { + %this.applyGraphicsSettings(); + } +} + function OptionsMenuSettingsList::onChange(%this) { + %optionName = %this.getRowLabel(%this.getSelectedRow()); + %tooltipText = %this.getTooltip(%this.getSelectedRow()); + + OptionName.setText(%optionName); + OptionDescription.setText(%tooltipText); return; OptionsMenuSettingsList.clearOptions(); @@ -128,6 +124,8 @@ function OptionsMenuSettingsList::onChange(%this) { OptionsMenuList.populateGamepadSettingsList(); } + + } function OptionsMenu::prevTab(%this) @@ -171,69 +169,57 @@ function OptionsMenu::populateDisplaySettingsList(%this) %this.pageTabIndex = 0; OptionsMenuSettingsList.clearRows(); + OptionName.setText(""); + OptionDescription.setText(""); + %resolutionList = getScreenResolutionList(); - //OptionsMenuSettingsList.addOptionsRow("Resolution", %yesNoList, false, "", 0, -15); - OptionsMenuSettingsList.addOptionRow("Resolution", %resolutionList, false, "screenResolutionOptionChanged", -1, -30); + OptionsMenuSettingsList.addOptionRow("Display API", "D3D11\tOpenGL", false, "", -1, -30, true, "The display API used for rendering.", getDisplayDeviceInformation()); + OptionsMenuSettingsList.addOptionRow("Resolution", %resolutionList, false, "screenResolutionOptionChanged", -1, -30, true, "Resolution of the game window", _makePrettyResString( $pref::Video::mode )); + OptionsMenuSettingsList.addOptionRow("Fullscreen", "No\tYes", false, "", -1, -30, true, "", convertBoolToYesNo($pref::Video::FullScreen)); + OptionsMenuSettingsList.addOptionRow("VSync", "No\tYes", false, "", -1, -30, true, "", convertBoolToYesNo(!$pref::Video::disableVerticalSync)); + + OptionsMenuSettingsList.addOptionRow("Refresh Rate", "30\t60\t75", false, "", -1, -30, true, "", $pref::Video::RefreshRate); + + //move to gameplay tab + OptionsMenuSettingsList.addSliderRow("Field of View", 75, 5, "65 100", "", -1, -30); + + OptionsMenuSettingsList.addSliderRow("Brightness", 0.5, 0.1, "0 1", "", -1, -30); + OptionsMenuSettingsList.addSliderRow("Contrast", 0.5, 0.1, "0 1", "", -1, -30); + + OptionsMenuSettingsList.refresh(); } -function _makePrettyResString( %resString, %giveAspectRation ) +function OptionsMenu::applyDisplaySettings(%this) { - %width = getWord( %resString, $WORD::RES_X ); - %height = getWord( %resString, $WORD::RES_Y ); - - %aspect = %width / %height; - %aspect = mRound( %aspect * 100 ) * 0.01; - - switch$( %aspect ) + %newAdapter = GraphicsMenuDriver.getText(); + %numAdapters = GFXInit::getAdapterCount(); + %newDevice = $pref::Video::displayDevice; + + for( %i = 0; %i < %numAdapters; %i ++ ) + { + if( GFXInit::getAdapterName( %i ) $= %newAdapter ) + { + %newDevice = GFXInit::getAdapterType( %i ); + break; + } + } + + // Change the device. + if ( %newDevice !$= $pref::Video::displayDevice ) { - case "1.33": - %aspect = "4:3"; - case "1.78": - %aspect = "16:9"; - default: - %aspect = ""; + if ( %testNeedApply ) + return true; + + $pref::Video::displayDevice = %newDevice; + if( %newAdapter !$= getDisplayDeviceInformation() ) + MessageBoxOK( "Change requires restart", "Please restart the game for a display device change to take effect." ); } - %outRes = %width @ " x " @ %height; - if ( %giveAspectRation && %aspect !$= "" ) - %outRes = %outRes @ " (" @ %aspect @ ")"; - - return %outRes; -} - -function getScreenResolutionList() -{ - %returnsList = ""; + updateDisplaySettings(); - %resCount = Canvas.getModeCount(); - for (%i = 0; %i < %resCount; %i++) - { - %testResString = Canvas.getMode( %i ); - %testRes = _makePrettyResString( %testResString ); - - //sanitize - %found = false; - %retCount = getTokenCount(%returnsList, "\t"); - for (%x = 0; %x < %retCount; %x++) - { - %existingEntry = getToken(%returnsList, "\t", %x); - if(%existingEntry $= %testRes) - { - %found = true; - break; - } - } - - if(%found) - continue; - - if(%i != 0) - %returnsList = %returnsList @ "\t" @ %testRes; - else - %returnsList = %testRes; - } - - return %returnsList; + echo("Exporting client prefs"); + %prefPath = getPrefpath(); + export("$pref::*", %prefPath @ "/clientPrefs.cs", false); } function screenResolutionOptionChanged() @@ -246,27 +232,124 @@ function OptionsMenu::populateGraphicsSettingsList(%this) %this.pageTabIndex = 1; OptionsMenuSettingsList.clearRows(); + OptionName.setText(""); + OptionDescription.setText(""); + %yesNoList = "No\tYes"; %onOffList = "Off\tOn"; %highMedLow = "Low\tMedium\tHigh"; %anisoFilter = "Off\t4\t8\t16"; - OptionsMenuSettingsList.addOptionRow("Shadow Quality", "High\tMedium\tLow\tNone", false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Soft Shadow Quality", %highMedLow, false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Mesh Quality", %highMedLow, false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Texture Quality", %highMedLow, false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Terrain Quality", %highMedLow, false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Decal Lifetime", %highMedLow, false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Ground Cover Density", %highMedLow, false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Shader Quality", %highMedLow, false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Anisotropic Filtering", %anisoFilter, false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Anti-Aliasing", "4\t2\t1\tOff", false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Refresh Rate", "75\t60\t30", false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Parallax", %onOffList, false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Water Reflections", %onOffList, false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("SSAO", %onOffList, false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Depth of Field", %onOffList, false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Vignette", %onOffList, false, "", -1, -30); - OptionsMenuSettingsList.addOptionRow("Light Rays", %onOffList, false, "", -1, -30); + OptionsMenuSettingsList.addOptionRow("Shadow Quality", getQualityLevels(ShadowQualityList), false, "", -1, -30, true, "Shadow revolution quality", getCurrentQualityLevel(ShadowQualityList)); + OptionsMenuSettingsList.addOptionRow("Soft Shadow Quality", getQualityLevels(SoftShadowList), false, "", -1, -30, true, "Amount of softening applied to shadowmaps", getCurrentQualityLevel(SoftShadowList)); + OptionsMenuSettingsList.addOptionRow("Mesh Quality", getQualityLevels(MeshQualityGroup), false, "", -1, -30, true, "Fidelity of rendering of mesh objects", getCurrentQualityLevel(MeshQualityGroup)); + OptionsMenuSettingsList.addOptionRow("Texture Quality", getQualityLevels(TextureQualityGroup), false, "", -1, -30, true, "Fidelity of textures", getCurrentQualityLevel(TextureQualityGroup)); + OptionsMenuSettingsList.addOptionRow("Terrain Quality", getQualityLevels(TerrainQualityGroup), false, "", -1, -30, true, "Quality level of terrain objects", getCurrentQualityLevel(TerrainQualityGroup)); + OptionsMenuSettingsList.addOptionRow("Decal Lifetime", getQualityLevels(DecalLifetimeGroup), false, "", -1, -30, true, "How long decals are rendered", getCurrentQualityLevel(DecalLifetimeGroup)); + OptionsMenuSettingsList.addOptionRow("Ground Cover Density", getQualityLevels(GroundCoverDensityGroup), false, "", -1, -30, true, "Density of ground cover items, such as grass", getCurrentQualityLevel(GroundCoverDensityGroup)); + OptionsMenuSettingsList.addOptionRow("Shader Quality", getQualityLevels(ShaderQualityGroup), false, "", -1, -30, true, "Dictates the overall shader quality level, adjusting what features are enabled.", getCurrentQualityLevel(ShaderQualityGroup)); + OptionsMenuSettingsList.addOptionRow("Anisotropic Filtering", %anisoFilter, false, "", -1, -30, true, "Amount of Anisotropic Filtering on textures, which dictates their sharpness at a distance", $pref::Video::defaultAnisotropy); + OptionsMenuSettingsList.addOptionRow("Anti-Aliasing", "4\t2\t1\tOff", false, "", -1, -30, true, "Amount of Post-Processing Anti-Aliasing applied to rendering", $pref::Video::AA); + OptionsMenuSettingsList.addOptionRow("Parallax", %onOffList, false, "", -1, -30, true, "Whether the surface parallax shader effect is enabled", convertBoolToOnOff(!$pref::Video::disableParallaxMapping)); + OptionsMenuSettingsList.addOptionRow("Water Reflections", %onOffList, false, "", -1, -30, true, "Whether water reflections are enabled", convertBoolToOnOff(!$pref::Water::disableTrueReflections)); + OptionsMenuSettingsList.addOptionRow("SSAO", %onOffList, false, "", -1, -30, true, "Whether Screen-Space Ambient Occlusion is enabled", convertBoolToOnOff($pref::PostFX::EnableSSAO)); + OptionsMenuSettingsList.addOptionRow("Depth of Field", %onOffList, false, "", -1, -30, true, "Whether the Depth of Field effect is enabled", convertBoolToOnOff($pref::PostFX::EnableDOF)); + OptionsMenuSettingsList.addOptionRow("Vignette", %onOffList, false, "", -1, -30, true, "Whether the vignette effect is enabled", convertBoolToOnOff($pref::PostFX::EnableVignette)); + OptionsMenuSettingsList.addOptionRow("Light Rays", %onOffList, false, "", -1, -30, true, "Whether the light rays effect is enabled", convertBoolToOnOff($pref::PostFX::EnableLightRays)); + + OptionsMenuSettingsList.refresh(); +} + +function OptionsMenu::applyGraphicsSettings(%this) +{ + ShadowQualityList.applySetting(OptionsMenuSettingsList.getCurrentOption(0)); + SoftShadowList.applySetting(OptionsMenuSettingsList.getCurrentOption(1)); + + MeshQualityGroup.applySetting(OptionsMenuSettingsList.getCurrentOption(2)); + TextureQualityGroup.applySetting(OptionsMenuSettingsList.getCurrentOption(3)); + TerrainQualityGroup.applySetting(OptionsMenuSettingsList.getCurrentOption(4)); + DecalLifetimeGroup.applySetting(OptionsMenuSettingsList.getCurrentOption(5)); + GroundCoverDensityGroup.applySetting(OptionsMenuSettingsList.getCurrentOption(6)); + ShaderQualityGroup.applySetting(OptionsMenuSettingsList.getCurrentOption(7)); + + //Update Textures + reloadTextures(); + + //Update lighting + // Set the light manager. This should do nothing + // if its already set or if its not compatible. + //setLightManager( $pref::lightManager ); + + $pref::PostFX::EnableSSAO = convertOptionToBool(OptionsMenuSettingsList.getCurrentOption(12)); + $pref::PostFX::EnableDOF = convertOptionToBool(OptionsMenuSettingsList.getCurrentOption(13)); + $pref::PostFX::EnableVignette = convertOptionToBool(OptionsMenuSettingsList.getCurrentOption(14)); + $pref::PostFX::EnableLightRays = convertOptionToBool(OptionsMenuSettingsList.getCurrentOption(15)); + + PostFXManager.settingsEffectSetEnabled("SSAO", $pref::PostFX::EnableSSAO); + PostFXManager.settingsEffectSetEnabled("DOF", $pref::PostFX::EnableDOF); + PostFXManager.settingsEffectSetEnabled("LightRays", $pref::PostFX::EnableLightRays); + PostFXManager.settingsEffectSetEnabled("Vignette", $pref::PostFX::EnableVignette); + + $pref::Video::disableParallaxMapping = !convertOptionToBool(OptionsMenuSettingsList.getCurrentOption(10)); + + //water reflections + $pref::Water::disableTrueReflections = !convertOptionToBool(OptionsMenuSettingsList.getCurrentOption(11)); + + // Check the anisotropic filtering. + %level = OptionsMenuSettingsList.getCurrentOption(8); + if ( %level != $pref::Video::defaultAnisotropy ) + { + if ( %testNeedApply ) + return true; + + $pref::Video::defaultAnisotropy = %level; + } + + updateDisplaySettings(); + + echo("Exporting client prefs"); + %prefPath = getPrefpath(); + export("$pref::*", %prefPath @ "/clientPrefs.cs", false); +} + +function updateDisplaySettings() +{ + //Update the display settings now + $pref::Video::Resolution = getWords( Canvas.getMode( GraphicsMenuResolution.getSelected() ), $WORD::RES_X, $WORD::RES_Y ); + %newBpp = 32; // ... its not 1997 anymore. + $pref::Video::FullScreen = GraphicsMenuFullScreen.isStateOn() ? "true" : "false"; + $pref::Video::RefreshRate = GraphicsMenuRefreshRate.getSelected(); + $pref::Video::disableVerticalSync = !GraphicsMenuVSync.isStateOn(); + $pref::Video::AA = GraphicsMenuAA.getSelected(); + + if ( %newFullScreen $= "false" ) + { + // If we're in windowed mode switch the fullscreen check + // if the resolution is bigger than the desktop. + %deskRes = getDesktopResolution(); + %deskResX = getWord(%deskRes, $WORD::RES_X); + %deskResY = getWord(%deskRes, $WORD::RES_Y); + if ( getWord( %newRes, $WORD::RES_X ) > %deskResX || + getWord( %newRes, $WORD::RES_Y ) > %deskResY ) + { + $pref::Video::FullScreen = "true"; + GraphicsMenuFullScreen.setStateOn( true ); + } + } + + // Build the final mode string. + %newMode = $pref::Video::Resolution SPC $pref::Video::FullScreen SPC %newBpp SPC $pref::Video::RefreshRate SPC $pref::Video::AA; + + // Change the video mode. + if ( %newMode !$= $pref::Video::mode || + %newVsync != $pref::Video::disableVerticalSync ) + { + if ( %testNeedApply ) + return true; + + $pref::Video::mode = %newMode; + $pref::Video::disableVerticalSync = %newVsync; + configureCanvas(); + } } function OptionsMenu::populateAudioSettingsList(%this) @@ -274,8 +357,56 @@ function OptionsMenu::populateAudioSettingsList(%this) %this.pageTabIndex = 2; OptionsMenuSettingsList.clearRows(); + OptionName.setText(""); + OptionDescription.setText(""); + + %buffer = sfxGetAvailableDevices(); + %count = getRecordCount( %buffer ); + %audioDriverList = ""; + + for(%i = 0; %i < %count; %i++) + { + %record = getRecord(%buffer, %i); + %provider = getField(%record, 0); + + if(%i == 0) + %audioDriverList = %provider; + else + %audioDriverList = %audioDriverList @ "\t" @ %provider; + } + %yesNoList = "Yes\tNo"; - OptionsMenuSettingsList.addOptionRow("Audio Device", %yesNoList, false, "", -1, -15); + OptionsMenuSettingsList.addOptionRow("Audio Driver", %audioDriverList, false, "", -1, -15, true, "", $pref::SFX::provider); + OptionsMenuSettingsList.addOptionRow("Audio Device", %yesNoList, false, "", -1, -15, true, ""); + + OptionsMenuSettingsList.addSliderRow("Master Volume", $pref::SFX::masterVolume, 0.1, "0 1", "", -1, -30); + OptionsMenuSettingsList.addSliderRow("GUI Volume", $pref::SFX::channelVolume[ $GuiAudioType], 0.1, "0 1", "", -1, -30); + OptionsMenuSettingsList.addSliderRow("Effects Volume", $pref::SFX::channelVolume[ $SimAudioType ], 0.1, "0 1", "", -1, -30); + OptionsMenuSettingsList.addSliderRow("Music Volume", $pref::SFX::channelVolume[ $MusicAudioType ], 0.1, "0 1", "", -1, -30); + + OptionsMenuSettingsList.refresh(); +} + +function OptionsMenu::applyAudioSettings(%this) +{ + sfxSetMasterVolume( $pref::SFX::masterVolume ); + + sfxSetChannelVolume( $GuiAudioType, $pref::SFX::channelVolume[ $GuiAudioType ] ); + sfxSetChannelVolume( $SimAudioType, $pref::SFX::channelVolume[ $SimAudioType ] ); + sfxSetChannelVolume( $MusicAudioType, $pref::SFX::channelVolume[ $MusicAudioType ] ); + + if ( !sfxCreateDevice( $pref::SFX::provider, + $pref::SFX::device, + $pref::SFX::useHardware, + -1 ) ) + error( "Unable to create SFX device: " @ $pref::SFX::provider + SPC $pref::SFX::device + SPC $pref::SFX::useHardware ); + + if( !isObject( $AudioTestHandle ) ) + { + sfxPlay(menuButtonPressed); + } } function OptionsMenu::populateKeyboardMouseSettingsList(%this) @@ -283,13 +414,23 @@ function OptionsMenu::populateKeyboardMouseSettingsList(%this) %this.pageTabIndex = 3; OptionsMenuSettingsList.clearRows(); - OptionsMenuSettingsList.addOptionRow("Forward", "W", false, "", -1, -15); + OptionName.setText(""); + OptionDescription.setText(""); + + OptionsMenuSettingsList.addKeybindRow("Forward", getButtonBitmap("Keyboard", "W"), "doKeyRemap", -1, -15, true, "Forward butaaaahn"); + + OptionsMenuSettingsList.refresh(); } function OptionsMenu::populateGamepadSettingsList(%this) { %this.pageTabIndex = 4; OptionsMenuSettingsList.clearRows(); + + OptionName.setText(""); + OptionDescription.setText(""); + + OptionsMenuSettingsList.refresh(); } function OptionsMenuList::activateRow(%this) @@ -297,78 +438,6 @@ function OptionsMenuList::activateRow(%this) OptionsMenuSettingsList.setFirstResponder(); } -function OptionsMenuList::backOut(%this) -{ - OptionsMenuList.setFirstResponder(); -} - -function OptionsMenuOKButton::onClick(%this) -{ - //save the settings and then back out - eval(OptionsMenu.currentMenu@"::apply();"); - OptionsMenu.backOut(); -} - -// -// -function OptionsMenuSettingsList::backOut(%this) -{ - OptionsMenuList.setFirstResponder(); -} -// -// - -function OptionsMenuCancelButton::onClick(%this) -{ - //we don't save, so just back out of the menu - OptionsMenu.backOut(); -} - -function OptionsMenuDefaultsButton::onClick(%this) -{ - //we don't save, so go straight to backing out of the menu - eval(OptionsMenu.currentMenu@"::applyDefaults();"); - OptionsMenu.backOut(); -} - -function ControlsSettingsMenuButton::onClick(%this) -{ - OptionsMain.hidden = true; - ControlsMenu.hidden = false; - - KeyboardControlPanel.hidden = false; - MouseControlPanel.hidden = true; - - ControlsMenu.reload(); -} - -function GraphicsSettingsMenuButton::onClick(%this) -{ - OptionsMain.hidden = true; - GraphicsMenu.hidden = false; -} - -function CameraSettingsMenuButton::onClick(%this) -{ - OptionsMain.hidden = true; - CameraMenu.hidden = false; - - CameraMenu.loadSettings(); -} - -function AudioSettingsMenuButton::onClick(%this) -{ - OptionsMain.hidden = true; - AudioMenu.hidden = false; - AudioMenu.loadSettings(); -} - -function ScreenBrSettingsMenuButton::onClick(%this) -{ - OptionsMain.hidden = true; - ScreenBrightnessMenu.hidden = false; -} - function OptionsMenu::backOut(%this) { //save the settings and then back out @@ -391,217 +460,26 @@ function OptionsMenu::backOut(%this) } } -function OptionsMenu::addSettingOption(%this, %arrayTarget, %optionName, %defaultValue, %settingsGroup, %targetVar) +function convertOptionToBool(%val) { - %option = TAMLRead("data/ui/guis/graphicsMenuSettingsCtrl.taml"); - - if(!isMethod(%settingsGroup, "get") || !isMethod(%settingsGroup, "set")) - { - error("OptionsMenu::addSettingsOption - unrecognized settings group of: " @ %settingsGroup @ ". Did not have proper getter/setter"); - return ""; - } - - %option-->nameText.text = %optionName; - %option-->SettingText.text = eval(%settingsGroup@"::"@"get();"); - %option.qualitySettingGroup = %settingsGroup; - %option.targetVar = %targetVar; - - %arrayTarget.add(%option); - - return %option; + if(%val $= "yes" || %val $= "on") + return 1; + else + return 0; } -function OptionsMenu::addSliderOption(%this, %arrayTarget, %optionName, %variable, %range, %ticks, %value, %class) +function convertBoolToYesNo(%val) { - %option = TAMLRead("data/ui/guis/graphicsMenuSettingsSlider.taml"); - - %option-->nameText.text = %optionName; - - %arrayTarget.add(%option); - - if(%range !$= "") - { - %option-->slider.range = %range; - } - - if(%ticks !$= "") - { - %option-->slider.ticks = %ticks; - } - - if(%variable !$= "") - { - %option-->slider.variable = %variable; - } - - if(%value !$= "") - { - %option-->slider.setValue(%value); - } - - if(%class !$= "") - { - %option-->slider.className = %class; - } - else - %option-->slider.className = OptionsMenuSlider; - - %option-->slider.snap = true; - - %option-->slider.onValueSet(); - - return %option; + if(%val == 1) + return "Yes"; + else + return "No"; } -function OptionsMenuSlider::onMouseDragged(%this) +function convertBoolToOnOff(%val) { - %this.onValueSet(); -} - -function OptionsMenuSlider::onValueSet(%this) -{ - %this.getParent().getParent()-->valueText.setText(mRound(%this.value * 10)); -} - -function FOVOptionSlider::onMouseDragged(%this) -{ - %this.onValueSet(); -} - -function FOVOptionSlider::onValueSet(%this) -{ - %this.getParent().getParent()-->valueText.setText(mRound(%this.value)); -} - -// -function OptionsMenuForwardSetting::onClick(%this) -{ - //we need to advance through the value list, unless it's the end, in which case we do nothing - echo("Move forward in the list!"); - - %settingCtrl = %this.getParent(); - %settingsList = eval(%settingCtrl.qualitySettingGroup@"::getList();"); - %settingsListCount = getTokenCount(%settingsList, ","); - %currentSetting = %settingCtrl-->SettingText.text; - - //We consider 'custom' to be the defacto end of the list. The only way back is to go lower - if(%currentSetting $= "Custom") - return; - - %currentSettingIdx = OptionsMenu.getCurrentIndexFromSetting(%settingCtrl); - - if(%currentSettingIdx != %settingsListCount-1) - { - %currentSettingIdx++; - - //advance by one - %newSetting = getToken(%settingsList, ",", %currentSettingIdx); - eval(%settingCtrl.qualitySettingGroup@"::set(\""@%newSetting@"\");"); - %settingCtrl-->SettingText.setText( %newSetting ); - - if(%currentSettingIdx == %settingsListCount) - { - //if we hit the end of the list, disable the forward button - } - } -} - -function OptionsMenuBackSetting::onClick(%this) -{ - //we need to advance through the value list, unless it's the end, in which case we do nothing - echo("Move back in the list!"); - - %settingCtrl = %this.getParent(); - %settingsList = eval(%settingCtrl.qualitySettingGroup@"::getList();"); - %settingsListCount = getTokenCount(%settingsList, ","); - %currentSetting = %settingCtrl-->SettingText.text; - - %currentSettingIdx = OptionsMenu.getCurrentIndexFromSetting(%settingCtrl); - - if(%currentSettingIdx != 0) - { - %currentSettingIdx--; - - //advance by one - %newSetting = getToken(%settingsList, ",", %currentSettingIdx); - eval(%settingCtrl.qualitySettingGroup@"::set(\""@%newSetting@"\");"); - %settingCtrl-->SettingText.setText( %newSetting ); - - if(%currentSettingIdx == %settingsListCount) - { - //if we hit the end of the list, disable the forward button - } - } -} - -function OptionsMenu::getCurrentIndexFromSetting(%this, %settingCtrl) -{ - %settingsList = eval(%settingCtrl.qualitySettingGroup@"::getList();"); - %settingsListCount = getTokenCount(%settingsList, ","); - %currentSetting = %settingCtrl-->SettingText.text; - - for ( %i=0; %i < %settingsListCount; %i++ ) - { - %level = getToken(%settingsList, ",", %i); - - //find our current level - if(%currentSetting $= %level) - { - return %i; - } - } - - return -1; -} - -// ============================================================================= -// CAMERA MENU -// ============================================================================= -function CameraMenu::onWake(%this) -{ - -} - -function CameraMenu::apply(%this) -{ - setFOV($pref::Player::defaultFov); -} - -function CameraMenu::loadSettings(%this) -{ - CameraMenuOptionsArray.clear(); - - %option = OptionsMenu.addSettingOption(CameraMenuOptionsArray); - %option-->nameText.setText("Invert Vertical"); - %option.qualitySettingGroup = InvertVerticalMouse; - %option.init(); - - %option = OptionsMenu.addSliderOption(CameraMenuOptionsArray, "0.1 1", 8, "$pref::Input::VertMouseSensitivity", $pref::Input::VertMouseSensitivity); - %option-->nameText.setText("Vertical Sensitivity"); - - %option = OptionsMenu.addSliderOption(CameraMenuOptionsArray, "0.1 1", 8, "$pref::Input::HorzMouseSensitivity", $pref::Input::HorzMouseSensitivity); - %option-->nameText.setText("Horizontal Sensitivity"); - - %option = OptionsMenu.addSliderOption(CameraMenuOptionsArray, "0.1 1", 8, "$pref::Input::ZoomVertMouseSensitivity", $pref::Input::ZoomVertMouseSensitivity); - %option-->nameText.setText("Zoom Vertical Sensitivity"); - - %option = OptionsMenu.addSliderOption(CameraMenuOptionsArray, "0.1 1", 8, "$pref::Input::ZoomHorzMouseSensitivity", $pref::Input::ZoomHorzMouseSensitivity); - %option-->nameText.setText("Zoom Horizontal Sensitivity"); - - %option = OptionsMenu.addSliderOption(CameraMenuOptionsArray, "65 90", 25, "$pref::Player::defaultFov", $pref::Player::defaultFov, FOVOptionSlider); - %option-->nameText.setText("Field of View"); - - CameraMenuOptionsArray.refresh(); -} - -function CameraMenuOKButton::onClick(%this) -{ - //save the settings and then back out - CameraMenu.apply(); - OptionsMenu.backOut(); -} - -function CameraMenuDefaultsButton::onClick(%this) -{ - + if(%val == 1) + return "On"; + else + return "Off"; } \ No newline at end of file diff --git a/Templates/BaseGame/game/data/ui/guis/optionsMenu.gui b/Templates/BaseGame/game/data/ui/guis/optionsMenu.gui index 00d48b1e6..494b83ae7 100644 --- a/Templates/BaseGame/game/data/ui/guis/optionsMenu.gui +++ b/Templates/BaseGame/game/data/ui/guis/optionsMenu.gui @@ -17,313 +17,6 @@ tile = "0"; useVariable = "0"; - new GuiControl() { - position = "89 75"; - extent = "846 618"; - minExtent = "8 2"; - horizSizing = "center"; - vertSizing = "center"; - profile = "GuiDefaultProfile"; - visible = "0"; - active = "1"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "1"; - hidden = "1"; - canSave = "1"; - canSaveDynamicFields = "0"; - - new GuiBitmapCtrl() { - bitmap = "data/ui/images/hudfill.png"; - color = "255 255 255 255"; - wrap = "0"; - position = "0 0"; - extent = "846 618"; - minExtent = "8 2"; - horizSizing = "width"; - vertSizing = "height"; - profile = "GuiDefaultProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "0"; - canSave = "1"; - canSaveDynamicFields = "0"; - }; - new GuiControl() { - position = "0 0"; - extent = "846 20"; - minExtent = "8 2"; - horizSizing = "width"; - vertSizing = "bottom"; - profile = "GuiDefaultProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "1"; - canSave = "1"; - canSaveDynamicFields = "0"; - - new GuiBitmapCtrl() { - bitmap = "data/ui/images/hudfill.png"; - color = "255 255 255 255"; - wrap = "0"; - position = "0 0"; - extent = "846 20"; - minExtent = "8 2"; - horizSizing = "width"; - vertSizing = "height"; - profile = "GuiDefaultProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "0"; - canSave = "1"; - canSaveDynamicFields = "0"; - }; - new GuiTextCtrl() { - text = "Options"; - maxLength = "1024"; - margin = "0 0 0 0"; - padding = "0 0 0 0"; - anchorTop = "1"; - anchorBottom = "0"; - anchorLeft = "1"; - anchorRight = "0"; - position = "0 0"; - extent = "846 20"; - minExtent = "8 2"; - horizSizing = "width"; - vertSizing = "bottom"; - profile = "GuiMenuButtonProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "1"; - canSave = "1"; - canSaveDynamicFields = "0"; - }; - }; - new GuiScrollCtrl() { - willFirstRespond = "1"; - hScrollBar = "alwaysOff"; - vScrollBar = "dynamic"; - lockHorizScroll = "0"; - lockVertScroll = "0"; - constantThumbHeight = "0"; - childMargin = "0 0"; - mouseWheelScrollSpeed = "-1"; - margin = "0 0 0 0"; - padding = "0 0 0 0"; - anchorTop = "1"; - anchorBottom = "0"; - anchorLeft = "1"; - anchorRight = "0"; - position = "0 25"; - extent = "846 522"; - minExtent = "8 2"; - horizSizing = "width"; - vertSizing = "height"; - profile = "GuiMenuScrollProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "1"; - canSave = "1"; - canSaveDynamicFields = "0"; - - new GuiStackControl(OptionsSettingStack) { - stackingType = "Vertical"; - horizStacking = "Left to Right"; - vertStacking = "Top to Bottom"; - padding = "0"; - dynamicSize = "1"; - dynamicNonStackExtent = "0"; - dynamicPos = "0"; - changeChildSizeToFit = "1"; - changeChildPosition = "1"; - position = "1 1"; - extent = "846 140"; - minExtent = "16 16"; - horizSizing = "width"; - vertSizing = "bottom"; - profile = "GuiDefaultProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "1"; - canSave = "1"; - canSaveDynamicFields = "0"; - - new GuiButtonCtrl() { - text = "Keyboard and Mouse"; - groupNum = "-1"; - buttonType = "PushButton"; - useMouseEvents = "0"; - position = "0 0"; - extent = "846 35"; - minExtent = "8 2"; - horizSizing = "right"; - vertSizing = "bottom"; - profile = "GuiMenuButtonProfile"; - visible = "1"; - active = "1"; - command = "ControlsMenu::loadSettings();"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "0"; - canSave = "1"; - canSaveDynamicFields = "0"; - }; - new GuiButtonCtrl() { - text = "Display"; - groupNum = "-1"; - buttonType = "PushButton"; - useMouseEvents = "0"; - position = "0 35"; - extent = "846 35"; - minExtent = "8 2"; - horizSizing = "right"; - vertSizing = "bottom"; - profile = "GuiMenuButtonProfile"; - visible = "1"; - active = "1"; - command = "DisplayMenu::loadSettings();"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "0"; - canSave = "1"; - canSaveDynamicFields = "0"; - }; - new GuiButtonCtrl() { - text = "Graphics"; - groupNum = "-1"; - buttonType = "PushButton"; - useMouseEvents = "0"; - position = "0 70"; - extent = "846 35"; - minExtent = "8 2"; - horizSizing = "right"; - vertSizing = "bottom"; - profile = "GuiMenuButtonProfile"; - visible = "1"; - active = "1"; - command = "GraphicsMenu::loadSettings();"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "0"; - canSave = "1"; - canSaveDynamicFields = "0"; - }; - new GuiButtonCtrl() { - text = "Audio"; - groupNum = "-1"; - buttonType = "PushButton"; - useMouseEvents = "0"; - position = "0 105"; - extent = "846 35"; - minExtent = "8 2"; - horizSizing = "right"; - vertSizing = "bottom"; - profile = "GuiMenuButtonProfile"; - visible = "1"; - active = "1"; - command = "AudioMenu::loadSettings();"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "0"; - canSave = "1"; - canSaveDynamicFields = "0"; - }; - }; - }; - new GuiMLTextCtrl() { - lineSpacing = "2"; - allowColorChars = "0"; - maxChars = "-1"; - text = "This is a test message to act as a tooltip for any selected options menus for more information on the given option."; - useURLMouseCursor = "0"; - position = "0 547"; - extent = "847 14"; - minExtent = "8 2"; - horizSizing = "width"; - vertSizing = "top"; - profile = "GuiMLWhiteTextProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "0"; - canSave = "1"; - canSaveDynamicFields = "0"; - }; - new GuiButtonCtrl() { - text = "OK"; - groupNum = "-1"; - buttonType = "PushButton"; - useMouseEvents = "0"; - position = "0 581"; - extent = "282 37"; - minExtent = "8 2"; - horizSizing = "right"; - vertSizing = "top"; - profile = "GuiMenuButtonProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "0"; - class = "OptionsMenuOKButton"; - canSave = "1"; - canSaveDynamicFields = "0"; - }; - new GuiButtonCtrl() { - text = "Defaults"; - groupNum = "-1"; - buttonType = "PushButton"; - useMouseEvents = "0"; - position = "282 581"; - extent = "282 37"; - minExtent = "8 2"; - horizSizing = "relative"; - vertSizing = "top"; - profile = "GuiMenuButtonProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "0"; - class = "OptionsMenuDefaultsButton"; - canSave = "1"; - canSaveDynamicFields = "0"; - }; - new GuiButtonCtrl() { - text = "Cancel"; - groupNum = "-1"; - buttonType = "PushButton"; - useMouseEvents = "0"; - position = "564 581"; - extent = "282 37"; - minExtent = "8 2"; - horizSizing = "left"; - vertSizing = "height"; - profile = "GuiMenuButtonProfile"; - visible = "1"; - active = "1"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "0"; - class = "OptionsMenuCancelButton"; - canSave = "1"; - canSaveDynamicFields = "0"; - }; - }; new GuiControl() { position = "48 56"; extent = "928 655"; diff --git a/Templates/BaseGame/game/data/ui/guis/pauseMenu.cs b/Templates/BaseGame/game/data/ui/guis/pauseMenu.cs index b23b423f0..a4519183a 100644 --- a/Templates/BaseGame/game/data/ui/guis/pauseMenu.cs +++ b/Templates/BaseGame/game/data/ui/guis/pauseMenu.cs @@ -1,30 +1,59 @@ +function PauseMenuList::onAdd(%this) +{ + %this.addRow("Options", "openPauseMenuOptions", -1, -30); + %this.addRow("Exit to Menu", "pauseMenuExitToMenu", -1, -30); + %this.addRow("Exit to Desktop", "pauseMenuExitToDesktop", -1, -30); +} + function PauseMenu::onWake(%this) { $timescale = 0; } + function PauseMenu::onSleep(%this) { $timescale = 1; } -function PauseMenu::openOptionsMenu(%this) -{ - Canvas.pushDialog(OptionsMenu); - OptionsMenu.returnGui = %this; - PauseOptionsMain.hidden = true; -} - -function PauseMenu::openControlsMenu(%this) -{ - Canvas.pushDialog(OptionsMenu); - OptionsMenu.returnGui = %this; - PauseOptionsMain.hidden = true; - OptionsMain.hidden = true; - ControlsMenu.hidden = false; -} - function PauseMenu::onReturnTo(%this) { - PauseOptionsMain.hidden = false; + PauseMenuList.hidden = false; + PauseButtonHolder.refresh(); +} + +function openPauseMenuOptions() +{ + Canvas.pushDialog(OptionsMenu); + OptionsMenu.returnGui = PauseMenu; + PauseMenuList.hidden = true; +} + +function pauseMenuExitToMenu() +{ + PauseMenuList.hidden = true; + MessageBoxOKCancel("Exit?", "Do you wish to exit to the Main Menu?", "escapeFromGame();", "PauseMenu.onReturnTo();"); +} + +function pauseMenuExitToDesktop() +{ + PauseMenuList.hidden = true; + MessageBoxOKCancel("Exit?", "Do you wish to exit to the desktop?", "quit();", "PauseMenu.onReturnTo();"); +} + +function PauseButtonHolder::onWake(%this) +{ + %this.refresh(); +} + +function PauseButtonHolder::refresh(%this) +{ + PauseButtonHolder.add(GamepadButtonsGui); + + GamepadButtonsGui.clearButtons(); + + GamepadButtonsGui.setButton(2, "A", "", "", "", true); + GamepadButtonsGui.setButton(3, "B", "Esc", "Back", "Canvas.popDialog();"); + + GamepadButtonsGui.refreshButtons(); } \ No newline at end of file diff --git a/Templates/BaseGame/game/data/ui/guis/pauseMenu.gui b/Templates/BaseGame/game/data/ui/guis/pauseMenu.gui index b59f13221..e57da0c7c 100644 --- a/Templates/BaseGame/game/data/ui/guis/pauseMenu.gui +++ b/Templates/BaseGame/game/data/ui/guis/pauseMenu.gui @@ -49,105 +49,43 @@ isContainer = "1"; canSave = "1"; canSaveDynamicFields = "0"; - - new GuiControl(PauseOptionsMain) { - position = "1 1"; + + new GuiGameListMenuCtrl(PauseMenuList) { + class = "UIMenuButtonList"; + debugRender = "0"; + callbackOnA = "OptionsMenuSettingsList.activateRow();"; + callbackOnB = "OptionsMenuSettingsList.backOut();"; + callbackOnInputs = "1"; + position = "0 0"; extent = "700 320"; minExtent = "8 2"; - horizSizing = "right"; - vertSizing = "center"; - profile = "GuiDefaultProfile"; + horizSizing = "width"; + vertSizing = "bottom"; + profile = "DefaultListMenuProfile"; visible = "1"; active = "1"; tooltipProfile = "GuiToolTipProfile"; hovertime = "1000"; - isContainer = "1"; + isContainer = "0"; canSave = "1"; canSaveDynamicFields = "0"; - - new GuiButtonCtrl(PauseMenuExitButton) { - text = "Exit Game"; - groupNum = "-1"; - buttonType = "PushButton"; - useMouseEvents = "1"; - position = "0 0"; - extent = "700 35"; - minExtent = "8 8"; - horizSizing = "relative"; - vertSizing = "bottom"; - profile = "GuiMenuButtonProfile"; - visible = "1"; - active = "1"; - command = "escapeFromGame();"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "0"; - canSave = "1"; - canSaveDynamicFields = "0"; - }; - new GuiButtonCtrl(PauseMenuOptionsButton) { - text = "Options"; - groupNum = "-1"; - buttonType = "PushButton"; - useMouseEvents = "1"; - position = "0 35"; - extent = "700 35"; - minExtent = "8 8"; - horizSizing = "relative"; - vertSizing = "bottom"; - profile = "GuiMenuButtonProfile"; - visible = "1"; - active = "1"; - command = "PauseMenu.openOptionsMenu();"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "0"; - canSave = "1"; - canSaveDynamicFields = "0"; - }; - new GuiButtonCtrl(PauseMenuControlsButton) { - text = "Controls"; - groupNum = "-1"; - buttonType = "PushButton"; - useMouseEvents = "1"; - position = "0 70"; - extent = "700 35"; - minExtent = "8 8"; - horizSizing = "relative"; - vertSizing = "bottom"; - profile = "GuiMenuButtonProfile"; - visible = "1"; - active = "1"; - command = "PauseMenu.openControlsMenu();"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "0"; - canSave = "1"; - canSaveDynamicFields = "0"; - }; - new GuiButtonCtrl(PauseMenuCancelButton) { - text = "Cancel"; - groupNum = "-1"; - buttonType = "PushButton"; - useMouseEvents = "1"; - position = "466 285"; - extent = "233 35"; - minExtent = "8 8"; - horizSizing = "relative"; - vertSizing = "bottom"; - profile = "GuiMenuButtonProfile"; - visible = "1"; - active = "1"; - command = "Canvas.popDialog();"; - accelerator = "escape"; - tooltipProfile = "GuiToolTipProfile"; - hovertime = "1000"; - isContainer = "0"; - class = "OptionsMenuDefaultsButton"; - canSave = "1"; - canSaveDynamicFields = "0"; - }; }; }; + + new GuiControl(PauseButtonHolder) { + position = "189 652"; + extent = "646 130"; + minExtent = "8 2"; + horizSizing = "center"; + vertSizing = "top"; + profile = "GuiDefaultProfile"; + visible = "1"; + active = "1"; + tooltipProfile = "GuiToolTipProfile"; + hovertime = "1000"; + isContainer = "1"; + canSave = "1"; + canSaveDynamicFields = "0"; + }; }; //--- OBJECT WRITE END --- diff --git a/Templates/BaseGame/game/data/ui/images/Inputs/Keyboard & Mouse/Keyboard_Black_Blank.png b/Templates/BaseGame/game/data/ui/images/Inputs/Keyboard & Mouse/Keyboard_Black_Blank.png new file mode 100644 index 0000000000000000000000000000000000000000..9c47c66f19d6ae647bec793cc23138c60aec3974 GIT binary patch literal 1162 zcmeAS@N?(olHy`uVBq!ia0vp^DImg|{?sUc5A>_Qp)n+10drfQaJzU6ztcf)aKzm39Dhcn!PE1HBSyhew@+HQ04;!mfZ9bJUbo(U3qSu^uT{WSNlDSgU-PQ=qP%cU z#a~`4?F1(Vt(vcL^6cl&pY5%$?>>F(ZQ1W^0harnFS4#Puk5s6GUa|bXPd0Y_S=7N ze%>Rk^y|>t#mnL*tL&8FVY9c8uD-LkYF@c7$KfZZ7v)DpG?whXo9}Yv@w*cKFJiS@ zwl-{@DDdc1NL@*Z%f9#P_r22TdwlhJiIwl)nv3rBdC~gj6TJ88@Hku9**yyhuXGf+ zP+@aV!}x2U+#5@m?duZ-_V)9*-n5#Kw)yAeI5ii=>Bdu^R?geV?^F9VG4^(zfmH9m ztEZ;~-3|-3US?^Ua>N!--k* zHZ)3m%-?ePo<(18dYHJl_>~;9nY$lyHZ7QNVR~sxqQ}~>?zp(P75CpSuhZ{KzWnTE z{Fz46mHO`=t}&JkS$+ z8IBtw|E3r%RPpri%FN#0%GK0RbN{}@+E~8!ZO}wB-mCW@AhRGd=ysu2Pi>|5f-E=HL z`b+Zl+tUgsO?tK1#!GsWf;`J331qao@yf$1-xmkpTlCQWh#?0WTEd`rr*8j6?p5DD z%!BoXpO*s4a=4}bdcJnXim_^$v zcdyuUoIz`;Mqje_>%e1=H(nJMS?zqSz+y{et(s!XRD&f`zI^x)P_g&*j>aW&3v#5= z7i%oKm~rGzYxI&SCFSMQzj{PmR$J5VQ@q}}?&9f9&)R?guI^f-VY)ozWQNHpp5_yG z%7W#e2A*29U!zN-Ymre|Xyp#RLZ8IOke}C1tn13L{(jB#)!J{7k6+svY`uHMy|Q5b z-#Tv>>B-k_-g9JTY{an^L HB{Ts59EB@) literal 0 HcmV?d00001 diff --git a/Templates/BaseGame/game/data/ui/scripts/displayMenu.cs b/Templates/BaseGame/game/data/ui/scripts/displayMenu.cs index bf84abfd8..c821eb72c 100644 --- a/Templates/BaseGame/game/data/ui/scripts/displayMenu.cs +++ b/Templates/BaseGame/game/data/ui/scripts/displayMenu.cs @@ -38,7 +38,7 @@ function DisplayMenu::apply(%this) } //Update the display settings now - if (getWord( $pref::Video::Resolution, 2) == "") + if (getWord( $pref::Video::Resolution, 2) $= "") { $pref::Video::Resolution = getWord( $pref::Video::Resolution, 0 ) SPC getWord( $pref::Video::Resolution, 1 ); } diff --git a/Templates/BaseGame/game/data/ui/scripts/keybindEdit.cs b/Templates/BaseGame/game/data/ui/scripts/keybindEdit.cs new file mode 100644 index 000000000..2171162c3 --- /dev/null +++ b/Templates/BaseGame/game/data/ui/scripts/keybindEdit.cs @@ -0,0 +1,401 @@ +// ============================================================================= +// KEYBINDS MENU +// ============================================================================= +$RemapCount = 0; +$RemapName[$RemapCount] = "Forward"; +$RemapCmd[$RemapCount] = "moveforward"; +$RemapGroup[$RemapCount] = "Movement"; +$RemapCount++; +$RemapName[$RemapCount] = "Backward"; +$RemapCmd[$RemapCount] = "movebackward"; +$RemapGroup[$RemapCount] = "Movement"; +$RemapCount++; +$RemapName[$RemapCount] = "Strafe Left"; +$RemapCmd[$RemapCount] = "moveleft"; +$RemapGroup[$RemapCount] = "Movement"; +$RemapCount++; +$RemapName[$RemapCount] = "Strafe Right"; +$RemapCmd[$RemapCount] = "moveright"; +$RemapGroup[$RemapCount] = "Movement"; +$RemapCount++; +$RemapName[$RemapCount] = "Jump"; +$RemapCmd[$RemapCount] = "jump"; +$RemapGroup[$RemapCount] = "Movement"; +$RemapCount++; + +$RemapName[$RemapCount] = "Fire Weapon"; +$RemapCmd[$RemapCount] = "mouseFire"; +$RemapGroup[$RemapCount] = "Combat"; +$RemapCount++; +$RemapName[$RemapCount] = "Adjust Zoom"; +$RemapCmd[$RemapCount] = "setZoomFov"; +$RemapGroup[$RemapCount] = "Combat"; +$RemapCount++; +$RemapName[$RemapCount] = "Toggle Zoom"; +$RemapCmd[$RemapCount] = "toggleZoom"; +$RemapGroup[$RemapCount] = "Combat"; +$RemapCount++; + +$RemapName[$RemapCount] = "Free Look"; +$RemapCmd[$RemapCount] = "toggleFreeLook"; +$RemapGroup[$RemapCount] = "Miscellaneous"; +$RemapCount++; +$RemapName[$RemapCount] = "Switch 1st/3rd"; +$RemapCmd[$RemapCount] = "toggleFirstPerson"; +$RemapGroup[$RemapCount] = "Miscellaneous"; +$RemapCount++; +$RemapName[$RemapCount] = "Toggle Camera"; +$RemapCmd[$RemapCount] = "toggleCamera"; +$RemapGroup[$RemapCount] = "Miscellaneous"; +$RemapCount++; + +function ControlSetList::onSelect( %this, %id, %text ) +{ + ControlsMenuOptionsArray.clear(); + + if(%text $= "Movement") + loadGroupKeybinds("Movement"); + else if(%text $= "Combat") + loadGroupKeybinds("Combat"); + else if(%text $= "Miscellaneous") + loadGroupKeybinds("Miscellaneous"); + + //ControlsMenuOptionsArray.refresh(); +} + +function ControlsMenuOKButton::onClick(%this) +{ + // write out the control config into the keybinds.cs file + %prefPath = getPrefpath(); + moveMap.save( %prefPath @ "/keybinds.cs" ); + + OptionsMenu.backOut(); +} + +function ControlsMenuDefaultsButton::onClick(%this) +{ + //For this to work with module-style, we have to figure that somewhere, we'll set where our default keybind script is at. + //This can be hardcoded in your actual project. + exec($KeybindPath); + ControlsMenu.reload(); +} + +function loadGroupKeybinds(%keybindGroup) +{ + %optionIndex = 0; + for(%i=0; %i < $RemapCount; %i++) + { + //find and add all the keybinds for the particular group we're looking at + if($RemapGroup[%i] $= %keybindGroup) + { + %temp = getKeybindString(%i); + + %option = addKeybindOption(); + %option-->nameText.setText($RemapName[%i]); + %option-->rebindButton.setText(%temp); + %option-->rebindButton.keybindIndex = %i; + %option-->rebindButton.optionIndex = %optionIndex; + %optionIndex++; + } + } +} + +function addKeybindOption() +{ + %tamlReader = new Taml(); + + %controlOption = %tamlReader.read("data/ui/guis/controlsMenuSetting.taml"); + %controlOption.extent.x = OptionsSettingStack.extent.x; + + OptionsSettingStack.add(%controlOption); + + return %graphicsOption; +} + +function getKeybindString(%index ) +{ + %name = $RemapName[%index]; + %cmd = $RemapCmd[%index]; + + %temp = moveMap.getBinding( %cmd ); + if ( %temp $= "" ) + return %name TAB ""; + + %mapString = ""; + + %count = getFieldCount( %temp ); + for ( %i = 0; %i < %count; %i += 2 ) + { + %device = getField( %temp, %i + 0 ); + %object = getField( %temp, %i + 1 ); + + %displayName = getMapDisplayName( %device, %object ); + + if(%displayName !$= "") + { + %tmpMapString = getMapDisplayName( %device, %object ); + + if(%mapString $= "") + { + %mapString = %tmpMapString; + } + else + { + if ( %tmpMapString !$= "") + { + %mapString = %mapString @ ", " @ %tmpMapString; + } + } + } + } + + return %mapString; +} + +function ControlsMenu::redoMapping( %device, %action, %cmd, %oldIndex, %newIndex ) +{ + //%actionMap.bind( %device, %action, $RemapCmd[%newIndex] ); + moveMap.bind( %device, %action, %cmd ); + + %remapList = %this-->OptRemapList; + %remapList.setRowById( %oldIndex, buildFullMapString( %oldIndex ) ); + %remapList.setRowById( %newIndex, buildFullMapString( %newIndex ) ); +} + +function getMapDisplayName( %device, %action ) +{ + if ( %device $= "keyboard" ) + return( %action ); + else if ( strstr( %device, "mouse" ) != -1 ) + { + // Substitute "mouse" for "button" in the action string: + %pos = strstr( %action, "button" ); + if ( %pos != -1 ) + { + %mods = getSubStr( %action, 0, %pos ); + %object = getSubStr( %action, %pos, 1000 ); + %instance = getSubStr( %object, strlen( "button" ), 1000 ); + return( %mods @ "mouse" @ ( %instance + 1 ) ); + } + else + error( "Mouse input object other than button passed to getDisplayMapName!" ); + } + else if ( strstr( %device, "joystick" ) != -1 ) + { + // Substitute "joystick" for "button" in the action string: + %pos = strstr( %action, "button" ); + if ( %pos != -1 ) + { + %mods = getSubStr( %action, 0, %pos ); + %object = getSubStr( %action, %pos, 1000 ); + %instance = getSubStr( %object, strlen( "button" ), 1000 ); + return( %mods @ "joystick" @ ( %instance + 1 ) ); + } + else + { + %pos = strstr( %action, "pov" ); + if ( %pos != -1 ) + { + %wordCount = getWordCount( %action ); + %mods = %wordCount > 1 ? getWords( %action, 0, %wordCount - 2 ) @ " " : ""; + %object = getWord( %action, %wordCount - 1 ); + switch$ ( %object ) + { + case "upov": %object = "POV1 up"; + case "dpov": %object = "POV1 down"; + case "lpov": %object = "POV1 left"; + case "rpov": %object = "POV1 right"; + case "upov2": %object = "POV2 up"; + case "dpov2": %object = "POV2 down"; + case "lpov2": %object = "POV2 left"; + case "rpov2": %object = "POV2 right"; + default: %object = ""; + } + return( %mods @ %object ); + } + else + error( "Unsupported Joystick input object passed to getDisplayMapName!" ); + } + } + + return( "" ); +} + +function ControlsMenu::buildFullMapString( %this, %index ) +{ + %name = $RemapName[%index]; + %cmd = $RemapCmd[%index]; + + %temp = moveMap.getBinding( %cmd ); + if ( %temp $= "" ) + return %name TAB ""; + + %mapString = ""; + + %count = getFieldCount( %temp ); + for ( %i = 0; %i < %count; %i += 2 ) + { + if ( %mapString !$= "" ) + %mapString = %mapString @ ", "; + + %device = getField( %temp, %i + 0 ); + %object = getField( %temp, %i + 1 ); + %mapString = %mapString @ %this.getMapDisplayName( %device, %object ); + } + + return %name TAB %mapString; +} + +function ControlsMenu::fillRemapList( %this ) +{ + %remapList = %this-->OptRemapList; + + %remapList.clear(); + for ( %i = 0; %i < $RemapCount; %i++ ) + %remapList.addRow( %i, %this.buildFullMapString( %i ) ); +} + +function doKeyRemap( %rowIndex ) +{ + %name = $RemapName[%rowIndex]; + + RemapDlg-->OptRemapText.setValue( "Re-bind \"" @ %name @ "\" to..." ); + OptRemapInputCtrl.index = %rowIndex; + Canvas.pushDialog( RemapDlg ); +} + +function ControlsMenuRebindButton::onClick(%this) +{ + %name = $RemapName[%this.keybindIndex]; + RemapDlg-->OptRemapText.setValue( "Re-bind \"" @ %name @ "\" to..." ); + + OptRemapInputCtrl.index = %this.keybindIndex; + OptRemapInputCtrl.optionIndex = %this.optionIndex; + Canvas.pushDialog( RemapDlg ); +} + +function OptRemapInputCtrl::onInputEvent( %this, %device, %action ) +{ + //error( "** onInputEvent called - device = " @ %device @ ", action = " @ %action @ " **" ); + Canvas.popDialog( RemapDlg ); + + // Test for the reserved keystrokes: + if ( %device $= "keyboard" ) + { + // Cancel... + if ( %action $= "escape" ) + { + // Do nothing... + return; + } + } + + %cmd = $RemapCmd[%this.index]; + %name = $RemapName[%this.index]; + + // Grab the friendly display name for this action + // which we'll use when prompting the user below. + %mapName = ControlsMenu.getMapDisplayName( %device, %action ); + + // Get the current command this action is mapped to. + %prevMap = moveMap.getCommand( %device, %action ); + + // If nothing was mapped to the previous command + // mapping then it's easy... just bind it. + if ( %prevMap $= "" ) + { + ControlsMenu.unbindExtraActions( %cmd, 1 ); + moveMap.bind( %device, %action, %cmd ); + + //ControlsMenu.reload(); + %newCommands = getField(ControlsMenu.buildFullMapString( %this.index ), 1); + ControlsMenuOptionsArray.getObject(%this.optionIndex)-->rebindButton.setText(%newCommands); + return; + } + + // If the previous command is the same as the + // current then they hit the same input as what + // was already assigned. + if ( %prevMap $= %cmd ) + { + ControlsMenu.unbindExtraActions( %cmd, 0 ); + moveMap.bind( %device, %action, %cmd ); + + //ControlsMenu.reload(); + %newCommands = getField(ControlsMenu.buildFullMapString( %this.index ), 1); + ControlsMenuOptionsArray.getObject(%this.optionIndex)-->rebindButton.setText(%newCommands); + return; + } + + // Look for the index of the previous mapping. + %prevMapIndex = ControlsMenu.findRemapCmdIndex( %prevMap ); + + // If we get a negative index then the previous + // mapping was to an item that isn't included in + // the mapping list... so we cannot unmap it. + if ( %prevMapIndex == -1 ) + { + MessageBoxOK( "Remap Failed", "\"" @ %mapName @ "\" is already bound to a non-remappable command!" ); + return; + } + + // Setup the forced remapping callback command. + %callback = "redoMapping(" @ %device @ ", \"" @ %action @ "\", \"" @ + %cmd @ "\", " @ %prevMapIndex @ ", " @ %this.index @ ");"; + + // Warn that we're about to remove the old mapping and + // replace it with another. + %prevCmdName = $RemapName[%prevMapIndex]; + Canvas.pushDialog( RemapConfirmDlg ); + + RemapConfirmationText.setText("\"" @ %mapName @ "\" is already bound to \"" + @ %prevCmdName @ "\"! Do you wish to replace this mapping?"); + RemapConfirmationYesButton.command = "ControlsMenu.redoMapping(" @ %device @ ", \"" @ %action @ "\", \"" @ + %cmd @ "\", " @ %prevMapIndex @ ", " @ %this.index @ "); Canvas.popDialog();"; + RemapConfirmationNoButton.command = "Canvas.popDialog();"; + + /*MessageBoxYesNo( "Warning", + "\"" @ %mapName @ "\" is already bound to \"" + @ %prevCmdName @ "\"!\nDo you wish to replace this mapping?", + %callback, "" );*/ +} + +function ControlsMenu::findRemapCmdIndex( %this, %command ) +{ + for ( %i = 0; %i < $RemapCount; %i++ ) + { + if ( %command $= $RemapCmd[%i] ) + return( %i ); + } + return( -1 ); +} + +/// This unbinds actions beyond %count associated to the +/// particular moveMap %commmand. +function ControlsMenu::unbindExtraActions( %this, %command, %count ) +{ + %temp = moveMap.getBinding( %command ); + if ( %temp $= "" ) + return; + + %count = getFieldCount( %temp ) - ( %count * 2 ); + for ( %i = 0; %i < %count; %i += 2 ) + { + %device = getField( %temp, %i + 0 ); + %action = getField( %temp, %i + 1 ); + + moveMap.unbind( %device, %action ); + } +} + +function ControlsMenu::redoMapping( %this, %device, %action, %cmd, %oldIndex, %newIndex ) +{ + //%actionMap.bind( %device, %action, $RemapCmd[%newIndex] ); + moveMap.bind( %device, %action, %cmd ); + + %remapList = %this-->OptRemapList; + %remapList.setRowById( %oldIndex, %this.buildFullMapString( %oldIndex ) ); + %remapList.setRowById( %newIndex, %this.buildFullMapString( %newIndex ) ); + + %this.changeSettingsPage(); +} \ No newline at end of file diff --git a/Templates/BaseGame/game/data/ui/scripts/optionsList.cs b/Templates/BaseGame/game/data/ui/scripts/optionsList.cs deleted file mode 100644 index e69de29bb..000000000 diff --git a/Templates/BaseGame/game/data/ui/scripts/utility.cs b/Templates/BaseGame/game/data/ui/scripts/utility.cs new file mode 100644 index 000000000..adff8f367 --- /dev/null +++ b/Templates/BaseGame/game/data/ui/scripts/utility.cs @@ -0,0 +1,65 @@ +function getButtonBitmap(%device, %button) +{ + %path = ""; + if(%device $= "PS4") + { + %path = "data/ui/images/inputs/PS4/PS4_"; + + if(%button $= "A") + %path = %path @ "Cross"; + else if(%button $= "B") + %path = %path @ "Circle"; + else if(%button $= "X") + %path = %path @ "Square"; + else if(%button $= "Y") + %path = %path @ "Triangle"; + else if(%button $= "LB") + %path = %path @ "L1"; + else if(%button $= "LT") + %path = %path @ "L2"; + else if(%button $= "RB") + %path = %path @ "R1"; + else if(%button $= "RT") + %path = %path @ "R2"; + else + continue; + } + else if(%device $= "Switch") + { + %path = "data/ui/images/inputs/Switch/Switch_"; + + if(%button $= "A") + %path = %path @ "B"; + else if(%button $= "B") + %path = %path @ "A"; + else if(%button $= "X") + %path = %path @ "Y"; + else if(%button $= "Y") + %path = %path @ "X"; + else if(%button $= "LB") + %path = %path @ "LB"; + else if(%button $= "LT") + %path = %path @ "LT"; + else if(%button $= "RB") + %path = %path @ "RB"; + else if(%button $= "RT") + %path = %path @ "RT"; + else + continue; + } + else if(%device $= "Keyboard" || %device $= "Mouse") + { + %pathBase = "data/ui/images/Inputs/Keyboard & Mouse/Keyboard_Black_"; + %path = %pathBase @ %button @ ".png"; + if(!isFile(%path)) + %path = %pathBase @ "Blank"; + } + else if(%device !$= "") + { + %path = "data/ui/images/inputs/Xbox/Xbox_"; + + %path = %path @ %button; + } + + return %path; +} \ No newline at end of file