mirror of
https://github.com/ddnet/ddnet.git
synced 2024-10-21 00:08:19 +00:00
55726e8da3
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.
218 lines
6.1 KiB
C++
218 lines
6.1 KiB
C++
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
|
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
|
#include <base/system.h>
|
|
#include <base/vmath.h>
|
|
|
|
#include <engine/config.h>
|
|
#include <engine/shared/config.h>
|
|
|
|
#include <game/localization.h>
|
|
|
|
#include "ui_listbox.h"
|
|
|
|
CListBox::CListBox()
|
|
{
|
|
m_ScrollOffset = vec2(0.0f, 0.0f);
|
|
m_ListBoxUpdateScroll = false;
|
|
m_FilterOffset = 0.0f;
|
|
m_HasHeader = false;
|
|
m_AutoSpacing = 0.0f;
|
|
m_ScrollbarIsShown = false;
|
|
m_Active = true;
|
|
}
|
|
|
|
void CListBox::DoBegin(const CUIRect *pRect)
|
|
{
|
|
// setup the variables
|
|
m_ListBoxView = *pRect;
|
|
}
|
|
|
|
void CListBox::DoHeader(const CUIRect *pRect, const char *pTitle, float HeaderHeight, float Spacing)
|
|
{
|
|
CUIRect View = *pRect;
|
|
CUIRect Header;
|
|
|
|
// background
|
|
View.HSplitTop(HeaderHeight + Spacing, &Header, 0);
|
|
Header.Draw(ColorRGBA(0.0f, 0.0f, 0.0f, 0.15f), m_BackgroundCorners & IGraphics::CORNER_T, 5.0f);
|
|
|
|
// draw header
|
|
View.HSplitTop(HeaderHeight, &Header, &View);
|
|
UI()->DoLabel(&Header, pTitle, Header.h * CUI::ms_FontmodHeight * 0.8f, TEXTALIGN_MC);
|
|
|
|
View.HSplitTop(Spacing, &Header, &View);
|
|
|
|
// setup the variables
|
|
m_ListBoxView = View;
|
|
m_HasHeader = true;
|
|
}
|
|
|
|
void CListBox::DoSpacing(float Spacing)
|
|
{
|
|
CUIRect View = m_ListBoxView;
|
|
View.HSplitTop(Spacing, 0, &View);
|
|
m_ListBoxView = View;
|
|
}
|
|
|
|
void CListBox::DoFooter(const char *pBottomText, float FooterHeight)
|
|
{
|
|
m_pBottomText = pBottomText;
|
|
m_FooterHeight = FooterHeight;
|
|
}
|
|
|
|
void CListBox::DoStart(float RowHeight, int NumItems, int ItemsPerRow, int RowsPerScroll, int SelectedIndex, const CUIRect *pRect, bool Background, int BackgroundCorners)
|
|
{
|
|
CUIRect View;
|
|
if(pRect)
|
|
View = *pRect;
|
|
else
|
|
View = m_ListBoxView;
|
|
|
|
// background
|
|
m_BackgroundCorners = BackgroundCorners;
|
|
if(Background)
|
|
View.Draw(ColorRGBA(0.0f, 0.0f, 0.0f, 0.15f), m_BackgroundCorners & (m_HasHeader ? IGraphics::CORNER_B : IGraphics::CORNER_ALL), 5.0f);
|
|
|
|
// draw footers
|
|
if(m_pBottomText)
|
|
{
|
|
CUIRect Footer;
|
|
View.HSplitBottom(m_FooterHeight, &View, &Footer);
|
|
Footer.VSplitLeft(10.0f, 0, &Footer);
|
|
UI()->DoLabel(&Footer, m_pBottomText, Footer.h * CUI::ms_FontmodHeight * 0.8f, TEXTALIGN_MC);
|
|
}
|
|
|
|
// setup the variables
|
|
m_ListBoxView = View;
|
|
m_RowView = {};
|
|
m_ListBoxSelectedIndex = SelectedIndex;
|
|
m_ListBoxNewSelected = SelectedIndex;
|
|
m_ListBoxNewSelOffset = 0;
|
|
m_ListBoxItemIndex = 0;
|
|
m_ListBoxRowHeight = RowHeight;
|
|
m_ListBoxNumItems = NumItems;
|
|
m_ListBoxItemsPerRow = ItemsPerRow;
|
|
m_ListBoxDoneEvents = false;
|
|
m_ListBoxItemActivated = false;
|
|
m_ListBoxItemSelected = false;
|
|
|
|
// handle input
|
|
if(m_Active)
|
|
{
|
|
if(UI()->ConsumeHotkey(CUI::HOTKEY_DOWN))
|
|
m_ListBoxNewSelOffset += 1;
|
|
else if(UI()->ConsumeHotkey(CUI::HOTKEY_UP))
|
|
m_ListBoxNewSelOffset -= 1;
|
|
else if(UI()->ConsumeHotkey(CUI::HOTKEY_PAGE_UP))
|
|
m_ListBoxNewSelOffset = -ItemsPerRow * RowsPerScroll * 4;
|
|
else if(UI()->ConsumeHotkey(CUI::HOTKEY_PAGE_DOWN))
|
|
m_ListBoxNewSelOffset = ItemsPerRow * RowsPerScroll * 4;
|
|
else if(UI()->ConsumeHotkey(CUI::HOTKEY_HOME))
|
|
m_ListBoxNewSelOffset = 1 - m_ListBoxNumItems;
|
|
else if(UI()->ConsumeHotkey(CUI::HOTKEY_END))
|
|
m_ListBoxNewSelOffset = m_ListBoxNumItems - 1;
|
|
}
|
|
|
|
// setup the scrollbar
|
|
m_ScrollOffset = vec2(0.0f, 0.0f);
|
|
CScrollRegionParams ScrollParams;
|
|
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);
|
|
m_ListBoxView.y += m_ScrollOffset.y;
|
|
}
|
|
|
|
CListboxItem CListBox::DoNextRow()
|
|
{
|
|
CListboxItem Item = {};
|
|
|
|
if(m_ListBoxItemIndex % m_ListBoxItemsPerRow == 0)
|
|
m_ListBoxView.HSplitTop(m_ListBoxRowHeight, &m_RowView, &m_ListBoxView);
|
|
m_ScrollRegion.AddRect(m_RowView);
|
|
if(m_ListBoxUpdateScroll && m_ListBoxSelectedIndex == m_ListBoxItemIndex)
|
|
{
|
|
m_ScrollRegion.ScrollHere(CScrollRegion::SCROLLHERE_KEEP_IN_VIEW);
|
|
m_ListBoxUpdateScroll = false;
|
|
}
|
|
|
|
m_RowView.VSplitLeft(m_RowView.w / (m_ListBoxItemsPerRow - m_ListBoxItemIndex % m_ListBoxItemsPerRow), &Item.m_Rect, &m_RowView);
|
|
|
|
Item.m_Selected = m_ListBoxSelectedIndex == m_ListBoxItemIndex;
|
|
Item.m_Visible = !m_ScrollRegion.IsRectClipped(Item.m_Rect);
|
|
|
|
m_ListBoxItemIndex++;
|
|
return Item;
|
|
}
|
|
|
|
CListboxItem CListBox::DoNextItem(const void *pId, bool Selected)
|
|
{
|
|
if(m_AutoSpacing > 0.0f && m_ListBoxItemIndex > 0)
|
|
DoSpacing(m_AutoSpacing);
|
|
|
|
const int ThisItemIndex = m_ListBoxItemIndex;
|
|
if(Selected)
|
|
{
|
|
if(m_ListBoxSelectedIndex == m_ListBoxNewSelected)
|
|
m_ListBoxNewSelected = ThisItemIndex;
|
|
m_ListBoxSelectedIndex = ThisItemIndex;
|
|
}
|
|
|
|
CListboxItem Item = DoNextRow();
|
|
bool ItemClicked = false;
|
|
|
|
if(Item.m_Visible && UI()->DoButtonLogic(pId, 0, &Item.m_Rect))
|
|
{
|
|
ItemClicked = true;
|
|
m_ListBoxNewSelected = ThisItemIndex;
|
|
m_ListBoxItemSelected = true;
|
|
m_Active = true;
|
|
}
|
|
else
|
|
ItemClicked = false;
|
|
|
|
// process input, regard selected index
|
|
if(m_ListBoxSelectedIndex == ThisItemIndex)
|
|
{
|
|
if(m_Active && !m_ListBoxDoneEvents)
|
|
{
|
|
m_ListBoxDoneEvents = true;
|
|
|
|
if(UI()->ConsumeHotkey(CUI::HOTKEY_ENTER) || (ItemClicked && Input()->MouseDoubleClick()))
|
|
{
|
|
m_ListBoxItemActivated = true;
|
|
UI()->SetActiveItem(nullptr);
|
|
}
|
|
}
|
|
|
|
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())
|
|
{
|
|
Item.m_Rect.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.33f), IGraphics::CORNER_ALL, 5.0f);
|
|
}
|
|
|
|
return Item;
|
|
}
|
|
|
|
CListboxItem CListBox::DoSubheader()
|
|
{
|
|
CListboxItem Item = DoNextRow();
|
|
Item.m_Rect.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.2f), IGraphics::CORNER_NONE, 0.0f);
|
|
return Item;
|
|
}
|
|
|
|
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)
|
|
{
|
|
m_ListBoxNewSelected = clamp((m_ListBoxNewSelected == -1 ? 0 : m_ListBoxNewSelected) + m_ListBoxNewSelOffset, 0, m_ListBoxNumItems - 1);
|
|
ScrollToSelected();
|
|
}
|
|
return m_ListBoxNewSelected;
|
|
}
|