OpenTTD Source 20260421-master-gc2fbc6fdeb
company_gui.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
10#include "stdafx.h"
11#include "currency.h"
12#include "error.h"
13#include "gui.h"
14#include "settings_gui.h"
15#include "window_gui.h"
16#include "textbuf_gui.h"
17#include "viewport_func.h"
18#include "company_func.h"
19#include "command_func.h"
20#include "network/network.h"
21#include "network/network_gui.h"
23#include "newgrf.h"
25#include "strings_func.h"
27#include "dropdown_type.h"
28#include "tilehighlight_func.h"
29#include "company_base.h"
31#include "object_type.h"
32#include "rail.h"
33#include "road.h"
34#include "engine_base.h"
35#include "window_func.h"
36#include "road_func.h"
37#include "water.h"
38#include "station_func.h"
39#include "zoom_func.h"
40#include "sortlist_type.h"
41#include "company_cmd.h"
42#include "economy_cmd.h"
43#include "group_cmd.h"
44#include "group_gui.h"
45#include "misc_cmd.h"
46#include "object_cmd.h"
47#include "timer/timer.h"
48#include "timer/timer_window.h"
50
52
53#include "table/strings.h"
54
56
57#include "safeguards.h"
58
59
61static void DoSelectCompanyManagerFace(Window *parent);
62static void ShowCompanyInfrastructure(CompanyID company);
63
65static const std::initializer_list<ExpensesType> _expenses_list_revenue = {
70};
71
81
83static const std::initializer_list<ExpensesType> _expenses_list_capital_costs = {
87};
88
90struct ExpensesList {
92 const std::initializer_list<ExpensesType> &items;
93
94 ExpensesList(StringID title, const std::initializer_list<ExpensesType> &list) : title(title), items(list)
95 {
96 }
97
98 uint GetHeight() const
99 {
100 /* Add up the height of all the lines. */
101 return static_cast<uint>(this->items.size()) * GetCharacterHeight(FontSize::Normal);
102 }
103
108 uint GetListWidth() const
109 {
110 uint width = 0;
111 for (const ExpensesType &et : this->items) {
112 width = std::max(width, GetStringBoundingBox(STR_FINANCES_SECTION_CONSTRUCTION + et).width);
113 }
114 return width;
115 }
116};
117
119static const std::initializer_list<ExpensesList> _expenses_list_types = {
120 { STR_FINANCES_REVENUE_TITLE, _expenses_list_revenue },
121 { STR_FINANCES_OPERATING_EXPENSES_TITLE, _expenses_list_operating_costs },
122 { STR_FINANCES_CAPITAL_EXPENSES_TITLE, _expenses_list_capital_costs },
123};
124
130{
131 /* There's an empty line and blockspace on the year row */
132 uint total_height = GetCharacterHeight(FontSize::Normal) + WidgetDimensions::scaled.vsep_wide;
133
134 for (const ExpensesList &list : _expenses_list_types) {
135 /* Title + expense list + total line + total + blockspace after category */
137 }
138
139 /* Total income */
141
142 return total_height;
143}
144
150{
151 uint max_width = GetStringBoundingBox(TimerGameEconomy::UsingWallclockUnits() ? STR_FINANCES_PERIOD_CAPTION : STR_FINANCES_YEAR_CAPTION).width;
152
153 /* Loop through categories to check max widths. */
154 for (const ExpensesList &list : _expenses_list_types) {
155 /* Title of category */
156 max_width = std::max(max_width, GetStringBoundingBox(list.title).width);
157 /* Entries in category */
158 max_width = std::max(max_width, list.GetListWidth() + WidgetDimensions::scaled.hsep_indent);
159 }
160
161 return max_width;
162}
163
170static void DrawCategory(const Rect &r, int start_y, const ExpensesList &list)
171{
173
174 tr.top = start_y;
175
176 for (const ExpensesType &et : list.items) {
177 DrawString(tr, STR_FINANCES_SECTION_CONSTRUCTION + et);
179 }
180}
181
187static void DrawCategories(const Rect &r)
188{
189 int y = r.top;
190 /* Draw description of 12-minute economic period. */
191 DrawString(r.left, r.right, y, (TimerGameEconomy::UsingWallclockUnits() ? STR_FINANCES_PERIOD_CAPTION : STR_FINANCES_YEAR_CAPTION), TC_FROMSTRING, SA_LEFT, true);
193
194 for (const ExpensesList &list : _expenses_list_types) {
195 /* Draw category title and advance y */
196 DrawString(r.left, r.right, y, list.title, TC_FROMSTRING, SA_LEFT);
198
199 /* Draw category items and advance y */
200 DrawCategory(r, y, list);
201 y += list.GetHeight();
202
203 /* Advance y by the height of the horizontal line between amounts and subtotal */
204 y += WidgetDimensions::scaled.vsep_normal;
205
206 /* Draw category total and advance y */
207 DrawString(r.left, r.right, y, STR_FINANCES_TOTAL_CAPTION, TC_FROMSTRING, SA_RIGHT);
209
210 /* Advance y by a blockspace after this category block */
211 y += WidgetDimensions::scaled.vsep_wide;
212 }
213
214 /* Draw total profit/loss */
215 y += WidgetDimensions::scaled.vsep_normal;
216 DrawString(r.left, r.right, y, STR_FINANCES_PROFIT, TC_FROMSTRING, SA_LEFT);
217}
218
227static void DrawPrice(Money amount, int left, int right, int top, TextColour colour)
228{
229 StringID str = STR_FINANCES_NEGATIVE_INCOME;
230 if (amount == 0) {
231 str = STR_FINANCES_ZERO_INCOME;
232 } else if (amount < 0) {
233 amount = -amount;
234 str = STR_FINANCES_POSITIVE_INCOME;
235 }
236 DrawString(left, right, top, GetString(str, amount), colour, SA_RIGHT | SA_FORCE);
237}
238
247static Money DrawYearCategory(const Rect &r, int start_y, const ExpensesList &list, const Expenses &tbl)
248{
249 int y = start_y;
250 Money sum = 0;
251
252 for (const ExpensesType &et : list.items) {
253 Money cost = tbl[et];
254 sum += cost;
255 if (cost != 0) DrawPrice(cost, r.left, r.right, y, TC_BLACK);
257 }
258
259 /* Draw the total at the bottom of the category. */
260 GfxFillRect(r.left, y, r.right, y + WidgetDimensions::scaled.bevel.top - 1, PC_BLACK);
261 y += WidgetDimensions::scaled.vsep_normal;
262 if (sum != 0) DrawPrice(sum, r.left, r.right, y, TC_WHITE);
263
264 /* Return the sum for the yearly total. */
265 return sum;
266}
267
268
276static void DrawYearColumn(const Rect &r, TimerGameEconomy::Year year, const Expenses &tbl)
277{
278 int y = r.top;
279 Money sum;
280
281 /* Year header */
282 DrawString(r.left, r.right, y, GetString(STR_FINANCES_YEAR, year), TC_FROMSTRING, SA_RIGHT | SA_FORCE, true);
284
285 /* Categories */
286 for (const ExpensesList &list : _expenses_list_types) {
288 sum += DrawYearCategory(r, y, list, tbl);
289 /* Expense list + expense category title + expense category total + blockspace after category */
290 y += list.GetHeight() + WidgetDimensions::scaled.vsep_normal + GetCharacterHeight(FontSize::Normal) + WidgetDimensions::scaled.vsep_wide;
291 }
292
293 /* Total income. */
294 GfxFillRect(r.left, y, r.right, y + WidgetDimensions::scaled.bevel.top - 1, PC_BLACK);
295 y += WidgetDimensions::scaled.vsep_normal;
296 DrawPrice(sum, r.left, r.right, y, TC_WHITE);
297}
298
299static constexpr std::initializer_list<NWidgetPart> _nested_company_finances_widgets = {
303 NWidget(WWT_IMGBTN, Colours::Grey, WID_CF_TOGGLE_SIZE), SetSpriteTip(SPR_LARGE_SMALL_WINDOW, STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW), SetAspect(WidgetDimensions::ASPECT_TOGGLE_SIZE),
306 EndContainer(),
314 EndContainer(),
315 EndContainer(),
316 EndContainer(),
319 NWidget(NWID_VERTICAL), // Vertical column with 'bank balance', 'loan'
320 NWidget(WWT_TEXT, Colours::Invalid), SetStringTip(STR_FINANCES_OWN_FUNDS_TITLE),
321 NWidget(WWT_TEXT, Colours::Invalid), SetStringTip(STR_FINANCES_LOAN_TITLE),
322 NWidget(WWT_TEXT, Colours::Invalid), SetStringTip(STR_FINANCES_BANK_BALANCE_TITLE), SetPadding(WidgetDimensions::unscaled.vsep_normal, 0, 0, 0),
323 EndContainer(),
324 NWidget(NWID_VERTICAL), // Vertical column with bank balance amount, loan amount, and total.
329 EndContainer(),
331 NWidget(NWID_VERTICAL), SetPIPRatio(0, 0, 1), // Max loan information
334 EndContainer(),
335 EndContainer(),
336 EndContainer(),
337 EndContainer(),
340 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_CF_INCREASE_LOAN), SetFill(1, 0), SetToolTip(STR_FINANCES_BORROW_TOOLTIP),
341 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_CF_REPAY_LOAN), SetFill(1, 0), SetToolTip(STR_FINANCES_REPAY_TOOLTIP),
342 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_CF_INFRASTRUCTURE), SetFill(1, 0), SetStringTip(STR_FINANCES_INFRASTRUCTURE_BUTTON, STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP),
343 EndContainer(),
344 EndContainer(),
345};
346
348struct CompanyFinancesWindow : Window {
349 static constexpr int NUM_PERIODS = WID_CF_EXPS_PRICE3 - WID_CF_EXPS_PRICE1 + 1;
350
351 static Money max_money;
352 bool small = false;
353 uint8_t first_visible = NUM_PERIODS - 1;
354
355 CompanyFinancesWindow(WindowDesc &desc, CompanyID company) : Window(desc)
356 {
357 this->CreateNestedTree();
358 this->SetupWidgets();
359 this->FinishInitNested(company);
360
361 this->owner = this->window_number;
362 this->InvalidateData();
363 }
364
365 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
366 {
367 switch (widget) {
368 case WID_CF_CAPTION:
369 return GetString(STR_FINANCES_CAPTION, this->window_number, this->window_number);
370
372 const Company *c = Company::Get(this->window_number);
373 return GetString(STR_FINANCES_BANK_BALANCE, c->money);
374 }
375
376 case WID_CF_LOAN_VALUE: {
377 const Company *c = Company::Get(this->window_number);
378 return GetString(STR_FINANCES_TOTAL_CURRENCY, c->current_loan);
379 }
380
381 case WID_CF_OWN_VALUE: {
382 const Company *c = Company::Get(this->window_number);
383 return GetString(STR_FINANCES_TOTAL_CURRENCY, c->money - c->current_loan);
384 }
385
387 return GetString(STR_FINANCES_INTEREST_RATE, _settings_game.difficulty.initial_interest);
388
390 const Company *c = Company::Get(this->window_number);
391 return GetString(STR_FINANCES_MAX_LOAN, c->GetMaxLoan());
392 }
393
395 return GetString(STR_FINANCES_BORROW_BUTTON, LOAN_INTERVAL);
396
398 return GetString(STR_FINANCES_REPAY_BUTTON, LOAN_INTERVAL);
399
400 default:
401 return this->Window::GetWidgetString(widget, stringid);
402 }
403 }
404
405 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
406 {
407 switch (widget) {
409 size.width = GetMaxCategoriesWidth();
410 size.height = GetTotalCategoriesHeight();
411 break;
412
416 size.height = GetTotalCategoriesHeight();
417 [[fallthrough]];
418
421 case WID_CF_OWN_VALUE: {
423 size.width = std::max(GetStringBoundingBox(GetString(STR_FINANCES_NEGATIVE_INCOME, max_value)).width, GetStringBoundingBox(GetString(STR_FINANCES_POSITIVE_INCOME, max_value)).width);
424 size.width += padding.width;
425 break;
426 }
427
430 break;
431 }
432 }
433
434 void DrawWidget(const Rect &r, WidgetID widget) const override
435 {
436 switch (widget) {
439 break;
440
443 case WID_CF_EXPS_PRICE3: {
444 int period = widget - WID_CF_EXPS_PRICE1;
445 if (period < this->first_visible) break;
446
447 const Company *c = Company::Get(this->window_number);
448 const auto &expenses = c->yearly_expenses[NUM_PERIODS - period - 1];
449 DrawYearColumn(r, TimerGameEconomy::year - (NUM_PERIODS - period - 1), expenses);
450 break;
451 }
452
454 GfxFillRect(r.left, r.top, r.right, r.top + WidgetDimensions::scaled.bevel.top - 1, PC_BLACK);
455 break;
456 }
457 }
458
464 {
465 int plane = this->small ? SZSP_NONE : 0;
466 this->GetWidget<NWidgetStacked>(WID_CF_SEL_PANEL)->SetDisplayedPlane(plane);
467 this->GetWidget<NWidgetStacked>(WID_CF_SEL_MAXLOAN)->SetDisplayedPlane(plane);
468
469 CompanyID company = this->window_number;
470 plane = (company != _local_company) ? SZSP_NONE : 0;
471 this->GetWidget<NWidgetStacked>(WID_CF_SEL_BUTTONS)->SetDisplayedPlane(plane);
472 }
473
474 void OnPaint() override
475 {
476 if (!this->IsShaded()) {
477 if (!this->small) {
478 /* Check that the expenses panel height matches the height needed for the layout. */
480 this->SetupWidgets();
481 this->ReInit();
482 return;
483 }
484 }
485
486 /* Check that the loan buttons are shown only when the user owns the company. */
487 CompanyID company = this->window_number;
488 int req_plane = (company != _local_company) ? SZSP_NONE : 0;
489 if (req_plane != this->GetWidget<NWidgetStacked>(WID_CF_SEL_BUTTONS)->shown_plane) {
490 this->SetupWidgets();
491 this->ReInit();
492 return;
493 }
494
495 const Company *c = Company::Get(company);
496 this->SetWidgetDisabledState(WID_CF_INCREASE_LOAN, c->current_loan >= c->GetMaxLoan()); // Borrow button only shows when there is any more money to loan.
497 this->SetWidgetDisabledState(WID_CF_REPAY_LOAN, company != _local_company || c->current_loan == 0); // Repay button only shows when there is any more money to repay.
498 }
499
500 this->DrawWidgets();
501 }
502
503 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
504 {
505 switch (widget) {
506 case WID_CF_TOGGLE_SIZE: // toggle size
507 this->small = !this->small;
508 this->SetupWidgets();
509 if (this->IsShaded()) {
510 /* Finances window is not resizable, so size hints given during unshading have no effect
511 * on the changed appearance of the window. */
512 this->SetShaded(false);
513 } else {
514 this->ReInit();
515 }
516 break;
517
518 case WID_CF_INCREASE_LOAN: // increase loan
519 Command<Commands::IncreaseLoan>::Post(STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY, _ctrl_pressed ? LoanCommand::Max : LoanCommand::Interval, 0);
520 break;
521
522 case WID_CF_REPAY_LOAN: // repay loan
523 Command<Commands::DecreaseLoan>::Post(STR_ERROR_CAN_T_REPAY_LOAN, _ctrl_pressed ? LoanCommand::Max : LoanCommand::Interval, 0);
524 break;
525
526 case WID_CF_INFRASTRUCTURE: // show infrastructure details
528 break;
529 }
530 }
531
532 void RefreshVisibleColumns()
533 {
534 for (uint period = 0; period < this->first_visible; ++period) {
535 const Company *c = Company::Get(this->window_number);
536 const Expenses &expenses = c->yearly_expenses[NUM_PERIODS - period - 1];
537 /* Show expenses column if it has any non-zero value in it. */
538 if (std::ranges::any_of(expenses, [](const Money &value) { return value != 0; })) {
539 this->first_visible = period;
540 break;
541 }
542 }
543 }
544
545 void OnInvalidateData(int, bool) override
546 {
547 this->RefreshVisibleColumns();
548 }
549
554 const IntervalTimer<TimerWindow> rescale_interval = {std::chrono::seconds(3), [this](auto) {
555 const Company *c = Company::Get(this->window_number);
558 this->SetupWidgets();
559 this->ReInit();
560 }
561 }};
562};
563
565Money CompanyFinancesWindow::max_money = INT32_MAX;
566
567static WindowDesc _company_finances_desc(
568 WDP_AUTO, "company_finances", 0, 0,
570 {},
571 _nested_company_finances_widgets
572);
573
579void ShowCompanyFinances(CompanyID company)
580{
581 if (!Company::IsValidID(company)) return;
582 if (BringWindowToFrontById(WC_FINANCES, company)) return;
583
584 new CompanyFinancesWindow(_company_finances_desc, company);
585}
586
588static const LiveryClass _livery_class[LS_END] = {
589 LC_OTHER,
590 LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL,
591 LC_ROAD, LC_ROAD,
592 LC_SHIP, LC_SHIP,
593 LC_AIRCRAFT, LC_AIRCRAFT, LC_AIRCRAFT,
594 LC_ROAD, LC_ROAD,
595};
596
601template <SpriteID TSprite = SPR_SQUARE>
602class DropDownListColourItem : public DropDownIcon<DropDownString<DropDownListItem>> {
603public:
604 DropDownListColourItem(int colour, bool masked) :
605 DropDownIcon<DropDownString<DropDownListItem>>(TSprite, GetColourPalette(static_cast<Colours>(colour % to_underlying(Colours::End))), GetString(colour < to_underlying(Colours::End) ? (STR_COLOUR_DARK_BLUE + colour) : STR_COLOUR_DEFAULT), colour, masked)
606
607 {
608 }
609};
610
617constexpr uint8_t GetColourOffset(const Livery &l, bool primary)
618{
619 return to_underlying(primary ? l.colour1 : l.colour2);
620}
621
623struct SelectCompanyLiveryWindow : public Window {
624private:
625 uint32_t sel = 0;
626 LiveryClass livery_class{};
627 Dimension square{};
628 uint rows = 0;
629 uint line_height = 0;
630 GUIGroupList groups{};
631 Scrollbar *vscroll = nullptr;
632
633 void ShowColourDropDownMenu(uint32_t widget)
634 {
636 const Livery *livery, *default_livery = nullptr;
637 bool primary = widget == WID_SCL_PRI_COL_DROPDOWN;
638 uint8_t default_col{};
639
640 /* Disallow other company colours for the primary colour */
641 if (this->livery_class < LC_GROUP_RAIL && HasBit(this->sel, LS_DEFAULT) && primary) {
642 for (const Company *c : Company::Iterate()) {
643 if (c->index != _local_company) used_colours.Set(c->colour);
644 }
645 }
646
647 const Company *c = Company::Get(this->window_number);
648
649 if (this->livery_class < LC_GROUP_RAIL) {
650 /* Get the first selected livery to use as the default dropdown item */
651 LiveryScheme scheme;
652 for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
653 if (HasBit(this->sel, scheme)) break;
654 }
655 if (scheme == LS_END) scheme = LS_DEFAULT;
656 livery = &c->livery[scheme];
657 if (scheme != LS_DEFAULT) default_livery = &c->livery[LS_DEFAULT];
658 } else {
659 const Group *g = Group::Get(this->sel);
660 livery = &g->livery;
661 if (g->parent == GroupID::Invalid()) {
662 default_livery = &c->livery[LS_DEFAULT];
663 } else {
664 const Group *pg = Group::Get(g->parent);
665 default_livery = &pg->livery;
666 }
667 }
668
669 DropDownList list;
670 if (default_livery != nullptr) {
671 /* Add Colours::End to put the colour out of range, but also allow us to show what the default is */
672 default_col = GetColourOffset(*default_livery, primary) + to_underlying(Colours::End);
673 list.push_back(std::make_unique<DropDownListColourItem<>>(default_col, false));
674 }
675 for (Colours colour = Colours::Begin; colour != Colours::End; colour++) {
676 list.push_back(std::make_unique<DropDownListColourItem<>>(to_underlying(colour), used_colours.Test(colour)));
677 }
678
679 uint8_t sel;
680 if (default_livery == nullptr || livery->in_use.Test(primary ? Livery::Flag::Primary : Livery::Flag::Secondary)) {
681 sel = GetColourOffset(*livery, primary);
682 } else {
683 sel = default_col;
684 }
685 ShowDropDownList(this, std::move(list), sel, widget);
686 }
687
688 void BuildGroupList(CompanyID owner)
689 {
690 if (!this->groups.NeedRebuild()) return;
691
692 this->groups.clear();
693
694 if (this->livery_class >= LC_GROUP_RAIL) {
695 VehicleType vtype = (VehicleType)(this->livery_class - LC_GROUP_RAIL);
696 BuildGuiGroupList(this->groups, false, owner, vtype);
697 }
698
699 this->groups.RebuildDone();
700 }
701
702 void SetRows()
703 {
704 if (this->livery_class < LC_GROUP_RAIL) {
705 this->rows = 0;
706 for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
707 if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
708 this->rows++;
709 }
710 }
711 } else {
712 this->rows = (uint)this->groups.size();
713 }
714
715 this->vscroll->SetCount(this->rows);
716 }
717
718public:
719 SelectCompanyLiveryWindow(WindowDesc &desc, CompanyID company, GroupID group) : Window(desc)
720 {
721 this->CreateNestedTree();
723 this->vscroll = this->GetScrollbar(WID_SCL_MATRIX_SCROLLBAR);
724
725 if (group == GroupID::Invalid()) {
726 this->livery_class = LC_OTHER;
727 this->sel = 1;
729 this->BuildGroupList(company);
730 this->SetRows();
731 } else {
732 this->SetSelectedGroup(company, group);
733 }
734
735 this->FinishInitNested(company);
736 this->owner = company;
737 this->InvalidateData(1);
738 }
739
740 void SetSelectedGroup(CompanyID company, GroupID group)
741 {
742 this->RaiseWidget(WID_SCL_CLASS_GENERAL + this->livery_class);
743 const Group *g = Group::Get(group);
744 switch (g->vehicle_type) {
745 case VEH_TRAIN: this->livery_class = LC_GROUP_RAIL; break;
746 case VEH_ROAD: this->livery_class = LC_GROUP_ROAD; break;
747 case VEH_SHIP: this->livery_class = LC_GROUP_SHIP; break;
748 case VEH_AIRCRAFT: this->livery_class = LC_GROUP_AIRCRAFT; break;
749 default: NOT_REACHED();
750 }
751 this->sel = group.base();
752 this->LowerWidget(WID_SCL_CLASS_GENERAL + this->livery_class);
753
754 this->groups.ForceRebuild();
755 this->BuildGroupList(company);
756 this->SetRows();
757
758 /* Position scrollbar to selected group */
759 for (uint i = 0; i < this->rows; i++) {
760 if (this->groups[i].group->index == sel) {
761 this->vscroll->SetPosition(i - this->vscroll->GetCapacity() / 2);
762 break;
763 }
764 }
765 }
766
767 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
768 {
769 switch (widget) {
771 /* The matrix widget below needs enough room to print all the schemes. */
772 Dimension d = {0, 0};
773 for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
774 d = maxdim(d, GetStringBoundingBox(STR_LIVERY_DEFAULT + scheme));
775 }
776
777 size.width = std::max(size.width, 5 + d.width + padding.width);
778 break;
779 }
780
781 case WID_SCL_MATRIX: {
782 /* 11 items in the default rail class */
783 this->square = GetSpriteSize(SPR_SQUARE);
784 this->line_height = std::max(this->square.height, (uint)GetCharacterHeight(FontSize::Normal)) + padding.height;
785
786 size.height = 5 * this->line_height;
787 resize.width = 1;
788 fill.height = resize.height = this->line_height;
789 break;
790 }
791
793 if (!_loaded_newgrf_features.has_2CC) break;
794 [[fallthrough]];
795
797 this->square = GetSpriteSize(SPR_SQUARE);
798 int string_padding = this->square.width + WidgetDimensions::scaled.hsep_normal + padding.width;
799 for (Colours colour = Colours::Begin; colour != Colours::End; colour++) {
800 size.width = std::max(size.width, GetStringBoundingBox(STR_COLOUR_DARK_BLUE + to_underlying(colour)).width + string_padding);
801 }
802 size.width = std::max(size.width, GetStringBoundingBox(STR_COLOUR_DEFAULT).width + string_padding);
803 break;
804 }
805 }
806 }
807
808 void OnPaint() override
809 {
810 bool local = this->window_number == _local_company;
811
812 /* Disable dropdown controls if no scheme is selected */
813 bool disabled = this->livery_class < LC_GROUP_RAIL ? (this->sel == 0) : (this->sel == GroupID::Invalid());
814 this->SetWidgetDisabledState(WID_SCL_PRI_COL_DROPDOWN, !local || disabled);
815 this->SetWidgetDisabledState(WID_SCL_SEC_COL_DROPDOWN, !local || disabled);
816
817 this->BuildGroupList(this->window_number);
818
819 this->DrawWidgets();
820 }
821
822 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
823 {
824 switch (widget) {
825 case WID_SCL_CAPTION:
826 return GetString(STR_LIVERY_CAPTION, this->window_number);
827
830 const Company *c = Company::Get(this->window_number);
831 bool primary = widget == WID_SCL_PRI_COL_DROPDOWN;
832 StringID colour = STR_COLOUR_DEFAULT;
833
834 if (this->livery_class < LC_GROUP_RAIL) {
835 if (this->sel != 0) {
836 LiveryScheme scheme = LS_DEFAULT;
837 for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
838 if (HasBit(this->sel, scheme)) break;
839 }
840 if (scheme == LS_END) scheme = LS_DEFAULT;
841 const Livery &livery = c->livery[scheme];
842 if (scheme == LS_DEFAULT || livery.in_use.Test(primary ? Livery::Flag::Primary : Livery::Flag::Secondary)) {
843 colour = STR_COLOUR_DARK_BLUE + GetColourOffset(livery, primary);
844 }
845 }
846 } else {
847 if (this->sel != GroupID::Invalid()) {
848 const Group *g = Group::Get(this->sel);
849 const Livery &livery = g->livery;
851 colour = STR_COLOUR_DARK_BLUE + GetColourOffset(livery, primary);
852 }
853 }
854 }
855 return GetString(colour);
856 }
857
858 default:
859 return this->Window::GetWidgetString(widget, stringid);
860 }
861 }
862
863 void DrawWidget(const Rect &r, WidgetID widget) const override
864 {
865 if (widget != WID_SCL_MATRIX) return;
866
867 bool rtl = _current_text_dir == TD_RTL;
868
869 /* Coordinates of scheme name column. */
871 Rect sch = nwi->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
872 /* Coordinates of first dropdown. */
874 Rect pri = nwi->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
875 /* Coordinates of second dropdown. */
877 Rect sec = nwi->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
878
879 Rect pri_squ = pri.WithWidth(this->square.width, rtl);
880 Rect sec_squ = sec.WithWidth(this->square.width, rtl);
881
882 pri = pri.Indent(this->square.width + WidgetDimensions::scaled.hsep_normal, rtl);
883 sec = sec.Indent(this->square.width + WidgetDimensions::scaled.hsep_normal, rtl);
884
885 Rect ir = r.WithHeight(this->resize.step_height).Shrink(WidgetDimensions::scaled.matrix);
886 int square_offs = (ir.Height() - this->square.height) / 2;
887 int text_offs = (ir.Height() - GetCharacterHeight(FontSize::Normal)) / 2;
888
889 int y = ir.top;
890
891 /* Helper function to draw livery info. */
892 auto draw_livery = [&](std::string_view str, const Livery &livery, bool is_selected, bool is_default_scheme, int indent) {
893 /* Livery Label. */
894 DrawString(sch.left + (rtl ? 0 : indent), sch.right - (rtl ? indent : 0), y + text_offs, str, is_selected ? TC_WHITE : TC_BLACK);
895
896 /* Text below the first dropdown. */
897 DrawSprite(SPR_SQUARE, GetColourPalette(livery.colour1), pri_squ.left, y + square_offs);
898 DrawString(pri.left, pri.right, y + text_offs, (is_default_scheme || livery.in_use.Test(Livery::Flag::Primary)) ? STR_COLOUR_DARK_BLUE + to_underlying(livery.colour1) : STR_COLOUR_DEFAULT, is_selected ? TC_WHITE : TC_GOLD);
899
900 /* Text below the second dropdown. */
901 if (sec.right > sec.left) { // Second dropdown has non-zero size.
902 DrawSprite(SPR_SQUARE, GetColourPalette(livery.colour2), sec_squ.left, y + square_offs);
903 DrawString(sec.left, sec.right, y + text_offs, (is_default_scheme || livery.in_use.Test(Livery::Flag::Secondary)) ? STR_COLOUR_DARK_BLUE + to_underlying(livery.colour2) : STR_COLOUR_DEFAULT, is_selected ? TC_WHITE : TC_GOLD);
904 }
905
906 y += this->line_height;
907 };
908
909 const Company *c = Company::Get(this->window_number);
910
911 if (livery_class < LC_GROUP_RAIL) {
912 int pos = this->vscroll->GetPosition();
913 for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
914 if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
915 if (pos-- > 0) continue;
916 draw_livery(GetString(STR_LIVERY_DEFAULT + scheme), c->livery[scheme], HasBit(this->sel, scheme), scheme == LS_DEFAULT, 0);
917 }
918 }
919 } else {
920 auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->groups);
921 for (auto it = first; it != last; ++it) {
922 const Group *g = it->group;
923 draw_livery(GetString(STR_GROUP_NAME, g->index), g->livery, this->sel == g->index, false, it->indent * WidgetDimensions::scaled.hsep_indent);
924 }
925
926 if (this->vscroll->GetCount() == 0) {
927 const StringID empty_labels[] = { STR_LIVERY_TRAIN_GROUP_EMPTY, STR_LIVERY_ROAD_VEHICLE_GROUP_EMPTY, STR_LIVERY_SHIP_GROUP_EMPTY, STR_LIVERY_AIRCRAFT_GROUP_EMPTY };
928 VehicleType vtype = (VehicleType)(this->livery_class - LC_GROUP_RAIL);
929 DrawString(ir.left, ir.right, y + text_offs, empty_labels[vtype], TC_BLACK);
930 }
931 }
932 }
933
934 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
935 {
936 switch (widget) {
937 /* Livery Class buttons */
947 this->RaiseWidget(WID_SCL_CLASS_GENERAL + this->livery_class);
948 this->livery_class = (LiveryClass)(widget - WID_SCL_CLASS_GENERAL);
949 this->LowerWidget(WID_SCL_CLASS_GENERAL + this->livery_class);
950
951 /* Select the first item in the list */
952 if (this->livery_class < LC_GROUP_RAIL) {
953 this->sel = 0;
954 for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
955 if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
956 this->sel = 1 << scheme;
957 break;
958 }
959 }
960 } else {
961 this->sel = GroupID::Invalid().base();
962 this->groups.ForceRebuild();
963 this->BuildGroupList(this->window_number);
964
965 if (!this->groups.empty()) {
966 this->sel = this->groups[0].group->index.base();
967 }
968 }
969
970 this->SetRows();
971 this->SetDirty();
972 break;
973
974 case WID_SCL_PRI_COL_DROPDOWN: // First colour dropdown
975 ShowColourDropDownMenu(WID_SCL_PRI_COL_DROPDOWN);
976 break;
977
978 case WID_SCL_SEC_COL_DROPDOWN: // Second colour dropdown
979 ShowColourDropDownMenu(WID_SCL_SEC_COL_DROPDOWN);
980 break;
981
982 case WID_SCL_MATRIX: {
983 if (this->livery_class < LC_GROUP_RAIL) {
984 uint row = this->vscroll->GetScrolledRowFromWidget(pt.y, this, widget);
985 if (row >= this->rows) return;
986
987 LiveryScheme j = (LiveryScheme)row;
988
989 for (LiveryScheme scheme = LS_BEGIN; scheme <= j && scheme < LS_END; scheme++) {
990 if (_livery_class[scheme] != this->livery_class || !HasBit(_loaded_newgrf_features.used_liveries, scheme)) j++;
991 }
992 assert(j < LS_END);
993
994 if (_ctrl_pressed) {
995 ToggleBit(this->sel, j);
996 } else {
997 this->sel = 1 << j;
998 }
999 } else {
1000 auto it = this->vscroll->GetScrolledItemFromWidget(this->groups, pt.y, this, widget);
1001 if (it == std::end(this->groups)) return;
1002
1003 this->sel = it->group->index.base();
1004 }
1005 this->SetDirty();
1006 break;
1007 }
1008 }
1009 }
1010
1011 void OnResize() override
1012 {
1013 this->vscroll->SetCapacityFromWidget(this, WID_SCL_MATRIX);
1014 }
1015
1016 void OnDropdownSelect(WidgetID widget, int index, int) override
1017 {
1018 bool local = this->window_number == _local_company;
1019 if (!local) return;
1020
1021 Colours colour = static_cast<Colours>(index);
1022 if (colour >= Colours::End) colour = Colours::Invalid;
1023
1024 if (this->livery_class < LC_GROUP_RAIL) {
1025 /* Set company colour livery */
1026 for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
1027 /* Changed colour for the selected scheme, or all visible schemes if CTRL is pressed. */
1028 if (HasBit(this->sel, scheme) || (_ctrl_pressed && _livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme))) {
1029 Command<Commands::SetCompanyColour>::Post(scheme, widget == WID_SCL_PRI_COL_DROPDOWN, colour);
1030 }
1031 }
1032 } else {
1033 /* Setting group livery */
1034 Command<Commands::SetGroupLivery>::Post(static_cast<GroupID>(this->sel), widget == WID_SCL_PRI_COL_DROPDOWN, colour);
1035 }
1036 }
1037
1043 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1044 {
1045 if (!gui_scope) return;
1046
1047 if (data != -1) {
1048 /* data contains a VehicleType, rebuild list if it displayed */
1049 if (this->livery_class == data + LC_GROUP_RAIL) {
1050 this->groups.ForceRebuild();
1051 this->BuildGroupList(this->window_number);
1052 this->SetRows();
1053
1054 if (!Group::IsValidID(this->sel)) {
1055 this->sel = GroupID::Invalid().base();
1056 if (!this->groups.empty()) this->sel = this->groups[0].group->index.base();
1057 }
1058
1059 this->SetDirty();
1060 }
1061 return;
1062 }
1063
1065
1066 bool current_class_valid = this->livery_class == LC_OTHER || this->livery_class >= LC_GROUP_RAIL;
1067 if (_settings_client.gui.liveries == LIT_ALL || (_settings_client.gui.liveries == LIT_COMPANY && this->window_number == _local_company)) {
1068 for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
1069 if (HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
1070 if (_livery_class[scheme] == this->livery_class) current_class_valid = true;
1072 } else if (this->livery_class < LC_GROUP_RAIL) {
1073 ClrBit(this->sel, scheme);
1074 }
1075 }
1076 }
1077
1078 if (!current_class_valid) {
1079 Point pt = {0, 0};
1080 this->OnClick(pt, WID_SCL_CLASS_GENERAL, 1);
1081 }
1082 }
1083};
1084
1085static constexpr std::initializer_list<NWidgetPart> _nested_select_company_livery_widgets = {
1092 EndContainer(),
1094 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCL_CLASS_GENERAL), SetToolbarMinimalSize(1), SetFill(0, 1), SetSpriteTip(SPR_IMG_COMPANY_GENERAL, STR_LIVERY_GENERAL_TOOLTIP),
1095 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCL_CLASS_RAIL), SetToolbarMinimalSize(1), SetFill(0, 1), SetSpriteTip(SPR_IMG_TRAINLIST, STR_LIVERY_TRAIN_TOOLTIP),
1096 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCL_CLASS_ROAD), SetToolbarMinimalSize(1), SetFill(0, 1), SetSpriteTip(SPR_IMG_TRUCKLIST, STR_LIVERY_ROAD_VEHICLE_TOOLTIP),
1097 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCL_CLASS_SHIP), SetToolbarMinimalSize(1), SetFill(0, 1), SetSpriteTip(SPR_IMG_SHIPLIST, STR_LIVERY_SHIP_TOOLTIP),
1098 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCL_CLASS_AIRCRAFT), SetToolbarMinimalSize(1), SetFill(0, 1), SetSpriteTip(SPR_IMG_AIRPLANESLIST, STR_LIVERY_AIRCRAFT_TOOLTIP),
1099 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCL_GROUPS_RAIL), SetToolbarMinimalSize(1), SetFill(0, 1), SetSpriteTip(SPR_GROUP_LIVERY_TRAIN, STR_LIVERY_TRAIN_GROUP_TOOLTIP),
1100 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCL_GROUPS_ROAD), SetToolbarMinimalSize(1), SetFill(0, 1), SetSpriteTip(SPR_GROUP_LIVERY_ROADVEH, STR_LIVERY_ROAD_VEHICLE_GROUP_TOOLTIP),
1101 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCL_GROUPS_SHIP), SetToolbarMinimalSize(1), SetFill(0, 1), SetSpriteTip(SPR_GROUP_LIVERY_SHIP, STR_LIVERY_SHIP_GROUP_TOOLTIP),
1102 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCL_GROUPS_AIRCRAFT), SetToolbarMinimalSize(1), SetFill(0, 1), SetSpriteTip(SPR_GROUP_LIVERY_AIRCRAFT, STR_LIVERY_AIRCRAFT_GROUP_TOOLTIP),
1104 EndContainer(),
1108 EndContainer(),
1111 NWidget(WWT_DROPDOWN, Colours::Grey, WID_SCL_PRI_COL_DROPDOWN), SetFill(0, 1), SetToolTip(STR_LIVERY_PRIMARY_TOOLTIP),
1113 NWidget(WWT_DROPDOWN, Colours::Grey, WID_SCL_SEC_COL_DROPDOWN), SetFill(0, 1), SetToolTip(STR_LIVERY_SECONDARY_TOOLTIP),
1114 EndContainer(),
1116 EndContainer(),
1117};
1118
1119static WindowDesc _select_company_livery_desc(
1120 WDP_AUTO, "company_colour_scheme", 0, 0,
1122 {},
1123 _nested_select_company_livery_widgets
1124);
1125
1126void ShowCompanyLiveryWindow(CompanyID company, GroupID group)
1127{
1129 if (w == nullptr) {
1130 new SelectCompanyLiveryWindow(_select_company_livery_desc, company, group);
1131 } else if (group != GroupID::Invalid()) {
1132 w->SetSelectedGroup(company, group);
1133 }
1134}
1135
1142void DrawCompanyManagerFace(const CompanyManagerFace &cmf, Colours colour, const Rect &r)
1143{
1144 /* Determine offset from centre of drawing rect. */
1145 Dimension d = GetSpriteSize(SPR_GRADIENT);
1146 int x = CentreBounds(r.left, r.right, d.width);
1147 int y = CentreBounds(r.top, r.bottom, d.height);
1148
1149 FaceVars vars = GetCompanyManagerFaceVars(cmf.style);
1150
1151 /* First determine which parts are enabled. */
1152 uint64_t active_vars = GetActiveFaceVars(cmf, vars);
1153
1154 std::unordered_map<uint8_t, PaletteID> palettes;
1155
1156 /* Second, get palettes. */
1157 for (auto var : SetBitIterator(active_vars)) {
1158 if (vars[var].type != FaceVarType::Palette) continue;
1159
1160 PaletteID pal = PAL_NONE;
1161 switch (vars[var].GetBits(cmf)) {
1162 default: NOT_REACHED();
1163 case 0: pal = PALETTE_TO_BROWN; break;
1164 case 1: pal = PALETTE_TO_BLUE; break;
1165 case 2: pal = PALETTE_TO_GREEN; break;
1166 }
1167 for (uint8_t affected_var : SetBitIterator(std::get<uint64_t>(vars[var].data))) {
1168 palettes[affected_var] = pal;
1169 }
1170 }
1171
1172 /* Draw the gradient (background) */
1173 DrawSprite(SPR_GRADIENT, GetColourPalette(colour), x, y);
1174
1175 /* Thirdly, draw sprites. */
1176 for (auto var : SetBitIterator(active_vars)) {
1177 if (vars[var].type != FaceVarType::Sprite) continue;
1178
1179 auto it = palettes.find(var);
1180 PaletteID pal = (it == std::end(palettes)) ? PAL_NONE : it->second;
1181 DrawSprite(vars[var].GetSprite(cmf), pal, x, y);
1182 }
1183}
1184
1186static constexpr std::initializer_list<NWidgetPart> _nested_select_company_manager_face_widgets = {
1189 NWidget(WWT_CAPTION, Colours::Grey, WID_SCMF_CAPTION), SetStringTip(STR_FACE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1190 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCMF_TOGGLE_LARGE_SMALL), SetSpriteTip(SPR_LARGE_SMALL_WINDOW, STR_FACE_ADVANCED_TOOLTIP), SetAspect(WidgetDimensions::ASPECT_TOGGLE_SIZE),
1191 EndContainer(),
1194 /* Left side */
1197 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SCMF_RANDOM_NEW_FACE), SetFill(1, 0), SetStringTip(STR_FACE_NEW_FACE_BUTTON, STR_FACE_NEW_FACE_TOOLTIP),
1198 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON), SetFill(1, 0), SetStringTip(STR_FACE_ADVANCED, STR_FACE_ADVANCED_TOOLTIP),
1199 NWidget(NWID_SELECTION, Colours::Invalid, WID_SCMF_SEL_LOADSAVE), // Load/number/save buttons under the portrait in the advanced view.
1201 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(0, 1),
1202 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SCMF_LOAD), SetFill(1, 0), SetStringTip(STR_FACE_LOAD, STR_FACE_LOAD_TOOLTIP),
1203 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SCMF_FACECODE), SetFill(1, 0), SetStringTip(STR_FACE_FACECODE, STR_FACE_FACECODE_TOOLTIP),
1204 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SCMF_SAVE), SetFill(1, 0), SetStringTip(STR_FACE_SAVE, STR_FACE_SAVE_TOOLTIP),
1205 EndContainer(),
1206 EndContainer(),
1207 EndContainer(),
1208 EndContainer(),
1209 /* Right side */
1210 NWidget(NWID_SELECTION, Colours::Invalid, WID_SCMF_SEL_PARTS), // Advanced face parts setting.
1216 EndContainer(),
1217 EndContainer(),
1218 EndContainer(),
1219 EndContainer(),
1221 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SCMF_CANCEL), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_BUTTON_CANCEL, STR_FACE_CANCEL_TOOLTIP),
1222 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SCMF_ACCEPT), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_BUTTON_OK, STR_FACE_OK_TOOLTIP),
1225 EndContainer(),
1226 EndContainer(),
1227};
1228
1230class SelectCompanyManagerFaceWindow : public Window
1231{
1233 bool advanced = false;
1234 uint selected_var = UINT_MAX;
1235 uint click_state = 0;
1236 int line_height = 0;
1237
1238 std::vector<const FaceVar *> face_vars;
1239
1244 {
1245 FaceVars vars = GetCompanyManagerFaceVars(this->face.style);
1246 ScaleAllCompanyManagerFaceBits(this->face, vars);
1247
1248 uint64_t active_vars = GetActiveFaceVars(this->face, vars);
1249 /* Exclude active parts which have no string. */
1250 for (auto var : SetBitIterator(active_vars)) {
1251 if (vars[var].name == STR_NULL) ClrBit(active_vars, var);
1252 }
1253
1254 /* Rebuild the sorted list of face variable pointers. */
1255 this->face_vars.clear();
1256 for (auto var : SetBitIterator(active_vars)) {
1257 this->face_vars.emplace_back(&vars[var]);
1258 }
1259 std::ranges::sort(this->face_vars, std::less{}, &FaceVar::position);
1260
1261 this->GetScrollbar(WID_SCMF_PARTS_SCROLLBAR)->SetCount(std::size(this->face_vars));
1262 }
1263
1264public:
1266 {
1267 this->CreateNestedTree();
1268 this->SelectDisplayPlanes(this->advanced);
1269 this->FinishInitNested(parent->window_number);
1270 this->parent = parent;
1271 this->owner = this->window_number;
1272 this->face = Company::Get(this->window_number)->face;
1273
1274 this->UpdateData();
1275 }
1276
1277 void OnInit() override
1278 {
1279 this->line_height = std::max(SETTING_BUTTON_HEIGHT, GetCharacterHeight(FontSize::Normal)) + WidgetDimensions::scaled.matrix.Vertical();
1280 }
1281
1287 {
1289 this->GetWidget<NWidgetStacked>(WID_SCMF_SEL_PARTS)->SetDisplayedPlane(advanced ? 0 : SZSP_NONE);
1290 this->GetWidget<NWidgetStacked>(WID_SCMF_SEL_RESIZE)->SetDisplayedPlane(advanced ? 0 : SZSP_NONE);
1291
1293 if (advanced) {
1294 wi->SetStringTip(STR_FACE_SIMPLE, STR_FACE_SIMPLE_TOOLTIP);
1295 } else {
1296 wi->SetStringTip(STR_FACE_ADVANCED, STR_FACE_ADVANCED_TOOLTIP);
1297 }
1298 }
1299
1300 static StringID GetLongestString(StringID a, StringID b)
1301 {
1302 return GetStringBoundingBox(a).width > GetStringBoundingBox(b).width ? a : b;
1303 }
1304
1305 static uint GetMaximumFacePartsWidth()
1306 {
1307 StringID yes_no = GetLongestString(STR_FACE_YES, STR_FACE_NO);
1308
1309 uint width = 0;
1310 for (uint style_index = 0; style_index != GetNumCompanyManagerFaceStyles(); ++style_index) {
1311 FaceVars vars = GetCompanyManagerFaceVars(style_index);
1312 for (const auto &info : vars) {
1313 if (info.name == STR_NULL) continue;
1314 if (info.type == FaceVarType::Toggle) {
1315 width = std::max(width, GetStringBoundingBox(GetString(STR_FACE_SETTING_TOGGLE, info.name, yes_no)).width);
1316 } else {
1317 uint64_t max_digits = GetParamMaxValue(info.valid_values);
1318 width = std::max(width, GetStringBoundingBox(GetString(STR_FACE_SETTING_NUMERIC, info.name, max_digits, max_digits)).width);
1319 }
1320 }
1321 }
1322
1323 /* Include width of button and spacing. */
1325 return width;
1326 }
1327
1328 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
1329 {
1330 switch (widget) {
1331 case WID_SCMF_FACE:
1332 size = maxdim(size, GetScaledSpriteSize(SPR_GRADIENT));
1333 break;
1334
1335 case WID_SCMF_STYLE:
1336 size.height = this->line_height;
1337 break;
1338
1339 case WID_SCMF_PARTS:
1340 fill.height = resize.height = this->line_height;
1341 size.width = GetMaximumFacePartsWidth();
1342 size.height = resize.height * 5;
1343 break;
1344 }
1345 }
1346
1347 void DrawWidget(const Rect &r, WidgetID widget) const override
1348 {
1349 switch (widget) {
1350 case WID_SCMF_FACE:
1351 DrawCompanyManagerFace(this->face, Company::Get(this->window_number)->colour, r);
1352 break;
1353
1354 case WID_SCMF_STYLE: {
1355 Rect ir = r.Shrink(WidgetDimensions::scaled.frametext, RectPadding::zero).WithHeight(this->line_height);
1356 bool rtl = _current_text_dir == TD_RTL;
1357
1360
1361 DrawArrowButtons(br.left, br.top, Colours::Yellow, this->selected_var == UINT_MAX - 1 ? this->click_state : 0, true, true);
1362 DrawString(tr, GetString(STR_FACE_SETTING_NUMERIC, STR_FACE_STYLE, this->face.style + 1, GetNumCompanyManagerFaceStyles()), TC_WHITE);
1363 break;
1364 }
1365
1366 case WID_SCMF_PARTS: {
1367 Rect ir = r.Shrink(WidgetDimensions::scaled.frametext, RectPadding::zero).WithHeight(this->line_height);
1368 bool rtl = _current_text_dir == TD_RTL;
1369
1370 FaceVars vars = GetCompanyManagerFaceVars(this->face.style);
1371
1372 auto [first, last] = this->GetScrollbar(WID_SCMF_PARTS_SCROLLBAR)->GetVisibleRangeIterators(this->face_vars);
1373 for (auto it = first; it != last; ++it) {
1374 const uint8_t var = static_cast<uint8_t>(*it - vars.data());
1375 const FaceVar &facevar = **it;
1376
1379
1380 uint val = vars[var].GetBits(this->face);
1381 if (facevar.type == FaceVarType::Toggle) {
1382 DrawBoolButton(br.left, br.top, Colours::Yellow, Colours::Grey, val == 1, true);
1383 DrawString(tr, GetString(STR_FACE_SETTING_TOGGLE, facevar.name, val == 1 ? STR_FACE_YES : STR_FACE_NO), TC_WHITE);
1384 } else {
1385 DrawArrowButtons(br.left, br.top, Colours::Yellow, this->selected_var == var ? this->click_state : 0, true, true);
1386 DrawString(tr, GetString(STR_FACE_SETTING_NUMERIC, facevar.name, val + 1, facevar.valid_values), TC_WHITE);
1387 }
1388
1389 ir = ir.Translate(0, this->line_height);
1390 }
1391 break;
1392 }
1393 }
1394 }
1395
1396 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1397 {
1398 switch (widget) {
1399 /* Toggle size, advanced/simple face selection */
1402 this->advanced = !this->advanced;
1403 this->SelectDisplayPlanes(this->advanced);
1404 this->ReInit();
1405 break;
1406
1407 /* OK button */
1408 case WID_SCMF_ACCEPT:
1409 Command<Commands::SetCompanyManagerFace>::Post(this->face.style, this->face.bits);
1410 [[fallthrough]];
1411
1412 /* Cancel button */
1413 case WID_SCMF_CANCEL:
1414 this->Close();
1415 break;
1416
1417 /* Load button */
1418 case WID_SCMF_LOAD: {
1420 if (cmf.has_value()) this->face = *cmf;
1421 ShowErrorMessage(GetEncodedString(STR_FACE_LOAD_DONE), {}, WL_INFO);
1422 this->UpdateData();
1423 this->SetDirty();
1424 break;
1425 }
1426
1427 /* 'Company manager face number' button, view and/or set company manager face number */
1428 case WID_SCMF_FACECODE:
1429 ShowQueryString(FormatCompanyManagerFaceCode(this->face), STR_FACE_FACECODE_CAPTION, 128, this, CS_ALPHANUMERAL, {});
1430 break;
1431
1432 /* Save button */
1433 case WID_SCMF_SAVE:
1435 ShowErrorMessage(GetEncodedString(STR_FACE_SAVE_DONE), {}, WL_INFO);
1436 break;
1437
1438 /* Randomize face button */
1441 this->UpdateData();
1442 this->SetDirty();
1443 break;
1444
1445 case WID_SCMF_STYLE: {
1446 bool rtl = _current_text_dir == TD_RTL;
1447 Rect ir = this->GetWidget<NWidgetCore>(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.frametext, RectPadding::zero);
1448 Rect br = ir.WithWidth(SETTING_BUTTON_WIDTH, rtl);
1449
1450 uint num_styles = GetNumCompanyManagerFaceStyles();
1451 this->selected_var = UINT_MAX - 1;
1452 if (IsInsideBS(pt.x, br.left, SETTING_BUTTON_WIDTH / 2)) {
1453 SetCompanyManagerFaceStyle(this->face, (this->face.style + num_styles - 1) % num_styles);
1454 this->click_state = 1;
1455 } else if (IsInsideBS(pt.x, br.left + SETTING_BUTTON_WIDTH / 2, SETTING_BUTTON_WIDTH / 2)) {
1456 SetCompanyManagerFaceStyle(this->face, (this->face.style + 1) % num_styles);
1457 this->click_state = 2;
1458 }
1459
1460 this->UpdateData();
1461 this->SetTimeout();
1462 this->SetDirty();
1463 break;
1464 }
1465
1466 case WID_SCMF_PARTS: {
1467 bool rtl = _current_text_dir == TD_RTL;
1468 Rect ir = this->GetWidget<NWidgetCore>(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.frametext, RectPadding::zero);
1469 Rect br = ir.WithWidth(SETTING_BUTTON_WIDTH, rtl);
1470
1471 this->selected_var = UINT_MAX;
1472
1473 FaceVars vars = GetCompanyManagerFaceVars(this->face.style);
1474 auto it = this->GetScrollbar(WID_SCMF_PARTS_SCROLLBAR)->GetScrolledItemFromWidget(this->face_vars, pt.y, this, widget, 0, this->line_height);
1475 if (it == std::end(this->face_vars)) break;
1476
1477 this->selected_var = static_cast<uint8_t>(*it - vars.data());
1478 const auto &facevar = **it;
1479
1480 if (facevar.type == FaceVarType::Toggle) {
1481 if (!IsInsideBS(pt.x, br.left, SETTING_BUTTON_WIDTH)) break;
1482 facevar.ChangeBits(this->face, 1);
1483 this->UpdateData();
1484 } else {
1485 if (IsInsideBS(pt.x, br.left, SETTING_BUTTON_WIDTH / 2)) {
1486 facevar.ChangeBits(this->face, -1);
1487 this->click_state = 1;
1488 } else if (IsInsideBS(pt.x, br.left + SETTING_BUTTON_WIDTH / 2, SETTING_BUTTON_WIDTH / 2)) {
1489 facevar.ChangeBits(this->face, 1);
1490 this->click_state = 2;
1491 } else {
1492 break;
1493 }
1494 }
1495
1496 this->SetTimeout();
1497 this->SetDirty();
1498 break;
1499 }
1500 }
1501 }
1502
1503 void OnResize() override
1504 {
1505 if (auto *wid = this->GetWidget<NWidgetResizeBase>(WID_SCMF_PARTS); wid != nullptr) {
1506 /* Workaround for automatic widget sizing ignoring resize steps. Manually ensure parts matrix is a
1507 * multiple of its resize step. This trick only works here as the window itself is not resizable. */
1508 if (wid->UpdateVerticalSize((wid->current_y + wid->resize_y - 1) / wid->resize_y * wid->resize_y)) {
1509 this->ReInit();
1510 return;
1511 }
1512 }
1513
1515 }
1516
1517 void OnTimeout() override
1518 {
1519 this->click_state = 0;
1520 this->selected_var = UINT_MAX;
1521 this->SetDirty();
1522 }
1523
1524 void OnQueryTextFinished(std::optional<std::string> str) override
1525 {
1526 if (!str.has_value()) return;
1527 /* Parse new company manager face number */
1528 auto cmf = ParseCompanyManagerFaceCode(*str);
1529 if (cmf.has_value()) {
1530 this->face = *cmf;
1531 ShowErrorMessage(GetEncodedString(STR_FACE_FACECODE_SET), {}, WL_INFO);
1532 this->UpdateData();
1533 this->SetDirty();
1534 } else {
1535 ShowErrorMessage(GetEncodedString(STR_FACE_FACECODE_ERR), {}, WL_INFO);
1536 }
1537 }
1538};
1539
1542 WDP_AUTO, {}, 0, 0,
1546);
1547
1560
1561static constexpr std::initializer_list<NWidgetPart> _nested_company_infrastructure_widgets = {
1568 EndContainer(),
1572 EndContainer(),
1576 EndContainer(),
1577 EndContainer(),
1578};
1579
1583struct CompanyInfrastructureWindow : Window
1584{
1591
1594 StringID label;
1595 uint count;
1596 Money cost;
1597 };
1598
1599 uint count_width = 0;
1600 uint cost_width = 0;
1601
1602 mutable std::vector<InfrastructureItem> list;
1603
1604 CompanyInfrastructureWindow(WindowDesc &desc, WindowNumber window_number) : Window(desc)
1605 {
1606 this->InitNested(window_number);
1607 this->owner = this->window_number;
1608 }
1609
1610 void OnInit() override
1611 {
1612 this->UpdateInfrastructureList();
1613 }
1614
1615 void UpdateInfrastructureList()
1616 {
1617 this->list.clear();
1618
1619 const Company *c = Company::GetIfValid(this->window_number);
1620 if (c == nullptr) return;
1621
1622 Money total_monthly_cost = 0;
1623
1624 if (uint32_t rail_total = c->infrastructure.GetRailTotal(); rail_total > 0) {
1625 /* Rail types and signals. */
1626 this->list.emplace_back(InfrastructureItemType::Header, STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT);
1627
1628 for (const RailType &rt : _sorted_railtypes) {
1629 if (c->infrastructure.rail[rt] == 0) continue;
1630 Money monthly_cost = RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total);
1631 total_monthly_cost += monthly_cost;
1632 this->list.emplace_back(InfrastructureItemType::Value, GetRailTypeInfo(rt)->strings.name, c->infrastructure.rail[rt], monthly_cost);
1633 }
1634
1635 if (c->infrastructure.signal > 0) {
1636 Money monthly_cost = SignalMaintenanceCost(c->infrastructure.signal);
1637 total_monthly_cost += monthly_cost;
1638 this->list.emplace_back(InfrastructureItemType::Value, STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS, c->infrastructure.signal, monthly_cost);
1639 }
1640 }
1641
1642 if (uint32_t road_total = c->infrastructure.GetRoadTotal(); road_total > 0) {
1643 /* Road types. */
1644 if (!this->list.empty()) this->list.emplace_back(InfrastructureItemType::Spacer);
1645 this->list.emplace_back(InfrastructureItemType::Header, STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT);
1646
1647 for (const RoadType &rt : _sorted_roadtypes) {
1648 if (!RoadTypeIsRoad(rt)) continue;
1649 if (c->infrastructure.road[rt] == 0) continue;
1650 Money monthly_cost = RoadMaintenanceCost(rt, c->infrastructure.road[rt], road_total);
1651 total_monthly_cost += monthly_cost;
1652 this->list.emplace_back(InfrastructureItemType::Value, GetRoadTypeInfo(rt)->strings.name, c->infrastructure.road[rt], monthly_cost);
1653 }
1654 }
1655
1656 if (uint32_t tram_total = c->infrastructure.GetTramTotal(); tram_total > 0) {
1657 /* Tram types. */
1658 if (!this->list.empty()) this->list.emplace_back(InfrastructureItemType::Spacer);
1659 this->list.emplace_back(InfrastructureItemType::Header, STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT);
1660
1661 for (const RoadType &rt : _sorted_roadtypes) {
1662 if (!RoadTypeIsTram(rt)) continue;
1663 if (c->infrastructure.road[rt] == 0) continue;
1664 Money monthly_cost = RoadMaintenanceCost(rt, c->infrastructure.road[rt], tram_total);
1665 total_monthly_cost += monthly_cost;
1666 this->list.emplace_back(InfrastructureItemType::Value, GetRoadTypeInfo(rt)->strings.name, c->infrastructure.road[rt], monthly_cost);
1667 }
1668 }
1669
1670 if (c->infrastructure.water > 0) {
1671 /* Canals, locks, and ship depots (docks are counted as stations). */
1672 if (!this->list.empty()) this->list.emplace_back(InfrastructureItemType::Spacer);
1673 this->list.emplace_back(InfrastructureItemType::Header, STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT);
1674
1675 Money monthly_cost = CanalMaintenanceCost(c->infrastructure.water);
1676 total_monthly_cost += monthly_cost;
1677 this->list.emplace_back(InfrastructureItemType::Value, STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS, c->infrastructure.water, monthly_cost);
1678 }
1679
1680 if (Money airport_cost = AirportMaintenanceCost(c->index); airport_cost > 0 || c->infrastructure.station > 0) {
1681 /* Stations and airports. */
1682 if (!this->list.empty()) this->list.emplace_back(InfrastructureItemType::Spacer);
1683 this->list.emplace_back(InfrastructureItemType::Header, STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT);
1684
1685 if (c->infrastructure.station > 0) {
1686 Money monthly_cost = StationMaintenanceCost(c->infrastructure.station);
1687 total_monthly_cost += monthly_cost;
1688 this->list.emplace_back(InfrastructureItemType::Value, STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS, c->infrastructure.station, monthly_cost);
1689 }
1690
1691 if (airport_cost > 0) {
1692 Money monthly_cost = airport_cost;
1693 total_monthly_cost += monthly_cost;
1694 this->list.emplace_back(InfrastructureItemType::Value, STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS, c->infrastructure.airport, monthly_cost);
1695 }
1696 }
1697
1699 /* Total monthly maintenance cost. */
1700 this->list.emplace_back(InfrastructureItemType::Spacer);
1701 this->list.emplace_back(InfrastructureItemType::Total, STR_NULL, 0, total_monthly_cost);
1702 }
1703
1704 /* Update scrollbar. */
1705 this->GetScrollbar(WID_CI_SCROLLBAR)->SetCount(std::size(list));
1706 }
1707
1708 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
1709 {
1710 switch (widget) {
1711 case WID_CI_CAPTION:
1712 return GetString(STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION, this->window_number);
1713
1714 default:
1715 return this->Window::GetWidgetString(widget, stringid);
1716 }
1717 }
1718
1719 void FindWindowPlacementAndResize(int def_width, int def_height, bool allow_resize) override
1720 {
1721 if (def_height == 0) {
1722 /* Try to open the window with the exact required rows, but clamp to a reasonable limit. */
1723 int rows = (this->GetWidget<NWidgetBase>(WID_CI_LIST)->current_y - WidgetDimensions::scaled.framerect.Vertical()) / GetCharacterHeight(FontSize::Normal);
1724 int delta = std::min(20, static_cast<int>(std::size(this->list))) - rows;
1725 def_height = this->height + delta * GetCharacterHeight(FontSize::Normal);
1726 }
1727
1728 this->Window::FindWindowPlacementAndResize(def_width, def_height, allow_resize);
1729 }
1730
1731 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
1732 {
1733 if (widget != WID_CI_LIST) return;
1734
1735 uint max_count = 1000; // Some random number to reserve minimum space.
1736 Money max_cost = 1000000; // Some random number to reserve minimum space.
1737
1738 /* List of headers that might be used. */
1739 static constexpr StringID header_strings[] = {
1740 STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT,
1741 STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT,
1742 STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT,
1743 STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT,
1744 STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT,
1745 };
1746 /* List of labels that might be used. */
1747 static constexpr StringID label_strings[] = {
1748 STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS,
1749 STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS,
1750 STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS,
1751 STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS,
1752 };
1753
1754 uint max_header_width = GetStringListWidth(header_strings);
1755 uint max_label_width = GetStringListWidth(label_strings);
1756
1757 /* Include width of all possible rail and road types. */
1758 for (const RailType &rt : _sorted_railtypes) max_label_width = std::max(max_label_width, GetStringBoundingBox(GetRailTypeInfo(rt)->strings.name).width);
1759 for (const RoadType &rt : _sorted_roadtypes) max_label_width = std::max(max_label_width, GetStringBoundingBox(GetRoadTypeInfo(rt)->strings.name).width);
1760
1761 for (const InfrastructureItem &entry : this->list) {
1762 max_count = std::max(max_count, entry.count);
1763 max_cost = std::max(max_cost, entry.cost * 12);
1764 }
1765
1766 max_label_width += WidgetDimensions::scaled.hsep_indent;
1767 this->count_width = GetStringBoundingBox(GetString(STR_JUST_COMMA, max_count)).width;
1768
1769 if (_settings_game.economy.infrastructure_maintenance) {
1770 this->cost_width = GetStringBoundingBox(GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_PERIOD : STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_YEAR, max_cost)).width;
1771 } else {
1772 this->cost_width = 0;
1773 }
1774
1775 size.width = max_label_width + WidgetDimensions::scaled.hsep_wide + this->count_width + WidgetDimensions::scaled.hsep_wide + this->cost_width;
1776 size.width = std::max(size.width, max_header_width) + WidgetDimensions::scaled.framerect.Horizontal();
1777
1778 fill.height = resize.height = GetCharacterHeight(FontSize::Normal);
1779 }
1780
1781 void DrawWidget(const Rect &r, WidgetID widget) const override
1782 {
1783 if (widget != WID_CI_LIST) return;
1784
1785 bool rtl = _current_text_dir == TD_RTL; // We allocate space from end-to-start so the label fills.
1786 int line_height = GetCharacterHeight(FontSize::Normal);
1787
1788 Rect ir = r.Shrink(WidgetDimensions::scaled.framerect);
1789 Rect countr = ir.WithWidth(this->count_width, !rtl);
1790 Rect costr = ir.Indent(this->count_width + WidgetDimensions::scaled.hsep_wide, !rtl).WithWidth(this->cost_width, !rtl);
1791 Rect labelr = ir.Indent(this->count_width + WidgetDimensions::scaled.hsep_wide + this->cost_width + WidgetDimensions::scaled.hsep_wide, !rtl);
1792
1793 auto [first, last] = this->GetScrollbar(WID_CI_SCROLLBAR)->GetVisibleRangeIterators(this->list);
1794 for (auto it = first; it != last; ++it) {
1795 switch (it->type) {
1797 /* Header is allowed to fill the window's width. */
1798 DrawString(ir.left, ir.right, labelr.top, GetString(it->label), TC_ORANGE);
1799 break;
1800
1802 break;
1803
1805 /* Draw line in the spacer above the total. */
1807 DrawString(costr, GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_PERIOD : STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_YEAR, it->cost * 12), TC_BLACK, SA_RIGHT | SA_FORCE);
1808 break;
1809
1811 DrawString(labelr.Indent(WidgetDimensions::scaled.hsep_indent, rtl), GetString(it->label), TC_WHITE);
1812 DrawString(countr, GetString(STR_JUST_COMMA, it->count), TC_WHITE, SA_RIGHT | SA_FORCE);
1813 if (_settings_game.economy.infrastructure_maintenance) {
1814 DrawString(costr, GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_PERIOD : STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_YEAR, it->cost * 12), TC_BLACK, SA_RIGHT | SA_FORCE);
1815 }
1816 break;
1817 }
1818
1819 labelr.top += line_height;
1820 countr.top += line_height;
1821 costr.top += line_height;
1822 }
1823 }
1824
1825 const IntervalTimer<TimerWindow> redraw_interval = {std::chrono::seconds(1), [this](auto) {
1826 this->UpdateInfrastructureList();
1828 }};
1829
1830 void OnResize() override
1831 {
1833 }
1834
1840 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1841 {
1842 if (!gui_scope) return;
1843
1844 this->ReInit();
1845 }
1846};
1847
1848static WindowDesc _company_infrastructure_desc(
1849 WDP_AUTO, "company_infrastructure", 0, 0,
1851 {},
1852 _nested_company_infrastructure_widgets
1853);
1854
1859static void ShowCompanyInfrastructure(CompanyID company)
1860{
1861 if (!Company::IsValidID(company)) return;
1862 AllocateWindowDescFront<CompanyInfrastructureWindow>(_company_infrastructure_desc, company);
1863}
1864
1865static constexpr std::initializer_list<NWidgetPart> _nested_company_widgets = {
1871 EndContainer(),
1877 EndContainer(),
1883 NWidget(WWT_LABEL, Colours::Invalid, WID_C_DESC_COLOUR_SCHEME), SetStringTip(STR_COMPANY_VIEW_COLOUR_SCHEME_TITLE),
1885 EndContainer(),
1889 EndContainer(),
1890 EndContainer(),
1893 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_C_VIEW_HQ), SetStringTip(STR_COMPANY_VIEW_VIEW_HQ_BUTTON, STR_COMPANY_VIEW_VIEW_HQ_TOOLTIP),
1894 NWidget(WWT_TEXTBTN, Colours::Grey, WID_C_BUILD_HQ), SetStringTip(STR_COMPANY_VIEW_BUILD_HQ_BUTTON, STR_COMPANY_VIEW_BUILD_HQ_TOOLTIP),
1895 EndContainer(),
1897 NWidget(WWT_TEXTBTN, Colours::Grey, WID_C_RELOCATE_HQ), SetStringTip(STR_COMPANY_VIEW_RELOCATE_HQ, STR_COMPANY_VIEW_RELOCATE_HQ_TOOLTIP),
1899 EndContainer(),
1900 EndContainer(),
1901 EndContainer(),
1902
1904
1909 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_C_VIEW_INFRASTRUCTURE), SetStringTip(STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON, STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP),
1910 EndContainer(),
1911 EndContainer(),
1912
1913 /* Multi player buttons. */
1917 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_C_HOSTILE_TAKEOVER), SetStringTip(STR_COMPANY_VIEW_HOSTILE_TAKEOVER_BUTTON, STR_COMPANY_VIEW_HOSTILE_TAKEOVER_TOOLTIP),
1918 EndContainer(),
1920 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_C_GIVE_MONEY), SetStringTip(STR_COMPANY_VIEW_GIVE_MONEY_BUTTON, STR_COMPANY_VIEW_GIVE_MONEY_TOOLTIP),
1921 EndContainer(),
1923 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_C_COMPANY_JOIN), SetStringTip(STR_COMPANY_VIEW_JOIN, STR_COMPANY_VIEW_JOIN_TOOLTIP),
1924 EndContainer(),
1925 EndContainer(),
1926 EndContainer(),
1927 EndContainer(),
1928 EndContainer(),
1929 EndContainer(),
1930 /* Button bars at the bottom. */
1933 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_C_NEW_FACE), SetFill(1, 0), SetStringTip(STR_COMPANY_VIEW_NEW_FACE_BUTTON, STR_COMPANY_VIEW_NEW_FACE_TOOLTIP),
1934 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_C_COLOUR_SCHEME), SetFill(1, 0), SetStringTip(STR_COMPANY_VIEW_COLOUR_SCHEME_BUTTON, STR_COMPANY_VIEW_COLOUR_SCHEME_TOOLTIP),
1935 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_C_PRESIDENT_NAME), SetFill(1, 0), SetStringTip(STR_COMPANY_VIEW_PRESIDENT_NAME_BUTTON, STR_COMPANY_VIEW_PRESIDENT_NAME_TOOLTIP),
1936 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_C_COMPANY_NAME), SetFill(1, 0), SetStringTip(STR_COMPANY_VIEW_COMPANY_NAME_BUTTON, STR_COMPANY_VIEW_COMPANY_NAME_TOOLTIP),
1937 EndContainer(),
1938 EndContainer(),
1939};
1940
1943 STR_COMPANY_VIEW_TRAINS, STR_COMPANY_VIEW_ROAD_VEHICLES, STR_COMPANY_VIEW_SHIPS, STR_COMPANY_VIEW_AIRCRAFT
1944};
1945
1949struct CompanyWindow : Window
1950{
1953
1954 CompanyWidgets query_widget{};
1955
1957 enum CompanyWindowPlanes : uint8_t {
1958 /* Display planes of the #WID_C_SELECT_VIEW_BUILD_HQ selection widget. */
1961
1962 /* Display planes of the #WID_C_SELECT_RELOCATE selection widget. */
1965 };
1966
1968 {
1969 this->InitNested(window_number);
1970 this->owner = this->window_number;
1971 this->OnInvalidateData();
1972 }
1973
1974 void OnPaint() override
1975 {
1976 const Company *c = Company::Get(this->window_number);
1977 bool local = this->window_number == _local_company;
1978
1979 if (!this->IsShaded()) {
1980 bool reinit = false;
1981
1982 /* Button bar selection. */
1983 reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_BUTTONS)->SetDisplayedPlane(local ? 0 : SZSP_NONE);
1984
1985 /* Build HQ button handling. */
1986 reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_VIEW_BUILD_HQ)->SetDisplayedPlane((local && c->location_of_HQ == INVALID_TILE) ? CWP_VB_BUILD : CWP_VB_VIEW);
1987
1989
1990 /* Enable/disable 'Relocate HQ' button. */
1991 reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_RELOCATE)->SetDisplayedPlane((!local || c->location_of_HQ == INVALID_TILE) ? CWP_RELOCATE_HIDE : CWP_RELOCATE_SHOW);
1992 /* Enable/disable 'Give money' button. */
1993 reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_GIVE_MONEY)->SetDisplayedPlane((local || _local_company == COMPANY_SPECTATOR || !_settings_game.economy.give_money) ? SZSP_NONE : 0);
1994 /* Enable/disable 'Hostile Takeover' button. */
1995 reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_HOSTILE_TAKEOVER)->SetDisplayedPlane((local || _local_company == COMPANY_SPECTATOR || !c->is_ai || _networking) ? SZSP_NONE : 0);
1996
1997 /* Multiplayer buttons. */
1998 reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_MULTIPLAYER)->SetDisplayedPlane((!_networking || !NetworkCanJoinCompany(c->index) || _local_company == c->index) ? (int)SZSP_NONE : 0);
1999
2001
2002 if (reinit) {
2003 this->ReInit();
2004 return;
2005 }
2006 }
2007
2008 this->DrawWidgets();
2009 }
2010
2011 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2012 {
2013 switch (widget) {
2014 case WID_C_FACE:
2015 size = maxdim(size, GetScaledSpriteSize(SPR_GRADIENT));
2016 break;
2017
2019 Point offset;
2020 Dimension d = GetSpriteSize(SPR_VEH_BUS_SW_VIEW, &offset);
2021 d.width -= offset.x;
2022 d.height -= offset.y;
2023 size = maxdim(size, d);
2024 break;
2025 }
2026
2028 /* INT64_MAX is arguably the maximum company value */
2029 size.width = GetStringBoundingBox(GetString(STR_COMPANY_VIEW_COMPANY_VALUE, INT64_MAX)).width;
2030 break;
2031
2033 uint64_t max_value = GetParamMaxValue(5000); // Maximum number of vehicles
2034 for (const auto &count_string : _company_view_vehicle_count_strings) {
2035 size.width = std::max(size.width, GetStringBoundingBox(GetString(count_string, max_value)).width + padding.width);
2036 }
2037 break;
2038 }
2039
2041 uint64_t max_value = GetParamMaxValue(UINT_MAX);
2042 size.width = GetStringBoundingBox(GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL, max_value)).width;
2043 size.width = std::max(size.width, GetStringBoundingBox(GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD, max_value)).width);
2044 size.width = std::max(size.width, GetStringBoundingBox(GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_WATER, max_value)).width);
2045 size.width = std::max(size.width, GetStringBoundingBox(GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_STATION, max_value)).width);
2046 size.width = std::max(size.width, GetStringBoundingBox(GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT, max_value)).width);
2047 size.width = std::max(size.width, GetStringBoundingBox(GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_NONE, max_value)).width);
2048 size.width += padding.width;
2049 break;
2050 }
2051
2052 case WID_C_VIEW_HQ:
2053 case WID_C_BUILD_HQ:
2054 case WID_C_RELOCATE_HQ:
2056 case WID_C_GIVE_MONEY:
2058 case WID_C_COMPANY_JOIN:
2059 size.width = GetStringBoundingBox(STR_COMPANY_VIEW_VIEW_HQ_BUTTON).width;
2060 size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_BUILD_HQ_BUTTON).width);
2061 size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_RELOCATE_HQ).width);
2062 size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON).width);
2063 size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_GIVE_MONEY_BUTTON).width);
2064 size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_HOSTILE_TAKEOVER_BUTTON).width);
2065 size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_JOIN).width);
2066 size.width += padding.width;
2067 break;
2068 }
2069 }
2070
2071 void DrawVehicleCountsWidget(const Rect &r, const Company *c) const
2072 {
2074
2075 int y = r.top;
2076 for (VehicleType type = VEH_BEGIN; type < VEH_COMPANY_END; type++) {
2077 uint amount = c->group_all[type].num_vehicle;
2078 if (amount != 0) {
2079 DrawString(r.left, r.right, y, GetString(_company_view_vehicle_count_strings[type], amount));
2081 }
2082 }
2083
2084 if (y == r.top) {
2085 /* No String was emitted before, so there must be no vehicles at all. */
2086 DrawString(r.left, r.right, y, STR_COMPANY_VIEW_VEHICLES_NONE);
2087 }
2088 }
2089
2090 void DrawInfrastructureCountsWidget(const Rect &r, const Company *c) const
2091 {
2092 int y = r.top;
2093
2094 uint rail_pieces = c->infrastructure.signal + c->infrastructure.GetRailTotal();
2095 if (rail_pieces != 0) {
2096 DrawString(r.left, r.right, y, GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL, rail_pieces));
2098 }
2099
2100 /* GetRoadTotal() skips tram pieces, but we actually want road and tram here. */
2101 uint road_pieces = std::accumulate(std::begin(c->infrastructure.road), std::end(c->infrastructure.road), 0U);
2102 if (road_pieces != 0) {
2103 DrawString(r.left, r.right, y, GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD, road_pieces));
2105 }
2106
2107 if (c->infrastructure.water != 0) {
2108 DrawString(r.left, r.right, y, GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_WATER, c->infrastructure.water));
2110 }
2111
2112 if (c->infrastructure.station != 0) {
2113 DrawString(r.left, r.right, y, GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_STATION, c->infrastructure.station));
2115 }
2116
2117 if (c->infrastructure.airport != 0) {
2118 DrawString(r.left, r.right, y, GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT, c->infrastructure.airport));
2120 }
2121
2122 if (y == r.top) {
2123 /* No String was emitted before, so there must be no infrastructure at all. */
2124 DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE);
2125 }
2126 }
2127
2128 void DrawWidget(const Rect &r, WidgetID widget) const override
2129 {
2130 const Company *c = Company::Get(this->window_number);
2131 switch (widget) {
2132 case WID_C_FACE:
2134 break;
2135
2136 case WID_C_FACE_TITLE:
2137 DrawStringMultiLine(r, GetString(STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE, c->index), TC_FROMSTRING, SA_HOR_CENTER);
2138 break;
2139
2141 Point offset;
2142 Dimension d = GetSpriteSize(SPR_VEH_BUS_SW_VIEW, &offset);
2143 d.height -= offset.y;
2144 DrawSprite(SPR_VEH_BUS_SW_VIEW, GetCompanyPalette(c->index), r.left - offset.x, CentreBounds(r.top, r.bottom, d.height) - offset.y);
2145 break;
2146 }
2147
2149 DrawVehicleCountsWidget(r, c);
2150 break;
2151
2153 DrawInfrastructureCountsWidget(r, c);
2154 break;
2155 }
2156 }
2157
2158 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
2159 {
2160 switch (widget) {
2161 case WID_C_CAPTION:
2162 return GetString(STR_COMPANY_VIEW_CAPTION, this->window_number, this->window_number);
2163
2165 const Company &c = *Company::Get(this->window_number);
2167 return GetString(STR_COMPANY_VIEW_INAUGURATED_TITLE_WALLCLOCK, c.inaugurated_year_calendar, c.inaugurated_year);
2168 }
2169 return GetString(STR_COMPANY_VIEW_INAUGURATED_TITLE, c.inaugurated_year);
2170 }
2171
2173 return GetString(STR_COMPANY_VIEW_COMPANY_VALUE, CalculateCompanyValue(Company::Get(this->window_number)));
2174
2175 default:
2176 return this->Window::GetWidgetString(widget, stringid);
2177 }
2178 }
2179
2180 void OnResize() override
2181 {
2183 int y = GetStringHeight(GetString(STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE, this->owner), wid->current_x);
2184 if (wid->UpdateVerticalSize(y)) this->ReInit(0, 0);
2185 }
2186
2187 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2188 {
2189 switch (widget) {
2190 case WID_C_NEW_FACE: DoSelectCompanyManagerFace(this); break;
2191
2193 ShowCompanyLiveryWindow(this->window_number, GroupID::Invalid());
2194 break;
2195
2197 ShowQueryString(GetString(STR_PRESIDENT_NAME, this->window_number), STR_COMPANY_VIEW_PRESIDENT_S_NAME_QUERY_CAPTION, MAX_LENGTH_PRESIDENT_NAME_CHARS, this, CS_ALPHANUMERAL, {QueryStringFlag::EnableDefault, QueryStringFlag::LengthIsInChars});
2198 this->query_widget = WID_C_PRESIDENT_NAME;
2199 break;
2200
2201 case WID_C_COMPANY_NAME:
2202 ShowQueryString(GetString(STR_COMPANY_NAME, this->window_number), STR_COMPANY_VIEW_COMPANY_NAME_QUERY_CAPTION, MAX_LENGTH_COMPANY_NAME_CHARS, this, CS_ALPHANUMERAL, {QueryStringFlag::EnableDefault, QueryStringFlag::LengthIsInChars});
2203 this->query_widget = WID_C_COMPANY_NAME;
2204 break;
2205
2206 case WID_C_VIEW_HQ: {
2207 TileIndex tile = Company::Get(this->window_number)->location_of_HQ;
2208 if (_ctrl_pressed) {
2210 } else {
2212 }
2213 break;
2214 }
2215
2216 case WID_C_BUILD_HQ:
2217 if (this->window_number != _local_company) return;
2218 if (this->IsWidgetLowered(WID_C_BUILD_HQ)) {
2220 this->RaiseButtons();
2221 break;
2222 }
2223 SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, HT_RECT, this);
2224 SetTileSelectSize(2, 2);
2227 break;
2228
2229 case WID_C_RELOCATE_HQ:
2232 this->RaiseButtons();
2233 break;
2234 }
2235 SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, HT_RECT, this);
2236 SetTileSelectSize(2, 2);
2239 break;
2240
2243 break;
2244
2245 case WID_C_GIVE_MONEY:
2246 ShowQueryString({}, STR_COMPANY_VIEW_GIVE_MONEY_QUERY_CAPTION, 30, this, CS_NUMERAL, {});
2247 this->query_widget = WID_C_GIVE_MONEY;
2248 break;
2249
2252 break;
2253
2254 case WID_C_COMPANY_JOIN: {
2255 this->query_widget = WID_C_COMPANY_JOIN;
2256 CompanyID company = this->window_number;
2257 if (_network_server) {
2260 } else {
2261 /* just send the join command */
2262 NetworkClientRequestMove(company);
2263 }
2264 break;
2265 }
2266 }
2267 }
2268
2270 const IntervalTimer<TimerWindow> redraw_interval = {std::chrono::seconds(3), [this](auto) {
2271 this->SetDirty();
2272 }};
2273
2274 void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
2275 {
2276 if (Command<Commands::BuildObject>::Post(STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS, tile, OBJECT_HQ, 0) && !_shift_pressed) {
2278 this->RaiseButtons();
2279 }
2280 }
2281
2282 void OnPlaceObjectAbort() override
2283 {
2284 this->RaiseButtons();
2285 }
2286
2287 void OnQueryTextFinished(std::optional<std::string> str) override
2288 {
2289 CompanyWidgets widget = this->query_widget;
2290 this->query_widget = CompanyWindow::INVALID_QUERY_WIDGET;
2291
2292 if (!str.has_value()) return;
2293
2294 switch (widget) {
2295 default: NOT_REACHED();
2296
2297 case WID_C_GIVE_MONEY: {
2298 auto value = ParseInteger<uint64_t>(*str, 10, true);
2299 if (!value.has_value()) return;
2300 Money money = *value / GetCurrency().rate;
2301 Command<Commands::GiveMoney>::Post(STR_ERROR_CAN_T_GIVE_MONEY, money, this->window_number);
2302 break;
2303 }
2304
2306 Command<Commands::RenamePresident>::Post(STR_ERROR_CAN_T_CHANGE_PRESIDENT, *str);
2307 break;
2308
2309 case WID_C_COMPANY_NAME:
2310 Command<Commands::RenameCompany>::Post(STR_ERROR_CAN_T_CHANGE_COMPANY_NAME, *str);
2311 break;
2312 }
2313 }
2314
2315 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
2316 {
2317 if (!gui_scope) return;
2318
2319 /* Manually call OnResize to adjust minimum height of president name widget. */
2320 if (data == WID_C_PRESIDENT_NAME) this->OnResize();
2321
2322 /* If a query string is visible, update its default value. */
2323 if (this->query_widget != CompanyWindow::INVALID_QUERY_WIDGET && data == this->query_widget) {
2324 UpdateQueryStringDefault(GetString(data == WID_C_COMPANY_NAME ? STR_COMPANY_NAME : STR_PRESIDENT_NAME, this->window_number));
2325 }
2326 }
2327};
2328
2330 WDP_AUTO, "company", 0, 0,
2332 {},
2333 _nested_company_widgets
2334);
2335
2340void ShowCompany(CompanyID company)
2341{
2342 if (!Company::IsValidID(company)) return;
2343
2344 AllocateWindowDescFront<CompanyWindow>(_company_desc, company);
2345}
2346
2352{
2353 SetWindowDirty(WC_COMPANY, company);
2355}
2356
2357struct BuyCompanyWindow : Window {
2359 {
2360 this->InitNested(window_number);
2361
2362 const Company *c = Company::Get(this->window_number);
2363 this->company_value = hostile_takeover ? CalculateHostileTakeoverValue(c) : c->bankrupt_value;
2364 }
2365
2366 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2367 {
2368 switch (widget) {
2369 case WID_BC_FACE:
2370 size = GetScaledSpriteSize(SPR_GRADIENT);
2371 break;
2372
2373 case WID_BC_QUESTION:
2374 const Company *c = Company::Get(this->window_number);
2375 size.height = GetStringHeight(GetString(this->hostile_takeover ? STR_BUY_COMPANY_HOSTILE_TAKEOVER : STR_BUY_COMPANY_MESSAGE, c->index, this->company_value), size.width);
2376 break;
2377 }
2378 }
2379
2380 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
2381 {
2382 switch (widget) {
2383 case WID_BC_CAPTION:
2384 return GetString(STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY, Company::Get(this->window_number)->index);
2385
2386 default:
2387 return this->Window::GetWidgetString(widget, stringid);
2388 }
2389 }
2390
2391 void DrawWidget(const Rect &r, WidgetID widget) const override
2392 {
2393 switch (widget) {
2394 case WID_BC_FACE: {
2395 const Company *c = Company::Get(this->window_number);
2397 break;
2398 }
2399
2400 case WID_BC_QUESTION: {
2401 const Company *c = Company::Get(this->window_number);
2402 DrawStringMultiLine(r, GetString(this->hostile_takeover ? STR_BUY_COMPANY_HOSTILE_TAKEOVER : STR_BUY_COMPANY_MESSAGE, c->index, this->company_value), TC_FROMSTRING, SA_CENTER);
2403 break;
2404 }
2405 }
2406 }
2407
2408 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2409 {
2410 switch (widget) {
2411 case WID_BC_NO:
2412 this->Close();
2413 break;
2414
2415 case WID_BC_YES:
2416 Command<Commands::BuyCompany>::Post(STR_ERROR_CAN_T_BUY_COMPANY, this->window_number, this->hostile_takeover);
2417 break;
2418 }
2419 }
2420
2424 const IntervalTimer<TimerWindow> rescale_interval = {std::chrono::seconds(3), [this](auto) {
2425 /* Value can't change when in bankruptcy. */
2426 if (!this->hostile_takeover) return;
2427
2428 const Company *c = Company::Get(this->window_number);
2429 auto new_value = CalculateHostileTakeoverValue(c);
2430 if (new_value != this->company_value) {
2431 this->company_value = new_value;
2432 this->ReInit();
2433 }
2434 }};
2435
2436private:
2437 bool hostile_takeover = false;
2439};
2440
2441static constexpr std::initializer_list<NWidgetPart> _nested_buy_company_widgets = {
2445 EndContainer(),
2451 EndContainer(),
2455 EndContainer(),
2456 EndContainer(),
2457 EndContainer(),
2458};
2459
2460static WindowDesc _buy_company_desc(
2461 WDP_AUTO, {}, 0, 0,
2464 _nested_buy_company_widgets
2465);
2466
2472void ShowBuyCompanyDialog(CompanyID company, bool hostile_takeover)
2473{
2474 auto window = BringWindowToFrontById(WC_BUY_COMPANY, company);
2475 if (window == nullptr) {
2476 new BuyCompanyWindow(_buy_company_desc, company, hostile_takeover);
2477 }
2478}
constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T ToggleBit(T &x, const uint8_t y)
Toggles a bit in a variable.
constexpr T ClrBit(T &x, const uint8_t y)
Clears a bit in a variable.
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr Timpl & Set()
Set all bits.
Colour selection list item, with icon and string components.
bool masked
Masked and unselectable item.
Enum-as-bit-set wrapper.
void RebuildDone()
Notify the sortlist that the rebuild is done.
bool NeedRebuild() const
Check if a rebuild is needed.
void ForceRebuild()
Force that a rebuild is needed.
An interval timer will fire every interval, and will continue to fire until it is deleted.
Definition timer.h:76
Baseclass for nested widgets.
uint current_x
Current horizontal size (after resizing).
Base class for a 'real' widget.
void SetStringTip(StringID string, StringID tool_tip)
Set string and tool tip of the nested widget.
Definition widget.cpp:1195
Base class for a resizable nested widget.
bool UpdateVerticalSize(uint min_y)
Set absolute (post-scaling) minimal size of the widget.
Definition widget.cpp:1151
StringID name
Name of this rail type.
Definition rail.h:165
StringID name
Name of this rail type.
Definition road.h:77
Scrollbar data structure.
size_type GetCapacity() const
Gets the number of visible elements of the scrollbar.
void SetCount(size_t num)
Sets the number of elements in the list.
auto GetScrolledItemFromWidget(Tcontainer &container, int clickpos, const Window *const w, WidgetID widget, int padding=0, int line_height=-1) const
Return an iterator pointing to the element of a scrolled widget that a user clicked in.
size_type GetScrolledRowFromWidget(int clickpos, const Window *const w, WidgetID widget, int padding=0, int line_height=-1) const
Compute the row of a scrolled widget that a user clicked in.
Definition widget.cpp:2458
bool SetPosition(size_type position)
Sets the position of the first visible element.
void SetCapacityFromWidget(Window *w, WidgetID widget, int padding=0)
Set capacity of visible elements from the size and resize properties of a widget.
Definition widget.cpp:2532
size_type GetCount() const
Gets the number of elements in the list.
auto GetVisibleRangeIterators(Tcontainer &container) const
Get a pair of iterators for the range of visible elements in a container.
size_type GetPosition() const
Gets the position of the first visible element in the list.
Management class for customizing the face of the company manager.
void SelectDisplayPlanes(bool advanced)
Select planes to display to the user with the NWID_SELECTION widgets WID_SCMF_SEL_LOADSAVE,...
uint click_state
Click state on selected face variable.
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.
std::vector< const FaceVar * > face_vars
Visible face variables.
void OnResize() override
Called after the window got resized.
bool advanced
advanced company manager face selection window
uint selected_var
Currently selected face variable. UINT_MAX for none, UINT_MAX - 1 means style is clicked instead.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
CompanyManagerFace face
company manager face bits
int line_height
Height of each face variable row.
void UpdateData()
Make face bits valid and update visible face variables.
void OnQueryTextFinished(std::optional< std::string > str) override
The query window opened from this window has closed.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void OnTimeout() override
Called when this window's timeout has been reached.
void OnInit() override
Notification that the nested widget tree gets initialized.
static Year year
Current year, starting at 0.
static bool UsingWallclockUnits(bool newgame=false)
Check if we are using wallclock units.
StrongType::Typedef< int32_t, struct YearTag< struct Economy >, StrongType::Compare, StrongType::Integer > Year
RectPadding frametext
Padding inside frame with text.
Definition window_gui.h:41
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:30
int hsep_wide
Wide horizontal spacing.
Definition window_gui.h:62
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition window_gui.h:93
Functions related to commands.
Definition of stuff that is very close to a company, like the company struct itself.
Money CalculateHostileTakeoverValue(const Company *c)
Calculate what you have to pay to take over a company.
Definition economy.cpp:177
Money CalculateCompanyValue(const Company *c, bool including_loan=true)
Calculate the value of the company.
Definition economy.cpp:150
std::optional< CompanyManagerFace > ParseCompanyManagerFaceCode(std::string_view str)
Parse a face code into a company manager face.
FaceVars GetCompanyManagerFaceVars(uint style)
Get the face variables for a face style.
void RandomiseCompanyManagerFace(CompanyManagerFace &cmf, Randomizer &randomizer)
Completely randomise a company manager face, including style.
std::string _company_manager_face
for company manager face storage in openttd.cfg
PaletteID GetCompanyPalette(CompanyID company)
Get the palette for recolouring with a company colour.
void SetCompanyManagerFaceStyle(CompanyManagerFace &cmf, uint style)
Set a company face style.
uint GetNumCompanyManagerFaceStyles()
Get the number of company manager face styles.
std::string FormatCompanyManagerFaceCode(const CompanyManagerFace &cmf)
Get a face code representation of a company manager face.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Command definitions related to companies.
Functions related to companies.
void ShowCompanyFinances(CompanyID company)
Open the finances window of a company.
static Money DrawYearCategory(const Rect &r, int start_y, const ExpensesList &list, const Expenses &tbl)
Draw a category of expenses/revenues in the year column.
static uint GetMaxCategoriesWidth()
Get the required width of the "categories" column, equal to the widest element.
constexpr uint8_t GetColourOffset(const Livery &l, bool primary)
Get either the primary or secondary colour of the given Livery for offsets.
static WindowDesc _select_company_manager_face_desc(WDP_AUTO, {}, 0, 0, WC_COMPANY_MANAGER_FACE, WC_NONE, WindowDefaultFlag::Construction, _nested_select_company_manager_face_widgets)
Company manager face selection window description.
static void DrawYearColumn(const Rect &r, TimerGameEconomy::Year year, const Expenses &tbl)
Draw a column with prices.
static const std::initializer_list< ExpensesType > _expenses_list_capital_costs
List of capital expenses.
void ShowBuyCompanyDialog(CompanyID company, bool hostile_takeover)
Show the query to buy another company.
static const StringID _company_view_vehicle_count_strings[]
Strings for the company vehicle counts.
static const std::initializer_list< ExpensesList > _expenses_list_types
Types of expense lists.
static void DrawPrice(Money amount, int left, int right, int top, TextColour colour)
Draw an amount of money.
static void ShowCompanyInfrastructure(CompanyID company)
Open the infrastructure window of a company.
static void DrawCategories(const Rect &r)
Draw the expenses categories.
static void DoSelectCompanyManagerFace(Window *parent)
Company GUI constants.
void ShowCompany(CompanyID company)
Show the window with the overview of the company.
static const std::initializer_list< ExpensesType > _expenses_list_operating_costs
List of operating expenses.
static uint GetTotalCategoriesHeight()
Get the total height of the "categories" column.
static constexpr std::initializer_list< NWidgetPart > _nested_select_company_manager_face_widgets
Nested widget description for the company manager face selection dialog.
static const LiveryClass _livery_class[LS_END]
Association of liveries to livery classes.
static const std::initializer_list< ExpensesType > _expenses_list_revenue
List of revenues.
void DirtyCompanyInfrastructureWindows(CompanyID company)
Redraw all windows with company infrastructure counts.
void DrawCompanyManagerFace(const CompanyManagerFace &cmf, Colours colour, const Rect &r)
Draws the face of a company manager's face.
static void DrawCategory(const Rect &r, int start_y, const ExpensesList &list)
Draw a category of expenses (revenue, operating expenses, capital expenses).
Functionality related to the company manager's face.
@ Palette
FaceVar describes a palette to apply to the given parts bitmask.
@ Sprite
FaceVar describes an offset to the given SpriteID.
@ Toggle
FaceVar describes which other FaceVars should be turned off.
uint64_t GetActiveFaceVars(const CompanyManagerFace &cmf, FaceVars vars)
Get a bitmask of currently active face variables.
void ScaleAllCompanyManagerFaceBits(CompanyManagerFace &cmf, FaceVars vars)
Scales all company manager's face bits to the correct scope.
static const SaveLoad _company_desc[]
Save/load of companies.
static const uint MAX_LENGTH_PRESIDENT_NAME_CHARS
The maximum length of a president name in characters including '\0'.
static const uint MAX_LENGTH_COMPANY_NAME_CHARS
The maximum length of a company name in characters including '\0'.
static constexpr CompanyID COMPANY_SPECTATOR
The client is spectating.
Types related to the company widgets.
@ WID_CF_CAPTION
Caption of the window.
@ WID_CF_SEL_BUTTONS
Selection of buttons.
@ WID_CF_SEL_PANEL
Select panel or nothing.
@ WID_CF_EXPS_CATEGORY
Column for expenses category strings.
@ WID_CF_EXPS_PRICE1
Column for year Y-2 expenses.
@ WID_CF_INFRASTRUCTURE
View company infrastructure.
@ WID_CF_TOGGLE_SIZE
Toggle windows size.
@ WID_CF_EXPS_PRICE2
Column for year Y-1 expenses.
@ WID_CF_OWN_VALUE
Own funds, not including loan.
@ WID_CF_LOAN_VALUE
Loan.
@ WID_CF_INCREASE_LOAN
Increase loan.
@ WID_CF_INTEREST_RATE
Loan interest rate.
@ WID_CF_BALANCE_VALUE
Bank balance value.
@ WID_CF_EXPS_PRICE3
Column for year Y expenses.
@ WID_CF_BALANCE_LINE
Available cash.
@ WID_CF_REPAY_LOAN
Decrease loan..
@ WID_CF_SEL_MAXLOAN
Selection of maxloan column.
@ WID_CF_MAXLOAN_VALUE
Max loan widget.
@ WID_BC_NO
No button.
@ WID_BC_YES
Yes button.
@ WID_BC_QUESTION
Question text.
@ WID_BC_CAPTION
Caption of window.
@ WID_BC_FACE
Face button.
@ WID_SCMF_CAPTION
Caption of window.
@ WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON
Toggle for large or small.
@ WID_SCMF_STYLE
Style selector widget.
@ WID_SCMF_SEL_RESIZE
Selection to display the resize button.
@ WID_SCMF_SELECT_FACE
Select face.
@ WID_SCMF_RANDOM_NEW_FACE
Create random new face.
@ WID_SCMF_SEL_PARTS
Selection to display the buttons for setting each part of the face in the advanced view.
@ WID_SCMF_PARTS_SCROLLBAR
Scrollbar for configuration parts widget.
@ WID_SCMF_CANCEL
Cancel.
@ WID_SCMF_SAVE
Save face.
@ WID_SCMF_SEL_LOADSAVE
Selection to display the load/save/number buttons in the advanced view.
@ WID_SCMF_FACE
Current face.
@ WID_SCMF_LOAD
Load face.
@ WID_SCMF_ACCEPT
Accept.
@ WID_SCMF_TOGGLE_LARGE_SMALL
Toggle for large or small.
@ WID_SCMF_FACECODE
Get the face code.
@ WID_SCMF_PARTS
Face configuration parts widget.
@ WID_SCL_CLASS_AIRCRAFT
Class aircraft.
@ WID_SCL_MATRIX_SCROLLBAR
Matrix scrollbar.
@ WID_SCL_CLASS_SHIP
Class ship.
@ WID_SCL_SEC_COL_DROP_SEL
Container for secondary color dropdown, which can be hidden.
@ WID_SCL_GROUPS_SHIP
Ship groups.
@ WID_SCL_GROUPS_ROAD
Road groups.
@ WID_SCL_CLASS_ROAD
Class road.
@ WID_SCL_GROUPS_AIRCRAFT
Aircraft groups.
@ WID_SCL_SEC_COL_DROPDOWN
Dropdown for secondary colour.
@ WID_SCL_SPACER_DROPDOWN
Spacer for dropdown.
@ WID_SCL_GROUPS_RAIL
Rail groups.
@ WID_SCL_PRI_COL_DROPDOWN
Dropdown for primary colour.
@ WID_SCL_CLASS_RAIL
Class rail.
@ WID_SCL_MATRIX
Matrix.
@ WID_SCL_CAPTION
Caption of window.
@ WID_SCL_CLASS_GENERAL
Class general.
@ WID_CI_SCROLLBAR
Infrastructure list scrollbar.
@ WID_CI_CAPTION
Caption of window.
@ WID_CI_LIST
Infrastructure list.
CompanyWidgets
Widgets of the CompanyWindow class.
@ WID_C_SELECT_VIEW_BUILD_HQ
Panel about HQ.
@ WID_C_DESC_INFRASTRUCTURE_COUNTS
Infrastructure count.
@ WID_C_DESC_VEHICLE
Vehicles.
@ WID_C_COLOUR_SCHEME
Button to change colour scheme.
@ WID_C_CAPTION
Caption of the window.
@ WID_C_VIEW_HQ
Button to view the HQ.
@ WID_C_SELECT_RELOCATE
Panel about 'Relocate HQ'.
@ WID_C_SELECT_BUTTONS
Selection widget for the button bar.
@ WID_C_VIEW_INFRASTRUCTURE
Panel about infrastructure.
@ WID_C_SELECT_HOSTILE_TAKEOVER
Selection widget for the hostile takeover button.
@ WID_C_SELECT_GIVE_MONEY
Selection widget for the give money button.
@ WID_C_DESC_COLOUR_SCHEME
Colour scheme.
@ WID_C_GIVE_MONEY
Button to give money.
@ WID_C_SELECT_MULTIPLAYER
Multiplayer selection panel.
@ WID_C_DESC_INAUGURATION
Inauguration.
@ WID_C_DESC_COLOUR_SCHEME_EXAMPLE
Colour scheme example.
@ WID_C_BUILD_HQ
Button to build the HQ.
@ WID_C_HOSTILE_TAKEOVER
Button to hostile takeover another company.
@ WID_C_DESC_INFRASTRUCTURE
Infrastructure.
@ WID_C_FACE_TITLE
Title for the face.
@ WID_C_DESC_COMPANY_VALUE
Company value.
@ WID_C_COMPANY_JOIN
Button to join company.
@ WID_C_PRESIDENT_NAME
Button to change president name.
@ WID_C_DESC_VEHICLE_COUNTS
Vehicle count.
@ WID_C_NEW_FACE
Button to make new face.
@ WID_C_FACE
View of the face.
@ WID_C_RELOCATE_HQ
Button to relocate the HQ.
@ WID_C_COMPANY_NAME
Button to change company name.
Functions to handle different currencies.
const CurrencySpec & GetCurrency()
Get the currently selected currency.
Definition currency.h:119
void ShowDropDownList(Window *w, DropDownList &&list, int selected, WidgetID button, uint width, DropDownOptions options, std::string *const persistent_filter_text)
Show a drop down list.
Definition dropdown.cpp:587
Common drop down list components.
Types related to the drop down widget.
std::vector< std::unique_ptr< const DropDownListItem > > DropDownList
A drop down list is a collection of drop down list items.
Command definitions related to the economy.
std::array< Money, EXPENSES_END > Expenses
Data type for storage of Money for each ExpensesType category.
ExpensesType
Types of expenses.
@ EXPENSES_ROADVEH_RUN
Running costs road vehicles.
@ EXPENSES_TRAIN_RUN
Running costs trains.
@ EXPENSES_AIRCRAFT_REVENUE
Revenue from aircraft.
@ EXPENSES_CONSTRUCTION
Construction costs.
@ EXPENSES_AIRCRAFT_RUN
Running costs aircraft.
@ EXPENSES_ROADVEH_REVENUE
Revenue from road vehicles.
@ EXPENSES_PROPERTY
Property costs.
@ EXPENSES_OTHER
Other expenses.
@ EXPENSES_SHIP_REVENUE
Revenue from ships.
@ EXPENSES_LOAN_INTEREST
Interest payments over the loan.
@ EXPENSES_TRAIN_REVENUE
Revenue from trains.
@ EXPENSES_SHIP_RUN
Running costs ships.
@ EXPENSES_NEW_VEHICLES
New vehicles.
static const int LOAN_INTERVAL
The "steps" in loan size, in British Pounds!
Base class for engines.
constexpr std::underlying_type_t< enum_type > to_underlying(enum_type e)
Implementation of std::to_underlying (from C++23).
Definition enum_type.hpp:21
Functions related to errors.
@ WL_INFO
Used for DoCommand-like (and some non-fatal AI GUI) errors/information.
Definition error.h:24
void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, CommandCost &cc)
Display an error message in a window.
int GetCharacterHeight(FontSize size)
Get height of a character for a given font size.
Definition fontcache.cpp:88
Dimension maxdim(const Dimension &d1, const Dimension &d2)
Compute bounding box of both dimensions.
Geometry functions.
int CentreBounds(int min, int max, int size)
Determine where to position a centred object.
int GetStringHeight(std::string_view str, int maxw, FontSize fontsize)
Calculates height of string (in pixels).
Definition gfx.cpp:717
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition gfx.cpp:972
bool _shift_pressed
Is Shift pressed?
Definition gfx.cpp:40
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:900
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.
Definition gfx.cpp:669
bool _ctrl_pressed
Is Ctrl pressed?
Definition gfx.cpp:39
uint GetStringListWidth(std::span< const StringID > list, FontSize fontsize)
Get maximum width of a list of strings.
Definition gfx.cpp:924
void DrawSprite(SpriteID img, PaletteID pal, int x, int y, const SubSprite *sub, ZoomLevel zoom)
Draw a sprite, not in a viewport.
Definition gfx.cpp:1038
int DrawStringMultiLine(int left, int right, int top, int bottom, std::string_view str, TextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly over multiple lines.
Definition gfx.cpp:788
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.
Definition gfx.cpp:116
Dimension GetScaledSpriteSize(SpriteID sprid)
Scale sprite size for GUI.
Definition widget.cpp:70
@ Normal
Index of the normal font in the font tables.
Definition gfx_type.h:249
@ SA_TOP
Top align the text.
Definition gfx_type.h:393
@ SA_LEFT
Left align the text.
Definition gfx_type.h:388
@ SA_RIGHT
Right align the text (must be a single bit).
Definition gfx_type.h:390
@ SA_HOR_CENTER
Horizontally center the text.
Definition gfx_type.h:389
@ SA_FORCE
Force the alignment, i.e. don't swap for RTL languages.
Definition gfx_type.h:400
@ SA_CENTER
Center both horizontally and vertically.
Definition gfx_type.h:398
@ SA_VERT_CENTER
Vertically center the text.
Definition gfx_type.h:394
uint32_t PaletteID
The number of the palette.
Definition gfx_type.h:18
Colours
One of 16 base colours used for companies and windows/widgets.
Definition gfx_type.h:283
@ Begin
Begin marker.
Definition gfx_type.h:284
@ Invalid
Invalid marker.
Definition gfx_type.h:302
@ LightBlue
Light blue.
Definition gfx_type.h:290
@ Yellow
Yellow.
Definition gfx_type.h:288
@ End
End-of-array marker.
Definition gfx_type.h:301
@ Grey
Grey.
Definition gfx_type.h:299
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition gfx_type.h:307
constexpr NWidgetPart SetMatrixDataTip(uint32_t cols, uint32_t rows, StringID tip={})
Widget part function for setting the data and tooltip of WWT_MATRIX widgets.
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
constexpr NWidgetPart SetSpriteTip(SpriteID sprite, StringID tip={})
Widget part function for setting the sprite and tooltip.
constexpr NWidgetPart SetToolbarMinimalSize(int width)
Widget part function to setting the minimal size for a toolbar button.
constexpr NWidgetPart SetPIP(uint8_t pre, uint8_t inter, uint8_t post)
Widget part function for setting a pre/inter/post spaces.
constexpr NWidgetPart SetScrollbar(WidgetID index)
Attach a scrollbar to a widget.
constexpr NWidgetPart SetPadding(uint8_t top, uint8_t right, uint8_t bottom, uint8_t left)
Widget part function for setting additional space around a widget.
constexpr NWidgetPart SetStringTip(StringID string, StringID tip={})
Widget part function for setting the string and tooltip.
constexpr NWidgetPart SetAspect(float ratio, AspectFlags flags=AspectFlag::ResizeX)
Widget part function for setting the aspect ratio.
constexpr NWidgetPart SetMinimalTextLines(uint8_t lines, uint8_t spacing, FontSize size=FontSize::Normal)
Widget part function for setting the minimal text lines.
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
constexpr NWidgetPart SetToolTip(StringID tip)
Widget part function for setting tooltip and clearing the widget data.
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=INVALID_WIDGET)
Widget part function for starting a new 'real' widget.
constexpr NWidgetPart SetAlignment(StringAlignment align)
Widget part function for setting the alignment of text/images.
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
constexpr NWidgetPart SetPIPRatio(uint8_t ratio_pre, uint8_t ratio_inter, uint8_t ratio_post)
Widget part function for setting a pre/inter/post ratio.
Command definitions related to engine groups.
void SetDirty() const
Mark entire window as dirty (in need of re-paint).
Definition window.cpp:980
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition gfx.cpp:1554
void BuildGuiGroupList(GUIGroupList &list, bool fold, Owner owner, VehicleType veh_type)
Build GUI group list, a sorted hierarchical list of groups for owner and vehicle type.
Functions/definitions that have something to do with groups.
GUI functions that shouldn't be here.
void ShowExtraViewportWindow(TileIndex tile=INVALID_TILE)
Show a new Extra Viewport window.
static const uint8_t LIT_ALL
Show the liveries of all companies.
Definition livery.h:19
LiveryScheme
List of different livery schemes.
Definition livery.h:22
static const uint8_t LIT_COMPANY
Show the liveries of your own company.
Definition livery.h:18
LiveryClass
List of different livery classes, used only by the livery GUI.
Definition livery.h:64
#define Rect
Macro that prevents name conflicts between included headers.
#define Point
Macro that prevents name conflicts between included headers.
constexpr bool IsInsideBS(const T x, const size_t base, const size_t size)
Checks if a value is between a window started at some base point.
Miscellaneous command definitions.
@ Max
Loan/repay the maximum amount permitting money/settings.
Definition misc_cmd.h:20
@ Interval
Loan/repay LOAN_INTERVAL.
Definition misc_cmd.h:19
void ShowQueryString(std::string_view str, StringID caption, uint maxsize, Window *parent, CharSetFilter afilter, QueryStringFlags flags)
Show a query popup window with a textbox in it.
void UpdateQueryStringDefault(std::string_view str)
Updates default text value of query strign window.
bool _networking
are we in networking mode?
Definition network.cpp:67
bool _network_server
network-server is active
Definition network.cpp:68
bool NetworkCanJoinCompany(CompanyID company_id)
Returns whether the given company can be joined by this client.
Definition network.cpp:143
Basic functions/variables used all over the place.
void NetworkClientRequestMove(CompanyID company_id)
Notify the server of this client wanting to be moved to another company.
Network functions used by other parts of OpenTTD.
void NetworkServerDoMove(ClientID client_id, CompanyID company_id)
Handle the tid-bits of moving a client from one company to another.
GUIs related to networking.
@ CLIENT_ID_SERVER
Servers always have this ID.
GRFLoadedFeatures _loaded_newgrf_features
Indicates which are the newgrf features currently loaded ingame.
Definition newgrf.cpp:75
Base for the NewGRF implementation.
@ Company
Company news item. (Newspaper with face).
Definition news_type.h:82
Command definitions related to objects.
Types related to object tiles.
static const ObjectType OBJECT_HQ
HeadQuarter of a player.
Definition object_type.h:22
static constexpr PixelColour PC_BLACK
Black palette colour.
static constexpr PixelColour PC_WHITE
White palette colour.
Rail specific functions.
std::vector< RailType > _sorted_railtypes
Sorted list of rail types.
Definition rail_cmd.cpp:47
Money RailMaintenanceCost(RailType railtype, uint32_t num, uint32_t total_num)
Calculates the maintenance cost of a number of track bits.
Definition rail.h:484
Money SignalMaintenanceCost(uint32_t num)
Calculates the maintenance cost of a number of signals.
Definition rail.h:495
const RailTypeInfo * GetRailTypeInfo(RailType railtype)
Returns a pointer to the Railtype information for a given railtype.
Definition rail.h:301
RailType
Enumeration for all possible railtypes.
Definition rail_type.h:25
Randomizer _interactive_random
Random used everywhere else, where it does not (directly) influence the game state.
Road specific functions.
const RoadTypeInfo * GetRoadTypeInfo(RoadType roadtype)
Returns a pointer to the Roadtype information for a given roadtype.
Definition road.h:215
std::vector< RoadType > _sorted_roadtypes
Sorted list of road types.
Definition road_cmd.cpp:55
Functions related to roads.
Money RoadMaintenanceCost(RoadType roadtype, uint32_t num, uint32_t total_num)
Calculates the maintenance cost of a number of road bits.
Definition road_func.h:125
RoadType
The different roadtypes we support.
Definition road_type.h:23
A number of safeguards to prevent using unsafe methods.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:61
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
void DrawArrowButtons(int x, int y, Colours button_colour, uint8_t state, bool clickable_left, bool clickable_right)
Draw [<][>] boxes.
void DrawBoolButton(int x, int y, Colours button_colour, Colours background, bool state, bool clickable)
Draw a toggle button.
Functions for setting GUIs.
#define SETTING_BUTTON_WIDTH
Width of setting buttons.
#define SETTING_BUTTON_HEIGHT
Height of setting buttons.
Base types for having sorted lists in GUIs.
static PaletteID GetColourPalette(Colours colour)
Get recolour palette for a colour.
Definition sprite.h:221
Money AirportMaintenanceCost(Owner owner)
Calculates the maintenance cost of all airports of a company.
Definition station.cpp:716
Functions related to stations.
Money StationMaintenanceCost(uint32_t num)
Calculates the maintenance cost of a number of station tiles.
Definition of base types and functions in a cross-platform compatible way.
#define lengthof(array)
Return the length of an fixed size array.
Definition stdafx.h:271
Parse strings.
static std::optional< T > ParseInteger(std::string_view arg, int base=10, bool clamp=false)
Change a string into its number representation.
@ CS_NUMERAL
Only numeric ones.
Definition string_type.h:26
@ CS_ALPHANUMERAL
Both numeric and alphabetic and spaces and stuff.
Definition string_type.h:25
uint64_t GetParamMaxValue(uint64_t max_value, uint min_count, FontSize size)
Get some number that is suitable for string size computations.
Definition strings.cpp:236
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:90
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:424
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition strings.cpp:56
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.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
Money company_value
The value of the company for which the user can buy it.
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
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.
bool hostile_takeover
Whether the window is showing a hostile takeover.
const IntervalTimer< TimerWindow > rescale_interval
Check on a regular interval if the company value has changed.
Window class displaying the company finances.
const IntervalTimer< TimerWindow > rescale_interval
Check on a regular interval if the maximum amount of money has changed.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
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 OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void OnInvalidateData(int, bool) 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.
bool small
Window is toggled to 'small'.
static Money max_money
The maximum amount of money a company has had this 'run'.
uint8_t first_visible
First visible expenses column. The last column (current) is always visible.
void SetupWidgets()
Setup the widgets in the nested tree, such that the finances window is displayed properly.
void OnPaint() override
The window must be repainted.
void OnInit() override
Notification that the nested widget tree gets initialized.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
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 FindWindowPlacementAndResize(int def_width, int def_height, bool allow_resize) override
Resize window towards the default size.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
void OnResize() override
Called after the window got resized.
std::array< uint32_t, ROADTYPE_END > road
Count of company owned track bits for each road type.
uint32_t GetRailTotal() const
Get total sum of all owned track bits.
uint32_t station
Count of company owned station tiles.
uint32_t signal
Count of company owned signals.
std::array< uint32_t, RAILTYPE_END > rail
Count of company owned track bits for each rail type.
uint32_t airport
Count of company owned airports.
uint32_t water
Count of company owned track bits for canals.
uint style
Company manager face style.
TileIndex location_of_HQ
Northern tile of HQ; INVALID_TILE when there is none.
bool is_ai
If true, the company is (also) controlled by the computer (a NoAI program).
Money current_loan
Amount of money borrowed from the bank.
TimerGameCalendar::Year inaugurated_year_calendar
Calendar year of starting the company. Used to display proper Inauguration year while in wallclock mo...
TimerGameEconomy::Year inaugurated_year
Economy year of starting the company.
Colours colour
Company colour.
CompanyManagerFace face
Face description of the president.
std::array< Expenses, 3 > yearly_expenses
Expenses of the company for the last three years.
Money money
Money owned by the company.
Window with general information about a company.
void OnResize() override
Called after the window got resized.
const IntervalTimer< TimerWindow > redraw_interval
Redraw the window on a regular interval.
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.
static constexpr CompanyWidgets INVALID_QUERY_WIDGET
WID_C_CAPTION does not have a query string, so it can be safely used as invalid value.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
void OnPlaceObjectAbort() override
The user cancelled a tile highlight mode that has been set.
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
void OnPlaceObject(Point pt, TileIndex tile) override
The user clicked some place on the map when a tile highlight mode has been set.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
void OnQueryTextFinished(std::optional< std::string > str) override
The query window opened from this window has closed.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
CompanyWindowPlanes
Display planes in the company window.
@ CWP_RELOCATE_SHOW
Show the relocate HQ button.
@ CWP_RELOCATE_HIDE
Hide the relocate HQ button.
@ CWP_VB_BUILD
Display the build button.
@ CWP_VB_VIEW
Display the view button.
void OnPaint() override
The window must be repainted.
Money GetMaxLoan() const
Calculate the max allowed loan for this company.
CompanyInfrastructure infrastructure
NOSAVE: Counts of company owned infrastructure.
std::array< GroupStatistics, VEH_COMPANY_END > group_all
NOSAVE: Statistics for the ALL_GROUP group.
T y
Y coordinate.
T x
X coordinate.
uint16_t rate
The conversion rate compared to the base currency.
Definition currency.h:78
Dimensions (a width and height) of a rectangle in 2D.
bool infrastructure_maintenance
enable monthly maintenance fee for owner infrastructure
Expense list container.
uint GetListWidth() const
Compute width of the expenses categories.
const std::initializer_list< ExpensesType > & items
List of expenses types.
const StringID title
StringID of list title.
Information about the valid values of CompanyManagerFace bitgroups as well as the sprites to draw.
uint8_t position
Position in UI.
FaceVarType type
Type of variable.
StringID name
Name of the configurable component of the face.
uint8_t valid_values
The number of valid values.
EconomySettings economy
settings to change the economy
Group data.
Definition group.h:74
Livery livery
Custom colour scheme for vehicles in this group.
Definition group.h:80
GroupID parent
Parent group.
Definition group.h:86
VehicleType vehicle_type
Vehicle type of the group.
Definition group.h:77
Information about a particular livery.
Definition livery.h:79
Flags in_use
Livery flags.
Definition livery.h:87
Colours colour2
Second colour, for vehicles with 2CC support.
Definition livery.h:89
Colours colour1
First colour, for all vehicles.
Definition livery.h:88
@ Primary
Primary colour is set.
Definition livery.h:82
@ Secondary
Secondary colour is set.
Definition livery.h:83
static Pool::IterateWrapper< Company > Iterate(size_t from=0)
static Company * Get(auto index)
static Company * GetIfValid(auto index)
constexpr uint Horizontal() const
Get total horizontal 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 CentreToHeight(int height) const
Centre a vertical dimension within this Rect.
int Height() const
Get height of Rect.
Rect Translate(int x, int y) const
Copy and translate Rect by x,y pixels.
Company livery colour scheme window.
void OnDropdownSelect(WidgetID widget, int index, int) override
A dropdown option associated to this window has been selected.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
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 OnPaint() override
The window must be repainted.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
void OnClick(Point pt, WidgetID widget, int click_count) override
A click with the left mouse button has been made on the window.
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a widget.
void OnResize() override
Called after the window got resized.
Iterable ensemble of each set bit in a value.
High level window description.
Definition window_gui.h:168
Number to differentiate different windows of the same class.
Data structure for an opened window.
Definition window_gui.h:274
void ReInit(int rx=0, int ry=0, bool reposition=false)
Re-initialize a window, and optionally change its size.
Definition window.cpp:992
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
Definition window.cpp:1117
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1822
void DrawWidgets() const
Paint all widgets of a window.
Definition widget.cpp:786
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing).
Definition window.cpp:3262
Window * parent
Parent window.
Definition window_gui.h:329
void RaiseWidget(WidgetID widget_index)
Marks a widget as raised.
Definition window_gui.h:470
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition window.cpp:570
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
Definition window.cpp:518
ResizeInfo resize
Resize information.
Definition window_gui.h:315
void SetShaded(bool make_shaded)
Set the shaded state of the window to make_shaded.
Definition window.cpp:1035
void SetWidgetsDisabledState(bool disab_stat, Args... widgets)
Sets the enabled/disabled status of a list of widgets.
Definition window_gui.h:516
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1812
bool IsWidgetLowered(WidgetID widget_index) const
Gets the lowered state of a widget.
Definition window_gui.h:492
void RaiseButtons(bool autoraise=false)
Raise the buttons of the window.
Definition window.cpp:544
Owner owner
The owner of the content shown in this window. Company colour is acquired from this variable.
Definition window_gui.h:317
void EnableWidget(WidgetID widget_index)
Sets a widget to Enabled.
Definition window_gui.h:401
virtual void FindWindowPlacementAndResize(int def_width, int def_height, bool allow_resize)
Resize window towards the default size.
Definition window.cpp:1490
bool IsShaded() const
Is window shaded currently?
Definition window_gui.h:563
void SetTimeout()
Set the timeout flag of the window and initiate the timer.
Definition window_gui.h:356
Window(WindowDesc &desc)
Empty constructor, initialization has been moved to InitNested() called from the constructor of the d...
Definition window.cpp:1846
const NWID * GetWidget(WidgetID widnum) const
Get the nested widget with number widnum from the nested widget tree.
Definition window_gui.h:990
void LowerWidget(WidgetID widget_index)
Marks a widget as lowered.
Definition window_gui.h:461
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition window.cpp:1836
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition window.cpp:327
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition window_gui.h:382
int height
Height of the window (number of pixels down in y direction).
Definition window_gui.h:313
int width
width of the window (number of pixels to the right in x direction)
Definition window_gui.h:312
WindowNumber window_number
Window number within the window class.
Definition window_gui.h:303
Stuff related to the text buffer GUI.
@ EnableDefault
enable the 'Default' button ("\0" is returned)
Definition textbuf_gui.h:20
@ LengthIsInChars
the length of the string is counted in characters
Definition textbuf_gui.h:21
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > > TileIndex
The index/ID of a Tile.
Definition tile_type.h:92
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:100
Functions related to tile highlights.
void ResetObjectToPlace()
Reset the cursor and mouse mode handling back to default (normal cursor, only clicking in windows).
void SetObjectToPlaceWnd(CursorID icon, PaletteID pal, HighLightStyle mode, Window *w)
Change the cursor and mouse click/drag handling to a mode for performing special operations like tile...
@ HT_RECT
rectangle (stations, depots, ...)
Definition of Interval and OneShot timers.
Definition of the game-economy-timer.
Definition of the Window system.
VehicleType
Available vehicle types.
@ VEH_ROAD
Road vehicle type.
@ VEH_AIRCRAFT
Aircraft vehicle type.
@ VEH_SHIP
Ship vehicle type.
@ VEH_TRAIN
Train vehicle type.
@ VEH_COMPANY_END
Last company-ownable type.
void SetTileSelectSize(int w, int h)
Highlight w by h tiles at the cursor.
bool ScrollMainWindowToTile(TileIndex tile, bool instant)
Scrolls the viewport of the main window to a given location.
Functions related to (drawing on) viewports.
Functions related to water management.
Money CanalMaintenanceCost(uint32_t num)
Calculates the maintenance cost of a number of canal tiles.
Definition water.h:53
@ WWT_PUSHTXTBTN
Normal push-button (no toggle button) with text caption.
@ WWT_IMGBTN
(Toggle) Button with image
Definition widget_type.h:41
@ WWT_LABEL
Centered label.
Definition widget_type.h:48
@ NWID_SPACER
Invisible widget that takes some space.
Definition widget_type.h:70
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:66
@ WWT_TEXTBTN
(Toggle) Button with text
Definition widget_type.h:44
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:39
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX).
Definition widget_type.h:57
@ WWT_MATRIX
Grid of rows and columns.
Definition widget_type.h:50
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX).
Definition widget_type.h:55
@ WWT_CAPTION
Window caption (window title between closebox and stickybox).
Definition widget_type.h:52
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition widget_type.h:76
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:68
@ WWT_CLOSEBOX
Close box (at top-left of a window).
Definition widget_type.h:60
@ WWT_EMPTY
Empty widget, place holder to reserve space in widget tree.
Definition widget_type.h:37
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window).
Definition widget_type.h:59
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX).
Definition widget_type.h:56
@ WWT_DROPDOWN
Drop down list.
Definition widget_type.h:61
@ WWT_TEXT
Pure simple text.
Definition widget_type.h:49
@ NWID_SELECTION
Stacked widgets, only one visible at a time (eg in a panel with tabs).
Definition widget_type.h:71
@ SZSP_HORIZONTAL
Display plane with zero size vertically, and filling and resizing horizontally.
@ SZSP_NONE
Display plane with zero size in both directions (none filling and resizing).
@ EqualSize
Containers should keep all their (resizing) children equally large.
Window * BringWindowToFrontById(WindowClass cls, WindowNumber number)
Find a window and make it the relative top-window on the screen.
Definition window.cpp:1293
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting).
Definition window.cpp:3200
Window functions not directly related to making/drawing windows.
Functions, definitions and such used only by the GUI.
@ Construction
This window is used for construction; close it whenever changing company.
Definition window_gui.h:153
Twindow * AllocateWindowDescFront(WindowDesc &desc, WindowNumber window_number, Targs... extra_arguments)
Open a new window.
@ WDP_AUTO
Find a place automatically.
Definition window_gui.h:144
int WidgetID
Widget ID.
Definition window_type.h:21
@ WC_BUY_COMPANY
Buyout company (merger); Window numbers:
@ WC_COMPANY_INFRASTRUCTURE
Company infrastructure overview; Window numbers:
@ WC_COMPANY_COLOUR
Company colour selection; Window numbers:
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition window_type.h:51
@ WC_FINANCES
Finances of a company; Window numbers:
@ WC_COMPANY_MANAGER_FACE
Alter company face window; Window numbers:
@ WC_COMPANY
Company view; Window numbers:
Functions related to zooming.