OpenTTD Source 15.0-RC2
sortlist_type.h
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
10#ifndef SORTLIST_TYPE_H
11#define SORTLIST_TYPE_H
12
13#include "core/enum_type.hpp"
15
17enum class SortListFlag : uint8_t {
18 Desc,
19 Resort,
20 Rebuild,
21 Filter,
22};
24
26struct Listing {
27 bool order;
28 uint8_t criteria;
29};
31struct Filtering {
32 bool state;
33 uint8_t criteria;
34};
35
42template <typename T, typename P = std::nullptr_t, typename F = std::string_view>
43class GUIList : public std::vector<T> {
44public:
45 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)>;
46 using FilterFunction = bool(const T*, F);
47
48protected:
49 std::span<SortFunction * const> sort_func_list;
50 std::span<FilterFunction * const> filter_func_list;
52 uint8_t sort_type;
53 uint8_t filter_type;
54 uint16_t resort_timer;
55
56 /* If sort parameters are used then params must be a reference, however if not then params cannot be a reference as
57 * it will not be able to reference anything. */
58 using SortParameterReference = std::conditional_t<std::is_same_v<P, std::nullptr_t>, P, P&>;
59 const SortParameterReference params;
60
66 bool IsSortable() const
67 {
68 return std::vector<T>::size() >= 2;
69 }
70
75 {
76 /* Resort every 10 days */
77 this->resort_timer = Ticks::DAY_TICKS * 10;
78 }
79
80public:
81 /* If sort parameters are not used then we don't require a reference to the params. */
82 template <typename T_ = T, typename P_ = P, typename _F = F, std::enable_if_t<std::is_same_v<P_, std::nullptr_t>>* = nullptr>
83 GUIList() :
86 flags({}),
87 sort_type(0),
88 filter_type(0),
89 resort_timer(1),
90 params(nullptr)
91 {};
92
93 /* If sort parameters are used then we require a reference to the params. */
94 template <typename T_ = T, typename P_ = P, typename _F = F, std::enable_if_t<!std::is_same_v<P_, std::nullptr_t>>* = nullptr>
95 GUIList(const P &params) :
98 flags({}),
99 sort_type(0),
100 filter_type(0),
101 resort_timer(1),
102 params(params)
103 {};
104
110 uint8_t SortType() const
111 {
112 return this->sort_type;
113 }
114
120 void SetSortType(uint8_t n_type)
121 {
122 assert(n_type < std::size(this->sort_func_list));
123 if (this->sort_type != n_type) {
124 this->flags.Set(SortListFlag::Resort);
125 this->sort_type = n_type;
126 }
127 }
128
135 {
136 Listing l;
137 l.order = this->flags.Test(SortListFlag::Desc);
138 l.criteria = this->sort_type;
139
140 return l;
141 }
142
149 {
150 if (l.order) {
151 this->flags.Set(SortListFlag::Desc);
152 } else {
153 this->flags.Reset(SortListFlag::Desc);
154 }
155 this->sort_type = l.criteria;
156 }
157
163 uint8_t FilterType() const
164 {
165 return this->filter_type;
166 }
167
173 void SetFilterType(uint8_t n_type)
174 {
175 assert(n_type < std::size(this->filter_func_list));
176 if (this->filter_type != n_type) {
177 this->filter_type = n_type;
178 }
179 }
180
187 {
188 Filtering f;
189 f.state = this->flags.Test(SortListFlag::Filter);
190 f.criteria = this->filter_type;
191
192 return f;
193 }
194
201 {
202 if (f.state) {
203 this->flags.Set(SortListFlag::Filter);
204 } else {
205 this->flags.Reset(SortListFlag::Filter);
206 }
207 this->filter_type = f.criteria;
208 }
209
219 {
220 if (--this->resort_timer == 0) {
221 this->flags.Set(SortListFlag::Resort);
222 this->ResetResortTimer();
223 return true;
224 }
225 return false;
226 }
227
233 {
234 this->flags.Set(SortListFlag::Resort);
235 }
236
242 bool IsDescSortOrder() const
243 {
244 return this->flags.Test(SortListFlag::Desc);
245 }
246
253 {
254 this->flags.Flip(SortListFlag::Desc);
255
256 if (this->IsSortable()) std::reverse(std::vector<T>::begin(), std::vector<T>::end());
257 }
258
265 template <typename Comp>
266 bool Sort(Comp compare)
267 {
268 /* Do not sort if the resort bit is not set */
269 if (!this->flags.Test(SortListFlag::Resort)) return false;
270
271 this->flags.Reset(SortListFlag::Resort);
272
273 this->ResetResortTimer();
274
275 /* Do not sort when the list is not sortable */
276 if (!this->IsSortable()) return false;
277
278 const bool desc = this->flags.Test(SortListFlag::Desc);
279
280 if constexpr (std::is_same_v<P, std::nullptr_t>) {
281 std::sort(std::vector<T>::begin(), std::vector<T>::end(), [&](const T &a, const T &b) { return desc ? compare(b, a) : compare(a, b); });
282 } else {
283 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); });
284 }
285 return true;
286 }
287
293 void SetSortFuncs(std::span<SortFunction * const> n_funcs)
294 {
295 this->sort_func_list = n_funcs;
296 }
297
304 bool Sort()
305 {
306 if (this->sort_func_list.empty()) return false;
307 assert(this->sort_type < this->sort_func_list.size());
308 return this->Sort(this->sort_func_list[this->sort_type]);
309 }
310
316 bool IsFilterEnabled() const
317 {
318 return this->flags.Test(SortListFlag::Filter);
319 }
320
326 void SetFilterState(bool state)
327 {
328 if (state) {
329 this->flags.Set(SortListFlag::Filter);
330 } else {
331 this->flags.Reset(SortListFlag::Filter);
332 }
333 }
334
342 bool Filter(FilterFunction *decide, F filter_data)
343 {
344 /* Do not filter if the filter bit is not set */
345 if (!this->flags.Test(SortListFlag::Filter)) return false;
346
347 bool changed = false;
348 for (auto it = std::vector<T>::begin(); it != std::vector<T>::end(); /* Nothing */) {
349 if (!decide(&*it, filter_data)) {
350 it = std::vector<T>::erase(it);
351 changed = true;
352 } else {
353 it++;
354 }
355 }
356
357 return changed;
358 }
359
365 void SetFilterFuncs(std::span<FilterFunction * const> n_funcs)
366 {
367 this->filter_func_list = n_funcs;
368 }
369
376 bool Filter(F filter_data)
377 {
378 if (this->filter_func_list.empty()) return false;
379 assert(this->filter_type < this->filter_func_list.size());
380 return this->Filter(this->filter_func_list[this->filter_type], filter_data);
381 }
382
387 bool NeedRebuild() const
388 {
389 return this->flags.Test(SortListFlag::Rebuild);
390 }
391
396 {
397 this->flags.Set(SortListFlag::Rebuild);
398 }
399
406 {
407 this->flags.Reset(SortListFlag::Rebuild);
408 this->flags.Set(SortListFlag::Resort);
409 }
410};
411
412#endif /* SORTLIST_TYPE_H */
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Timpl & Reset()
Reset all bits.
constexpr Timpl & Flip(Tvalue_type value)
Flip the value-th bit.
constexpr Timpl & Set()
Set all bits.
List template of 'things' T to sort in a GUI.
bool Filter(FilterFunction *decide, F filter_data)
Filter the list.
void RebuildDone()
Notify the sortlist that the rebuild is done.
void SetFiltering(Filtering f)
Import filter conditions.
void SetListing(Listing l)
Import sort conditions.
bool IsSortable() const
Check if the list is sortable.
uint16_t resort_timer
resort list after a given amount of ticks if set
void SetFilterState(bool state)
Enable or disable the filter.
bool IsDescSortOrder() const
Check if the sort order is descending.
void ToggleSortOrder()
Toggle the sort order Since that is the worst condition for the sort function reverse the list here.
bool(const T *, F) FilterFunction
Signature of filter function.
void SetFilterFuncs(std::span< FilterFunction *const > n_funcs)
Hand the filter function pointers to the GUIList.
Filtering GetFiltering() const
Export current filter conditions.
bool NeedRebuild() const
Check if a rebuild is needed.
void SetFilterType(uint8_t n_type)
Set the filtertype of the list.
std::span< FilterFunction *const > filter_func_list
the filter criteria functions
void ResetResortTimer()
Reset the resort timer.
void ForceRebuild()
Force that a rebuild is needed.
bool IsFilterEnabled() const
Check if the filter is enabled.
std::conditional_t< std::is_same_v< P, std::nullptr_t >, bool(const T &, const T &), bool(const T &, const T &, const P)> SortFunction
Signature of sort function.
std::span< SortFunction *const > sort_func_list
the sort criteria functions
bool Sort(Comp compare)
Sort the list.
void ForceResort()
Force a resort next Sort call Reset the resort timer if used too.
uint8_t SortType() const
Get the sorttype of the list.
bool Filter(F filter_data)
Filter the data with the currently selected filter.
bool Sort()
Overload of #Sort(SortFunction *compare) Overloaded to reduce external code.
Listing GetListing() const
Export current sort conditions.
uint8_t sort_type
what criteria to sort on
void SetSortFuncs(std::span< SortFunction *const > n_funcs)
Hand the sort function pointers to the GUIList.
bool NeedResort()
Check if a resort is needed next loop If used the resort timer will decrease every call till 0.
void SetSortType(uint8_t n_type)
Set the sorttype of the list.
uint8_t filter_type
what criteria to filter on
SortListFlags flags
used to control sorting/resorting/etc.
uint8_t FilterType() const
Get the filtertype of the list.
static constexpr TimerGameTick::Ticks DAY_TICKS
1 day is 74 ticks; TimerGameCalendar::date_fract used to be uint16_t and incremented by 885.
Type (helpers) for enums.
SortListFlag
Flags of the sort list.
@ Rebuild
rebuild the sort list
@ Desc
sort descending or ascending
@ Resort
instruct the code to resort the list in the next loop
@ Filter
filter disabled/enabled
Data structure describing what to show in the list (filter criteria).
uint8_t criteria
Filtering criteria.
bool state
Filter on/off.
Data structure describing how to show the list (what sort direction and criteria).
uint8_t criteria
Sorting criteria.
bool order
Ascending/descending.
Definition of the tick-based game-timer.