1
0
Fork 0

Codechange: Optionally allow passing state to GUIList sorter function.

GUIList sorter functions can currently only use global state, which makes per-window-instance sorting difficult.
pull/11539/head
Peter Nelson 2023-12-02 23:28:01 +00:00 committed by Peter Nelson
parent 4d9f335f36
commit dcf730f1f6
13 changed files with 67 additions and 43 deletions

View File

@ -28,7 +28,7 @@ struct GUIEngineListItem {
bool operator == (const EngineID &other) const { return this->engine_id == other; } bool operator == (const EngineID &other) const { return this->engine_id == other; }
}; };
typedef GUIList<GUIEngineListItem, CargoID> GUIEngineList; typedef GUIList<GUIEngineListItem, std::nullptr_t, CargoID> GUIEngineList;
typedef bool EngList_SortTypeFunction(const GUIEngineListItem&, const GUIEngineListItem&); ///< argument type for #EngList_Sort. typedef bool EngList_SortTypeFunction(const GUIEngineListItem&, const GUIEngineListItem&); ///< argument type for #EngList_Sort.
void EngList_Sort(GUIEngineList &el, EngList_SortTypeFunction compare); void EngList_Sort(GUIEngineList &el, EngList_SortTypeFunction compare);

View File

@ -1245,7 +1245,7 @@ static const NWidgetPart _nested_industry_directory_widgets[] = {
EndContainer(), EndContainer(),
}; };
typedef GUIList<const Industry *, const std::pair<CargoID, CargoID> &> GUIIndustryList; typedef GUIList<const Industry *, const CargoID &, const std::pair<CargoID, CargoID> &> GUIIndustryList;
/** Special cargo filter criteria */ /** Special cargo filter criteria */
enum CargoFilterSpecialType { enum CargoFilterSpecialType {
@ -1315,7 +1315,7 @@ protected:
static const StringID sorter_names[]; static const StringID sorter_names[];
static GUIIndustryList::SortFunction * const sorter_funcs[]; static GUIIndustryList::SortFunction * const sorter_funcs[];
GUIIndustryList industries; GUIIndustryList industries{IndustryDirectoryWindow::produced_cargo_filter};
Scrollbar *vscroll; Scrollbar *vscroll;
Scrollbar *hscroll; Scrollbar *hscroll;
@ -1484,7 +1484,7 @@ protected:
} }
/** Sort industries by name */ /** Sort industries by name */
static bool IndustryNameSorter(const Industry * const &a, const Industry * const &b) static bool IndustryNameSorter(const Industry * const &a, const Industry * const &b, const CargoID &)
{ {
int r = StrNaturalCompare(a->GetCachedName(), b->GetCachedName()); // Sort by name (natural sorting). int r = StrNaturalCompare(a->GetCachedName(), b->GetCachedName()); // Sort by name (natural sorting).
if (r == 0) return a->index < b->index; if (r == 0) return a->index < b->index;
@ -1492,21 +1492,20 @@ protected:
} }
/** Sort industries by type and name */ /** Sort industries by type and name */
static bool IndustryTypeSorter(const Industry * const &a, const Industry * const &b) static bool IndustryTypeSorter(const Industry * const &a, const Industry * const &b, const CargoID &filter)
{ {
int it_a = 0; int it_a = 0;
while (it_a != NUM_INDUSTRYTYPES && a->type != _sorted_industry_types[it_a]) it_a++; while (it_a != NUM_INDUSTRYTYPES && a->type != _sorted_industry_types[it_a]) it_a++;
int it_b = 0; int it_b = 0;
while (it_b != NUM_INDUSTRYTYPES && b->type != _sorted_industry_types[it_b]) it_b++; while (it_b != NUM_INDUSTRYTYPES && b->type != _sorted_industry_types[it_b]) it_b++;
int r = it_a - it_b; int r = it_a - it_b;
return (r == 0) ? IndustryNameSorter(a, b) : r < 0; return (r == 0) ? IndustryNameSorter(a, b, filter) : r < 0;
} }
/** Sort industries by production and name */ /** Sort industries by production and name */
static bool IndustryProductionSorter(const Industry * const &a, const Industry * const &b) static bool IndustryProductionSorter(const Industry * const &a, const Industry * const &b, const CargoID &filter)
{ {
CargoID filter = IndustryDirectoryWindow::produced_cargo_filter; if (filter == CF_NONE) return IndustryTypeSorter(a, b, filter);
if (filter == CF_NONE) return IndustryTypeSorter(a, b);
uint prod_a = 0, prod_b = 0; uint prod_a = 0, prod_b = 0;
if (filter == CF_ANY) { if (filter == CF_ANY) {
@ -1522,14 +1521,14 @@ protected:
} }
int r = prod_a - prod_b; int r = prod_a - prod_b;
return (r == 0) ? IndustryTypeSorter(a, b) : r < 0; return (r == 0) ? IndustryTypeSorter(a, b, filter) : r < 0;
} }
/** Sort industries by transported cargo and name */ /** Sort industries by transported cargo and name */
static bool IndustryTransportedCargoSorter(const Industry * const &a, const Industry * const &b) static bool IndustryTransportedCargoSorter(const Industry * const &a, const Industry * const &b, const CargoID &filter)
{ {
int r = GetCargoTransportedSortValue(a) - GetCargoTransportedSortValue(b); int r = GetCargoTransportedSortValue(a) - GetCargoTransportedSortValue(b);
return (r == 0) ? IndustryNameSorter(a, b) : r < 0; return (r == 0) ? IndustryNameSorter(a, b, filter) : r < 0;
} }
/** /**

View File

@ -326,7 +326,7 @@ enum ContentListFilterCriteria {
/** Window that lists the content that's at the content server */ /** Window that lists the content that's at the content server */
class NetworkContentListWindow : public Window, ContentCallback { class NetworkContentListWindow : public Window, ContentCallback {
/** List with content infos. */ /** List with content infos. */
typedef GUIList<const ContentInfo *, ContentListFilterData &> GUIContentList; typedef GUIList<const ContentInfo *, std::nullptr_t, ContentListFilterData &> GUIContentList;
static const uint EDITBOX_MAX_SIZE = 50; ///< Maximum size of the editbox in characters. static const uint EDITBOX_MAX_SIZE = 50; ///< Maximum size of the editbox in characters.

View File

@ -79,7 +79,7 @@ static DropDownList BuildVisibilityDropDownList()
return list; return list;
} }
typedef GUIList<NetworkGameList*, StringFilter&> GUIGameServerList; typedef GUIList<NetworkGameList*, std::nullptr_t, StringFilter&> GUIGameServerList;
typedef int ServerListPosition; typedef int ServerListPosition;
static const ServerListPosition SLP_INVALID = -1; static const ServerListPosition SLP_INVALID = -1;

