From 9efab4964bfafcff65181a6f02f3009eb2afdd15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Sun, 2 Jul 2023 23:13:05 +0200 Subject: [PATCH 1/2] Add parameter to force showing scrollbar with listbox --- src/game/client/ui_listbox.cpp | 3 ++- src/game/client/ui_listbox.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/game/client/ui_listbox.cpp b/src/game/client/ui_listbox.cpp index b73611809..8014a23dd 100644 --- a/src/game/client/ui_listbox.cpp +++ b/src/game/client/ui_listbox.cpp @@ -60,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, int BackgroundCorners) +void CListBox::DoStart(float RowHeight, int NumItems, int ItemsPerRow, int RowsPerScroll, int SelectedIndex, const CUIRect *pRect, bool Background, int BackgroundCorners, bool ForceShowScrollbar) { CUIRect View; if(pRect) @@ -119,6 +119,7 @@ void CListBox::DoStart(float RowHeight, int NumItems, int ItemsPerRow, int RowsP ScrollParams.m_Active = m_Active; ScrollParams.m_ScrollbarWidth = ScrollbarWidthMax(); ScrollParams.m_ScrollUnit = (m_ListBoxRowHeight + m_AutoSpacing) * RowsPerScroll; + ScrollParams.m_Flags = ForceShowScrollbar ? CScrollRegionParams::FLAG_CONTENT_STATIC_WIDTH : 0; m_ScrollRegion.Begin(&m_ListBoxView, &m_ScrollOffset, &ScrollParams); m_ListBoxView.y += m_ScrollOffset.y; } diff --git a/src/game/client/ui_listbox.h b/src/game/client/ui_listbox.h index fff29f26a..e50aa246a 100644 --- a/src/game/client/ui_listbox.h +++ b/src/game/client/ui_listbox.h @@ -51,7 +51,7 @@ 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, 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, bool ForceShowScrollbar = false); void ScrollToSelected() { m_ListBoxUpdateScroll = true; } CListboxItem DoNextItem(const void *pID, bool Selected = false); CListboxItem DoSubheader(); From eb79b17308bd9c1a8a00a9c39852ebe3631cd907 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Sun, 2 Jul 2023 23:15:27 +0200 Subject: [PATCH 2/2] Improve demo browser layout Use separate columns for icons and spacing like in the server browser. Always show scrollbar for more consistent layout. Show ellipsis if filename is too long, also for the filename shown in the demo player. Hide number of markers and length if the demo is invalid. --- src/game/client/components/menus_demo.cpp | 149 +++++++++++----------- 1 file changed, 75 insertions(+), 74 deletions(-) diff --git a/src/game/client/components/menus_demo.cpp b/src/game/client/components/menus_demo.cpp index 96f7f08e8..701bcfe7f 100644 --- a/src/game/client/components/menus_demo.cpp +++ b/src/game/client/components/menus_demo.cpp @@ -593,7 +593,11 @@ void CMenus::RenderDemoPlayer(CUIRect MainView) DemoPlayer()->GetDemoName(aDemoName, sizeof(aDemoName)); char aBuf[IO_MAX_PATH_LENGTH + 128]; str_format(aBuf, sizeof(aBuf), Localize("Demofile: %s"), aDemoName); - UI()->DoLabel(&NameBar, aBuf, Button.h * 0.5f, TEXTALIGN_ML); + SLabelProperties Props; + Props.m_MaxWidth = NameBar.w; + Props.m_EllipsisAtEnd = true; + Props.m_EnableWidthCheck = false; + UI()->DoLabel(&NameBar, aBuf, Button.h * 0.5f, TEXTALIGN_ML, Props); if(IncreaseDemoSpeed) { @@ -1043,69 +1047,69 @@ void CMenus::RenderDemoList(CUIRect MainView) int m_Direction; float m_Width; CUIRect m_Rect; - CUIRect m_Spacer; }; enum { - COL_DEMONAME = 0, + COL_ICON = 0, + COL_DEMONAME, COL_MARKERS, COL_LENGTH, COL_DATE, }; + static CListBox s_ListBox; static CColumn s_aCols[] = { - {COL_DEMONAME, SORT_DEMONAME, Localizable("Demo"), 0, 0.0f, {0}, {0}}, - {COL_MARKERS, SORT_MARKERS, Localizable("Markers"), 1, 75.0f, {0}, {0}}, - {COL_LENGTH, SORT_LENGTH, Localizable("Length"), 1, 75.0f, {0}, {0}}, - {COL_DATE, SORT_DATE, Localizable("Date"), 1, 160.0f, {0}, {0}}, + {-1, -1, "", -1, 2.0f, {0}}, + {COL_ICON, -1, "", -1, ms_ListheaderHeight, {0}}, + {-1, -1, "", -1, 2.0f, {0}}, + {COL_DEMONAME, SORT_DEMONAME, Localizable("Demo"), 0, 0.0f, {0}}, + {-1, -1, "", 1, 2.0f, {0}}, + {COL_MARKERS, SORT_MARKERS, Localizable("Markers"), 1, 75.0f, {0}}, + {-1, -1, "", 1, 2.0f, {0}}, + {COL_LENGTH, SORT_LENGTH, Localizable("Length"), 1, 75.0f, {0}}, + {-1, -1, "", 1, 2.0f, {0}}, + {COL_DATE, SORT_DATE, Localizable("Date"), 1, 160.0f, {0}}, + {-1, -1, "", 1, s_ListBox.ScrollbarWidthMax(), {0}}, }; - Headers.Draw(ColorRGBA(0.0f, 0, 0, 0.15f), 0, 0); - - int NumCols = std::size(s_aCols); + Headers.Draw(ColorRGBA(0.0f, 0.0f, 0.0f, 0.15f), IGraphics::CORNER_NONE, 0.0f); // do layout - for(int i = 0; i < NumCols; i++) + for(auto &Col : s_aCols) { - if(s_aCols[i].m_Direction == -1) + if(Col.m_Direction == -1) { - Headers.VSplitLeft(s_aCols[i].m_Width, &s_aCols[i].m_Rect, &Headers); - - if(i + 1 < NumCols) - { - Headers.VSplitLeft(2, &s_aCols[i].m_Spacer, &Headers); - } + Headers.VSplitLeft(Col.m_Width, &Col.m_Rect, &Headers); } } - for(int i = NumCols - 1; i >= 0; i--) + for(int i = std::size(s_aCols) - 1; i >= 0; i--) { if(s_aCols[i].m_Direction == 1) { Headers.VSplitRight(s_aCols[i].m_Width, &Headers, &s_aCols[i].m_Rect); - Headers.VSplitRight(2, &Headers, &s_aCols[i].m_Spacer); } } - for(int i = 0; i < NumCols; i++) + for(auto &Col : s_aCols) { - if(s_aCols[i].m_Direction == 0) - s_aCols[i].m_Rect = Headers; + if(Col.m_Direction == 0) + Col.m_Rect = Headers; } // do headers - for(int i = 0; i < NumCols; i++) + for(auto &Col : s_aCols) { - if(DoButton_GridHeader(s_aCols[i].m_Caption, Localize(s_aCols[i].m_Caption), g_Config.m_BrDemoSort == s_aCols[i].m_Sort, &s_aCols[i].m_Rect)) + if(DoButton_GridHeader(&Col.m_ID, Col.m_Caption, g_Config.m_BrDemoSort == Col.m_Sort, &Col.m_Rect)) { - if(s_aCols[i].m_Sort != -1) + if(Col.m_Sort != -1) { - if(g_Config.m_BrDemoSort == s_aCols[i].m_Sort) + if(g_Config.m_BrDemoSort == Col.m_Sort) g_Config.m_BrDemoSortOrder ^= 1; else g_Config.m_BrDemoSortOrder = 0; - g_Config.m_BrDemoSort = s_aCols[i].m_Sort; + g_Config.m_BrDemoSort = Col.m_Sort; } // Don't rescan in order to keep fetched headers, just resort @@ -1114,13 +1118,12 @@ void CMenus::RenderDemoList(CUIRect MainView) } } - static CListBox s_ListBox; if(m_DemolistSelectedReveal) { s_ListBox.ScrollToSelected(); m_DemolistSelectedReveal = false; } - s_ListBox.DoStart(ms_ListheaderHeight, m_vDemos.size(), 1, 3, m_DemolistSelectedIndex, &ListBox, false); + s_ListBox.DoStart(ms_ListheaderHeight, m_vDemos.size(), 1, 3, m_DemolistSelectedIndex, &ListBox, false, IGraphics::CORNER_ALL, true); int ItemIndex = -1; for(auto &Item : m_vDemos) @@ -1131,63 +1134,61 @@ void CMenus::RenderDemoList(CUIRect MainView) if(!ListItem.m_Visible) continue; - CUIRect Row = ListItem.m_Rect; - CUIRect FileIcon; - Row.VSplitLeft(Row.h, &FileIcon, &Row); - Row.VSplitLeft(5.0f, 0, &Row); - FileIcon.Margin(1.0f, &FileIcon); - FileIcon.x += 2.0f; - - const char *pIconType; - if(Item.m_IsLink || str_comp(Item.m_aFilename, "..") == 0) - pIconType = FONT_ICON_FOLDER_TREE; - else if(Item.m_IsDir) - pIconType = FONT_ICON_FOLDER; - else - pIconType = FONT_ICON_FILM; - - ColorRGBA IconColor(1.0f, 1.0f, 1.0f, 1.0f); - if(!Item.m_IsDir && (!Item.m_InfosLoaded || !Item.m_Valid)) - IconColor = ColorRGBA(0.6f, 0.6f, 0.6f, 1.0f); // not loaded - - TextRender()->SetCurFont(TextRender()->GetFont(TEXT_FONT_ICON_FONT)); - TextRender()->TextColor(IconColor); - TextRender()->SetRenderFlags(ETextRenderFlags::TEXT_RENDER_FLAG_ONLY_ADVANCE_WIDTH | ETextRenderFlags::TEXT_RENDER_FLAG_NO_X_BEARING | ETextRenderFlags::TEXT_RENDER_FLAG_NO_Y_BEARING); - UI()->DoLabel(&FileIcon, pIconType, 12.0f, TEXTALIGN_ML); - TextRender()->SetRenderFlags(0); - TextRender()->TextColor(TextRender()->DefaultTextColor()); - TextRender()->SetCurFont(nullptr); - - for(int c = 0; c < NumCols; c++) + for(const auto &Col : s_aCols) { CUIRect Button; - Button.x = s_aCols[c].m_Rect.x; - Button.y = Row.y; - Button.h = Row.h; - Button.w = s_aCols[c].m_Rect.w; + Button.x = Col.m_Rect.x; + Button.y = ListItem.m_Rect.y; + Button.h = ListItem.m_Rect.h; + Button.w = Col.m_Rect.w; - int ID = s_aCols[c].m_ID; + int ID = Col.m_ID; - if(ID == COL_DEMONAME) + if(ID == COL_ICON) { - Button.x += FileIcon.w + 6.0f; - CTextCursor Cursor; - TextRender()->SetCursor(&Cursor, Button.x, Button.y + (Button.h - 12.0f) / 2.f, 12.0f, TEXTFLAG_RENDER | TEXTFLAG_STOP_AT_END); - Cursor.m_LineWidth = Button.w; - TextRender()->TextEx(&Cursor, Item.m_aName, -1); + Button.Margin(1.0f, &Button); + + const char *pIconType; + if(Item.m_IsLink || str_comp(Item.m_aFilename, "..") == 0) + pIconType = FONT_ICON_FOLDER_TREE; + else if(Item.m_IsDir) + pIconType = FONT_ICON_FOLDER; + else + pIconType = FONT_ICON_FILM; + + ColorRGBA IconColor; + if(!Item.m_IsDir && (!Item.m_InfosLoaded || !Item.m_Valid)) + IconColor = ColorRGBA(0.6f, 0.6f, 0.6f, 1.0f); // not loaded + else + IconColor = ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f); + + TextRender()->SetCurFont(TextRender()->GetFont(TEXT_FONT_ICON_FONT)); + TextRender()->TextColor(IconColor); + TextRender()->SetRenderFlags(ETextRenderFlags::TEXT_RENDER_FLAG_ONLY_ADVANCE_WIDTH | ETextRenderFlags::TEXT_RENDER_FLAG_NO_X_BEARING | ETextRenderFlags::TEXT_RENDER_FLAG_NO_Y_BEARING); + UI()->DoLabel(&Button, pIconType, 12.0f, TEXTALIGN_ML); + TextRender()->SetRenderFlags(0); + TextRender()->TextColor(TextRender()->DefaultTextColor()); + TextRender()->SetCurFont(nullptr); } - else if(ID == COL_MARKERS && !Item.m_IsDir && Item.m_InfosLoaded) + else if(ID == COL_DEMONAME) + { + SLabelProperties Props; + Props.m_MaxWidth = Button.w; + Props.m_EllipsisAtEnd = true; + Props.m_EnableWidthCheck = false; + UI()->DoLabel(&Button, Item.m_aName, 12.0f, TEXTALIGN_ML, Props); + } + else if(ID == COL_MARKERS && !Item.m_IsDir && Item.m_InfosLoaded && Item.m_Valid) { char aBuf[3]; str_format(aBuf, sizeof(aBuf), "%d", Item.NumMarkers()); Button.VMargin(4.0f, &Button); UI()->DoLabel(&Button, aBuf, 12.0f, TEXTALIGN_MR); } - else if(ID == COL_LENGTH && !Item.m_IsDir && Item.m_InfosLoaded) + else if(ID == COL_LENGTH && !Item.m_IsDir && Item.m_InfosLoaded && Item.m_Valid) { - int Length = Item.Length(); char aBuf[32]; - str_time((int64_t)Length * 100, TIME_HOURS, aBuf, sizeof(aBuf)); + str_time((int64_t)Item.Length() * 100, TIME_HOURS, aBuf, sizeof(aBuf)); Button.VMargin(4.0f, &Button); UI()->DoLabel(&Button, aBuf, 12.0f, TEXTALIGN_MR); } @@ -1195,7 +1196,7 @@ void CMenus::RenderDemoList(CUIRect MainView) { char aBuf[64]; str_timestamp_ex(Item.m_Date, aBuf, sizeof(aBuf), FORMAT_SPACE); - Button.VSplitRight(24.0f, &Button, 0); + Button.VMargin(4.0f, &Button); UI()->DoLabel(&Button, aBuf, 12.0f, TEXTALIGN_MR); } }