Demo browser: Show markers (fixes #329)

- Fetch Headers button
- Display Markers & Length columns
- Display footer info
- Don't rescan directory when not required
- Clean up code a bit
This commit is contained in:
def 2019-01-08 20:12:21 +01:00 committed by Dennis Felsing
parent d6db284324
commit f9d9fee314
7 changed files with 140 additions and 82 deletions

View file

@ -23,15 +23,15 @@ public:
return parent::insert(item, partition_binary(all(), item));
}
int add_unsorted(const T& item)
{
return parent::add(item);
}
void sort_range()
{
sort(all());
}
int add_unsorted(const T& item)
{
return parent::add(item);
}
void sort_range()
{
sort(all());
}
/*

View file

@ -67,7 +67,7 @@ public:
virtual bool IsPlaying() const = 0;
virtual const CInfo *BaseInfo() const = 0;
virtual void GetDemoName(char *pBuffer, int BufferSize) const = 0;
virtual bool GetDemoInfo(class IStorage *pStorage, const char *pFilename, int StorageType, CDemoHeader *pDemoHeader) const = 0;
virtual bool GetDemoInfo(class IStorage *pStorage, const char *pFilename, int StorageType, CDemoHeader *pDemoHeader, CTimelineMarkers *pTimelineMarkers) const = 0;
virtual int GetDemoType() const = 0;
};

View file

@ -61,7 +61,7 @@ MACRO_CONFIG_INT(BrSort, br_sort, 4, 0, 256, CFGFLAG_SAVE|CFGFLAG_CLIENT, "")
MACRO_CONFIG_INT(BrSortOrder, br_sort_order, 1, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "")
MACRO_CONFIG_INT(BrMaxRequests, br_max_requests, 25, 0, 1000, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Number of requests to use when refreshing server browser")
MACRO_CONFIG_INT(BrDemoSort, br_demo_sort, 0, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "")
MACRO_CONFIG_INT(BrDemoSort, br_demo_sort, 0, 0, 3, CFGFLAG_SAVE|CFGFLAG_CLIENT, "")
MACRO_CONFIG_INT(BrDemoSortOrder, br_demo_sort_order, 0, 0, 1, CFGFLAG_SAVE|CFGFLAG_CLIENT, "")
MACRO_CONFIG_INT(SndBufferSize, snd_buffer_size, 512, 128, 32768, CFGFLAG_SAVE|CFGFLAG_CLIENT, "Sound buffer size")

View file

@ -914,18 +914,20 @@ void CDemoPlayer::GetDemoName(char *pBuffer, int BufferSize) const
str_copy(pBuffer, pExtractedName, Length);
}
bool CDemoPlayer::GetDemoInfo(class IStorage *pStorage, const char *pFilename, int StorageType, CDemoHeader *pDemoHeader) const
bool CDemoPlayer::GetDemoInfo(class IStorage *pStorage, const char *pFilename, int StorageType, CDemoHeader *pDemoHeader, CTimelineMarkers *pTimelineMarkers) const
{
if(!pDemoHeader)
if(!pDemoHeader || !pTimelineMarkers)
return false;
mem_zero(pDemoHeader, sizeof(CDemoHeader));
mem_zero(pTimelineMarkers, sizeof(CTimelineMarkers));
IOHANDLE File = pStorage->OpenFile(pFilename, IOFLAG_READ, StorageType);
if(!File)
return false;
io_read(File, pDemoHeader, sizeof(CDemoHeader));
io_read(File, pTimelineMarkers, sizeof(CTimelineMarkers));
io_close(File);
return !(mem_comp(pDemoHeader->m_aMarker, gs_aHeaderMarker, sizeof(gs_aHeaderMarker)) || pDemoHeader->m_Version < gs_OldVersion);
}

View file

@ -135,7 +135,7 @@ public:
int SetPos(float Percent);
const CInfo *BaseInfo() const { return &m_Info.m_Info; }
void GetDemoName(char *pBuffer, int BufferSize) const;
bool GetDemoInfo(class IStorage *pStorage, const char *pFilename, int StorageType, CDemoHeader *pDemoHeader) const;
bool GetDemoInfo(class IStorage *pStorage, const char *pFilename, int StorageType, CDemoHeader *pDemoHeader, CTimelineMarkers *pTimelineMarkers) const;
const char *GetDemoFileName() { return m_aFilename; };
int GetDemoType() const;

View file

@ -152,6 +152,14 @@ class CMenus : public CComponent
char m_aFilterString[25];
// demo
enum
{
SORT_DEMONAME=0,
SORT_MARKERS,
SORT_LENGTH,
SORT_DATE,
};
struct CDemoItem
{
char m_aFilename[128];
@ -163,39 +171,51 @@ class CMenus : public CComponent
bool m_InfosLoaded;
bool m_Valid;
CDemoHeader m_Info;
CTimelineMarkers m_TimelineMarkers;
bool operator<(const CDemoItem &Other)
int NumMarkers() const
{
if (g_Config.m_BrDemoSort)
{
if (g_Config.m_BrDemoSortOrder)
{
return !str_comp(m_aFilename, "..") ? true : !str_comp(Other.m_aFilename, "..") ? false :
m_IsDir && !Other.m_IsDir ? true : !m_IsDir && Other.m_IsDir ? false :
m_Date < Other.m_Date;
}
else
{
return !str_comp(m_aFilename, "..") ? true : !str_comp(Other.m_aFilename, "..") ? false :
m_IsDir && !Other.m_IsDir ? true : !m_IsDir && Other.m_IsDir ? false :
m_Date > Other.m_Date;
}
}
else
{
if (g_Config.m_BrDemoSortOrder)
{
return !str_comp(m_aFilename, "..") ? true : !str_comp(Other.m_aFilename, "..") ? false :
m_IsDir && !Other.m_IsDir ? true : !m_IsDir && Other.m_IsDir ? false :
str_comp_nocase(m_aFilename, Other.m_aFilename) < 0;
}
else
{
return !str_comp(m_aFilename, "..") ? true : !str_comp(Other.m_aFilename, "..") ? false :
m_IsDir && !Other.m_IsDir ? true : !m_IsDir && Other.m_IsDir ? false :
str_comp_nocase(m_aFilename, Other.m_aFilename) > 0;
}
}
return ((m_TimelineMarkers.m_aNumTimelineMarkers[0]<<24)&0xFF000000) | ((m_TimelineMarkers.m_aNumTimelineMarkers[1]<<16)&0xFF0000) |
((m_TimelineMarkers.m_aNumTimelineMarkers[2]<<8)&0xFF00) | (m_TimelineMarkers.m_aNumTimelineMarkers[3]&0xFF);
}
int Length() const
{
return ((m_Info.m_aLength[0]<<24)&0xFF000000) | ((m_Info.m_aLength[1]<<16)&0xFF0000) |
((m_Info.m_aLength[2]<<8)&0xFF00) | (m_Info.m_aLength[3]&0xFF);
}
bool operator<(const CDemoItem &Other) const
{
if(!str_comp(m_aFilename, ".."))
return true;
if(!str_comp(Other.m_aFilename, ".."))
return false;
if(m_IsDir && !Other.m_IsDir)
return true;
if(!m_IsDir && Other.m_IsDir)
return false;
const CDemoItem &Left = g_Config.m_BrDemoSortOrder ? Other : *this;
const CDemoItem &Right = g_Config.m_BrDemoSortOrder ? *this : Other;
if(g_Config.m_BrDemoSort == SORT_DEMONAME)
return str_comp_nocase(Left.m_aFilename, Right.m_aFilename) < 0;
if(g_Config.m_BrDemoSort == SORT_DATE)
return Left.m_Date < Right.m_Date;
if(!Other.m_InfosLoaded)
return m_InfosLoaded;
if(!m_InfosLoaded)
return !Other.m_InfosLoaded;
if(g_Config.m_BrDemoSort == SORT_MARKERS)
return Left.NumMarkers() < Right.NumMarkers();
if(g_Config.m_BrDemoSort == SORT_LENGTH)
return Left.Length() < Right.Length();
// Unknown sort
return true;
}
};
@ -247,6 +267,7 @@ class CMenus : public CComponent
// found in menus_demo.cpp
static bool DemoFilterChat(const void *pData, int Size, void *pUser);
bool FetchHeader(CDemoItem &Item);
void RenderDemoPlayer(CUIRect MainView);
void RenderDemoList(CUIRect MainView);

View file

@ -419,7 +419,6 @@ void CMenus::RenderDemoPlayer(CUIRect MainView)
if(DoButton_DemoPlayer(&s_ExitButton, Localize("Close"), 0, &Button))
{
Client()->Disconnect();
DemolistPopulate();
DemolistOnUpdate(false);
}
@ -744,6 +743,18 @@ void CMenus::DemolistOnUpdate(bool Reset)
m_DemolistSelectedIsDir = m_DemolistSelectedIndex < 0 ? false : m_lDemos[m_DemolistSelectedIndex].m_IsDir;
}
bool CMenus::FetchHeader(CDemoItem &Item)
{
if(!Item.m_InfosLoaded)
{
char aBuffer[512];
str_format(aBuffer, sizeof(aBuffer), "%s/%s", m_aCurrentDemoFolder, Item.m_aFilename);
Item.m_Valid = DemoPlayer()->GetDemoInfo(Storage(), aBuffer, Item.m_StorageType, &Item.m_Info, &Item.m_TimelineMarkers);
Item.m_InfosLoaded = true;
}
return Item.m_Valid;
}
void CMenus::RenderDemoList(CUIRect MainView)
{
static int s_Inited = 0;
@ -757,40 +768,34 @@ void CMenus::RenderDemoList(CUIRect MainView)
char aFooterLabel[128] = {0};
if(m_DemolistSelectedIndex >= 0)
{
CDemoItem *Item = &m_lDemos[m_DemolistSelectedIndex];
if(str_comp(Item->m_aFilename, "..") == 0)
CDemoItem &Item = m_lDemos[m_DemolistSelectedIndex];
if(str_comp(Item.m_aFilename, "..") == 0)
str_copy(aFooterLabel, Localize("Parent Folder"), sizeof(aFooterLabel));
else if(m_DemolistSelectedIsDir)
str_copy(aFooterLabel, Localize("Folder"), sizeof(aFooterLabel));
else if(!FetchHeader(Item))
str_copy(aFooterLabel, Localize("Invalid Demo"), sizeof(aFooterLabel));
else
{
if(!Item->m_InfosLoaded)
{
char aBuffer[512];
str_format(aBuffer, sizeof(aBuffer), "%s/%s", m_aCurrentDemoFolder, Item->m_aFilename);
Item->m_Valid = DemoPlayer()->GetDemoInfo(Storage(), aBuffer, Item->m_StorageType, &Item->m_Info);
Item->m_InfosLoaded = true;
}
if(!Item->m_Valid)
str_copy(aFooterLabel, Localize("Invalid Demo"), sizeof(aFooterLabel));
else
str_copy(aFooterLabel, Localize("Demo details"), sizeof(aFooterLabel));
}
str_copy(aFooterLabel, Localize("Demo details"), sizeof(aFooterLabel));
}
// render background
RenderTools()->DrawUIRect(&MainView, ms_ColorTabbarActive, CUI::CORNER_ALL, 10.0f);
MainView.Margin(10.0f, &MainView);
CUIRect ButtonBar, RefreshRect, PlayRect, DeleteRect, RenameRect, ListBox;
CUIRect ButtonBar, RefreshRect, FetchRect, PlayRect, DeleteRect, RenameRect, LabelRect, ListBox;
MainView.HSplitBottom(ms_ButtonHeight+5.0f, &MainView, &ButtonBar);
ButtonBar.HSplitTop(5.0f, 0, &ButtonBar);
ButtonBar.VSplitRight(130.0f, &ButtonBar, &PlayRect);
ButtonBar.VSplitLeft(130.0f, &RefreshRect, &ButtonBar);
ButtonBar.VSplitLeft(10.0f, 0, &ButtonBar);
ButtonBar.VSplitLeft(130.0f, &FetchRect, &ButtonBar);
ButtonBar.VSplitLeft(10.0f, 0, &ButtonBar);
ButtonBar.VSplitLeft(120.0f, &DeleteRect, &ButtonBar);
ButtonBar.VSplitLeft(10.0f, 0, &ButtonBar);
ButtonBar.VSplitLeft(120.0f, &RenameRect, &ButtonBar);
ButtonBar.VSplitLeft(10.0f, 0, &ButtonBar);
ButtonBar.VSplitLeft(120.0f, &LabelRect, &ButtonBar);
MainView.HSplitBottom(140.0f, &ListBox, &MainView);
// render demo info
@ -800,7 +805,8 @@ void CMenus::RenderDemoList(CUIRect MainView)
if(!m_DemolistSelectedIsDir && m_DemolistSelectedIndex >= 0 && m_lDemos[m_DemolistSelectedIndex].m_Valid)
{
CUIRect Left, Right, Labels;
MainView.Margin(20.0f, &MainView);
MainView.VMargin(20.0f, &MainView);
MainView.HMargin(10.0f, &MainView);
MainView.VSplitMid(&Labels, &MainView);
// left side
@ -821,8 +827,7 @@ void CMenus::RenderDemoList(CUIRect MainView)
Labels.HSplitTop(20.0f, &Left, &Labels);
Left.VSplitLeft(150.0f, &Left, &Right);
UI()->DoLabelScaled(&Left, Localize("Length:"), 14.0f, -1);
int Length = ((m_lDemos[m_DemolistSelectedIndex].m_Info.m_aLength[0]<<24)&0xFF000000) | ((m_lDemos[m_DemolistSelectedIndex].m_Info.m_aLength[1]<<16)&0xFF0000) |
((m_lDemos[m_DemolistSelectedIndex].m_Info.m_aLength[2]<<8)&0xFF00) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aLength[3]&0xFF);
int Length = m_lDemos[m_DemolistSelectedIndex].Length();
char aBuf[64];
str_format(aBuf, sizeof(aBuf), "%d:%02d", Length/60, Length%60);
UI()->DoLabelScaled(&Right, aBuf, 14.0f, -1);
@ -832,6 +837,12 @@ void CMenus::RenderDemoList(CUIRect MainView)
UI()->DoLabelScaled(&Left, Localize("Version:"), 14.0f, -1);
str_format(aBuf, sizeof(aBuf), "%d", m_lDemos[m_DemolistSelectedIndex].m_Info.m_Version);
UI()->DoLabelScaled(&Right, aBuf, 14.0f, -1);
Labels.HSplitTop(5.0f, 0, &Labels);
Labels.HSplitTop(20.0f, &Left, &Labels);
Left.VSplitLeft(150.0f, &Left, &Right);
UI()->DoLabelScaled(&Left, Localize("Markers:"), 14.0f, -1);
str_format(aBuf, sizeof(aBuf), "%d", m_lDemos[m_DemolistSelectedIndex].NumMarkers());
UI()->DoLabelScaled(&Right, aBuf, 14.0f, -1);
// right side
Labels = MainView;
@ -841,8 +852,7 @@ void CMenus::RenderDemoList(CUIRect MainView)
UI()->DoLabelScaled(&Right, m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapName, 14.0f, -1);
Labels.HSplitTop(5.0f, 0, &Labels);
Labels.HSplitTop(20.0f, &Left, &Labels);
Left.VSplitLeft(20.0f, 0, &Left);
Left.VSplitLeft(130.0f, &Left, &Right);
Left.VSplitLeft(150.0f, &Left, &Right);
UI()->DoLabelScaled(&Left, Localize("Size:"), 14.0f, -1);
unsigned Size = (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapSize[0]<<24) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapSize[1]<<16) |
(m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapSize[2]<<8) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapSize[3]);
@ -853,8 +863,7 @@ void CMenus::RenderDemoList(CUIRect MainView)
UI()->DoLabelScaled(&Right, aBuf, 14.0f, -1);
Labels.HSplitTop(5.0f, 0, &Labels);
Labels.HSplitTop(20.0f, &Left, &Labels);
Left.VSplitLeft(20.0f, 0, &Left);
Left.VSplitLeft(130.0f, &Left, &Right);
Left.VSplitLeft(150.0f, &Left, &Right);
UI()->DoLabelScaled(&Left, Localize("Crc:"), 14.0f, -1);
unsigned Crc = (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapCrc[0]<<24) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapCrc[1]<<16) |
(m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapCrc[2]<<8) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapCrc[3]);
@ -890,16 +899,17 @@ void CMenus::RenderDemoList(CUIRect MainView)
{
COL_ICON=0,
COL_DEMONAME,
COL_MARKERS,
COL_LENGTH,
COL_DATE,
SORT_DEMONAME=0,
SORT_DATE,
};
static CColumn s_aCols[] = {
{COL_ICON, -1, " ", -1, 14.0f, 0, {0}, {0}},
{COL_DEMONAME, SORT_DEMONAME, Localize("Demo"), 0, 0.0f, 0, {0}, {0}},
{COL_DATE, SORT_DATE, Localize("Date"), 1, 300.0f, 0, {0}, {0}},
{COL_ICON, -1, " ", -1, 14.0f, 0, {0}, {0}},
{COL_DEMONAME, SORT_DEMONAME, Localize("Demo"), 0, 0.0f, 0, {0}, {0}},
{COL_MARKERS, SORT_MARKERS, Localize("Markers"), 1, 75.0f, 0, {0}, {0}},
{COL_LENGTH, SORT_LENGTH, Localize("Length"), 1, 75.0f, 0, {0}, {0}},
{COL_DATE, SORT_DATE, Localize("Date"), 1, 160.0f, 1, {0}, {0}},
};
RenderTools()->DrawUIRect(&Headers, vec4(0.0f,0,0,0.15f), 0, 0);
@ -950,7 +960,8 @@ void CMenus::RenderDemoList(CUIRect MainView)
g_Config.m_BrDemoSort = s_aCols[i].m_Sort;
}
DemolistPopulate();
// Don't rescan in order to keep fetched headers, just resort
m_lDemos.sort_range();
DemolistOnUpdate(false);
}
}
@ -1115,15 +1126,27 @@ void CMenus::RenderDemoList(CUIRect MainView)
TextRender()->TextEx(&Cursor, r.front().m_aName, -1);
}
else if(ID == COL_MARKERS && !r.front().m_IsDir && r.front().m_InfosLoaded)
{
char aBuf[3];
str_format(aBuf, sizeof(aBuf), "%d", r.front().NumMarkers());
Button.VMargin(4.0f, &Button);
UI()->DoLabelScaled(&Button, aBuf, 12.0f, 1);
}
else if(ID == COL_LENGTH && !r.front().m_IsDir && r.front().m_InfosLoaded)
{
int Length = r.front().Length();
char aBuf[32];
str_format(aBuf, sizeof(aBuf), "%d:%02d", Length/60, Length%60);
Button.VMargin(4.0f, &Button);
UI()->DoLabelScaled(&Button, aBuf, 12.0f, 1);
}
else if(ID == COL_DATE && !r.front().m_IsDir)
{
CTextCursor Cursor;
TextRender()->SetCursor(&Cursor, Button.x, Button.y + (Button.h - 12.0f * UI()->Scale()) / 2.f, 12.0f * UI()->Scale(), TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
Cursor.m_LineWidth = Button.w;
char aBuf[256];
char aBuf[64];
str_timestamp_ex(r.front().m_Date, aBuf, sizeof(aBuf), FORMAT_SPACE);
TextRender()->TextEx(&Cursor, aBuf, -1);
Button.VSplitRight(24.0f, &Button, 0);
UI()->DoLabelScaled(&Button, aBuf, 12.0f, 1);
}
}
}
@ -1150,6 +1173,16 @@ void CMenus::RenderDemoList(CUIRect MainView)
DemolistOnUpdate(false);
}
static int s_FetchButton = 0;
if(DoButton_Menu(&s_FetchButton, Localize("Fetch Info"), 0, &FetchRect) || (Input()->KeyPress(KEY_F) && (Input()->KeyIsPressed(KEY_LCTRL) || Input()->KeyIsPressed(KEY_RCTRL))))
{
for(sorted_array<CDemoItem>::range r = m_lDemos.all(); !r.empty(); r.pop_front())
{
FetchHeader(r.front());
}
m_lDemos.sort_range();
}
static int s_PlayButton = 0;
if(DoButton_Menu(&s_PlayButton, m_DemolistSelectedIsDir?Localize("Open"):Localize("Play"), 0, &PlayRect) || Activated)
{
@ -1210,4 +1243,6 @@ void CMenus::RenderDemoList(CUIRect MainView)
}
}
}
UI()->DoLabelScaled(&LabelRect, aFooterLabel, 14.0f, -1);
}