diff --git a/src/departures_gui.cpp b/src/departures_gui.cpp index 3704f1a6be..199d003e8c 100644 --- a/src/departures_gui.cpp +++ b/src/departures_gui.cpp @@ -190,7 +190,7 @@ protected: } for (GroupID gid : groups) { - SetDParam(0, (uint64)gid); + SetDParam(0, (uint64)(gid | GROUP_NAME_HIERARCHY)); int width = (GetStringBoundingBox(STR_DEPARTURES_GROUP)).width + 4; if (width > this->group_width) this->group_width = width; } @@ -895,7 +895,7 @@ void DeparturesWindow::DrawDeparturesListItems(const Rect &r) const /* Group name */ if (_settings_client.gui.departure_show_group && d->vehicle->group_id != INVALID_GROUP && d->vehicle->group_id != DEFAULT_GROUP) { - SetDParam(0, (uint64)(d->vehicle->group_id)); + SetDParam(0, (uint64)(d->vehicle->group_id | GROUP_NAME_HIERARCHY)); ltr ? DrawString(text_right - (toc_width + group_width + 2), text_right - toc_width - 2, y + 1, STR_DEPARTURES_GROUP) : DrawString( text_left + toc_width + 2, text_left + (toc_width + group_width + 2), y + 1, STR_DEPARTURES_GROUP); } diff --git a/src/group_type.h b/src/group_type.h index 8936c3609a..f23a1eecc8 100644 --- a/src/group_type.h +++ b/src/group_type.h @@ -16,6 +16,7 @@ static const GroupID NEW_GROUP = 0xFFFC; ///< Sentinel for a to-be-created g static const GroupID ALL_GROUP = 0xFFFD; ///< All vehicles are in this group. static const GroupID DEFAULT_GROUP = 0xFFFE; ///< Ungrouped vehicles are in this group. static const GroupID INVALID_GROUP = 0xFFFF; ///< Sentinel for invalid groups. +static const uint32 GROUP_NAME_HIERARCHY = 0x80000000; ///< String constant to display the group name with its full hierarchy static const uint MAX_LENGTH_GROUP_NAME_CHARS = 128; ///< The maximum length of a group name in characters including '\0' diff --git a/src/lang/english.txt b/src/lang/english.txt index 7cfcefe65e..536474b8ac 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1633,6 +1633,9 @@ STR_CONFIG_SETTING_DISABLE_WATER_ANIMATION_32X :32x zoom and ab STR_CONFIG_SETTING_SHOW_ORDER_OCCUPANCY_BY_DEFAULT :Show order occupancy by default: {STRING2} STR_CONFIG_SETTING_SHOW_ORDER_OCCUPANCY_BY_DEFAULT_HELPTEXT :Show detailed per-order occupancy by default when opening a vehicle's orders window +STR_CONFIG_SETTING_SHOW_GROUP_HIERARCHY_NAME :Show group hierarchy in name: {STRING2} +STR_CONFIG_SETTING_SHOW_GROUP_HIERARCHY_NAME_HELPTEXT :When enabled, group names include the full hierarchy of their parent group names + STR_CONFIG_SETTING_ADV_SIG_BRIDGE_TUN_MODES :Enable signals on bridges/tunnels advanced modes: {STRING2} STR_CONFIG_SETTING_ADV_SIG_BRIDGE_TUN_MODES_HELPTEXT :Enables use of advanced modes of signal simulation on bridges and tunnels. When disabled, bridges/tunnels which are not already in an advanced mode cannot be changed to an advanced mode, however other players may choose to enable this setting and use an advanced mode. @@ -7088,6 +7091,8 @@ STR_TOOLBAR_RAILTYPE_VELOCITY :{STRING} ({VELO STR_DECIMAL1_WITH_SCALE :{DECIMAL1} ({DECIMAL}x) +STR_HIERARCHY_SEPARATOR :{SP}/{SP} + ######## Zoning toolbar STR_ZONING_TOOLBAR :{WHITE}Zoning toolbar diff --git a/src/settings_gui.cpp b/src/settings_gui.cpp index e6e828c981..97c3c3b0c0 100644 --- a/src/settings_gui.cpp +++ b/src/settings_gui.cpp @@ -1936,6 +1936,7 @@ static SettingsContainer &GetSettingsTree() interface->Add(new SettingEntry("gui.allow_hiding_waypoint_labels")); interface->Add(new SettingEntry("gui.disable_water_animation")); interface->Add(new SettingEntry("gui.show_order_occupancy_by_default")); + interface->Add(new SettingEntry("gui.show_group_hierarchy_name")); } SettingsPage *advisors = main->Add(new SettingsPage(STR_CONFIG_SETTING_ADVISORS)); diff --git a/src/settings_type.h b/src/settings_type.h index 56f930d04f..3885dc109e 100644 --- a/src/settings_type.h +++ b/src/settings_type.h @@ -248,6 +248,7 @@ struct GUISettings : public TimeSettings { bool allow_hiding_waypoint_labels; ///< Allow hiding waypoint viewport labels uint8 disable_water_animation; ///< Disable water animation depending on zoom level bool show_order_occupancy_by_default; ///< Show order occupancy by default in vehicle order window + bool show_group_hierarchy_name; ///< Show the full hierarchy in group names uint16 console_backlog_timeout; ///< the minimum amount of time items should be in the console backlog before they will be removed in ~3 seconds granularity. uint16 console_backlog_length; ///< the minimum amount of items in the console backlog before items will be removed. diff --git a/src/strings.cpp b/src/strings.cpp index 58dcc92520..50673590c7 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -36,6 +36,7 @@ #include "tracerestrict.h" #include "game/game_text.hpp" #include "network/network_content_gui.h" +#include "core/y_combinator.hpp" #include #include "table/strings.h" @@ -1705,19 +1706,30 @@ static char *FormatString(char *buff, const char *str_arg, StringParameters *arg } case SCC_GROUP_NAME: { // {GROUP} - const Group *g = Group::GetIfValid(args->GetInt32()); - if (g == nullptr) break; + uint32 id = (uint32)args->GetInt64(); + bool recurse = _settings_client.gui.show_group_hierarchy_name && (id & GROUP_NAME_HIERARCHY); + id &= ~GROUP_NAME_HIERARCHY; + const Group *group = Group::GetIfValid(id); + if (group == nullptr) break; - if (!g->name.empty()) { - int64 args_array[] = {(int64)(size_t)g->name.c_str()}; - StringParameters tmp_params(args_array); - buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); - } else { - int64 args_array[] = {g->index}; - StringParameters tmp_params(args_array); + auto handle_group = y_combinator([&](auto handle_group, const Group *g) -> void { + if (recurse && g->parent != INVALID_GROUP) { + handle_group(Group::Get(g->parent)); + StringParameters tmp_params(nullptr, 0, nullptr); + buff = GetStringWithArgs(buff, STR_HIERARCHY_SEPARATOR, &tmp_params, last); + } + if (!g->name.empty()) { + int64 args_array[] = {(int64)(size_t)g->name.c_str()}; + StringParameters tmp_params(args_array); + buff = GetStringWithArgs(buff, STR_JUST_RAW_STRING, &tmp_params, last); + } else { + int64 args_array[] = {g->index}; + StringParameters tmp_params(args_array); - buff = GetStringWithArgs(buff, STR_FORMAT_GROUP_NAME, &tmp_params, last); - } + buff = GetStringWithArgs(buff, STR_FORMAT_GROUP_NAME, &tmp_params, last); + } + }); + handle_group(group); break; } diff --git a/src/table/settings/settings.ini b/src/table/settings/settings.ini index c9442f574d..87a2bc3f3d 100644 --- a/src/table/settings/settings.ini +++ b/src/table/settings/settings.ini @@ -5544,6 +5544,15 @@ str = STR_CONFIG_SETTING_SHOW_ORDER_OCCUPANCY_BY_DEFAULT strhelp = STR_CONFIG_SETTING_SHOW_ORDER_OCCUPANCY_BY_DEFAULT_HELPTEXT cat = SC_BASIC +[SDTC_BOOL] +var = gui.show_group_hierarchy_name +flags = SF_NOT_IN_SAVE | SF_NO_NETWORK_SYNC +def = false +str = STR_CONFIG_SETTING_SHOW_GROUP_HIERARCHY_NAME +strhelp = STR_CONFIG_SETTING_SHOW_GROUP_HIERARCHY_NAME_HELPTEXT +post_cb = [](auto) { MarkWholeScreenDirty(); } +cat = SC_BASIC + ; For the dedicated build we'll enable dates in logs by default. [SDTC_BOOL] ifdef = DEDICATED diff --git a/src/table/strgen_tables.h b/src/table/strgen_tables.h index 4bdc7d3b4d..0bfb272514 100644 --- a/src/table/strgen_tables.h +++ b/src/table/strgen_tables.h @@ -144,6 +144,7 @@ static const CmdStruct _cmd_structs[] = { {"BUS", EmitSingleChar, SCC_BUS, 0, -1, C_DONTCOUNT}, {"PLANE", EmitSingleChar, SCC_PLANE, 0, -1, C_DONTCOUNT}, {"SHIP", EmitSingleChar, SCC_SHIP, 0, -1, C_DONTCOUNT}, + {"SP", EmitSingleChar, 0x20, 0, -1, C_DONTCOUNT}, {"NBSP", EmitSingleChar, 0xA0, 0, -1, C_DONTCOUNT}, {"COPYRIGHT", EmitSingleChar, 0xA9, 0, -1, C_DONTCOUNT}, {"DOWN_ARROW", EmitSingleChar, SCC_DOWN_ARROW, 0, -1, C_DONTCOUNT}, diff --git a/src/tracerestrict_gui.cpp b/src/tracerestrict_gui.cpp index 740544f6f5..2c801ca92b 100644 --- a/src/tracerestrict_gui.cpp +++ b/src/tracerestrict_gui.cpp @@ -656,7 +656,7 @@ static DropDownList GetGroupDropDownList(Owner owner, GroupID group_id, int &sel const Group *g = list[i]; if (group_id == g->index) selected = group_id; DropDownListParamStringItem *item = new DropDownListParamStringItem(STR_GROUP_NAME, g->index, false); - item->SetParam(0, g->index); + item->SetParam(0, g->index | GROUP_NAME_HIERARCHY); dlist.emplace_back(item); } @@ -1311,7 +1311,7 @@ static void DrawInstructionString(const TraceRestrictProgram *prog, TraceRestric SetDParam(3, selected ? STR_TRACE_RESTRICT_WHITE : STR_EMPTY); } else { instruction_string = STR_TRACE_RESTRICT_CONDITIONAL_GROUP; - SetDParam(2, GetTraceRestrictValue(item)); + SetDParam(2, GetTraceRestrictValue(item) | GROUP_NAME_HIERARCHY); } break; } @@ -1985,7 +1985,7 @@ public: case TRVT_GROUP_INDEX: { int selected; DropDownList dlist = GetGroupDropDownList(this->GetOwner(), GetTraceRestrictValue(item), selected); - ShowDropDownList(this, std::move(dlist), selected, TR_WIDGET_VALUE_DROPDOWN); + ShowDropDownList(this, std::move(dlist), selected, TR_WIDGET_VALUE_DROPDOWN, 0, true); break; } diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 2e53136cda..d87067d092 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -1994,7 +1994,7 @@ void BaseVehicleListWindow::DrawVehicleListItems(VehicleID selected_vehicle, int DrawString(text_left, text_right, y, STR_TINY_BLACK_VEHICLE); } else if (v->group_id != DEFAULT_GROUP) { /* The vehicle has no name, but is member of a group, so print group name */ - SetDParam(0, v->group_id); + SetDParam(0, v->group_id | GROUP_NAME_HIERARCHY); DrawString(text_left, text_right, y, STR_TINY_GROUP, TC_BLACK); } @@ -2031,7 +2031,7 @@ void BaseVehicleListWindow::DrawVehicleListItems(VehicleID selected_vehicle, int } } if (show_group) { - SetDParam(0, gid); + SetDParam(0, gid | GROUP_NAME_HIERARCHY); DrawString(text_left, text_right, y, STR_TINY_GROUP, TC_BLACK); } } @@ -2895,7 +2895,7 @@ struct VehicleDetailsWindow : Window { dim = maxdim(dim, GetStringBoundingBox(STR_VEHICLE_INFO_PROFIT_THIS_YEAR_LAST_YEAR_LIFETIME)); } if (this->vehicle_group_line_shown) { - SetDParam(0, v->group_id); + SetDParam(0, v->group_id | GROUP_NAME_HIERARCHY); dim = maxdim(dim, GetStringBoundingBox(STR_VEHICLE_INFO_GROUP)); } if (this->vehicle_weight_ratio_line_shown) { @@ -3098,7 +3098,7 @@ struct VehicleDetailsWindow : Window { bool should_show_group = this->ShouldShowGroupLine(v); if (should_show_group) { - SetDParam(0, v->group_id); + SetDParam(0, v->group_id | GROUP_NAME_HIERARCHY); DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y, STR_VEHICLE_INFO_GROUP); y += FONT_HEIGHT_NORMAL; }