@ -550,18 +550,18 @@ struct RefitOption {
}
} ;
typedef std : : vector < RefitOption > SubtypeList ; ///< List of refit subtypes associated to a cargo .
using RefitOptions = std : : map < CargoID , std : : vector < RefitOption > , CargoIDComparator > ; ///< Available refit options (subtype and string) associated with each cargo type .
/**
* Draw the list of available refit options for a consist and highlight the selected refit option ( if any ) .
* @ param list List of subtype options for each ( sorted ) cargo .
* @ param sel Selected refit cargo- type in the window
* @ param refits Available refit options for each ( sorted ) cargo .
* @ param sel Selected refit option in the window
* @ param pos Position of the selected item in caller widow
* @ param rows Number of rows ( capacity ) in caller window
* @ param delta Step height in caller window
* @ param r Rectangle of the matrix widget .
*/
static void DrawVehicleRefitWindow ( const SubtypeList list [ NUM_CARGO ] , const int sel [ 2 ] , uint pos , uint rows , uint delta , const Rect & r )
static void DrawVehicleRefitWindow ( const RefitOptions & refits , const RefitOption * sel , uint pos , uint rows , uint delta , const Rect & r )
{
Rect ir = r . Shrink ( WidgetDimensions : : scaled . matrix ) ;
uint current = 0 ;
@ -578,12 +578,13 @@ static void DrawVehicleRefitWindow(const SubtypeList list[NUM_CARGO], const int
Rect tr = ir . Indent ( iconwidth + WidgetDimensions : : scaled . hsep_wide , rtl ) ;
/* Draw the list of subtypes for each cargo, and find the selected refit option (by its position). */
for ( uint i = 0 ; current < pos + rows & & i < NUM_CARGO ; i + + ) {
for ( uint j = 0 ; current < pos + rows & & j < list [ i ] . size ( ) ; j + + ) {
const RefitOption & refit = list [ i ] [ j ] ;
for ( const auto & pair : refits ) {
bool has_subtypes = pair . second . size ( ) > 1 ;
for ( const RefitOption & refit : pair . second ) {
if ( current > = pos + rows ) break ;
/* Hide subtypes if sel [0] does not match */
if ( sel [ 0 ] ! = ( int ) i & & refit . subtype ! = 0xFF ) continue ;
/* Hide subtypes if sel ected cargo type does not match */
if ( ( sel = = nullptr | | sel - > cargo ! = refit . cargo ) & & refit . subtype ! = UINT8_MAX ) continue ;
/* Refit options with a position smaller than pos don't have to be drawn. */
if ( current < pos ) {
@ -591,19 +592,19 @@ static void DrawVehicleRefitWindow(const SubtypeList list[NUM_CARGO], const int
continue ;
}
if ( list[ i ] . size ( ) > 1 ) {
if ( refit . subtype ! = 0xFF ) {
if ( has_subtypes ) {
if ( refit . subtype ! = UINT8_MAX ) {
/* Draw tree lines */
int ycenter = tr . top + FONT_HEIGHT_NORMAL / 2 ;
GfxDrawLine ( iconcenter , tr . top - WidgetDimensions : : scaled . matrix . top , iconcenter , j = = list [ i ] . size ( ) - 1 ? ycenter : tr . top - WidgetDimensions : : scaled . matrix . top + delta - 1 , linecolour ) ;
GfxDrawLine ( iconcenter , tr . top - WidgetDimensions : : scaled . matrix . top , iconcenter , ( & refit = = & pair . second . back ( ) ) ? ycenter : tr . top - WidgetDimensions : : scaled . matrix . top + delta - 1 , linecolour ) ;
GfxDrawLine ( iconcenter , ycenter , iconinner , ycenter , linecolour ) ;
} else {
/* Draw expand/collapse icon */
DrawSprite ( sel [ 0 ] = = ( int ) i ? SPR_CIRCLE_UNFOLDED : SPR_CIRCLE_FOLDED , PAL_NONE , iconleft , tr . top + ( FONT_HEIGHT_NORMAL - iconheight ) / 2 ) ;
DrawSprite ( ( sel ! = nullptr & & sel - > cargo = = refit . cargo ) ? SPR_CIRCLE_UNFOLDED : SPR_CIRCLE_FOLDED , PAL_NONE , iconleft , tr . top + ( FONT_HEIGHT_NORMAL - iconheight ) / 2 ) ;
}
}
TextColour colour = ( sel [ 0 ] = = ( int ) i & & ( uint ) sel [ 1 ] = = j ) ? TC_WHITE : TC_BLACK ;
TextColour colour = ( sel ! = nullptr & & sel - > cargo = = refit . cargo & & sel - > subtype = = refit . subtype ) ? TC_WHITE : TC_BLACK ;
/* Get the cargo name. */
SetDParam ( 0 , CargoSpec : : Get ( refit . cargo ) - > name ) ;
SetDParam ( 1 , refit . string ) ;
@ -617,9 +618,8 @@ static void DrawVehicleRefitWindow(const SubtypeList list[NUM_CARGO], const int
/** Refit cargo window. */
struct RefitWindow : public Window {
int sel [ 2 ] ; ///< Index in refit options, sel[0] == -1 if nothing is selected.
RefitOption * cargo ; ///< Refit option selected by #sel.
SubtypeList list [ NUM_CARGO ] ; ///< List of refit subtypes available for each sorted cargo.
const RefitOption * selected_refit ; ///< Selected refit option.
RefitOptions refit_list ; ///< List of refit subtypes available for each sorted cargo.
VehicleOrderID order ; ///< If not #INVALID_VEH_ORDER_ID, selection is part of a refit order (rather than execute directly).
uint information_width ; ///< Width required for correctly displaying all cargoes in the information panel.
Scrollbar * vscroll ; ///< The main scrollbar.
@ -638,7 +638,12 @@ struct RefitWindow : public Window {
*/
void BuildRefitList ( )
{
for ( uint i = 0 ; i < NUM_CARGO ; i + + ) this - > list [ i ] . clear ( ) ;
/* Store the currently selected RefitOption. */
std : : optional < RefitOption > current_refit_option ;
if ( this - > selected_refit ! = nullptr ) current_refit_option = * ( this - > selected_refit ) ;
this - > selected_refit = nullptr ;
this - > refit_list . clear ( ) ;
Vehicle * v = Vehicle : : Get ( this - > window_number ) ;
/* Check only the selected vehicles. */
@ -657,19 +662,16 @@ struct RefitWindow : public Window {
if ( this - > auto_refit & & ! HasBit ( e - > info . misc_flags , EF_AUTO_REFIT ) ) continue ;
/* Loop through all cargoes in the refit mask */
int current_index = 0 ;
for ( const auto & cs : _sorted_cargo_specs ) {
CargoID cid = cs - > Index ( ) ;
/* Skip cargo type if it's not listed */
if ( ! HasBit ( cmask , cid ) ) {
current_index + + ;
continue ;
}
if ( ! HasBit ( cmask , cid ) ) continue ;
bool first_vehicle = this - > list [ current_index ] . size ( ) = = 0 ;
auto & list = this - > refit_list [ cid ] ;
bool first_vehicle = list . size ( ) = = 0 ;
if ( first_vehicle ) {
/* Keeping the current subtype is always an option. It also serves as the option in case of no subtypes */
this - > list [current_index ] .push_back ( { cid , 0xFF , STR_EMPTY } ) ;
list .push_back ( { cid , UINT8_MAX , STR_EMPTY } ) ;
}
/* Check the vehicle's callback mask for cargo suffixes.
@ -701,16 +703,15 @@ struct RefitWindow : public Window {
option . cargo = cid ;
option . subtype = refit_cyc ;
option . string = subtype ;
include ( this - > list [ current_index ] , option ) ;
include ( list , option ) ;
} else {
/* Intersect the subtypes of earlier vehicles with the subtypes of this vehicle */
if ( subtype = = STR_EMPTY ) {
/* No more subtypes for this vehicle, delete all subtypes >= refit_cyc */
SubtypeList & l = this - > list [ current_index ] ;
/* 0xFF item is in front, other subtypes are sorted. So just truncate the list in the right spot */
for ( uint i = 1 ; i < l . size ( ) ; i + + ) {
if ( l [ i ] . subtype > = refit_cyc ) {
l . resize ( i ) ;
/* UINT8_MAX item is in front, other subtypes are sorted. So just truncate the list in the right spot */
for ( uint i = 1 ; i < list . size ( ) ; i + + ) {
if ( list [ i ] . subtype > = refit_cyc ) {
list . resize ( i ) ;
break ;
}
}
@ -718,11 +719,10 @@ struct RefitWindow : public Window {
} else {
/* Check whether the subtype matches with the subtype of earlier vehicles. */
uint pos = 1 ;
SubtypeList & l = this - > list [ current_index ] ;
while ( pos < l . size ( ) & & l [ pos ] . subtype ! = refit_cyc ) pos + + ;
if ( pos < l . size ( ) & & l [ pos ] . string ! = subtype ) {
while ( pos < list . size ( ) & & list [ pos ] . subtype ! = refit_cyc ) pos + + ;
if ( pos < list . size ( ) & & list [ pos ] . string ! = subtype ) {
/* String mismatch, remove item keeping the order */
l . erase ( l . begin ( ) + pos ) ;
l ist . erase ( l ist . begin ( ) + pos ) ;
}
}
}
@ -736,9 +736,23 @@ struct RefitWindow : public Window {
v - > First ( ) - > InvalidateNewGRFCache ( ) ;
v - > InvalidateNewGRFCache ( ) ;
}
current_index + + ;
}
} while ( v - > IsGroundVehicle ( ) & & ( v = v - > Next ( ) ) ! = nullptr ) ;
/* Restore the previously selected RefitOption. */
if ( current_refit_option . has_value ( ) ) {
for ( const auto & pair : this - > refit_list ) {
for ( const auto & refit : pair . second ) {
if ( refit . cargo = = current_refit_option - > cargo & & refit . subtype = = current_refit_option - > subtype ) {
this - > selected_refit = & refit ;
break ;
}
}
if ( this - > selected_refit ! = nullptr ) break ;
}
}
this - > SetWidgetDisabledState ( WID_VR_REFIT , this - > selected_refit = = nullptr ) ;
}
/**
@ -746,24 +760,22 @@ struct RefitWindow : public Window {
*/
void RefreshScrollbar ( )
{
uint scroll_row = 0 ;
uint row = 0 ;
for ( uint i = 0 ; i < NUM_CARGO ; i + + ) {
for ( uint j = 0 ; j < this - > list [ i ] . size ( ) ; j + + ) {
const RefitOption & refit = this - > list [ i ] [ j ] ;
/* Hide subtypes if sel[0] does not match */
if ( this - > sel [ 0 ] ! = ( int ) i & & refit . subtype ! = 0xFF ) continue ;
if ( this - > sel [ 0 ] = = ( int ) i & & ( uint ) this - > sel [ 1 ] = = j ) scroll_row = row ;
row + + ;
size_t scroll_row = 0 ;
size_t rows = 0 ;
CargoID cargo = this - > selected_refit = = nullptr ? ( CargoID ) CT_INVALID : this - > selected_refit - > cargo ;
for ( const auto & pair : this - > refit_list ) {
if ( pair . first = = cargo ) {
/* selected_refit points to an element in the vector so no need to search for it. */
scroll_row = rows + ( this - > selected_refit - pair . second . data ( ) ) ;
rows + = pair . second . size ( ) ;
} else {
rows + + ; /* Unselected cargo type is collapsed into one row. */
}
}
this - > vscroll - > SetCount ( row ) ;
if ( scroll_row < row ) this- > vscroll - > ScrollTowards ( scroll_row ) ;
this - > vscroll - > SetCount ( row s ) ;
this- > vscroll - > ScrollTowards ( static_cast < int > ( scroll_row ) ) ;
}
/**
@ -774,45 +786,24 @@ struct RefitWindow : public Window {
{
uint row = 0 ;
for ( uint i = 0 ; i < NUM_CARGO ; i + + ) {
for ( uint j = 0 ; j < this - > list [ i ] . size ( ) ; j + + ) {
const RefitOption & refit = this - > list [ i ] [ j ] ;
/* Hide subtypes if sel[0] does not match */
if ( this - > sel [ 0 ] ! = ( int ) i & & refit . subtype ! = 0xFF ) continue ;
for ( const auto & pair : refit_list ) {
for ( const RefitOption & refit : pair . second ) {
if ( row = = click_row ) {
this - > sel [ 0 ] = i ;
this - > sel [ 1 ] = j ;
this - > selected_refit = & refit ;
return ;
}
row + + ;
/* If this cargo type is not already selected then its subtypes are not visible, so skip the rest. */
if ( this - > selected_refit = = nullptr | | this - > selected_refit - > cargo ! = refit . cargo ) break ;
}
}
this - > sel [ 0 ] = - 1 ;
this - > sel [ 1 ] = 0 ;
}
/**
* Gets the # RefitOption placed in the selected index .
* @ return Pointer to the # RefitOption currently in use .
*/
RefitOption * GetRefitOption ( )
{
if ( this - > sel [ 0 ] < 0 ) return nullptr ;
SubtypeList & l = this - > list [ this - > sel [ 0 ] ] ;
if ( ( uint ) this - > sel [ 1 ] > = l . size ( ) ) return nullptr ;
return & l [ this - > sel [ 1 ] ] ;
/* No selection made */
this - > selected_refit = nullptr ;
}
RefitWindow ( WindowDesc * desc , const Vehicle * v , VehicleOrderID order , bool auto_refit ) : Window ( desc )
{
this - > sel [ 0 ] = - 1 ;
this - > sel [ 1 ] = 0 ;
this - > auto_refit = auto_refit ;
this - > order = order ;
this - > CreateNestedTree ( ) ;
@ -830,37 +821,13 @@ struct RefitWindow : public Window {
this - > FinishInitNested ( v - > index ) ;
this - > owner = v - > owner ;
this - > SetWidgetDisabledState ( WID_VR_REFIT , this - > sel [ 0 ] < 0 ) ;
this - > SetWidgetDisabledState ( WID_VR_REFIT , this - > sel ected_refit = = nullptr ) ;
}
void OnInit ( ) override
{
if ( this - > cargo ! = nullptr ) {
/* Store the RefitOption currently in use. */
RefitOption current_refit_option = * ( this - > cargo ) ;
/* Rebuild the refit list */
this - > BuildRefitList ( ) ;
this - > sel [ 0 ] = - 1 ;
this - > sel [ 1 ] = 0 ;
this - > cargo = nullptr ;
for ( uint i = 0 ; this - > cargo = = nullptr & & i < NUM_CARGO ; i + + ) {
for ( uint j = 0 ; j < list [ i ] . size ( ) ; j + + ) {
if ( list [ i ] [ j ] = = current_refit_option ) {
this - > sel [ 0 ] = i ;
this - > sel [ 1 ] = j ;
this - > cargo = & list [ i ] [ j ] ;
break ;
}
}
}
this - > SetWidgetDisabledState ( WID_VR_REFIT , this - > sel [ 0 ] < 0 ) ;
this - > RefreshScrollbar ( ) ;
} else {
/* Rebuild the refit list */
this - > OnInvalidateData ( VIWD_CONSIST_CHANGED ) ;
}
/* (Re)build the refit list */
this - > OnInvalidateData ( VIWD_CONSIST_CHANGED ) ;
}
void OnPaint ( ) override
@ -913,14 +880,14 @@ struct RefitWindow : public Window {
* @ return INVALID_STRING_ID if there is no capacity . StringID to use in any other case .
* @ post String parameters have been set .
*/
StringID GetCapacityString ( RefitOption * option ) const
StringID GetCapacityString ( const RefitOption & option ) const
{
assert ( _current_company = = _local_company ) ;
auto [ cost , refit_capacity , mail_capacity , cargo_capacities ] = Command < CMD_REFIT_VEHICLE > : : Do ( DC_QUERY_COST , this - > selected_vehicle , option - > cargo , option - > subtype , this - > auto_refit , false , this - > num_vehicles ) ;
auto [ cost , refit_capacity , mail_capacity , cargo_capacities ] = Command < CMD_REFIT_VEHICLE > : : Do ( DC_QUERY_COST , this - > selected_vehicle , option . cargo , option . subtype , this - > auto_refit , false , this - > num_vehicles ) ;
if ( cost . Failed ( ) ) return INVALID_STRING_ID ;
SetDParam ( 0 , option - > cargo ) ;
SetDParam ( 0 , option . cargo ) ;
SetDParam ( 1 , refit_capacity ) ;
Money money = cost . GetCost ( ) ;
@ -1021,12 +988,12 @@ struct RefitWindow : public Window {
}
case WID_VR_MATRIX :
DrawVehicleRefitWindow ( this - > list, this - > sel , this - > vscroll - > GetPosition ( ) , this - > vscroll - > GetCapacity ( ) , this - > resize . step_height , r ) ;
DrawVehicleRefitWindow ( this - > refit_ list, this - > sel ected_refit , this - > vscroll - > GetPosition ( ) , this - > vscroll - > GetCapacity ( ) , this - > resize . step_height , r ) ;
break ;
case WID_VR_INFO :
if ( this - > cargo ! = nullptr ) {
StringID string = this - > GetCapacityString ( this - > cargo ) ;
if ( this - > selected_refit ! = nullptr ) {
StringID string = this - > GetCapacityString ( * this - > selected_refit ) ;
if ( string ! = INVALID_STRING_ID ) {
DrawStringMultiLine ( r . Shrink ( WidgetDimensions : : scaled . framerect ) , string ) ;
}
@ -1061,9 +1028,9 @@ struct RefitWindow : public Window {
uint max_width = 0 ;
/* Check the width of all cargo information strings. */
for ( uint i = 0 ; i < NUM_CARGO ; i + + ) {
for ( uint j = 0 ; j < this - > list [ i ] . size ( ) ; j + + ) {
StringID string = this - > GetCapacityString ( & list [ i ] [ j ] ) ;
for ( const auto & list : this - > refit_list ) {
for ( const RefitOption & refit : list . second ) {
StringID string = this - > GetCapacityString ( refit ) ;
if ( string ! = INVALID_STRING_ID ) {
Dimension dim = GetStringBoundingBox ( string ) ;
max_width = std : : max ( dim . width , max_width ) ;
@ -1080,7 +1047,6 @@ struct RefitWindow : public Window {
case 1 : // A new cargo has been selected.
if ( ! gui_scope ) break ;
this - > cargo = GetRefitOption ( ) ;
this - > RefreshScrollbar ( ) ;
break ;
}
@ -1168,7 +1134,7 @@ struct RefitWindow : public Window {
case WID_VR_MATRIX : { // listbox
this - > SetSelection ( this - > vscroll - > GetScrolledRowFromWidget ( pt . y , this , WID_VR_MATRIX ) ) ;
this - > SetWidgetDisabledState ( WID_VR_REFIT , this - > sel [ 0 ] < 0 ) ;
this - > SetWidgetDisabledState ( WID_VR_REFIT , this - > sel ected_refit = = nullptr ) ;
this - > InvalidateData ( 1 ) ;
if ( click_count = = 1 ) break ;
@ -1176,14 +1142,14 @@ struct RefitWindow : public Window {
}
case WID_VR_REFIT : // refit button
if ( this - > cargo ! = nullptr ) {
if ( this - > selected_refit ! = nullptr ) {
const Vehicle * v = Vehicle : : Get ( this - > window_number ) ;
if ( this - > order = = INVALID_VEH_ORDER_ID ) {
bool delete_window = this - > selected_vehicle = = v - > index & & this - > num_vehicles = = UINT8_MAX ;
if ( Command < CMD_REFIT_VEHICLE > : : Post ( GetCmdRefitVehMsg ( v ) , v - > tile , this - > selected_vehicle , this - > cargo- > cargo , this - > cargo - > subtype , false , false , this - > num_vehicles ) & & delete_window ) this - > Close ( ) ;
if ( Command < CMD_REFIT_VEHICLE > : : Post ( GetCmdRefitVehMsg ( v ) , v - > tile , this - > selected_vehicle , this - > selected_refit- > cargo , this - > selected_refit - > subtype , false , false , this - > num_vehicles ) & & delete_window ) this - > Close ( ) ;
} else {
if ( Command < CMD_ORDER_REFIT > : : Post ( v - > tile , v - > index , this - > order , this - > cargo - > cargo ) ) this - > Close ( ) ;
if ( Command < CMD_ORDER_REFIT > : : Post ( v - > tile , v - > index , this - > order , this - > selected_refit - > cargo ) ) this - > Close ( ) ;
}
}
break ;