2009-08-21 22:21:05 +02:00
/*
* 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/>.
*/
2008-05-17 15:01:30 +02:00
/** @file sortlist_type.h Base types for having sorted lists in GUIs. */
# ifndef SORTLIST_TYPE_H
# define SORTLIST_TYPE_H
2008-05-30 11:32:24 +02:00
# include "core/enum_type.hpp"
# include "core/bitmath_func.hpp"
2023-05-18 11:20:35 +02:00
# include "core/mem_func.hpp"
2023-08-16 15:01:24 +02:00
# include "timer/timer_game_tick.h"
2008-05-26 18:23:23 +02:00
2009-07-03 21:34:28 +02:00
/** Flags of the sort list. */
2008-05-17 15:01:30 +02:00
enum SortListFlags {
2008-05-26 23:27:06 +02:00
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
2021-01-01 00:37:29 +01:00
VL_FILTER = 1 < < 3 , ///< filter disabled/enabled
VL_END = 1 < < 4 ,
2008-05-17 15:01:30 +02:00
} ;
2010-03-23 23:25:43 +01:00
DECLARE_ENUM_AS_BIT_SET ( SortListFlags )
2008-05-17 15:01:30 +02:00
2013-01-08 23:46:42 +01:00
/** Data structure describing how to show the list (what sort direction and criteria). */
2008-05-17 15:01:30 +02:00
struct Listing {
bool order ; ///< Ascending/descending
2024-03-16 23:59:32 +01:00
uint8_t criteria ; ///< Sorting criteria
2008-05-17 15:01:30 +02:00
} ;
2009-07-03 21:34:28 +02:00
/** Data structure describing what to show in the list (filter criteria). */
2009-02-06 01:51:11 +01:00
struct Filtering {
bool state ; ///< Filter on/off
2024-03-16 23:59:32 +01:00
uint8_t criteria ; ///< Filtering criteria
2009-02-06 01:51:11 +01:00
} ;
2008-05-17 15:01:30 +02:00
2009-07-03 21:34:28 +02:00
/**
* List template of ' things ' \ p T to sort in a GUI .
* @ tparam T Type of data stored in the list to represent each item .
2023-12-03 00:28:01 +01:00
* @ tparam P Tyoe of data passed as additional parameter to the sort function .
2009-07-03 21:34:28 +02:00
* @ tparam F Type of data fed as additional value to the filter function . @ see FilterFunction
*/
2023-12-03 00:28:01 +01:00
template < typename T , typename P = std : : nullptr_t , typename F = const char * >
2019-03-03 18:30:09 +01:00
class GUIList : public std : : vector < T > {
2008-05-26 18:44:48 +02:00
public :
2023-12-03 00:28:01 +01:00
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.
2024-04-25 23:13:23 +02:00
using FilterFunction = bool ( const T * , F ) ; ///< Signature of filter function.
2008-05-26 18:44:48 +02:00
2008-06-16 19:10:55 +02:00
protected :
2024-04-25 22:00:49 +02:00
std : : span < SortFunction * const > sort_func_list ; ///< the sort criteria functions
std : : span < FilterFunction * const > filter_func_list ; ///< the filter criteria functions
2009-02-06 01:51:11 +01:00
SortListFlags flags ; ///< used to control sorting/resorting/etc.
2023-05-08 19:01:06 +02:00
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
2008-05-26 18:44:48 +02:00
2023-12-03 00:28:01 +01:00
/* 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 ;
2008-05-26 18:44:48 +02:00
/**
* Check if the list is sortable
*
* @ return true if we can sort the list
*/
bool IsSortable ( ) const
{
2018-09-20 23:41:43 +02:00
return std : : vector < T > : : size ( ) > = 2 ;
2008-05-26 18:44:48 +02:00
}
/**
* Reset the resort timer
*/
void ResetResortTimer ( )
{
/* Resort every 10 days */
2023-08-16 15:01:24 +02:00
this - > resort_timer = Ticks : : DAY_TICKS * 10 ;
2008-05-26 18:44:48 +02:00
}
public :
2023-12-03 00:28:01 +01:00
/* 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 >
2008-05-26 18:44:48 +02:00
GUIList ( ) :
2024-04-25 22:00:49 +02:00
sort_func_list ( { } ) ,
filter_func_list ( { } ) ,
2021-01-01 00:37:29 +01:00
flags ( VL_NONE ) ,
2008-05-26 18:44:48 +02:00
sort_type ( 0 ) ,
2009-02-06 01:51:11 +01:00
filter_type ( 0 ) ,
2023-12-03 00:28:01 +01:00
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 >
2024-01-03 22:33:38 +01:00
GUIList ( const P & params ) :
2024-04-25 22:00:49 +02:00
sort_func_list ( { } ) ,
filter_func_list ( { } ) ,
2023-12-03 00:28:01 +01:00
flags ( VL_NONE ) ,
sort_type ( 0 ) ,
filter_type ( 0 ) ,
resort_timer ( 1 ) ,
params ( params )
2008-05-26 18:44:48 +02:00
{ } ;
/**
* Get the sorttype of the list
*
* @ return The current sorttype
*/
2023-05-08 19:01:06 +02:00
uint8_t SortType ( ) const
2008-05-26 18:44:48 +02:00
{
return this - > sort_type ;
}
/**
* Set the sorttype of the list
*
* @ param n_type the new sort type
*/
2023-05-08 19:01:06 +02:00
void SetSortType ( uint8_t n_type )
2008-05-26 18:44:48 +02:00
{
2024-04-25 22:00:49 +02:00
assert ( n_type < std : : size ( this - > sort_func_list ) ) ;
2008-05-26 18:44:48 +02:00
if ( this - > sort_type ! = n_type ) {
2021-01-01 00:37:29 +01:00
SETBITS ( this - > flags , VL_RESORT ) ;
2008-05-26 18:44:48 +02:00
this - > sort_type = n_type ;
}
}
/**
* Export current sort conditions
*
* @ return the current sort conditions
*/
Listing GetListing ( ) const
{
Listing l ;
2009-06-01 17:01:54 +02:00
l . order = ( this - > flags & VL_DESC ) ! = 0 ;
2008-05-26 18:44:48 +02:00
l . criteria = this - > sort_type ;
return l ;
}
/**
* Import sort conditions
*
2009-02-06 01:51:11 +01:00
* @ param l The sort conditions we want to use
2008-05-26 18:44:48 +02:00
*/
void SetListing ( Listing l )
{
if ( l . order ) {
SETBITS ( this - > flags , VL_DESC ) ;
} else {
CLRBITS ( this - > flags , VL_DESC ) ;
}
this - > sort_type = l . criteria ;
}
2009-02-06 01:51:11 +01:00
/**
* Get the filtertype of the list
*
* @ return The current filtertype
*/
2023-05-08 19:01:06 +02:00
uint8_t FilterType ( ) const
2009-02-06 01:51:11 +01:00
{
return this - > filter_type ;
}
/**
* Set the filtertype of the list
*
* @ param n_type the new filter type
*/
2023-05-08 19:01:06 +02:00
void SetFilterType ( uint8_t n_type )
2009-02-06 01:51:11 +01:00
{
2024-04-25 22:00:49 +02:00
assert ( n_type < std : : size ( this - > filter_func_list ) ) ;
2009-02-06 01:51:11 +01:00
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 ;
2009-06-01 17:01:54 +02:00
f . state = ( this - > flags & VL_FILTER ) ! = 0 ;
2009-02-06 01:51:11 +01:00
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 ;
}
2008-05-26 18:44:48 +02:00
/**
* 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
{
2009-06-01 17:01:54 +02:00
return ( this - > flags & VL_DESC ) ! = 0 ;
2008-05-26 18:44:48 +02:00
}
/**
2013-01-08 23:46:42 +01:00
* Toggle the sort order
2008-05-26 18:44:48 +02:00
* Since that is the worst condition for the sort function
* reverse the list here .
*/
2008-06-14 18:23:08 +02:00
void ToggleSortOrder ( )
2008-05-26 18:44:48 +02:00
{
this - > flags ^ = VL_DESC ;
2023-06-04 00:25:01 +02:00
if ( this - > IsSortable ( ) ) std : : reverse ( std : : vector < T > : : begin ( ) , std : : vector < T > : : end ( ) ) ;
2008-05-26 18:44:48 +02:00
}
/**
2008-06-14 18:23:08 +02:00
* Sort the list .
2008-05-26 18:44:48 +02:00
* @ param compare The function to compare two list items
2008-05-27 12:27:30 +02:00
* @ return true if the list sequence has been altered
2010-08-01 21:44:49 +02:00
*
*/
2020-06-15 19:53:13 +02:00
template < typename Comp >
bool Sort ( Comp compare )
2008-05-26 18:44:48 +02:00
{
/* Do not sort if the resort bit is not set */
2009-06-01 17:01:54 +02:00
if ( ! ( this - > flags & VL_RESORT ) ) return false ;
2008-05-26 18:44:48 +02:00
2008-05-26 23:08:03 +02:00
CLRBITS ( this - > flags , VL_RESORT ) ;
this - > ResetResortTimer ( ) ;
/* Do not sort when the list is not sortable */
2008-05-27 12:27:30 +02:00
if ( ! this - > IsSortable ( ) ) return false ;
2008-05-26 23:08:03 +02:00
2009-06-01 17:01:54 +02:00
const bool desc = ( this - > flags & VL_DESC ) ! = 0 ;
2008-05-26 23:27:06 +02:00
2023-12-03 00:28:01 +01:00
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 ) ; } ) ;
}
2008-05-27 12:27:30 +02:00
return true ;
2008-05-26 18:44:48 +02:00
}
/**
2024-04-25 22:00:49 +02:00
* Hand the sort function pointers to the GUIList .
2008-05-26 18:44:48 +02:00
*
2024-04-25 22:00:49 +02:00
* @ param n_funcs Span covering the sort function pointers .
2008-05-26 18:44:48 +02:00
*/
2024-04-25 22:00:49 +02:00
void SetSortFuncs ( std : : span < SortFunction * const > n_funcs )
2008-05-26 18:44:48 +02:00
{
2009-02-06 01:51:11 +01:00
this - > sort_func_list = n_funcs ;
2008-05-26 18:44:48 +02:00
}
/**
2009-07-03 21:34:28 +02:00
* Overload of # Sort ( SortFunction * compare )
2008-05-26 18:44:48 +02:00
* Overloaded to reduce external code
2008-05-27 12:27:30 +02:00
*
* @ return true if the list sequence has been altered
2008-05-26 18:44:48 +02:00
*/
2008-05-27 12:27:30 +02:00
bool Sort ( )
2008-05-26 18:44:48 +02:00
{
2024-04-25 22:00:49 +02:00
if ( this - > sort_func_list . empty ( ) ) return false ;
assert ( this - > sort_type < this - > sort_func_list . size ( ) ) ;
2009-02-06 01:51:11 +01:00
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
{
2009-06-01 17:01:54 +02:00
return ( this - > flags & VL_FILTER ) ! = 0 ;
2009-02-06 01:51:11 +01:00
}
/**
* 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
2009-02-06 11:31:05 +01:00
* @ param filter_data Additional data passed to the filter function
2009-02-06 01:51:11 +01:00
* @ return true if the list has been altered by filtering
2009-02-06 11:31:05 +01:00
*/
2009-02-06 11:38:57 +01:00
bool Filter ( FilterFunction * decide , F filter_data )
2009-02-06 01:51:11 +01:00
{
/* Do not filter if the filter bit is not set */
2009-06-01 17:01:54 +02:00
if ( ! ( this - > flags & VL_FILTER ) ) return false ;
2009-02-06 01:51:11 +01:00
2009-02-06 19:00:05 +01:00
bool changed = false ;
2018-09-25 23:01:05 +02:00
for ( auto it = std : : vector < T > : : begin ( ) ; it ! = std : : vector < T > : : end ( ) ; /* Nothing */ ) {
if ( ! decide ( & * it , filter_data ) ) {
it = std : : vector < T > : : erase ( it ) ;
2009-02-06 19:00:05 +01:00
changed = true ;
2009-02-06 01:51:11 +01:00
} else {
2018-09-25 23:01:05 +02:00
it + + ;
2009-02-06 01:51:11 +01:00
}
}
2009-02-06 19:00:05 +01:00
return changed ;
2009-02-06 01:51:11 +01:00
}
/**
2024-04-25 22:00:49 +02:00
* Hand the filter function pointers to the GUIList .
2009-02-06 01:51:11 +01:00
*
2024-04-25 22:00:49 +02:00
* @ param n_funcs Span covering the filter function pointers .
2009-02-06 01:51:11 +01:00
*/
2024-04-25 22:00:49 +02:00
void SetFilterFuncs ( std : : span < FilterFunction * const > n_funcs )
2009-02-06 01:51:11 +01:00
{
this - > filter_func_list = n_funcs ;
}
/**
* Filter the data with the currently selected filter .
*
2009-02-06 11:31:05 +01:00
* @ param filter_data Additional data passed to the filter function .
2009-02-06 01:51:11 +01:00
* @ return true if the list has been altered by filtering
*/
2009-02-06 11:38:57 +01:00
bool Filter ( F filter_data )
2009-02-06 01:51:11 +01:00
{
2024-04-25 22:00:49 +02:00
if ( this - > filter_func_list . empty ( ) ) return false ;
assert ( this - > filter_type < this - > filter_func_list . size ( ) ) ;
2009-02-06 01:51:11 +01:00
return this - > Filter ( this - > filter_func_list [ this - > filter_type ] , filter_data ) ;
2008-05-26 18:44:48 +02:00
}
/**
* Check if a rebuild is needed
* @ return true if a rebuild is needed
*/
bool NeedRebuild ( ) const
{
2009-06-01 17:01:54 +02:00
return ( this - > flags & VL_REBUILD ) ! = 0 ;
2008-05-26 18:44:48 +02:00
}
/**
* 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 ) ;
2021-01-01 00:37:29 +01:00
SETBITS ( this - > flags , VL_RESORT ) ;
2008-05-26 18:44:48 +02:00
}
2008-05-17 15:01:30 +02:00
} ;
# endif /* SORTLIST_TYPE_H */