35#include "table/strings.h"
45static const uint INVALID_DATAPOINT_POS = UINT_MAX;
59 for (
CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
105 void OnInvalidateData([[maybe_unused]]
int data = 0, [[maybe_unused]]
bool gui_scope =
true)
override
107 if (!gui_scope)
return;
110 _legend_excluded_companies.
Set(
static_cast<CompanyID>(data));
105 void OnInvalidateData([[maybe_unused]]
int data = 0, [[maybe_unused]]
bool gui_scope =
true)
override {
…}
122 vert->SetPadding(2, 2, 2, 2);
126 auto panel = std::make_unique<NWidgetBackground>(
WWT_PANEL, COLOUR_BROWN, widnum);
129 panel->SetFill(1, 1);
130 panel->SetToolTip(STR_GRAPH_KEY_COMPANY_SELECTION_TOOLTIP);
131 vert->Add(std::move(panel));
136static constexpr NWidgetPart _nested_graph_legend_widgets[] = {
152 _nested_graph_legend_widgets
155static void ShowGraphLegend()
157 AllocateWindowDescFront<GraphLegendWindow>(_graph_legend_desc, 0);
172 static const int GRAPH_MAX_DATASETS = 64;
193 uint8_t month_increment = 0;
194 int16_t x_values_increment = 0;
198 static inline constexpr GraphScale MONTHLY_SCALE_WALLCLOCK[] = {
199 {STR_GRAPH_LAST_24_MINUTES_TIME_LABEL, HISTORY_MONTH.total_division,
ECONOMY_MONTH_MINUTES, &HISTORY_MONTH},
200 {STR_GRAPH_LAST_72_MINUTES_TIME_LABEL, HISTORY_QUARTER.total_division,
ECONOMY_QUARTER_MINUTES, &HISTORY_QUARTER},
201 {STR_GRAPH_LAST_288_MINUTES_TIME_LABEL, HISTORY_YEAR.total_division,
ECONOMY_YEAR_MINUTES, &HISTORY_YEAR},
204 static inline constexpr GraphScale MONTHLY_SCALE_CALENDAR[] = {
213 uint8_t num_on_x_axis = 0;
225 bool x_values_reversed =
true;
231 std::array<OverflowSafeInt64, GRAPH_NUM_MONTHS> values;
237 std::vector<DataSet> data{};
239 std::span<const StringID> ranges{};
240 std::span<const GraphScale> scales{};
241 uint8_t selected_scale = 0;
250 inline void MakeZero(uint i)
const { this->dataset.values[i] = 0; }
251 inline void MakeInvalid(uint i)
const { this->dataset.values[i] = INVALID_DATAPOINT; }
254 template <
typename Tprojection>
258 inline void Fill(uint i,
const auto &data)
const { this->
dataset.values[i] = std::invoke(this->proj, data); }
268 return {std::begin(dataset.values), std::begin(dataset.values) + this->num_on_x_axis};
279 assert(num_hori_lines > 0);
282 current_interval.
highest = INT64_MIN;
283 current_interval.
lowest = INT64_MAX;
285 for (
const DataSet &dataset : this->data) {
286 if (
HasBit(this->excluded_data, dataset.exclude_bit))
continue;
287 if (
HasBit(this->excluded_range, dataset.range_bit))
continue;
290 if (datapoint != INVALID_DATAPOINT) {
291 current_interval.
highest = std::max(current_interval.
highest, datapoint);
292 current_interval.
lowest = std::min(current_interval.
lowest, datapoint);
298 double abs_lower = (current_interval.
lowest > 0) ? 0 : (double)
abs(current_interval.
lowest);
299 double abs_higher = (current_interval.
highest < 0) ? 0 : (double)current_interval.
highest;
302 abs_higher = (11.0 * abs_higher) / 10.0;
303 abs_lower = (11.0 * abs_lower) / 10.0;
308 if (abs_lower != 0 || abs_higher != 0) {
310 num_pos_grids = (int)floor(0.5 + num_hori_lines * abs_higher / (abs_higher + abs_lower));
313 if (num_pos_grids == 0 && abs_higher != 0) num_pos_grids++;
314 if (num_pos_grids == num_hori_lines && abs_lower != 0) num_pos_grids--;
319 if (abs_higher > 0) {
320 grid_size_higher = abs_higher >
INT64_MAX_IN_DOUBLE ? INT64_MAX :
static_cast<int64_t
>(abs_higher);
321 grid_size_higher = (grid_size_higher + num_pos_grids - 1) / num_pos_grids;
326 grid_size_lower = abs_lower >
INT64_MAX_IN_DOUBLE ? INT64_MAX :
static_cast<int64_t
>(abs_lower);
327 grid_size_lower = (grid_size_lower + num_hori_lines - num_pos_grids - 1) / (num_hori_lines - num_pos_grids);
330 grid_size = std::max(grid_size_higher, grid_size_lower);
333 num_pos_grids = num_hori_lines / 2;
337 current_interval.
highest = num_pos_grids * grid_size;
338 current_interval.
lowest = -(num_hori_lines - num_pos_grids) * grid_size;
339 return current_interval;
350 int64_t y_label = current_interval.
highest;
351 int64_t y_label_separation = (current_interval.
highest - current_interval.
lowest) / num_hori_lines;
355 for (
int i = 0; i < (num_hori_lines + 1); i++) {
357 if (d.width > max_width) max_width = d.width;
359 y_label -= y_label_separation;
377 static_assert(GRAPH_MAX_DATASETS >= (int)
NUM_CARGO && GRAPH_MAX_DATASETS >= (
int)MAX_COMPANIES);
378 assert(this->num_vert_lines > 0);
400 r.right -= label_width;
402 r.left += label_width;
405 int x_sep = (r.right - r.left) / this->num_vert_lines;
406 int y_sep = (r.bottom - r.top) / num_hori_lines;
411 r.left = r.right - x_sep * this->num_vert_lines;
413 r.right = r.left + x_sep * this->num_vert_lines;
415 r.bottom = r.top + y_sep * num_hori_lines;
419 x_axis_offset = (int)((r.bottom - r.top) * (double)interval.
highest / (
double)interval_size);
422 GfxFillRect(r.left, r.top, r.right, r.bottom, GRAPH_BASE_COLOUR);
436 for (
int i = 1; i < this->num_vert_lines + 1; i++) {
439 grid_colour = (i % 4 == 0) ? GRAPH_YEAR_LINE_COLOUR : GRAPH_GRID_COLOUR;
441 GfxFillRect(x, r.top, x + gridline_width - 1, r.bottom, grid_colour);
448 for (
int i = 0; i < (num_hori_lines + 1); i++) {
454 GfxFillRect(r.left, y, r.right + gridline_width - 1, y + gridline_width - 1, GRAPH_GRID_COLOUR);
459 GfxFillRect(r.left, r.top, r.left + gridline_width - 1, r.bottom + gridline_width - 1, GRAPH_AXIS_LINE_COLOUR);
462 y = x_axis_offset + r.top;
463 GfxFillRect(r.left, y, r.right + gridline_width - 1, y + gridline_width - 1, GRAPH_ZERO_LINE_COLOUR);
466 if (this->num_on_x_axis == 0)
return;
468 assert(this->num_on_x_axis > 0);
471 int64_t y_label = interval.
highest;
472 int64_t y_label_separation =
abs(interval.
highest - interval.
lowest) / num_hori_lines;
476 for (
int i = 0; i < (num_hori_lines + 1); i++) {
479 GetString(STR_GRAPH_Y_LABEL, this->format_str_y_axis, y_label),
483 GetString(STR_GRAPH_Y_LABEL, this->format_str_y_axis, y_label),
487 y_label -= y_label_separation;
491 x = rtl ? r.right : r.left;
495 x += (this->num_vert_lines - this->num_on_x_axis) * x_sep;
498 if (this->draw_dates) {
501 for (
int i = 0; i < this->num_on_x_axis; i++) {
504 GetString(month == 0 ? STR_GRAPH_X_LABEL_MONTH_YEAR : STR_GRAPH_X_LABEL_MONTH, STR_MONTH_ABBREV_JAN + month, year),
508 GetString(month == 0 ? STR_GRAPH_X_LABEL_MONTH_YEAR : STR_GRAPH_X_LABEL_MONTH, STR_MONTH_ABBREV_JAN + month, year),
518 GfxFillRect(x + x_sep, r.top + gridline_width, x + x_sep + gridline_width - 1, r.bottom - 1, GRAPH_YEAR_LINE_COLOUR);
526 if (this->x_values_reversed) {
527 label = this->x_values_increment * this->num_on_x_axis;
528 iterator = -this->x_values_increment;
530 label = this->x_values_increment;
531 iterator = this->x_values_increment;
534 for (
int i = 0; i < this->num_on_x_axis; i++) {
549 uint pointoffs1 = pointwidth / 2;
550 uint pointoffs2 = pointwidth - pointoffs1;
553 if (
HasBit(this->excluded_data, dataset.exclude_bit))
return;
554 if (
HasBit(this->excluded_range, dataset.range_bit))
return;
558 x = r.right + (x_sep / 2);
560 x = r.left + (x_sep / 2);
564 x += (this->num_vert_lines - this->num_on_x_axis) * x_sep;
566 uint prev_x = INVALID_DATAPOINT_POS;
567 uint prev_y = INVALID_DATAPOINT_POS;
571 if (datapoint != INVALID_DATAPOINT) {
583 int mult_range = FindLastBit<uint32_t>(x_axis_offset) + FindLastBit<uint64_t>(
abs(datapoint));
584 int reduce_range = std::max(mult_range - 31, 0);
588 datapoint = -(
abs(datapoint) >> reduce_range);
590 datapoint >>= reduce_range;
592 y = r.top + x_axis_offset - ((r.bottom - r.top) * datapoint) / (interval_size >> reduce_range);
595 GfxFillRect(x - pointoffs1, y - pointoffs1, x + pointoffs2, y + pointoffs2, colour);
598 if (prev_x != INVALID_DATAPOINT_POS) GfxDrawLine(prev_x, prev_y, x, y, colour, linewidth, dash);
603 prev_x = INVALID_DATAPOINT_POS;
604 prev_y = INVALID_DATAPOINT_POS;
612 for (
const DataSet &dataset : this->data) {
613 if (dataset.exclude_bit != this->highlight_data && dataset.range_bit != this->highlight_range) {
614 draw_dataset(dataset, dataset.colour);
620 if (this->highlight_state && (this->highlight_data != UINT8_MAX || this->highlight_range != UINT8_MAX)) {
621 for (
const DataSet &dataset : this->data) {
622 if (dataset.exclude_bit == this->highlight_data || dataset.range_bit == this->highlight_range) {
631 format_str_y_axis(format_str_y_axis)
638 if (this->highlight_data == UINT8_MAX && this->highlight_range == UINT8_MAX)
return;
648 for (
const StringID &str : labels) {
656 size.height *=
static_cast<uint
>(std::size(labels));
660 this->GetWidget<NWidgetCore>(widget)->SetMatrixDimension(1, ClampTo<uint32_t>(std::size(labels)));
668 this->UpdateMatrixSize(widget, size,
resize, this->ranges);
672 this->UpdateMatrixSize(widget, size,
resize, this->scales | std::views::transform(&GraphScale::label));
676 uint x_label_width = 0;
679 if (this->draw_dates) {
682 for (
int i = 0; i < this->num_on_x_axis; i++) {
683 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);
701 size.height = std::max<uint>(size.height, size.width / 3);
720 for (
const auto &str : this->ranges) {
721 bool lowered = !
HasBit(this->excluded_range, index) && !
HasBit(this->masked_range, index);
727 DrawString(text, str, (this->highlight_state && this->highlight_range == index) ? TC_WHITE : TC_BLACK,
SA_CENTER,
false,
FS_SMALL);
729 if (
HasBit(this->masked_range, index)) {
741 uint8_t selected_month_increment = this->scales[this->selected_scale].month_increment;
743 for (
const auto &
scale : this->scales) {
769 if (
HasBit(this->masked_range, row))
break;
778 const auto &
scale = this->scales[row];
779 if (this->selected_scale != row) {
780 this->selected_scale = row;
781 this->month_increment =
scale.month_increment;
782 this->x_values_increment =
scale.x_values_increment;
795 uint8_t new_highlight_range = UINT8_MAX;
798 if (!
HasBit(this->excluded_range, row)) new_highlight_range =
static_cast<uint8_t
>(row);
802 uint8_t new_highlight_data = UINT8_MAX;
804 auto dataset_index = this->GetDatasetIndex(pt.
y);
805 if (dataset_index.has_value() && !
HasBit(this->excluded_data, *dataset_index)) new_highlight_data = *dataset_index;
808 if (this->highlight_data == new_highlight_data && this->highlight_range == new_highlight_range)
return;
811 this->highlight_data = new_highlight_data;
812 this->highlight_range = new_highlight_range;
813 this->highlight_state =
true;
819 this->UpdateStatistics(
false);
827 void OnInvalidateData([[maybe_unused]]
int data = 0, [[maybe_unused]]
bool gui_scope =
true)
override
829 if (!gui_scope)
return;
830 this->UpdateStatistics(
true);
827 void OnInvalidateData([[maybe_unused]]
int data = 0, [[maybe_unused]]
bool gui_scope =
true)
override {
…}
833 virtual void UpdateStatistics(
bool initialize) = 0;
835 virtual std::optional<uint8_t> GetDatasetIndex(
int) {
return std::nullopt; }
861 CompanyMask excluded_companies = _legend_excluded_companies;
864 for (
CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
870 nums = std::min(this->num_vert_lines, std::max(nums, c->num_valid_stat_ent));
880 if (!initialize && this->excluded_data == excluded_companies.
base() && this->num_on_x_axis == nums &&
881 this->year == yr && this->month == mo) {
886 this->excluded_data = excluded_companies.
base();
887 this->num_on_x_axis = nums;
892 for (
CompanyID k = CompanyID::Begin(); k < MAX_COMPANIES; ++k) {
894 if (c ==
nullptr)
continue;
896 DataSet &dataset = this->data.emplace_back();
898 dataset.exclude_bit = k.base();
900 for (
int j = this->num_on_x_axis, i = 0; --j >= 0;) {
902 dataset.values[i] = INVALID_DATAPOINT;
906 dataset.values[i] = std::min(GetGraphData(c, j), INVALID_DATAPOINT - 1);
938static constexpr NWidgetPart _nested_operating_profit_widgets[] = {
950 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),
957 WDP_AUTO,
"graph_operating_profit", 0, 0,
960 _nested_operating_profit_widgets
964void ShowOperatingProfitGraph()
966 AllocateWindowDescFront<OperatingProfitGraphWindow>(_operating_profit_desc, 0);
991static constexpr NWidgetPart _nested_income_graph_widgets[] = {
1003 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),
1013 _nested_income_graph_widgets
1016void ShowIncomeGraph()
1018 AllocateWindowDescFront<IncomeGraphWindow>(_income_graph_desc, 0);
1042static constexpr NWidgetPart _nested_delivered_cargo_graph_widgets[] = {
1054 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),
1060static WindowDesc _delivered_cargo_graph_desc(
1061 WDP_AUTO,
"graph_delivered_cargo", 0, 0,
1064 _nested_delivered_cargo_graph_widgets
1067void ShowDeliveredCargoGraph()
1069 AllocateWindowDescFront<DeliveredCargoGraphWindow>(_delivered_cargo_graph_desc, 0);
1099static constexpr NWidgetPart _nested_performance_history_widgets[] = {
1112 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),
1119 WDP_AUTO,
"graph_performance", 0, 0,
1122 _nested_performance_history_widgets
1125void ShowPerformanceHistoryGraph()
1127 AllocateWindowDescFront<PerformanceHistoryGraphWindow>(_performance_history_desc, 0);
1151static constexpr NWidgetPart _nested_company_value_graph_widgets[] = {
1163 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),
1170 WDP_AUTO,
"graph_company_value", 0, 0,
1173 _nested_company_value_graph_widgets
1176void ShowCompanyValueGraph()
1178 AllocateWindowDescFront<CompanyValueGraphWindow>(_company_value_graph_desc, 0);
1209 virtual CargoTypes GetCargoTypes(
WindowNumber number)
const = 0;
1210 virtual CargoTypes &GetExcludedCargoTypes()
const = 0;
1212 std::optional<uint8_t> GetDatasetIndex(
int y)
override
1215 if (row >= this->vscroll->
GetCount())
return std::nullopt;
1219 if (row-- > 0)
continue;
1224 return std::nullopt;
1252 this->line_height = size.height;
1253 size.height = this->line_height * 11;
1275 if (pos-- > 0)
continue;
1276 if (--max < 0)
break;
1278 bool lowered = !
HasBit(this->excluded_data, cs->Index());
1289 if (this->highlight_data == cs->Index()) pc = this->highlight_state ?
PC_WHITE :
PC_BLACK;
1295 line = line.
Translate(0, this->line_height);
1304 this->GetExcludedCargoTypes() = {};
1305 this->excluded_data = this->GetExcludedCargoTypes();
1311 this->GetExcludedCargoTypes() = this->
cargo_types;
1312 this->excluded_data = this->GetExcludedCargoTypes();
1319 if (row >= this->vscroll->
GetCount())
return;
1325 if (row-- > 0)
continue;
1327 ToggleBit(this->GetExcludedCargoTypes(), cs->Index());
1328 this->excluded_data = this->GetExcludedCargoTypes();
1352 static inline CargoTypes excluded_cargo_types{};
1358 this->draw_dates =
false;
1360 this->x_values_reversed =
false;
1364 this->InitializeWindow(
window_number, STR_GRAPH_CARGO_PAYMENT_RATES_SECONDS, STR_GRAPH_CARGO_PAYMENT_RATES_DAYS);
1372 CargoTypes &GetExcludedCargoTypes()
const override
1374 return PaymentRatesGraphWindow::excluded_cargo_types;
1382 void OnInvalidateData([[maybe_unused]]
int data = 0, [[maybe_unused]]
bool gui_scope =
true)
override
1384 if (!gui_scope)
return;
1382 void OnInvalidateData([[maybe_unused]]
int data = 0, [[maybe_unused]]
bool gui_scope =
true)
override {
…}
1393 void UpdateStatistics(
bool)
override {}
1400 this->excluded_data = this->GetExcludedCargoTypes();
1404 DataSet &dataset = this->data.emplace_back();
1405 dataset.colour = cs->legend_colour;
1406 dataset.exclude_bit = cs->Index();
1408 for (uint j = 0; j != this->num_on_x_axis; j++) {
1409 dataset.values[j] = GetTransportedGoodsIncome(10, 20, j * 4 + 4, cs->Index());
1415static constexpr NWidgetPart _nested_cargo_payment_rates_widgets[] = {
1424 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),
1433 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),
1441 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),
1448 WDP_AUTO,
"graph_cargo_payment_rates", 0, 0,
1451 _nested_cargo_payment_rates_widgets
1455void ShowCargoPaymentRates()
1457 AllocateWindowDescFront<PaymentRatesGraphWindow>(_cargo_payment_rates_desc, 0);
1467 uint score_info_left = 0;
1468 uint score_info_right = 0;
1472 uint bar_height = 0;
1473 uint score_detail_left = 0;
1474 uint score_detail_right = 0;
1478 this->UpdateCompanyStats();
1484 void UpdateCompanyStats()
1502 uint score_info_width = 0;
1503 for (uint i = SCORE_BEGIN; i <
SCORE_END; i++) {
1516 int max = -(999999999 - 500);
1537 this->score_info_left = rtl ? right - score_info_width :
left;
1538 this->score_info_right = rtl ? right :
left + score_info_width;
1540 this->score_detail_left = rtl ?
left : right - score_detail_width;
1541 this->score_detail_right = rtl ?
left + score_detail_width : right;
1544 this->bar_right = this->bar_left + this->bar_width - 1;
1552 if (this->company == CompanyID::Invalid())
return;
1571 int64_t val = _score_part[company][score_type];
1581 uint bar_top =
CentreBounds(r.top, r.bottom, this->bar_height);
1584 DrawString(this->score_info_left, this->score_info_right, text_top, STR_PERFORMANCE_DETAIL_VEHICLES + score_type);
1590 uint x = Clamp<int64_t>(val, 0, needed) * this->bar_width / needed;
1593 x = this->bar_right - x;
1595 x = this->bar_left + x;
1599 if (x != this->bar_left)
GfxFillRect(this->bar_left, bar_top, x, bar_top + this->bar_height - 1, rtl ? colour_notdone : colour_done);
1600 if (x != this->bar_right)
GfxFillRect(x, bar_top, this->bar_right, bar_top + this->bar_height - 1, rtl ? colour_done : colour_notdone);
1603 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);
1606 if (score_type == SCORE_LOAN) val = needed - val;
1610 switch (score_type) {
1611 case SCORE_MIN_PROFIT:
1612 case SCORE_MIN_INCOME:
1613 case SCORE_MAX_INCOME:
1616 DrawString(this->score_detail_left, this->score_detail_right, text_top,
GetString(STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY, val, needed));
1619 DrawString(this->score_detail_left, this->score_detail_right, text_top,
GetString(STR_PERFORMANCE_DETAIL_AMOUNT_INT, val, needed));
1641 if (--this->timeout == 0) {
1642 this->UpdateCompanyStats();
1652 void OnInvalidateData([[maybe_unused]]
int data = 0, [[maybe_unused]]
bool gui_scope =
true)
override
1654 if (!gui_scope)
return;
1656 for (
CompanyID i = CompanyID::Begin(); i < MAX_COMPANIES; ++i) {
1664 this->company = CompanyID::Invalid();
1667 if (this->company == CompanyID::Invalid()) {
1669 this->company = c->index;
1675 if (this->company != CompanyID::Invalid()) {
1652 void OnInvalidateData([[maybe_unused]]
int data = 0, [[maybe_unused]]
bool gui_scope =
true)
override {
…}
1681CompanyID PerformanceRatingDetailWindow::company = CompanyID::Invalid();
1688 static inline constexpr StringID RANGE_LABELS[] = {
1689 STR_GRAPH_INDUSTRY_RANGE_PRODUCED,
1690 STR_GRAPH_INDUSTRY_RANGE_TRANSPORTED,
1691 STR_GRAPH_INDUSTRY_RANGE_DELIVERED,
1692 STR_GRAPH_INDUSTRY_RANGE_WAITING,
1695 static inline CargoTypes excluded_cargo_types{};
1702 this->month_increment = 1;
1705 this->ranges = RANGE_LABELS;
1708 if (!i->
IsCargoProduced()) this->masked_range = (1U << 0) | (1U << 1);
1709 if (!i->
IsCargoAccepted()) this->masked_range = (1U << 2) | (1U << 3);
1725 for (
const auto &a : i->accepted) {
1728 for (
const auto &p : i->produced) {
1734 CargoTypes &GetExcludedCargoTypes()
const override
1736 return IndustryProductionGraphWindow::excluded_cargo_types;
1746 void UpdateStatistics(
bool initialize)
override
1755 if (!initialize && this->excluded_data == this->GetExcludedCargoTypes() && this->num_on_x_axis == this->num_vert_lines && this->year == yr && this->month == mo) {
1760 this->excluded_data = this->GetExcludedCargoTypes();
1767 for (
const auto &p : i->produced) {
1771 this->data.reserve(this->data.size() + 2);
1773 DataSet &produced = this->data.emplace_back();
1774 produced.colour = cs->legend_colour;
1775 produced.exclude_bit = cs->
Index();
1776 produced.range_bit = 0;
1778 DataSet &transported = this->data.emplace_back();
1779 transported.colour = cs->legend_colour;
1780 transported.exclude_bit = cs->
Index();
1781 transported.range_bit = 1;
1782 transported.dash = 2;
1784 FillFromHistory<GRAPH_NUM_MONTHS>(p.history, i->
valid_history, *this->scales[this->selected_scale].history_range,
1789 for (
const auto &a : i->accepted) {
1793 this->data.reserve(this->data.size() + 2);
1795 DataSet &accepted = this->data.emplace_back();
1796 accepted.colour = cs->legend_colour;
1797 accepted.exclude_bit = cs->
Index();
1798 accepted.range_bit = 2;
1801 DataSet &waiting = this->data.emplace_back();
1802 waiting.colour = cs->legend_colour;
1803 waiting.exclude_bit = cs->
Index();
1804 waiting.range_bit = 3;
1807 FillFromHistory<GRAPH_NUM_MONTHS>(a.history.get(), i->
valid_history, *this->scales[this->selected_scale].history_range,
1808 Filler{{accepted}, &Industry::AcceptedHistory::accepted},
1816static constexpr NWidgetPart _nested_industry_production_widgets[] = {
1829 NWidget(
WWT_MATRIX, COLOUR_BROWN,
WID_GRAPH_RANGE_MATRIX),
SetFill(1, 0),
SetResize(0, 0),
SetMatrixDataTip(1, 0, STR_GRAPH_TOGGLE_RANGE),
1835 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),
1839 NWidget(
WWT_MATRIX, COLOUR_BROWN,
WID_GRAPH_SCALE_MATRIX),
SetFill(1, 0),
SetResize(0, 0),
SetMatrixDataTip(1, 0, STR_GRAPH_SELECT_SCALE),
1845 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),
1852 WDP_AUTO,
"graph_industry_production", 0, 0,
1855 _nested_industry_production_widgets
1858void ShowIndustryProductionGraph(
WindowNumber window_number)
1860 AllocateWindowDescFront<IndustryProductionGraphWindow>(_industry_production_desc, window_number);
1864 static inline constexpr StringID RANGE_LABELS[] = {
1865 STR_GRAPH_TOWN_RANGE_PRODUCED,
1866 STR_GRAPH_TOWN_RANGE_TRANSPORTED,
1869 static inline CargoTypes excluded_cargo_types{};
1875 this->month_increment = 1;
1876 this->x_values_reversed =
true;
1879 this->ranges = RANGE_LABELS;
1895 for (
const auto &s : t->supplied) {
1901 CargoTypes &GetExcludedCargoTypes()
const override
1903 return TownCargoGraphWindow::excluded_cargo_types;
1913 void UpdateStatistics(
bool initialize)
override
1922 if (!initialize && this->excluded_data == this->GetExcludedCargoTypes() && this->num_on_x_axis == this->num_vert_lines && this->year == yr && this->month == mo) {
1927 this->excluded_data = this->GetExcludedCargoTypes();
1934 for (
const auto &s : t->supplied) {
1938 this->data.reserve(this->data.size() + 2);
1940 DataSet &produced = this->data.emplace_back();
1941 produced.colour = cs->legend_colour;
1942 produced.exclude_bit = cs->
Index();
1943 produced.range_bit = 0;
1945 DataSet &transported = this->data.emplace_back();
1946 transported.colour = cs->legend_colour;
1947 transported.exclude_bit = cs->
Index();
1948 transported.range_bit = 1;
1949 transported.dash = 2;
1951 FillFromHistory<GRAPH_NUM_MONTHS>(s.history, t->
valid_history, *this->scales[this->selected_scale].history_range,
1960static constexpr NWidgetPart _nested_town_cargo_graph_widgets[] = {
1973 NWidget(
WWT_MATRIX, COLOUR_BROWN,
WID_GRAPH_RANGE_MATRIX),
SetFill(1, 0),
SetResize(0, 0),
SetMatrixDataTip(1, 0, STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO),
1979 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),
1983 NWidget(
WWT_MATRIX, COLOUR_BROWN,
WID_GRAPH_SCALE_MATRIX),
SetFill(1, 0),
SetResize(0, 0),
SetMatrixDataTip(1, 0, STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO),
1989 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),
1996 WDP_AUTO,
"graph_town_cargo", 0, 0,
1999 _nested_town_cargo_graph_widgets
2004 AllocateWindowDescFront<TownCargoGraphWindow>(_town_cargo_graph_desc, window_number);
2014 const StringID performance_tips[] = {
2015 realtime ? STR_PERFORMANCE_DETAIL_VEHICLES_TOOLTIP_PERIODS : STR_PERFORMANCE_DETAIL_VEHICLES_TOOLTIP_YEARS,
2016 STR_PERFORMANCE_DETAIL_STATIONS_TOOLTIP,
2017 realtime ? STR_PERFORMANCE_DETAIL_MIN_PROFIT_TOOLTIP_PERIODS : STR_PERFORMANCE_DETAIL_MIN_PROFIT_TOOLTIP_YEARS,
2018 STR_PERFORMANCE_DETAIL_MIN_INCOME_TOOLTIP,
2019 STR_PERFORMANCE_DETAIL_MAX_INCOME_TOOLTIP,
2020 STR_PERFORMANCE_DETAIL_DELIVERED_TOOLTIP,
2021 STR_PERFORMANCE_DETAIL_CARGO_TOOLTIP,
2022 STR_PERFORMANCE_DETAIL_MONEY_TOOLTIP,
2023 STR_PERFORMANCE_DETAIL_LOAN_TOOLTIP,
2024 STR_PERFORMANCE_DETAIL_TOTAL_TOOLTIP,
2031 auto panel = std::make_unique<NWidgetBackground>(
WWT_PANEL, COLOUR_BROWN, widnum);
2032 panel->SetFill(1, 1);
2034 vert->Add(std::move(panel));
2045static constexpr NWidgetPart _nested_performance_rating_detail_widgets[] = {
2058static WindowDesc _performance_rating_detail_desc(
2062 _nested_performance_rating_detail_widgets
2065void ShowPerformanceRatingDetail()
2067 AllocateWindowDescFront<PerformanceRatingDetailWindow>(_performance_rating_detail_desc, 0);
2070void InitializeGraphGui()
2073 PaymentRatesGraphWindow::excluded_cargo_types = {};
2074 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.
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...
void GfxFillRect(int left, int top, int right, int bottom, const std::variant< PixelColour, PaletteID > &colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen.
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...
@ FILLRECT_CHECKER
Draw only every second pixel, used for greying-out.
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.
PixelColour GetColourGradient(Colours colour, ColourShade shade)
Get colour gradient palette index.
constexpr PixelColour GREY_SCALE(uint8_t level)
Return the colour for a particular greyscale level.
static constexpr PixelColour PC_BLACK
Black palette colour.
static constexpr PixelColour PC_WHITE
White palette colour.
A number of safeguards to prevent using unsafe methods.
ClientSettings _settings_client
The current settings for this game.
void SndClickBeep()
Play a beep sound for a click event if enabled in settings.
Functions related to sound.
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.
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 datasets hidden by the player.
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 hidden by the player.
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".
static const int ECONOMY_YEAR_MINUTES
Minutes per economic year.
ValuesInterval GetValuesInterval(int num_hori_lines) const
Get the interval that contains the graph's data.
uint64_t masked_range
bitmask of ranges that are not available for the current 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.
void OnInit() override
Notification that the nested widget tree gets initialized.
uint16_t waiting
Total accepted.
uint16_t transported
Total transported.
uint16_t production
Total produced.
Defines the internal data of a functional industry.
bool IsCargoAccepted() const
Test if this industry accepts any cargo.
ValidHistoryMask valid_history
Mask of valid history records.
bool IsCargoProduced() const
Test if this industry produces any cargo.
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.
Colour for pixel/line drawing.
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.
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
void OnInit() override
Notification that the nested widget tree gets initialized.
uint32_t transported
Total transported.
uint32_t production
Total produced.
ValidHistoryMask valid_history
Mask of valid history records.
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.
int scale
Scale of this window – used to determine how to resize.
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_TOWN_VIEW
Town view; 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:
@ WC_TOWN_CARGO_GRAPH
Town cargo history graph; Window numbers:
Functions related to zooming.
@ Normal
The normal zoom level.