diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index 15f10e22a..00fe9826c 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -343,6 +343,9 @@ MACRO_CONFIG_INT(BrDemoSort, br_demo_sort, 0, 0, 2, CFGFLAG_SAVE | CFGFLAG_CLIEN MACRO_CONFIG_INT(BrDemoSortOrder, br_demo_sort_order, 0, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Sorting order in demo browser") MACRO_CONFIG_INT(BrDemoFetchInfo, br_demo_fetch_info, 0, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Whether to auto fetch demo infos on refresh") +MACRO_CONFIG_INT(GhSort, gh_sort, 1, 0, 2, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Sorting column in ghost list") +MACRO_CONFIG_INT(GhSortOrder, gh_sort_order, 0, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Sorting order in ghost list") + MACRO_CONFIG_INT(SndBufferSize, snd_buffer_size, 512, 128, 32768, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Sound buffer size (may cause delay if large)") MACRO_CONFIG_INT(SndRate, snd_rate, 48000, 5512, 384000, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Sound mixing rate") MACRO_CONFIG_INT(SndEnable, snd_enable, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Sound enable") diff --git a/src/game/client/components/menus.h b/src/game/client/components/menus.h index d0e08c2d6..2bc2437cc 100644 --- a/src/game/client/components/menus.h +++ b/src/game/client/components/menus.h @@ -768,6 +768,14 @@ public: bool HasFile() const { return m_aFilename[0]; } }; + enum + { + GHOST_SORT_NONE = -1, + GHOST_SORT_NAME, + GHOST_SORT_TIME, + GHOST_SORT_DATE, + }; + std::vector m_vGhosts; std::chrono::nanoseconds m_GhostPopulateStartTime{0}; @@ -776,6 +784,7 @@ public: CGhostItem *GetOwnGhost(); void UpdateOwnGhost(CGhostItem Item); void DeleteGhostItem(int Index); + void SortGhostlist(); bool CanDisplayWarning() const; diff --git a/src/game/client/components/menus_ingame.cpp b/src/game/client/components/menus_ingame.cpp index 47e1ea345..bd7f9cf57 100644 --- a/src/game/client/components/menus_ingame.cpp +++ b/src/game/client/components/menus_ingame.cpp @@ -944,7 +944,7 @@ void CMenus::GhostlistPopulate() m_vGhosts.clear(); m_GhostPopulateStartTime = time_get_nanoseconds(); Storage()->ListDirectoryInfo(IStorage::TYPE_ALL, m_pClient->m_Ghost.GetGhostDir(), GhostlistFetchCallback, this); - std::sort(m_vGhosts.begin(), m_vGhosts.end()); + SortGhostlist(); CGhostItem *pOwnGhost = 0; for(auto &Ghost : m_vGhosts) @@ -1000,6 +1000,7 @@ void CMenus::UpdateOwnGhost(CGhostItem Item) Item.m_Date = std::time(0); Item.m_Failed = false; m_vGhosts.insert(std::lower_bound(m_vGhosts.begin(), m_vGhosts.end(), Item), Item); + SortGhostlist(); } void CMenus::DeleteGhostItem(int Index) @@ -1009,6 +1010,22 @@ void CMenus::DeleteGhostItem(int Index) m_vGhosts.erase(m_vGhosts.begin() + Index); } +void CMenus::SortGhostlist() +{ + if(g_Config.m_GhSort == GHOST_SORT_NAME) + std::stable_sort(m_vGhosts.begin(), m_vGhosts.end(), [](const CGhostItem &Left, const CGhostItem &Right) { + return g_Config.m_GhSortOrder ? (str_comp(Left.m_aPlayer, Right.m_aPlayer) > 0) : (str_comp(Left.m_aPlayer, Right.m_aPlayer) < 0); + }); + else if(g_Config.m_GhSort == GHOST_SORT_TIME) + std::stable_sort(m_vGhosts.begin(), m_vGhosts.end(), [](const CGhostItem &Left, const CGhostItem &Right) { + return g_Config.m_GhSortOrder ? (Left.m_Time > Right.m_Time) : (Left.m_Time < Right.m_Time); + }); + else if(g_Config.m_GhSort == GHOST_SORT_DATE) + std::stable_sort(m_vGhosts.begin(), m_vGhosts.end(), [](const CGhostItem &Left, const CGhostItem &Right) { + return g_Config.m_GhSortOrder ? (Left.m_Date > Right.m_Date) : (Left.m_Date < Right.m_Date); + }); +} + void CMenus::RenderGhost(CUIRect MainView) { // render background @@ -1029,10 +1046,12 @@ void CMenus::RenderGhost(CUIRect MainView) Headers.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_T, 5.0f); Headers.VSplitRight(20.0f, &Headers, 0); - struct CColumn + class CColumn { + public: const char *m_pCaption; int m_Id; + int m_Sort; float m_Width; CUIRect m_Rect; }; @@ -1046,11 +1065,11 @@ void CMenus::RenderGhost(CUIRect MainView) }; static CColumn s_aCols[] = { - {"", -1, 2.0f, {0}}, - {"", COL_ACTIVE, 30.0f, {0}}, - {Localizable("Name"), COL_NAME, 200.0f, {0}}, - {Localizable("Time"), COL_TIME, 90.0f, {0}}, - {Localizable("Date"), COL_DATE, 150.0f, {0}}, + {"", -1, GHOST_SORT_NONE, 2.0f, {0}}, + {"", COL_ACTIVE, GHOST_SORT_NONE, 30.0f, {0}}, + {Localizable("Name"), COL_NAME, GHOST_SORT_NAME, 200.0f, {0}}, + {Localizable("Time"), COL_TIME, GHOST_SORT_TIME, 90.0f, {0}}, + {Localizable("Date"), COL_DATE, GHOST_SORT_DATE, 150.0f, {0}}, }; int NumCols = std::size(s_aCols); @@ -1065,8 +1084,22 @@ void CMenus::RenderGhost(CUIRect MainView) } // do headers - for(int i = 0; i < NumCols; i++) - DoButton_GridHeader(&s_aCols[i].m_Id, Localize(s_aCols[i].m_pCaption), 0, &s_aCols[i].m_Rect); + for(const auto &Col : s_aCols) + { + if(DoButton_GridHeader(&Col.m_Id, Localize(Col.m_pCaption), g_Config.m_GhSort == Col.m_Sort, &Col.m_Rect)) + { + if(Col.m_Sort != GHOST_SORT_NONE) + { + if(g_Config.m_GhSort == Col.m_Sort) + g_Config.m_GhSortOrder ^= 1; + else + g_Config.m_GhSortOrder = 0; + g_Config.m_GhSort = Col.m_Sort; + + SortGhostlist(); + } + } + } View.Draw(ColorRGBA(0, 0, 0, 0.15f), 0, 0);