@ -1045,6 +1045,9 @@ void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_li
int small_text_y_offset = ir . Height ( ) - GetCharacterHeight ( FS_SMALL ) ;
int replace_icon_y_offset = ( ir . Height ( ) - replace_icon . height ) / 2 ;
const int offset = ( rtl ? - circle_width : circle_width ) / 2 ;
const int level_width = rtl ? - WidgetDimensions : : scaled . hsep_indent : WidgetDimensions : : scaled . hsep_indent ;
int y = ir . top ;
for ( auto it = first ; it ! = last ; + + it ) {
const auto & item = * it ;
@ -1052,6 +1055,21 @@ void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_li
bool has_variants = ( item . flags & EngineDisplayFlags : : HasVariants ) ! = EngineDisplayFlags : : None ;
bool is_folded = ( item . flags & EngineDisplayFlags : : IsFolded ) ! = EngineDisplayFlags : : None ;
bool shaded = ( item . flags & EngineDisplayFlags : : Shaded ) ! = EngineDisplayFlags : : None ;
if ( item . indent > 0 ) {
/* Draw tree continuation lines. */
int tx = ( rtl ? ir . right : ir . left ) + offset ;
int ty = y - WidgetDimensions : : scaled . matrix . top ;
for ( uint lvl = 1 ; lvl < = item . indent ; + + lvl ) {
if ( HasBit ( item . level_mask , lvl ) ) GfxDrawLine ( tx , ty , tx , ty + step_size - 1 , linecolour , WidgetDimensions : : scaled . fullbevel . top ) ;
if ( lvl < item . indent ) tx + = level_width ;
}
/* Draw our node in the tree. */
int ycentre = y + normal_text_y_offset + GetCharacterHeight ( FS_NORMAL ) / 2 - 1 ;
if ( ! HasBit ( item . level_mask , item . indent ) ) GfxDrawLine ( tx , ty , tx , ycentre , linecolour , WidgetDimensions : : scaled . fullbevel . top ) ;
GfxDrawLine ( tx , ycentre , tx + offset - ( rtl ? - 1 : 1 ) , ycentre , linecolour , WidgetDimensions : : scaled . fullbevel . top ) ;
}
/* Note: num_engines is only used in the autoreplace GUI, so it is correct to use _local_company here. */
const uint num_engines = GetGroupNumEngines ( _local_company , selected_group , item . engine_id ) ;
@ -1079,14 +1097,6 @@ void DrawEngineList(VehicleType type, const Rect &r, const GUIEngineList &eng_li
Rect fr = ir . Indent ( indent , rtl ) . WithWidth ( circle_width , rtl ) ;
DrawSpriteIgnorePadding ( is_folded ? SPR_CIRCLE_FOLDED : SPR_CIRCLE_UNFOLDED , PAL_NONE , { fr . left , y , fr . right , y + ir . Height ( ) - 1 } , SA_CENTER ) ;
}
if ( indent > 0 ) {
/* Draw tree lines */
Rect fr = ir . Indent ( indent - WidgetDimensions : : scaled . hsep_indent , rtl ) . WithWidth ( circle_width , rtl ) ;
int ycenter = y + normal_text_y_offset + GetCharacterHeight ( FS_NORMAL ) / 2 ;
bool continues = std : : next ( it ) ! = std : : end ( eng_list ) & & std : : next ( it ) - > indent = = item . indent ;
GfxDrawLine ( fr . left + circle_width / 2 , y - WidgetDimensions : : scaled . matrix . top , fr . left + circle_width / 2 , continues ? y - WidgetDimensions : : scaled . matrix . top + step_size - 1 : ycenter , linecolour , WidgetDimensions : : scaled . fullbevel . top ) ;
GfxDrawLine ( fr . left + circle_width / 2 , ycenter , fr . right , ycenter , linecolour , WidgetDimensions : : scaled . fullbevel . top ) ;
}
y + = step_size ;
}
}
@ -1114,6 +1124,44 @@ void DisplayVehicleSortDropDown(Window *w, VehicleType vehicle_type, int selecte
ShowDropDownMenu ( w , _engine_sort_listing [ vehicle_type ] , selected , button , 0 , hidden_mask ) ;
}
/**
* Add children to GUI engine list to build a hierarchical tree .
* @ param dst Destination list .
* @ param src Source list .
* @ param parent Current tree parent ( set by self with recursion ) .
* @ param indent Current tree indentation level ( set by self with recursion ) .
*/
void GUIEngineListAddChildren ( GUIEngineList & dst , const GUIEngineList & src , EngineID parent , uint8_t indent )
{
for ( const auto & item : src ) {
if ( item . variant_id ! = parent | | item . engine_id = = parent ) continue ;
const Engine * e = Engine : : Get ( item . engine_id ) ;
EngineDisplayFlags flags = item . flags ;
if ( e - > display_last_variant ! = INVALID_ENGINE ) flags & = ~ EngineDisplayFlags : : Shaded ;
dst . emplace_back ( e - > display_last_variant = = INVALID_ENGINE ? item . engine_id : e - > display_last_variant , item . engine_id , flags , indent ) ;
/* Add variants if not folded */
if ( ( item . flags & ( EngineDisplayFlags : : HasVariants | EngineDisplayFlags : : IsFolded ) ) = = EngineDisplayFlags : : HasVariants ) {
/* Add this engine again as a child */
if ( ( item . flags & EngineDisplayFlags : : Shaded ) = = EngineDisplayFlags : : None ) {
dst . emplace_back ( item . engine_id , item . engine_id , EngineDisplayFlags : : None , indent + 1 ) ;
}
GUIEngineListAddChildren ( dst , src , item . engine_id , indent + 1 ) ;
}
}
if ( indent > 0 | | dst . empty ( ) ) return ;
/* Hierarchy is complete, traverse in reverse to find where indentation levels continue. */
uint16_t level_mask = 0 ;
for ( auto it = std : : rbegin ( dst ) ; std : : next ( it ) ! = std : : rend ( dst ) ; + + it ) {
auto next_it = std : : next ( it ) ;
SB ( level_mask , it - > indent , 1 , it - > indent < = next_it - > indent ) ;
next_it - > level_mask = level_mask ;
}
}
/** Enum referring to the Hotkeys in the build vehicle window */
enum BuildVehicleHotkeys {
BVHK_FOCUS_FILTER_BOX , ///< Focus the edit box for editing the filter string
@ -1157,27 +1205,6 @@ struct BuildVehicleWindow : Window {
}
}
void AddChildren ( const GUIEngineList & source , EngineID parent , int indent )
{
for ( const auto & item : source ) {
if ( item . variant_id ! = parent | | item . engine_id = = parent ) continue ;
const Engine * e = Engine : : Get ( item . engine_id ) ;
EngineDisplayFlags flags = item . flags ;
if ( e - > display_last_variant ! = INVALID_ENGINE ) flags & = ~ EngineDisplayFlags : : Shaded ;
this - > eng_list . emplace_back ( e - > display_last_variant = = INVALID_ENGINE ? item . engine_id : e - > display_last_variant , item . engine_id , flags , indent ) ;
/* Add variants if not folded */
if ( ( item . flags & ( EngineDisplayFlags : : HasVariants | EngineDisplayFlags : : IsFolded ) ) = = EngineDisplayFlags : : HasVariants ) {
/* Add this engine again as a child */
if ( ( item . flags & EngineDisplayFlags : : Shaded ) = = EngineDisplayFlags : : None ) {
this - > eng_list . emplace_back ( item . engine_id , item . engine_id , EngineDisplayFlags : : None , indent + 1 ) ;
}
AddChildren ( source , item . engine_id , indent + 1 ) ;
}
}
}
BuildVehicleWindow ( WindowDesc * desc , TileIndex tile , VehicleType type ) : Window ( desc ) , vehicle_editbox ( MAX_LENGTH_VEHICLE_NAME_CHARS * MAX_CHAR_LENGTH , MAX_LENGTH_VEHICLE_NAME_CHARS )
{
this - > vehicle_type = type ;
@ -1518,7 +1545,7 @@ struct BuildVehicleWindow : Window {
default : NOT_REACHED ( ) ;
case VEH_TRAIN :
this - > GenerateBuildTrainList ( list ) ;
AddChildren( list , INVALID_ENGINE , 0 ) ;
GUIEngineListAddChildren( this - > eng_list , list ) ;
this - > eng_list . shrink_to_fit ( ) ;
this - > eng_list . RebuildDone ( ) ;
return ;
@ -1556,7 +1583,7 @@ struct BuildVehicleWindow : Window {
EngList_Sort ( this - > eng_list , _engine_sort_functions [ this - > vehicle_type ] [ this - > sort_criteria ] ) ;
this - > eng_list . swap ( list ) ;
AddChildren( list , INVALID_ENGINE , 0 ) ;
GUIEngineList AddChildren( this - > eng_list , list , INVALID_ENGINE , 0 ) ;
this - > eng_list . shrink_to_fit ( ) ;
this - > eng_list . RebuildDone ( ) ;
}