gzdoom-gles/wadsrc/static/zscript/ui/menu/optionmenuitems.zs
Christoph Oelckers 3a23cc69d6 - since we already got lots of CVAR descriptions from the menu's content, let's use that as CVAR description if none is explicitly provided.
This also necessitated localization support for CVAR descriptions because menu content is multi-language.
2020-06-08 23:37:22 +02:00

1262 lines
31 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 drawText(int x, int y, int color, String text, bool grayed = false)
{
Menu.DrawOptionText(x, y, color, text, grayed);
}
protected int drawLabel(int indent, int y, int color, bool grayed = false)
{
String label = Stringtable.Localize(mLabel);
int x;
int w = Menu.OptionWidth(label) * CleanXfac_1;
if (!mCentered) x = indent - w;
else x = (screen.GetWidth() - w) / 2;
Menu.DrawOptionText(x, y, color, label, grayed);
return x;
}
protected void drawValue(int indent, int y, int color, String text, bool grayed = false)
{
Menu.DrawOptionText(indent + CursorSpace(), y, color, text, grayed);
}
int CursorSpace()
{
return (14 * CleanXfac_1);
}
override bool Selectable()
{
return true;
}
override int GetIndent()
{
if (mCentered) return 0;
if (screen.GetWidth() < 640) return screen.GetWidth() / 2;
return Menu.OptionWidth(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, bool centered = false)
{
Super.init(label, command, centered);
mParam = param;
return self;
}
override int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected)
{
int x = drawLabel(indent, y, selected? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColorMore);
if (mCentered)
{
return x - 16*CleanXfac_1;
}
return indent;
}
override bool Activate()
{
Menu.MenuSound("menu/choose");
Menu.SetMenu(mAction, mParam);
return true;
}
}
//=============================================================================
//
// opens a submenu, command is a submenu name
//
//=============================================================================
class OptionMenuItemLabeledSubmenu : OptionMenuItemSubmenu
{
CVar mLabelCVar;
OptionMenuItemSubmenu Init(String label, CVar labelcvar, Name command, int param = 0)
{
Super.init(label, command, false);
mLabelCVar = labelcvar;
return self;
}
override int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected)
{
drawLabel(indent, y, selected? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor);
String text = mLabelCVar.GetString();
if (text.Length() == 0) text = Stringtable.Localize("$notset");
drawValue(indent, y, OptionMenuSettings.mFontColorValue, text);
return indent;
}
}
//=============================================================================
//
// Executes a CCMD, command is a CCMD name
//
//=============================================================================
class OptionMenuItemCommand : OptionMenuItemSubmenu
{
private String ccmd; // do not allow access to this from the outside.
bool mCloseOnSelect;
private bool mUnsafe;
OptionMenuItemCommand Init(String label, Name command, bool centered = false, bool closeonselect = false)
{
Super.Init(label, command, 0, centered);
ccmd = command;
mCloseOnSelect = closeonselect;
mUnsafe = true;
return self;
}
private native static void DoCommand(String cmd, bool unsafe); // 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.
if (GetClass() != "OptionMenuItemSafeCommand")
{
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.GetItem(mAction) != self) return false;
}
else mUnsafe = false;
Menu.MenuSound("menu/choose");
DoCommand(ccmd, mUnsafe);
if (mCloseOnSelect)
{
let curmenu = Menu.GetCurrentMenu();
if (curmenu != null) curmenu.Close();
}
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)
{
if (mCenter)
{
indent = (screen.GetWidth() / 2);
}
drawLabel(indent, y, selected? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor, isGrayed());
int Selection = GetSelection();
String text = StringTable.Localize(OptionValues.GetText(mValues, Selection));
if (text.Length() == 0) text = "Unknown";
drawValue(indent, y, OptionMenuSettings.mFontColorValue, text, isGrayed());
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;
}
virtual bool isGrayed()
{
return mGrayCheck != null && !mGrayCheck.GetInt();
}
override bool Selectable()
{
return !isGrayed();
}
}
//=============================================================================
//
// Change a CVAR, command is the CVAR name
//
//=============================================================================
class OptionMenuItemOption : OptionMenuItemOptionBase
{
CVar mCVar;
private static native void SetCVarDescription(CVar cv, String label);
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);
if (mCVar) SetCVarDescription(mCVar, label);
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 OnInputEvent(InputEvent ev)
{
// This menu checks raw keys, not GUI keys because it needs the raw codes for binding.
if (ev.type == InputEvent.Type_KeyDown)
{
mOwner.SendKey(ev.KeyScan);
menuactive = Menu.On;
SetMenuMessage(0);
Close();
mParentMenu.MenuEvent((ev.KeyScan == 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)
{
drawValue(indent, y, Font.CR_WHITE, description);
}
else
{
drawValue(indent, y, Font.CR_BLACK, "---");
}
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 = Menu.OptionWidth(txt) * CleanXfac_1;
int x = (screen.GetWidth() - w) / 2;
drawText(x, y, mColor, txt);
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, Name command = 'none')
{
Super.Init(label, command);
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 DrawSliderElement (int color, int x, int y, String str)
{
screen.DrawText (ConFont, color, x, y, str, DTA_CellX, 16 * CleanXfac_1, DTA_CellY, 16 * CleanYfac_1);
}
protected 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*16 + 4) * CleanXfac_1; // length of slider. This uses the old ConFont and
int cy = y + CleanYFac;
range = max - min;
double ccur = clamp(cur, min, max) - min;
if (fracdigits >= 0)
{
textbuf = String.format(formater, max);
maxlen = Menu.OptionWidth(textbuf) * CleanXfac_1;
}
mSliderShort = right + maxlen > screen.GetWidth();
if (!mSliderShort)
{
DrawSliderElement(Font.CR_WHITE, x, cy, "\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12");
DrawSliderElement(Font.FindFontColor(gameinfo.mSliderColor), x + int((5 + ((ccur * 78) / range)) * 2 * CleanXfac_1), cy, "\x13");
}
else
{
// On 320x200 we need a shorter slider
DrawSliderElement(Font.CR_WHITE, x, cy, "\x10\x11\x11\x11\x11\x11\x12");
DrawSliderElement(Font.FindFontColor(gameinfo.mSliderColor), x + int((5 + ((ccur * 38) / range)) * 2 * CleanXfac_1), cy, "\x13");
right -= 5*8*CleanXfac;
}
if (fracdigits >= 0 && right + maxlen <= screen.GetWidth())
{
textbuf = String.format(formater, cur);
drawText(right, y, Font.CR_DARKGRAY, textbuf);
}
}
//=============================================================================
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+16*CleanXfac_1;
int slide_right = slide_left + (10*16*CleanXfac_1 >> mSliderShort); // 10 char cells with 16 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, command);
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;
}
}
//=============================================================================
//
// [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);
drawValue(indent, y, OptionMenuSettings.mFontColorValue, Represent(), grayed);
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;
}
override bool Selectable()
{
return mGrayCheck == null || mGrayCheck.GetInt() != 0;
}
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() .. Menu.OptionFont().GetCursor();
else
{
bool b;
String s;
[b, s] = GetString(0);
return s;
}
}
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 = Menu.OptionWidth(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)
{
bool b;
String s;
[b, s] = GetString(0);
Menu.MenuSound("menu/choose");
mEnter = TextEnterMenu.OpenTextEnter(Menu.GetCurrentMenu(), Menu.OptionFont(), s, -1, fromcontroller);
mEnter.ActivateMenu();
return true;
}
else if (mkey == Menu.MKEY_Input)
{
SetString(0, 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;
}
//=============================================================================
//
// A special slider that displays plain text for special settings related
// to scaling.
//
//=============================================================================
class OptionMenuItemScaleSlider : OptionMenuItemSlider
{
String TextZero;
String TextNegOne;
int mClickVal;
OptionMenuItemScaleSlider Init(String label, Name command, double min, double max, double step, String zero, String negone = "")
{
Super.Init(label, command, min, max, step, 0);
mCVar =CVar.FindCVar(command);
TextZero = zero;
TextNEgOne = negone;
mClickVal = -10;
return self;
}
//=============================================================================
override int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected)
{
drawLabel(indent, y, selected? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor);
int Selection = int(GetSliderValue());
if ((Selection == 0 || Selection == -1) && mClickVal <= 0)
{
String text = Selection == 0? TextZero : Selection == -1? TextNegOne : "";
drawValue(indent, y, OptionMenuSettings.mFontColorValue, text);
}
else
{
mDrawX = indent + CursorSpace();
DrawSlider (mDrawX, y, mMin, mMax, GetSliderValue(), mShowValue, indent);
}
return indent;
}
override bool MouseEvent(int type, int x, int y)
{
int value = int(GetSliderValue());
switch (type)
{
case Menu.MOUSE_Click:
mClickVal = value;
if (value <= 0) return false;
return Super.MouseEvent(type, x, y);
case Menu.MOUSE_Move:
if (mClickVal <= 0) return false;
return Super.MouseEvent(type, x, y);
case Menu.MOUSE_Release:
if (mClickVal <= 0)
{
mClickVal = -10;
SetSliderValue(value + 1);
return true;
}
mClickVal = -10;
return Super.MouseEvent(type, x, y);
}
return false;
}
}
//=============================================================================
//
// Placeholder classes for overhauled video mode menu. Do not use!
// Their sole purpose is to support mods with full copy of embedded MENUDEF
//
//=============================================================================
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)
{
return self;
}
override bool Selectable()
{
return false;
}
}
class VideoModeMenu : OptionMenu
{
static bool SetSelectedSize()
{
return false;
}
}