Files @ r28829:39f59d27ad2a
Branch filter:

Location: cpp/openttd-patchpack/source/src/sortlist_type.h

translators
Update: Translations from eints
chinese (simplified): 19 changes by WenSimEHRP
ukrainian: 9 changes by StepanIvasyn
portuguese (brazilian): 43 changes by pasantoro
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
/*
 * This file is part of OpenTTD.
 * 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.
 * 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.
 * 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 <http://www.gnu.org/licenses/>.
 */

/** @file sortlist_type.h Base types for having sorted lists in GUIs. */

#ifndef SORTLIST_TYPE_H
#define SORTLIST_TYPE_H

#include "core/enum_type.hpp"
#include "core/bitmath_func.hpp"
#include "core/mem_func.hpp"
#include "timer/timer_game_tick.h"

/** Flags of the sort list. */
enum SortListFlags {
	VL_NONE       = 0,      ///< no sort
	VL_DESC       = 1 << 0, ///< sort descending or ascending
	VL_RESORT     = 1 << 1, ///< instruct the code to resort the list in the next loop
	VL_REBUILD    = 1 << 2, ///< rebuild the sort list
	VL_FILTER     = 1 << 3, ///< filter disabled/enabled
	VL_END        = 1 << 4,
};
DECLARE_ENUM_AS_BIT_SET(SortListFlags)

/** Data structure describing how to show the list (what sort direction and criteria). */
struct Listing {
	bool order;    ///< Ascending/descending
	byte criteria; ///< Sorting criteria
};
/** Data structure describing what to show in the list (filter criteria). */
struct Filtering {
	bool state;    ///< Filter on/off
	byte criteria; ///< Filtering criteria
};

