Simplify list box activation handling

Store the list box active state inside `CListBox` instead of tracking it separately with a pointer.

Allow activating list boxes by clicking the scrollbar. Previously it was only possible to activate list boxes by selecting an item.

Fix country selection list box in players settings not being deactivated properly when name/clan edit boxes are active, because wrong UI element IDs were being used.
This commit is contained in:
Robert Müller 2023-06-07 18:08:55 +02:00
parent 161f8442b7
commit 55726e8da3
8 changed files with 47 additions and 45 deletions

View file

@ -1806,7 +1806,7 @@ void CMenus::RenderThemeSelection(CUIRect MainView)
static CListBox s_ListBox;
s_ListBox.DoHeader(&MainView, Localize("Theme"), 20.0f);
s_ListBox.DoStart(20.0f, vThemes.size(), 1, 3, SelectedTheme, nullptr, true);
s_ListBox.DoStart(20.0f, vThemes.size(), 1, 3, SelectedTheme);
for(int i = 0; i < (int)vThemes.size(); i++)
{

View file

@ -184,10 +184,9 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
g_Config.m_UiToolboxPage = (g_Config.m_UiToolboxPage + 3 + Direction) % 3;
}
bool ListBoxUsed = !UI()->IsPopupOpen();
static CListBox s_ListBox;
s_ListBox.DoStart(ms_ListheaderHeight, NumServers, 1, 3, -1, &View, false, &ListBoxUsed);
s_ListBox.SetActive(!UI()->IsPopupOpen());
s_ListBox.DoStart(ms_ListheaderHeight, NumServers, 1, 3, -1, &View, false);
int NumPlayers = 0;
static int s_PrevSelectedIndex = -1;
@ -224,7 +223,7 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
pItem->m_pUIElement = UI()->GetNewUIElement(UIRectCount);
}
const CListboxItem ListItem = s_ListBox.DoNextItem(pItem, str_comp(pItem->m_aAddress, g_Config.m_UiServerAddress) == 0, &ListBoxUsed);
const CListboxItem ListItem = s_ListBox.DoNextItem(pItem, str_comp(pItem->m_aAddress, g_Config.m_UiServerAddress) == 0);
if(ListItem.m_Selected)
m_SelectedIndex = i;
@ -984,11 +983,9 @@ CUI::EPopupMenuFunctionResult CMenus::PopupCountrySelection(void *pContext, CUIR
SPopupCountrySelectionContext *pPopupContext = static_cast<SPopupCountrySelectionContext *>(pContext);
CMenus *pMenus = pPopupContext->m_pMenus;
bool ListBoxUsed = Active;
static CListBox s_ListBox;
int OldSelected = -1;
s_ListBox.DoStart(50.0f, pMenus->m_pClient->m_CountryFlags.Num(), 8, 1, OldSelected, &View, false, &ListBoxUsed);
s_ListBox.SetActive(Active);
s_ListBox.DoStart(50.0f, pMenus->m_pClient->m_CountryFlags.Num(), 8, 1, -1, &View, false);
if(pPopupContext->m_New)
{
@ -999,10 +996,8 @@ CUI::EPopupMenuFunctionResult CMenus::PopupCountrySelection(void *pContext, CUIR
for(size_t i = 0; i < pMenus->m_pClient->m_CountryFlags.Num(); ++i)
{
const CCountryFlags::CCountryFlag *pEntry = pMenus->m_pClient->m_CountryFlags.GetByIndex(i);
if(pEntry->m_CountryCode == pPopupContext->m_Selection)
OldSelected = i;
const CListboxItem Item = s_ListBox.DoNextItem(pEntry, OldSelected >= 0 && (size_t)OldSelected == i, &ListBoxUsed);
const CListboxItem Item = s_ListBox.DoNextItem(pEntry, pEntry->m_CountryCode == pPopupContext->m_Selection);
if(!Item.m_Visible)
continue;
@ -1020,7 +1015,7 @@ CUI::EPopupMenuFunctionResult CMenus::PopupCountrySelection(void *pContext, CUIR
}
const int NewSelected = s_ListBox.DoEnd();
pPopupContext->m_Selection = pMenus->m_pClient->m_CountryFlags.GetByIndex(NewSelected)->m_CountryCode;
pPopupContext->m_Selection = NewSelected >= 0 ? pMenus->m_pClient->m_CountryFlags.GetByIndex(NewSelected)->m_CountryCode : -1;
if(s_ListBox.WasItemSelected() || s_ListBox.WasItemActivated())
{
g_Config.m_BrFilterCountry = 1;

View file

@ -363,15 +363,13 @@ void CMenus::RenderSettingsPlayer(CUIRect MainView)
m_Dummy ^= 1;
}
static bool s_ListBoxUsed = false;
if(UI()->CheckActiveItem(pClan) || UI()->CheckActiveItem(pName))
s_ListBoxUsed = false;
// country flag selector
MainView.HSplitTop(20.0f, 0, &MainView);
int OldSelected = -1;
static CListBox s_ListBox;
s_ListBox.DoStart(50.0f, m_pClient->m_CountryFlags.Num(), 10, 3, OldSelected, &MainView, true, &s_ListBoxUsed);
if(UI()->CheckActiveItem(&s_ClanInput) || UI()->CheckActiveItem(&s_NameInput))
s_ListBox.SetActive(false);
s_ListBox.DoStart(50.0f, m_pClient->m_CountryFlags.Num(), 10, 3, OldSelected, &MainView);
for(size_t i = 0; i < m_pClient->m_CountryFlags.Num(); ++i)
{
@ -379,7 +377,7 @@ void CMenus::RenderSettingsPlayer(CUIRect MainView)
if(pEntry->m_CountryCode == *pCountry)
OldSelected = i;
const CListboxItem Item = s_ListBox.DoNextItem(&pEntry->m_CountryCode, OldSelected >= 0 && (size_t)OldSelected == i, &s_ListBoxUsed);
const CListboxItem Item = s_ListBox.DoNextItem(&pEntry->m_CountryCode, OldSelected >= 0 && (size_t)OldSelected == i);
if(!Item.m_Visible)
continue;
@ -1565,15 +1563,16 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
static const float sc_RowHeightResList = 22.0f;
static const float sc_FontSizeResListHeader = 12.0f;
static const float sc_FontSizeResList = 10.0f;
bool ListBoxUsed = !UI()->IsPopupOpen();
int OldSelected = -1;
{
int G = std::gcd(g_Config.m_GfxScreenWidth, g_Config.m_GfxScreenHeight);
str_format(aBuf, sizeof(aBuf), "%s: %dx%d @%dhz %d bit (%d:%d)", Localize("Current"), (int)(g_Config.m_GfxScreenWidth * Graphics()->ScreenHiDPIScale()), (int)(g_Config.m_GfxScreenHeight * Graphics()->ScreenHiDPIScale()), g_Config.m_GfxScreenRefreshRate, g_Config.m_GfxColorDepth, g_Config.m_GfxScreenWidth / G, g_Config.m_GfxScreenHeight / G);
UI()->DoLabel(&ModeLabel, aBuf, sc_FontSizeResListHeader, TEXTALIGN_MC);
}
UI()->DoLabel(&ModeLabel, aBuf, sc_FontSizeResListHeader, TEXTALIGN_MC);
s_ListBox.DoStart(sc_RowHeightResList, s_NumNodes, 1, 3, OldSelected, &ModeList, true, &ListBoxUsed);
int OldSelected = -1;
s_ListBox.SetActive(!UI()->IsPopupOpen());
s_ListBox.DoStart(sc_RowHeightResList, s_NumNodes, 1, 3, OldSelected, &ModeList);
for(int i = 0; i < s_NumNodes; ++i)
{
@ -1586,7 +1585,7 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
OldSelected = i;
}
const CListboxItem Item = s_ListBox.DoNextItem(&s_aModes[i], OldSelected == i, &ListBoxUsed);
const CListboxItem Item = s_ListBox.DoNextItem(&s_aModes[i], OldSelected == i);
if(!Item.m_Visible)
continue;
@ -2059,7 +2058,7 @@ bool CMenus::RenderLanguageSelection(CUIRect MainView)
const int OldSelected = s_SelectedLanguage;
s_ListBox.DoStart(24.0f, g_Localization.Languages().size(), 1, 3, s_SelectedLanguage, &MainView, true);
s_ListBox.DoStart(24.0f, g_Localization.Languages().size(), 1, 3, s_SelectedLanguage, &MainView);
for(const auto &Language : g_Localization.Languages())
{

View file

@ -18,6 +18,7 @@ CListBox::CListBox()
m_HasHeader = false;
m_AutoSpacing = 0.0f;
m_ScrollbarIsShown = false;
m_Active = true;
}
void CListBox::DoBegin(const CUIRect *pRect)
@ -59,7 +60,7 @@ void CListBox::DoFooter(const char *pBottomText, float FooterHeight)
m_FooterHeight = FooterHeight;
}
void CListBox::DoStart(float RowHeight, int NumItems, int ItemsPerRow, int RowsPerScroll, int SelectedIndex, const CUIRect *pRect, bool Background, bool *pActive, int BackgroundCorners)
void CListBox::DoStart(float RowHeight, int NumItems, int ItemsPerRow, int RowsPerScroll, int SelectedIndex, const CUIRect *pRect, bool Background, int BackgroundCorners)
{
CUIRect View;
if(pRect)
@ -96,7 +97,7 @@ void CListBox::DoStart(float RowHeight, int NumItems, int ItemsPerRow, int RowsP
m_ListBoxItemSelected = false;
// handle input
if(!pActive || *pActive)
if(m_Active)
{
if(UI()->ConsumeHotkey(CUI::HOTKEY_DOWN))
m_ListBoxNewSelOffset += 1;
@ -115,7 +116,7 @@ void CListBox::DoStart(float RowHeight, int NumItems, int ItemsPerRow, int RowsP
// setup the scrollbar
m_ScrollOffset = vec2(0.0f, 0.0f);
CScrollRegionParams ScrollParams;
ScrollParams.m_Active = !pActive || *pActive;
ScrollParams.m_Active = m_Active;
ScrollParams.m_ScrollbarWidth = ScrollbarWidthMax();
ScrollParams.m_ScrollUnit = (m_ListBoxRowHeight + m_AutoSpacing) * RowsPerScroll;
m_ScrollRegion.Begin(&m_ListBoxView, &m_ScrollOffset, &ScrollParams);
@ -144,7 +145,7 @@ CListboxItem CListBox::DoNextRow()
return Item;
}
CListboxItem CListBox::DoNextItem(const void *pId, bool Selected, bool *pActive)
CListboxItem CListBox::DoNextItem(const void *pId, bool Selected)
{
if(m_AutoSpacing > 0.0f && m_ListBoxItemIndex > 0)
DoSpacing(m_AutoSpacing);
@ -165,18 +166,15 @@ CListboxItem CListBox::DoNextItem(const void *pId, bool Selected, bool *pActive)
ItemClicked = true;
m_ListBoxNewSelected = ThisItemIndex;
m_ListBoxItemSelected = true;
if(pActive)
*pActive = true;
m_Active = true;
}
else
ItemClicked = false;
const bool ProcessInput = !pActive || *pActive;
// process input, regard selected index
if(m_ListBoxSelectedIndex == ThisItemIndex)
{
if(ProcessInput && !m_ListBoxDoneEvents)
if(m_Active && !m_ListBoxDoneEvents)
{
m_ListBoxDoneEvents = true;
@ -187,7 +185,7 @@ CListboxItem CListBox::DoNextItem(const void *pId, bool Selected, bool *pActive)
}
}
Item.m_Rect.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, ProcessInput ? 0.5f : 0.33f), IGraphics::CORNER_ALL, 5.0f);
Item.m_Rect.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, m_Active ? 0.5f : 0.33f), IGraphics::CORNER_ALL, 5.0f);
}
if(UI()->HotItem() == pId && !m_ScrollRegion.IsAnimating())
{
@ -207,6 +205,8 @@ CListboxItem CListBox::DoSubheader()
int CListBox::DoEnd()
{
m_ScrollRegion.End();
m_Active |= m_ScrollRegion.Params().m_Active;
m_ScrollbarIsShown = m_ScrollRegion.IsScrollbarShown();
if(m_ListBoxNewSelOffset != 0 && m_ListBoxNumItems > 0 && m_ListBoxSelectedIndex == m_ListBoxNewSelected)
{

View file

@ -38,6 +38,7 @@ private:
float m_FilterOffset;
int m_BackgroundCorners;
bool m_HasHeader;
bool m_Active;
protected:
CListboxItem DoNextRow();
@ -50,14 +51,19 @@ public:
void DoAutoSpacing(float Spacing = 20.0f) { m_AutoSpacing = Spacing; }
void DoSpacing(float Spacing = 20.0f);
void DoFooter(const char *pBottomText, float FooterHeight = 20.0f); // call before DoStart to create a footer
void DoStart(float RowHeight, int NumItems, int ItemsPerRow, int RowsPerScroll, int SelectedIndex, const CUIRect *pRect = nullptr, bool Background = true, bool *pActive = nullptr, int BackgroundCorners = IGraphics::CORNER_ALL);
void DoStart(float RowHeight, int NumItems, int ItemsPerRow, int RowsPerScroll, int SelectedIndex, const CUIRect *pRect = nullptr, bool Background = true, int BackgroundCorners = IGraphics::CORNER_ALL);
void ScrollToSelected() { m_ListBoxUpdateScroll = true; }
CListboxItem DoNextItem(const void *pID, bool Selected = false, bool *pActive = nullptr);
CListboxItem DoNextItem(const void *pID, bool Selected = false);
CListboxItem DoSubheader();
int DoEnd();
bool FilterMatches(const char *pNeedle) const;
// Active state must be set before calling DoStart.
bool Active() const { return m_Active; }
void SetActive(bool Active) { m_Active = Active; }
bool WasItemSelected() const { return m_ListBoxItemSelected; }
bool WasItemActivated() const { return m_ListBoxItemActivated; }
bool ScrollbarIsShown() const { return m_ScrollbarIsShown; }
float ScrollbarWidth() const { return ScrollbarIsShown() ? ScrollbarWidthMax() : 0.0f; }
float ScrollbarWidthMax() const { return 20.0f; }

View file

@ -157,6 +157,7 @@ void CScrollRegion::End()
m_SliderGrabPos.y = UI()->MouseY() - Slider.y;
m_AnimTargetScrollY = m_ScrollY;
m_AnimTime = 0.0f;
m_Params.m_Active = true;
}
}
else if(InsideRail && UI()->MouseButtonClicked(0))
@ -167,6 +168,7 @@ void CScrollRegion::End()
m_SliderGrabPos.y = Slider.h / 2.0f;
m_AnimTargetScrollY = m_ScrollY;
m_AnimTime = 0.0f;
m_Params.m_Active = true;
}
else if(UI()->CheckActiveItem(pID) && !UI()->MouseButton(0))
{

View file

@ -134,6 +134,7 @@ public:
bool IsRectClipped(const CUIRect &Rect) const;
bool IsScrollbarShown() const;
bool IsAnimating() const;
const CScrollRegionParams &Params() const { return m_Params; }
};
#endif

View file

@ -4664,8 +4664,7 @@ void CEditor::RenderFileDialog()
// filebox
static CListBox s_ListBox;
static bool s_ListBoxUsed = false;
s_ListBoxUsed = !UI()->IsPopupOpen();
s_ListBox.SetActive(!UI()->IsPopupOpen());
if(m_FileDialogStorageType == IStorage::TYPE_SAVE)
{
@ -4791,11 +4790,11 @@ void CEditor::RenderFileDialog()
}
}
s_ListBox.DoStart(15.0f, m_vpFilteredFileList.size(), 1, 5, m_FilesSelectedIndex, &View, false, &s_ListBoxUsed);
s_ListBox.DoStart(15.0f, m_vpFilteredFileList.size(), 1, 5, m_FilesSelectedIndex, &View, false);
for(size_t i = 0; i < m_vpFilteredFileList.size(); i++)
{
const CListboxItem Item = s_ListBox.DoNextItem(m_vpFilteredFileList[i], m_FilesSelectedIndex >= 0 && (size_t)m_FilesSelectedIndex == i, &s_ListBoxUsed);
const CListboxItem Item = s_ListBox.DoNextItem(m_vpFilteredFileList[i], m_FilesSelectedIndex >= 0 && (size_t)m_FilesSelectedIndex == i);
if(!Item.m_Visible)
continue;
@ -4920,12 +4919,12 @@ void CEditor::RenderFileDialog()
ButtonBar.VSplitRight(ButtonSpacing, &ButtonBar, nullptr);
ButtonBar.VSplitRight(50.0f, &ButtonBar, &Button);
if(DoButton_Editor(&s_CancelButton, "Cancel", 0, &Button, 0, nullptr) || (s_ListBoxUsed && UI()->ConsumeHotkey(CUI::HOTKEY_ESCAPE)))
if(DoButton_Editor(&s_CancelButton, "Cancel", 0, &Button, 0, nullptr) || (s_ListBox.Active() && UI()->ConsumeHotkey(CUI::HOTKEY_ESCAPE)))
m_Dialog = DIALOG_NONE;
ButtonBar.VSplitRight(ButtonSpacing, &ButtonBar, nullptr);
ButtonBar.VSplitRight(50.0f, &ButtonBar, &Button);
if(DoButton_Editor(&s_RefreshButton, "Refresh", 0, &Button, 0, nullptr) || (s_ListBoxUsed && (Input()->KeyIsPressed(KEY_F5) || (Input()->ModifierIsPressed() && Input()->KeyIsPressed(KEY_R)))))
if(DoButton_Editor(&s_RefreshButton, "Refresh", 0, &Button, 0, nullptr) || (s_ListBox.Active() && (Input()->KeyIsPressed(KEY_F5) || (Input()->ModifierIsPressed() && Input()->KeyIsPressed(KEY_R)))))
FilelistPopulate(m_FileDialogLastPopulatedStorageType, true);
ButtonBar.VSplitRight(ButtonSpacing, &ButtonBar, nullptr);
@ -4943,7 +4942,7 @@ void CEditor::RenderFileDialog()
static CUI::SConfirmPopupContext s_ConfirmDeletePopupContext;
if(m_FilesSelectedIndex >= 0 && m_vpFilteredFileList[m_FilesSelectedIndex]->m_StorageType == IStorage::TYPE_SAVE && !m_vpFilteredFileList[m_FilesSelectedIndex]->m_IsLink && str_comp(m_vpFilteredFileList[m_FilesSelectedIndex]->m_aFilename, "..") != 0)
{
if(DoButton_Editor(&s_DeleteButton, "Delete", 0, &Button, 0, nullptr) || (s_ListBoxUsed && UI()->ConsumeHotkey(CUI::HOTKEY_DELETE)))
if(DoButton_Editor(&s_DeleteButton, "Delete", 0, &Button, 0, nullptr) || (s_ListBox.Active() && UI()->ConsumeHotkey(CUI::HOTKEY_DELETE)))
{
s_ConfirmDeletePopupContext.Reset();
s_ConfirmDeletePopupContext.YesNoButtons();