From 60f6adfea8639150ee0e425095cfeeb9e42e310c Mon Sep 17 00:00:00 2001 From: NahashonM Date: Mon, 16 Dec 2024 03:50:33 +0300 Subject: [PATCH] Fix #9056: [interface] missing scrollbar on infrastructure window. --- src/company_gui.cpp | 450 ++++++++++++++++------------------- src/widgets/company_widget.h | 14 +- 2 files changed, 205 insertions(+), 259 deletions(-) diff --git a/src/company_gui.cpp b/src/company_gui.cpp index 46a8c00da0..9cd30d3c99 100644 --- a/src/company_gui.cpp +++ b/src/company_gui.cpp @@ -1752,32 +1752,11 @@ static constexpr NWidgetPart _nested_company_infrastructure_widgets[] = { NWidget(WWT_SHADEBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY), EndContainer(), - NWidget(WWT_PANEL, COLOUR_GREY), - NWidget(NWID_VERTICAL), SetPadding(WidgetDimensions::unscaled.framerect), SetPIP(0, WidgetDimensions::unscaled.vsep_normal, 0), - NWidget(NWID_HORIZONTAL), SetPIP(0, WidgetDimensions::unscaled.hsep_wide, 0), - NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_RAIL_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0), - NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_RAIL_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1), - EndContainer(), - NWidget(NWID_HORIZONTAL), SetPIP(0, WidgetDimensions::unscaled.hsep_wide, 0), - NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_ROAD_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0), - NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_ROAD_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1), - EndContainer(), - NWidget(NWID_HORIZONTAL), SetPIP(0, WidgetDimensions::unscaled.hsep_wide, 0), - NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_TRAM_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0), - NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_TRAM_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1), - EndContainer(), - NWidget(NWID_HORIZONTAL), SetPIP(0, WidgetDimensions::unscaled.hsep_wide, 0), - NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_WATER_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0), - NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_WATER_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1), - EndContainer(), - NWidget(NWID_HORIZONTAL), SetPIP(0, WidgetDimensions::unscaled.hsep_wide, 0), - NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_STATION_DESC), SetMinimalTextLines(3, 0), SetFill(1, 0), - NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_STATION_COUNT), SetMinimalTextLines(3, 0), SetFill(0, 1), - EndContainer(), - NWidget(NWID_HORIZONTAL), SetPIP(0, WidgetDimensions::unscaled.hsep_wide, 0), - NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_TOTAL_DESC), SetFill(1, 0), - NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_TOTAL), SetFill(0, 1), - EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PANEL, COLOUR_GREY, WID_CI_LIST), SetFill(1, 0), SetResize(1, 1), SetScrollbar(WID_CI_SCROLLBAR), EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_CI_SCROLLBAR), + NWidget(WWT_RESIZEBOX, COLOUR_GREY), EndContainer(), EndContainer(), }; @@ -1787,16 +1766,52 @@ static constexpr NWidgetPart _nested_company_infrastructure_widgets[] = { */ struct CompanyInfrastructureWindow : Window { + /* Company Ifrastructure Window infrastructure cache type. */ + enum CacheEntryType : int { + ENTRY_HEADER, ///< section headers. + ENTRY_BLANK_LINE, ///< blank line. + ENTRY_LABEL_ONLY, ///< label only entry, no values. + ENTRY_LABEL_VALUES, ///< label and values (count, cost). + ENTRY_TOTAL_COST, ///< total maintenance cost. + }; + + /* Infrastructure count and maintenance cost cache container. */ + struct InfrastructureCache { + CacheEntryType type; + StringID label; + uint count; + Money yearly_cost; + + InfrastructureCache(CacheEntryType type, StringID label, uint count = 0, Money monthly_cost = 0) : type(type), label(label), count(count), yearly_cost(monthly_cost * 12) + { + } + }; + RailTypes railtypes; ///< Valid railtypes. RoadTypes roadtypes; ///< Valid roadtypes. - uint total_width; ///< String width of the total cost line. + uint total_y_padding; ///< Infrastructure label size. + uint max_label_width; ///< Infrastructure label size. + uint max_cost_width; ///< Infratructure maintenance cost text size. + uint max_count_width; ///< Infrastructure count text size. + + Scrollbar *vscroll; ///< scroll bar widget. + + mutable std::vector infrastructurelist; ///< infrastructure and total maintenance cost cache. CompanyInfrastructureWindow(WindowDesc &desc, WindowNumber window_number) : Window(desc) { this->UpdateRailRoadTypes(); - this->InitNested(window_number); + this->CreateNestedTree(); + + this->vscroll = this->GetScrollbar(WID_CI_SCROLLBAR); + this->BuildCompanyInfrastructureCache(); + + this->SetWidgetDirty(WID_CI_LIST); // Force repaint of company infrastructure widget. + + this->FinishInitNested(window_number); + this->owner = (Owner)this->window_number; } @@ -1827,29 +1842,89 @@ struct CompanyInfrastructureWindow : Window this->roadtypes &= ~_roadtypes_hidden_mask; } - /** Get total infrastructure maintenance cost. */ - Money GetTotalMaintenanceCost() const + /** + * Build a vector of infrastructure types(roads, trains, trams, airports, stations, ships) to be displayed. + * Total maintenance cost of all infrastructure types is last entry in vector. + */ + void BuildCompanyInfrastructureCache() const { const Company *c = Company::Get((CompanyID)this->window_number); - Money total; - uint32_t rail_total = c->infrastructure.GetRailTotal(); - for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) { - if (HasBit(this->railtypes, rt)) total += RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total); - } - total += SignalMaintenanceCost(c->infrastructure.signal); + Money monthly_cost = 0; + Money total_monthly_cost = 0; - uint32_t road_total = c->infrastructure.GetRoadTotal(); - uint32_t tram_total = c->infrastructure.GetTramTotal(); - for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) { - if (HasBit(this->roadtypes, rt)) total += RoadMaintenanceCost(rt, c->infrastructure.road[rt], RoadTypeIsRoad(rt) ? road_total : tram_total); + this->infrastructurelist.clear(); + + /* Railtypes and signals. */ + this->infrastructurelist.emplace_back(ENTRY_HEADER, STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT); + + if (this->railtypes != RAILTYPES_NONE) { + for (const auto &rt : _sorted_railtypes) { + if (!HasBit(this->railtypes, rt)) continue; + monthly_cost = RailMaintenanceCost(rt, c->infrastructure.rail[rt], c->infrastructure.GetRailTotal()); + total_monthly_cost += monthly_cost; + this->infrastructurelist.emplace_back(ENTRY_LABEL_VALUES, GetRailTypeInfo(rt)->strings.name, c->infrastructure.rail[rt], monthly_cost); + } + + monthly_cost = SignalMaintenanceCost(c->infrastructure.signal); + total_monthly_cost += monthly_cost; + this->infrastructurelist.emplace_back(ENTRY_LABEL_VALUES, STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS, c->infrastructure.signal, monthly_cost); + } else { + /* No valid railtype. */ + this->infrastructurelist.emplace_back(ENTRY_LABEL_ONLY, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE); } - total += CanalMaintenanceCost(c->infrastructure.water); - total += StationMaintenanceCost(c->infrastructure.station); - total += AirportMaintenanceCost(c->index); + /* roadtypes. */ + this->infrastructurelist.emplace_back(ENTRY_HEADER, STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT); - return total; + for (const auto &rt : _sorted_roadtypes) { + if (!HasBit(this->roadtypes, rt) || !RoadTypeIsRoad(rt)) continue; + + monthly_cost = RoadMaintenanceCost(rt, c->infrastructure.road[rt], c->infrastructure.GetRoadTotal()); + total_monthly_cost += monthly_cost; + this->infrastructurelist.emplace_back(ENTRY_LABEL_VALUES, GetRoadTypeInfo(rt)->strings.name, c->infrastructure.road[rt], monthly_cost); + } + + /* trams. */ + this->infrastructurelist.emplace_back(ENTRY_HEADER, STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT); + + bool has_trams = false; + for (const auto &rt : _sorted_roadtypes) { + if (!HasBit(this->roadtypes, rt) || !RoadTypeIsTram(rt)) continue; + + has_trams = true; + monthly_cost = RoadMaintenanceCost(rt, c->infrastructure.road[rt], c->infrastructure.GetRoadTotal()); + total_monthly_cost += monthly_cost; + this->infrastructurelist.emplace_back(ENTRY_LABEL_VALUES, GetRoadTypeInfo(rt)->strings.name, c->infrastructure.road[rt], monthly_cost); + } + /* No valid trams. */ + if (!has_trams) + this->infrastructurelist.emplace_back(ENTRY_BLANK_LINE, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE); + + /* Canals, locks, and ship depots (docks are counted as stations). */ + this->infrastructurelist.emplace_back(ENTRY_HEADER, STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT); + + monthly_cost = CanalMaintenanceCost(c->infrastructure.water); + total_monthly_cost += monthly_cost; + this->infrastructurelist.emplace_back(ENTRY_LABEL_VALUES, STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS, c->infrastructure.water, monthly_cost); + + /* Airports. */ + this->infrastructurelist.emplace_back(ENTRY_HEADER, STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT); + + monthly_cost = StationMaintenanceCost(c->infrastructure.station); + total_monthly_cost += monthly_cost; + this->infrastructurelist.emplace_back(ENTRY_LABEL_VALUES, STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS, c->infrastructure.station, monthly_cost); + + monthly_cost = AirportMaintenanceCost(c->index); + total_monthly_cost += monthly_cost; + this->infrastructurelist.emplace_back(ENTRY_LABEL_VALUES, STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS, c->infrastructure.airport, monthly_cost); + + /* Total monthly maintenance cost. */ + if(_settings_game.economy.infrastructure_maintenance) + this->infrastructurelist.emplace_back(ENTRY_TOTAL_COST, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE, 0, total_monthly_cost); + + /* Update scrollbar as well. */ + this->vscroll->SetCount(this->infrastructurelist.size()); } void SetStringParameters(WidgetID widget) const override @@ -1863,231 +1938,110 @@ struct CompanyInfrastructureWindow : Window void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override { - const Company *c = Company::Get((CompanyID)this->window_number); + if (widget != WID_CI_LIST) return; - switch (widget) { - case WID_CI_RAIL_DESC: { - uint lines = 1; // Starts at 1 because a line is also required for the section title + uint max_lwidth = 0; + uint max_count = 1000; // Some random number to reserve enough space. + Money max_cost = 1000000; // Some random number to reserve enough space. - size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT).width + padding.width); - - for (const auto &rt : _sorted_railtypes) { - if (HasBit(this->railtypes, rt)) { - lines++; - size.width = std::max(size.width, GetStringBoundingBox(GetRailTypeInfo(rt)->strings.name).width + padding.width + WidgetDimensions::scaled.hsep_indent); - } - } - if (this->railtypes != RAILTYPES_NONE) { - lines++; - size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS).width + padding.width + WidgetDimensions::scaled.hsep_indent); - } - - size.height = std::max(size.height, lines * GetCharacterHeight(FS_NORMAL)); - break; - } - - case WID_CI_ROAD_DESC: - case WID_CI_TRAM_DESC: { - uint lines = 1; // Starts at 1 because a line is also required for the section title - - size.width = std::max(size.width, GetStringBoundingBox(widget == WID_CI_ROAD_DESC ? STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT : STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT).width + padding.width); - - for (const auto &rt : _sorted_roadtypes) { - if (HasBit(this->roadtypes, rt) && RoadTypeIsRoad(rt) == (widget == WID_CI_ROAD_DESC)) { - lines++; - size.width = std::max(size.width, GetStringBoundingBox(GetRoadTypeInfo(rt)->strings.name).width + padding.width + WidgetDimensions::scaled.hsep_indent); - } - } - - size.height = std::max(size.height, lines * GetCharacterHeight(FS_NORMAL)); - break; - } - - case WID_CI_WATER_DESC: - size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT).width + padding.width); - size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS).width + padding.width + WidgetDimensions::scaled.hsep_indent); - break; - - case WID_CI_STATION_DESC: - size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT).width + padding.width); - size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS).width + padding.width + WidgetDimensions::scaled.hsep_indent); - size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS).width + padding.width + WidgetDimensions::scaled.hsep_indent); - break; - - case WID_CI_RAIL_COUNT: - case WID_CI_ROAD_COUNT: - case WID_CI_TRAM_COUNT: - case WID_CI_WATER_COUNT: - case WID_CI_STATION_COUNT: - case WID_CI_TOTAL: { - /* Find the maximum count that is displayed. */ - uint32_t max_val = 1000; // Some random number to reserve enough space. - Money max_cost = 10000; // Some random number to reserve enough space. - uint32_t rail_total = c->infrastructure.GetRailTotal(); - for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) { - max_val = std::max(max_val, c->infrastructure.rail[rt]); - max_cost = std::max(max_cost, RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total)); - } - max_val = std::max(max_val, c->infrastructure.signal); - max_cost = std::max(max_cost, SignalMaintenanceCost(c->infrastructure.signal)); - uint32_t road_total = c->infrastructure.GetRoadTotal(); - uint32_t tram_total = c->infrastructure.GetTramTotal(); - for (RoadType rt = ROADTYPE_BEGIN; rt < ROADTYPE_END; rt++) { - max_val = std::max(max_val, c->infrastructure.road[rt]); - max_cost = std::max(max_cost, RoadMaintenanceCost(rt, c->infrastructure.road[rt], RoadTypeIsRoad(rt) ? road_total : tram_total)); - - } - max_val = std::max(max_val, c->infrastructure.water); - max_cost = std::max(max_cost, CanalMaintenanceCost(c->infrastructure.water)); - max_val = std::max(max_val, c->infrastructure.station); - max_cost = std::max(max_cost, StationMaintenanceCost(c->infrastructure.station)); - max_val = std::max(max_val, c->infrastructure.airport); - max_cost = std::max(max_cost, AirportMaintenanceCost(c->index)); - - SetDParamMaxValue(0, max_val); - uint count_width = GetStringBoundingBox(STR_JUST_COMMA).width + WidgetDimensions::scaled.hsep_indent; // Reserve some wiggle room - - if (_settings_game.economy.infrastructure_maintenance) { - StringID str_total = TimerGameEconomy::UsingWallclockUnits() ? STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_PERIOD : STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_YEAR; - SetDParamMaxValue(0, this->GetTotalMaintenanceCost() * 12); // Convert to per year - this->total_width = GetStringBoundingBox(str_total).width + WidgetDimensions::scaled.hsep_indent * 2; - size.width = std::max(size.width, this->total_width); - - SetDParamMaxValue(0, max_cost * 12); // Convert to per year - count_width += std::max(this->total_width, GetStringBoundingBox(str_total).width); - } - - size.width = std::max(size.width, count_width); - - /* Set height of the total line. */ - if (widget == WID_CI_TOTAL) { - size.height = _settings_game.economy.infrastructure_maintenance ? std::max(size.height, WidgetDimensions::scaled.vsep_normal + GetCharacterHeight(FS_NORMAL)) : 0; - } - break; - } + for (const auto &ie : this->infrastructurelist) { + max_lwidth = std::max(max_lwidth, GetStringBoundingBox(ie.label).width); + max_cost = std::max(max_cost, ie.yearly_cost); + max_count = std::max(max_count, ie.count); } - } - /** - * Helper for drawing the counts line. - * @param r The bounds to draw in. - * @param y The y position to draw at. - * @param count The count to show on this line. - * @param monthly_cost The monthly costs. - */ - void DrawCountLine(const Rect &r, int &y, int count, Money monthly_cost) const - { - SetDParam(0, count); - DrawString(r.left, r.right, y += GetCharacterHeight(FS_NORMAL), STR_JUST_COMMA, TC_WHITE, SA_RIGHT); + /* add indent width to label text width. */ + this->max_label_width = max_lwidth + WidgetDimensions::scaled.hsep_indent; + + SetDParam(0, max_count); + this->max_count_width = GetStringBoundingBox(STR_JUST_COMMA).width + padding.width * 2; if (_settings_game.economy.infrastructure_maintenance) { - SetDParam(0, monthly_cost * 12); // Convert to per year - Rect tr = r.WithWidth(this->total_width, _current_text_dir == TD_RTL); - DrawString(tr.left, tr.right, y, - TimerGameEconomy::UsingWallclockUnits() ? STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_PERIOD : STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_YEAR, - TC_FROMSTRING, SA_RIGHT); + SetDParam(0, max_cost); + this->max_cost_width = GetStringBoundingBox(TimerGameEconomy::UsingWallclockUnits() + ? STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_PERIOD : STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_YEAR).width; + this->total_y_padding = WidgetDimensions::scaled.vsep_normal * 3; // padding before and after horizontal line and after total cost line. + } else { + this->max_cost_width = 0; + this->total_y_padding = WidgetDimensions::scaled.vsep_normal; // padding after last count line. } + + size.width = this->max_label_width + this->max_cost_width + this->max_count_width + WidgetDimensions::scaled.hsep_wide * 2; + size.width += WidgetDimensions::scaled.hsep_normal * 2; + + /* Set max auto resize height for widget to 25 text lines. */ + size.height = static_cast(this->infrastructurelist.size()) * GetCharacterHeight(FS_NORMAL); + size.height = Clamp(size.height, 0, GetCharacterHeight(FS_NORMAL) * 25); + size.height += this->total_y_padding; + + resize.height = GetCharacterHeight(FS_NORMAL); } void DrawWidget(const Rect &r, WidgetID widget) const override { - const Company *c = Company::Get((CompanyID)this->window_number); + if (widget != WID_CI_LIST) return; int y = r.top; + Rect rr = r.Shrink(WidgetDimensions::scaled.hsep_normal); + Rect ir = rr.Indent(WidgetDimensions::scaled.hsep_indent, _current_text_dir == TD_RTL); - Rect ir = r.Indent(WidgetDimensions::scaled.hsep_indent, _current_text_dir == TD_RTL); - switch (widget) { - case WID_CI_RAIL_DESC: - DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT); + /* set boundaries for labels, infrastructure count and cost secions to handle text overflows and text direction change */ + int label_right = rr.left + this->max_label_width; + int cost_left = label_right + WidgetDimensions::scaled.hsep_wide; + int cost_right = cost_left + this->max_cost_width; + int count_left = cost_right + WidgetDimensions::scaled.hsep_wide; - if (this->railtypes != RAILTYPES_NONE) { - /* Draw name of each valid railtype. */ - for (const auto &rt : _sorted_railtypes) { - if (HasBit(this->railtypes, rt)) { - DrawString(ir.left, ir.right, y += GetCharacterHeight(FS_NORMAL), GetRailTypeInfo(rt)->strings.name, TC_WHITE); + auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->infrastructurelist); + + for (auto it = first; it != last; ++it, y += GetCharacterHeight(FS_NORMAL)) { + switch (it->type) { + case ENTRY_LABEL_VALUES: + + SetDParam(0, it->count); + DrawString(count_left, ir.right, y, STR_JUST_COMMA, TC_WHITE, SA_RIGHT); + + [[fallthrough]]; + + case ENTRY_TOTAL_COST: + if (_settings_game.economy.infrastructure_maintenance) { + + if (it->type == ENTRY_TOTAL_COST) { + y += WidgetDimensions::scaled.vsep_normal; + GfxFillRect(cost_left, y, cost_right, y + WidgetDimensions::scaled.bevel.top - 1, PC_WHITE); + y += WidgetDimensions::scaled.vsep_normal; } - } - DrawString(ir.left, ir.right, y += GetCharacterHeight(FS_NORMAL), STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS); - } else { - /* No valid railtype. */ - DrawString(ir.left, ir.right, y += GetCharacterHeight(FS_NORMAL), STR_COMPANY_VIEW_INFRASTRUCTURE_NONE); - } - break; - - case WID_CI_RAIL_COUNT: { - /* Draw infrastructure count for each valid railtype. */ - uint32_t rail_total = c->infrastructure.GetRailTotal(); - for (const auto &rt : _sorted_railtypes) { - if (HasBit(this->railtypes, rt)) { - this->DrawCountLine(r, y, c->infrastructure.rail[rt], RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total)); + SetDParam(0, it->yearly_cost); + DrawString(cost_left, cost_right, y, TimerGameEconomy::UsingWallclockUnits() + ? STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_PERIOD : STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_YEAR, TC_FROMSTRING, SA_RIGHT); } - } - if (this->railtypes != RAILTYPES_NONE) { - this->DrawCountLine(r, y, c->infrastructure.signal, SignalMaintenanceCost(c->infrastructure.signal)); - } - break; + if (it->type == ENTRY_TOTAL_COST) break; + + [[fallthrough]]; + + case ENTRY_LABEL_ONLY: + DrawString(ir.left, label_right, y, it->label, TC_WHITE); + break; + case ENTRY_HEADER: + DrawString(rr.left, label_right, y, it->label); + break; + case ENTRY_BLANK_LINE: + break; } - - case WID_CI_ROAD_DESC: - case WID_CI_TRAM_DESC: { - DrawString(r.left, r.right, y, widget == WID_CI_ROAD_DESC ? STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT : STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT); - - /* Draw name of each valid roadtype. */ - for (const auto &rt : _sorted_roadtypes) { - if (HasBit(this->roadtypes, rt) && RoadTypeIsRoad(rt) == (widget == WID_CI_ROAD_DESC)) { - DrawString(ir.left, ir.right, y += GetCharacterHeight(FS_NORMAL), GetRoadTypeInfo(rt)->strings.name, TC_WHITE); - } - } - - break; - } - - case WID_CI_ROAD_COUNT: - case WID_CI_TRAM_COUNT: { - uint32_t road_tram_total = widget == WID_CI_ROAD_COUNT ? c->infrastructure.GetRoadTotal() : c->infrastructure.GetTramTotal(); - for (const auto &rt : _sorted_roadtypes) { - if (HasBit(this->roadtypes, rt) && RoadTypeIsRoad(rt) == (widget == WID_CI_ROAD_COUNT)) { - this->DrawCountLine(r, y, c->infrastructure.road[rt], RoadMaintenanceCost(rt, c->infrastructure.road[rt], road_tram_total)); - } - } - break; - } - - case WID_CI_WATER_DESC: - DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT); - DrawString(ir.left, ir.right, y += GetCharacterHeight(FS_NORMAL), STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS); - break; - - case WID_CI_WATER_COUNT: - this->DrawCountLine(r, y, c->infrastructure.water, CanalMaintenanceCost(c->infrastructure.water)); - break; - - case WID_CI_TOTAL: - if (_settings_game.economy.infrastructure_maintenance) { - Rect tr = r.WithWidth(this->total_width, _current_text_dir == TD_RTL); - GfxFillRect(tr.left, y, tr.right, y + WidgetDimensions::scaled.bevel.top - 1, PC_WHITE); - y += WidgetDimensions::scaled.vsep_normal; - SetDParam(0, this->GetTotalMaintenanceCost() * 12); // Convert to per year - DrawString(tr.left, tr.right, y, - TimerGameEconomy::UsingWallclockUnits() ? STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_PERIOD : STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_YEAR, - TC_FROMSTRING, SA_RIGHT); - } - break; - - case WID_CI_STATION_DESC: - DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT); - DrawString(ir.left, ir.right, y += GetCharacterHeight(FS_NORMAL), STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS); - DrawString(ir.left, ir.right, y += GetCharacterHeight(FS_NORMAL), STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS); - break; - - case WID_CI_STATION_COUNT: - this->DrawCountLine(r, y, c->infrastructure.station, StationMaintenanceCost(c->infrastructure.station)); - this->DrawCountLine(r, y, c->infrastructure.airport, AirportMaintenanceCost(c->index)); - break; } } + /** Update cache at regular intervals. */ + IntervalTimer redraw_interval = {std::chrono::seconds(1), [this](auto) { + this->BuildCompanyInfrastructureCache(); + this->SetWidgetDirty(WID_CI_LIST); + }}; + + void OnResize() override + { + this->vscroll->SetCapacityFromWidget(this, WID_CI_LIST, this->total_y_padding); + } + /** * Some data on this window has become invalid. * @param data Information about the changed data. @@ -2098,6 +2052,8 @@ struct CompanyInfrastructureWindow : Window if (!gui_scope) return; this->UpdateRailRoadTypes(); + this->BuildCompanyInfrastructureCache(); + this->SetWidgetDirty(WID_CI_LIST); this->ReInit(); } }; diff --git a/src/widgets/company_widget.h b/src/widgets/company_widget.h index 452632dccb..79374bdb5f 100644 --- a/src/widgets/company_widget.h +++ b/src/widgets/company_widget.h @@ -170,18 +170,8 @@ enum SelectCompanyManagerFaceWidgets : WidgetID { /** Widgets of the #CompanyInfrastructureWindow class. */ enum CompanyInfrastructureWidgets : WidgetID { WID_CI_CAPTION, ///< Caption of window. - WID_CI_RAIL_DESC, ///< Description of rail. - WID_CI_RAIL_COUNT, ///< Count of rail. - WID_CI_ROAD_DESC, ///< Description of road. - WID_CI_ROAD_COUNT, ///< Count of road. - WID_CI_TRAM_DESC, ///< Description of tram. - WID_CI_TRAM_COUNT, ///< Count of tram. - WID_CI_WATER_DESC, ///< Description of water. - WID_CI_WATER_COUNT, ///< Count of water. - WID_CI_STATION_DESC, ///< Description of station. - WID_CI_STATION_COUNT, ///< Count of station. - WID_CI_TOTAL_DESC, ///< Description of total. - WID_CI_TOTAL, ///< Count of total. + WID_CI_LIST, ///< Infrastructure list. + WID_CI_SCROLLBAR, ///< Infrastructure list scroll bar. }; /** Widgets of the #BuyCompanyWindow class. */