Added ability to set visibility of menu options

This commit is contained in:
Marcus Minhorst 2025-07-06 20:46:21 -04:00 committed by Ricardo Luís Vaz Silva
commit 8182c02947
2 changed files with 194 additions and 74 deletions

View file

@ -21,7 +21,8 @@ class MenuItemBase : Object native ui version("2.4")
virtual bool CheckCoordinate(int x, int y) { return false; }
virtual void Ticker() {}
virtual void Drawer(bool selected) {}
virtual bool Selectable() {return false; }
virtual bool Selectable() { return false; }
virtual bool Visible() { return true; }
virtual bool Activate() { return false; }
virtual Name, int GetAction() { return mAction, 0; }
virtual bool SetString(int i, String s) { return false; }
@ -48,4 +49,4 @@ class MenuItemBase : Object native ui version("2.4")
enum MenudefColorRange
{
NO_COLOR = -1
}
}

View file

@ -82,6 +82,7 @@ class OptionMenuDescriptor : MenuDescriptor native
for (int i = 0; i < mItems.Size(); i++)
{
if (!mItems[i].Visible()) continue;
thiswidth = mItems[i].GetIndent();
if (thiswidth > widest) widest = thiswidth;
}
@ -171,7 +172,7 @@ class OptionMenu : Menu
{
i++;
}
while (i < mDesc.mItems.Size() && !mDesc.mItems[i].Selectable());
while (i < mDesc.mItems.Size() && !(mDesc.mItems[i].Selectable() && mDesc.mItems[i].Visible()));
if (i>=0 && i < mDesc.mItems.Size()) return i;
else return -1;
}
@ -182,30 +183,51 @@ class OptionMenu : Menu
//
//=============================================================================
int LastVisibleItem()
{
int i = mDesc.mItems.Size();
do
{
i--;
}
while (i >= 0 && !mDesc.mItems[i].Visible());
return i;
}
//=============================================================================
//
//
//
//=============================================================================
int RemainingVisibleItems(int start)
{
int count = 0;
for (int i = start+1; i < mDesc.mItems.Size(); i++)
{
if (mDesc.mItems[i].Visible())
{
count++;
}
}
return count;
}
//=============================================================================
//
//
//
//=============================================================================
override bool OnUIEvent(UIEvent ev)
{
if (ev.type == UIEvent.Type_WheelUp)
{
int scrollamt = MIN(2, mDesc.mScrollPos);
mDesc.mScrollPos -= scrollamt;
return true;
return MenuEvent(MKEY_Up, false);
}
else if (ev.type == UIEvent.Type_WheelDown)
{
if (CanScrollDown)
{
if (VisBottom >= 0 && VisBottom < (mDesc.mItems.Size()-2))
{
mDesc.mScrollPos += 2;
VisBottom += 2;
}
else if (VisBottom < mDesc.mItems.Size()-1)
{
mDesc.mScrollPos++;
VisBottom++;
}
}
return true;
return MenuEvent(MKEY_Down, false);
}
else if (ev.type == UIEvent.Type_Char)
{
@ -215,7 +237,7 @@ class OptionMenu : Menu
for (int i = 0; i < itemsNumber; ++i)
{
int index = (mDesc.mSelectedItem + direction * (i + 1) + itemsNumber) % itemsNumber;
if (!mDesc.mItems[index].Selectable()) continue;
if (!(mDesc.mItems[index].Selectable() && mDesc.mItems[index].Visible())) continue;
String label = StringTable.Localize(mDesc.mItems[index].mLabel);
int firstLabelCharacter = String.CharLower(label.GetNextCodePoint(0));
if (firstLabelCharacter == key)
@ -228,7 +250,7 @@ class OptionMenu : Menu
|| mDesc.mSelectedItem > VisBottom)
{
int pagesize = VisBottom - mDesc.mScrollPos - mDesc.mScrollTop;
mDesc.mScrollPos = clamp(mDesc.mSelectedItem - mDesc.mScrollTop - 1, 0, mDesc.mItems.size() - pagesize - 1);
mDesc.mScrollPos = clamp(mDesc.mSelectedItem - mDesc.mScrollTop - 1, 0, RemainingVisibleItems(mDesc.mSelectedItem) - pagesize - 1);
}
}
return Super.OnUIEvent(ev);
@ -247,72 +269,136 @@ class OptionMenu : Menu
switch (mkey)
{
case MKEY_Up:
{
if (mDesc.mSelectedItem == -1)
{
mDesc.mSelectedItem = FirstSelectable();
mDesc.mSelectedItem = LastVisibleItem();
break;
}
int previousSelection = mDesc.mSelectedItem;
do
{
--mDesc.mSelectedItem;
if (mDesc.mScrollPos > 0 &&
mDesc.mSelectedItem <= mDesc.mScrollTop + mDesc.mScrollPos)
mDesc.mSelectedItem--;
if (mDesc.mSelectedItem < 0)
{
mDesc.mScrollPos = MAX(mDesc.mSelectedItem - mDesc.mScrollTop - 1, 0);
mDesc.mSelectedItem = mDesc.mItems.Size() - 1;
}
}
while (!(mDesc.mItems[mDesc.mSelectedItem].Selectable() && mDesc.mItems[mDesc.mSelectedItem].Visible()) && mDesc.mSelectedItem != previousSelection);
if (mDesc.mSelectedItem < 0)
if (mDesc.mSelectedItem != previousSelection)
{
int viewTop = mDesc.mScrollTop + mDesc.mScrollPos;
if (previousSelection == FirstSelectable() && mDesc.mSelectedItem == LastVisibleItem())
{
// Figure out how many lines of text fit on the menu
int y = mDesc.mPosition;
if (y <= 0) y = DrawCaption(mDesc.mTitle, -y, false);
int lastrow = screen.GetHeight() - OptionHeight() * CleanYfac_1;
int rowheight = OptionMenuSettings.mLinespacing * CleanYfac_1 + 1;
int maxitems = (lastrow - y) / rowheight + 1;
Console.printf("%d %d", maxitems, RemainingVisibleItems(0));
if (maxitems < RemainingVisibleItems(0))
{
maxItems -= 2;
}
if (maxitems <= 0) maxitems = 1;
if (y <= 0)
int lastItem = LastVisibleItem();
int newTopIndex = 0;
int visibleItemsOnPage = 0;
for (int i = lastItem; i >= 0; i--)
{
y = DrawCaption(mDesc.mTitle, -y, false);
if (mDesc.mItems[i].Visible())
{
visibleItemsOnPage++;
if (visibleItemsOnPage >= maxitems)
{
newTopIndex = i;
break;
}
}
}
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;
mDesc.mScrollPos = newTopIndex - mDesc.mScrollTop;
}
else if (mDesc.mSelectedItem < viewTop)
{
int visibleLinesJumped = 0;
for (int i = previousSelection - 1; i >= mDesc.mSelectedItem; i--)
{
if (mDesc.mItems[i].Visible())
{
visibleLinesJumped++;
}
}
int visibleLinesToScroll = 0;
int newScrollPos = mDesc.mScrollPos;
while (visibleLinesToScroll < visibleLinesJumped && newScrollPos > 0)
{
newScrollPos--;
if ((newScrollPos + mDesc.mScrollTop) >= 0 && mDesc.mItems[newScrollPos + mDesc.mScrollTop].Visible())
{
visibleLinesToScroll++;
}
}
mDesc.mScrollPos = newScrollPos;
}
}
while (!mDesc.mItems[mDesc.mSelectedItem].Selectable() && mDesc.mSelectedItem != startedAt);
break;
}
case MKEY_Down:
{
if (mDesc.mSelectedItem == -1)
{
mDesc.mSelectedItem = FirstSelectable();
break;
}
int previousSelection = mDesc.mSelectedItem;
do
{
++mDesc.mSelectedItem;
mDesc.mSelectedItem++;
if (mDesc.mSelectedItem >= mDesc.mItems.Size())
mDesc.mSelectedItem = 0;
}
while (!(mDesc.mItems[mDesc.mSelectedItem].Selectable() && mDesc.mItems[mDesc.mSelectedItem].Visible()) && mDesc.mSelectedItem != previousSelection);
if (CanScrollDown && mDesc.mSelectedItem == VisBottom)
if (mDesc.mSelectedItem != previousSelection)
{
if (previousSelection == LastVisibleItem())
{
mDesc.mScrollPos++;
VisBottom++;
mDesc.mScrollPos = 0;
}
if (mDesc.mSelectedItem >= mDesc.mItems.Size())
else if (mDesc.mSelectedItem > VisBottom && VisBottom != -1)
{
if (startedAt == -1)
int visibleLinesJumped = 0;
for (int i = previousSelection + 1; i <= mDesc.mSelectedItem; i++)
{
mDesc.mSelectedItem = -1;
mDesc.mScrollPos = -1;
break;
if (mDesc.mItems[i].Visible())
{
visibleLinesJumped++;
}
}
else
int visibleLinesToScroll = 0;
int newScrollPos = mDesc.mScrollPos;
while (visibleLinesToScroll < visibleLinesJumped && newScrollPos < mDesc.mItems.Size() - 1)
{
mDesc.mSelectedItem = 0;
mDesc.mScrollPos = 0;
newScrollPos++;
if ((newScrollPos + mDesc.mScrollTop) < mDesc.mItems.Size() && mDesc.mItems[newScrollPos + mDesc.mScrollTop].Visible())
{
visibleLinesToScroll++;
}
}
mDesc.mScrollPos = newScrollPos;
}
}
while (!mDesc.mItems[mDesc.mSelectedItem].Selectable() && mDesc.mSelectedItem != startedAt);
break;
}
case MKEY_PageUp:
if (mDesc.mScrollPos > 0)
@ -325,9 +411,9 @@ class OptionMenu : Menu
if (mDesc.mSelectedItem != -1)
{
mDesc.mSelectedItem = mDesc.mScrollTop + mDesc.mScrollPos + 1;
while (!mDesc.mItems[mDesc.mSelectedItem].Selectable())
while (!(mDesc.mItems[mDesc.mSelectedItem].Selectable() && mDesc.mItems[mDesc.mSelectedItem].Visible()))
{
if (++mDesc.mSelectedItem >= mDesc.mItems.Size())
if (++mDesc.mSelectedItem >= RemainingVisibleItems(0))
{
mDesc.mSelectedItem = 0;
}
@ -344,7 +430,9 @@ class OptionMenu : Menu
if (CanScrollDown)
{
int pagesize = VisBottom - mDesc.mScrollPos - mDesc.mScrollTop;
mDesc.mScrollPos += pagesize;
if (pagesize > 0) mDesc.mScrollPos += pagesize;
else mDesc.mScrollPos++;
if (mDesc.mScrollPos + mDesc.mScrollTop + pagesize > mDesc.mItems.Size())
{
mDesc.mScrollPos = mDesc.mItems.Size() - mDesc.mScrollTop - pagesize;
@ -352,7 +440,7 @@ class OptionMenu : Menu
if (mDesc.mSelectedItem != -1)
{
mDesc.mSelectedItem = mDesc.mScrollTop + mDesc.mScrollPos;
while (!mDesc.mItems[mDesc.mSelectedItem].Selectable())
while (!(mDesc.mItems[mDesc.mSelectedItem].Selectable() && mDesc.mItems[mDesc.mSelectedItem].Visible()))
{
if (++mDesc.mSelectedItem >= mDesc.mItems.Size())
{
@ -368,13 +456,13 @@ class OptionMenu : Menu
break;
case MKEY_Enter:
if (mDesc.mSelectedItem >= 0 && mDesc.mItems[mDesc.mSelectedItem].Activate())
if (mDesc.mSelectedItem >= 0 && mDesc.mItems[mDesc.mSelectedItem].Activate())
{
return true;
}
// fall through to default
default:
if (mDesc.mSelectedItem >= 0 &&
if (mDesc.mSelectedItem >= 0 &&
mDesc.mItems[mDesc.mSelectedItem].MenuEvent(mkey, fromcontroller)) return true;
return Super.MenuEvent(mkey, fromcontroller);
}
@ -386,7 +474,6 @@ class OptionMenu : Menu
return true;
}
//=============================================================================
//
//
@ -404,26 +491,50 @@ class OptionMenu : Menu
}
else
{
int yline = (y / OptionMenuSettings.mLinespacing);
if (yline >= mDesc.mScrollTop)
int visual_line_clicked = y / OptionMenuSettings.mLinespacing;
int current_visual_line = 0;
for (int i = 0; i < mDesc.mItems.Size(); i++)
{
yline += mDesc.mScrollPos;
}
if (yline >= 0 && yline < mDesc.mItems.Size() && mDesc.mItems[yline].Selectable())
{
if (yline != mDesc.mSelectedItem)
if (i == mDesc.mScrollTop)
{
mDesc.mSelectedItem = yline;
i += mDesc.mScrollPos;
if (i >= mDesc.mItems.Size())
{
break;
}
}
mDesc.mItems[yline].MouseEvent(type, x, y);
return true;
if (!mDesc.mItems[i].Visible())
{
continue;
}
if (current_visual_line == visual_line_clicked)
{
if (mDesc.mItems[i].Selectable())
{
if (i != mDesc.mSelectedItem)
{
MenuSound ("menu/cursor");
mDesc.mSelectedItem = i;
}
mDesc.mItems[i].MouseEvent(type, x, y);
return true;
}
break;
}
current_visual_line++;
}
}
mDesc.mSelectedItem = -1;
return Super.MouseEvent(type, x, y);
}
//=============================================================================
//
//
@ -453,7 +564,7 @@ class OptionMenu : Menu
//=============================================================================
//
// draws and/or measures the caption.
// draws and/or measures the caption.
//
//=============================================================================
@ -476,7 +587,6 @@ class OptionMenu : Menu
//
//
//=============================================================================
override void Drawer ()
{
int y = mDesc.mPosition;
@ -494,17 +604,26 @@ class OptionMenu : Menu
int lastrow = screen.GetHeight() - OptionHeight() * CleanYfac_1;
int i;
int lastDrawnItemIndex = -1;
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
if (i >= mDesc.mItems.Size()) break; // skipped beyond end of menu
}
if (!mDesc.mItems[i].Visible())
{
continue;
}
lastDrawnItemIndex = i;
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 (cur_indent >= 0 && isSelected && mDesc.mItems[i].Selectable() && mDesc.mItems[i].Visible())
{
if (((MenuTime() % 8) < 6) || GetCurrentMenu() != self)
{
@ -515,8 +634,8 @@ class OptionMenu : Menu
}
CanScrollUp = (mDesc.mScrollPos > 0);
CanScrollDown = (i < mDesc.mItems.Size());
VisBottom = i - 1;
CanScrollDown = LastVisibleItem() > i;
VisBottom = lastDrawnItemIndex;
if (CanScrollUp)
{