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.
This commit is contained in:
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; }
};
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.
void EngList_Sort(GUIEngineList &el, EngList_SortTypeFunction compare);

View File

@ -1245,7 +1245,7 @@ static const NWidgetPart _nested_industry_directory_widgets[] = {
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 */
enum CargoFilterSpecialType {
@ -1315,7 +1315,7 @@ protected:
static const StringID sorter_names[];
static GUIIndustryList::SortFunction * const sorter_funcs[];
GUIIndustryList industries;
GUIIndustryList industries{IndustryDirectoryWindow::produced_cargo_filter};
Scrollbar *vscroll;
Scrollbar *hscroll;
@ -1484,7 +1484,7 @@ protected:
}
/** 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).
if (r == 0) return a->index < b->index;
@ -1492,21 +1492,20 @@ protected:
}
/** 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;
while (it_a != NUM_INDUSTRYTYPES && a->type != _sorted_industry_types[it_a]) it_a++;
int it_b = 0;
while (it_b != NUM_INDUSTRYTYPES && b->type != _sorted_industry_types[it_b]) 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 */
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);
if (filter == CF_NONE) return IndustryTypeSorter(a, b, filter);
uint prod_a = 0, prod_b = 0;
if (filter == CF_ANY) {
@ -1522,14 +1521,14 @@ protected:
}
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 */
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);
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 */
class NetworkContentListWindow : public Window, ContentCallback {
/** 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.

View File

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

View File

@ -602,7 +602,7 @@ static void ShowSavePresetWindow(const char *initial_text);
* Window for showing NewGRF files
*/
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;

View File

@ -45,7 +45,7 @@ enum BuildObjectHotkeys {
/** The window used for building objects. */
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.

View File

@ -903,7 +903,7 @@ private:
Scrollbar *vscroll; ///< Vertical scrollbar of the new station list.
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.

View File

@ -1101,7 +1101,7 @@ private:
Scrollbar *vscrollList; ///< Vertical scrollbar of the new station list.
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.

View File

@ -41,7 +41,7 @@ struct SignList {
/**
* 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;

View File

@ -40,12 +40,13 @@ struct Filtering {
/**
* 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 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
*/
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> {
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.
protected:
@ -56,6 +57,11 @@ protected:
uint8_t filter_type; ///< what criteria to filter on
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
*
@ -76,13 +82,28 @@ protected:
}
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() :
sort_func_list(nullptr),
filter_func_list(nullptr),
flags(VL_NONE),
sort_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;
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;
}

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);
}
typedef GUIList<const Station*> GUIStationList;
typedef GUIList<const Station*, const CargoTypes &> GUIStationList;
/**
* The list of stations per company.
@ -228,7 +228,7 @@ protected:
static const StringID sorter_names[];
static GUIStationList::SortFunction * const sorter_funcs[];
GUIStationList stations;
GUIStationList stations{cargo_filter};
Scrollbar *vscroll;
uint rating_width;
@ -273,7 +273,7 @@ protected:
}
/** 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).
if (r == 0) return a->index < b->index;
@ -281,13 +281,13 @@ protected:
}
/** 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;
}
/** 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;
@ -299,7 +299,7 @@ protected:
}
/** 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;
@ -311,7 +311,7 @@ protected:
}
/** 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 maxr2 = 0;
@ -325,7 +325,7 @@ protected:
}
/** 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 minr2 = 255;

View File

@ -47,7 +47,7 @@
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[] = {
NWidget(NWID_HORIZONTAL),
@ -707,7 +707,7 @@ private:
StringFilter string_filter; ///< Filter for towns
QueryString townname_editbox; ///< Filter editbox
GUITownList towns;
GUITownList towns{TownDirectoryWindow::last_sorting.order};
Scrollbar *vscroll;
@ -736,31 +736,31 @@ private:
}
/** 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).
}
/** 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 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;
}
/** 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. */
if (HasBit(a->have_ratings, _local_company)) {
if (HasBit(b->have_ratings, _local_company)) {
int16_t a_rating = a->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 before;
@ -768,8 +768,8 @@ private:
if (HasBit(b->have_ratings, _local_company)) return !before;
/* Sort unrated towns always on ascending town name. */
if (before) return TownDirectoryWindow::TownNameSorter(a, b);
return TownDirectoryWindow::TownNameSorter(b, a);
if (before) return TownDirectoryWindow::TownNameSorter(a, b, order);
return TownDirectoryWindow::TownNameSorter(b, a, order);
}
public:

View File

@ -19,7 +19,7 @@
#include "window_gui.h"
#include "widgets/dropdown_type.h"
typedef GUIList<const Vehicle*, CargoID> GUIVehicleList;
typedef GUIList<const Vehicle*, std::nullptr_t, CargoID> GUIVehicleList;
struct GUIVehicleGroup {
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 {