diff --git a/src/fios.cpp b/src/fios.cpp index 748ffed6e5..1cf15d945a 100644 --- a/src/fios.cpp +++ b/src/fios.cpp @@ -26,7 +26,6 @@ #include "safeguards.h" static std::string *_fios_path = nullptr; -SortingBits _savegame_sort_order = SORT_BY_DATE | SORT_DESCENDING; /* OS-specific functions are taken from their respective files (win32/unix .c) */ extern bool FiosIsRoot(const std::string &path); @@ -36,22 +35,17 @@ extern void FiosGetDrives(FileList &file_list); /* get the name of an oldstyle savegame */ extern std::string GetOldSaveGameName(std::string_view file); -/** - * Compare two FiosItem's. Used with sort when sorting the file list. - * @param other The FiosItem to compare to. - * @return for ascending order: returns true if da < db. Vice versa for descending order. - */ -bool FiosItem::operator< (const FiosItem &other) const +/** Sort files by their name. @copydoc GUIList::Sorter */ +bool FiosItemNameSorter(const FiosItem &a, const FiosItem &b) { - int r = false; + return StrNaturalCompare(a.title.GetDecodedString(), b.title.GetDecodedString()) < 0; +} - if ((_savegame_sort_order & SORT_BY_NAME) == 0 && (*this).mtime != other.mtime) { - r = ClampTo(this->mtime - other.mtime); - } else { - r = StrNaturalCompare(this->title.GetDecodedString(), other.title.GetDecodedString()); - } - if (r == 0) return false; - return (_savegame_sort_order & SORT_DESCENDING) ? r > 0 : r < 0; +/** Sort files by their modification date, and name when they are equal. @copydoc GUIList::Sorter */ +bool FiosItemModificationDateSorter(const FiosItem &a, const FiosItem &b) +{ + if (a.mtime == b.mtime) return FiosItemNameSorter(a, b); + return a.mtime < b.mtime; } /** @@ -333,11 +327,8 @@ static void FiosGetFileList(SaveLoadOperation fop, bool show_dirs, FiosGetTypeAn fios.title = GetEncodedString(STR_SAVELOAD_DIRECTORY, fios.name + PATHSEP); } - /* Sort the subdirs always by name, ascending, remember user-sorting order */ - SortingBits order = _savegame_sort_order; - _savegame_sort_order = SORT_BY_NAME | SORT_ASCENDING; - std::sort(file_list.begin() + sort_start, file_list.end()); - _savegame_sort_order = order; + /* Sort the subdirs always ascending by name. */ + std::sort(file_list.begin() + sort_start, file_list.end(), FiosItemNameSorter); } /* This is where to start sorting for the filenames */ @@ -351,7 +342,7 @@ static void FiosGetFileList(SaveLoadOperation fop, bool show_dirs, FiosGetTypeAn scanner.Scan({}, subdir, true, true); } - std::sort(file_list.begin() + sort_start, file_list.end()); + std::sort(file_list.begin() + sort_start, file_list.end(), FiosItemSorter); /* Show drives */ FiosGetDrives(file_list); @@ -718,13 +709,9 @@ FiosNumberedSaveName::FiosNumberedSaveName(const std::string &prefix) : prefix(p scanner.Scan(".sav", *_autosave_path, false); /* Find the number for the most recent save, if any. */ - if (list.begin() != list.end()) { - SortingBits order = _savegame_sort_order; - _savegame_sort_order = SORT_BY_DATE | SORT_DESCENDING; - std::sort(list.begin(), list.end()); - _savegame_sort_order = order; - - std::string name = list.begin()->title.GetDecodedString(); + if (!list.empty()) { + auto elem = std::ranges::max_element(list, FiosItemModificationDateSorter); + std::string name = elem->title.GetDecodedString(); std::from_chars(name.data() + this->prefix.size(), name.data() + name.size(), this->number); } } diff --git a/src/fios.h b/src/fios.h index 22793942a4..8a2fc84c8d 100644 --- a/src/fios.h +++ b/src/fios.h @@ -80,7 +80,6 @@ struct FiosItem { int64_t mtime; EncodedString title; std::string name; - bool operator< (const FiosItem &other) const; }; /** List of file information. */ @@ -89,16 +88,9 @@ public: void BuildFileList(AbstractFileType abstract_filetype, SaveLoadOperation fop, bool show_dirs); const FiosItem *FindItem(std::string_view file); }; - -enum SortingBits : uint8_t { - SORT_ASCENDING = 0, - SORT_DESCENDING = 1, - SORT_BY_DATE = 0, - SORT_BY_NAME = 2 -}; -DECLARE_ENUM_AS_BIT_SET(SortingBits) - -extern SortingBits _savegame_sort_order; +bool FiosItemSorter(const FiosItem &a, const FiosItem &b); +bool FiosItemNameSorter(const FiosItem &a, const FiosItem &b); +bool FiosItemModificationDateSorter(const FiosItem &a, const FiosItem &b); void ShowSaveLoadDialog(AbstractFileType abstract_filetype, SaveLoadOperation fop); diff --git a/src/fios_gui.cpp b/src/fios_gui.cpp index 8e9dbf1839..7ede8083e8 100644 --- a/src/fios_gui.cpp +++ b/src/fios_gui.cpp @@ -43,6 +43,28 @@ LoadCheckData _load_check_data; ///< Data loaded from save during SL_LOAD_CHE static bool _fios_path_changed; static bool _savegame_sort_dirty; +/** The available sorters for FiosItems. */ +enum class SavegameSorter : uint8_t { + Date, ///< Sort by date. + Name, ///< Sort by name. +}; + +static SavegameSorter _savegame_sorter = SavegameSorter::Date; ///< Sorter for savegames. +static bool _savegame_sorter_ascending = false; ///< Sorter for savegames. + +/** Sorts the FiosItems based on the savegame sorter and order. @copydoc GUIList::Sorter */ +bool FiosItemSorter(const FiosItem &a, const FiosItem &b) +{ + switch (_savegame_sorter) { + case SavegameSorter::Date: + return _savegame_sorter_ascending ? FiosItemModificationDateSorter(a, b) : FiosItemModificationDateSorter(b, a); + case SavegameSorter::Name: + return _savegame_sorter_ascending ? FiosItemNameSorter(a, b) : FiosItemNameSorter(b, a); + default: + NOT_REACHED(); + } +} + /** * Reset read data. */ @@ -317,7 +339,7 @@ static void SortSaveGameList(FileList &file_list) } } - std::sort(file_list.begin() + sort_start, file_list.end() - sort_end); + std::sort(file_list.begin() + sort_start, file_list.end() - sort_end, FiosItemSorter); } struct SaveLoadWindow : public Window { @@ -491,8 +513,8 @@ public: switch (widget) { case WID_SL_SORT_BYNAME: case WID_SL_SORT_BYDATE: - if (((_savegame_sort_order & SORT_BY_NAME) != 0) == (widget == WID_SL_SORT_BYNAME)) { - this->DrawSortButtonState(widget, _savegame_sort_order & SORT_DESCENDING ? SBS_DOWN : SBS_UP); + if ((_savegame_sorter == SavegameSorter::Name) == (widget == WID_SL_SORT_BYNAME)) { + this->DrawSortButtonState(widget, _savegame_sorter_ascending ? SBS_UP : SBS_DOWN); } break; @@ -667,16 +689,16 @@ public: void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override { switch (widget) { - case WID_SL_SORT_BYNAME: // Sort save names by name - _savegame_sort_order = (_savegame_sort_order == SORT_BY_NAME) ? - SORT_BY_NAME | SORT_DESCENDING : SORT_BY_NAME; + case WID_SL_SORT_BYNAME: // Sort save games by name + _savegame_sorter_ascending = _savegame_sorter != SavegameSorter::Name || !_savegame_sorter_ascending; + _savegame_sorter = SavegameSorter::Name; _savegame_sort_dirty = true; this->SetDirty(); break; - case WID_SL_SORT_BYDATE: // Sort save names by date - _savegame_sort_order = (_savegame_sort_order == SORT_BY_DATE) ? - SORT_BY_DATE | SORT_DESCENDING : SORT_BY_DATE; + case WID_SL_SORT_BYDATE: // Sort save games by date + _savegame_sorter_ascending = _savegame_sorter != SavegameSorter::Date || !_savegame_sorter_ascending; + _savegame_sorter = SavegameSorter::Date; _savegame_sort_dirty = true; this->SetDirty(); break;