OpenTTD Source 20260512-master-g20b387b91f
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
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 + to_underlying(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 + to_underlying(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
569 WindowPosition::Automatic, "company_finances", 0, 0,
571 {},
572 _nested_company_finances_widgets
573);
574
580void ShowCompanyFinances(CompanyID company)
581{
582 if (!Company::IsValidID(company)) return;
583 if (BringWindowToFrontById(WC_FINANCES, company)) return;
584
586}
587
589static const LiveryClass _livery_class[LS_END] = {
590 LC_OTHER,
591 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,
592 LC_ROAD, LC_ROAD,
593 LC_SHIP, LC_SHIP,
594 LC_AIRCRAFT, LC_AIRCRAFT, LC_AIRCRAFT,
595 LC_ROAD, LC_ROAD,
596};
597
602template <SpriteID TSprite = SPR_SQUARE>
603class DropDownListColourItem : public DropDownIcon<DropDownString<DropDownListItem>> {
604public:
605 DropDownListColourItem(int colour, bool masked) :
606 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)
607
608 {
609 }
610};
611
618constexpr uint8_t GetColourOffset(const Livery &l, bool primary)
619{
620 return to_underlying(primary ? l.colour1 : l.colour2);
621}
622
624struct SelectCompanyLiveryWindow : public Window {
625private:
626 uint32_t sel = 0;
627 LiveryClass livery_class{};
628 Dimension square{};
629 uint rows = 0;
630 uint line_height = 0;
631 GUIGroupList groups{};
632 Scrollbar *vscroll = nullptr;
633
634 void ShowColourDropDownMenu(uint32_t widget)
635 {
637 const Livery *livery, *default_livery = nullptr;
638 bool primary = widget == WID_SCL_PRI_COL_DROPDOWN;
639 uint8_t default_col{};
640
641 /* Disallow other company colours for the primary colour */
642 if (this->livery_class < LC_GROUP_RAIL && HasBit(this->sel, LS_DEFAULT) && primary) {
643 for (const Company *c : Company::Iterate()) {
644 if (c->index != _local_company) used_colours.Set(c->colour);
645 }
646 }
647
648 const Company *c = Company::Get(this->window_number);
649
650 if (this->livery_class < LC_GROUP_RAIL) {
651 /* Get the first selected livery to use as the default dropdown item */
652 LiveryScheme scheme;
653 for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
654 if (HasBit(this->sel, scheme)) break;
655 }
656 if (scheme == LS_END) scheme = LS_DEFAULT;
657 livery = &c->livery[scheme];
658 if (scheme != LS_DEFAULT) default_livery = &c->livery[LS_DEFAULT];
659 } else {
660 const Group *g = Group::Get(this->sel);
661 livery = &g->livery;
662 if (g->parent == GroupID::Invalid()) {
663 default_livery = &c->livery[LS_DEFAULT];
664 } else {
665 const Group *pg = Group::Get(g->parent);
666 default_livery = &pg->livery;
667 }
668 }
669
670 DropDownList list;
671 if (default_livery != nullptr) {
672 /* Add Colours::End to put the colour out of range, but also allow us to show what the default is */
673 default_col = GetColourOffset(*default_livery, primary) + to_underlying(Colours::End);
674 list.push_back(std::make_unique<DropDownListColourItem<>>(default_col, false));
675 }
676 for (Colours colour = Colours::Begin; colour != Colours::End; colour++) {
677 list.push_back(std::make_unique<DropDownListColourItem<>>(to_underlying(colour), used_colours.Test(colour)));
678 }
679
680 uint8_t sel;
681 if (default_livery == nullptr || livery->in_use.Test(primary ? Livery::Flag::Primary : Livery::Flag::Secondary)) {
682 sel = GetColourOffset(*livery, primary);
683 } else {
684 sel = default_col;
685 }
686 ShowDropDownList(this, std::move(list), sel, widget);
687 }
688
689 void BuildGroupList(CompanyID owner)
690 {
691 if (!this->groups.NeedRebuild()) return;
692
693 this->groups.clear();
694
695 if (this->livery_class >= LC_GROUP_RAIL) {
696 VehicleType vtype = (VehicleType)(this->livery_class - LC_GROUP_RAIL);
697 BuildGuiGroupList(this->groups, false, owner, vtype);
698 }
699
700 this->groups.RebuildDone();
701 }
702
703 void SetRows()
704 {
705 if (this->livery_class < LC_GROUP_RAIL) {
706 this->rows = 0;
707 for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
708 if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
709 this->rows++;
710 }
711 }
712 } else {
713 this->rows = (uint)this->groups.size();
714 }
715
716 this->vscroll->SetCount(this->rows);
717 }
718
719public:
720 SelectCompanyLiveryWindow(WindowDesc &desc, CompanyID company, GroupID group) : Window(desc)
721 {
722 this->CreateNestedTree();
724 this->vscroll = this->GetScrollbar(WID_SCL_MATRIX_SCROLLBAR);
725
726 if (group == GroupID::Invalid()) {
727 this->livery_class = LC_OTHER;
728 this->sel = 1;
730 this->BuildGroupList(company);
731 this->SetRows();
732 } else {
733 this->SetSelectedGroup(company, group);
734 }
735
736 this->FinishInitNested(company);
737 this->owner = company;
738 this->InvalidateData(1);
739 }
740
741 void SetSelectedGroup(CompanyID company, GroupID group)
742 {
743 this->RaiseWidget(WID_SCL_CLASS_GENERAL + this->livery_class);
744 const Group *g = Group::Get(group);
745 switch (g->vehicle_type) {
746 case VehicleType::Train: this->livery_class = LC_GROUP_RAIL; break;
747 case VehicleType::Road: this->livery_class = LC_GROUP_ROAD; break;
748 case VehicleType::Ship: this->livery_class = LC_GROUP_SHIP; break;
749 case VehicleType::Aircraft: this->livery_class = LC_GROUP_AIRCRAFT; break;
750 default: NOT_REACHED();
751 }
752 this->sel = group.base();
753 this->LowerWidget(WID_SCL_CLASS_GENERAL + this->livery_class);
754
755 this->groups.ForceRebuild();
756 this->BuildGroupList(company);
757 this->SetRows();
758
759 /* Position scrollbar to selected group */
760 for (uint i = 0; i < this->rows; i++) {
761 if (this->groups[i].group->index == sel) {
762 this->vscroll->SetPosition(i - this->vscroll->GetCapacity() / 2);
763 break;
764 }
765 }
766 }
767
768 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
769 {
770 switch (widget) {
772 /* The matrix widget below needs enough room to print all the schemes. */
773 Dimension d = {0, 0};
774 for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
775 d = maxdim(d, GetStringBoundingBox(STR_LIVERY_DEFAULT + scheme));
776 }
777
778 size.width = std::max(size.width, 5 + d.width + padding.width);
779 break;
780 }
781
782 case WID_SCL_MATRIX: {
783 /* 11 items in the default rail class */
784 this->square = GetSpriteSize(SPR_SQUARE);
785 this->line_height = std::max(this->square.height, (uint)GetCharacterHeight(FontSize::Normal)) + padding.height;
786
787 size.height = 5 * this->line_height;
788 resize.width = 1;
789 fill.height = resize.height = this->line_height;
790 break;
791 }
792
794 if (!_loaded_newgrf_features.has_2CC) break;
795 [[fallthrough]];
796
798 this->square = GetSpriteSize(SPR_SQUARE);
799 int string_padding = this->square.width + WidgetDimensions::scaled.hsep_normal + padding.width;
800 for (Colours colour = Colours::Begin; colour != Colours::End; colour++) {
801 size.width = std::max(size.width, GetStringBoundingBox(STR_COLOUR_DARK_BLUE + to_underlying(colour)).width + string_padding);
802 }
803 size.width = std::max(size.width, GetStringBoundingBox(STR_COLOUR_DEFAULT).width + string_padding);
804 break;
805 }
806 }
807 }
808
809 void OnPaint() override
810 {
811 bool local = this->window_number == _local_company;
812
813 /* Disable dropdown controls if no scheme is selected */
814 bool disabled = this->livery_class < LC_GROUP_RAIL ? (this->sel == 0) : (this->sel == GroupID::Invalid());
815 this->SetWidgetDisabledState(WID_SCL_PRI_COL_DROPDOWN, !local || disabled);
816 this->SetWidgetDisabledState(WID_SCL_SEC_COL_DROPDOWN, !local || disabled);
817
818 this->BuildGroupList(this->window_number);
819
820 this->DrawWidgets();
821 }
822
823 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
824 {
825 switch (widget) {
826 case WID_SCL_CAPTION:
827 return GetString(STR_LIVERY_CAPTION, this->window_number);
828
831 const Company *c = Company::Get(this->window_number);
832 bool primary = widget == WID_SCL_PRI_COL_DROPDOWN;
833 StringID colour = STR_COLOUR_DEFAULT;
834
835 if (this->livery_class < LC_GROUP_RAIL) {
836 if (this->sel != 0) {
837 LiveryScheme scheme = LS_DEFAULT;
838 for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
839 if (HasBit(this->sel, scheme)) break;
840 }
841 if (scheme == LS_END) scheme = LS_DEFAULT;
842 const Livery &livery = c->livery[scheme];
843 if (scheme == LS_DEFAULT || livery.in_use.Test(primary ? Livery::Flag::Primary : Livery::Flag::Secondary)) {
844 colour = STR_COLOUR_DARK_BLUE + GetColourOffset(livery, primary);
845 }
846 }
847 } else {
848 if (this->sel != GroupID::Invalid()) {
849 const Group *g = Group::Get(this->sel);
850 const Livery &livery = g->livery;
852 colour = STR_COLOUR_DARK_BLUE + GetColourOffset(livery, primary);
853 }
854 }
855 }
856 return GetString(colour);
857 }
858
859 default:
860 return this->Window::GetWidgetString(widget, stringid);
861 }
862 }
863
864 void DrawWidget(const Rect &r, WidgetID widget) const override
865 {
866 if (widget != WID_SCL_MATRIX) return;
867
868 bool rtl = _current_text_dir == TD_RTL;
869
870 /* Coordinates of scheme name column. */
872 Rect sch = nwi->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
873 /* Coordinates of first dropdown. */
875 Rect pri = nwi->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
876 /* Coordinates of second dropdown. */
878 Rect sec = nwi->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
879
880 Rect pri_squ = pri.WithWidth(this->square.width, rtl);
881 Rect sec_squ = sec.WithWidth(this->square.width, rtl);
882
883 pri = pri.Indent(this->square.width + WidgetDimensions::scaled.hsep_normal, rtl);
884 sec = sec.Indent(this->square.width + WidgetDimensions::scaled.hsep_normal, rtl);
885
886 Rect ir = r.WithHeight(this->resize.step_height).Shrink(WidgetDimensions::scaled.matrix);
887 int square_offs = (ir.Height() - this->square.height) / 2;
888 int text_offs = (ir.Height() - GetCharacterHeight(FontSize::Normal)) / 2;
889
890 int y = ir.top;
891
892 /* Helper function to draw livery info. */
893 auto draw_livery = [&](std::string_view str, const Livery &livery, bool is_selected, bool is_default_scheme, int indent) {
894 /* Livery Label. */
895 DrawString(sch.left + (rtl ? 0 : indent), sch.right - (rtl ? indent : 0), y + text_offs, str, is_selected ? TC_WHITE : TC_BLACK);
896
897 /* Text below the first dropdown. */
898 DrawSprite(SPR_SQUARE, GetColourPalette(livery.colour1), pri_squ.left, y + square_offs);
899 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);
900
901 /* Text below the second dropdown. */
902 if (sec.right > sec.left) { // Second dropdown has non-zero size.
903 DrawSprite(SPR_SQUARE, GetColourPalette(livery.colour2), sec_squ.left, y + square_offs);
904 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);
905 }
906
907 y += this->line_height;
908 };
909
910 const Company *c = Company::Get(this->window_number);
911
912 if (livery_class < LC_GROUP_RAIL) {
913 int pos = this->vscroll->GetPosition();
914 for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
915 if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
916 if (pos-- > 0) continue;
917 draw_livery(GetString(STR_LIVERY_DEFAULT + scheme), c->livery[scheme], HasBit(this->sel, scheme), scheme == LS_DEFAULT, 0);
918 }
919 }
920 } else {
921 auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->groups);
922 for (auto it = first; it != last; ++it) {
923 const Group *g = it->group;
924 draw_livery(GetString(STR_GROUP_NAME, g->index), g->livery, this->sel == g->index, false, it->indent * WidgetDimensions::scaled.hsep_indent);
925 }
926
927 if (this->vscroll->GetCount() == 0) {
928 constexpr VehicleTypeIndexArray<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 };
929 VehicleType vtype = (VehicleType)(this->livery_class - LC_GROUP_RAIL);
930 DrawString(ir.left, ir.right, y + text_offs, empty_labels[vtype], TC_BLACK);
931 }
932 }
933 }
934
935 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
936 {
937 switch (widget) {
938 /* Livery Class buttons */
948 this->RaiseWidget(WID_SCL_CLASS_GENERAL + this->livery_class);
949 this->livery_class = (LiveryClass)(widget - WID_SCL_CLASS_GENERAL);
950 this->LowerWidget(WID_SCL_CLASS_GENERAL + this->livery_class);
951
952 /* Select the first item in the list */
953 if (this->livery_class < LC_GROUP_RAIL) {
954 this->sel = 0;
955 for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
956 if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
957 this->sel = 1 << scheme;
958 break;
959 }
960 }
961 } else {
962 this->sel = GroupID::Invalid().base();
963 this->groups.ForceRebuild();
964 this->BuildGroupList(this->window_number);
965
966 if (!this->groups.empty()) {
967 this->sel = this->groups[0].group->index.base();
968 }
969 }
970
971 this->SetRows();
972 this->SetDirty();
973 break;
974
975 case WID_SCL_PRI_COL_DROPDOWN: // First colour dropdown
976 ShowColourDropDownMenu(WID_SCL_PRI_COL_DROPDOWN);
977 break;
978
979 case WID_SCL_SEC_COL_DROPDOWN: // Second colour dropdown
980 ShowColourDropDownMenu(WID_SCL_SEC_COL_DROPDOWN);
981 break;
982
983 case WID_SCL_MATRIX: {
984 if (this->livery_class < LC_GROUP_RAIL) {
985 uint row = this->vscroll->GetScrolledRowFromWidget(pt.y, this, widget);
986 if (row >= this->rows) return;
987
988 LiveryScheme j = (LiveryScheme)row;
989
990 for (LiveryScheme scheme = LS_BEGIN; scheme <= j && scheme < LS_END; scheme++) {
991 if (_livery_class[scheme] != this->livery_class || !HasBit(_loaded_newgrf_features.used_liveries, scheme)) j++;
992 }
993 assert(j < LS_END);
994
995 if (_ctrl_pressed) {
996 ToggleBit(this->sel, j);
997 } else {
998 this->sel = 1 << j;
999 }
1000 } else {
1001 auto it = this->vscroll->GetScrolledItemFromWidget(this->groups, pt.y, this, widget);
1002 if (it == std::end(this->groups)) return;
1003
1004 this->sel = it->group->index.base();
1005 }
1006 this->SetDirty();
1007 break;
1008 }
1009 }
1010 }
1011
1012 void OnResize() override
1013 {
1014 this->vscroll->SetCapacityFromWidget(this, WID_SCL_MATRIX);
1015 }
1016
1017 void OnDropdownSelect(WidgetID widget, int index, int) override
1018 {
1019 bool local = this->window_number == _local_company;
1020 if (!local) return;
1021
1022 Colours colour = static_cast<Colours>(index);
1023 if (colour >= Colours::End) colour = Colours::Invalid;
1024
1025 if (this->livery_class < LC_GROUP_RAIL) {
1026 /* Set company colour livery */
1027 for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
1028 /* Changed colour for the selected scheme, or all visible schemes if CTRL is pressed. */
1029 if (HasBit(this->sel, scheme) || (_ctrl_pressed && _livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme))) {
1030 Command<Commands::SetCompanyColour>::Post(scheme, widget == WID_SCL_PRI_COL_DROPDOWN, colour);
1031 }
1032 }
1033 } else {
1034 /* Setting group livery */
1035 Command<Commands::SetGroupLivery>::Post(static_cast<GroupID>(this->sel), widget == WID_SCL_PRI_COL_DROPDOWN, colour);
1036 }
1037 }
1038
1044 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1045 {
1046 if (!gui_scope) return;
1047
1048 if (data != -1) {
1049 /* data contains a VehicleType, rebuild list if it displayed */
1050 if (this->livery_class == data + LC_GROUP_RAIL) {
1051 this->groups.ForceRebuild();
1052 this->BuildGroupList(this->window_number);
1053 this->SetRows();
1054
1055 if (!Group::IsValidID(this->sel)) {
1056 this->sel = GroupID::Invalid().base();
1057 if (!this->groups.empty()) this->sel = this->groups[0].group->index.base();
1058 }
1059
1060 this->SetDirty();
1061 }
1062 return;
1063 }
1064
1066
1067 bool current_class_valid = this->livery_class == LC_OTHER || this->livery_class >= LC_GROUP_RAIL;
1068 if (_settings_client.gui.liveries == LIT_ALL || (_settings_client.gui.liveries == LIT_COMPANY && this->window_number == _local_company)) {
1069 for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
1070 if (HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
1071 if (_livery_class[scheme] == this->livery_class) current_class_valid = true;
1073 } else if (this->livery_class < LC_GROUP_RAIL) {
1074 ClrBit(this->sel, scheme);
1075 }
1076 }
1077 }
1078
1079 if (!current_class_valid) {
1080 Point pt = {0, 0};
1081 this->OnClick(pt, WID_SCL_CLASS_GENERAL, 1);
1082 }
1083 }
1084};
1085
1086static constexpr std::initializer_list<NWidgetPart> _nested_select_company_livery_widgets = {
1093 EndContainer(),
1095 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCL_CLASS_GENERAL), SetToolbarMinimalSize(1), SetFill(0, 1), SetSpriteTip(SPR_IMG_COMPANY_GENERAL, STR_LIVERY_GENERAL_TOOLTIP),
1096 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCL_CLASS_RAIL), SetToolbarMinimalSize(1), SetFill(0, 1), SetSpriteTip(SPR_IMG_TRAINLIST, STR_LIVERY_TRAIN_TOOLTIP),
1097 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCL_CLASS_ROAD), SetToolbarMinimalSize(1), SetFill(0, 1), SetSpriteTip(SPR_IMG_TRUCKLIST, STR_LIVERY_ROAD_VEHICLE_TOOLTIP),
1098 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCL_CLASS_SHIP), SetToolbarMinimalSize(1), SetFill(0, 1), SetSpriteTip(SPR_IMG_SHIPLIST, STR_LIVERY_SHIP_TOOLTIP),
1099 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCL_CLASS_AIRCRAFT), SetToolbarMinimalSize(1), SetFill(0, 1), SetSpriteTip(SPR_IMG_AIRPLANESLIST, STR_LIVERY_AIRCRAFT_TOOLTIP),
1100 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCL_GROUPS_RAIL), SetToolbarMinimalSize(1), SetFill(0, 1), SetSpriteTip(SPR_GROUP_LIVERY_TRAIN, STR_LIVERY_TRAIN_GROUP_TOOLTIP),
1101 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),
1102 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCL_GROUPS_SHIP), SetToolbarMinimalSize(1), SetFill(0, 1), SetSpriteTip(SPR_GROUP_LIVERY_SHIP, STR_LIVERY_SHIP_GROUP_TOOLTIP),
1103 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCL_GROUPS_AIRCRAFT), SetToolbarMinimalSize(1), SetFill(0, 1), SetSpriteTip(SPR_GROUP_LIVERY_AIRCRAFT, STR_LIVERY_AIRCRAFT_GROUP_TOOLTIP),
1105 EndContainer(),
1109 EndContainer(),
1112 NWidget(WWT_DROPDOWN, Colours::Grey, WID_SCL_PRI_COL_DROPDOWN), SetFill(0, 1), SetToolTip(STR_LIVERY_PRIMARY_TOOLTIP),
1114 NWidget(WWT_DROPDOWN, Colours::Grey, WID_SCL_SEC_COL_DROPDOWN), SetFill(0, 1), SetToolTip(STR_LIVERY_SECONDARY_TOOLTIP),
1115 EndContainer(),
1117 EndContainer(),
1118};
1119
1122 WindowPosition::Automatic, "company_colour_scheme", 0, 0,
1124 {},
1125 _nested_select_company_livery_widgets
1126);
1127
1128void ShowCompanyLiveryWindow(CompanyID company, GroupID group)
1129{
1131 if (w == nullptr) {
1133 } else if (group != GroupID::Invalid()) {
1134 w->SetSelectedGroup(company, group);
1135 }
1136}
1137
1144void DrawCompanyManagerFace(const CompanyManagerFace &cmf, Colours colour, const Rect &r)
1145{
1146 /* Determine offset from centre of drawing rect. */
1147 Dimension d = GetSpriteSize(SPR_GRADIENT);
1148 int x = CentreBounds(r.left, r.right, d.width);
1149 int y = CentreBounds(r.top, r.bottom, d.height);
1150
1151 FaceVars vars = GetCompanyManagerFaceVars(cmf.style);
1152
1153 /* First determine which parts are enabled. */
1154 uint64_t active_vars = GetActiveFaceVars(cmf, vars);
1155
1156 std::unordered_map<uint8_t, PaletteID> palettes;
1157
1158 /* Second, get palettes. */
1159 for (auto var : SetBitIterator(active_vars)) {
1160 if (vars[var].type != FaceVarType::Palette) continue;
1161
1162 PaletteID pal = PAL_NONE;
1163 switch (vars[var].GetBits(cmf)) {
1164 default: NOT_REACHED();
1165 case 0: pal = PALETTE_TO_BROWN; break;
1166 case 1: pal = PALETTE_TO_BLUE; break;
1167 case 2: pal = PALETTE_TO_GREEN; break;
1168 }
1169 for (uint8_t affected_var : SetBitIterator(std::get<uint64_t>(vars[var].data))) {
1170 palettes[affected_var] = pal;
1171 }
1172 }
1173
1174 /* Draw the gradient (background) */
1175 DrawSprite(SPR_GRADIENT, GetColourPalette(colour), x, y);
1176
1177 /* Thirdly, draw sprites. */
1178 for (auto var : SetBitIterator(active_vars)) {
1179 if (vars[var].type != FaceVarType::Sprite) continue;
1180
1181 auto it = palettes.find(var);
1182 PaletteID pal = (it == std::end(palettes)) ? PAL_NONE : it->second;
1183 DrawSprite(vars[var].GetSprite(cmf), pal, x, y);
1184 }
1185}
1186
1188static constexpr std::initializer_list<NWidgetPart> _nested_select_company_manager_face_widgets = {
1191 NWidget(WWT_CAPTION, Colours::Grey, WID_SCMF_CAPTION), SetStringTip(STR_FACE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1192 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCMF_TOGGLE_LARGE_SMALL), SetSpriteTip(SPR_LARGE_SMALL_WINDOW, STR_FACE_ADVANCED_TOOLTIP), SetAspect(WidgetDimensions::ASPECT_TOGGLE_SIZE),
1193 EndContainer(),
1196 /* Left side */
1199 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SCMF_RANDOM_NEW_FACE), SetFill(1, 0), SetStringTip(STR_FACE_NEW_FACE_BUTTON, STR_FACE_NEW_FACE_TOOLTIP),
1200 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON), SetFill(1, 0), SetStringTip(STR_FACE_ADVANCED, STR_FACE_ADVANCED_TOOLTIP),
1201 NWidget(NWID_SELECTION, Colours::Invalid, WID_SCMF_SEL_LOADSAVE), // Load/number/save buttons under the portrait in the advanced view.
1203 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(0, 1),
1204 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SCMF_LOAD), SetFill(1, 0), SetStringTip(STR_FACE_LOAD, STR_FACE_LOAD_TOOLTIP),
1205 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SCMF_FACECODE), SetFill(1, 0), SetStringTip(STR_FACE_FACECODE, STR_FACE_FACECODE_TOOLTIP),
1206 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SCMF_SAVE), SetFill(1, 0), SetStringTip(STR_FACE_SAVE, STR_FACE_SAVE_TOOLTIP),
1207 EndContainer(),
1208 EndContainer(),
1209 EndContainer(),
1210 EndContainer(),
1211 /* Right side */
1212 NWidget(NWID_SELECTION, Colours::Invalid, WID_SCMF_SEL_PARTS), // Advanced face parts setting.
1218 EndContainer(),
1219 EndContainer(),
1220 EndContainer(),
1221 EndContainer(),
1223 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SCMF_CANCEL), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_BUTTON_CANCEL, STR_FACE_CANCEL_TOOLTIP),
1224 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SCMF_ACCEPT), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_BUTTON_OK, STR_FACE_OK_TOOLTIP),
1227 EndContainer(),
1228 EndContainer(),
1229};
1230
1232class SelectCompanyManagerFaceWindow : public Window
1233{
1235 bool advanced = false;
1236 uint selected_var = UINT_MAX;
1237 uint click_state = 0;
1238 int line_height = 0;
1239
1240 std::vector<const FaceVar *> face_vars;
1241
1246 {
1247 FaceVars vars = GetCompanyManagerFaceVars(this->face.style);
1248 ScaleAllCompanyManagerFaceBits(this->face, vars);
1249
1250 uint64_t active_vars = GetActiveFaceVars(this->face, vars);
1251 /* Exclude active parts which have no string. */
1252 for (auto var : SetBitIterator(active_vars)) {
1253 if (vars[var].name == STR_NULL) ClrBit(active_vars, var);
1254 }
1255
1256 /* Rebuild the sorted list of face variable pointers. */
1257 this->face_vars.clear();
1258 for (auto var : SetBitIterator(active_vars)) {
1259 this->face_vars.emplace_back(&vars[var]);
1260 }
1261 std::ranges::sort(this->face_vars, std::less{}, &FaceVar::position);
1262
1263 this->GetScrollbar(WID_SCMF_PARTS_SCROLLBAR)->SetCount(std::size(this->face_vars));
1264 }
1265
1266public:
1268 {
1269 this->CreateNestedTree();
1270 this->SelectDisplayPlanes(this->advanced);
1271 this->FinishInitNested(parent->window_number);
1272 this->parent = parent;
1273 this->owner = this->window_number;
1274 this->face = Company::Get(this->window_number)->face;
1275
1276 this->UpdateData();
1277 }
1278
1279 void OnInit() override
1280 {
1281 this->line_height = std::max(SETTING_BUTTON_HEIGHT, GetCharacterHeight(FontSize::Normal)) + WidgetDimensions::scaled.matrix.Vertical();
1282 }
1283
1289 {
1291 this->GetWidget<NWidgetStacked>(WID_SCMF_SEL_PARTS)->SetDisplayedPlane(advanced ? 0 : SZSP_NONE);
1292 this->GetWidget<NWidgetStacked>(WID_SCMF_SEL_RESIZE)->SetDisplayedPlane(advanced ? 0 : SZSP_NONE);
1293
1295 if (advanced) {
1296 wi->SetStringTip(STR_FACE_SIMPLE, STR_FACE_SIMPLE_TOOLTIP);
1297 } else {
1298 wi->SetStringTip(STR_FACE_ADVANCED, STR_FACE_ADVANCED_TOOLTIP);
1299 }
1300 }
1301
1302 static StringID GetLongestString(StringID a, StringID b)
1303 {
1304 return GetStringBoundingBox(a).width > GetStringBoundingBox(b).width ? a : b;
1305 }
1306
1307 static uint GetMaximumFacePartsWidth()
1308 {
1309 StringID yes_no = GetLongestString(STR_FACE_YES, STR_FACE_NO);
1310
1311 uint width = 0;
1312 for (uint style_index = 0; style_index != GetNumCompanyManagerFaceStyles(); ++style_index) {
1313 FaceVars vars = GetCompanyManagerFaceVars(style_index);
1314 for (const auto &info : vars) {
1315 if (info.name == STR_NULL) continue;
1316 if (info.type == FaceVarType::Toggle) {
1317 width = std::max(width, GetStringBoundingBox(GetString(STR_FACE_SETTING_TOGGLE, info.name, yes_no)).width);
1318 } else {
1319 uint64_t max_digits = GetParamMaxValue(info.valid_values);
1320 width = std::max(width, GetStringBoundingBox(GetString(STR_FACE_SETTING_NUMERIC, info.name, max_digits, max_digits)).width);
1321 }
1322 }
1323 }
1324
1325 /* Include width of button and spacing. */
1327 return width;
1328 }
1329
1330 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
1331 {
1332 switch (widget) {
1333 case WID_SCMF_FACE:
1334 size = maxdim(size, GetScaledSpriteSize(SPR_GRADIENT));
1335 break;
1336
1337 case WID_SCMF_STYLE:
1338 size.height = this->line_height;
1339 break;
1340
1341 case WID_SCMF_PARTS:
1342 fill.height = resize.height = this->line_height;
1343 size.width = GetMaximumFacePartsWidth();
1344 size.height = resize.height * 5;
1345 break;
1346 }
1347 }
1348
1349 void DrawWidget(const Rect &r, WidgetID widget) const override
1350 {
1351 switch (widget) {
1352 case WID_SCMF_FACE:
1353 DrawCompanyManagerFace(this->face, Company::Get(this->window_number)->colour, r);
1354 break;
1355
1356 case WID_SCMF_STYLE: {
1357 Rect ir = r.Shrink(WidgetDimensions::scaled.frametext, RectPadding::zero).WithHeight(this->line_height);
1358 bool rtl = _current_text_dir == TD_RTL;
1359
1362
1363 DrawArrowButtons(br.left, br.top, Colours::Yellow, this->selected_var == UINT_MAX - 1 ? this->click_state : 0, true, true);
1364 DrawString(tr, GetString(STR_FACE_SETTING_NUMERIC, STR_FACE_STYLE, this->face.style + 1, GetNumCompanyManagerFaceStyles()), TC_WHITE);
1365 break;
1366 }
1367
1368 case WID_SCMF_PARTS: {
1369 Rect ir = r.Shrink(WidgetDimensions::scaled.frametext, RectPadding::zero).WithHeight(this->line_height);
1370 bool rtl = _current_text_dir == TD_RTL;
1371
1372 FaceVars vars = GetCompanyManagerFaceVars(this->face.style);
1373
1374 auto [first, last] = this->GetScrollbar(WID_SCMF_PARTS_SCROLLBAR)->GetVisibleRangeIterators(this->face_vars);
1375 for (auto it = first; it != last; ++it) {
1376 const uint8_t var = static_cast<uint8_t>(*it - vars.data());
1377 const FaceVar &facevar = **it;
1378
1381
1382 uint val = vars[var].GetBits(this->face);
1383 if (facevar.type == FaceVarType::Toggle) {
1384 DrawBoolButton(br.left, br.top, Colours::Yellow, Colours::Grey, val == 1, true);
1385 DrawString(tr, GetString(STR_FACE_SETTING_TOGGLE, facevar.name, val == 1 ? STR_FACE_YES : STR_FACE_NO), TC_WHITE);
1386 } else {
1387 DrawArrowButtons(br.left, br.top, Colours::Yellow, this->selected_var == var ? this->click_state : 0, true, true);
1388 DrawString(tr, GetString(STR_FACE_SETTING_NUMERIC, facevar.name, val + 1, facevar.valid_values), TC_WHITE);
1389 }
1390
1391 ir = ir.Translate(0, this->line_height);
1392 }
1393 break;
1394 }
1395 }
1396 }
1397
1398 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1399 {
1400 switch (widget) {
1401 /* Toggle size, advanced/simple face selection */
1404 this->advanced = !this->advanced;
1405 this->SelectDisplayPlanes(this->advanced);
1406 this->ReInit();
1407 break;
1408
1409 /* OK button */
1410 case WID_SCMF_ACCEPT:
1411 Command<Commands::SetCompanyManagerFace>::Post(this->face.style, this->face.bits);
1412 [[fallthrough]];
1413
1414 /* Cancel button */
1415 case WID_SCMF_CANCEL:
1416 this->Close();
1417 break;
1418
1419 /* Load button */
1420 case WID_SCMF_LOAD: {
1422 if (cmf.has_value()) this->face = *cmf;
1423 ShowErrorMessage(GetEncodedString(STR_FACE_LOAD_DONE), {}, WL_INFO);
1424 this->UpdateData();
1425 this->SetDirty();
1426 break;
1427 }
1428
1429 /* 'Company manager face number' button, view and/or set company manager face number */
1430 case WID_SCMF_FACECODE:
1431 ShowQueryString(FormatCompanyManagerFaceCode(this->face), STR_FACE_FACECODE_CAPTION, 128, this, CS_ALPHANUMERAL, {});
1432 break;
1433
1434 /* Save button */
1435 case WID_SCMF_SAVE:
1437 ShowErrorMessage(GetEncodedString(STR_FACE_SAVE_DONE), {}, WL_INFO);
1438 break;
1439
1440 /* Randomize face button */
1443 this->UpdateData();
1444 this->SetDirty();
1445 break;
1446
1447 case WID_SCMF_STYLE: {
1448 bool rtl = _current_text_dir == TD_RTL;
1449 Rect ir = this->GetWidget<NWidgetCore>(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.frametext, RectPadding::zero);
1450 Rect br = ir.WithWidth(SETTING_BUTTON_WIDTH, rtl);
1451
1452 uint num_styles = GetNumCompanyManagerFaceStyles();
1453 this->selected_var = UINT_MAX - 1;
1454 if (IsInsideBS(pt.x, br.left, SETTING_BUTTON_WIDTH / 2)) {
1455 SetCompanyManagerFaceStyle(this->face, (this->face.style + num_styles - 1) % num_styles);
1456 this->click_state = 1;
1457 } else if (IsInsideBS(pt.x, br.left + SETTING_BUTTON_WIDTH / 2, SETTING_BUTTON_WIDTH / 2)) {
1458 SetCompanyManagerFaceStyle(this->face, (this->face.style + 1) % num_styles);
1459 this->click_state = 2;
1460 }
1461
1462 this->UpdateData();
1463 this->SetTimeout();
1464 this->SetDirty();
1465 break;
1466 }
1467
1468 case WID_SCMF_PARTS: {
1469 bool rtl = _current_text_dir == TD_RTL;
1470 Rect ir = this->GetWidget<NWidgetCore>(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.frametext, RectPadding::zero);
1471 Rect br = ir.WithWidth(SETTING_BUTTON_WIDTH, rtl);
1472
1473 this->selected_var = UINT_MAX;
1474
1475 FaceVars vars = GetCompanyManagerFaceVars(this->face.style);
1476 auto it = this->GetScrollbar(WID_SCMF_PARTS_SCROLLBAR)->GetScrolledItemFromWidget(this->face_vars, pt.y, this, widget, 0, this->line_height);
1477 if (it == std::end(this->face_vars)) break;
1478
1479 this->selected_var = static_cast<uint8_t>(*it - vars.data());
1480 const auto &facevar = **it;
1481
1482 if (facevar.type == FaceVarType::Toggle) {
1483 if (!IsInsideBS(pt.x, br.left, SETTING_BUTTON_WIDTH)) break;
1484 facevar.ChangeBits(this->face, 1);
1485 this->UpdateData();
1486 } else {
1487 if (IsInsideBS(pt.x, br.left, SETTING_BUTTON_WIDTH / 2)) {
1488 facevar.ChangeBits(this->face, -1);
1489 this->click_state = 1;
1490 } else if (IsInsideBS(pt.x, br.left + SETTING_BUTTON_WIDTH / 2, SETTING_BUTTON_WIDTH / 2)) {
1491 facevar.ChangeBits(this->face, 1);
1492 this->click_state = 2;
1493 } else {
1494 break;
1495 }
1496 }
1497
1498 this->SetTimeout();
1499 this->SetDirty();
1500 break;
1501 }
1502 }
1503 }
1504
1505 void OnResize() override
1506 {
1507 if (auto *wid = this->GetWidget<NWidgetResizeBase>(WID_SCMF_PARTS); wid != nullptr) {
1508 /* Workaround for automatic widget sizing ignoring resize steps. Manually ensure parts matrix is a
1509 * multiple of its resize step. This trick only works here as the window itself is not resizable. */
1510 if (wid->UpdateVerticalSize((wid->current_y + wid->resize_y - 1) / wid->resize_y * wid->resize_y)) {
1511 this->ReInit();
1512 return;
1513 }
1514 }
1515
1517 }
1518
1519 void OnTimeout() override
1520 {
1521 this->click_state = 0;
1522 this->selected_var = UINT_MAX;
1523 this->SetDirty();
1524 }
1525
1526 void OnQueryTextFinished(std::optional<std::string> str) override
1527 {
1528 if (!str.has_value()) return;
1529 /* Parse new company manager face number */
1530 auto cmf = ParseCompanyManagerFaceCode(*str);
1531 if (cmf.has_value()) {
1532 this->face = *cmf;
1533 ShowErrorMessage(GetEncodedString(STR_FACE_FACECODE_SET), {}, WL_INFO);
1534 this->UpdateData();
1535 this->SetDirty();
1536 } else {
1537 ShowErrorMessage(GetEncodedString(STR_FACE_FACECODE_ERR), {}, WL_INFO);
1538 }
1539 }
1540};
1541
1544 WindowPosition::Automatic, {}, 0, 0,
1548);
1549
1562
1563static constexpr std::initializer_list<NWidgetPart> _nested_company_infrastructure_widgets = {
1570 EndContainer(),
1574 EndContainer(),
1578 EndContainer(),
1579 EndContainer(),
1580};
1581
1585struct CompanyInfrastructureWindow : Window
1586{
1593
1596 StringID label;
1597 uint count;
1598 Money cost;
1599 };
1600
1601 uint count_width = 0;
1602 uint cost_width = 0;
1603
1604 mutable std::vector<InfrastructureItem> list;
1605
1606 CompanyInfrastructureWindow(WindowDesc &desc, WindowNumber window_number) : Window(desc)
1607 {
1608 this->InitNested(window_number);
1609 this->owner = this->window_number;
1610 }
1611
1612 void OnInit() override
1613 {
1614 this->UpdateInfrastructureList();
1615 }
1616
1617 void UpdateInfrastructureList()
1618 {
1619 this->list.clear();
1620
1621 const Company *c = Company::GetIfValid(this->window_number);
1622 if (c == nullptr) return;
1623
1624 Money total_monthly_cost = 0;
1625
1626 if (uint32_t rail_total = c->infrastructure.GetRailTotal(); rail_total > 0) {
1627 /* Rail types and signals. */
1628 this->list.emplace_back(InfrastructureItemType::Header, STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT);
1629
1630 for (const RailType &rt : _sorted_railtypes) {
1631 if (c->infrastructure.rail[rt] == 0) continue;
1632 Money monthly_cost = RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total);
1633 total_monthly_cost += monthly_cost;
1634 this->list.emplace_back(InfrastructureItemType::Value, GetRailTypeInfo(rt)->strings.name, c->infrastructure.rail[rt], monthly_cost);
1635 }
1636
1637 if (c->infrastructure.signal > 0) {
1638 Money monthly_cost = SignalMaintenanceCost(c->infrastructure.signal);
1639 total_monthly_cost += monthly_cost;
1640 this->list.emplace_back(InfrastructureItemType::Value, STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS, c->infrastructure.signal, monthly_cost);
1641 }
1642 }
1643
1644 if (uint32_t road_total = c->infrastructure.GetRoadTotal(); road_total > 0) {
1645 /* Road types. */
1646 if (!this->list.empty()) this->list.emplace_back(InfrastructureItemType::Spacer);
1647 this->list.emplace_back(InfrastructureItemType::Header, STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT);
1648
1649 for (const RoadType &rt : _sorted_roadtypes) {
1650 if (!RoadTypeIsRoad(rt)) continue;
1651 if (c->infrastructure.road[rt] == 0) continue;
1652 Money monthly_cost = RoadMaintenanceCost(rt, c->infrastructure.road[rt], road_total);
1653 total_monthly_cost += monthly_cost;
1654 this->list.emplace_back(InfrastructureItemType::Value, GetRoadTypeInfo(rt)->strings.name, c->infrastructure.road[rt], monthly_cost);
1655 }
1656 }
1657
1658 if (uint32_t tram_total = c->infrastructure.GetTramTotal(); tram_total > 0) {
1659 /* Tram types. */
1660 if (!this->list.empty()) this->list.emplace_back(InfrastructureItemType::Spacer);
1661 this->list.emplace_back(InfrastructureItemType::Header, STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT);
1662
1663 for (const RoadType &rt : _sorted_roadtypes) {
1664 if (!RoadTypeIsTram(rt)) continue;
1665 if (c->infrastructure.road[rt] == 0) continue;
1666 Money monthly_cost = RoadMaintenanceCost(rt, c->infrastructure.road[rt], tram_total);
1667 total_monthly_cost += monthly_cost;
1668 this->list.emplace_back(InfrastructureItemType::Value, GetRoadTypeInfo(rt)->strings.name, c->infrastructure.road[rt], monthly_cost);
1669 }
1670 }
1671
1672 if (c->infrastructure.water > 0) {
1673 /* Canals, locks, and ship depots (docks are counted as stations). */
1674 if (!this->list.empty()) this->list.emplace_back(InfrastructureItemType::Spacer);
1675 this->list.emplace_back(InfrastructureItemType::Header, STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT);
1676
1677 Money monthly_cost = CanalMaintenanceCost(c->infrastructure.water);
1678 total_monthly_cost += monthly_cost;
1679 this->list.emplace_back(InfrastructureItemType::Value, STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS, c->infrastructure.water, monthly_cost);
1680 }
1681
1682 if (Money airport_cost = AirportMaintenanceCost(c->index); airport_cost > 0 || c->infrastructure.station > 0) {
1683 /* Stations and airports. */
1684 if (!this->list.empty()) this->list.emplace_back(InfrastructureItemType::Spacer);
1685 this->list.emplace_back(InfrastructureItemType::Header, STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT);
1686
1687 if (c->infrastructure.station > 0) {
1688 Money monthly_cost = StationMaintenanceCost(c->infrastructure.station);
1689 total_monthly_cost += monthly_cost;
1690 this->list.emplace_back(InfrastructureItemType::Value, STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS, c->infrastructure.station, monthly_cost);
1691 }
1692
1693 if (airport_cost > 0) {
1694 Money monthly_cost = airport_cost;
1695 total_monthly_cost += monthly_cost;
1696 this->list.emplace_back(InfrastructureItemType::Value, STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS, c->infrastructure.airport, monthly_cost);
1697 }
1698 }
1699
1701 /* Total monthly maintenance cost. */
1702 this->list.emplace_back(InfrastructureItemType::Spacer);
1703 this->list.emplace_back(InfrastructureItemType::Total, STR_NULL, 0, total_monthly_cost);
1704 }
1705
1706 /* Update scrollbar. */
1707 this->GetScrollbar(WID_CI_SCROLLBAR)->SetCount(std::size(list));
1708 }
1709
1710 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
1711 {
1712 switch (widget) {
1713 case WID_CI_CAPTION:
1714 return GetString(STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION, this->window_number);
1715
1716 default:
1717 return this->Window::GetWidgetString(widget, stringid);
1718 }
1719 }
1720
1721 void FindWindowPlacementAndResize(int def_width, int def_height, bool allow_resize) override
1722 {
1723 if (def_height == 0) {
1724 /* Try to open the window with the exact required rows, but clamp to a reasonable limit. */
1725 int rows = (this->GetWidget<NWidgetBase>(WID_CI_LIST)->current_y - WidgetDimensions::scaled.framerect.Vertical()) / GetCharacterHeight(FontSize::Normal);
1726 int delta = std::min(20, static_cast<int>(std::size(this->list))) - rows;
1727 def_height = this->height + delta * GetCharacterHeight(FontSize::Normal);
1728 }
1729
1730 this->Window::FindWindowPlacementAndResize(def_width, def_height, allow_resize);
1731 }
1732
1733 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
1734 {
1735 if (widget != WID_CI_LIST) return;
1736
1737 uint max_count = 1000; // Some random number to reserve minimum space.
1738 Money max_cost = 1000000; // Some random number to reserve minimum space.
1739
1740 /* List of headers that might be used. */
1741 static constexpr StringID header_strings[] = {
1742 STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT,
1743 STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT,
1744 STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT,
1745 STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT,
1746 STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT,
1747 };
1748 /* List of labels that might be used. */
1749 static constexpr StringID label_strings[] = {
1750 STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS,
1751 STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS,
1752 STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS,
1753 STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS,
1754 };
1755
1756 uint max_header_width = GetStringListWidth(header_strings);
1757 uint max_label_width = GetStringListWidth(label_strings);
1758
1759 /* Include width of all possible rail and road types. */
1760 for (const RailType &rt : _sorted_railtypes) max_label_width = std::max(max_label_width, GetStringBoundingBox(GetRailTypeInfo(rt)->strings.name).width);
1761 for (const RoadType &rt : _sorted_roadtypes) max_label_width = std::max(max_label_width, GetStringBoundingBox(GetRoadTypeInfo(rt)->strings.name).width);
1762
1763 for (const InfrastructureItem &entry : this->list) {
1764 max_count = std::max(max_count, entry.count);
1765 max_cost = std::max(max_cost, entry.cost * 12);
1766 }
1767
1768 max_label_width += WidgetDimensions::scaled.hsep_indent;
1769 this->count_width = GetStringBoundingBox(GetString(STR_JUST_COMMA, max_count)).width;
1770
1771 if (_settings_game.economy.infrastructure_maintenance) {
1772 this->cost_width = GetStringBoundingBox(GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_PERIOD : STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_YEAR, max_cost)).width;
1773 } else {
1774 this->cost_width = 0;
1775 }
1776
1777 size.width = max_label_width + WidgetDimensions::scaled.hsep_wide + this->count_width + WidgetDimensions::scaled.hsep_wide + this->cost_width;
1778 size.width = std::max(size.width, max_header_width) + WidgetDimensions::scaled.framerect.Horizontal();
1779
1780 fill.height = resize.height = GetCharacterHeight(FontSize::Normal);
1781 }
1782
1783 void DrawWidget(const Rect &r, WidgetID widget) const override
1784 {
1785 if (widget != WID_CI_LIST) return;
1786
1787 bool rtl = _current_text_dir == TD_RTL; // We allocate space from end-to-start so the label fills.
1788 int line_height = GetCharacterHeight(FontSize::Normal);
1789
1790 Rect ir = r.Shrink(WidgetDimensions::scaled.framerect);
1791 Rect countr = ir.WithWidth(this->count_width, !rtl);
1792 Rect costr = ir.Indent(this->count_width + WidgetDimensions::scaled.hsep_wide, !rtl).WithWidth(this->cost_width, !rtl);
1793 Rect labelr = ir.Indent(this->count_width + WidgetDimensions::scaled.hsep_wide + this->cost_width + WidgetDimensions::scaled.hsep_wide, !rtl);
1794
1795 auto [first, last] = this->GetScrollbar(WID_CI_SCROLLBAR)->GetVisibleRangeIterators(this->list);
1796 for (auto it = first; it != last; ++it) {
1797 switch (it->type) {
1799 /* Header is allowed to fill the window's width. */
1800 DrawString(ir.left, ir.right, labelr.top, GetString(it->label), TC_ORANGE);
1801 break;
1802
1804 break;
1805
1807 /* Draw line in the spacer above the total. */
1809 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);
1810 break;
1811
1813 DrawString(labelr.Indent(WidgetDimensions::scaled.hsep_indent, rtl), GetString(it->label), TC_WHITE);
1814 DrawString(countr, GetString(STR_JUST_COMMA, it->count), TC_WHITE, SA_RIGHT | SA_FORCE);
1815 if (_settings_game.economy.infrastructure_maintenance) {
1816 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);
1817 }
1818 break;
1819 }
1820
1821 labelr.top += line_height;
1822 countr.top += line_height;
1823 costr.top += line_height;
1824 }
1825 }
1826
1827 const IntervalTimer<TimerWindow> redraw_interval = {std::chrono::seconds(1), [this](auto) {
1828 this->UpdateInfrastructureList();
1830 }};
1831
1832 void OnResize() override
1833 {
1835 }
1836
1842 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1843 {
1844 if (!gui_scope) return;
1845
1846 this->ReInit();
1847 }
1848};
1849
1852 WindowPosition::Automatic, "company_infrastructure", 0, 0,
1854 {},
1855 _nested_company_infrastructure_widgets
1856);
1857
1862static void ShowCompanyInfrastructure(CompanyID company)
1863{
1864 if (!Company::IsValidID(company)) return;
1866}
1867
1868static constexpr std::initializer_list<NWidgetPart> _nested_company_widgets = {
1874 EndContainer(),
1880 EndContainer(),
1886 NWidget(WWT_LABEL, Colours::Invalid, WID_C_DESC_COLOUR_SCHEME), SetStringTip(STR_COMPANY_VIEW_COLOUR_SCHEME_TITLE),
1888 EndContainer(),
1892 EndContainer(),
1893 EndContainer(),
1896 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_C_VIEW_HQ), SetStringTip(STR_COMPANY_VIEW_VIEW_HQ_BUTTON, STR_COMPANY_VIEW_VIEW_HQ_TOOLTIP),
1897 NWidget(WWT_TEXTBTN, Colours::Grey, WID_C_BUILD_HQ), SetStringTip(STR_COMPANY_VIEW_BUILD_HQ_BUTTON, STR_COMPANY_VIEW_BUILD_HQ_TOOLTIP),
1898 EndContainer(),
1900 NWidget(WWT_TEXTBTN, Colours::Grey, WID_C_RELOCATE_HQ), SetStringTip(STR_COMPANY_VIEW_RELOCATE_HQ, STR_COMPANY_VIEW_RELOCATE_HQ_TOOLTIP),
1902 EndContainer(),
1903 EndContainer(),
1904 EndContainer(),
1905
1907
1912 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_C_VIEW_INFRASTRUCTURE), SetStringTip(STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON, STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP),
1913 EndContainer(),
1914 EndContainer(),
1915
1916 /* Multi player buttons. */
1920 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_C_HOSTILE_TAKEOVER), SetStringTip(STR_COMPANY_VIEW_HOSTILE_TAKEOVER_BUTTON, STR_COMPANY_VIEW_HOSTILE_TAKEOVER_TOOLTIP),
1921 EndContainer(),
1923 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_C_GIVE_MONEY), SetStringTip(STR_COMPANY_VIEW_GIVE_MONEY_BUTTON, STR_COMPANY_VIEW_GIVE_MONEY_TOOLTIP),
1924 EndContainer(),
1926 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_C_COMPANY_JOIN), SetStringTip(STR_COMPANY_VIEW_JOIN, STR_COMPANY_VIEW_JOIN_TOOLTIP),
1927 EndContainer(),
1928 EndContainer(),
1929 EndContainer(),
1930 EndContainer(),
1931 EndContainer(),
1932 EndContainer(),
1933 /* Button bars at the bottom. */
1936 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),
1937 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),
1938 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),
1939 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),
1940 EndContainer(),
1941 EndContainer(),
1942};
1943
1946 STR_COMPANY_VIEW_TRAINS, STR_COMPANY_VIEW_ROAD_VEHICLES, STR_COMPANY_VIEW_SHIPS, STR_COMPANY_VIEW_AIRCRAFT
1947};
1948
1952struct CompanyWindow : Window
1953{
1956
1957 CompanyWidgets query_widget{};
1958
1960 enum CompanyWindowPlanes : uint8_t {
1961 /* Display planes of the #WID_C_SELECT_VIEW_BUILD_HQ selection widget. */
1964
1965 /* Display planes of the #WID_C_SELECT_RELOCATE selection widget. */
1968 };
1969
1971 {
1972 this->InitNested(window_number);
1973 this->owner = this->window_number;
1974 this->OnInvalidateData();
1975 }
1976
1977 void OnPaint() override
1978 {
1979 const Company *c = Company::Get(this->window_number);
1980 bool local = this->window_number == _local_company;
1981
1982 if (!this->IsShaded()) {
1983 bool reinit = false;
1984
1985 /* Button bar selection. */
1986 reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_BUTTONS)->SetDisplayedPlane(local ? 0 : SZSP_NONE);
1987
1988 /* Build HQ button handling. */
1989 reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_VIEW_BUILD_HQ)->SetDisplayedPlane((local && c->location_of_HQ == INVALID_TILE) ? CWP_VB_BUILD : CWP_VB_VIEW);
1990
1992
1993 /* Enable/disable 'Relocate HQ' button. */
1994 reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_RELOCATE)->SetDisplayedPlane((!local || c->location_of_HQ == INVALID_TILE) ? CWP_RELOCATE_HIDE : CWP_RELOCATE_SHOW);
1995 /* Enable/disable 'Give money' button. */
1996 reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_GIVE_MONEY)->SetDisplayedPlane((local || _local_company == COMPANY_SPECTATOR || !_settings_game.economy.give_money) ? SZSP_NONE : 0);
1997 /* Enable/disable 'Hostile Takeover' button. */
1998 reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_HOSTILE_TAKEOVER)->SetDisplayedPlane((local || _local_company == COMPANY_SPECTATOR || !c->is_ai || _networking) ? SZSP_NONE : 0);
1999
2000 /* Multiplayer buttons. */
2001 reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_MULTIPLAYER)->SetDisplayedPlane((!_networking || !NetworkCanJoinCompany(c->index) || _local_company == c->index) ? (int)SZSP_NONE : 0);
2002
2004
2005 if (reinit) {
2006 this->ReInit();
2007 return;
2008 }
2009 }
2010
2011 this->DrawWidgets();
2012 }
2013
2014 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2015 {
2016 switch (widget) {
2017 case WID_C_FACE:
2018 size = maxdim(size, GetScaledSpriteSize(SPR_GRADIENT));
2019 break;
2020
2022 Point offset;
2023 Dimension d = GetSpriteSize(SPR_VEH_BUS_SW_VIEW, &offset);
2024 d.width -= offset.x;
2025 d.height -= offset.y;
2026 size = maxdim(size, d);
2027 break;
2028 }
2029
2031 /* INT64_MAX is arguably the maximum company value */
2032 size.width = GetStringBoundingBox(GetString(STR_COMPANY_VIEW_COMPANY_VALUE, INT64_MAX)).width;
2033 break;
2034
2036 uint64_t max_value = GetParamMaxValue(5000); // Maximum number of vehicles
2037 for (const auto &count_string : _company_view_vehicle_count_strings) {
2038 size.width = std::max(size.width, GetStringBoundingBox(GetString(count_string, max_value)).width + padding.width);
2039 }
2040 break;
2041 }
2042
2044 uint64_t max_value = GetParamMaxValue(UINT_MAX);
2045 size.width = GetStringBoundingBox(GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL, max_value)).width;
2046 size.width = std::max(size.width, GetStringBoundingBox(GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD, max_value)).width);
2047 size.width = std::max(size.width, GetStringBoundingBox(GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_WATER, max_value)).width);
2048 size.width = std::max(size.width, GetStringBoundingBox(GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_STATION, max_value)).width);
2049 size.width = std::max(size.width, GetStringBoundingBox(GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT, max_value)).width);
2050 size.width = std::max(size.width, GetStringBoundingBox(GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_NONE, max_value)).width);
2051 size.width += padding.width;
2052 break;
2053 }
2054
2055 case WID_C_VIEW_HQ:
2056 case WID_C_BUILD_HQ:
2057 case WID_C_RELOCATE_HQ:
2059 case WID_C_GIVE_MONEY:
2061 case WID_C_COMPANY_JOIN:
2062 size.width = GetStringBoundingBox(STR_COMPANY_VIEW_VIEW_HQ_BUTTON).width;
2063 size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_BUILD_HQ_BUTTON).width);
2064 size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_RELOCATE_HQ).width);
2065 size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON).width);
2066 size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_GIVE_MONEY_BUTTON).width);
2067 size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_HOSTILE_TAKEOVER_BUTTON).width);
2068 size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_JOIN).width);
2069 size.width += padding.width;
2070 break;
2071 }
2072 }
2073
2074 void DrawVehicleCountsWidget(const Rect &r, const Company *c) const
2075 {
2076 int y = r.top;
2077 for (VehicleType type = VehicleType::Begin; type < VehicleType::CompanyEnd; type++) {
2078 uint amount = c->group_all[type].num_vehicle;
2079 if (amount != 0) {
2080 DrawString(r.left, r.right, y, GetString(_company_view_vehicle_count_strings[type], amount));
2082 }
2083 }
2084
2085 if (y == r.top) {
2086 /* No String was emitted before, so there must be no vehicles at all. */
2087 DrawString(r.left, r.right, y, STR_COMPANY_VIEW_VEHICLES_NONE);
2088 }
2089 }
2090
2091 void DrawInfrastructureCountsWidget(const Rect &r, const Company *c) const
2092 {
2093 int y = r.top;
2094
2095 uint rail_pieces = c->infrastructure.signal + c->infrastructure.GetRailTotal();
2096 if (rail_pieces != 0) {
2097 DrawString(r.left, r.right, y, GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL, rail_pieces));
2099 }
2100
2101 /* GetRoadTotal() skips tram pieces, but we actually want road and tram here. */
2102 uint road_pieces = std::accumulate(std::begin(c->infrastructure.road), std::end(c->infrastructure.road), 0U);
2103 if (road_pieces != 0) {
2104 DrawString(r.left, r.right, y, GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD, road_pieces));
2106 }
2107
2108 if (c->infrastructure.water != 0) {
2109 DrawString(r.left, r.right, y, GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_WATER, c->infrastructure.water));
2111 }
2112
2113 if (c->infrastructure.station != 0) {
2114 DrawString(r.left, r.right, y, GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_STATION, c->infrastructure.station));
2116 }
2117
2118 if (c->infrastructure.airport != 0) {
2119 DrawString(r.left, r.right, y, GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT, c->infrastructure.airport));
2121 }
2122
2123 if (y == r.top) {
2124 /* No String was emitted before, so there must be no infrastructure at all. */
2125 DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE);
2126 }
2127 }
2128
2129 void DrawWidget(const Rect &r, WidgetID widget) const override
2130 {
2131 const Company *c = Company::Get(this->window_number);
2132 switch (widget) {
2133 case WID_C_FACE:
2135 break;
2136
2137 case WID_C_FACE_TITLE:
2138 DrawStringMultiLine(r, GetString(STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE, c->index), TC_FROMSTRING, SA_HOR_CENTER);
2139 break;
2140
2142 Point offset;
2143 Dimension d = GetSpriteSize(SPR_VEH_BUS_SW_VIEW, &offset);
2144 d.height -= offset.y;
2145 DrawSprite(SPR_VEH_BUS_SW_VIEW, GetCompanyPalette(c->index), r.left - offset.x, CentreBounds(r.top, r.bottom, d.height) - offset.y);
2146 break;
2147 }
2148
2150 DrawVehicleCountsWidget(r, c);
2151 break;
2152
2154 DrawInfrastructureCountsWidget(r, c);
2155 break;
2156 }
2157 }
2158
2159 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
2160 {
2161 switch (widget) {
2162 case WID_C_CAPTION:
2163 return GetString(STR_COMPANY_VIEW_CAPTION, this->window_number, this->window_number);
2164
2166 const Company &c = *Company::Get(this->window_number);
2168 return GetString(STR_COMPANY_VIEW_INAUGURATED_TITLE_WALLCLOCK, c.inaugurated_year_calendar, c.inaugurated_year);
2169 }
2170 return GetString(STR_COMPANY_VIEW_INAUGURATED_TITLE, c.inaugurated_year);
2171 }
2172
2174 return GetString(STR_COMPANY_VIEW_COMPANY_VALUE, CalculateCompanyValue(Company::Get(this->window_number)));
2175
2176 default:
2177 return this->Window::GetWidgetString(widget, stringid);
2178 }
2179 }
2180
2181 void OnResize() override
2182 {
2184 int y = GetStringHeight(GetString(STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE, this->owner), wid->current_x);
2185 if (wid->UpdateVerticalSize(y)) this->ReInit(0, 0);
2186 }
2187
2188 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2189 {
2190 switch (widget) {
2191 case WID_C_NEW_FACE: DoSelectCompanyManagerFace(this); break;
2192
2194 ShowCompanyLiveryWindow(this->window_number, GroupID::Invalid());
2195 break;
2196
2198 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});
2199 this->query_widget = WID_C_PRESIDENT_NAME;
2200 break;
2201
2202 case WID_C_COMPANY_NAME:
2203 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});
2204 this->query_widget = WID_C_COMPANY_NAME;
2205 break;
2206
2207 case WID_C_VIEW_HQ: {
2208 TileIndex tile = Company::Get(this->window_number)->location_of_HQ;
2209 if (_ctrl_pressed) {
2211 } else {
2213 }
2214 break;
2215 }
2216
2217 case WID_C_BUILD_HQ:
2218 if (this->window_number != _local_company) return;
2219 if (this->IsWidgetLowered(WID_C_BUILD_HQ)) {
2221 this->RaiseButtons();
2222 break;
2223 }
2224 SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, HT_RECT, this);
2225 SetTileSelectSize(2, 2);
2228 break;
2229
2230 case WID_C_RELOCATE_HQ:
2233 this->RaiseButtons();
2234 break;
2235 }
2236 SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, HT_RECT, this);
2237 SetTileSelectSize(2, 2);
2240 break;
2241
2244 break;
2245
2246 case WID_C_GIVE_MONEY:
2247 ShowQueryString({}, STR_COMPANY_VIEW_GIVE_MONEY_QUERY_CAPTION, 30, this, CS_NUMERAL, {});
2248 this->query_widget = WID_C_GIVE_MONEY;
2249 break;
2250
2253 break;
2254
2255 case WID_C_COMPANY_JOIN: {
2256 this->query_widget = WID_C_COMPANY_JOIN;
2257 CompanyID company = this->window_number;
2258 if (_network_server) {
2261 } else {
2262 /* just send the join command */
2263 NetworkClientRequestMove(company);
2264 }
2265 break;
2266 }
2267 }
2268 }
2269
2271 const IntervalTimer<TimerWindow> redraw_interval = {std::chrono::seconds(3), [this](auto) {
2272 this->SetDirty();
2273 }};
2274
2275 void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
2276 {
2277 if (Command<Commands::BuildObject>::Post(STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS, tile, OBJECT_HQ, 0) && !_shift_pressed) {
2279 this->RaiseButtons();
2280 }
2281 }
2282
2283 void OnPlaceObjectAbort() override
2284 {
2285 this->RaiseButtons();
2286 }
2287
2288 void OnQueryTextFinished(std::optional<std::string> str) override
2289 {
2290 CompanyWidgets widget = this->query_widget;
2291 this->query_widget = CompanyWindow::INVALID_QUERY_WIDGET;
2292
2293 if (!str.has_value()) return;
2294
2295 switch (widget) {
2296 default: NOT_REACHED();
2297
2298 case WID_C_GIVE_MONEY: {
2299 auto value = ParseInteger<uint64_t>(*str, 10, true);
2300 if (!value.has_value()) return;
2301 Money money = *value / GetCurrency().rate;
2302 Command<Commands::GiveMoney>::Post(STR_ERROR_CAN_T_GIVE_MONEY, money, this->window_number);
2303 break;
2304 }
2305
2307 Command<Commands::RenamePresident>::Post(STR_ERROR_CAN_T_CHANGE_PRESIDENT, *str);
2308 break;
2309
2310 case WID_C_COMPANY_NAME:
2311 Command<Commands::RenameCompany>::Post(STR_ERROR_CAN_T_CHANGE_COMPANY_NAME, *str);
2312 break;
2313 }
2314 }
2315
2316 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
2317 {
2318 if (!gui_scope) return;
2319
2320 /* Manually call OnResize to adjust minimum height of president name widget. */
2321 if (data == WID_C_PRESIDENT_NAME) this->OnResize();
2322
2323 /* If a query string is visible, update its default value. */
2324 if (this->query_widget != CompanyWindow::INVALID_QUERY_WIDGET && data == this->query_widget) {
2325 UpdateQueryStringDefault(GetString(data == WID_C_COMPANY_NAME ? STR_COMPANY_NAME : STR_PRESIDENT_NAME, this->window_number));
2326 }
2327 }
2328};
2329
2332 WindowPosition::Automatic, "company", 0, 0,
2334 {},
2335 _nested_company_widgets
2336);
2337
2342void ShowCompany(CompanyID company)
2343{
2344 if (!Company::IsValidID(company)) return;
2345
2347}
2348
2354{
2355 SetWindowDirty(WC_COMPANY, company);
2357}
2358
2359struct BuyCompanyWindow : Window {
2361 {
2362 this->InitNested(window_number);
2363
2364 const Company *c = Company::Get(this->window_number);
2365 this->company_value = hostile_takeover ? CalculateHostileTakeoverValue(c) : c->bankrupt_value;
2366 }
2367
2368 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2369 {
2370 switch (widget) {
2371 case WID_BC_FACE:
2372 size = GetScaledSpriteSize(SPR_GRADIENT);
2373 break;
2374
2375 case WID_BC_QUESTION:
2376 const Company *c = Company::Get(this->window_number);
2377 size.height = GetStringHeight(GetString(this->hostile_takeover ? STR_BUY_COMPANY_HOSTILE_TAKEOVER : STR_BUY_COMPANY_MESSAGE, c->index, this->company_value), size.width);
2378 break;
2379 }
2380 }
2381
2382 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
2383 {
2384 switch (widget) {
2385 case WID_BC_CAPTION:
2386 return GetString(STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY, Company::Get(this->window_number)->index);
2387
2388 default:
2389 return this->Window::GetWidgetString(widget, stringid);
2390 }
2391 }
2392
2393 void DrawWidget(const Rect &r, WidgetID widget) const override
2394 {
2395 switch (widget) {
2396 case WID_BC_FACE: {
2397 const Company *c = Company::Get(this->window_number);
2399 break;
2400 }
2401
2402 case WID_BC_QUESTION: {
2403 const Company *c = Company::Get(this->window_number);
2404 DrawStringMultiLine(r, GetString(this->hostile_takeover ? STR_BUY_COMPANY_HOSTILE_TAKEOVER : STR_BUY_COMPANY_MESSAGE, c->index, this->company_value), TC_FROMSTRING, SA_CENTER);
2405 break;
2406 }
2407 }
2408 }
2409
2410 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2411 {
2412 switch (widget) {
2413 case WID_BC_NO:
2414 this->Close();
2415 break;
2416
2417 case WID_BC_YES:
2418 Command<Commands::BuyCompany>::Post(STR_ERROR_CAN_T_BUY_COMPANY, this->window_number, this->hostile_takeover);
2419 break;
2420 }
2421 }
2422
2426 const IntervalTimer<TimerWindow> rescale_interval = {std::chrono::seconds(3), [this](auto) {
2427 /* Value can't change when in bankruptcy. */
2428 if (!this->hostile_takeover) return;
2429
2430 const Company *c = Company::Get(this->window_number);
2431 auto new_value = CalculateHostileTakeoverValue(c);
2432 if (new_value != this->company_value) {
2433 this->company_value = new_value;
2434 this->ReInit();
2435 }
2436 }};
2437
2438private:
2439 bool hostile_takeover = false;
2441};
2442
2443static constexpr std::initializer_list<NWidgetPart> _nested_buy_company_widgets = {
2447 EndContainer(),
2453 EndContainer(),
2457 EndContainer(),
2458 EndContainer(),
2459 EndContainer(),
2460};
2461
2464 WindowPosition::Automatic, {}, 0, 0,
2467 _nested_buy_company_widgets
2468);
2469
2475void ShowBuyCompanyDialog(CompanyID company, bool hostile_takeover)
2476{
2477 auto window = BringWindowToFrontById(WC_BUY_COMPANY, company);
2478 if (window == nullptr) {
2479 new BuyCompanyWindow(_buy_company_desc, company, hostile_takeover);
2480 }
2481}
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 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 WindowDesc _select_company_livery_desc(WindowPosition::Automatic, "company_colour_scheme", 0, 0, WC_COMPANY_COLOUR, WC_NONE, {}, _nested_select_company_livery_widgets)
Window definition for the company livery configuration window.
static WindowDesc _company_finances_desc(WindowPosition::Automatic, "company_finances", 0, 0, WC_FINANCES, WC_NONE, {}, _nested_company_finances_widgets)
Window definition for the company finances window.
static WindowDesc _select_company_manager_face_desc(WindowPosition::Automatic, {}, 0, 0, WC_COMPANY_MANAGER_FACE, WC_NONE, WindowDefaultFlag::Construction, _nested_select_company_manager_face_widgets)
Company manager face selection window description.
static WindowDesc _buy_company_desc(WindowPosition::Automatic, {}, 0, 0, WC_BUY_COMPANY, WC_NONE, WindowDefaultFlag::Construction, _nested_buy_company_widgets)
Window definition for the window to buy a company.
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 constexpr VehicleTypeIndexArray< const StringID > _company_view_vehicle_count_strings
Strings for the company vehicle counts.
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 WindowDesc _company_desc(WindowPosition::Automatic, "company", 0, 0, WC_COMPANY, WC_NONE, {}, _nested_company_widgets)
Window definition for the company window.
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 WindowDesc _company_infrastructure_desc(WindowPosition::Automatic, "company_infrastructure", 0, 0, WC_COMPANY_INFRASTRUCTURE, WC_NONE, {}, _nested_company_infrastructure_widgets)
Window definition for the company infrastructure statistics window.
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 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.
EnumIndexArray< Money, ExpensesType, ExpensesType::End > Expenses
Data type for storage of Money for each ExpensesType category.
ExpensesType
Types of expenses.
@ LoanInterest
Interest payments over the loan.
@ Construction
Construction costs.
@ TrainRun
Running costs trains.
@ AircraftRevenue
Revenue from aircraft.
@ Property
Property costs.
@ Other
Other expenses.
@ RoadVehRevenue
Revenue from road vehicles.
@ NewVehicles
New vehicles.
@ AircraftRun
Running costs aircraft.
@ RoadVehRun
Running costs road vehicles.
@ ShipRevenue
Revenue from ships.
@ TrainRevenue
Revenue from trains.
@ ShipRun
Running costs ships.
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.
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.
VehicleTypeIndexArray< GroupStatistics > group_all
NOSAVE: Statistics for the ALL_GROUP group.
CompanyInfrastructure infrastructure
NOSAVE: Counts of company owned infrastructure.
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.
@ Ship
Ship vehicle type.
@ Begin
Begin marker.
@ CompanyEnd
Last company-ownable type.
@ Aircraft
Aircraft vehicle type.
@ Road
Road vehicle type.
@ Train
Train vehicle type.
EnumIndexArray< T, VehicleType, Tend > VehicleTypeIndexArray
Array with VehicleType as index.
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.
@ Automatic
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.