mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-11-28 06:53:40 +00:00
added option search menu
This commit is contained in:
parent
540e180fb1
commit
73d81d3983
6 changed files with 368 additions and 1 deletions
|
@ -51,6 +51,9 @@ CVAR(Int, developer, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
|
|||
// [RH] Feature control cvars
|
||||
CVAR(Bool, var_friction, true, CVAR_SERVERINFO);
|
||||
|
||||
// Option Search
|
||||
CVAR(Bool, os_isanyof, true, CVAR_ARCHIVE);
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -138,4 +141,3 @@ CUSTOM_CVAR(String, language, "auto", CVAR_ARCHIVE | CVAR_NOINITCALL | CVAR_GLOB
|
|||
if (Level->info != nullptr) Level->LevelName = Level->info->LookupLevelName();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -378,6 +378,8 @@ OptionMenu "OptionsMenu" protected
|
|||
Submenu "$OPTMNU_DISPLAY", "VideoOptions"
|
||||
Submenu "$OPTMNU_VIDEO", "VideoModeMenu"
|
||||
StaticText " "
|
||||
Submenu "$OS_TITLE", "os_Menu"
|
||||
StaticText " "
|
||||
SafeCommand "$OPTMNU_DEFAULTS", "reset2defaults"
|
||||
SafeCommand "$OPTMNU_RESETTOSAVED", "reset2saved"
|
||||
Command "$OPTMNU_CONSOLE", "menuconsole"
|
||||
|
@ -2606,3 +2608,21 @@ OptionString "LanguageOptions"
|
|||
"ptb", "Português do Brasil (PTB)"
|
||||
"rus", "Русский (RU)"
|
||||
}
|
||||
|
||||
/*=======================================
|
||||
*
|
||||
* Option Search menu
|
||||
*
|
||||
*=======================================*/
|
||||
|
||||
OptionMenu "os_Menu"
|
||||
{
|
||||
Class "os_Menu"
|
||||
Title "$OS_TITLE"
|
||||
}
|
||||
|
||||
OptionValue "os_isanyof_values"
|
||||
{
|
||||
0, "$OS_ALL"
|
||||
1, "$OS_ANY"
|
||||
}
|
||||
|
|
|
@ -253,6 +253,10 @@ version "3.8"
|
|||
#include "zscript/ui/menu/reverbedit.zs"
|
||||
#include "zscript/ui/menu/textentermenu.zs"
|
||||
|
||||
#include "zscript/ui/menu/search/menu.zs"
|
||||
#include "zscript/ui/menu/search/searchfield.zs"
|
||||
#include "zscript/ui/menu/search/query.zs"
|
||||
|
||||
#include "zscript/ui/statscreen/statscreen.zs"
|
||||
#include "zscript/ui/statscreen/statscreen_coop.zs"
|
||||
#include "zscript/ui/statscreen/statscreen_dm.zs"
|
||||
|
|
212
wadsrc/static/zscript/ui/menu/search/menu.zs
Normal file
212
wadsrc/static/zscript/ui/menu/search/menu.zs
Normal file
|
@ -0,0 +1,212 @@
|
|||
//=============================================================================
|
||||
//
|
||||
// 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(os_Query query)
|
||||
{
|
||||
mDesc.mItems.clear();
|
||||
|
||||
addSearchField(query.getText());
|
||||
|
||||
string path = StringTable.Localize("$OPTMNU_TITLE");
|
||||
bool isAnyTermMatches = mIsAnyOfItem.mCVar.GetBool();
|
||||
bool found = listOptions(mDesc, "MainMenu", query, path, isAnyTermMatches);
|
||||
|
||||
if (!found) { addNoResultsItem(mDesc); }
|
||||
|
||||
mDesc.CalcIndent();
|
||||
}
|
||||
|
||||
private void addSearchField(string query = "")
|
||||
{
|
||||
string searchLabel = StringTable.Localize("$OS_LABEL");
|
||||
let searchField = new("os_SearchField").Init(searchLabel, self, query);
|
||||
|
||||
mIsAnyOfItem = new("OptionMenuItemOption").Init("", "os_isanyof", "os_isanyof_values");
|
||||
|
||||
mDesc.mItems.push(searchField);
|
||||
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();
|
||||
string newPath = (actionN == "Optionsmenu")
|
||||
? StringTable.Localize("$OPTMNU_TITLE")
|
||||
: StringTable.Localize("$OS_MAIN");
|
||||
|
||||
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)
|
||||
{
|
||||
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 OptionMenuItemOption mIsAnyOfItem;
|
||||
}
|
78
wadsrc/static/zscript/ui/menu/search/query.zs
Normal file
78
wadsrc/static/zscript/ui/menu/search/query.zs
Normal file
|
@ -0,0 +1,78 @@
|
|||
//=============================================================================
|
||||
//
|
||||
// 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);
|
||||
|
||||
query.mText = str;
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
bool matches(string text, bool isSearchForAny)
|
||||
{
|
||||
return isSearchForAny
|
||||
? matchesAny(text)
|
||||
: matchesAll(text);
|
||||
}
|
||||
|
||||
string getText() { return mText; }
|
||||
|
||||
// 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)
|
||||
{
|
||||
str .toLower();
|
||||
substr.toLower();
|
||||
|
||||
bool contains = (str.IndexOf(substr) != -1);
|
||||
|
||||
return contains;
|
||||
}
|
||||
|
||||
private string mText;
|
||||
private Array<String> mQueryParts;
|
||||
}
|
51
wadsrc/static/zscript/ui/menu/search/searchfield.zs
Normal file
51
wadsrc/static/zscript/ui/menu/search/searchfield.zs
Normal file
|
@ -0,0 +1,51 @@
|
|||
//=============================================================================
|
||||
//
|
||||
// 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(), SmallFont, mText, -1, fromcontroller);
|
||||
mEnter.ActivateMenu();
|
||||
return true;
|
||||
}
|
||||
if (mkey == Menu.MKEY_Input)
|
||||
{
|
||||
string text = mEnter.GetText();
|
||||
let query = os_Query.fromString(text);
|
||||
|
||||
mMenu.search(query);
|
||||
}
|
||||
|
||||
return Super.MenuEvent(mkey, fromcontroller);
|
||||
}
|
||||
|
||||
override String Represent()
|
||||
{
|
||||
return mEnter
|
||||
? mEnter.GetText() .. SmallFont.GetCursor()
|
||||
: mText;
|
||||
}
|
||||
|
||||
private os_Menu mMenu;
|
||||
private string mText;
|
||||
}
|
Loading…
Reference in a new issue