/**
 * 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 P = std::nullptr_t, typename F = const char*>
class GUIList : public std::vector<T> {
public:
	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:
	SortFunction * const *sort_func_list;     ///< the sort criteria functions
	FilterFunction * const *filter_func_list; ///< the filter criteria functions
	SortListFlags flags;                      ///< used to control sorting/resorting/etc.
	uint8_t sort_type;                          ///< what criteria to sort on
	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
	 *
	 * @return true if we can sort the list
	 */
	bool IsSortable() const
	{
		return std::vector<T>::size() >= 2;
	}

	/**
	 * Reset the resort timer
	 */
	void ResetResortTimer()
	{
		/* Resort every 10 days */
		this->resort_timer = Ticks::DAY_TICKS * 10;
	}

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),
		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)
	{};

	/**
	 * Get the sorttype of the list
	 *
	 * @return The current sorttype
	 */
	uint8_t SortType() const
	{
		return this->sort_type;
	}

	/**
	 * Set the sorttype of the list
	 *
	 * @param n_type the new sort type
	 */
	void SetSortType(uint8_t n_type)
	{
		if (this->sort_type != n_type) {
			SETBITS(this->flags, VL_RESORT);
			this->sort_type = n_type;
		}
	}

	/**
	 * Export current sort conditions
	 *
	 * @return the current sort conditions
	 */
	Listing GetListing() const
	{
		Listing l;
		l.order = (this->flags & VL_DESC) != 0;
		l.criteria = this->sort_type;

		return l;
	}

	/**
	 * Import sort conditions
	 *
	 * @param l The sort conditions we want to use
	 */
	void SetListing(Listing l)
	{
		if (l.order) {
			SETBITS(this->flags, VL_DESC);
		} else {
			CLRBITS(this->flags, VL_DESC);
		}
		this->sort_type = l.criteria;
	}

	/**
	 * Get the filtertype of the list
	 *
	 * @return The current filtertype
	 */
	uint8_t FilterType() const
	{
		return this->filter_type;
	}

	/**
	 * Set the filtertype of the list
	 *
	 * @param n_type the new filter type
	 */
	void SetFilterType(uint8_t n_type)
	{
		if (this->filter_type != n_type) {
			this->filter_type = n_type;
		}
	}

	/**
	 * Export current filter conditions
	 *
	 * @return the current filter conditions
	 */
	Filtering GetFiltering() const
	{
		Filtering f;
		f.state = (this->flags & VL_FILTER) != 0;
		f.criteria = this->filter_type;

		return f;
	}

	/**
	 * Import filter conditions
	 *
	 * @param f The filter conditions we want to use
	 */
	void SetFiltering(Filtering f)
	{
		if (f.state) {
			SETBITS(this->flags, VL_FILTER);
		} else {
			CLRBITS(this->flags, VL_FILTER);
		}
		this->filter_type = f.criteria;
	}

	/**
	 * Check if a resort is needed next loop
	 *  If used the resort timer will decrease every call
	 *  till 0. If 0 reached the resort bit will be set and
	 *  the timer will be reset.
	 *
	 * @return true if resort bit is set for next loop
	 */
	bool NeedResort()
	{
		if (--this->resort_timer == 0) {
			SETBITS(this->flags, VL_RESORT);
			this->ResetResortTimer();
			return true;
		}
		return false;
	}

	/**
	 * Force a resort next Sort call
	 *  Reset the resort timer if used too.
	 */
	void ForceResort()
	{
		SETBITS(this->flags, VL_RESORT);
	}

	/**
	 * Check if the sort order is descending
	 *
	 * @return true if the sort order is descending
	 */
	bool IsDescSortOrder() const
	{
		return (this->flags & VL_DESC) != 0;
	}

	/**
	 * Toggle the sort order
	 *  Since that is the worst condition for the sort function
	 *  reverse the list here.
	 */
	void ToggleSortOrder()
	{
		this->flags ^= VL_DESC;

		if (this->IsSortable()) std::reverse(std::vector<T>::begin(), std::vector<T>::end());
	}

	/**
	 * Sort the list.
	 * @param compare The function to compare two list items
	 * @return true if the list sequence has been altered
	 *
	 */
	template <typename Comp>
	bool Sort(Comp compare)
	{
		/* Do not sort if the resort bit is not set */
		if (!(this->flags & VL_RESORT)) return false;

		CLRBITS(this->flags, VL_RESORT);

		this->ResetResortTimer();

		/* Do not sort when the list is not sortable */
		if (!this->IsSortable()) return false;

		const bool desc = (this->flags & VL_DESC) != 0;

		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;
	}

	/**
	 * Hand the array of sort function pointers to the sort list
	 *
	 * @param n_funcs The pointer to the first sort func
	 */
	void SetSortFuncs(SortFunction * const *n_funcs)
	{
		this->sort_func_list = n_funcs;
	}

	/**
	 * Overload of #Sort(SortFunction *compare)
	 * Overloaded to reduce external code
	 *
	 * @return true if the list sequence has been altered
	 */
	bool Sort()
	{
		assert(this->sort_func_list != nullptr);
		return this->Sort(this->sort_func_list[this->sort_type]);
	}

	/**
	 * Check if the filter is enabled
	 *
	 * @return true if the filter is enabled
	 */
	bool IsFilterEnabled() const
	{
		return (this->flags & VL_FILTER) != 0;
	}

	/**
	 * Enable or disable the filter
	 *
	 * @param state If filtering should be enabled or disabled
	 */
	void SetFilterState(bool state)
	{
		if (state) {
			SETBITS(this->flags, VL_FILTER);
		} else {
			CLRBITS(this->flags, VL_FILTER);
		}
	}

	/**
	 * Filter the list.
	 *
	 * @param decide The function to decide about an item
	 * @param filter_data Additional data passed to the filter function
	 * @return true if the list has been altered by filtering
	 */
	bool Filter(FilterFunction *decide, F filter_data)
	{
		/* Do not filter if the filter bit is not set */
		if (!(this->flags & VL_FILTER)) return false;

		bool changed = false;
		for (auto it = std::vector<T>::begin(); it != std::vector<T>::end(); /* Nothing */) {
			if (!decide(&*it, filter_data)) {
				it = std::vector<T>::erase(it);
				changed = true;
			} else {
				it++;
			}
		}

		return changed;
	}

	/**
	 * Hand the array of filter function pointers to the sort list
	 *
	 * @param n_funcs The pointer to the first filter func
	 */
	void SetFilterFuncs(FilterFunction * const *n_funcs)
	{
		this->filter_func_list = n_funcs;
	}

	/**
	 * Filter the data with the currently selected filter.
	 *
	 * @param filter_data Additional data passed to the filter function.
	 * @return true if the list has been altered by filtering
	 */
	bool Filter(F filter_data)
	{
		if (this->filter_func_list == nullptr) return false;
		return this->Filter(this->filter_func_list[this->filter_type], filter_data);
	}

	/**
	 * Check if a rebuild is needed
	 * @return true if a rebuild is needed
	 */
	bool NeedRebuild() const
	{
		return (this->flags & VL_REBUILD) != 0;
	}

	/**
	 * Force that a rebuild is needed
	 */
	void ForceRebuild()
	{
		SETBITS(this->flags, VL_REBUILD);
	}

	/**
	 * Notify the sortlist that the rebuild is done
	 *
	 * @note This forces a resort
	 */
	void RebuildDone()
	{
		CLRBITS(this->flags, VL_REBUILD);
		SETBITS(this->flags, VL_RESORT);
	}
};

#endif /* SORTLIST_TYPE_H */