32#include "table/strings.h"
42static const uint INVALID_DATAPOINT_POS = UINT_MAX;
56 for (
CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
100 void OnInvalidateData([[maybe_unused]]
int data = 0, [[maybe_unused]]
bool gui_scope =
true)
override
102 if (!gui_scope)
return;
105 _legend_excluded_companies.
Set(
static_cast<CompanyID>(data));
100 void OnInvalidateData([[maybe_unused]]
int data = 0, [[maybe_unused]]
bool gui_scope =
true)
override {
…}
117 vert->SetPadding(2, 2, 2, 2);
121 auto panel = std::make_unique<NWidgetBackground>(
WWT_PANEL, COLOUR_BROWN, widnum);
124 panel->SetFill(1, 1);
125 panel->SetToolTip(STR_GRAPH_KEY_COMPANY_SELECTION_TOOLTIP);
126 vert->Add(std::move(panel));
131static constexpr NWidgetPart _nested_graph_legend_widgets[] = {
147 _nested_graph_legend_widgets
150static void ShowGraphLegend()
152 AllocateWindowDescFront<GraphLegendWindow>(_graph_legend_desc, 0);
167 static const int GRAPH_MAX_DATASETS = 64;
168 static const int GRAPH_BASE_COLOUR =
GREY_SCALE(2);
169 static const int GRAPH_GRID_COLOUR =
GREY_SCALE(3);
170 static const int GRAPH_AXIS_LINE_COLOUR =
GREY_SCALE(1);
171 static const int GRAPH_ZERO_LINE_COLOUR =
GREY_SCALE(8);
172 static const int GRAPH_YEAR_LINE_COLOUR =
GREY_SCALE(5);
187 uint8_t num_on_x_axis = 0;
199 bool x_values_reversed =
true;
205 std::array<OverflowSafeInt64, GRAPH_NUM_MONTHS> values;
211 std::vector<DataSet> data{};
213 std::span<const StringID> ranges = {};
219 template <
typename Tprojection>
224 inline void Fill(uint i,
const auto &data)
const { this->dataset.values[i] = std::invoke(this->proj, data); }
225 inline void MakeInvalid(uint i)
const { this->dataset.values[i] = INVALID_DATAPOINT; }
235 return {std::begin(dataset.values), std::begin(dataset.values) + this->num_on_x_axis};
246 assert(num_hori_lines > 0);
249 current_interval.
highest = INT64_MIN;
250 current_interval.
lowest = INT64_MAX;
252 for (
const DataSet &dataset : this->data) {
253 if (
HasBit(this->excluded_data, dataset.exclude_bit))
continue;
254 if (
HasBit(this->excluded_range, dataset.range_bit))
continue;
257 if (datapoint != INVALID_DATAPOINT) {
258 current_interval.
highest = std::max(current_interval.
highest, datapoint);
259 current_interval.
lowest = std::min(current_interval.
lowest, datapoint);
265 double abs_lower = (current_interval.
lowest > 0) ? 0 : (double)
abs(current_interval.
lowest);
266 double abs_higher = (current_interval.
highest < 0) ? 0 : (double)current_interval.
highest;
269 abs_higher = (11.0 * abs_higher) / 10.0;
270 abs_lower = (11.0 * abs_lower) / 10.0;
275 if (abs_lower != 0 || abs_higher != 0) {
277 num_pos_grids = (int)floor(0.5 + num_hori_lines * abs_higher / (abs_higher + abs_lower));
280 if (num_pos_grids == 0 && abs_higher != 0) num_pos_grids++;
281 if (num_pos_grids == num_hori_lines && abs_lower != 0) num_pos_grids--;
286 if (abs_higher > 0) {
287 grid_size_higher = abs_higher >
INT64_MAX_IN_DOUBLE ? INT64_MAX :
static_cast<int64_t
>(abs_higher);
288 grid_size_higher = (grid_size_higher + num_pos_grids - 1) / num_pos_grids;
293 grid_size_lower = abs_lower >
INT64_MAX_IN_DOUBLE ? INT64_MAX :
static_cast<int64_t
>(abs_lower);
294 grid_size_lower = (grid_size_lower + num_hori_lines - num_pos_grids - 1) / (num_hori_lines - num_pos_grids);
297 grid_size = std::max(grid_size_higher, grid_size_lower);
300 num_pos_grids = num_hori_lines / 2;
304 current_interval.
highest = num_pos_grids * grid_size;
305 current_interval.
lowest = -(num_hori_lines - num_pos_grids) * grid_size;
306 return current_interval;
317 int64_t y_label = current_interval.
highest;
318 int64_t y_label_separation = (current_interval.
highest - current_interval.
lowest) / num_hori_lines;
322 for (
int i = 0; i < (num_hori_lines + 1); i++) {
324 if (d.width > max_width) max_width = d.width;
326 y_label -= y_label_separation;
344 static_assert(GRAPH_MAX_DATASETS >= (int)
NUM_CARGO && GRAPH_MAX_DATASETS >= (
int)MAX_COMPANIES);
345 assert(this->num_vert_lines > 0);
367 r.right -= label_width;
369 r.left += label_width;
372 int x_sep = (r.right - r.left) / this->num_vert_lines;
373 int y_sep = (r.bottom - r.top) / num_hori_lines;
378 r.left = r.right - x_sep * this->num_vert_lines;
380 r.right = r.left + x_sep * this->num_vert_lines;
382 r.bottom = r.top + y_sep * num_hori_lines;
386 x_axis_offset = (int)((r.bottom - r.top) * (double)interval.
highest / (
double)interval_size);
389 GfxFillRect(r.left, r.top, r.right, r.bottom, GRAPH_BASE_COLOUR);
393 int grid_colour = GRAPH_GRID_COLOUR;
403 for (
int i = 1; i < this->num_vert_lines + 1; i++) {
406 grid_colour = (i % 4 == 0) ? GRAPH_YEAR_LINE_COLOUR : GRAPH_GRID_COLOUR;
408 GfxFillRect(x, r.top, x + gridline_width - 1, r.bottom, grid_colour);
415 for (
int i = 0; i < (num_hori_lines + 1); i++) {
421 GfxFillRect(r.left, y, r.right + gridline_width - 1, y + gridline_width - 1, GRAPH_GRID_COLOUR);
426 GfxFillRect(r.left, r.top, r.left + gridline_width - 1, r.bottom + gridline_width - 1, GRAPH_AXIS_LINE_COLOUR);
429 y = x_axis_offset + r.top;
430 GfxFillRect(r.left, y, r.right + gridline_width - 1, y + gridline_width - 1, GRAPH_ZERO_LINE_COLOUR);
433 if (this->num_on_x_axis == 0)
return;
435 assert(this->num_on_x_axis > 0);
438 int64_t y_label = interval.
highest;
439 int64_t y_label_separation =
abs(interval.
highest - interval.
lowest) / num_hori_lines;
443 for (
int i = 0; i < (num_hori_lines + 1); i++) {
446 GetString(STR_GRAPH_Y_LABEL, this->format_str_y_axis, y_label),
450 GetString(STR_GRAPH_Y_LABEL, this->format_str_y_axis, y_label),
454 y_label -= y_label_separation;
458 x = rtl ? r.right : r.left;
462 x += (this->num_vert_lines - this->num_on_x_axis) * x_sep;
465 if (this->draw_dates) {
468 for (
int i = 0; i < this->num_on_x_axis; i++) {
471 GetString(month == 0 ? STR_GRAPH_X_LABEL_MONTH_YEAR : STR_GRAPH_X_LABEL_MONTH, STR_MONTH_ABBREV_JAN + month, year),
475 GetString(month == 0 ? STR_GRAPH_X_LABEL_MONTH_YEAR : STR_GRAPH_X_LABEL_MONTH, STR_MONTH_ABBREV_JAN + month, year),
485 GfxFillRect(x + x_sep, r.top + gridline_width, x + x_sep + gridline_width - 1, r.bottom - 1, GRAPH_YEAR_LINE_COLOUR);
493 if (this->x_values_reversed) {
494 label = this->x_values_increment * this->num_on_x_axis;
495 iterator = -this->x_values_increment;
497 label = this->x_values_increment;
498 iterator = this->x_values_increment;
501 for (
int i = 0; i < this->num_on_x_axis; i++) {
516 uint pointoffs1 = pointwidth / 2;
517 uint pointoffs2 = pointwidth - pointoffs1;
519 auto draw_dataset = [&](
const DataSet &dataset, uint8_t colour) {
520 if (
HasBit(this->excluded_data, dataset.exclude_bit))
return;
521 if (
HasBit(this->excluded_range, dataset.range_bit))
return;
525 x = r.right + (x_sep / 2);
527 x = r.left + (x_sep / 2);
531 x += (this->num_vert_lines - this->num_on_x_axis) * x_sep;
533 uint prev_x = INVALID_DATAPOINT_POS;
534 uint prev_y = INVALID_DATAPOINT_POS;
538 if (datapoint != INVALID_DATAPOINT) {
550 int mult_range = FindLastBit<uint32_t>(x_axis_offset) + FindLastBit<uint64_t>(
abs(datapoint));
551 int reduce_range = std::max(mult_range - 31, 0);
555 datapoint = -(
abs(datapoint) >> reduce_range);
557 datapoint >>= reduce_range;
559 y = r.top + x_axis_offset - ((r.bottom - r.top) * datapoint) / (interval_size >> reduce_range);
562 GfxFillRect(x - pointoffs1, y - pointoffs1, x + pointoffs2, y + pointoffs2, colour);
565 if (prev_x != INVALID_DATAPOINT_POS) GfxDrawLine(prev_x, prev_y, x, y, colour, linewidth, dash);
570 prev_x = INVALID_DATAPOINT_POS;
571 prev_y = INVALID_DATAPOINT_POS;
579 for (
const DataSet &dataset : this->data) {
580 if (dataset.exclude_bit != this->highlight_data && dataset.range_bit != this->highlight_range) {
581 draw_dataset(dataset, dataset.colour);
587 if (this->highlight_state && (this->highlight_data != UINT8_MAX || this->highlight_range != UINT8_MAX)) {
588 for (
const DataSet &dataset : this->data) {
589 if (dataset.exclude_bit == this->highlight_data || dataset.range_bit == this->highlight_range) {
598 format_str_y_axis(format_str_y_axis)
605 if (this->highlight_data == UINT8_MAX && this->highlight_range == UINT8_MAX)
return;
617 for (
const StringID &str : this->ranges) {
625 size.height *=
static_cast<uint
>(std::size(this->ranges));
629 this->GetWidget<NWidgetCore>(
WID_GRAPH_RANGE_MATRIX)->SetMatrixDimension(1, ClampTo<uint32_t>(std::size(this->ranges)));
633 uint x_label_width = 0;
636 if (this->draw_dates) {
639 for (
int i = 0; i < this->num_on_x_axis; i++) {
640 x_label_width = std::max(x_label_width,
GetStringBoundingBox(
GetString(month == 0 ? STR_GRAPH_X_LABEL_MONTH_YEAR : STR_GRAPH_X_LABEL_MONTH, STR_MONTH_ABBREV_JAN + month, year)).width);
658 size.height = std::max<uint>(size.height, size.width / 3);
677 for (
const auto &str : this->ranges) {
678 bool lowered = !
HasBit(this->excluded_range, index);
719 uint8_t new_highlight_range = UINT8_MAX;
722 if (!
HasBit(this->excluded_range, row)) new_highlight_range =
static_cast<uint8_t
>(row);
726 uint8_t new_highlight_data = UINT8_MAX;
728 auto dataset_index = this->GetDatasetIndex(pt.y);
729 if (dataset_index.has_value() && !
HasBit(this->excluded_data, *dataset_index)) new_highlight_data = *dataset_index;
732 if (this->highlight_data == new_highlight_data && this->highlight_range == new_highlight_range)
return;
735 this->highlight_data = new_highlight_data;
736 this->highlight_range = new_highlight_range;
737 this->highlight_state =
true;
743 this->UpdateStatistics(
false);
751 void OnInvalidateData([[maybe_unused]]
int data = 0, [[maybe_unused]]
bool gui_scope =
true)
override
753 if (!gui_scope)
return;
754 this->UpdateStatistics(
true);
751 void OnInvalidateData([[maybe_unused]]
int data = 0, [[maybe_unused]]
bool gui_scope =
true)
override {
…}
757 virtual void UpdateStatistics(
bool initialize) = 0;
759 virtual std::optional<uint8_t> GetDatasetIndex(
int) {
return std::nullopt; }
785 CompanyMask excluded_companies = _legend_excluded_companies;
788 for (
CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
794 nums = std::min(this->num_vert_lines, std::max(nums, c->num_valid_stat_ent));
804 if (!initialize && this->excluded_data == excluded_companies.
base() && this->num_on_x_axis == nums &&
805 this->year == yr && this->month == mo) {
810 this->excluded_data = excluded_companies.
base();
811 this->num_on_x_axis = nums;
816 for (
CompanyID k = CompanyID::Begin(); k < MAX_COMPANIES; ++k) {
818 if (c ==
nullptr)
continue;
820 DataSet &dataset = this->data.emplace_back();
822 dataset.exclude_bit = k.base();
824 for (
int j = this->num_on_x_axis, i = 0; --j >= 0;) {
826 dataset.values[i] = INVALID_DATAPOINT;
830 dataset.values[i] = std::min(GetGraphData(c, j), INVALID_DATAPOINT - 1);
862static constexpr NWidgetPart _nested_operating_profit_widgets[] = {
874 NWidget(
WWT_TEXT, INVALID_COLOUR,
WID_GRAPH_FOOTER),
SetFill(1, 0),
SetResize(1, 0),
SetPadding(2, 0, 2, 0),
SetTextStyle(TC_BLACK,
FS_SMALL),
SetAlignment(
SA_CENTER),
881 WDP_AUTO,
"graph_operating_profit", 0, 0,
884 _nested_operating_profit_widgets
888void ShowOperatingProfitGraph()
890 AllocateWindowDescFront<OperatingProfitGraphWindow>(_operating_profit_desc, 0);
915static constexpr NWidgetPart _nested_income_graph_widgets[] = {
927 NWidget(
WWT_TEXT, INVALID_COLOUR,
WID_GRAPH_FOOTER),
SetFill(1, 0),
SetResize(1, 0),
SetPadding(2, 0, 2, 0),
SetTextStyle(TC_BLACK,
FS_SMALL),
SetAlignment(
SA_CENTER),
937 _nested_income_graph_widgets
940void ShowIncomeGraph()
942 AllocateWindowDescFront<IncomeGraphWindow>(_income_graph_desc, 0);
966static constexpr NWidgetPart _nested_delivered_cargo_graph_widgets[] = {
978 NWidget(
WWT_TEXT, INVALID_COLOUR,
WID_GRAPH_FOOTER),
SetFill(1, 0),
SetResize(1, 0),
SetPadding(2, 0, 2, 0),
SetTextStyle(TC_BLACK,
FS_SMALL),
SetAlignment(
SA_CENTER),
985 WDP_AUTO,
"graph_delivered_cargo", 0, 0,
988 _nested_delivered_cargo_graph_widgets
991void ShowDeliveredCargoGraph()
993 AllocateWindowDescFront<DeliveredCargoGraphWindow>(_delivered_cargo_graph_desc, 0);
1023static constexpr NWidgetPart _nested_performance_history_widgets[] = {
1036 NWidget(
WWT_TEXT, INVALID_COLOUR,
WID_GRAPH_FOOTER),
SetFill(1, 0),
SetResize(1, 0),
SetPadding(2, 0, 2, 0),
SetTextStyle(TC_BLACK,
FS_SMALL),
SetAlignment(
SA_CENTER),
1043 WDP_AUTO,
"graph_performance", 0, 0,
1046 _nested_performance_history_widgets
1049void ShowPerformanceHistoryGraph()
1051 AllocateWindowDescFront<PerformanceHistoryGraphWindow>(_performance_history_desc, 0);
1075static constexpr NWidgetPart _nested_company_value_graph_widgets[] = {
1087 NWidget(
WWT_TEXT, INVALID_COLOUR,
WID_GRAPH_FOOTER),
SetFill(1, 0),
SetResize(1, 0),
SetPadding(2, 0, 2, 0),
SetTextStyle(TC_BLACK,
FS_SMALL),
SetAlignment(
SA_CENTER),
1094 WDP_AUTO,
"graph_company_value", 0, 0,
1097 _nested_company_value_graph_widgets
1100void ShowCompanyValueGraph()
1102 AllocateWindowDescFront<CompanyValueGraphWindow>(_company_value_graph_desc, 0);
1132 virtual CargoTypes GetCargoTypes(
WindowNumber number)
const = 0;
1133 virtual CargoTypes &GetExcludedCargoTypes()
const = 0;
1135 std::optional<uint8_t> GetDatasetIndex(
int y)
override
1138 if (row >= this->vscroll->
GetCount())
return std::nullopt;
1142 if (row-- > 0)
continue;
1147 return std::nullopt;
1175 this->line_height = size.height;
1176 size.height = this->line_height * 11;
1198 if (pos-- > 0)
continue;
1199 if (--max < 0)
break;
1201 bool lowered = !
HasBit(this->excluded_data, cs->Index());
1211 uint8_t pc = cs->legend_colour;
1212 if (this->highlight_data == cs->Index()) pc = this->highlight_state ?
PC_WHITE :
PC_BLACK;
1218 line = line.
Translate(0, this->line_height);
1227 this->GetExcludedCargoTypes() = {};
1228 this->excluded_data = this->GetExcludedCargoTypes();
1234 this->GetExcludedCargoTypes() = this->
cargo_types;
1235 this->excluded_data = this->GetExcludedCargoTypes();
1242 if (row >= this->vscroll->
GetCount())
return;
1246 if (row-- > 0)
continue;
1248 ToggleBit(this->GetExcludedCargoTypes(), cs->Index());
1249 this->excluded_data = this->GetExcludedCargoTypes();
1273 static inline CargoTypes excluded_cargo_types{};
1279 this->draw_dates =
false;
1281 this->x_values_reversed =
false;
1285 this->InitializeWindow(
window_number, STR_GRAPH_CARGO_PAYMENT_RATES_SECONDS, STR_GRAPH_CARGO_PAYMENT_RATES_DAYS);
1293 CargoTypes &GetExcludedCargoTypes()
const override
1295 return PaymentRatesGraphWindow::excluded_cargo_types;
1303 void OnInvalidateData([[maybe_unused]]
int data = 0, [[maybe_unused]]
bool gui_scope =
true)
override
1305 if (!gui_scope)
return;
1303 void OnInvalidateData([[maybe_unused]]
int data = 0, [[maybe_unused]]
bool gui_scope =
true)
override {
…}
1314 void UpdateStatistics(
bool)
override {}
1321 this->excluded_data = this->GetExcludedCargoTypes();
1325 DataSet &dataset = this->data.emplace_back();
1326 dataset.colour = cs->legend_colour;
1327 dataset.exclude_bit = cs->Index();
1329 for (uint j = 0; j != this->num_on_x_axis; j++) {
1330 dataset.values[j] = GetTransportedGoodsIncome(10, 20, j * 4 + 4, cs->Index());
1336static constexpr NWidgetPart _nested_cargo_payment_rates_widgets[] = {
1345 NWidget(
WWT_TEXT, INVALID_COLOUR,
WID_GRAPH_HEADER),
SetFill(1, 0),
SetResize(1, 0),
SetPadding(2, 0, 2, 0),
SetStringTip(STR_GRAPH_CARGO_PAYMENT_RATES_TITLE),
SetTextStyle(TC_BLACK,
FS_SMALL),
SetAlignment(
SA_CENTER),
1354 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),
1362 NWidget(
WWT_TEXT, INVALID_COLOUR,
WID_GRAPH_FOOTER),
SetFill(1, 0),
SetResize(1, 0),
SetPadding(2, 0, 2, 0),
SetTextStyle(TC_BLACK,
FS_SMALL),
SetAlignment(
SA_CENTER),
1369 WDP_AUTO,
"graph_cargo_payment_rates", 0, 0,
1372 _nested_cargo_payment_rates_widgets
1376void ShowCargoPaymentRates()
1378 AllocateWindowDescFront<PaymentRatesGraphWindow>(_cargo_payment_rates_desc, 0);
1388 uint score_info_left = 0;
1389 uint score_info_right = 0;
1393 uint bar_height = 0;
1394 uint score_detail_left = 0;
1395 uint score_detail_right = 0;
1399 this->UpdateCompanyStats();
1405 void UpdateCompanyStats()
1423 uint score_info_width = 0;
1424 for (uint i = SCORE_BEGIN; i <
SCORE_END; i++) {
1437 int max = -(999999999 - 500);
1458 this->score_info_left = rtl ? right - score_info_width :
left;
1459 this->score_info_right = rtl ? right :
left + score_info_width;
1461 this->score_detail_left = rtl ?
left : right - score_detail_width;
1462 this->score_detail_right = rtl ?
left + score_detail_width : right;
1465 this->bar_right = this->bar_left + this->bar_width - 1;
1473 if (this->company == CompanyID::Invalid())
return;
1492 int64_t val = _score_part[company][score_type];
1502 uint bar_top =
CentreBounds(r.top, r.bottom, this->bar_height);
1505 DrawString(this->score_info_left, this->score_info_right, text_top, STR_PERFORMANCE_DETAIL_VEHICLES + score_type);
1511 uint x = Clamp<int64_t>(val, 0, needed) * this->bar_width / needed;
1514 x = this->bar_right - x;
1516 x = this->bar_left + x;
1520 if (x != this->bar_left)
GfxFillRect(this->bar_left, bar_top, x, bar_top + this->bar_height - 1, rtl ? colour_notdone : colour_done);
1521 if (x != this->bar_right)
GfxFillRect(x, bar_top, this->bar_right, bar_top + this->bar_height - 1, rtl ? colour_done : colour_notdone);
1524 DrawString(this->bar_left, this->bar_right, text_top,
GetString(STR_PERFORMANCE_DETAIL_PERCENT, Clamp<int64_t>(val, 0, needed) * 100 / needed), TC_FROMSTRING,
SA_HOR_CENTER);
1527 if (score_type == SCORE_LOAN) val = needed - val;
1531 switch (score_type) {
1532 case SCORE_MIN_PROFIT:
1533 case SCORE_MIN_INCOME:
1534 case SCORE_MAX_INCOME:
1537 DrawString(this->score_detail_left, this->score_detail_right, text_top,
GetString(STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY, val, needed));
1540 DrawString(this->score_detail_left, this->score_detail_right, text_top,
GetString(STR_PERFORMANCE_DETAIL_AMOUNT_INT, val, needed));
1562 if (--this->timeout == 0) {
1563 this->UpdateCompanyStats();
1573 void OnInvalidateData([[maybe_unused]]
int data = 0, [[maybe_unused]]
bool gui_scope =
true)
override
1575 if (!gui_scope)
return;
1577 for (
CompanyID i = CompanyID::Begin(); i < MAX_COMPANIES; ++i) {
1585 this->company = CompanyID::Invalid();
1588 if (this->company == CompanyID::Invalid()) {
1590 this->company = c->index;
1596 if (this->company != CompanyID::Invalid()) {
1573 void OnInvalidateData([[maybe_unused]]
int data = 0, [[maybe_unused]]
bool gui_scope =
true)
override {
…}
1602CompanyID PerformanceRatingDetailWindow::company = CompanyID::Invalid();
1609 static inline constexpr StringID RANGE_LABELS[] = {
1610 STR_GRAPH_INDUSTRY_RANGE_PRODUCED,
1611 STR_GRAPH_INDUSTRY_RANGE_TRANSPORTED
1614 static inline CargoTypes excluded_cargo_types{};
1621 this->month_increment = 1;
1624 this->ranges = RANGE_LABELS;
1626 this->InitializeWindow(
window_number, STR_GRAPH_LAST_24_MINUTES_TIME_LABEL);
1633 for (
const auto &p : i->
produced) {
1639 CargoTypes &GetExcludedCargoTypes()
const override
1641 return IndustryProductionGraphWindow::excluded_cargo_types;
1651 void UpdateStatistics(
bool initialize)
override
1660 if (!initialize && this->excluded_data == this->GetExcludedCargoTypes() && this->num_on_x_axis == this->num_vert_lines && this->year == yr && this->month == mo) {
1665 this->excluded_data = this->GetExcludedCargoTypes();
1672 for (
const auto &p : i->produced) {
1676 this->data.reserve(this->data.size() + 2);
1678 DataSet &produced = this->data.emplace_back();
1679 produced.colour = cs->legend_colour;
1680 produced.exclude_bit = cs->
Index();
1681 produced.range_bit = 0;
1684 DataSet &transported = this->data.emplace_back();
1685 transported.colour = cs->legend_colour;
1686 transported.exclude_bit = cs->
Index();
1687 transported.range_bit = 1;
1688 transported.dash = 2;
1691 FillFromHistory<GRAPH_NUM_MONTHS>(p.history, i->
valid_history, produced_filler, transported_filler);
1698static constexpr NWidgetPart _nested_industry_production_widgets[] = {
1711 NWidget(
WWT_MATRIX, COLOUR_BROWN,
WID_GRAPH_RANGE_MATRIX),
SetFill(1, 0),
SetResize(0, 0),
SetMatrixDataTip(1, 0, STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO),
1717 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),
1725 NWidget(
WWT_TEXT, INVALID_COLOUR,
WID_GRAPH_FOOTER),
SetFill(1, 0),
SetResize(1, 0),
SetPadding(2, 0, 2, 0),
SetTextStyle(TC_BLACK,
FS_SMALL),
SetAlignment(
SA_CENTER),
1732 WDP_AUTO,
"graph_industry_production", 0, 0,
1735 _nested_industry_production_widgets
1738void ShowIndustryProductionGraph(
WindowNumber window_number)
1740 AllocateWindowDescFront<IndustryProductionGraphWindow>(_industry_production_desc, window_number);
1750 const StringID performance_tips[] = {
1751 realtime ? STR_PERFORMANCE_DETAIL_VEHICLES_TOOLTIP_PERIODS : STR_PERFORMANCE_DETAIL_VEHICLES_TOOLTIP_YEARS,
1752 STR_PERFORMANCE_DETAIL_STATIONS_TOOLTIP,
1753 realtime ? STR_PERFORMANCE_DETAIL_MIN_PROFIT_TOOLTIP_PERIODS : STR_PERFORMANCE_DETAIL_MIN_PROFIT_TOOLTIP_YEARS,
1754 STR_PERFORMANCE_DETAIL_MIN_INCOME_TOOLTIP,
1755 STR_PERFORMANCE_DETAIL_MAX_INCOME_TOOLTIP,
1756 STR_PERFORMANCE_DETAIL_DELIVERED_TOOLTIP,
1757 STR_PERFORMANCE_DETAIL_CARGO_TOOLTIP,
1758 STR_PERFORMANCE_DETAIL_MONEY_TOOLTIP,
1759 STR_PERFORMANCE_DETAIL_LOAN_TOOLTIP,
1760 STR_PERFORMANCE_DETAIL_TOTAL_TOOLTIP,
1767 auto panel = std::make_unique<NWidgetBackground>(
WWT_PANEL, COLOUR_BROWN, widnum);
1768 panel->SetFill(1, 1);
1770 vert->Add(std::move(panel));
1781static constexpr NWidgetPart _nested_performance_rating_detail_widgets[] = {
1794static WindowDesc _performance_rating_detail_desc(
1798 _nested_performance_rating_detail_widgets
1801void ShowPerformanceRatingDetail()
1803 AllocateWindowDescFront<PerformanceRatingDetailWindow>(_performance_rating_detail_desc, 0);
1806void InitializeGraphGui()
1809 PaymentRatesGraphWindow::excluded_cargo_types = {};
1810 IndustryProductionGraphWindow::excluded_cargo_types = {};
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
constexpr uint CountBits(T value)
Counts the number of set bits in a variable.
constexpr T ToggleBit(T &x, const uint8_t y)
Toggles a bit in a variable.
uint8_t CargoType
Cargo slots to indicate a cargo type within a game.
bool IsValidCargoType(CargoType cargo)
Test whether cargo type is not INVALID_CARGO.
static const CargoType NUM_CARGO
Maximum number of cargo types in a game.
std::span< const CargoSpec * > _sorted_standard_cargo_specs
Standard cargo specifications sorted alphabetically by name.
CargoTypes _standard_cargo_mask
Bitmask of real cargo types available.
std::vector< const CargoSpec * > _sorted_cargo_specs
Cargo specifications sorted alphabetically by name.
Types/functions related to cargoes.
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Tstorage base() const noexcept
Retrieve the raw value behind this bit set.
constexpr Timpl & Flip(Tvalue_type value)
Flip the value-th bit.
constexpr Timpl & Set()
Set all bits.
void UpdateStatistics(bool initialize) override
Update the statistics.
An interval timer will fire every interval, and will continue to fire until it is deleted.
static constexpr TimerGameTick::Ticks DAY_TICKS
1 day is 74 ticks; TimerGameCalendar::date_fract used to be uint16_t and incremented by 885.
static Year year
Current year, starting at 0.
static Month month
Current month (0..11).
static bool UsingWallclockUnits(bool newgame=false)
Check if we are using wallclock units.
uint8_t Month
Type for the month, note: 0 based, i.e.
Definition of stuff that is very close to a company, like the company struct itself.
void DrawCompanyIcon(CompanyID c, int x, int y)
Draw the icon of a company.
GUI Functions related to companies.
Functions to handle different currencies.
const CurrencySpec & GetCurrency()
Get the currently selected currency.
int UpdateCompanyRatingAndValue(Company *c, bool update)
if update is set to true, the economy is updated with this score (also the house is updated,...
const ScoreInfo _score_info[]
Score info, values used for computing the detailed performance rating.
Functions related to the economy.
ScoreID
Score categories in the detailed performance rating.
@ SCORE_END
How many scores are there..
@ SCORE_TOTAL
This must always be the last entry.
static constexpr int SCORE_MAX
The max score that can be in the performance history.
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
int CentreBounds(int min, int max, int size)
Determine where to position a centred object.
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
int DrawString(int left, int right, int top, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen.
bool DrawStringMultiLineWithClipping(int left, int right, int top, int bottom, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw a multiline string, possibly over multiple lines, if the region is within the current display cl...
Functions related to the gfx engine.
@ FS_SMALL
Index of the small font in the font tables.
@ FS_NORMAL
Index of the normal font in the font tables.
@ SA_LEFT
Left align the text.
@ SA_RIGHT
Right align the text (must be a single bit).
@ SA_HOR_CENTER
Horizontally center the text.
@ SA_FORCE
Force the alignment, i.e. don't swap for RTL languages.
@ SA_CENTER
Center both horizontally and vertically.
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
constexpr double INT64_MAX_IN_DOUBLE
The biggest double that when cast to int64_t still fits in a int64_t.
static std::unique_ptr< NWidgetBase > MakeNWidgetCompanyLines()
Construct a vertical list of buttons, one for each company.
std::unique_ptr< NWidgetBase > MakeCompanyButtonRowsGraphGUI()
Make a number of rows with buttons for each company for the performance rating detail window.
static std::unique_ptr< NWidgetBase > MakePerformanceDetailPanels()
Make a vertical list of panels for outputting score details.
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
Functions for storing historical data.
constexpr bool IsInsideMM(const size_t x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
constexpr T abs(const T a)
Returns the absolute value of (scalar) variable.
uint8_t GetColourGradient(Colours colour, ColourShade shade)
Get colour gradient palette index.
static const uint8_t PC_WHITE
White palette colour.
constexpr uint8_t GREY_SCALE(uint8_t level)
Return the colour for a particular greyscale level.
static const uint8_t PC_BLACK
Black palette colour.
A number of safeguards to prevent using unsafe methods.
ClientSettings _settings_client
The current settings for this game.
This file contains all sprite-related enums and defines.
Definition of base types and functions in a cross-platform compatible way.
#define lengthof(array)
Return the length of an fixed size array.
uint64_t GetParamMaxValue(uint64_t max_value, uint min_count, FontSize size)
Get some number that is suitable for string size computations.
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
TextDirection _current_text_dir
Text direction of the currently selected language.
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
@ TD_RTL
Text is written right-to-left by default.
uint legend_width
Width of legend 'blob'.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void OnInit() override
Notification that the nested widget tree gets initialized.
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
CargoTypes cargo_types
Cargo types that can be selected.
void OnResize() override
Called after the window got resized.
Scrollbar * vscroll
Cargo list scrollbar.
uint line_height
Pixel height of each cargo type row.
DataSet & dataset
Dataset to fill.
const Tprojection & proj
Projection to apply.
uint GetYLabelWidth(ValuesInterval current_interval, int num_hori_lines) const
Get width for Y labels.
void OnGameTick() override
Called once per (game) tick.
static const int MIN_GRID_PIXEL_SIZE
Minimum distance between graph lines.
static const int GRAPH_NUM_MONTHS
Number of months displayed in the graph.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
static const int ECONOMY_QUARTER_MINUTES
Minutes per economic quarter.
static const int GRAPH_PAYMENT_RATE_STEPS
Number of steps on Payment rate graph.
void OnMouseOver(Point pt, WidgetID widget) override
The mouse is currently moving over the window or has just moved outside of the window.
std::span< const OverflowSafeInt64 > GetDataSetRange(const DataSet &dataset) const
Get appropriate part of dataset values for the current number of horizontal points.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
static const int ECONOMY_MONTH_MINUTES
Minutes per economic month.
uint64_t excluded_data
bitmask of the datasets that shouldn't be displayed.
bool draw_dates
Should we draw months and years on the time axis?
static const int MIN_GRAPH_NUM_LINES_Y
Minimal number of horizontal lines to draw.
uint64_t excluded_range
bitmask of ranges that should not be displayed.
uint8_t highlight_range
Data range that should be highlighted, or UINT8_MAX for none.
bool highlight_state
Current state of highlight, toggled every TIMER_BLINK_INTERVAL period.
uint8_t month_increment
month increment between vertical lines. must be divisor of 12.
static const int PAYMENT_GRAPH_X_STEP_DAYS
X-axis step label for cargo payment rates "Days in transit".
ValuesInterval GetValuesInterval(int num_hori_lines) const
Get the interval that contains the graph's data.
static const TextColour GRAPH_AXIS_LABEL_COLOUR
colour of the graph axis label.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
void DrawGraph(Rect r) const
Actually draw the graph.
static const int PAYMENT_GRAPH_X_STEP_SECONDS
X-axis step label for cargo payment rates "Seconds in transit".
void UpdateWidgetSize(WidgetID widget, Dimension &size, const Dimension &padding, Dimension &fill, Dimension &resize) override
Update size and resize step of a widget in the window.
uint8_t highlight_data
Data set that should be highlighted, or UINT8_MAX for none.
Specification of a cargo type.
static CargoSpec * Get(size_t index)
Retrieve cargo details for the given cargo type.
CargoType Index() const
Determines index of this cargospec.
StringID name
Name of this type of cargo.
GUISettings gui
settings related to the GUI
Colours colour
Company colour.
std::array< CompanyEconomyEntry, MAX_HISTORY_QUARTERS > old_economy
Economic data of the company of the last MAX_HISTORY_QUARTERS quarters.
uint8_t num_valid_stat_ent
Number of valid statistical entries in old_economy.
uint16_t rate
The conversion rate compared to the base currency.
Dimensions (a width and height) of a rectangle in 2D.
uint8_t graph_line_thickness
the thickness of the lines in the various graph guis
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
uint16_t transported
Total transported.
uint16_t production
Total produced.
Defines the internal data of a functional industry.
ValidHistoryMask valid_history
Mask of valid history records.
ProducedCargoes produced
produced cargo slots
void UpdatePaymentRates()
Update the payment rates according to the latest information.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
const IntervalTimer< TimerWindow > update_payment_interval
Update the payment rates on a regular interval.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
Coordinates of a point in 2D.
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static Titem * Get(auto index)
Returns Titem with given index.
static bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
static Titem * GetIfValid(auto index)
Returns Titem with given index.
constexpr uint Horizontal() const
Get total horizontal padding of RectPadding.
constexpr uint Vertical() const
Get total vertical padding of RectPadding.
Specification of a rectangle with absolute coordinates of all edges.
Rect WithWidth(int width, bool end) const
Copy Rect and set its width.
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
Rect WithHeight(int height, bool end=false) const
Copy Rect and set its height.
Rect Indent(int indent, bool end) const
Copy Rect and indent it from its position.
Rect Translate(int x, int y) const
Copy and translate Rect by x,y pixels.
int needed
How much you need to get the perfect score.
int score
How much score it will give.
Iterable ensemble of each set bit in a value.
Templated helper to make a type-safe 'typedef' representing a single POD value.
Contains the interval of a graph's data.
OverflowSafeInt64 lowest
Lowest value of this interval. Must be zero or less.
OverflowSafeInt64 highest
Highest value of this interval. Must be zero or greater.
High level window description.
Number to differentiate different windows of the same class.
Data structure for an opened window.
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing)
void RaiseWidget(WidgetID widget_index)
Marks a widget as raised.
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
ResizeInfo resize
Resize information.
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
bool IsWidgetDisabled(WidgetID widget_index) const
Gets the enabled/disabled status of a widget.
int left
x position of left edge of the window
int GetRowFromWidget(int clickpos, WidgetID widget, int padding, int line_height=-1) const
Compute the row of a widget that a user clicked in.
void LowerWidget(WidgetID widget_index)
Marks a widget as lowered.
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
int height
Height of the window (number of pixels down in y direction)
int width
width of the window (number of pixels to the right in x direction)
void ToggleWidgetLoweredState(WidgetID widget_index)
Invert the lowered/raised status of a widget.
WindowNumber window_number
Window number within the window class.
Definition of Interval and OneShot timers.
Definition of the game-economy-timer.
Definition of the tick-based game-timer.
Definition of the Window system.
static constexpr std::chrono::milliseconds TIMER_BLINK_INTERVAL
Interval used by blinking interface elements.
void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope)
Mark window data of the window of a given class and specific window number as invalid (in need of re-...
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Window functions not directly related to making/drawing windows.
Functions, definitions and such used only by the GUI.
@ Lowered
If set the frame is lowered and the background colour brighter (ie. buttons when pressed)
@ WDP_AUTO
Find a place automatically.
@ WC_PERFORMANCE_HISTORY
Performance history graph; Window numbers:
@ WC_PERFORMANCE_DETAIL
Performance detail window; Window numbers:
@ WC_PAYMENT_RATES
Payment rates graph; Window numbers:
@ WC_GRAPH_LEGEND
Legend for graphs; Window numbers:
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
@ WC_OPERATING_PROFIT
Operating profit graph; Window numbers:
@ WC_INDUSTRY_PRODUCTION
Industry production history graph; Window numbers:
@ WC_INDUSTRY_VIEW
Industry view; Window numbers:
@ WC_INCOME_GRAPH
Income graph; Window numbers:
@ WC_DELIVERED_CARGO
Delivered cargo graph; Window numbers:
@ WC_COMPANY_VALUE
Company value graph; Window numbers:
Functions related to zooming.
@ Normal
The normal zoom level.