- added GZDoom's menu script code.

This commit is contained in:
Christoph Oelckers 2020-10-04 18:59:51 +02:00
parent 82612a1330
commit 0b9c6fe559
19 changed files with 5664 additions and 2 deletions

View file

@ -810,7 +810,7 @@ set (PCH_SOURCES
common/audio/sound/oalsound.cpp
common/audio/sound/s_environment.cpp
common/audio/sound/s_sound.cpp
#common/audio/sound/s_reverbedit.cpp
common/audio/sound/s_reverbedit.cpp
common/audio/music/music_midi_base.cpp
common/audio/music/music.cpp
common/audio/music/i_music.cpp

View file

@ -4,4 +4,18 @@ version "4.3"
#include "zscript/constants.zs"
#include "zscript/events.zs"
#include "zscript/dictionary.zs"
#include "zscript/gamescreen.zs"
#include "zscript/gamescreen.zs"
#include "zscript/ui/menu/colorpickermenu.zs"
#include "zscript/ui/menu/joystickmenu.zs"
#include "zscript/ui/menu/listmenu.zs"
#include "zscript/ui/menu/listmenuitems.zs"
#include "zscript/ui/menu/loadsavemenu.zs"
#include "zscript/ui/menu/menu.zs"
#include "zscript/ui/menu/menuitembase.zs"
#include "zscript/ui/menu/messagebox.zs"
#include "zscript/ui/menu/optionmenu.zs"
#include "zscript/ui/menu/optionmenuitems.zs"
#include "zscript/ui/menu/readthis.zs"
#include "zscript/ui/menu/reverbedit.zs"
#include "zscript/ui/menu/textentermenu.zs"

View file

@ -0,0 +1,355 @@
/*
** colorpickermenu.txt
** The color picker menu
**
**---------------------------------------------------------------------------
** 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.
**---------------------------------------------------------------------------
**
*/
//=============================================================================
//
// This is only used by the color picker
//
//=============================================================================
class OptionMenuSliderVar : OptionMenuSliderBase
{
int mIndex;
OptionMenuSliderVar Init(String label, int index, double min, double max, double step, int showval)
{
Super.Init(label, min, max, step, showval);
mIndex = index;
return self;
}
override double GetSliderValue()
{
return ColorpickerMenu(Menu.GetCurrentMenu()).GetColor(mIndex);
}
override void SetSliderValue(double val)
{
ColorpickerMenu(Menu.GetCurrentMenu()).setColor(mIndex, val);
}
}
class ColorpickerMenu : OptionMenu
{
float mRed;
float mGreen;
float mBlue;
int mGridPosX;
int mGridPosY;
int mStartItem;
CVar mCVar;
double GetColor(int index)
{
double v = index == 0? mRed : index == 1? mGreen : mBlue;
return v;
}
void SetColor(int index, double val)
{
if (index == 0) mRed = val;
else if (index == 1) mGreen = val;
else mBlue = val;
}
//=============================================================================
//
//
//
//=============================================================================
void Init(Menu parent, String name, OptionMenuDescriptor desc, CVar cv)
{
Super.Init(parent, desc);
mStartItem = mDesc.mItems.Size();
mCVar = cv;
ResetColor();
mGridPosX = 0;
mGridPosY = 0;
// This menu uses some features that are hard to implement in an external control lump
// so it creates its own list of menu items.
mDesc.mItems.Resize(mStartItem+8);
mDesc.mItems[mStartItem+0] = new ("OptionMenuItemStaticText").Init(name, false);
mDesc.mItems[mStartItem+1] = new ("OptionMenuItemStaticText").Init(" ", false);
mDesc.mItems[mStartItem+2] = new ("OptionMenuSliderVar").Init("$TXT_COLOR_RED", 0, 0, 255, 15, 0);
mDesc.mItems[mStartItem+3] = new ("OptionMenuSliderVar").Init("$TXT_COLOR_GREEN", 1, 0, 255, 15, 0);
mDesc.mItems[mStartItem+4] = new ("OptionMenuSliderVar").Init("$TXT_COLOR_BLUE", 2, 0, 255, 15, 0);
mDesc.mItems[mStartItem+5] = new ("OptionMenuItemStaticText").Init(" ", false);
mDesc.mItems[mStartItem+6] = new ("OptionMenuItemCommand").Init("$TXT_UNDOCHANGES", "undocolorpic");
mDesc.mItems[mStartItem+7] = new ("OptionMenuItemStaticText").Init(" ", false);
mDesc.mSelectedItem = mStartItem + 2;
mDesc.mIndent = 0;
mDesc.CalcIndent();
}
//=============================================================================
//
//
//
//=============================================================================
override bool MenuEvent (int mkey, bool fromcontroller)
{
switch (mkey)
{
case MKEY_Down:
if (mDesc.mSelectedItem == mStartItem+6) // last valid item
{
MenuSound ("menu/cursor");
mGridPosY = 0;
// let it point to the last static item so that the super class code still has a valid item
mDesc.mSelectedItem = mStartItem+7;
return true;
}
else if (mDesc.mSelectedItem == mStartItem+7)
{
if (mGridPosY < 15)
{
MenuSound ("menu/cursor");
mGridPosY++;
}
return true;
}
break;
case MKEY_Up:
if (mDesc.mSelectedItem == mStartItem+7)
{
if (mGridPosY > 0)
{
MenuSound ("menu/cursor");
mGridPosY--;
}
else
{
MenuSound ("menu/cursor");
mDesc.mSelectedItem = mStartItem+6;
}
return true;
}
break;
case MKEY_Left:
if (mDesc.mSelectedItem == mStartItem+7)
{
MenuSound ("menu/cursor");
if (--mGridPosX < 0) mGridPosX = 15;
return true;
}
break;
case MKEY_Right:
if (mDesc.mSelectedItem == mStartItem+7)
{
MenuSound ("menu/cursor");
if (++mGridPosX > 15) mGridPosX = 0;
return true;
}
break;
case MKEY_Enter:
if (mDesc.mSelectedItem == mStartItem+7)
{
// Choose selected palette entry
int index = mGridPosX + mGridPosY * 16;
color col = Screen.PaletteColor(index);
mRed = col.r;
mGreen = col.g;
mBlue = col.b;
MenuSound ("menu/choose");
return true;
}
break;
}
if (mDesc.mSelectedItem >= 0 && mDesc.mSelectedItem < mStartItem+7)
{
if (mDesc.mItems[mDesc.mSelectedItem].MenuEvent(mkey, fromcontroller)) return true;
}
return Super.MenuEvent(mkey, fromcontroller);
}
//=============================================================================
//
//
//
//=============================================================================
override bool MouseEvent(int type, int mx, int my)
{
int olditem = mDesc.mSelectedItem;
bool res = Super.MouseEvent(type, mx, my);
if (mDesc.mSelectedItem == -1 || mDesc.mSelectedItem == mStartItem+7)
{
int y = (-mDesc.mPosition + BigFont.GetHeight() + mDesc.mItems.Size() * OptionMenuSettings.mLinespacing) * CleanYfac_1;
int h = (screen.GetHeight() - y) / 16;
int fh = OptionMenuSettings.mLinespacing * CleanYfac_1;
int w = fh;
int yy = y + 2 * CleanYfac_1;
int indent = (screen.GetWidth() / 2);
if (h > fh) h = fh;
else if (h < 4) return res; // no space to draw it.
int box_y = y - 2 * CleanYfac_1;
int box_x = indent - 16*w;
if (mx >= box_x && mx < box_x + 16*w && my >= box_y && my < box_y + 16*h)
{
int cell_x = (mx - box_x) / w;
int cell_y = (my - box_y) / h;
if (olditem != mStartItem+7 || cell_x != mGridPosX || cell_y != mGridPosY)
{
mGridPosX = cell_x;
mGridPosY = cell_y;
}
mDesc.mSelectedItem = mStartItem+7;
if (type == MOUSE_Release)
{
MenuEvent(MKEY_Enter, true);
if (m_use_mouse == 2) mDesc.mSelectedItem = -1;
}
res = true;
}
}
return res;
}
//=============================================================================
//
//
//
//=============================================================================
override void Drawer()
{
Super.Drawer();
if (mCVar == null) return;
int y = (-mDesc.mPosition + BigFont.GetHeight() + mDesc.mItems.Size() * OptionMenuSettings.mLinespacing) * CleanYfac_1;
int fh = OptionMenuSettings.mLinespacing * CleanYfac_1;
int h = (screen.GetHeight() - y) / 16;
int w = fh;
int yy = y;
if (h > fh) h = fh;
else if (h < 4) return; // no space to draw it.
int indent = (screen.GetWidth() / 2);
int p = 0;
for(int i = 0; i < 16; i++)
{
int box_x, box_y;
int x1;
box_y = y - 2 * CleanYfac_1;
box_x = indent - 16*w;
for (x1 = 0; x1 < 16; ++x1)
{
screen.Clear (box_x, box_y, box_x + w, box_y + h, 0, p);
if ((mDesc.mSelectedItem == mStartItem+7) &&
(/*p == CurrColorIndex ||*/ (i == mGridPosY && x1 == mGridPosX)))
{
int r, g, b;
Color col;
double blinky;
if (i == mGridPosY && x1 == mGridPosX)
{
r = 255; g = 128; b = 0;
}
else
{
r = 200; g = 200; b = 255;
}
// Make sure the cursors stand out against similar colors
// by pulsing them.
blinky = abs(sin(MSTime()/1000.0)) * 0.5 + 0.5;
col = Color(255, int(r*blinky), int(g*blinky), int(b*blinky));
screen.Clear (box_x, box_y, box_x + w, box_y + 1, col);
screen.Clear (box_x, box_y + h-1, box_x + w, box_y + h, col);
screen.Clear (box_x, box_y, box_x + 1, box_y + h, col);
screen.Clear (box_x + w - 1, box_y, box_x + w, box_y + h, col);
}
box_x += w;
p++;
}
y += h;
}
y = yy;
color newColor = Color(255, int(mRed), int(mGreen), int(mBlue));
color oldColor = mCVar.GetInt() | 0xFF000000;
int x = screen.GetWidth()*2/3;
screen.Clear (x, y, x + 48*CleanXfac_1, y + 48*CleanYfac_1, oldColor);
screen.Clear (x + 48*CleanXfac_1, y, x + 48*2*CleanXfac_1, y + 48*CleanYfac_1, newColor);
y += 49*CleanYfac_1;
screen.DrawText (SmallFont, Font.CR_GRAY, x+(48-SmallFont.StringWidth("---->")/2)*CleanXfac_1, y, "---->", DTA_CleanNoMove_1, true);
}
override void OnDestroy()
{
if (mStartItem >= 0)
{
mDesc.mItems.Resize(mStartItem);
if (mCVar != null)
{
mCVar.SetInt(Color(int(mRed), int(mGreen), int(mBlue)));
}
mStartItem = -1;
}
}
override void ResetColor()
{
if (mCVar != null)
{
Color clr = Color(mCVar.GetInt());
mRed = clr.r;
mGreen = clr.g;
mBlue = clr.b;
}
}
}

View file

@ -0,0 +1,312 @@
/*
** joystickmenu.cpp
** The joystick configuration 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 OptionMenuSliderJoySensitivity : OptionMenuSliderBase
{
JoystickConfig mJoy;
OptionMenuSliderJoySensitivity Init(String label, double min, double max, double step, int showval, JoystickConfig joy)
{
Super.Init(label, min, max, step, showval);
mJoy = joy;
return self;
}
override double GetSliderValue()
{
return mJoy.GetSensitivity();
}
override void SetSliderValue(double val)
{
mJoy.SetSensitivity(val);
}
}
//=============================================================================
//
//
//
//=============================================================================
class OptionMenuSliderJoyScale : OptionMenuSliderBase
{
int mAxis;
int mNeg;
JoystickConfig mJoy;
OptionMenuSliderJoyScale Init(String label, int axis, double min, double max, double step, int showval, JoystickConfig joy)
{
Super.Init(label, min, max, step, showval);
mAxis = axis;
mNeg = 1;
mJoy = joy;
return self;
}
override double GetSliderValue()
{
double d = mJoy.GetAxisScale(mAxis);
mNeg = d < 0? -1:1;
return d;
}
override void SetSliderValue(double val)
{
mJoy.SetAxisScale(mAxis, val * mNeg);
}
}
//=============================================================================
//
//
//
//=============================================================================
class OptionMenuSliderJoyDeadZone : OptionMenuSliderBase
{
int mAxis;
int mNeg;
JoystickConfig mJoy;
OptionMenuSliderJoyDeadZone Init(String label, int axis, double min, double max, double step, int showval, JoystickConfig joy)
{
Super.Init(label, min, max, step, showval);
mAxis = axis;
mNeg = 1;
mJoy = joy;
return self;
}
override double GetSliderValue()
{
double d = mJoy.GetAxisDeadZone(mAxis);
mNeg = d < 0? -1:1;
return d;
}
override void SetSliderValue(double val)
{
mJoy.SetAxisDeadZone(mAxis, val * mNeg);
}
}
//=============================================================================
//
//
//
//=============================================================================
class OptionMenuItemJoyMap : OptionMenuItemOptionBase
{
int mAxis;
JoystickConfig mJoy;
OptionMenuItemJoyMap Init(String label, int axis, Name values, int center, JoystickConfig joy)
{
Super.Init(label, 'none', values, null, center);
mAxis = axis;
mJoy = joy;
return self;
}
override int GetSelection()
{
double f = mJoy.GetAxisMap(mAxis);
let opt = OptionValues.GetCount(mValues);
if (opt > 0)
{
// Map from joystick axis to menu selection.
for(int i = 0; i < opt; i++)
{
if (f ~== OptionValues.GetValue(mValues, i))
{
return i;
}
}
}
return -1;
}
override void SetSelection(int selection)
{
let opt = OptionValues.GetCount(mValues);
// Map from menu selection to joystick axis.
if (opt == 0 || selection >= opt)
{
selection = JoystickConfig.JOYAXIS_None;
}
else
{
selection = int(OptionValues.GetValue(mValues, selection));
}
mJoy.SetAxisMap(mAxis, selection);
}
}
//=============================================================================
//
//
//
//=============================================================================
class OptionMenuItemInverter : OptionMenuItemOptionBase
{
int mAxis;
JoystickConfig mJoy;
OptionMenuItemInverter Init(String label, int axis, int center, JoystickConfig joy)
{
Super.Init(label, "none", "YesNo", NULL, center);
mAxis = axis;
mJoy = joy;
return self;
}
override int GetSelection()
{
float f = mJoy.GetAxisScale(mAxis);
return f > 0? 0:1;
}
override void SetSelection(int Selection)
{
let f = abs(mJoy.GetAxisScale(mAxis));
if (Selection) f*=-1;
mJoy.SetAxisScale(mAxis, f);
}
}
//=============================================================================
//
// Executes a CCMD, action is a CCMD name
//
//=============================================================================
class OptionMenuItemJoyConfigMenu : OptionMenuItemSubmenu
{
JoystickConfig mJoy;
OptionMenuItemJoyConfigMenu Init(String label, JoystickConfig joy)
{
Super.Init(label, "JoystickConfigMenu");
mJoy = joy;
return self;
}
override bool Activate()
{
let desc = OptionMenuDescriptor(MenuDescriptor.GetDescriptor('JoystickConfigMenu'));
if (desc != NULL)
{
SetController(OptionMenuDescriptor(desc), mJoy);
}
let res = Super.Activate();
let joymenu = JoystickConfigMenu(Menu.GetCurrentMenu());
if (res && joymenu != null) joymenu.mJoy = mJoy;
return res;
}
static void SetController(OptionMenuDescriptor opt, JoystickConfig joy)
{
OptionMenuItem it;
opt.mItems.Clear();
if (joy == NULL)
{
opt.mTitle = "$JOYMNU_CONFIG";
it = new("OptionMenuItemStaticText").Init("$JOYMNU_INVALID", false);
opt.mItems.Push(it);
}
else
{
it = new("OptionMenuItemStaticText").Init(joy.GetName(), false);
it = new("OptionMenuItemStaticText").Init("", false);
it = new("OptionMenuSliderJoySensitivity").Init("$JOYMNU_OVRSENS", 0, 2, 0.1, 3, joy);
opt.mItems.Push(it);
it = new("OptionMenuItemStaticText").Init(" ", false);
opt.mItems.Push(it);
if (joy.GetNumAxes() > 0)
{
it = new("OptionMenuItemStaticText").Init("$JOYMNU_AXIS", true);
opt.mItems.Push(it);
for (int i = 0; i < joy.GetNumAxes(); ++i)
{
it = new("OptionMenuItemStaticText").Init(" ", false);
opt.mItems.Push(it);
it = new("OptionMenuItemJoyMap").Init(joy.GetAxisName(i), i, "JoyAxisMapNames", false, joy);
opt.mItems.Push(it);
it = new("OptionMenuSliderJoyScale").Init("$JOYMNU_OVRSENS", i, 0, 4, 0.1, 3, joy);
opt.mItems.Push(it);
it = new("OptionMenuItemInverter").Init("$JOYMNU_INVERT", i, false, joy);
opt.mItems.Push(it);
it = new("OptionMenuSliderJoyDeadZone").Init("$JOYMNU_DEADZONE", i, 0, 0.9, 0.05, 3, joy);
opt.mItems.Push(it);
}
}
else
{
it = new("OptionMenuItemStaticText").Init("$JOYMNU_NOAXES", false);
opt.mItems.Push(it);
}
}
opt.mScrollPos = 0;
opt.mSelectedItem = -1;
opt.mIndent = 0;
opt.mPosition = -25;
opt.CalcIndent();
}
}
//=============================================================================
//
//
//
//=============================================================================
class JoystickConfigMenu : OptionMenu
{
JoystickConfig mJoy;
}

View file

@ -0,0 +1,279 @@
class ListMenuDescriptor : MenuDescriptor native
{
enum EScale
{
CleanScale = -1,
OptCleanScale = -2
};
native Array<ListMenuItem> mItems;
native int mSelectedItem;
native double mSelectOfsX;
native double mSelectOfsY;
native TextureID mSelector;
native int mDisplayTop;
native double mXpos, mYpos;
native int mWLeft, mWRight;
native int mLinespacing; // needs to be stored for dynamically created menus
native int mAutoselect; // this can only be set by internal menu creation functions
native Font mFont;
native int mFontColor;
native int mFontColor2;
native bool mCenter;
native int mVirtWidth, mVirtHeight;
native void Reset();
int DisplayWidth()
{
if (mVirtWidth == OptCleanScale) return m_cleanscale ? CleanScale : 320;
return mVirtWidth;
}
int DisplayHeight()
{
if (mVirtWidth == OptCleanScale) return m_cleanscale ? CleanScale : 200;
return mVirtHeight;
}
}
//=============================================================================
//
// list menu class runs a menu described by a DListMenuDescriptor
//
//=============================================================================
class ListMenu : Menu
{
ListMenuDescriptor mDesc;
MenuItemBase mFocusControl;
virtual void Init(Menu parent = NULL, ListMenuDescriptor desc = NULL)
{
Super.Init(parent);
mDesc = desc;
if (desc.mCenter)
{
double center = 160;
for(int i=0; i < mDesc.mItems.Size(); i++)
{
double xpos = mDesc.mItems[i].GetX();
int width = mDesc.mItems[i].GetWidth();
double curx = mDesc.mSelectOfsX;
if (width > 0 && mDesc.mItems[i].Selectable())
{
double left = 160 - (width - curx) / 2 - curx;
if (left < center) center = left;
}
}
for(int i=0;i<mDesc.mItems.Size(); i++)
{
int width = mDesc.mItems[i].GetWidth();
if (width > 0)
{
mDesc.mItems[i].SetX(center);
}
}
}
// notify all items that the menu was just created.
for(int i=0;i<mDesc.mItems.Size(); i++)
{
mDesc.mItems[i].OnMenuCreated();
}
}
//=============================================================================
//
//
//
//=============================================================================
ListMenuItem GetItem(Name name)
{
for(int i = 0; i < mDesc.mItems.Size(); i++)
{
Name nm = mDesc.mItems[i].GetAction();
if (nm == name) return mDesc.mItems[i];
}
return NULL;
}
//=============================================================================
//
//
//
//=============================================================================
override bool OnUIEvent(UIEvent ev)
{
if (ev.Type == UIEvent.Type_KeyDown && ev.KeyChar > 0)
{
// tolower
int ch = ev.KeyChar;
ch = ch >= 65 && ch < 91 ? ch + 32 : ch;
for(int i = mDesc.mSelectedItem + 1; i < mDesc.mItems.Size(); i++)
{
if (mDesc.mitems[i].Selectable() && mDesc.mItems[i].CheckHotkey(ch))
{
mDesc.mSelectedItem = i;
MenuSound("menu/cursor");
return true;
}
}
for(int i = 0; i < mDesc.mSelectedItem; i++)
{
if (mDesc.mitems[i].Selectable() && mDesc.mItems[i].CheckHotkey(ch))
{
mDesc.mSelectedItem = i;
MenuSound("menu/cursor");
return true;
}
}
}
return Super.OnUIEvent(ev);
}
//=============================================================================
//
//
//
//=============================================================================
override bool MenuEvent (int mkey, bool fromcontroller)
{
int oldSelect = mDesc.mSelectedItem;
int startedAt = mDesc.mSelectedItem;
switch (mkey)
{
case MKEY_Up:
do
{
if (--mDesc.mSelectedItem < 0) mDesc.mSelectedItem = mDesc.mItems.Size()-1;
}
while (!mDesc.mItems[mDesc.mSelectedItem].Selectable() && mDesc.mSelectedItem != startedAt);
if (mDesc.mSelectedItem == startedAt) mDesc.mSelectedItem = oldSelect;
MenuSound("menu/cursor");
return true;
case MKEY_Down:
do
{
if (++mDesc.mSelectedItem >= mDesc.mItems.Size()) mDesc.mSelectedItem = 0;
}
while (!mDesc.mItems[mDesc.mSelectedItem].Selectable() && mDesc.mSelectedItem != startedAt);
if (mDesc.mSelectedItem == startedAt) mDesc.mSelectedItem = oldSelect;
MenuSound("menu/cursor");
return true;
case MKEY_Enter:
if (mDesc.mSelectedItem >= 0 && mDesc.mItems[mDesc.mSelectedItem].Activate())
{
MenuSound("menu/choose");
}
return true;
default:
return Super.MenuEvent(mkey, fromcontroller);
}
}
//=============================================================================
//
//
//
//=============================================================================
override bool MouseEvent(int type, int x, int y)
{
int sel = -1;
// convert x/y from screen to virtual coordinates, according to CleanX/Yfac use in DrawTexture
x = ((x - (screen.GetWidth() / 2)) / CleanXfac) + 160;
y = ((y - (screen.GetHeight() / 2)) / CleanYfac) + 100;
if (mFocusControl != NULL)
{
mFocusControl.MouseEvent(type, x, y);
return true;
}
else
{
if ((mDesc.mWLeft <= 0 || x > mDesc.mWLeft) &&
(mDesc.mWRight <= 0 || x < mDesc.mWRight))
{
for(int i=0;i<mDesc.mItems.Size(); i++)
{
if (mDesc.mItems[i].CheckCoordinate(x, y))
{
if (i != mDesc.mSelectedItem)
{
//MenuSound("menu/cursor");
}
mDesc.mSelectedItem = i;
mDesc.mItems[i].MouseEvent(type, x, y);
return true;
}
}
}
}
mDesc.mSelectedItem = -1;
return Super.MouseEvent(type, x, y);
}
//=============================================================================
//
//
//
//=============================================================================
override void Ticker ()
{
Super.Ticker();
for(int i=0;i<mDesc.mItems.Size(); i++)
{
mDesc.mItems[i].Ticker();
}
}
//=============================================================================
//
//
//
//=============================================================================
override void Drawer ()
{
for(int i=0;i<mDesc.mItems.Size(); i++)
{
if (mDesc.mItems[i].mEnabled) mDesc.mItems[i].Draw(mDesc.mSelectedItem == i, mDesc);
}
if (mDesc.mSelectedItem >= 0 && mDesc.mSelectedItem < mDesc.mItems.Size())
mDesc.mItems[mDesc.mSelectedItem].DrawSelector(mDesc.mSelectOfsX, mDesc.mSelectOfsY, mDesc.mSelector, mDesc);
Super.Drawer();
}
//=============================================================================
//
//
//
//=============================================================================
override void SetFocus(MenuItemBase fc)
{
mFocusControl = fc;
}
override bool CheckFocus(MenuItemBase fc)
{
return mFocusControl == fc;
}
override void ReleaseFocus()
{
mFocusControl = NULL;
}
}

View file

@ -0,0 +1,342 @@
/*
** listmenu.cpp
** A simple menu consisting of a list of items
**
**---------------------------------------------------------------------------
** 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 ListMenuItem : MenuItemBase
{
protected void DrawText(ListMenuDescriptor desc, Font fnt, int color, double x, double y, String text, bool ontop = false)
{
int w = desc ? desc.DisplayWidth() : ListMenuDescriptor.CleanScale;
int h = desc ? desc.DisplayHeight() : -1;
if (w == ListMenuDescriptor.CleanScale)
{
screen.DrawText(fnt, color, x, y, text, ontop? DTA_CleanTop : DTA_Clean, true);
}
else
{
screen.DrawText(fnt, color, x, y, text, DTA_VirtualWidth, w, DTA_VirtualHeight, h, DTA_FullscreenScale, FSMode_ScaleToFit43);
}
}
protected void DrawTexture(ListMenuDescriptor desc, TextureID tex, double x, double y, bool ontop = false)
{
int w = desc ? desc.DisplayWidth() : ListMenuDescriptor.CleanScale;
int h = desc ? desc.DisplayHeight() : -1;
if (w == ListMenuDescriptor.CleanScale)
{
screen.DrawTexture(tex, true, x, y, ontop ? DTA_CleanTop : DTA_Clean, true);
}
else
{
screen.DrawTexture(tex, true, x, y, DTA_VirtualWidth, w, DTA_VirtualHeight, h, DTA_FullscreenScale, FSMode_ScaleToFit43);
}
}
virtual void DrawSelector(double xofs, double yofs, TextureID tex, ListMenuDescriptor desc = null)
{
if (tex.isNull())
{
if ((Menu.MenuTime() % 8) < 6)
{
DrawText(desc, ConFont, OptionMenuSettings.mFontColorSelection, mXpos + xofs, mYpos + yofs + 8, "\xd");
}
}
else
{
DrawTexture(desc, tex, mXpos + xofs, mYpos + yofs);
}
}
// We cannot extend Drawer here because it is inherited from the parent class.
virtual void Draw(bool selected, ListMenuDescriptor desc)
{
Drawer(selected); // fall back to the legacy version, if not overridden
}
}
//=============================================================================
//
// static patch
//
//=============================================================================
class ListMenuItemStaticPatch : ListMenuItem
{
TextureID mTexture;
bool mCentered;
String mSubstitute;
Font mFont;
int mColor;
void Init(ListMenuDescriptor desc, double x, double y, TextureID patch, bool centered = false, String substitute = "")
{
Super.Init(x, y);
mTexture = patch;
mCentered = centered;
mSubstitute = substitute;
mFont = desc.mFont;
mColor = desc.mFontColor;
}
override void Draw(bool selected, ListMenuDescriptor desc)
{
if (!mTexture.Exists())
{
return;
}
double x = mXpos;
Vector2 vec = TexMan.GetScaledSize(mTexture);
if (mSubstitute == "" || TexMan.OkForLocalization(mTexture, mSubstitute))
{
if (mCentered) x -= vec.X / 2;
DrawTexture(desc, mTexture, x, abs(mYpos), mYpos < 0);
}
else
{
let font = generic_ui ? NewSmallFont : mFont;
if (mCentered) x -= font.StringWidth(mSubstitute) / 2;
DrawText(desc, font, mColor, x, abs(mYpos), mSubstitute, mYpos < 0);
}
}
}
class ListMenuItemStaticPatchCentered : ListMenuItemStaticPatch
{
void Init(ListMenuDescriptor desc, double x, double y, TextureID patch)
{
Super.Init(desc, x, y, patch, true);
}
}
//=============================================================================
//
// static text
//
//=============================================================================
class ListMenuItemStaticText : ListMenuItem
{
String mText;
Font mFont;
int mColor;
bool mCentered;
void Init(ListMenuDescriptor desc, double x, double y, String text, int color = -1)
{
Super.Init(x, y);
mText = text;
mFont = desc.mFont;
mColor = color >= 0? color : desc.mFontColor;
mCentered = false;
}
void InitDirect(double x, double y, String text, Font font, int color = Font.CR_UNTRANSLATED, bool centered = false)
{
Super.Init(x, y);
mText = text;
mFont = font;
mColor = color;
mCentered = centered;
}
override void Draw(bool selected, ListMenuDescriptor desc)
{
if (mText.Length() != 0)
{
let font = generic_ui? NewSmallFont : mFont;
String text = Stringtable.Localize(mText);
double x = mXpos;
if (mCentered) x -= font.StringWidth(text) / 2;
DrawText(desc, font, mColor, x, abs(mYpos), text, mYpos < 0);
}
}
}
class ListMenuItemStaticTextCentered : ListMenuItemStaticText
{
void Init(ListMenuDescriptor desc, double x, double y, String text, int color = -1)
{
Super.Init(desc, x, y, text, color);
mCentered = true;
}
}
//=============================================================================
//
// selectable items
//
//=============================================================================
class ListMenuItemSelectable : ListMenuItem
{
int mHotkey;
int mHeight;
int mParam;
protected void Init(double x, double y, int height, Name childmenu, int param = -1)
{
Super.Init(x, y, childmenu);
mHeight = height;
mParam = param;
mHotkey = 0;
}
override bool CheckCoordinate(int x, int y)
{
return mEnabled && y >= mYpos && y < mYpos + mHeight; // no x check here
}
override bool Selectable()
{
return mEnabled;
}
override bool CheckHotkey(int c)
{
return c > 0 && c == mHotkey;
}
override bool Activate()
{
Menu.SetMenu(mAction, mParam);
return true;
}
override bool MouseEvent(int type, int x, int y)
{
if (type == Menu.MOUSE_Release)
{
let m = Menu.GetCurrentMenu();
if (m != NULL && m.MenuEvent(Menu.MKEY_Enter, true))
{
return true;
}
}
return false;
}
override Name, int GetAction()
{
return mAction, mParam;
}
}
//=============================================================================
//
// text item
//
//=============================================================================
class ListMenuItemTextItem : ListMenuItemSelectable
{
String mText;
Font mFont;
int mColor;
int mColorSelected;
void Init(ListMenuDescriptor desc, String text, String hotkey, Name child, int param = 0)
{
Super.Init(desc.mXpos, desc.mYpos, desc.mLinespacing, child, param);
mText = text;
mFont = desc.mFont;
mColor = desc.mFontColor;
mColorSelected = desc.mFontcolor2;
mHotkey = hotkey.GetNextCodePoint(0);
}
void InitDirect(double x, double y, int height, String hotkey, String text, Font font, int color, int color2, Name child, int param = 0)
{
Super.Init(x, y, height, child, param);
mText = text;
mFont = font;
mColor = color;
mColorSelected = color2;
int pos = 0;
mHotkey = hotkey.GetNextCodePoint(0);
}
override void Draw(bool selected, ListMenuDescriptor desc)
{
let font = generic_ui ? NewSmallFont : mFont;
DrawText(desc, font, selected ? mColorSelected : mColor, mXpos, mYpos, mText);
}
override int GetWidth()
{
let font = generic_ui? NewSmallFont : mFont;
return max(1, font.StringWidth(StringTable.Localize(mText)));
}
}
//=============================================================================
//
// patch item
//
//=============================================================================
class ListMenuItemPatchItem : ListMenuItemSelectable
{
TextureID mTexture;
void Init(ListMenuDescriptor desc, TextureID patch, String hotkey, Name child, int param = 0)
{
Super.Init(desc.mXpos, desc.mYpos, desc.mLinespacing, child, param);
mHotkey = hotkey.GetNextCodePoint(0);
mTexture = patch;
}
void InitDirect(double x, double y, int height, TextureID patch, String hotkey, Name child, int param = 0)
{
Super.Init(x, y, height, child, param);
mHotkey = hotkey.GetNextCodePoint(0);
mTexture = patch;
}
override void Draw(bool selected, ListMenuDescriptor desc)
{
DrawTexture(desc, mTexture, mXpos, mYpos);
}
override int GetWidth()
{
return TexMan.GetSize(mTexture);
}
}

View file

@ -0,0 +1,644 @@
/*
** loacpp
** The load game and save game menus
**
**---------------------------------------------------------------------------
** Copyright 2001-2010 Randy Heit
** 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.
**---------------------------------------------------------------------------
**
*/
struct SaveGameNode native
{
native String SaveTitle;
native readonly String Filename;
native bool bOldVersion;
native bool bMissingWads;
native bool bNoDelete;
}
struct SavegameManager native ui
{
native int WindowSize;
native SaveGameNode quickSaveSlot;
native readonly String SaveCommentString;
native static SavegameManager GetManager();
native void ReadSaveStrings();
native void UnloadSaveData();
native int RemoveSaveSlot(int index);
native void LoadSavegame(int Selected);
native void DoSave(int Selected, String savegamestring);
native int ExtractSaveData(int index);
native void ClearSaveStuff();
native bool DrawSavePic(int x, int y, int w, int h);
deprecated("4.0") void DrawSaveComment(Font font, int cr, int x, int y, int scalefactor)
{
// Unfortunately, this was broken beyond repair so it now prints nothing.
}
native void SetFileInfo(int Selected);
native int SavegameCount();
native SaveGameNode GetSavegame(int i);
native void InsertNewSaveNode();
native bool RemoveNewSaveNode();
}
class LoadSaveMenu : ListMenu
{
SavegameManager manager;
int TopItem;
int Selected;
int savepicLeft;
int savepicTop;
int savepicWidth;
int savepicHeight;
int rowHeight;
int listboxLeft;
int listboxTop;
int listboxWidth;
int listboxRows;
int listboxHeight;
int listboxRight;
int listboxBottom;
int commentLeft;
int commentTop;
int commentWidth;
int commentHeight;
int commentRight;
int commentBottom;
int commentRows;
bool mEntering;
TextEnterMenu mInput;
double FontScale;
BrokenLines BrokenSaveComment;
//=============================================================================
//
//
//
//=============================================================================
override void Init(Menu parent, ListMenuDescriptor desc)
{
Super.Init(parent, desc);
manager = SavegameManager.GetManager();
manager.ReadSaveStrings();
savepicLeft = 10;
savepicTop = 54*CleanYfac;
savepicWidth = 216*screen.GetWidth() / 640;
savepicHeight = 135*screen.GetHeight() / 400;
FontScale = max(screen.GetHeight() / 480, 1);
rowHeight = int(max((NewConsoleFont.GetHeight() + 1) * FontScale, 1));
listboxLeft = savepicLeft + savepicWidth + 14;
listboxTop = savepicTop;
listboxWidth = screen.GetWidth() - listboxLeft - 10;
int listboxHeight1 = screen.GetHeight() - listboxTop - 10;
listboxRows = (listboxHeight1 - 1) / rowHeight;
listboxHeight = listboxRows * rowHeight + 1;
listboxRight = listboxLeft + listboxWidth;
listboxBottom = listboxTop + listboxHeight;
commentLeft = savepicLeft;
commentTop = savepicTop + savepicHeight + 16;
commentWidth = savepicWidth;
//commentHeight = (51+(screen.GetHeight()>200?10:0))*CleanYfac;
commentHeight = listboxHeight - savepicHeight - 16;
commentRight = commentLeft + commentWidth;
commentBottom = commentTop + commentHeight;
commentRows = commentHeight / rowHeight;
}
//=============================================================================
//
//
//
//=============================================================================
override void OnDestroy()
{
//manager.ClearSaveStuff ();
Super.OnDestroy();
}
//=============================================================================
//
//
//
//=============================================================================
override void Drawer ()
{
Super.Drawer();
SaveGameNode node;
int i;
int j;
bool didSeeSelected = false;
// Draw picture area
if (gameaction == ga_loadgame || gameaction == ga_loadgamehidecon || gameaction == ga_savegame)
{
return;
}
Screen.DrawFrame (savepicLeft, savepicTop, savepicWidth, savepicHeight);
if (!manager.DrawSavePic(savepicLeft, savepicTop, savepicWidth, savepicHeight))
{
screen.Clear (savepicLeft, savepicTop, savepicLeft+savepicWidth, savepicTop+savepicHeight, 0, 0);
if (manager.SavegameCount() > 0)
{
String text = (Selected == -1 || !manager.GetSavegame(Selected).bOldVersion)? Stringtable.Localize("$MNU_NOPICTURE") : Stringtable.Localize("$MNU_DIFFVERSION");
int textlen = NewSmallFont.StringWidth(text) * CleanXfac;
screen.DrawText (NewSmallFont, Font.CR_GOLD, savepicLeft+(savepicWidth-textlen)/2,
savepicTop+(savepicHeight-rowHeight)/2, text, DTA_CleanNoMove, true);
}
}
// Draw comment area
Screen.DrawFrame (commentLeft, commentTop, commentWidth, commentHeight);
screen.Clear (commentLeft, commentTop, commentRight, commentBottom, 0, 0);
int numlinestoprint = min(commentRows, BrokenSaveComment? BrokenSaveComment.Count() : 0);
for(int i = 0; i < numlinestoprint; i++)
{
screen.DrawText(NewConsoleFont, Font.CR_ORANGE, commentLeft / FontScale, (commentTop + rowHeight * i) / FontScale, BrokenSaveComment.StringAt(i),
DTA_VirtualWidthF, screen.GetWidth() / FontScale, DTA_VirtualHeightF, screen.GetHeight() / FontScale, DTA_KeepRatio, true);
}
// Draw file area
Screen.DrawFrame (listboxLeft, listboxTop, listboxWidth, listboxHeight);
screen.Clear (listboxLeft, listboxTop, listboxRight, listboxBottom, 0, 0);
if (manager.SavegameCount() == 0)
{
String text = Stringtable.Localize("$MNU_NOFILES");
int textlen = int(NewConsoleFont.StringWidth(text) * FontScale);
screen.DrawText (NewConsoleFont, Font.CR_GOLD, (listboxLeft+(listboxWidth-textlen)/2) / FontScale, (listboxTop+(listboxHeight-rowHeight)/2) / FontScale, text,
DTA_VirtualWidthF, screen.GetWidth() / FontScale, DTA_VirtualHeightF, screen.GetHeight() / FontScale, DTA_KeepRatio, true);
return;
}
j = TopItem;
for (i = 0; i < listboxRows && j < manager.SavegameCount(); i++)
{
int colr;
node = manager.GetSavegame(j);
if (node.bOldVersion)
{
colr = Font.CR_RED;
}
else if (node.bMissingWads)
{
colr = Font.CR_YELLOW;
}
else if (j == Selected)
{
colr = Font.CR_WHITE;
}
else
{
colr = Font.CR_TAN;
}
screen.SetClipRect(listboxLeft, listboxTop+rowHeight*i, listboxRight, listboxTop+rowHeight*(i+1));
if (j == Selected)
{
screen.Clear (listboxLeft, listboxTop+rowHeight*i, listboxRight, listboxTop+rowHeight*(i+1), mEntering ? Color(255,255,0,0) : Color(255,0,0,255));
didSeeSelected = true;
if (!mEntering)
{
screen.DrawText (NewConsoleFont, colr, (listboxLeft+1) / FontScale, (listboxTop+rowHeight*i + FontScale) / FontScale, node.SaveTitle,
DTA_VirtualWidthF, screen.GetWidth() / FontScale, DTA_VirtualHeightF, screen.GetHeight() / FontScale, DTA_KeepRatio, true);
}
else
{
String s = mInput.GetText() .. NewConsoleFont.GetCursor();
int length = int(NewConsoleFont.StringWidth(s) * FontScale);
int displacement = min(0, listboxWidth - 2 - length);
screen.DrawText (NewConsoleFont, Font.CR_WHITE, (listboxLeft + 1 + displacement) / FontScale, (listboxTop+rowHeight*i + FontScale) / FontScale, s,
DTA_VirtualWidthF, screen.GetWidth() / FontScale, DTA_VirtualHeightF, screen.GetHeight() / FontScale, DTA_KeepRatio, true);
}
}
else
{
screen.DrawText (NewConsoleFont, colr, (listboxLeft+1) / FontScale, (listboxTop+rowHeight*i + FontScale) / FontScale, node.SaveTitle,
DTA_VirtualWidthF, screen.GetWidth() / FontScale, DTA_VirtualHeightF, screen.GetHeight() / FontScale, DTA_KeepRatio, true);
}
screen.ClearClipRect();
j++;
}
}
void UpdateSaveComment()
{
BrokenSaveComment = NewConsoleFont.BreakLines(manager.SaveCommentString, int(commentWidth / FontScale));
}
//=============================================================================
//
//
//
//=============================================================================
override bool MenuEvent (int mkey, bool fromcontroller)
{
switch (mkey)
{
case MKEY_Up:
if (manager.SavegameCount() > 1)
{
if (Selected == -1) Selected = TopItem;
else
{
if (--Selected < 0) Selected = manager.SavegameCount()-1;
if (Selected < TopItem) TopItem = Selected;
else if (Selected >= TopItem + listboxRows) TopItem = MAX(0, Selected - listboxRows + 1);
}
manager.UnloadSaveData ();
manager.ExtractSaveData (Selected);
UpdateSaveComment();
}
return true;
case MKEY_Down:
if (manager.SavegameCount() > 1)
{
if (Selected == -1) Selected = TopItem;
else
{
if (++Selected >= manager.SavegameCount()) Selected = 0;
if (Selected < TopItem) TopItem = Selected;
else if (Selected >= TopItem + listboxRows) TopItem = MAX(0, Selected - listboxRows + 1);
}
manager.UnloadSaveData ();
manager.ExtractSaveData (Selected);
UpdateSaveComment();
}
return true;
case MKEY_PageDown:
if (manager.SavegameCount() > 1)
{
if (TopItem >= manager.SavegameCount() - listboxRows)
{
TopItem = 0;
if (Selected != -1) Selected = 0;
}
else
{
TopItem = MIN(TopItem + listboxRows, manager.SavegameCount() - listboxRows);
if (TopItem > Selected && Selected != -1) Selected = TopItem;
}
manager.UnloadSaveData ();
manager.ExtractSaveData (Selected);
UpdateSaveComment();
}
return true;
case MKEY_PageUp:
if (manager.SavegameCount() > 1)
{
if (TopItem == 0)
{
TopItem = MAX(0, manager.SavegameCount() - listboxRows);
if (Selected != -1) Selected = TopItem;
}
else
{
TopItem = MAX(TopItem - listboxRows, 0);
if (Selected >= TopItem + listboxRows) Selected = TopItem;
}
manager.UnloadSaveData ();
manager.ExtractSaveData (Selected);
UpdateSaveComment();
}
return true;
case MKEY_Enter:
return false; // This event will be handled by the subclasses
case MKEY_MBYes:
{
if (Selected < manager.SavegameCount())
{
Selected = manager.RemoveSaveSlot (Selected);
UpdateSaveComment();
}
return true;
}
default:
return Super.MenuEvent(mkey, fromcontroller);
}
}
//=============================================================================
//
//
//
//=============================================================================
override bool MouseEvent(int type, int x, int y)
{
if (x >= listboxLeft && x < listboxLeft + listboxWidth &&
y >= listboxTop && y < listboxTop + listboxHeight)
{
int lineno = (y - listboxTop) / rowHeight;
if (TopItem + lineno < manager.SavegameCount())
{
Selected = TopItem + lineno;
manager.UnloadSaveData ();
manager.ExtractSaveData (Selected);
UpdateSaveComment();
if (type == MOUSE_Release)
{
if (MenuEvent(MKEY_Enter, true))
{
return true;
}
}
}
else Selected = -1;
}
else Selected = -1;
return Super.MouseEvent(type, x, y);
}
//=============================================================================
//
//
//
//=============================================================================
override bool OnUIEvent(UIEvent ev)
{
if (ev.Type == UIEvent.Type_KeyDown)
{
if (Selected != -1 && Selected < manager.SavegameCount())
{
switch (ev.KeyChar)
{
case UIEvent.Key_F1:
manager.SetFileInfo(Selected);
UpdateSaveComment();
return true;
case UIEvent.Key_DEL:
{
String EndString;
EndString = String.Format("%s%s%s%s?\n\n%s", Stringtable.Localize("$MNU_DELETESG"), TEXTCOLOR_WHITE, manager.GetSavegame(Selected).SaveTitle, TEXTCOLOR_NORMAL, Stringtable.Localize("$PRESSYN"));
StartMessage (EndString, 0);
}
return true;
}
}
}
else if (ev.Type == UIEvent.Type_WheelUp)
{
if (TopItem > 0) TopItem--;
return true;
}
else if (ev.Type == UIEvent.Type_WheelDown)
{
if (TopItem < manager.SavegameCount() - listboxRows) TopItem++;
return true;
}
return Super.OnUIEvent(ev);
}
}
class SaveMenu : LoadSaveMenu
{
String mSaveName;
//=============================================================================
//
//
//
//=============================================================================
override void Init(Menu parent, ListMenuDescriptor desc)
{
Super.Init(parent, desc);
manager.InsertNewSaveNode();
TopItem = 0;
Selected = manager.ExtractSaveData (-1);
UpdateSaveComment();
}
//=============================================================================
//
//
//
//=============================================================================
override void OnDestroy()
{
if (manager.RemoveNewSaveNode())
{
Selected--;
}
Super.OnDestroy();
}
//=============================================================================
//
//
//
//=============================================================================
override bool MenuEvent (int mkey, bool fromcontroller)
{
if (Super.MenuEvent(mkey, fromcontroller))
{
return true;
}
if (Selected == -1)
{
return false;
}
if (mkey == MKEY_Enter)
{
String SavegameString = (Selected != 0)? manager.GetSavegame(Selected).SaveTitle : "";
mInput = TextEnterMenu.OpenTextEnter(self, Menu.OptionFont(), SavegameString, -1, fromcontroller);
mInput.ActivateMenu();
mEntering = true;
}
else if (mkey == MKEY_Input)
{
// Do not start the save here, it would cause some serious execution ordering problems.
mEntering = false;
mSaveName = mInput.GetText();
mInput = null;
}
else if (mkey == MKEY_Abort)
{
mEntering = false;
mInput = null;
}
return false;
}
//=============================================================================
//
//
//
//=============================================================================
override bool MouseEvent(int type, int x, int y)
{
if (mSaveName.Length() > 0)
{
// Do not process events when saving is in progress to avoid update of the current index,
// i.e. Selected member variable must remain unchanged
return true;
}
return Super.MouseEvent(type, x, y);
}
//=============================================================================
//
//
//
//=============================================================================
override bool OnUIEvent(UIEvent ev)
{
if (ev.Type == UIEvent.Type_KeyDown)
{
if (Selected != -1)
{
switch (ev.KeyChar)
{
case UIEvent.Key_DEL:
// cannot delete 'new save game' item
if (Selected == 0) return true;
break;
case 78://'N':
Selected = TopItem = 0;
manager.UnloadSaveData ();
return true;
}
}
}
return Super.OnUIEvent(ev);
}
//=============================================================================
//
//
//
//=============================================================================
override void Ticker()
{
if (mSaveName.Length() > 0)
{
manager.DoSave(Selected, mSaveName);
mSaveName = "";
}
}
}
//=============================================================================
//
//
//
//=============================================================================
class LoadMenu : LoadSaveMenu
{
//=============================================================================
//
//
//
//=============================================================================
override void Init(Menu parent, ListMenuDescriptor desc)
{
Super.Init(parent, desc);
TopItem = 0;
Selected = manager.ExtractSaveData (-1);
UpdateSaveComment();
}
//=============================================================================
//
//
//
//=============================================================================
override bool MenuEvent (int mkey, bool fromcontroller)
{
if (Super.MenuEvent(mkey, fromcontroller))
{
return true;
}
if (Selected == -1 || manager.SavegameCount() == 0)
{
return false;
}
if (mkey == MKEY_Enter)
{
manager.LoadSavegame(Selected);
return true;
}
return false;
}
}

View file

@ -0,0 +1,334 @@
struct KeyBindings native version("2.4")
{
native static String NameKeys(int k1, int k2);
native int, int GetKeysForCommand(String cmd);
native void SetBind(int key, String cmd);
native void UnbindACommand (String str);
}
struct OptionValues native version("2.4")
{
native static int GetCount(Name group);
native static String GetText(Name group, int index);
native static double GetValue(Name group, int index);
native static String GetTextValue(Name group, int index);
}
struct JoystickConfig native version("2.4")
{
enum EJoyAxis
{
JOYAXIS_None = -1,
JOYAXIS_Yaw,
JOYAXIS_Pitch,
JOYAXIS_Forward,
JOYAXIS_Side,
JOYAXIS_Up,
// JOYAXIS_Roll, // Ha ha. No roll for you.
NUM_JOYAXIS,
};
native float GetSensitivity();
native void SetSensitivity(float scale);
native float GetAxisScale(int axis);
native void SetAxisScale(int axis, float scale);
native float GetAxisDeadZone(int axis);
native void SetAxisDeadZone(int axis, float zone);
native int GetAxisMap(int axis);
native void SetAxisMap(int axis, int gameaxis);
native String GetName();
native int GetNumAxes();
native String GetAxisName(int axis);
}
class Menu : Object native ui version("2.4")
{
enum EMenuKey
{
MKEY_Up,
MKEY_Down,
MKEY_Left,
MKEY_Right,
MKEY_PageUp,
MKEY_PageDown,
MKEY_Enter,
MKEY_Back,
MKEY_Clear,
NUM_MKEYS,
// These are not buttons but events sent from other menus
MKEY_Input,
MKEY_Abort,
MKEY_MBYes,
MKEY_MBNo,
}
enum EMenuMouse
{
MOUSE_Click,
MOUSE_Move,
MOUSE_Release
};
enum EMenuState
{
Off, // Menu is closed
On, // Menu is opened
WaitKey, // Menu is opened and waiting for a key in the controls menu
OnNoPause, // Menu is opened but does not pause the game
};
native Menu mParentMenu;
native bool mMouseCapture;
native bool mBackbuttonSelected;
native bool DontDim;
native bool DontBlur;
native static int MenuTime();
native static Menu GetCurrentMenu();
native static clearscope void SetMenu(Name mnu, int param = 0); // This is not 100% safe but needs to be available - but always make sure to check that only the desired player opens it!
native static void StartMessage(String msg, int mode = 0, Name command = 'none');
native static void SetMouseCapture(bool on);
native void Close();
native void ActivateMenu();
//=============================================================================
//
//
//
//=============================================================================
void Init(Menu parent)
{
mParentMenu = parent;
mMouseCapture = false;
mBackbuttonSelected = false;
DontDim = false;
DontBlur = false;
}
//=============================================================================
//
//
//
//=============================================================================
virtual bool MenuEvent (int mkey, bool fromcontroller)
{
switch (mkey)
{
case MKEY_Back:
Close();
MenuSound (GetCurrentMenu() != null? "menu/backup" : "menu/clear");
return true;
}
return false;
}
//=============================================================================
//
//
//
//=============================================================================
protected bool MouseEventBack(int type, int x, int y)
{
if (m_show_backbutton >= 0)
{
let tex = TexMan.CheckForTexture(gameinfo.mBackButton, TexMan.Type_MiscPatch);
if (tex.IsValid())
{
Vector2 v = TexMan.GetScaledSize(tex);
int w = int(v.X + 0.5) * CleanXfac;
int h = int(v.Y + 0.5) * CleanYfac;
if (m_show_backbutton&1) x -= screen.GetWidth() - w;
if (m_show_backbutton&2) y -= screen.GetHeight() - h;
mBackbuttonSelected = ( x >= 0 && x < w && y >= 0 && y < h);
if (mBackbuttonSelected && type == MOUSE_Release)
{
if (m_use_mouse == 2) mBackbuttonSelected = false;
MenuEvent(MKEY_Back, true);
}
return mBackbuttonSelected;
}
}
return false;
}
//=============================================================================
//
//
//
//=============================================================================
virtual bool OnUIEvent(UIEvent ev)
{
bool res = false;
int y = ev.MouseY;
if (ev.type == UIEvent.Type_LButtonDown)
{
res = MouseEventBack(MOUSE_Click, ev.MouseX, y);
// make the menu's mouse handler believe that the current coordinate is outside the valid range
if (res) y = -1;
res |= MouseEvent(MOUSE_Click, ev.MouseX, y);
if (res)
{
SetCapture(true);
}
}
else if (ev.type == UIEvent.Type_MouseMove)
{
BackbuttonTime = 4*Thinker.TICRATE;
if (mMouseCapture || m_use_mouse == 1)
{
res = MouseEventBack(MOUSE_Move, ev.MouseX, y);
if (res) y = -1;
res |= MouseEvent(MOUSE_Move, ev.MouseX, y);
}
}
else if (ev.type == UIEvent.Type_LButtonUp)
{
if (mMouseCapture)
{
SetCapture(false);
res = MouseEventBack(MOUSE_Release, ev.MouseX, y);
if (res) y = -1;
res |= MouseEvent(MOUSE_Release, ev.MouseX, y);
}
}
return false;
}
virtual bool OnInputEvent(InputEvent ev)
{
return false;
}
//=============================================================================
//
//
//
//=============================================================================
virtual void Drawer ()
{
if (self == GetCurrentMenu() && BackbuttonAlpha > 0 && m_show_backbutton >= 0 && m_use_mouse)
{
let tex = TexMan.CheckForTexture(gameinfo.mBackButton, TexMan.Type_MiscPatch);
if (tex.IsValid())
{
Vector2 v = TexMan.GetScaledSize(tex);
int w = int(v.X + 0.5) * CleanXfac;
int h = int(v.Y + 0.5) * CleanYfac;
int x = (!(m_show_backbutton&1))? 0:screen.GetWidth() - w;
int y = (!(m_show_backbutton&2))? 0:screen.GetHeight() - h;
if (mBackbuttonSelected && (mMouseCapture || m_use_mouse == 1))
{
screen.DrawTexture(tex, true, x, y, DTA_CleanNoMove, true, DTA_ColorOverlay, Color(40, 255,255,255));
}
else
{
screen.DrawTexture(tex, true, x, y, DTA_CleanNoMove, true, DTA_Alpha, BackbuttonAlpha);
}
}
}
}
//=============================================================================
//
//
//
//=============================================================================
void SetCapture(bool on)
{
if (mMouseCapture != on)
{
mMouseCapture = on;
SetMouseCapture(on);
}
}
//=============================================================================
//
//
//
//=============================================================================
virtual bool TranslateKeyboardEvents() { return true; }
virtual void SetFocus(MenuItemBase fc) {}
virtual bool CheckFocus(MenuItemBase fc) { return false; }
virtual void ReleaseFocus() {}
virtual void ResetColor() {}
virtual bool MouseEvent(int type, int mx, int my) { return true; }
virtual void Ticker() {}
virtual void OnReturn() {}
//=============================================================================
//
//
//
//=============================================================================
static void MenuSound(Sound snd)
{
S_StartSound (snd, CHAN_VOICE, CHANF_MAYBE_LOCAL|CHAN_UI, snd_menuvolume, ATTN_NONE);
}
deprecated("4.0") static void DrawConText (int color, int x, int y, String str)
{
screen.DrawText (ConFont, color, x, y, str, DTA_CellX, 8 * CleanXfac, DTA_CellY, 8 * CleanYfac);
}
static Font OptionFont()
{
return NewSmallFont;
}
static int OptionHeight()
{
return OptionFont().GetHeight();
}
static int OptionWidth(String s)
{
return OptionFont().StringWidth(s);
}
static void DrawOptionText(int x, int y, int color, String text, bool grayed = false)
{
String label = Stringtable.Localize(text);
int overlay = grayed? Color(96,48,0,0) : 0;
screen.DrawText (OptionFont(), color, x, y, text, DTA_CleanNoMove_1, true, DTA_ColorOverlay, overlay);
}
}
class MenuDescriptor : Object native ui version("2.4")
{
native Name mMenuName;
native String mNetgameMessage;
native Class<Menu> mClass;
native static MenuDescriptor GetDescriptor(Name n);
}
// This class is only needed to give it a virtual Init method that doesn't belong to Menu itself
class GenericMenu : Menu
{
virtual void Init(Menu parent)
{
Super.Init(parent);
}
}

View file

@ -0,0 +1,50 @@
//=============================================================================
//
// base class for menu items
//
//=============================================================================
class MenuItemBase : Object native ui version("2.4")
{
protected native double mXpos, mYpos;
protected native Name mAction;
native bool mEnabled;
void Init(double xpos = 0, double ypos = 0, Name actionname = 'None')
{
mXpos = xpos;
mYpos = ypos;
mAction = actionname;
mEnabled = true;
}
virtual bool CheckCoordinate(int x, int y) { return false; }
virtual void Ticker() {}
virtual void Drawer(bool selected) {}
virtual bool Selectable() {return false; }
virtual bool Activate() { return false; }
virtual Name, int GetAction() { return mAction, 0; }
virtual bool SetString(int i, String s) { return false; }
virtual bool, String GetString(int i) { return false, ""; }
virtual bool SetValue(int i, int value) { return false; }
virtual bool, int GetValue(int i) { return false, 0; }
virtual void Enable(bool on) { mEnabled = on; }
virtual bool MenuEvent (int mkey, bool fromcontroller) { return false; }
virtual bool MouseEvent(int type, int x, int y) { return false; }
virtual bool CheckHotkey(int c) { return false; }
virtual int GetWidth() { return 0; }
virtual int GetIndent() { return 0; }
virtual int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected) { return indent; }
void OffsetPositionY(double ydelta) { mYpos += ydelta; }
double GetY() { return mYpos; }
double GetX() { return mXpos; }
void SetX(double x) { mXpos = x; }
virtual void OnMenuCreated() {}
}
// this is only used to parse font color ranges in MENUDEF
enum MenudefColorRange
{
NO_COLOR = -1
}

