Skip to content

GameList: Allow sorting by more columns #1571

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions src/Cafe/IOSU/PDM/iosu_pdm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -464,5 +464,34 @@ namespace iosu
return static_cast<IOSUModule*>(&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;

};
};
6 changes: 5 additions & 1 deletion src/Cafe/IOSU/PDM/iosu_pdm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down
61 changes: 47 additions & 14 deletions src/gui/components/wxGameList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down
6 changes: 3 additions & 3 deletions src/gui/components/wxGameList.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Expand Down
Loading