diff --git a/src/Cafe/IOSU/PDM/iosu_pdm.cpp b/src/Cafe/IOSU/PDM/iosu_pdm.cpp index d94b1dbfc3..b9dda445f8 100644 --- a/src/Cafe/IOSU/PDM/iosu_pdm.cpp +++ b/src/Cafe/IOSU/PDM/iosu_pdm.cpp @@ -464,5 +464,34 @@ namespace iosu return static_cast(&sIOSUModuleNNPDM); } + + bool GameListStat::LastPlayDate::operator<(const LastPlayDate& b) const + { + const auto& a = *this; + + if(a.year < b.year) + return true; + if(a.year > b.year) + return false; + + // same year + if(a.month < b.month) + return true; + if(a.month > b.month) + return false; + + // same year and month + return a.day < b.day; + } + + bool GameListStat::LastPlayDate::operator==(const LastPlayDate& b) const + { + const auto& a = *this; + return a.year == b.year && + a.month == b.month && + a.day == b.day; + } + std::weak_ordering GameListStat::LastPlayDate::operator<=>(const LastPlayDate& b) const = default; + }; }; diff --git a/src/Cafe/IOSU/PDM/iosu_pdm.h b/src/Cafe/IOSU/PDM/iosu_pdm.h index 0dd8a39d2d..63f99a4abd 100644 --- a/src/Cafe/IOSU/PDM/iosu_pdm.h +++ b/src/Cafe/IOSU/PDM/iosu_pdm.h @@ -21,11 +21,15 @@ namespace iosu /* Helper for UI game list */ struct GameListStat { - struct + struct LastPlayDate { uint32 year; // if 0 -> never played uint32 month; uint32 day; + + bool operator<(const LastPlayDate& b) const; + bool operator==(const LastPlayDate& b) const; + std::weak_ordering operator<=>(const LastPlayDate& b) const; }last_played; uint32 numMinutesPlayed; }; diff --git a/src/gui/components/wxGameList.cpp b/src/gui/components/wxGameList.cpp index e418ca0afd..1d5e5a4605 100644 --- a/src/gui/components/wxGameList.cpp +++ b/src/gui/components/wxGameList.cpp @@ -434,25 +434,57 @@ static inline int order_to_int(const std::weak_ordering &wo) return 0; } -int wxGameList::SortComparator(uint64 titleId1, uint64 titleId2, SortData* sortData) +std::weak_ordering wxGameList::SortComparator(uint64 titleId1, uint64 titleId2, SortData* sortData) { - const auto isFavoriteA = GetConfig().IsGameListFavorite(titleId1); - const auto isFavoriteB = GetConfig().IsGameListFavorite(titleId2); - const auto& name1 = GetNameByTitleId(titleId1); - const auto& name2 = GetNameByTitleId(titleId2); + auto titleLastPlayed = [](uint64_t id) + { + iosu::pdm::GameListStat playTimeStat{}; + iosu::pdm::GetStatForGamelist(id, playTimeStat); + return playTimeStat; + }; - if(sortData->dir > 0) - return order_to_int(std::tie(isFavoriteB, name1) <=> std::tie(isFavoriteA, name2)); - else - return order_to_int(std::tie(isFavoriteB, name2) <=> std::tie(isFavoriteA, name1)); + auto titlePlayMinutes = [](uint64_t id) + { + iosu::pdm::GameListStat playTimeStat; + if (!iosu::pdm::GetStatForGamelist(id, playTimeStat)) + return 0u; + return playTimeStat.numMinutesPlayed; + }; + + auto titleRegion = [](uint64_t id) + { + return CafeTitleList::GetGameInfo(id).GetRegion(); + }; + + switch(sortData->column) + { + default: + case ColumnName: + { + const auto isFavoriteA = GetConfig().IsGameListFavorite(titleId1); + const auto isFavoriteB = GetConfig().IsGameListFavorite(titleId2); + const auto nameA = GetNameByTitleId(titleId1); + const auto nameB = GetNameByTitleId(titleId2); + return std::tie(isFavoriteB, nameA) <=> std::tie(isFavoriteA, nameB); + } + case ColumnGameStarted: + return titleLastPlayed(titleId1).last_played <=> titleLastPlayed(titleId2).last_played; + case ColumnGameTime: + return titlePlayMinutes(titleId1) <=> titlePlayMinutes(titleId2); + case ColumnRegion: + return titleRegion(titleId1) <=> titleRegion(titleId2); + case ColumnTitleID: + return titleId1 <=> titleId2; + } + // unreachable + cemu_assert_debug(false); + return std::weak_ordering::less; } int wxGameList::SortFunction(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData) { const auto sort_data = (SortData*)sortData; - const int dir = sort_data->dir; - - return sort_data->thisptr->SortComparator((uint64)item1, (uint64)item2, sort_data); + return sort_data->dir * order_to_int(sort_data->thisptr->SortComparator((uint64)item1, (uint64)item2, sort_data)); } void wxGameList::SortEntries(int column) @@ -479,8 +511,9 @@ void wxGameList::SortEntries(int column) case ColumnGameTime: case ColumnGameStarted: case ColumnRegion: + case ColumnTitleID: { - SortData data{ this, column, s_direction }; + SortData data{ this, ItemColumns{column}, s_direction }; SortItems(SortFunction, (wxIntPtr)&data); break; } @@ -1004,7 +1037,7 @@ void wxGameList::OnClose(wxCloseEvent& event) int wxGameList::FindInsertPosition(TitleId titleId) { - SortData data{ this, s_last_column, s_direction }; + SortData data{ this, ItemColumns{s_last_column}, s_direction }; const auto itemCount = GetItemCount(); if (itemCount == 0) return 0; diff --git a/src/gui/components/wxGameList.h b/src/gui/components/wxGameList.h index b285d259f2..74cbc87df9 100644 --- a/src/gui/components/wxGameList.h +++ b/src/gui/components/wxGameList.h @@ -70,7 +70,7 @@ class wxGameList : public wxListCtrl inline static const wxColour kSecondColor{ 0xFDF9F2 }; void UpdateItemColors(sint32 startIndex = 0); - enum ItemColumns + enum ItemColumns : int { ColumnHiddenName = 0, ColumnIcon, @@ -91,12 +91,12 @@ class wxGameList : public wxListCtrl struct SortData { wxGameList* thisptr; - int column; + ItemColumns column; int dir; }; int FindInsertPosition(TitleId titleId); - int SortComparator(uint64 titleId1, uint64 titleId2, SortData* sortData); + std::weak_ordering SortComparator(uint64 titleId1, uint64 titleId2, SortData* sortData); static int SortFunction(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData); wxTimer* m_tooltip_timer;