View file

@ -0,0 +1,318 @@
/*
** messagebox.cpp
** Confirmation, notification screens
**
**---------------------------------------------------------------------------
** 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 MessageBoxMenu : Menu
{
BrokenLines mMessage;
voidptr Handler;
int mMessageMode;
int messageSelection;
int mMouseLeft, mMouseRight, mMouseY;
Name mAction;
Font textFont, arrowFont;
int destWidth, destHeight;
String selector;
native static void CallHandler(voidptr hnd);
//=============================================================================
//
//
//
//=============================================================================
virtual void Init(Menu parent, String message, int messagemode, bool playsound = false, Name cmd = 'None', voidptr native_handler = null)
{
Super.Init(parent);
mAction = cmd;
messageSelection = 0;
mMouseLeft = 140;
mMouseY = 0x80000000;
textFont = null;
if (!generic_ui)
{
if (SmallFont && SmallFont.CanPrint(message) && SmallFont.CanPrint("$TXT_YES") && SmallFont.CanPrint("$TXT_NO")) textFont = SmallFont;
else if (OriginalSmallFont && OriginalSmallFont.CanPrint(message) && OriginalSmallFont.CanPrint("$TXT_YES") && OriginalSmallFont.CanPrint("$TXT_NO")) textFont = OriginalSmallFont;
}
if (!textFont)
{
arrowFont = textFont = NewSmallFont;
int factor = (CleanXfac+1) / 2;
destWidth = screen.GetWidth() / factor;
destHeight = screen.GetHeight() / factor;
selector = "▶";
}
else
{
arrowFont = ConFont;
destWidth = CleanWidth;
destHeight = CleanHeight;
selector = "\xd";
}
int mr1 = destWidth/2 + 10 + textFont.StringWidth(Stringtable.Localize("$TXT_YES"));
int mr2 = destWidth/2 + 10 + textFont.StringWidth(Stringtable.Localize("$TXT_NO"));
mMouseRight = MAX(mr1, mr2);
mParentMenu = parent;
mMessage = textFont.BreakLines(Stringtable.Localize(message), generic_ui? 600 : 300);
mMessageMode = messagemode;
if (playsound)
{
MenuSound ("menu/prompt");
}
Handler = native_handler;
}
//=============================================================================
//
//
//
//=============================================================================
override void Drawer ()
{
int i, y;
int fontheight = textFont.GetHeight();
y = destHeight / 2;
int c = mMessage.Count();
y -= c * fontHeight / 2;
for (i = 0; i < c; i++)
{
screen.DrawText (textFont, Font.CR_UNTRANSLATED, destWidth/2 - mMessage.StringWidth(i)/2, y, mMessage.StringAt(i), DTA_VirtualWidth, destWidth, DTA_VirtualHeight, destHeight, DTA_KeepRatio, true);
y += fontheight;
}
if (mMessageMode == 0)
{
y += fontheight;
mMouseY = y;
screen.DrawText(textFont, messageSelection == 0? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor, destWidth / 2, y, Stringtable.Localize("$TXT_YES"), DTA_VirtualWidth, destWidth, DTA_VirtualHeight, destHeight, DTA_KeepRatio, true);
screen.DrawText(textFont, messageSelection == 1? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor, destWidth / 2, y + fontheight, Stringtable.Localize("$TXT_NO"), DTA_VirtualWidth, destWidth, DTA_VirtualHeight, destHeight, DTA_KeepRatio, true);
if (messageSelection >= 0)
{
if ((MenuTime() % 8) < 6)
{
screen.DrawText(arrowFont, OptionMenuSettings.mFontColorSelection,
destWidth/2 - 11, y + fontheight * messageSelection, selector, DTA_VirtualWidth, destWidth, DTA_VirtualHeight, destHeight, DTA_KeepRatio, true);
}
}
}
}
//=============================================================================
//
//
//
//=============================================================================
protected void CloseSound()
{
MenuSound (GetCurrentMenu() != NULL? "menu/backup" : "menu/dismiss");
}
//=============================================================================
//
//
//
//=============================================================================
virtual void HandleResult(bool res)
{
if (Handler != null)
{
if (res)
{
CallHandler(Handler);
}
else
{
Close();
CloseSound();
}
}
else if (mParentMenu != NULL)
{
if (mMessageMode == 0)
{
if (mAction == 'None')
{
mParentMenu.MenuEvent(res? MKEY_MBYes : MKEY_MBNo, false);
Close();
}
else
{
Close();
if (res) SetMenu(mAction, -1);
}
CloseSound();
}
}
}
//=============================================================================
//
//
//
//=============================================================================
override bool OnUIEvent(UIEvent ev)
{
if (ev.type == UIEvent.Type_KeyDown)
{
if (mMessageMode == 0)
{
// tolower
int ch = ev.KeyChar;
ch = ch >= 65 && ch <91? ch + 32 : ch;
if (ch == 110 /*'n'*/ || ch == 32)
{
HandleResult(false);
return true;
}
else if (ch == 121 /*'y'*/)
{
HandleResult(true);
return true;
}
}
else
{
Close();
return true;
}
return false;
}
return Super.OnUIEvent(ev);
}
override bool OnInputEvent(InputEvent ev)
{
if (ev.type == InputEvent.Type_KeyDown)
{
Close();
return true;
}
return Super.OnInputEvent(ev);
}
//=============================================================================
//
//
//
//=============================================================================
override bool MenuEvent(int mkey, bool fromcontroller)
{
if (mMessageMode == 0)
{
if (mkey == MKEY_Up || mkey == MKEY_Down)
{
MenuSound("menu/cursor");
messageSelection = !messageSelection;
return true;
}
else if (mkey == MKEY_Enter)
{
// 0 is yes, 1 is no
HandleResult(!messageSelection);
return true;
}
else if (mkey == MKEY_Back)
{
HandleResult(false);
return true;
}
return false;
}
else
{
Close();
CloseSound();
return true;
}
}
//=============================================================================
//
//
//
//=============================================================================
override bool MouseEvent(int type, int x, int y)
{
if (mMessageMode == 1)
{
if (type == MOUSE_Click)
{
return MenuEvent(MKEY_Enter, true);
}
return false;
}
else
{
int sel = -1;
int fh = textFont.GetHeight() + 1;
// convert x/y from screen to virtual coordinates, according to CleanX/Yfac use in DrawTexture
x = x * destWidth / screen.GetWidth();
y = y * destHeight / screen.GetHeight();
if (x >= mMouseLeft && x <= mMouseRight && y >= mMouseY && y < mMouseY + 2 * fh)
{
sel = y >= mMouseY + fh;
}
messageSelection = sel;
if (type == MOUSE_Release)
{
return MenuEvent(MKEY_Enter, true);
}
return true;
}
}
}

