option search improvements

1. Top-level menu names are now properly handled.
2. Changing "Any or All terms" option now immediately updates the results.
3. Reformatted menu.zs to have tabs instead of spaces.
This commit is contained in:
Alexander 2019-03-17 16:17:12 +07:00 committed by Christoph Oelckers
parent b515ac662e
commit dbb93d6c08
5 changed files with 194 additions and 158 deletions

View file

@ -256,6 +256,7 @@ version "3.8"
#include "zscript/ui/menu/search/menu.zs" #include "zscript/ui/menu/search/menu.zs"
#include "zscript/ui/menu/search/searchfield.zs" #include "zscript/ui/menu/search/searchfield.zs"
#include "zscript/ui/menu/search/query.zs" #include "zscript/ui/menu/search/query.zs"
#include "zscript/ui/menu/search/anyoralloption.zs"
#include "zscript/ui/statscreen/statscreen.zs" #include "zscript/ui/statscreen/statscreen.zs"
#include "zscript/ui/statscreen/statscreen_coop.zs" #include "zscript/ui/statscreen/statscreen_coop.zs"

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)
{
mMenu.search();
}
return result;
}
private os_Menu mMenu;
}

View file

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

@ -19,8 +19,6 @@ class os_Query
str.Split(query.mQueryParts, " ", TOK_SKIPEMPTY); str.Split(query.mQueryParts, " ", TOK_SKIPEMPTY);
query.mText = str;
return query; return query;
} }
@ -31,8 +29,6 @@ class os_Query
: matchesAll(text); : matchesAll(text);
} }
string getText() { return mText; }
// private: ////////////////////////////////////////////////////////////////// // private: //////////////////////////////////////////////////////////////////
private bool matchesAny(string text) private bool matchesAny(string text)
@ -73,6 +69,5 @@ class os_Query
return contains; return contains;
} }
private string mText;
private Array<String> mQueryParts; private Array<String> mQueryParts;
} }

View file

@ -30,10 +30,9 @@ class os_SearchField : OptionMenuItemTextField
} }
if (mkey == Menu.MKEY_Input) if (mkey == Menu.MKEY_Input)
{ {
string text = mEnter.GetText(); mtext = mEnter.GetText();
let query = os_Query.fromString(text);
mMenu.search(query); mMenu.search();
} }
return Super.MenuEvent(mkey, fromcontroller); return Super.MenuEvent(mkey, fromcontroller);
@ -46,6 +45,8 @@ class os_SearchField : OptionMenuItemTextField
: mText; : mText;
} }
String GetText() { return mText; }
private os_Menu mMenu; private os_Menu mMenu;
private string mText; private string mText;
} }