From 642f4d0ab68c8094efc0e371f3fde614b0aa767e Mon Sep 17 00:00:00 2001 From: Peter Nelson Date: Sun, 22 Jun 2025 15:49:02 +0100 Subject: [PATCH] Change: Add support for different horizontal graph scales. --- src/graph_gui.cpp | 104 ++++++++++++++++++++++++++++++------- src/lang/english.txt | 8 +++ src/widgets/graph_widget.h | 1 + 3 files changed, 95 insertions(+), 18 deletions(-) diff --git a/src/graph_gui.cpp b/src/graph_gui.cpp index 8a11f8c3a2..a11687fdad 100644 --- a/src/graph_gui.cpp +++ b/src/graph_gui.cpp @@ -8,6 +8,7 @@ /** @file graph_gui.cpp GUI that shows performance graphs. */ #include "stdafx.h" +#include #include "misc/history_func.hpp" #include "graph_gui.h" #include "window_gui.h" @@ -174,6 +175,7 @@ protected: static const int GRAPH_PAYMENT_RATE_STEPS = 20; ///< Number of steps on Payment rate graph. static const int PAYMENT_GRAPH_X_STEP_DAYS = 10; ///< X-axis step label for cargo payment rates "Days in transit". static const int PAYMENT_GRAPH_X_STEP_SECONDS = 20; ///< X-axis step label for cargo payment rates "Seconds in transit". + static const int ECONOMY_YEAR_MINUTES = 12; ///< Minutes per economic year. static const int ECONOMY_QUARTER_MINUTES = 3; ///< Minutes per economic quarter. static const int ECONOMY_MONTH_MINUTES = 1; ///< Minutes per economic month. @@ -182,6 +184,24 @@ protected: static const int MIN_GRAPH_NUM_LINES_Y = 9; ///< Minimal number of horizontal lines to draw. static const int MIN_GRID_PIXEL_SIZE = 20; ///< Minimum distance between graph lines. + struct GraphScale { + StringID label = STR_NULL; + uint8_t month_increment = 0; + int16_t x_values_increment = 0; + }; + + static inline constexpr GraphScale MONTHLY_SCALE_WALLCLOCK[] = { + {STR_GRAPH_LAST_24_MINUTES_TIME_LABEL, HISTORY_MONTH.total_division, ECONOMY_MONTH_MINUTES}, + {STR_GRAPH_LAST_72_MINUTES_TIME_LABEL, HISTORY_QUARTER.total_division, ECONOMY_QUARTER_MINUTES}, + {STR_GRAPH_LAST_288_MINUTES_TIME_LABEL, HISTORY_YEAR.total_division, ECONOMY_YEAR_MINUTES}, + }; + + static inline constexpr GraphScale MONTHLY_SCALE_CALENDAR[] = { + {STR_GRAPH_LAST_24_MONTHS, HISTORY_MONTH.total_division, ECONOMY_MONTH_MINUTES}, + {STR_GRAPH_LAST_24_QUARTERS, HISTORY_QUARTER.total_division, ECONOMY_QUARTER_MINUTES}, + {STR_GRAPH_LAST_24_YEARS, HISTORY_YEAR.total_division, ECONOMY_YEAR_MINUTES}, + }; + uint64_t excluded_data = 0; ///< bitmask of datasets hidden by the player. uint64_t excluded_range = 0; ///< bitmask of ranges hidden by the player. uint64_t masked_range = 0; ///< bitmask of ranges that are not available for the current data. @@ -211,7 +231,9 @@ protected: }; std::vector data{}; - std::span ranges = {}; + std::span ranges{}; + std::span scales{}; + uint8_t selected_scale = 0; uint8_t highlight_data = UINT8_MAX; ///< Data set that should be highlighted, or UINT8_MAX for none. uint8_t highlight_range = UINT8_MAX; ///< Data range that should be highlighted, or UINT8_MAX for none. @@ -615,24 +637,34 @@ protected: this->SetDirty(); }}; + void UpdateMatrixSize(WidgetID widget, Dimension &size, Dimension &resize, auto labels) + { + size = {}; + for (const StringID &str : labels) { + size = maxdim(size, GetStringBoundingBox(str, FS_SMALL)); + } + + size.width += WidgetDimensions::scaled.framerect.Horizontal(); + size.height += WidgetDimensions::scaled.framerect.Vertical(); + + /* Set fixed height for number of ranges. */ + size.height *= static_cast(std::size(labels)); + + resize.width = 0; + resize.height = 0; + this->GetWidget(widget)->SetMatrixDimension(1, ClampTo(std::size(labels))); + } + public: void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override { switch (widget) { case WID_GRAPH_RANGE_MATRIX: - for (const StringID &str : this->ranges) { - size = maxdim(size, GetStringBoundingBox(str, FS_SMALL)); - } + this->UpdateMatrixSize(widget, size, resize, this->ranges); + break; - size.width += WidgetDimensions::scaled.framerect.Horizontal(); - size.height += WidgetDimensions::scaled.framerect.Vertical(); - - /* Set fixed height for number of ranges. */ - size.height *= static_cast(std::size(this->ranges)); - - resize.width = 0; - resize.height = 0; - this->GetWidget(WID_GRAPH_RANGE_MATRIX)->SetMatrixDimension(1, ClampTo(std::size(this->ranges))); + case WID_GRAPH_SCALE_MATRIX: + this->UpdateMatrixSize(widget, size, resize, this->scales | std::views::transform(&GraphScale::label)); break; case WID_GRAPH_GRAPH: { @@ -699,6 +731,21 @@ public: break; } + case WID_GRAPH_SCALE_MATRIX: { + uint line_height = GetCharacterHeight(FS_SMALL) + WidgetDimensions::scaled.framerect.Vertical(); + uint8_t selected_month_increment = this->scales[this->selected_scale].month_increment; + Rect line = r.WithHeight(line_height); + for (const auto &scale : this->scales) { + /* Redraw frame if selected */ + if (selected_month_increment == scale.month_increment) DrawFrameRect(line, COLOUR_BROWN, FrameFlag::Lowered); + + DrawString(line.Shrink(WidgetDimensions::scaled.framerect), scale.label, TC_BLACK, SA_CENTER, false, FS_SMALL); + + line = line.Translate(0, line_height); + } + break; + } + default: break; } } @@ -720,6 +767,18 @@ public: break; } + case WID_GRAPH_SCALE_MATRIX: { + int row = GetRowFromWidget(pt.y, widget, 0, GetCharacterHeight(FS_SMALL) + WidgetDimensions::scaled.framerect.Vertical()); + const auto &scale = this->scales[row]; + if (this->selected_scale != row) { + this->selected_scale = row; + this->month_increment = scale.month_increment; + this->x_values_increment = scale.x_values_increment; + this->InvalidateData(); + } + break; + } + default: break; } } @@ -1644,6 +1703,13 @@ struct IndustryProductionGraphWindow : BaseCargoGraphWindow { this->InitializeWindow(window_number, STR_GRAPH_LAST_24_MINUTES_TIME_LABEL); } + void OnInit() override + { + this->BaseCargoGraphWindow::OnInit(); + + this->scales = TimerGameEconomy::UsingWallclockUnits() ? MONTHLY_SCALE_WALLCLOCK : MONTHLY_SCALE_CALENDAR; + } + CargoTypes GetCargoTypes(WindowNumber window_number) const override { CargoTypes cargo_types{}; @@ -1671,7 +1737,7 @@ struct IndustryProductionGraphWindow : BaseCargoGraphWindow { void UpdateStatistics(bool initialize) override { - int mo = TimerGameEconomy::month - this->num_vert_lines; + int mo = (TimerGameEconomy::month / this->month_increment - this->num_vert_lines) * this->month_increment; auto yr = TimerGameEconomy::year; while (mo < 0) { yr--; @@ -1709,7 +1775,7 @@ struct IndustryProductionGraphWindow : BaseCargoGraphWindow { transported.dash = 2; auto transported_filler = Filler{transported, &Industry::ProducedHistory::transported}; - FillFromHistory(p.history, i->valid_history, 0, produced_filler, transported_filler); + FillFromHistory(p.history, i->valid_history, this->selected_scale, produced_filler, transported_filler); } for (const auto &a : i->accepted) { @@ -1733,9 +1799,9 @@ struct IndustryProductionGraphWindow : BaseCargoGraphWindow { auto waiting_filler = Filler{waiting, &Industry::AcceptedHistory::waiting}; if (a.history == nullptr) { - FillFromEmpty(i->valid_history, 0, accepted_filler, waiting_filler); + FillFromEmpty(i->valid_history, this->selected_scale, accepted_filler, waiting_filler); } else { - FillFromHistory(*a.history, i->valid_history, 0, accepted_filler, waiting_filler); + FillFromHistory(*a.history, i->valid_history, this->selected_scale, accepted_filler, waiting_filler); } } @@ -1756,7 +1822,7 @@ static constexpr NWidgetPart _nested_industry_production_widgets[] = { NWidget(WWT_EMPTY, INVALID_COLOUR, WID_GRAPH_GRAPH), SetMinimalSize(495, 0), SetFill(1, 1), SetResize(1, 1), NWidget(NWID_VERTICAL), NWidget(NWID_SPACER), SetMinimalSize(0, 24), SetFill(0, 1), - NWidget(WWT_MATRIX, COLOUR_BROWN, WID_GRAPH_RANGE_MATRIX), SetFill(1, 0), SetResize(0, 0), SetMatrixDataTip(1, 0, STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO), + NWidget(WWT_MATRIX, COLOUR_BROWN, WID_GRAPH_RANGE_MATRIX), SetFill(1, 0), SetResize(0, 0), SetMatrixDataTip(1, 0, STR_GRAPH_TOGGLE_RANGE), NWidget(NWID_SPACER), SetMinimalSize(0, 4), NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_GRAPH_ENABLE_CARGOES), SetStringTip(STR_GRAPH_CARGO_ENABLE_ALL, STR_GRAPH_CARGO_TOOLTIP_ENABLE_ALL), SetFill(1, 0), NWidget(WWT_PUSHTXTBTN, COLOUR_BROWN, WID_GRAPH_DISABLE_CARGOES), SetStringTip(STR_GRAPH_CARGO_DISABLE_ALL, STR_GRAPH_CARGO_TOOLTIP_DISABLE_ALL), SetFill(1, 0), @@ -1765,6 +1831,8 @@ static constexpr NWidgetPart _nested_industry_production_widgets[] = { NWidget(WWT_MATRIX, COLOUR_BROWN, WID_GRAPH_MATRIX), SetFill(1, 0), SetResize(0, 2), SetMatrixDataTip(1, 0, STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO), SetScrollbar(WID_GRAPH_MATRIX_SCROLLBAR), NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_GRAPH_MATRIX_SCROLLBAR), EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 4), + NWidget(WWT_MATRIX, COLOUR_BROWN, WID_GRAPH_SCALE_MATRIX), SetFill(1, 0), SetResize(0, 0), SetMatrixDataTip(1, 0, STR_GRAPH_SELECT_SCALE), NWidget(NWID_SPACER), SetMinimalSize(0, 24), SetFill(0, 1), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(5, 0), SetFill(0, 1), SetResize(0, 1), diff --git a/src/lang/english.txt b/src/lang/english.txt index bdad6cd5ad..1728d1d64e 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -622,6 +622,14 @@ STR_GRAPH_COMPANY_VALUES_CAPTION :{WHITE}Company STR_GRAPH_LAST_24_MINUTES_TIME_LABEL :{TINY_FONT}{BLACK}Last 24 minutes STR_GRAPH_LAST_72_MINUTES_TIME_LABEL :{TINY_FONT}{BLACK}Last 72 minutes +STR_GRAPH_LAST_288_MINUTES_TIME_LABEL :{TINY_FONT}{BLACK}Last 288 minutes + +STR_GRAPH_LAST_24_MONTHS :{TINY_FONT}{BLACK}2 years (monthly) +STR_GRAPH_LAST_24_QUARTERS :{TINY_FONT}{BLACK}6 years (quarterly) +STR_GRAPH_LAST_24_YEARS :{TINY_FONT}{BLACK}24 years (yearly) + +STR_GRAPH_TOGGLE_RANGE :Toggle graph for this data range +STR_GRAPH_SELECT_SCALE :Change horizontal scale of graph STR_GRAPH_CARGO_PAYMENT_RATES_CAPTION :{WHITE}Cargo Payment Rates STR_GRAPH_CARGO_PAYMENT_RATES_DAYS :{TINY_FONT}{BLACK}Days in transit diff --git a/src/widgets/graph_widget.h b/src/widgets/graph_widget.h index 496410eb8a..f6c1ae56bc 100644 --- a/src/widgets/graph_widget.h +++ b/src/widgets/graph_widget.h @@ -37,6 +37,7 @@ enum GraphWidgets : WidgetID { WID_GRAPH_MATRIX_SCROLLBAR,///< Cargo list scrollbar. WID_GRAPH_RANGE_MATRIX, ///< Range list. + WID_GRAPH_SCALE_MATRIX, ///< Horizontal axis scale list. WID_PHG_DETAILED_PERFORMANCE, ///< Detailed performance. };