View file

@ -0,0 +1,601 @@
/*
** optionmenu.cpp
** Handler class for the option menus and associated items
**
**---------------------------------------------------------------------------
** 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.
**---------------------------------------------------------------------------
**
*/
struct FOptionMenuSettings native version("2.4")
{
int mTitleColor;
int mFontColor;
int mFontColorValue;
int mFontColorMore;
int mFontColorHeader;
int mFontColorHighlight;
int mFontColorSelection;
int mLinespacing;
}
class OptionMenuDescriptor : MenuDescriptor native
{
native Array<OptionMenuItem> mItems;
native String mTitle;
native int mSelectedItem;
native int mDrawTop;
native int mScrollTop;
native int mScrollPos;
native int mIndent;
native int mPosition;
native bool mDontDim;
native Font mFont;
void Reset()
{
// Reset the default settings (ignore all other values in the struct)
mPosition = 0;
mScrollTop = 0;
mIndent = 0;
mDontDim = 0;
}
//=============================================================================
//
//
//
//=============================================================================
void CalcIndent()
{
// calculate the menu indent
int widest = 0, thiswidth;
for (int i = 0; i < mItems.Size(); i++)
{
thiswidth = mItems[i].GetIndent();
if (thiswidth > widest) widest = thiswidth;
}
mIndent = widest + 4;
}
}
class OptionMenu : Menu
{
OptionMenuDescriptor mDesc;
bool CanScrollUp;
bool CanScrollDown;
int VisBottom;
OptionMenuItem mFocusControl;
//=============================================================================
//
//
//
//=============================================================================
virtual void Init(Menu parent, OptionMenuDescriptor desc)
{
mParentMenu = parent;
mDesc = desc;
DontDim = desc.mDontDim;
let itemCount = mDesc.mItems.size();
if (itemCount > 0)
{
let last = mDesc.mItems[itemCount - 1];
bool lastIsText = (last is "OptionMenuItemStaticText");
if (lastIsText)
{
String text = last.mLabel;
bool lastIsSpace = (text == "" || text == " ");
if (lastIsSpace)
{
mDesc.mItems.Pop();
}
}
}
if (mDesc.mSelectedItem == -1) mDesc.mSelectedItem = FirstSelectable();
mDesc.CalcIndent();
// notify all items that the menu was just created.
for(int i=0;i<mDesc.mItems.Size(); i++)
{
mDesc.mItems[i].OnMenuCreated();
}
}
//=============================================================================
//
//
//
//=============================================================================
OptionMenuItem GetItem(Name name)
{
for(int i = 0; i < mDesc.mItems.Size(); i++)
{
Name nm = mDesc.mItems[i].GetAction();
if (nm == name) return mDesc.mItems[i];
}
return NULL;
}
//=============================================================================
//
//
//
//=============================================================================
int FirstSelectable()
{
// Go down to the first selectable item
int i = -1;
do
{
i++;
}
while (i < mDesc.mItems.Size() && !mDesc.mItems[i].Selectable());
if (i>=0 && i < mDesc.mItems.Size()) return i;
else return -1;
}
//=============================================================================
//
//
//
//=============================================================================
override bool OnUIEvent(UIEvent ev)
{
if (ev.type == UIEvent.Type_WheelUp)
{
int scrollamt = MIN(2, mDesc.mScrollPos);
mDesc.mScrollPos -= scrollamt;
return true;
}
else if (ev.type == UIEvent.Type_WheelDown)
{
if (CanScrollDown)
{
if (VisBottom >= 0 && VisBottom < (mDesc.mItems.Size()-2))
{
mDesc.mScrollPos += 2;
VisBottom += 2;
}
else
{
mDesc.mScrollPos++;
VisBottom++;
}
}
return true;
}
return Super.OnUIEvent(ev);
}
//=============================================================================
//
//
//
//=============================================================================
override bool MenuEvent (int mkey, bool fromcontroller)
{
int startedAt = mDesc.mSelectedItem;
switch (mkey)
{
case MKEY_Up:
if (mDesc.mSelectedItem == -1)
{
mDesc.mSelectedItem = FirstSelectable();
break;
}
do
{
--mDesc.mSelectedItem;
if (mDesc.mScrollPos > 0 &&
mDesc.mSelectedItem <= mDesc.mScrollTop + mDesc.mScrollPos)
{
mDesc.mScrollPos = MAX(mDesc.mSelectedItem - mDesc.mScrollTop - 1, 0);
}
if (mDesc.mSelectedItem < 0)
{
// Figure out how many lines of text fit on the menu
int y = mDesc.mPosition;
if (y <= 0)
{
let font = generic_ui || !mDesc.mFont? NewSmallFont : mDesc.mFont;
if (font && mDesc.mTitle.Length() > 0)
{
y = -y + font.GetHeight();
}
else
{
y = -y;
}
}
y *= CleanYfac_1;
int rowheight = OptionMenuSettings.mLinespacing * CleanYfac_1;
int maxitems = (screen.GetHeight() - rowheight - y) / rowheight + 1;
mDesc.mScrollPos = MAX (0, mDesc.mItems.Size() - maxitems + mDesc.mScrollTop);
mDesc.mSelectedItem = mDesc.mItems.Size()-1;
}
}
while (!mDesc.mItems[mDesc.mSelectedItem].Selectable() && mDesc.mSelectedItem != startedAt);
break;
case MKEY_Down:
if (mDesc.mSelectedItem == -1)
{
mDesc.mSelectedItem = FirstSelectable();
break;
}
do
{
++mDesc.mSelectedItem;
if (CanScrollDown && mDesc.mSelectedItem == VisBottom)
{
mDesc.mScrollPos++;
VisBottom++;
}
if (mDesc.mSelectedItem >= mDesc.mItems.Size())
{
if (startedAt == -1)
{
mDesc.mSelectedItem = -1;
mDesc.mScrollPos = -1;
break;
}
else
{
mDesc.mSelectedItem = 0;
mDesc.mScrollPos = 0;
}
}
}
while (!mDesc.mItems[mDesc.mSelectedItem].Selectable() && mDesc.mSelectedItem != startedAt);
break;
case MKEY_PageUp:
if (mDesc.mScrollPos > 0)
{
mDesc.mScrollPos -= VisBottom - mDesc.mScrollPos - mDesc.mScrollTop;
if (mDesc.mScrollPos < 0)
{
mDesc.mScrollPos = 0;
}
if (mDesc.mSelectedItem != -1)
{
mDesc.mSelectedItem = mDesc.mScrollTop + mDesc.mScrollPos + 1;
while (!mDesc.mItems[mDesc.mSelectedItem].Selectable())
{
if (++mDesc.mSelectedItem >= mDesc.mItems.Size())
{
mDesc.mSelectedItem = 0;
}
}
if (mDesc.mScrollPos > mDesc.mSelectedItem)
{
mDesc.mScrollPos = mDesc.mSelectedItem;
}
}
}
break;
case MKEY_PageDown:
if (CanScrollDown)
{
int pagesize = VisBottom - mDesc.mScrollPos - mDesc.mScrollTop;
mDesc.mScrollPos += pagesize;
if (mDesc.mScrollPos + mDesc.mScrollTop + pagesize > mDesc.mItems.Size())
{
mDesc.mScrollPos = mDesc.mItems.Size() - mDesc.mScrollTop - pagesize;
}
if (mDesc.mSelectedItem != -1)
{
mDesc.mSelectedItem = mDesc.mScrollTop + mDesc.mScrollPos;
while (!mDesc.mItems[mDesc.mSelectedItem].Selectable())
{
if (++mDesc.mSelectedItem >= mDesc.mItems.Size())
{
mDesc.mSelectedItem = 0;
}
}
if (mDesc.mScrollPos > mDesc.mSelectedItem)
{
mDesc.mScrollPos = mDesc.mSelectedItem;
}
}
}
break;
case MKEY_Enter:
if (mDesc.mSelectedItem >= 0 && mDesc.mItems[mDesc.mSelectedItem].Activate())
{
return true;
}
// fall through to default
default:
if (mDesc.mSelectedItem >= 0 &&
mDesc.mItems[mDesc.mSelectedItem].MenuEvent(mkey, fromcontroller)) return true;
return Super.MenuEvent(mkey, fromcontroller);
}
if (mDesc.mSelectedItem != startedAt)
{
MenuSound ("menu/cursor");
}
return true;
}
//=============================================================================
//
//
//
//=============================================================================
override bool MouseEvent(int type, int x, int y)
{
y = (y / CleanYfac_1) - mDesc.mDrawTop;
if (mFocusControl)
{
mFocusControl.MouseEvent(type, x, y);
return true;
}
else
{
int yline = (y / OptionMenuSettings.mLinespacing);
if (yline >= mDesc.mScrollTop)
{
yline += mDesc.mScrollPos;
}
if (yline >= 0 && yline < mDesc.mItems.Size() && mDesc.mItems[yline].Selectable())
{
if (yline != mDesc.mSelectedItem)
{
mDesc.mSelectedItem = yline;
}
mDesc.mItems[yline].MouseEvent(type, x, y);
return true;
}
}
mDesc.mSelectedItem = -1;
return Super.MouseEvent(type, x, y);
}
//=============================================================================
//
//
//
//=============================================================================
override void Ticker ()
{
Super.Ticker();
for(int i = 0; i < mDesc.mItems.Size(); i++)
{
mDesc.mItems[i].Ticker();
}
}
//=============================================================================
//
//
//
//=============================================================================
virtual int GetIndent()
{
int indent = max(0, (mDesc.mIndent + 40) - CleanWidth_1 / 2);
return screen.GetWidth() / 2 + indent * CleanXfac_1;
}
override void Drawer ()
{
int y = mDesc.mPosition;
if (y <= 0)
{
let font = generic_ui || !mDesc.mFont? NewSmallFont : mDesc.mFont;
if (font && mDesc.mTitle.Length() > 0)
{
let tt = Stringtable.Localize(mDesc.mTitle);
screen.DrawText (font, OptionMenuSettings.mTitleColor,
(screen.GetWidth() - font.StringWidth(tt) * CleanXfac_1) / 2, 10*CleanYfac_1,
tt, DTA_CleanNoMove_1, true);
y = -y + font.GetHeight();
}
else
{
y = -y;
}
}
mDesc.mDrawTop = y;
int fontheight = OptionMenuSettings.mLinespacing * CleanYfac_1;
y *= CleanYfac_1;
int indent = GetIndent();
int ytop = y + mDesc.mScrollTop * 8 * CleanYfac_1;
int lastrow = screen.GetHeight() - OptionHeight() * CleanYfac_1;
int i;
for (i = 0; i < mDesc.mItems.Size() && y <= lastrow; i++)
{
// Don't scroll the uppermost items
if (i == mDesc.mScrollTop)
{
i += mDesc.mScrollPos;
if (i >= mDesc.mItems.Size()) break; // skipped beyond end of menu
}
bool isSelected = mDesc.mSelectedItem == i;
int cur_indent = mDesc.mItems[i].Draw(mDesc, y, indent, isSelected);
if (cur_indent >= 0 && isSelected && mDesc.mItems[i].Selectable())
{
if (((MenuTime() % 8) < 6) || GetCurrentMenu() != self)
{
DrawOptionText(cur_indent + 3 * CleanXfac_1, y, OptionMenuSettings.mFontColorSelection, "◄");
}
}
y += fontheight;
}
CanScrollUp = (mDesc.mScrollPos > 0);
CanScrollDown = (i < mDesc.mItems.Size());
VisBottom = i - 1;
if (CanScrollUp)
{
DrawOptionText(screen.GetWidth() - 11 * CleanXfac_1, ytop, OptionMenuSettings.mFontColorSelection, "▲");
}
if (CanScrollDown)
{
DrawOptionText(screen.GetWidth() - 11 * CleanXfac_1 , y - 8*CleanYfac_1, OptionMenuSettings.mFontColorSelection, "▼");
}
Super.Drawer();
}
//=============================================================================
//
//
//
//=============================================================================
override void SetFocus(MenuItemBase fc)
{
mFocusControl = OptionMenuItem(fc);
}
override bool CheckFocus(MenuItemBase fc)
{
return mFocusControl == fc;
}
override void ReleaseFocus()
{
mFocusControl = NULL;
}
}
class GameplayMenu : OptionMenu
{
override void Drawer ()
{
Super.Drawer();
String s = String.Format("dmflags = %d dmflags2 = %d", dmflags, dmflags2);
screen.DrawText (OptionFont(), OptionMenuSettings.mFontColorValue,
(screen.GetWidth() - OptionWidth (s) * CleanXfac_1) / 2, 35 * CleanXfac_1, s,
DTA_CleanNoMove_1, true);
}
}
class CompatibilityMenu : OptionMenu
{
override void Drawer ()
{
Super.Drawer();
String s = String.Format("compatflags = %d compatflags2 = %d", compatflags, compatflags2);
screen.DrawText (OptionFont(), OptionMenuSettings.mFontColorValue,
(screen.GetWidth() - OptionWidth (s) * CleanXfac_1) / 2, 35 * CleanXfac_1, s,
DTA_CleanNoMove_1, true);
}
}
class GLTextureGLOptions : OptionMenu
{
private int mWarningIndex;
private string mWarningLabel;
override void Init(Menu parent, OptionMenuDescriptor desc)
{
super.Init(parent, desc);
// Find index of warning item placeholder
mWarningIndex = -1;
mWarningLabel = "!HQRESIZE_WARNING!";
for (int i=0; i < mDesc.mItems.Size(); ++i)
{
if (mDesc.mItems[i].mLabel == mWarningLabel)
{
mWarningIndex = i;
break;
}
}
}
override void OnDestroy()
{
// Restore warning item placeholder
if (mWarningIndex >= 0)
{
mDesc.mItems[mWarningIndex].mLabel = mWarningLabel;
}
Super.OnDestroy();
}
override void Ticker()
{
Super.Ticker();
if (mWarningIndex >= 0)
{
string message;
if (gl_texture_hqresizemult > 1 && gl_texture_hqresizemode > 0)
{
int multiplier = gl_texture_hqresizemult * gl_texture_hqresizemult;
message = StringTable.Localize("$GLTEXMNU_HQRESIZEWARN");
string mult = String.Format("%d", multiplier);
message.Replace("%d", mult);
}
mDesc.mItems[mWarningIndex].mLabel = Font.TEXTCOLOR_CYAN .. message;
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,125 @@
/*
** readthis.cpp
** Help screens
**
**---------------------------------------------------------------------------
** Copyright 2001-2010 Randy Heit
** Copyright 2010 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 ReadThisMenu : GenericMenu
{
int mScreen;
int mInfoTic;
//=============================================================================
//
//
//
//=============================================================================
override void Init(Menu parent)
{
Super.Init(parent);
mScreen = 1;
mInfoTic = gametic;
}
override void Drawer()
{
double alpha;
TextureID tex, prevpic;
// Did the mapper choose a custom help page via MAPINFO?
if (Level.F1Pic.Length() != 0)
{
tex = TexMan.CheckForTexture(Level.F1Pic, TexMan.Type_MiscPatch);
mScreen = 1;
}
if (!tex.IsValid())
{
tex = TexMan.CheckForTexture(gameinfo.infoPages[mScreen-1], TexMan.Type_MiscPatch);
}
if (mScreen > 1)
{
prevpic = TexMan.CheckForTexture(gameinfo.infoPages[mScreen-2], TexMan.Type_MiscPatch);
}
screen.Dim(0, 1.0, 0,0, screen.GetWidth(), screen.GetHeight());
alpha = MIN((gametic - mInfoTic) * (3. / Thinker.TICRATE), 1.);
if (alpha < 1. && prevpic.IsValid())
{
screen.DrawTexture (prevpic, false, 0, 0, DTA_Fullscreen, true);
}
else alpha = 1;
screen.DrawTexture (tex, false, 0, 0, DTA_Fullscreen, true, DTA_Alpha, alpha);
}
//=============================================================================
//
//
//
//=============================================================================
override bool MenuEvent(int mkey, bool fromcontroller)
{
if (mkey == MKEY_Enter)
{
MenuSound("menu/choose");
mScreen++;
mInfoTic = gametic;
if (Level.F1Pic.Length() != 0 || mScreen > gameinfo.infoPages.Size())
{
Close();
}
return true;
}
else return Super.MenuEvent(mkey, fromcontroller);
}
//=============================================================================
//
//
//
//=============================================================================
override bool MouseEvent(int type, int x, int y)
{
if (type == MOUSE_Click)
{
return MenuEvent(MKEY_Enter, true);
}
return false;
}
}

View file

@ -0,0 +1,258 @@
class ReverbEdit : OptionMenu
{
static native double GetValue(int index);
static native double SetValue(int index, double value);
static native bool GrayCheck();
static native string, int GetSelectedEnvironment();
static native void FillSelectMenu(String ccmd, OptionMenuDescriptor desc);
static native void FillSaveMenu(OptionMenuDescriptor desc);
static native int GetSaveSelection(int num);
static native void ToggleSaveSelection(int num);
override void Init(Menu parent, OptionMenuDescriptor desc)
{
super.Init(parent, desc);
OnReturn();
}
override void OnReturn()
{
string env;
int id;
[env, id] = GetSelectedEnvironment();
let li = GetItem('EvironmentName');
if (li != NULL)
{
if (id != -1)
{
li.SetValue(0, 1);
li.SetString(0, env);
}
else
{
li.SetValue(0, 0);
}
}
li = GetItem('EvironmentID');
if (li != NULL)
{
if (id != -1)
{
li.SetValue(0, 1);
li.SetString(0, String.Format("%d, %d", (id >> 8) & 255, id & 255));
}
else
{
li.SetValue(0, 0);
}
}
}
}
class ReverbSelect : OptionMenu
{
//=============================================================================
//
//
//
//=============================================================================
override void Init(Menu parent, OptionMenuDescriptor desc)
{
ReverbEdit.FillSelectMenu("selectenvironment", desc);
super.Init(parent, desc);
}
}
class ReverbSave : OptionMenu
{
//=============================================================================
//
//
//
//=============================================================================
override void Init(Menu parent, OptionMenuDescriptor desc)
{
ReverbEdit.FillSaveMenu(desc);
super.Init(parent, desc);
}
}
//=============================================================================
//
// Change a CVAR, command is the CVAR name
//
//=============================================================================
class OptionMenuItemReverbSaveSelect : OptionMenuItemOptionBase
{
int mValIndex;
OptionMenuItemReverbSaveSelect Init(String label, int index, Name values)
{
Super.Init(label, 'None', values, null, 0);
mValIndex = index;
return self;
}
//=============================================================================
override int GetSelection()
{
return ReverbEdit.GetSaveSelection(mValIndex);
}
override void SetSelection(int Selection)
{
ReverbEdit.ToggleSaveSelection(mValIndex);
}
}
//=============================================================================
//
// opens a submenu, command is a submenu name
//
//=============================================================================
class OptionMenuItemReverbSelect : OptionMenuItemSubMenu
{
OptionMenuItemReverbSelect Init(String label, Name command)
{
Super.init(label, command, 0, false);
return self;
}
override int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected)
{
int x = drawLabel(indent, y, selected? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor);
String text = ReverbEdit.GetSelectedEnvironment();
drawValue(indent, y, OptionMenuSettings.mFontColorValue, text);
return indent;
}
}
//=============================================================================
//
//
//
//=============================================================================
class OptionMenuItemReverbOption : OptionMenuItemOptionBase
{
int mValIndex;
OptionMenuItemReverbOption Init(String label, int valindex, Name values)
{
Super.Init(label, "", values, null, false);
mValIndex = valindex;
return self;
}
override bool isGrayed()
{
return ReverbEdit.GrayCheck();
}
override int GetSelection()
{
return int(ReverbEdit.GetValue(mValIndex));
}
override void SetSelection(int Selection)
{
ReverbEdit.SetValue(mValIndex, Selection);
}
}
//=============================================================================
//
//
//
//=============================================================================
class OptionMenuItemSliderReverbEditOption : OptionMenuSliderBase
{
int mValIndex;
String mEditValue;
TextEnterMenu mEnter;
OptionMenuItemSliderReverbEditOption Init(String label, double min, double max, double step, int showval, int valindex)
{
Super.Init(label, min, max, step, showval);
mValIndex = valindex;
mEnter = null;
return self;
}
override double GetSliderValue()
{
return ReverbEdit.GetValue(mValIndex);
}
override void SetSliderValue(double val)
{
ReverbEdit.SetValue(mValIndex, val);
}
override bool Selectable()
{
return !ReverbEdit.GrayCheck();
}
virtual String Represent()
{
return mEnter.GetText() .. Menu.OptionFont().GetCursor();
}
//=============================================================================
override int Draw(OptionMenuDescriptor desc, int y, int indent, bool selected)
{
drawLabel(indent, y, selected ? OptionMenuSettings.mFontColorSelection : OptionMenuSettings.mFontColor, ReverbEdit.GrayCheck());
mDrawX = indent + CursorSpace();
if (mEnter)
{
drawText(mDrawX, y, OptionMenuSettings.mFontColorValue, Represent());
}
else
{
DrawSlider (mDrawX, y, mMin, mMax, GetSliderValue(), mShowValue, indent);
}
return indent;
}
override bool MenuEvent (int mkey, bool fromcontroller)
{
if (mkey == Menu.MKEY_Enter)
{
Menu.MenuSound("menu/choose");
mEnter = TextEnterMenu.OpenTextEnter(Menu.GetCurrentMenu(), Menu.OptionFont(), String.Format("%.3f", GetSliderValue()), -1, fromcontroller);
mEnter.ActivateMenu();
return true;
}
else if (mkey == Menu.MKEY_Input)
{
String val = mEnter.GetText();
SetSliderValue(val.toDouble());
mEnter = null;
return true;
}
else if (mkey == Menu.MKEY_Abort)
{
mEnter = null;
return true;
}
return Super.MenuEvent(mkey, fromcontroller);
}
}

View file

@ -0,0 +1,33 @@
//=============================================================================
//
// os_AnyOrAllOption class represents an Option Item for Option Search menu.
// Changing the value of this option causes the menu to refresh the search
// results.
//
//=============================================================================
class os_AnyOrAllOption : OptionMenuItemOption
{
os_AnyOrAllOption Init(os_Menu menu)
{
Super.Init("", "os_isanyof", "os_isanyof_values");
mMenu = menu;
return self;
}
override bool MenuEvent(int mkey, bool fromcontroller)
{
bool result = Super.MenuEvent(mkey, fromcontroller);
if (mKey == Menu.MKEY_Left || mKey == Menu.MKEY_Right || mkey == Menu.MKEY_Enter)
{
mMenu.search();
}
return result;
}
private os_Menu mMenu;
}

View file

@ -0,0 +1,218 @@
//=============================================================================
//
// Option Search Menu class.
// This menu contains search field, and is dynamically filled with search
// results.
//
//=============================================================================
class os_Menu : OptionMenu
{
override void Init(Menu parent, OptionMenuDescriptor desc)
{
Super.Init(parent, desc);
mDesc.mItems.clear();
addSearchField();
mDesc.mScrollPos = 0;
mDesc.mSelectedItem = 0;
mDesc.CalcIndent();
}
void search()
{
string text = mSearchField.GetText();
let query = os_Query.fromString(text);
bool isAnyTermMatches = mIsAnyOfItem.mCVar.GetBool();
mDesc.mItems.clear();
addSearchField(text);
bool found = listOptions(mDesc, "MainMenu", query, "", isAnyTermMatches);
if (!found) { addNoResultsItem(mDesc); }
mDesc.CalcIndent();
}
private void addSearchField(string query = "")
{
string searchLabel = StringTable.Localize("$OS_LABEL");
mSearchField = new("os_SearchField").Init(searchLabel, self, query);
mIsAnyOfItem = new("os_AnyOrAllOption").Init(self);
mDesc.mItems.push(mSearchField);
mDesc.mItems.push(mIsAnyOfItem);
addEmptyLine(mDesc);
}
private static bool listOptions(OptionMenuDescriptor targetDesc,
string menuName,
os_Query query,
string path,
bool isAnyTermMatches)
{
let desc = MenuDescriptor.GetDescriptor(menuName);
let listMenuDesc = ListMenuDescriptor(desc);
if (listMenuDesc)
{
return listOptionsListMenu(listMenuDesc, targetDesc, query, path, isAnyTermMatches);
}
let optionMenuDesc = OptionMenuDescriptor(desc);
if (optionMenuDesc)
{
return listOptionsOptionMenu(optionMenuDesc, targetDesc, query, path, isAnyTermMatches);
}
return false;
}
private static bool listOptionsListMenu(ListMenuDescriptor sourceDesc,
OptionMenuDescriptor targetDesc,
os_Query query,
string path,
bool isAnyTermMatches)
{
int nItems = sourceDesc.mItems.size();
bool found = false;
for (int i = 0; i < nItems; ++i)
{
let item = sourceDesc.mItems[i];
string actionN = item.GetAction();
let textItem = ListMenuItemTextItem(item);
string newPath = textItem
? makePath(path, StringTable.Localize(textItem.mText))
: path;
found |= listOptions(targetDesc, actionN, query, newPath, isAnyTermMatches);
}
return found;
}
private static bool listOptionsOptionMenu(OptionMenuDescriptor sourceDesc,
OptionMenuDescriptor targetDesc,
os_Query query,
string path,
bool isAnyTermMatches)
{
if (sourceDesc == targetDesc) { return false; }
int nItems = sourceDesc.mItems.size();
bool first = true;
bool found = false;
for (int i = 0; i < nItems; ++i)
{
let item = sourceDesc.mItems[i];
if (item is "OptionMenuItemStaticText") { continue; }
string label = StringTable.Localize(item.mLabel);
if (!query.matches(label, isAnyTermMatches)) { continue; }
found = true;
if (first)
{
addEmptyLine(targetDesc);
addPathItem(targetDesc, path);
first = false;
}
let itemOptionBase = OptionMenuItemOptionBase(item);
if (itemOptionBase)
{
itemOptionBase.mCenter = false;
}
targetDesc.mItems.push(item);
}
for (int i = 0; i < nItems; ++i)
{
let item = sourceDesc.mItems[i];
string label = StringTable.Localize(item.mLabel);
string optionSearchTitle = StringTable.Localize("$OS_TITLE");
if (label == optionSearchTitle) { continue; }
if (item is "OptionMenuItemSubMenu")
{
string newPath = makePath(path, label);
found |= listOptions(targetDesc, item.GetAction(), query, newPath, isAnyTermMatches);
}
}
return found;
}
private static string makePath(string path, string label)
{
if (path.length() == 0) { return label; }
int pathWidth = SmallFont.StringWidth(path .. "/" .. label);
int screenWidth = Screen.GetWidth();
bool isTooWide = (pathWidth > screenWidth / 3);
string newPath = isTooWide
? path .. "/" .. "\n" .. label
: path .. "/" .. label;
return newPath;
}
private static void addPathItem(OptionMenuDescriptor desc, string path)
{
Array<String> lines;
path.split(lines, "\n");
int nLines = lines.size();
for (int i = 0; i < nLines; ++i)
{
OptionMenuItemStaticText text = new("OptionMenuItemStaticText").Init(lines[i], 1);
desc.mItems.push(text);
}
}
private static void addEmptyLine(OptionMenuDescriptor desc)
{
int nItems = desc.mItems.size();
if (nItems > 0)
{
let staticText = OptionMenuItemStaticText(desc.mItems[nItems - 1]);
if (staticText != null && staticText.mLabel == "") { return; }
}
let item = new("OptionMenuItemStaticText").Init("");
desc.mItems.push(item);
}
private static void addNoResultsItem(OptionMenuDescriptor desc)
{
string noResults = StringTable.Localize("$OS_NO_RESULTS");
let text = new("OptionMenuItemStaticText").Init(noResults, 0);
addEmptyLine(desc);
desc.mItems.push(text);
}
private os_AnyOrAllOption mIsAnyOfItem;
private os_SearchField mSearchField;
}

View file

@ -0,0 +1,73 @@
//=============================================================================
//
// Option Search Query class represents a search query.
// A search query consists constists of one or more terms (words).
//
// Query matching deponds on "os_is_any_of" variable.
// If this variable is "true", the text matches the query if any of the terms
// matches the query.
// If this variable is "false", the text matches the query only if all the
// terms match the query.
//
//=============================================================================
class os_Query
{
static os_Query fromString(string str)
{
let query = new("os_Query");
str.Split(query.mQueryParts, " ", TOK_SKIPEMPTY);
return query;
}
bool matches(string text, bool isSearchForAny)
{
return isSearchForAny
? matchesAny(text)
: matchesAll(text);
}
// private: //////////////////////////////////////////////////////////////////
private bool matchesAny(string text)
{
int nParts = mQueryParts.size();
for (int i = 0; i < nParts; ++i)
{
string queryPart = mQueryParts[i];
if (contains(text, queryPart)) { return true; }
}
return false;
}
private bool matchesAll(string text)
{
int nParts = mQueryParts.size();
for (int i = 0; i < nParts; ++i)
{
string queryPart = mQueryParts[i];
if (!contains(text, queryPart)) { return false; }
}
return true;
}
private static bool contains(string str, string substr)
{
let lowerstr = str .MakeLower();
let lowersubstr = substr.MakeLower();
bool contains = (lowerstr.IndexOf(lowersubstr) != -1);
return contains;
}
private Array<String> mQueryParts;
}

View file

@ -0,0 +1,52 @@
//=============================================================================
//
// Option Search Field class.
//
// When the search query is entered, makes Search Menu perform a search.
//
//=============================================================================
class os_SearchField : OptionMenuItemTextField
{
os_SearchField Init(String label, os_Menu menu, string query)
{
Super.Init(label, "");
mMenu = menu;
mText = query;
return self;
}
override bool MenuEvent(int mkey, bool fromcontroller)
{
if (mkey == Menu.MKEY_Enter)
{
Menu.MenuSound("menu/choose");
mEnter = TextEnterMenu.OpenTextEnter(Menu.GetCurrentMenu(), Menu.OptionFont(), mText, -1, fromcontroller);
mEnter.ActivateMenu();
return true;
}
if (mkey == Menu.MKEY_Input)
{
mtext = mEnter.GetText();
mMenu.search();
}
return Super.MenuEvent(mkey, fromcontroller);
}
override String Represent()
{
return mEnter
? mEnter.GetText() .. NewSmallFont.GetCursor()
: mText;
}
String GetText() { return mText; }
private os_Menu mMenu;
private string mText;
}

View file

@ -0,0 +1,379 @@
/*
** menuinput.cpp
** The string input code
**
**---------------------------------------------------------------------------
** Copyright 2001-2010 Randy Heit
** 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 TextEnterMenu : Menu
{
const INPUTGRID_WIDTH = 13;
const INPUTGRID_HEIGHT = 5;
const Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+-=.,!?@'\":;[]()<>^#$%&*/_ \b";
String mEnterString;
int mEnterSize;
int mEnterPos;
bool mInputGridOkay;
int InputGridX;
int InputGridY;
int CursorSize;
bool AllowColors;
Font displayFont;
//=============================================================================
//
//
//
//=============================================================================
// [TP] Added allowcolors
private void Init(Menu parent, Font dpf, String textbuffer, int maxlen, bool showgrid, bool allowcolors)
{
Super.init(parent);
mEnterString = textbuffer;
mEnterSize = maxlen;
mInputGridOkay = (showgrid && (m_showinputgrid == 0)) || (m_showinputgrid >= 1);
if (mEnterString.Length() > 0)
{
InputGridX = INPUTGRID_WIDTH - 1;
InputGridY = INPUTGRID_HEIGHT - 1;
}
else
{
// If we are naming a new save, don't start the cursor on "end".
InputGridX = 0;
InputGridY = 0;
}
AllowColors = allowcolors; // [TP]
displayFont = dpf;
CursorSize = displayFont.StringWidth(displayFont.GetCursor());
}
// This had to be deprecated because the unit for maxlen is 8 pixels.
deprecated("3.8") static TextEnterMenu Open(Menu parent, String textbuffer, int maxlen, int sizemode, bool showgrid = false, bool allowcolors = false)
{
let me = new("TextEnterMenu");
me.Init(parent, Menu.OptionFont(), textbuffer, maxlen*8, showgrid, allowcolors);
return me;
}
static TextEnterMenu OpenTextEnter(Menu parent, Font displayfnt, String textbuffer, int maxlen, bool showgrid = false, bool allowcolors = false)
{
let me = new("TextEnterMenu");
me.Init(parent, displayfnt, textbuffer, maxlen, showgrid, allowcolors);
return me;
}
//=============================================================================
//
//
//
//=============================================================================
String GetText()
{
return mEnterString;
}
override bool TranslateKeyboardEvents()
{
return mInputGridOkay;
}
//=============================================================================
//
//
//
//=============================================================================
override bool OnUIEvent(UIEvent ev)
{
// Save game and player name string input
if (ev.Type == UIEvent.Type_Char)
{
mInputGridOkay = false;
AppendChar(ev.KeyChar);
return true;
}
int ch = ev.KeyChar;
if ((ev.Type == UIEvent.Type_KeyDown || ev.Type == UIEvent.Type_KeyRepeat) && ch == 8)
{
if (mEnterString.Length() > 0)
{
mEnterString.DeleteLastCharacter();
}
}
else if (ev.Type == UIEvent.Type_KeyDown)
{
if (ch == UIEvent.Key_ESCAPE)
{
Menu parent = mParentMenu;
Close();
parent.MenuEvent(MKEY_Abort, false);
return true;
}
else if (ch == 13)
{
if (mEnterString.Length() > 0)
{
// [TP] If we allow color codes, colorize the string now.
if (AllowColors)
mEnterString = mEnterString.Filter();
Menu parent = mParentMenu;
parent.MenuEvent(MKEY_Input, false);
Close();
return true;
}
}
}
if (ev.Type == UIEvent.Type_KeyDown || ev.Type == UIEvent.Type_KeyRepeat)
{
return true;
}
return Super.OnUIEvent(ev);
}
//=============================================================================
//
//
//
//=============================================================================
override bool MouseEvent(int type, int x, int y)
{
int cell_width = 18 * CleanXfac_1;
int cell_height = 16 * CleanYfac_1;
int screen_y = screen.GetHeight() - INPUTGRID_HEIGHT * cell_height;
int screen_x = (screen.GetWidth() - INPUTGRID_WIDTH * cell_width) / 2;
if (x >= screen_x && x < screen_x + INPUTGRID_WIDTH * cell_width && y >= screen_y)
{
InputGridX = (x - screen_x) / cell_width;
InputGridY = (y - screen_y) / cell_height;
if (type == MOUSE_Release)
{
if (MenuEvent(MKEY_Enter, true))
{
MenuSound("menu/choose");
if (m_use_mouse == 2) InputGridX = InputGridY = -1;
}
}
return true;
}
else
{
InputGridX = InputGridY = -1;
}
return Super.MouseEvent(type, x, y);
}
//=============================================================================
//
//
//
//=============================================================================
private void AppendChar(int ch)
{
String newstring = String.Format("%s%c%s", mEnterString, ch, displayFont.GetCursor());
if (mEnterSize < 0 || displayFont.StringWidth(newstring) < mEnterSize)
{
mEnterString.AppendCharacter(ch);
}
}
//=============================================================================
//
//
//
//=============================================================================
override bool MenuEvent (int key, bool fromcontroller)
{
String InputGridChars = Chars;
if (key == MKEY_Back)
{
mParentMenu.MenuEvent(MKEY_Abort, false);
return Super.MenuEvent(key, fromcontroller);
}
if (fromcontroller)
{
mInputGridOkay = true;
}
if (mInputGridOkay)
{
int ch;
if (InputGridX == -1 || InputGridY == -1)
{
InputGridX = InputGridY = 0;
}
switch (key)
{
case MKEY_Down:
InputGridY = (InputGridY + 1) % INPUTGRID_HEIGHT;
return true;
case MKEY_Up:
InputGridY = (InputGridY + INPUTGRID_HEIGHT - 1) % INPUTGRID_HEIGHT;
return true;
case MKEY_Right:
InputGridX = (InputGridX + 1) % INPUTGRID_WIDTH;
return true;
case MKEY_Left:
InputGridX = (InputGridX + INPUTGRID_WIDTH - 1) % INPUTGRID_WIDTH;
return true;
case MKEY_Clear:
if (mEnterString.Length() > 0)
{
mEnterString.DeleteLastCharacter();
}
return true;
case MKEY_Enter:
if (mInputGridOkay)
{
int ch = InputGridChars.ByteAt(InputGridX + InputGridY * INPUTGRID_WIDTH);
if (ch == 0) // end
{
if (mEnterString.Length() > 0)
{
Menu parent = mParentMenu;
parent.MenuEvent(MKEY_Input, false);
Close();
return true;
}
}
else if (ch == 8) // bs
{
if (mEnterString.Length() > 0)
{
mEnterString.DeleteLastCharacter();
}
}
else
{
AppendChar(ch);
}
}
return true;
default:
break;
}
}
return false;
}
//=============================================================================
//
//
//
//=============================================================================
override void Drawer ()
{
mParentMenu.Drawer();
if (mInputGridOkay)
{
String InputGridChars = Chars;
int cell_width = 18 * CleanXfac_1;
int cell_height = 16 * CleanYfac_1;
int top_padding = cell_height / 2 - displayFont.GetHeight() * CleanYfac_1 / 2;
// Darken the background behind the character grid.
screen.Dim(0, 0.8, 0, screen.GetHeight() - INPUTGRID_HEIGHT * cell_height, screen.GetWidth(), INPUTGRID_HEIGHT * cell_height);
if (InputGridX >= 0 && InputGridY >= 0)
{
// Highlight the background behind the selected character.
screen.Dim(Color(255,248,220), 0.6,
InputGridX * cell_width - INPUTGRID_WIDTH * cell_width / 2 + screen.GetWidth() / 2,
InputGridY * cell_height - INPUTGRID_HEIGHT * cell_height + screen.GetHeight(),
cell_width, cell_height);
}
for (int y = 0; y < INPUTGRID_HEIGHT; ++y)
{
int yy = y * cell_height - INPUTGRID_HEIGHT * cell_height + screen.GetHeight();
for (int x = 0; x < INPUTGRID_WIDTH; ++x)
{
int xx = x * cell_width - INPUTGRID_WIDTH * cell_width / 2 + screen.GetWidth() / 2;
int ch = InputGridChars.ByteAt(y * INPUTGRID_WIDTH + x);
int width = displayFont.GetCharWidth(ch);
// The highlighted character is yellow; the rest are dark gray.
int colr = (x == InputGridX && y == InputGridY) ? Font.CR_YELLOW : Font.CR_DARKGRAY;
Color palcolor = (x == InputGridX && y == InputGridY) ? Color(160, 120, 0) : Color(120, 120, 120);
if (ch > 32)
{
// Draw a normal character.
screen.DrawChar(displayFont, colr, xx + cell_width/2 - width*CleanXfac_1/2, yy + top_padding, ch, DTA_CleanNoMove_1, true);
}
else if (ch == 32)
{
// Draw the space as a box outline. We also draw it 50% wider than it really is.
int x1 = xx + cell_width/2 - width * CleanXfac_1 * 3 / 4;
int x2 = x1 + width * 3 * CleanXfac_1 / 2;
int y1 = yy + top_padding;
int y2 = y1 + displayFont.GetHeight() * CleanYfac_1;
screen.Clear(x1, y1, x2, y1+CleanYfac_1, palcolor); // top
screen.Clear(x1, y2, x2, y2+CleanYfac_1, palcolor); // bottom
screen.Clear(x1, y1+CleanYfac_1, x1+CleanXfac_1, y2, palcolor); // left
screen.Clear(x2-CleanXfac_1, y1+CleanYfac_1, x2, y2, palcolor); // right
}
else if (ch == 8 || ch == 0)
{
// Draw the backspace and end "characters".
String str = ch == 8 ? "BS" : "ED";
screen.DrawText(displayFont, colr,
xx + cell_width/2 - displayFont.StringWidth(str)*CleanXfac_1/2,
yy + top_padding, str, DTA_CleanNoMove_1, true);
}
}
}
}
Super.Drawer();
}
}