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.
This commit is contained in:
Robert Müller 2023-07-02 23:15:27 +02:00
parent 9efab4964b
commit eb79b17308

View file

@ -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,12 +1134,19 @@ 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;
for(const auto &Col : s_aCols)
{
CUIRect Button;
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 = Col.m_ID;
if(ID == COL_ICON)
{
Button.Margin(1.0f, &Button);
const char *pIconType;
if(Item.m_IsLink || str_comp(Item.m_aFilename, "..") == 0)
@ -1146,48 +1156,39 @@ void CMenus::RenderDemoList(CUIRect MainView)
else
pIconType = FONT_ICON_FILM;
ColorRGBA IconColor(1.0f, 1.0f, 1.0f, 1.0f);
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(&FileIcon, pIconType, 12.0f, TEXTALIGN_ML);
UI()->DoLabel(&Button, pIconType, 12.0f, TEXTALIGN_ML);
TextRender()->SetRenderFlags(0);
TextRender()->TextColor(TextRender()->DefaultTextColor());
TextRender()->SetCurFont(nullptr);
for(int c = 0; c < NumCols; c++)
{
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;
int ID = s_aCols[c].m_ID;
if(ID == COL_DEMONAME)
{
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);
}
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);
}
}