4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
10 /** @file sortlist_type.h Base types for having sorted lists in GUIs. */
12 #ifndef SORTLIST_TYPE_H
13 #define SORTLIST_TYPE_H
15 #include "core/enum_type.hpp"
16 #include "core/bitmath_func.hpp"
17 #include "core/sort_func.hpp"
18 #include "core/smallvec_type.hpp"
19 #include "date_type.h"
21 /** Flags of the sort list. */
23 VL_NONE
= 0, ///< no sort
24 VL_DESC
= 1 << 0, ///< sort descending or ascending
25 VL_RESORT
= 1 << 1, ///< instruct the code to resort the list in the next loop
26 VL_REBUILD
= 1 << 2, ///< rebuild the sort list
27 VL_FIRST_SORT
= 1 << 3, ///< sort with quick sort first
28 VL_FILTER
= 1 << 4, ///< filter disabled/enabled
31 DECLARE_ENUM_AS_BIT_SET(SortListFlags
)
33 /** Data structure describing how to show the list (what sort direction and criteria). */
35 bool order
; ///< Ascending/descending
36 byte criteria
; ///< Sorting criteria
40 * List template of 'things' \p T to sort in a GUI.
41 * @tparam T Type of data stored in the list to represent each item.
44 class GUIList
: public SmallVector
<T
, 32> {
46 typedef int CDECL
SortFunction(const T
*, const T
*); ///< Signature of sort function.
49 SortFunction
* const *sort_func_list
; ///< the sort criteria functions
50 SortListFlags flags
; ///< used to control sorting/resorting/etc.
51 uint8 sort_type
; ///< what criteria to sort on
52 uint16 resort_timer
; ///< resort list after a given amount of ticks if set
55 * Check if the list is sortable
57 * @return true if we can sort the list
59 bool IsSortable() const
61 return (this->data
!= NULL
&& this->items
>= 2);
65 * Reset the resort timer
67 void ResetResortTimer()
69 /* Resort every 10 days */
70 this->resort_timer
= DAY_TICKS
* 10;
82 * Get the sorttype of the list
84 * @return The current sorttype
86 uint8
SortType() const
88 return this->sort_type
;
92 * Set the sorttype of the list
94 * @param n_type the new sort type
96 void SetSortType(uint8 n_type
)
98 if (this->sort_type
!= n_type
) {
99 SETBITS(this->flags
, VL_RESORT
| VL_FIRST_SORT
);
100 this->sort_type
= n_type
;
105 * Export current sort conditions
107 * @return the current sort conditions
109 Listing
GetListing() const
112 l
.order
= (this->flags
& VL_DESC
) != 0;
113 l
.criteria
= this->sort_type
;
119 * Import sort conditions
121 * @param l The sort conditions we want to use
123 void SetListing(Listing l
)
126 SETBITS(this->flags
, VL_DESC
);
128 CLRBITS(this->flags
, VL_DESC
);
130 this->sort_type
= l
.criteria
;
132 SETBITS(this->flags
, VL_FIRST_SORT
);
136 * Check if a resort is needed next loop
137 * If used the resort timer will decrease every call
138 * till 0. If 0 reached the resort bit will be set and
139 * the timer will be reset.
141 * @return true if resort bit is set for next loop
145 if (--this->resort_timer
== 0) {
146 SETBITS(this->flags
, VL_RESORT
);
147 this->ResetResortTimer();
154 * Force a resort next Sort call
155 * Reset the resort timer if used too.
159 SETBITS(this->flags
, VL_RESORT
);
163 * Check if the sort order is descending
165 * @return true if the sort order is descending
167 bool IsDescSortOrder() const
169 return (this->flags
& VL_DESC
) != 0;
173 * Toggle the sort order
174 * Since that is the worst condition for the sort function
175 * reverse the list here.
177 void ToggleSortOrder()
179 this->flags
^= VL_DESC
;
181 if (this->IsSortable()) MemReverseT(this->data
, this->items
);
186 * For the first sorting we use quick sort since it is
187 * faster for irregular sorted data. After that we
190 * @param compare The function to compare two list items
191 * @return true if the list sequence has been altered
194 bool Sort(SortFunction
*compare
)
196 /* Do not sort if the resort bit is not set */
197 if (!(this->flags
& VL_RESORT
)) return false;
199 CLRBITS(this->flags
, VL_RESORT
);
201 this->ResetResortTimer();
203 /* Do not sort when the list is not sortable */
204 if (!this->IsSortable()) return false;
206 const bool desc
= (this->flags
& VL_DESC
) != 0;
208 if (this->flags
& VL_FIRST_SORT
) {
209 CLRBITS(this->flags
, VL_FIRST_SORT
);
211 QSortT(this->data
, this->items
, compare
, desc
);
215 GSortT(this->data
, this->items
, compare
, desc
);
220 * Hand the array of sort function pointers to the sort list
222 * @param n_funcs The pointer to the first sort func
224 void SetSortFuncs(SortFunction
* const *n_funcs
)
226 this->sort_func_list
= n_funcs
;
230 * Overload of #Sort(SortFunction *compare)
231 * Overloaded to reduce external code
233 * @return true if the list sequence has been altered
237 assert(this->sort_func_list
!= NULL
);
238 return this->Sort(this->sort_func_list
[this->sort_type
]);
242 * Check if the filter is enabled
244 * @return true if the filter is enabled
246 bool IsFilterEnabled() const
248 return (this->flags
& VL_FILTER
) != 0;
252 * Enable or disable the filter
254 * @param state If filtering should be enabled or disabled
256 void SetFilterState(bool state
)
259 SETBITS(this->flags
, VL_FILTER
);
261 CLRBITS(this->flags
, VL_FILTER
);
267 * @tparam F Type of data fed as additional value to the filter function.
268 * @param decide The function to decide about an item
269 * @param filter_data Additional data passed to the filter function
270 * @return true if the list has been altered by filtering
272 template <typename F
>
273 bool Filter (bool CDECL
decide (const T
*, F
), F filter_data
)
275 /* Do not filter if the filter bit is not set */
276 if (!(this->flags
& VL_FILTER
)) return false;
278 bool changed
= false;
279 for (uint iter
= 0; iter
< this->items
;) {
280 T
*item
= &this->data
[iter
];
281 if (!decide(item
, filter_data
)) {
293 * Check if a rebuild is needed
294 * @return true if a rebuild is needed
296 bool NeedRebuild() const
298 return (this->flags
& VL_REBUILD
) != 0;
302 * Force that a rebuild is needed
306 SETBITS(this->flags
, VL_REBUILD
);
310 * Notify the sortlist that the rebuild is done
312 * @note This forces a resort
316 CLRBITS(this->flags
, VL_REBUILD
);
317 SETBITS(this->flags
, VL_RESORT
| VL_FIRST_SORT
);
321 #endif /* SORTLIST_TYPE_H */