mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2024-11-30 07:31:12 +00:00
1209 lines
29 KiB
Text
1209 lines
29 KiB
Text
/*
|
|
** optionmenuitems.txt
|
|
** Control items for option menus
|
|
**
|
|
**---------------------------------------------------------------------------
|
|
** Copyright 2010-2017 Christoph Oelckers
|
|
** All rights reserved.
|
|
**
|
|
** Redistribution and use in source and binary forms, with or without
|
|
** modification, are permitted provided that the following conditions
|
|
** are met:
|
|
**
|
|
** 1. Redistributions of source code must retain the above copyright
|
|
** notice, this list of conditions and the following disclaimer.
|
|
** 2. Redistributions in binary form must reproduce the above copyright
|
|
** notice, this list of conditions and the following disclaimer in the
|
|
** documentation and/or other materials provided with the distribution.
|
|
** 3. The name of the author may not be used to endorse or promote products
|
|
** derived from this software without specific prior written permission.
|
|
**
|
|
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
**---------------------------------------------------------------------------
|
|
**
|
|
*/
|
|
|
|
class OptionMenuItem : MenuItemBase
|
|
{
|
|
String mLabel;
|
|
bool mCentered;
|
|
|
|
protected void Init(String label, String command, bool center = false)
|
|
{
|
|
Super.Init(0, 0, command);
|
|
mLabel = label;
|
|
mCentered = center;
|
|
}
|
|
|
|
protected void drawLabel(int indent, int y, int color, bool grayed = false)
|
|
{
|
|
String label = Stringtable.Localize(mLabel);
|
|
|
|
int overlay = grayed? Color(96,48,0,0) : 0;
|
|
|
|
int x;
|
|
int w = SmallFont.StringWidth(label) * CleanXfac_1;
|
|
if (!mCentered) x = indent - w;
|
|
else x = (screen.GetWidth() - w) / 2;
|
|
screen.DrawText (SmallFont, color, x, y, label, DTA_CleanNoMove_1, true, DTA_ColorOverlay, overlay);
|
|
}
|
|
|
|
int CursorSpace()
|
|
{
|
|
return (14 * CleanXfac_1);
|
|
}
|
|
|
|
override bool Selectable()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
override int GetIndent()
|
|
{
|
|
if (mCentered) return 0;
|
|
return SmallFont.StringWidth(Stringtable.Localize(mLabel));
|
|
}
|
|
|
|
override bool MouseEvent(int type, int x, int y)
|
|
{
|
|
if (Selectable() && type == Menu.MOUSE_Release)
|
|
{
|
|
return Menu.GetCurrentMenu().MenuEvent(Menu.MKEY_Enter, true);
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
//
|
|
// opens a submenu, command is a submenu name
|
|
//
|
|
//=============================================================================
|
|
|
|
class OptionMenuItemSubmenu : OptionMenuItem
|
|
{
|
|
int mParam;
|
|
OptionMenuItemSubmenu Init(String label, Name command, int param = 0)
|
|
{
|
|
Super.init(label, command);
|
|
mParam = param;
|
|
return self;
|
|
}
|
|
|
|
override int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected)
|
|
{
|
|
drawLabel(indent, y, selected? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColorMore);
|
|
return indent;
|
|
}
|
|
|
|
override bool Activate()
|
|
{
|
|
Menu.MenuSound("menu/choose");
|
|
Menu.SetMenu(mAction, mParam);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
//
|
|
// Executes a CCMD, command is a CCMD name
|
|
//
|
|
//=============================================================================
|
|
|
|
class OptionMenuItemCommand : OptionMenuItemSubmenu
|
|
{
|
|
OptionMenuItemCommand Init(String label, Name command)
|
|
{
|
|
Super.Init(label, command);
|
|
return self;
|
|
}
|
|
|
|
private native static void DoCommand(String cmd); // This is very intentionally limited to this menu item to prevent abuse.
|
|
|
|
override bool Activate()
|
|
{
|
|
// This needs to perform a few checks to prevent abuse by malicious modders.
|
|
let m = OptionMenu(Menu.GetCurrentMenu());
|
|
// don't execute if no menu is active
|
|
if (m == null) return false;
|
|
// don't execute if this item cannot be found in the current menu.
|
|
if (m.mDesc.GetItem(mAction) != self) return false;
|
|
Menu.MenuSound("menu/choose");
|
|
DoCommand(mAction);
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|
|
//=============================================================================
|
|
//
|
|
// Executes a CCMD after confirmation, command is a CCMD name
|
|
//
|
|
//=============================================================================
|
|
|
|
class OptionMenuItemSafeCommand : OptionMenuItemCommand
|
|
{
|
|
String mPrompt;
|
|
|
|
|
|
OptionMenuItemSafeCommand Init(String label, Name command, String prompt = "")
|
|
{
|
|
Super.Init(label, command);
|
|
mPrompt = prompt;
|
|
return self;
|
|
}
|
|
|
|
override bool MenuEvent (int mkey, bool fromcontroller)
|
|
{
|
|
if (mkey == Menu.MKEY_MBYes)
|
|
{
|
|
Super.Activate();
|
|
return true;
|
|
}
|
|
return Super.MenuEvent(mkey, fromcontroller);
|
|
}
|
|
|
|
override bool Activate()
|
|
{
|
|
String msg = mPrompt.Length() > 0 ? mPrompt : "$SAFEMESSAGE";
|
|
msg = StringTable.Localize(msg);
|
|
String actionLabel = StringTable.localize(mLabel);
|
|
|
|
String FullString;
|
|
FullString = String.Format("%s%s%s\n\n%s", TEXTCOLOR_WHITE, actionLabel, TEXTCOLOR_NORMAL, msg);
|
|
Menu.StartMessage(FullString, 0);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
//
|
|
// Base class for option lists
|
|
//
|
|
//=============================================================================
|
|
|
|
class OptionMenuItemOptionBase : OptionMenuItem
|
|
{
|
|
// command is a CVAR
|
|
Name mValues; // Entry in OptionValues table
|
|
CVar mGrayCheck;
|
|
int mCenter;
|
|
|
|
const OP_VALUES = 0x11001;
|
|
|
|
protected void Init(String label, Name command, Name values, CVar graycheck, int center)
|
|
{
|
|
Super.Init(label, command);
|
|
mValues = values;
|
|
mGrayCheck = graycheck;
|
|
mCenter = center;
|
|
}
|
|
|
|
override bool SetString(int i, String newtext)
|
|
{
|
|
if (i == OP_VALUES)
|
|
{
|
|
int cnt = OptionValues.GetCount(mValues);
|
|
if (cnt >= 0)
|
|
{
|
|
mValues = newtext;
|
|
int s = GetSelection();
|
|
if (s >= cnt) s = 0;
|
|
SetSelection(s); // readjust the CVAR if its value is outside the range now
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//=============================================================================
|
|
virtual int GetSelection()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
virtual void SetSelection(int Selection)
|
|
{
|
|
}
|
|
|
|
//=============================================================================
|
|
override int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected)
|
|
{
|
|
bool grayed = mGrayCheck != null && !(mGrayCheck.GetInt());
|
|
|
|
if (mCenter)
|
|
{
|
|
indent = (screen.GetWidth() / 2);
|
|
}
|
|
drawLabel(indent, y, selected? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor, grayed);
|
|
|
|
int overlay = grayed? Color(96,48,0,0) : 0;
|
|
int Selection = GetSelection();
|
|
String text = StringTable.Localize(OptionValues.GetText(mValues, Selection));
|
|
if (text.Length() == 0) text = "Unknown";
|
|
screen.DrawText (SmallFont, OptionMenuSettings.mFontColorValue, indent + CursorSpace(), y, text, DTA_CleanNoMove_1, true, DTA_ColorOverlay, overlay);
|
|
return indent;
|
|
}
|
|
|
|
//=============================================================================
|
|
override bool MenuEvent (int mkey, bool fromcontroller)
|
|
{
|
|
int cnt = OptionValues.GetCount(mValues);
|
|
if (cnt > 0)
|
|
{
|
|
int Selection = GetSelection();
|
|
if (mkey == Menu.MKEY_Left)
|
|
{
|
|
if (Selection == -1) Selection = 0;
|
|
else if (--Selection < 0) Selection = cnt - 1;
|
|
}
|
|
else if (mkey == Menu.MKEY_Right || mkey == Menu.MKEY_Enter)
|
|
{
|
|
if (++Selection >= cnt) Selection = 0;
|
|
}
|
|
else
|
|
{
|
|
return Super.MenuEvent(mkey, fromcontroller);
|
|
}
|
|
SetSelection(Selection);
|
|
Menu.MenuSound("menu/change");
|
|
}
|
|
else
|
|
{
|
|
return Super.MenuEvent(mkey, fromcontroller);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
override bool Selectable()
|
|
{
|
|
return mGrayCheck == null || mGrayCheck.GetInt();
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
//
|
|
// Change a CVAR, command is the CVAR name
|
|
//
|
|
//=============================================================================
|
|
|
|
class OptionMenuItemOption : OptionMenuItemOptionBase
|
|
{
|
|
CVar mCVar;
|
|
|
|
OptionMenuItemOption Init(String label, Name command, Name values, CVar graycheck = null, int center = 0)
|
|
{
|
|
Super.Init(label, command, values, graycheck, center);
|
|
mCVar = CVar.FindCVar(mAction);
|
|
return self;
|
|
}
|
|
|
|
//=============================================================================
|
|
override int GetSelection()
|
|
{
|
|
int Selection = -1;
|
|
int cnt = OptionValues.GetCount(mValues);
|
|
if (cnt > 0 && mCVar != null)
|
|
{
|
|
if (OptionValues.GetTextValue(mValues, 0).Length() == 0)
|
|
{
|
|
let f = mCVar.GetFloat();
|
|
for(int i = 0; i < cnt; i++)
|
|
{
|
|
if (f ~== OptionValues.GetValue(mValues, i))
|
|
{
|
|
Selection = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
String cv = mCVar.GetString();
|
|
for(int i = 0; i < cnt; i++)
|
|
{
|
|
if (cv ~== OptionValues.GetTextValue(mValues, i))
|
|
{
|
|
Selection = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return Selection;
|
|
}
|
|
|
|
override void SetSelection(int Selection)
|
|
{
|
|
int cnt = OptionValues.GetCount(mValues);
|
|
if (cnt > 0 && mCVar != null)
|
|
{
|
|
if (OptionValues.GetTextValue(mValues, 0).Length() == 0)
|
|
{
|
|
mCVar.SetFloat(OptionValues.GetValue(mValues, Selection));
|
|
}
|
|
else
|
|
{
|
|
mCVar.SetString(OptionValues.GetTextValue(mValues, Selection));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
//
|
|
// This class is used to capture the key to be used as the new key binding
|
|
// for a control item
|
|
//
|
|
//=============================================================================
|
|
|
|
class EnterKey : Menu
|
|
{
|
|
OptionMenuItemControlBase mOwner;
|
|
|
|
void Init(Menu parent, OptionMenuItemControlBase owner)
|
|
{
|
|
Super.Init(parent);
|
|
mOwner = owner;
|
|
SetMenuMessage(1);
|
|
menuactive = Menu.WaitKey; // There should be a better way to disable GUI capture...
|
|
}
|
|
|
|
override bool TranslateKeyboardEvents()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
private void SetMenuMessage(int which)
|
|
{
|
|
let parent = OptionMenu(mParentMenu);
|
|
if (parent != null)
|
|
{
|
|
let it = parent.GetItem('Controlmessage');
|
|
if (it != null)
|
|
{
|
|
it.SetValue(0, which);
|
|
}
|
|
}
|
|
}
|
|
|
|
override bool Responder(InputEvent ev)
|
|
{
|
|
// This checks raw keys, not GUI keys.
|
|
if (ev.type == InputEvent.KeyDown)
|
|
{
|
|
mOwner.SendKey(ev.data1);
|
|
menuactive = Menu.On;
|
|
SetMenuMessage(0);
|
|
Close();
|
|
mParentMenu.MenuEvent((ev.data1 == InputEvent.KEY_ESCAPE)? Menu.MKEY_Abort : Menu.MKEY_Input, 0);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
override void Drawer()
|
|
{
|
|
mParentMenu.Drawer();
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
//
|
|
// // Edit a key binding, Action is the CCMD to bind
|
|
//
|
|
//=============================================================================
|
|
|
|
class OptionMenuItemControlBase : OptionMenuItem
|
|
{
|
|
KeyBindings mBindings;
|
|
int mInput;
|
|
bool mWaiting;
|
|
|
|
protected void Init(String label, Name command, KeyBindings bindings)
|
|
{
|
|
Super.init(label, command);
|
|
mBindings = bindings;
|
|
mWaiting = false;
|
|
}
|
|
|
|
//=============================================================================
|
|
override int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected)
|
|
{
|
|
drawLabel(indent, y, mWaiting? OptionMenuSettings.mFontColorHighlight:
|
|
(selected? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor));
|
|
|
|
String description;
|
|
int Key1, Key2;
|
|
|
|
[Key1, Key2] = mBindings.GetKeysForCommand(mAction);
|
|
description = KeyBindings.NameKeys (Key1, Key2);
|
|
if (description.Length() > 0)
|
|
{
|
|
Menu.DrawConText(Font.CR_WHITE, indent + CursorSpace(), y + (OptionMenuSettings.mLinespacing-8)*CleanYfac_1, description);
|
|
}
|
|
else
|
|
{
|
|
screen.DrawText(SmallFont, Font.CR_BLACK, indent + CursorSpace(), y + (OptionMenuSettings.mLinespacing-8)*CleanYfac_1, "---", DTA_CleanNoMove_1, true);
|
|
}
|
|
return indent;
|
|
}
|
|
|
|
//=============================================================================
|
|
override bool MenuEvent(int mkey, bool fromcontroller)
|
|
{
|
|
if (mkey == Menu.MKEY_Input)
|
|
{
|
|
mWaiting = false;
|
|
mBindings.SetBind(mInput, mAction);
|
|
return true;
|
|
}
|
|
else if (mkey == Menu.MKEY_Clear)
|
|
{
|
|
mBindings.UnbindACommand(mAction);
|
|
return true;
|
|
}
|
|
else if (mkey == Menu.MKEY_Abort)
|
|
{
|
|
mWaiting = false;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void SendKey(int key)
|
|
{
|
|
mInput = key;
|
|
}
|
|
|
|
override bool Activate()
|
|
{
|
|
Menu.MenuSound("menu/choose");
|
|
mWaiting = true;
|
|
let input = new("EnterKey");
|
|
input.Init(Menu.GetCurrentMenu(), self);
|
|
input.ActivateMenu();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
class OptionMenuItemControl : OptionMenuItemControlBase
|
|
{
|
|
OptionMenuItemControl Init(String label, Name command)
|
|
{
|
|
Super.Init(label, command, Bindings);
|
|
return self;
|
|
}
|
|
}
|
|
|
|
class OptionMenuItemMapControl : OptionMenuItemControlBase
|
|
{
|
|
OptionMenuItemMapControl Init(String label, Name command)
|
|
{
|
|
Super.Init(label, command, AutomapBindings);
|
|
return self;
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
//
|
|
//
|
|
//
|
|
//=============================================================================
|
|
|
|
class OptionMenuItemStaticText : OptionMenuItem
|
|
{
|
|
int mColor;
|
|
|
|
// this function is only for use from MENUDEF, it needs to do some strange things with the color for backwards compatibility.
|
|
OptionMenuItemStaticText Init(String label, int cr = -1)
|
|
{
|
|
Super.Init(label, 'None', true);
|
|
mColor = OptionMenuSettings.mFontColor;
|
|
if ((cr & 0xffff0000) == 0x12340000) mColor = cr & 0xffff;
|
|
else if (cr > 0) mColor = OptionMenuSettings.mFontColorHeader;
|
|
return self;
|
|
}
|
|
|
|
OptionMenuItemStaticText InitDirect(String label, int cr)
|
|
{
|
|
Super.Init(label, 'None', true);
|
|
mColor = cr;
|
|
return self;
|
|
}
|
|
|
|
override int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected)
|
|
{
|
|
drawLabel(indent, y, mColor);
|
|
return -1;
|
|
}
|
|
|
|
override bool Selectable()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
//=============================================================================
|
|
//
|
|
//
|
|
//
|
|
//=============================================================================
|
|
|
|
class OptionMenuItemStaticTextSwitchable : OptionMenuItem
|
|
{
|
|
int mColor;
|
|
String mAltText;
|
|
int mCurrent;
|
|
|
|
// this function is only for use from MENUDEF, it needs to do some strange things with the color for backwards compatibility.
|
|
OptionMenuItemStaticTextSwitchable Init(String label, String label2, Name command, int cr = -1)
|
|
{
|
|
Super.Init(label, command, true);
|
|
mAltText = label2;
|
|
mCurrent = 0;
|
|
|
|
mColor = OptionMenuSettings.mFontColor;
|
|
if ((cr & 0xffff0000) == 0x12340000) mColor = cr & 0xffff;
|
|
else if (cr > 0) mColor = OptionMenuSettings.mFontColorHeader;
|
|
return self;
|
|
}
|
|
|
|
OptionMenuItemStaticTextSwitchable InitDirect(String label, String label2, Name command, int cr)
|
|
{
|
|
Super.Init(label, command, true);
|
|
mColor = cr;
|
|
mAltText = label2;
|
|
mCurrent = 0;
|
|
return self;
|
|
}
|
|
|
|
override int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected)
|
|
{
|
|
String txt = StringTable.Localize(mCurrent? mAltText : mLabel);
|
|
int w = SmallFont.StringWidth(txt) * CleanXfac_1;
|
|
int x = (screen.GetWidth() - w) / 2;
|
|
screen.DrawText (SmallFont, mColor, x, y, txt, DTA_CleanNoMove_1, true);
|
|
return -1;
|
|
}
|
|
|
|
override bool SetValue(int i, int val)
|
|
{
|
|
if (i == 0)
|
|
{
|
|
mCurrent = val;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
override bool SetString(int i, String newtext)
|
|
{
|
|
if (i == 0)
|
|
{
|
|
mAltText = newtext;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
override bool Selectable()
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
//
|
|
//
|
|
//
|
|
//=============================================================================
|
|
|
|
class OptionMenuSliderBase : OptionMenuItem
|
|
{
|
|
// command is a CVAR
|
|
double mMin, mMax, mStep;
|
|
int mShowValue;
|
|
int mDrawX;
|
|
int mSliderShort;
|
|
|
|
protected void Init(String label, double min, double max, double step, int showval)
|
|
{
|
|
Super.Init(label, 'None');
|
|
mMin = min;
|
|
mMax = max;
|
|
mStep = step;
|
|
mShowValue = showval;
|
|
mDrawX = 0;
|
|
mSliderShort = 0;
|
|
}
|
|
|
|
virtual double GetSliderValue()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
virtual void SetSliderValue(double val)
|
|
{
|
|
}
|
|
|
|
//=============================================================================
|
|
//
|
|
// Draw a slider. Set fracdigits negative to not display the current value numerically.
|
|
//
|
|
//=============================================================================
|
|
|
|
private void DrawSlider (int x, int y, double min, double max, double cur, int fracdigits, int indent)
|
|
{
|
|
String formater = String.format("%%.%df", fracdigits); // The format function cannot do the '%.*f' syntax.
|
|
String textbuf;
|
|
double range;
|
|
int maxlen = 0;
|
|
int right = x + (12*8 + 4) * CleanXfac_1;
|
|
int cy = y + (OptionMenuSettings.mLinespacing-8)*CleanYfac_1;
|
|
|
|
range = max - min;
|
|
double ccur = clamp(cur, min, max) - min;
|
|
|
|
if (fracdigits >= 0)
|
|
{
|
|
textbuf = String.format(formater, max);
|
|
maxlen = SmallFont.StringWidth(textbuf) * CleanXfac_1;
|
|
}
|
|
|
|
mSliderShort = right + maxlen > screen.GetWidth();
|
|
|
|
if (!mSliderShort)
|
|
{
|
|
Menu.DrawConText(Font.CR_WHITE, x, cy, "\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12");
|
|
Menu.DrawConText(Font.CR_ORANGE, x + int((5 + ((ccur * 78) / range)) * CleanXfac_1), cy, "\x13");
|
|
}
|
|
else
|
|
{
|
|
// On 320x200 we need a shorter slider
|
|
Menu.DrawConText(Font.CR_WHITE, x, cy, "\x10\x11\x11\x11\x11\x11\x12");
|
|
Menu.DrawConText(Font.CR_ORANGE, x + int((5 + ((ccur * 38) / range)) * CleanXfac_1), cy, "\x13");
|
|
right -= 5*8*CleanXfac_1;
|
|
}
|
|
|
|
if (fracdigits >= 0 && right + maxlen <= screen.GetWidth())
|
|
{
|
|
textbuf = String.format(formater, cur);
|
|
screen.DrawText(SmallFont, Font.CR_DARKGRAY, right, y, textbuf, DTA_CleanNoMove_1, true);
|
|
}
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
override int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected)
|
|
{
|
|
drawLabel(indent, y, selected? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor);
|
|
mDrawX = indent + CursorSpace();
|
|
DrawSlider (mDrawX, y, mMin, mMax, GetSliderValue(), mShowValue, indent);
|
|
return indent;
|
|
}
|
|
|
|
//=============================================================================
|
|
override bool MenuEvent (int mkey, bool fromcontroller)
|
|
{
|
|
double value = GetSliderValue();
|
|
|
|
if (mkey == Menu.MKEY_Left)
|
|
{
|
|
value -= mStep;
|
|
}
|
|
else if (mkey == Menu.MKEY_Right)
|
|
{
|
|
value += mStep;
|
|
}
|
|
else
|
|
{
|
|
return OptionMenuItem.MenuEvent(mkey, fromcontroller);
|
|
}
|
|
if (value ~== 0) value = 0; // This is to prevent formatting anomalies with very small values
|
|
SetSliderValue(clamp(value, mMin, mMax));
|
|
Menu.MenuSound("menu/change");
|
|
return true;
|
|
}
|
|
|
|
override bool MouseEvent(int type, int x, int y)
|
|
{
|
|
let lm = OptionMenu(Menu.GetCurrentMenu());
|
|
if (type != Menu.MOUSE_Click)
|
|
{
|
|
if (!lm.CheckFocus(self)) return false;
|
|
}
|
|
if (type == Menu.MOUSE_Release)
|
|
{
|
|
lm.ReleaseFocus();
|
|
}
|
|
|
|
int slide_left = mDrawX+8*CleanXfac_1;
|
|
int slide_right = slide_left + (10*8*CleanXfac_1 >> mSliderShort); // 12 char cells with 8 pixels each.
|
|
|
|
if (type == Menu.MOUSE_Click)
|
|
{
|
|
if (x < slide_left || x >= slide_right) return true;
|
|
}
|
|
|
|
x = clamp(x, slide_left, slide_right);
|
|
double v = mMin + ((x - slide_left) * (mMax - mMin)) / (slide_right - slide_left);
|
|
if (v != GetSliderValue())
|
|
{
|
|
SetSliderValue(v);
|
|
//Menu.MenuSound("menu/change");
|
|
}
|
|
if (type == Menu.MOUSE_Click)
|
|
{
|
|
lm.SetFocus(self);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
}
|
|
|
|
//=============================================================================
|
|
//
|
|
//
|
|
//
|
|
//=============================================================================
|
|
|
|
class OptionMenuItemSlider : OptionMenuSliderBase
|
|
{
|
|
CVar mCVar;
|
|
|
|
OptionMenuItemSlider Init(String label, Name command, double min, double max, double step, int showval = 1)
|
|
{
|
|
Super.Init(label, min, max, step, showval);
|
|
mCVar =CVar.FindCVar(command);
|
|
return self;
|
|
}
|
|
|
|
override double GetSliderValue()
|
|
{
|
|
if (mCVar != null)
|
|
{
|
|
return mCVar.GetFloat();
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
override void SetSliderValue(double val)
|
|
{
|
|
if (mCVar != null)
|
|
{
|
|
mCVar.SetFloat(val);
|
|
}
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
//
|
|
// // Edit a key binding, Action is the CCMD to bind
|
|
//
|
|
//=============================================================================
|
|
|
|
class OptionMenuItemColorPicker : OptionMenuItem
|
|
{
|
|
CVar mCVar;
|
|
|
|
const CPF_RESET = 0x20001;
|
|
|
|
OptionMenuItemColorPicker Init(String label, Name command)
|
|
{
|
|
Super.Init(label, command);
|
|
CVar cv = CVar.FindCVar(command);
|
|
if (cv != null && cv.GetRealType() != CVar.CVAR_Color) cv = null;
|
|
mCVar = cv;
|
|
return self;
|
|
}
|
|
|
|
//=============================================================================
|
|
override int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected)
|
|
{
|
|
drawLabel(indent, y, selected? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor);
|
|
|
|
if (mCVar != null)
|
|
{
|
|
int box_x = indent + CursorSpace();
|
|
int box_y = y + CleanYfac_1;
|
|
screen.Clear (box_x, box_y, box_x + 32*CleanXfac_1, box_y + OptionMenuSettings.mLinespacing*CleanYfac_1, mCVar.GetInt() | 0xff000000);
|
|
}
|
|
return indent;
|
|
}
|
|
|
|
override bool SetValue(int i, int v)
|
|
{
|
|
if (i == CPF_RESET && mCVar != null)
|
|
{
|
|
mCVar.ResetToDefault();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
override bool Activate()
|
|
{
|
|
if (mCVar != null)
|
|
{
|
|
Menu.MenuSound("menu/choose");
|
|
|
|
// This code is a bit complicated because it should allow subclassing the
|
|
// colorpicker menu.
|
|
// New color pickers must inherit from the internal one to work here.
|
|
|
|
let desc = MenuDescriptor.GetDescriptor('Colorpickermenu');
|
|
if (desc != NULL && (desc.mClass == null || desc.mClass is "ColorPickerMenu"))
|
|
{
|
|
let odesc = OptionMenuDescriptor(desc);
|
|
if (odesc != null)
|
|
{
|
|
let cls = desc.mClass;
|
|
if (cls == null) cls = "ColorpickerMenu";
|
|
let picker = ColorpickerMenu(new(cls));
|
|
picker.Init(Menu.GetCurrentMenu(), mLabel, odesc, mCVar);
|
|
picker.ActivateMenu();
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
class OptionMenuItemScreenResolution : OptionMenuItem
|
|
{
|
|
String mResTexts[3];
|
|
int mSelection;
|
|
int mHighlight;
|
|
int mMaxValid;
|
|
|
|
enum EValues
|
|
{
|
|
SRL_INDEX = 0x30000,
|
|
SRL_SELECTION = 0x30003,
|
|
SRL_HIGHLIGHT = 0x30004,
|
|
};
|
|
|
|
OptionMenuItemScreenResolution Init(String command)
|
|
{
|
|
Super.Init("", command);
|
|
mSelection = 0;
|
|
mHighlight = -1;
|
|
return self;
|
|
}
|
|
|
|
override bool SetValue(int i, int v)
|
|
{
|
|
if (i == SRL_SELECTION)
|
|
{
|
|
mSelection = v;
|
|
return true;
|
|
}
|
|
else if (i == SRL_HIGHLIGHT)
|
|
{
|
|
mHighlight = v;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
override bool, int GetValue(int i)
|
|
{
|
|
if (i == SRL_SELECTION)
|
|
{
|
|
return true, mSelection;
|
|
}
|
|
return false, 0;
|
|
}
|
|
|
|
override bool SetString(int i, String newtext)
|
|
{
|
|
if (i >= SRL_INDEX && i <= SRL_INDEX+2)
|
|
{
|
|
mResTexts[i-SRL_INDEX] = newtext;
|
|
if (mResTexts[0].Length() == 0) mMaxValid = -1;
|
|
else if (mResTexts[1].Length() == 0) mMaxValid = 0;
|
|
else if (mResTexts[2].Length() == 0) mMaxValid = 1;
|
|
else mMaxValid = 2;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
override bool, String GetString(int i)
|
|
{
|
|
if (i >= SRL_INDEX && i <= SRL_INDEX+2)
|
|
{
|
|
return true, mResTexts[i-SRL_INDEX];
|
|
}
|
|
return false, "";
|
|
}
|
|
|
|
override bool MenuEvent (int mkey, bool fromcontroller)
|
|
{
|
|
if (mkey == Menu.MKEY_Left)
|
|
{
|
|
if (--mSelection < 0) mSelection = mMaxValid;
|
|
Menu.MenuSound ("menu/cursor");
|
|
return true;
|
|
}
|
|
else if (mkey == Menu.MKEY_Right)
|
|
{
|
|
if (++mSelection > mMaxValid) mSelection = 0;
|
|
Menu.MenuSound ("menu/cursor");
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return Super.MenuEvent(mkey, fromcontroller);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
override bool MouseEvent(int type, int x, int y)
|
|
{
|
|
int colwidth = screen.GetWidth() / 3;
|
|
mSelection = x / colwidth;
|
|
return Super.MouseEvent(type, x, y);
|
|
}
|
|
|
|
override bool Activate()
|
|
{
|
|
Menu.MenuSound("menu/choose");
|
|
Menu.SetVideoMode();
|
|
return true;
|
|
}
|
|
|
|
override int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected)
|
|
{
|
|
int colwidth = screen.GetWidth() / 3;
|
|
int col;
|
|
|
|
for (int x = 0; x < 3; x++)
|
|
{
|
|
if (selected && mSelection == x)
|
|
col = OptionMenuSettings.mFontColorSelection;
|
|
else if (x == mHighlight)
|
|
col = OptionMenuSettings.mFontColorHighlight;
|
|
else
|
|
col = OptionMenuSettings.mFontColorValue;
|
|
|
|
screen.DrawText (SmallFont, col, colwidth * x + 20 * CleanXfac_1, y, mResTexts[x], DTA_CleanNoMove_1, true);
|
|
}
|
|
return colwidth * mSelection + 20 * CleanXfac_1 - CursorSpace();
|
|
}
|
|
|
|
override bool Selectable()
|
|
{
|
|
return mMaxValid >= 0;
|
|
}
|
|
|
|
override void Ticker()
|
|
{
|
|
if (Selectable() && mSelection > mMaxValid)
|
|
{
|
|
mSelection = mMaxValid;
|
|
}
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
//
|
|
// [TP] OptionMenuFieldBase
|
|
//
|
|
// Base class for input fields
|
|
//
|
|
//=============================================================================
|
|
|
|
class OptionMenuFieldBase : OptionMenuItem
|
|
{
|
|
void Init (String label, Name command, CVar graycheck = null)
|
|
{
|
|
Super.Init(label, command);
|
|
mCVar = CVar.FindCVar(mAction);
|
|
mGrayCheck = graycheck;
|
|
}
|
|
|
|
String GetCVarString()
|
|
{
|
|
if (mCVar == null)
|
|
return "";
|
|
|
|
return mCVar.GetString();
|
|
}
|
|
|
|
virtual String Represent()
|
|
{
|
|
return GetCVarString();
|
|
}
|
|
|
|
override int Draw (OptionMenuDescriptor d, int y, int indent, bool selected)
|
|
{
|
|
bool grayed = mGrayCheck != null && !mGrayCheck.GetInt();
|
|
drawLabel(indent, y, selected ? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor, grayed);
|
|
int overlay = grayed? Color(96, 48, 0, 0) : 0;
|
|
|
|
screen.DrawText(SmallFont, OptionMenuSettings.mFontColorValue, indent + CursorSpace(), y, Represent(), DTA_CleanNoMove_1, true, DTA_ColorOverlay, overlay);
|
|
return indent;
|
|
}
|
|
|
|
override bool, String GetString (int i)
|
|
{
|
|
if (i == 0)
|
|
{
|
|
return true, GetCVarString();
|
|
}
|
|
return false, "";
|
|
}
|
|
|
|
override bool SetString (int i, String s)
|
|
{
|
|
if (i == 0)
|
|
{
|
|
if (mCVar) mCVar.SetString(s);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
CVar mCVar;
|
|
CVar mGrayCheck;
|
|
}
|
|
|
|
//=============================================================================
|
|
//
|
|
// [TP] OptionMenuTextField
|
|
//
|
|
// A text input field widget, for use with string CVars.
|
|
//
|
|
//=============================================================================
|
|
|
|
class OptionMenuItemTextField : OptionMenuFieldBase
|
|
{
|
|
TextEnterMenu mEnter;
|
|
|
|
OptionMenuItemTextField Init (String label, Name command, CVar graycheck = null)
|
|
{
|
|
Super.Init(label, command, graycheck);
|
|
mEnter = null;
|
|
return self;
|
|
}
|
|
|
|
override String Represent()
|
|
{
|
|
if (mEnter) return mEnter.GetText() .. SmallFont.GetCursor();
|
|
else return GetCVarString();
|
|
}
|
|
|
|
override int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected)
|
|
{
|
|
if (mEnter)
|
|
{
|
|
// reposition the text so that the cursor is visible when in entering mode.
|
|
String text = Represent();
|
|
int tlen = SmallFont.StringWidth(text) * CleanXfac_1;
|
|
int newindent = screen.GetWidth() - tlen - CursorSpace();
|
|
if (newindent < indent) indent = newindent;
|
|
}
|
|
return Super.Draw(desc, y, indent, selected);
|
|
}
|
|
|
|
override bool MenuEvent (int mkey, bool fromcontroller)
|
|
{
|
|
if (mkey == Menu.MKEY_Enter)
|
|
{
|
|
Menu.MenuSound("menu/choose");
|
|
mEnter = TextEnterMenu.Open(Menu.GetCurrentMenu(), GetCVarString(), -1, 2, fromcontroller);
|
|
return true;
|
|
}
|
|
else if (mkey == Menu.MKEY_Input)
|
|
{
|
|
if (mCVar) mCVar.SetString(mEnter.GetText());
|
|
mEnter = null;
|
|
return true;
|
|
}
|
|
else if (mkey == Menu.MKEY_Abort)
|
|
{
|
|
mEnter = null;
|
|
return true;
|
|
}
|
|
|
|
return Super.MenuEvent(mkey, fromcontroller);
|
|
}
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
//
|
|
// [TP] FOptionMenuNumberField
|
|
//
|
|
// A numeric input field widget, for use with number CVars where sliders are inappropriate (i.e.
|
|
// where the user is interested in the exact value specifically)
|
|
//
|
|
//=============================================================================
|
|
|
|
class OptionMenuItemNumberField : OptionMenuFieldBase
|
|
{
|
|
OptionMenuItemNumberField Init (String label, Name command, float minimum = 0, float maximum = 100, float step = 1, CVar graycheck = null)
|
|
{
|
|
Super.Init(label, command, graycheck);
|
|
mMinimum = min(minimum, maximum);
|
|
mMaximum = max(minimum, maximum);
|
|
mStep = max(1, step);
|
|
return self;
|
|
}
|
|
|
|
override String Represent()
|
|
{
|
|
if (mCVar == null) return "";
|
|
return String.format("%.3f", mCVar.GetFloat());
|
|
}
|
|
|
|
|
|
override bool MenuEvent (int mkey, bool fromcontroller)
|
|
{
|
|
if (mCVar)
|
|
{
|
|
float value = mCVar.GetFloat();
|
|
|
|
if (mkey == Menu.MKEY_Left)
|
|
{
|
|
value -= mStep;
|
|
if (value < mMinimum) value = mMaximum;
|
|
}
|
|
else if (mkey == Menu.MKEY_Right || mkey == Menu.MKEY_Enter)
|
|
{
|
|
value += mStep;
|
|
if (value > mMaximum) value = mMinimum;
|
|
}
|
|
else
|
|
return Super.MenuEvent(mkey, fromcontroller);
|
|
|
|
mCVar.SetFloat(value);
|
|
Menu.MenuSound("menu/change");
|
|
}
|
|
else return Super.MenuEvent(mkey, fromcontroller);
|
|
|
|
return true;
|
|
}
|
|
|
|
float mMinimum;
|
|
float mMaximum;
|
|
float mStep;
|
|
}
|
|
|