View File

@ -602,7 +602,7 @@ static void ShowSavePresetWindow(const char *initial_text);
* Window for showing NewGRF files * Window for showing NewGRF files
*/ */
struct NewGRFWindow : public Window, NewGRFScanCallback { struct NewGRFWindow : public Window, NewGRFScanCallback {
typedef GUIList<const GRFConfig *, StringFilter &> GUIGRFConfigList; typedef GUIList<const GRFConfig *, std::nullptr_t, StringFilter &> GUIGRFConfigList;
static const uint EDITBOX_MAX_SIZE = 50; static const uint EDITBOX_MAX_SIZE = 50;

View File

@ -45,7 +45,7 @@ enum BuildObjectHotkeys {
/** The window used for building objects. */ /** The window used for building objects. */
class BuildObjectWindow : public Window { class BuildObjectWindow : public Window {
typedef GUIList<ObjectClassID, StringFilter &> GUIObjectClassList; ///< Type definition for the list to hold available object classes. typedef GUIList<ObjectClassID, std::nullptr_t, StringFilter &> GUIObjectClassList; ///< Type definition for the list to hold available object classes.
static const uint EDITBOX_MAX_SIZE = 16; ///< The maximum number of characters for the filter edit box. static const uint EDITBOX_MAX_SIZE = 16; ///< The maximum number of characters for the filter edit box.

View File

@ -903,7 +903,7 @@ private:
Scrollbar *vscroll; ///< Vertical scrollbar of the new station list. Scrollbar *vscroll; ///< Vertical scrollbar of the new station list.
Scrollbar *vscroll2; ///< Vertical scrollbar of the matrix with new stations. Scrollbar *vscroll2; ///< Vertical scrollbar of the matrix with new stations.
typedef GUIList<StationClassID, StringFilter &> GUIStationClassList; ///< Type definition for the list to hold available station classes. typedef GUIList<StationClassID, std::nullptr_t, StringFilter &> GUIStationClassList; ///< Type definition for the list to hold available station classes.
static const uint EDITBOX_MAX_SIZE = 16; ///< The maximum number of characters for the filter edit box. static const uint EDITBOX_MAX_SIZE = 16; ///< The maximum number of characters for the filter edit box.

View File

@ -1101,7 +1101,7 @@ private:
Scrollbar *vscrollList; ///< Vertical scrollbar of the new station list. Scrollbar *vscrollList; ///< Vertical scrollbar of the new station list.
Scrollbar *vscrollMatrix; ///< Vertical scrollbar of the station picker matrix. Scrollbar *vscrollMatrix; ///< Vertical scrollbar of the station picker matrix.
typedef GUIList<RoadStopClassID, StringFilter &> GUIRoadStopClassList; ///< Type definition for the list to hold available road stop classes. typedef GUIList<RoadStopClassID, std::nullptr_t, StringFilter &> GUIRoadStopClassList; ///< Type definition for the list to hold available road stop classes.
static const uint EDITBOX_MAX_SIZE = 16; ///< The maximum number of characters for the filter edit box. static const uint EDITBOX_MAX_SIZE = 16; ///< The maximum number of characters for the filter edit box.

View File

@ -41,7 +41,7 @@ struct SignList {
/** /**
* A GUIList contains signs and uses a StringFilter for filtering. * A GUIList contains signs and uses a StringFilter for filtering.
*/ */
typedef GUIList<const Sign *, StringFilter &> GUISignList; typedef GUIList<const Sign *, std::nullptr_t, StringFilter &> GUISignList;
GUISignList signs; GUISignList signs;

View File

@ -40,12 +40,13 @@ struct Filtering {
/** /**
* List template of 'things' \p T to sort in a GUI. * List template of 'things' \p T to sort in a GUI.
* @tparam T Type of data stored in the list to represent each item. * @tparam T Type of data stored in the list to represent each item.
* @tparam P Tyoe of data passed as additional parameter to the sort function.
* @tparam F Type of data fed as additional value to the filter function. @see FilterFunction * @tparam F Type of data fed as additional value to the filter function. @see FilterFunction
*/ */
template <typename T, typename F = const char*> template <typename T, typename P = std::nullptr_t, typename F = const char*>
class GUIList : public std::vector<T> { class GUIList : public std::vector<T> {
public: public:
typedef bool SortFunction(const T&, const T&); ///< Signature of sort function. using SortFunction = std::conditional_t<std::is_same_v<P, std::nullptr_t>, bool (const T&, const T&), bool (const T&, const T&, const P)>; ///< Signature of sort function.
typedef bool CDECL FilterFunction(const T*, F); ///< Signature of filter function. typedef bool CDECL FilterFunction(const T*, F); ///< Signature of filter function.
protected: protected:
@ -56,6 +57,11 @@ protected:
uint8_t filter_type; ///< what criteria to filter on uint8_t filter_type; ///< what criteria to filter on
uint16_t resort_timer; ///< resort list after a given amount of ticks if set uint16_t resort_timer; ///< resort list after a given amount of ticks if set
/* If sort parameters are used then params must be a reference, however if not then params cannot be a reference as
* it will not be able to reference anything. */
using SortParameterReference = std::conditional_t<std::is_same_v<P, std::nullptr_t>, P, P&>;
const SortParameterReference params;
/** /**
* Check if the list is sortable * Check if the list is sortable
* *
@ -76,13 +82,28 @@ protected:
} }
public: public:
/* If sort parameters are not used then we don't require a reference to the params. */
template <typename T_ = T, typename P_ = P, typename _F = F, std::enable_if_t<std::is_same_v<P_, std::nullptr_t>>* = nullptr>
GUIList() : GUIList() :
sort_func_list(nullptr), sort_func_list(nullptr),
filter_func_list(nullptr), filter_func_list(nullptr),
flags(VL_NONE), flags(VL_NONE),
sort_type(0), sort_type(0),
filter_type(0), filter_type(0),
resort_timer(1) resort_timer(1),
params(nullptr)
{};
/* If sort parameters are used then we require a reference to the params. */
template <typename T_ = T, typename P_ = P, typename _F = F, std::enable_if_t<!std::is_same_v<P_, std::nullptr_t>>* = nullptr>
GUIList(const P& params) :
sort_func_list(nullptr),
filter_func_list(nullptr),
flags(VL_NONE),
sort_type(0),
filter_type(0),
resort_timer(1),
params(params)
{}; {};
/** /**
@ -258,7 +279,11 @@ public:
const bool desc = (this->flags & VL_DESC) != 0; const bool desc = (this->flags & VL_DESC) != 0;
std::sort(std::vector<T>::begin(), std::vector<T>::end(), [&](const T &a, const T &b) { return desc ? compare(b, a) : compare(a, b); }); if constexpr (std::is_same_v<P, std::nullptr_t>) {
std::sort(std::vector<T>::begin(), std::vector<T>::end(), [&](const T &a, const T &b) { return desc ? compare(b, a) : compare(a, b); });
} else {
std::sort(std::vector<T>::begin(), std::vector<T>::end(), [&](const T &a, const T &b) { return desc ? compare(b, a, params) : compare(a, b, params); });
}
return true; return true;
} }

View File

@ -209,7 +209,7 @@ static void StationsWndShowStationRating(int left, int right, int y, CargoID typ
if (w != 0) GfxFillRect(left + padding, y, left + w - 1, y + padding - 1, PC_GREEN); if (w != 0) GfxFillRect(left + padding, y, left + w - 1, y + padding - 1, PC_GREEN);
} }
typedef GUIList<const Station*> GUIStationList; typedef GUIList<const Station*, const CargoTypes &> GUIStationList;
/** /**
* The list of stations per company. * The list of stations per company.
@ -228,7 +228,7 @@ protected:
static const StringID sorter_names[]; static const StringID sorter_names[];
static GUIStationList::SortFunction * const sorter_funcs[]; static GUIStationList::SortFunction * const sorter_funcs[];
GUIStationList stations; GUIStationList stations{cargo_filter};
Scrollbar *vscroll; Scrollbar *vscroll;
uint rating_width; uint rating_width;
@ -273,7 +273,7 @@ protected:
} }
/** Sort stations by their name */ /** Sort stations by their name */
static bool StationNameSorter(const Station * const &a, const Station * const &b) static bool StationNameSorter(const Station * const &a, const Station * const &b, const CargoTypes &)
{ {
int r = StrNaturalCompare(a->GetCachedName(), b->GetCachedName()); // Sort by name (natural sorting). int r = StrNaturalCompare(a->GetCachedName(), b->GetCachedName()); // Sort by name (natural sorting).
if (r == 0) return a->index < b->index; if (r == 0) return a->index < b->index;
@ -281,13 +281,13 @@ protected:
} }
/** Sort stations by their type */ /** Sort stations by their type */
static bool StationTypeSorter(const Station * const &a, const Station * const &b) static bool StationTypeSorter(const Station * const &a, const Station * const &b, const CargoTypes &)
{ {
return a->facilities < b->facilities; return a->facilities < b->facilities;
} }
/** Sort stations by their waiting cargo */ /** Sort stations by their waiting cargo */
static bool StationWaitingTotalSorter(const Station * const &a, const Station * const &b) static bool StationWaitingTotalSorter(const Station * const &a, const Station * const &b, const CargoTypes &cargo_filter)
{ {
int diff = 0; int diff = 0;
@ -299,7 +299,7 @@ protected:
} }
/** Sort stations by their available waiting cargo */ /** Sort stations by their available waiting cargo */
static bool StationWaitingAvailableSorter(const Station * const &a, const Station * const &b) static bool StationWaitingAvailableSorter(const Station * const &a, const Station * const &b, const CargoTypes &cargo_filter)
{ {
int diff = 0; int diff = 0;
@ -311,7 +311,7 @@ protected:
} }
/** Sort stations by their rating */ /** Sort stations by their rating */
static bool StationRatingMaxSorter(const Station * const &a, const Station * const &b) static bool StationRatingMaxSorter(const Station * const &a, const Station * const &b, const CargoTypes &cargo_filter)
{ {
byte maxr1 = 0; byte maxr1 = 0;
byte maxr2 = 0; byte maxr2 = 0;
@ -325,7 +325,7 @@ protected:
} }
/** Sort stations by their rating */ /** Sort stations by their rating */
static bool StationRatingMinSorter(const Station * const &a, const Station * const &b) static bool StationRatingMinSorter(const Station * const &a, const Station * const &b, const CargoTypes &cargo_filter)
{ {
byte minr1 = 255; byte minr1 = 255;
byte minr2 = 255; byte minr2 = 255;

View File

@ -47,7 +47,7 @@
TownKdtree _town_local_authority_kdtree(&Kdtree_TownXYFunc); TownKdtree _town_local_authority_kdtree(&Kdtree_TownXYFunc);
typedef GUIList<const Town*> GUITownList; typedef GUIList<const Town*, const bool &> GUITownList;
static const NWidgetPart _nested_town_authority_widgets[] = { static const NWidgetPart _nested_town_authority_widgets[] = {
NWidget(NWID_HORIZONTAL), NWidget(NWID_HORIZONTAL),
@ -707,7 +707,7 @@ private:
StringFilter string_filter; ///< Filter for towns StringFilter string_filter; ///< Filter for towns
QueryString townname_editbox; ///< Filter editbox QueryString townname_editbox; ///< Filter editbox
GUITownList towns; GUITownList towns{TownDirectoryWindow::last_sorting.order};
Scrollbar *vscroll; Scrollbar *vscroll;
@ -736,31 +736,31 @@ private:
} }
/** Sort by town name */ /** Sort by town name */
static bool TownNameSorter(const Town * const &a, const Town * const &b) static bool TownNameSorter(const Town * const &a, const Town * const &b, const bool &)
{ {
return StrNaturalCompare(a->GetCachedName(), b->GetCachedName()) < 0; // Sort by name (natural sorting). return StrNaturalCompare(a->GetCachedName(), b->GetCachedName()) < 0; // Sort by name (natural sorting).
} }
/** Sort by population (default descending, as big towns are of the most interest). */ /** Sort by population (default descending, as big towns are of the most interest). */
static bool TownPopulationSorter(const Town * const &a, const Town * const &b) static bool TownPopulationSorter(const Town * const &a, const Town * const &b, const bool &order)
{ {
uint32_t a_population = a->cache.population; uint32_t a_population = a->cache.population;
uint32_t b_population = b->cache.population; uint32_t b_population = b->cache.population;
if (a_population == b_population) return TownDirectoryWindow::TownNameSorter(a, b); if (a_population == b_population) return TownDirectoryWindow::TownNameSorter(a, b, order);
return a_population < b_population; return a_population < b_population;
} }
/** Sort by town rating */ /** Sort by town rating */
static bool TownRatingSorter(const Town * const &a, const Town * const &b) static bool TownRatingSorter(const Town * const &a, const Town * const &b, const bool &order)
{ {
bool before = !TownDirectoryWindow::last_sorting.order; // Value to get 'a' before 'b'. bool before = !order; // Value to get 'a' before 'b'.
/* Towns without rating are always after towns with rating. */ /* Towns without rating are always after towns with rating. */
if (HasBit(a->have_ratings, _local_company)) { if (HasBit(a->have_ratings, _local_company)) {
if (HasBit(b->have_ratings, _local_company)) { if (HasBit(b->have_ratings, _local_company)) {
int16_t a_rating = a->ratings[_local_company]; int16_t a_rating = a->ratings[_local_company];
int16_t b_rating = b->ratings[_local_company]; int16_t b_rating = b->ratings[_local_company];
if (a_rating == b_rating) return TownDirectoryWindow::TownNameSorter(a, b); if (a_rating == b_rating) return TownDirectoryWindow::TownNameSorter(a, b, order);
return a_rating < b_rating; return a_rating < b_rating;
} }
return before; return before;
@ -768,8 +768,8 @@ private:
if (HasBit(b->have_ratings, _local_company)) return !before; if (HasBit(b->have_ratings, _local_company)) return !before;
/* Sort unrated towns always on ascending town name. */ /* Sort unrated towns always on ascending town name. */
if (before) return TownDirectoryWindow::TownNameSorter(a, b); if (before) return TownDirectoryWindow::TownNameSorter(a, b, order);
return TownDirectoryWindow::TownNameSorter(b, a); return TownDirectoryWindow::TownNameSorter(b, a, order);
} }
public: public:

View File

@ -19,7 +19,7 @@
#include "window_gui.h" #include "window_gui.h"
#include "widgets/dropdown_type.h" #include "widgets/dropdown_type.h"
typedef GUIList<const Vehicle*, CargoID> GUIVehicleList; typedef GUIList<const Vehicle*, std::nullptr_t, CargoID> GUIVehicleList;
struct GUIVehicleGroup { struct GUIVehicleGroup {
VehicleList::const_iterator vehicles_begin; ///< Pointer to beginning element of this vehicle group. VehicleList::const_iterator vehicles_begin; ///< Pointer to beginning element of this vehicle group.
@ -62,7 +62,7 @@ struct GUIVehicleGroup {
} }
}; };
typedef GUIList<GUIVehicleGroup, CargoID> GUIVehicleGroupList; typedef GUIList<GUIVehicleGroup, std::nullptr_t, CargoID> GUIVehicleGroupList;
struct BaseVehicleListWindow : public Window { struct BaseVehicleListWindow : public Window {