OpenTTD Source 20260531-master-g0e951f3528
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), TextColour::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, TextColour::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, TextColour::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, TextColour::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, TextColour::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, TextColour::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), TextColour::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, TextColour::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,
570 WindowClass::Finances, WindowClass::None,
571 {},
572 _nested_company_finances_widgets
573);
574
580void ShowCompanyFinances(CompanyID company)
581{
582 if (!Company::IsValidID(company)) return;
583 if (BringWindowToFrontById(WindowClass::Finances, company)) return;
584
586}
587
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 struct {
628 GroupID group = GroupID::Invalid();
629 } sel{};
630 LiveryClass livery_class{};
631 Dimension square{};
632 uint rows = 0;
633 uint line_height = 0;
634 GUIGroupList groups{};
635 Scrollbar *vscroll = nullptr;
637
638 void ShowColourDropDownMenu(uint32_t widget)
639 {
641 const Livery *livery, *default_livery = nullptr;
642 bool primary = widget == WID_SCL_PRI_COL_DROPDOWN;
643 uint8_t default_col{};
644
645 /* Disallow other company colours for the primary colour */
646 if (this->livery_class < LiveryClass::GroupRail && this->sel.schemes.Test(LiveryScheme::Default) && primary) {
647 for (const Company *c : Company::Iterate()) {
648 if (c->index != _local_company) used_colours.Set(c->colour);
649 }
650 }
651
652 const Company *c = Company::Get(this->window_number);
653
654 if (this->livery_class < LiveryClass::GroupRail) {
655 /* Get the first selected livery to use as the default dropdown item */
656 LiveryScheme scheme = this->sel.schemes.GetNthSetBit(0).value_or(LiveryScheme::Default);
657 livery = &c->livery[scheme];
658 if (scheme != LiveryScheme::Default) default_livery = &c->livery[LiveryScheme::Default];
659 } else {
660 const Group *g = Group::Get(this->sel.group);
661 livery = &g->livery;
662 if (g->parent == GroupID::Invalid()) {
663 default_livery = &c->livery[LiveryScheme::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
691 {
692 visible_schemes.Reset();
693 for (LiveryScheme scheme : _loaded_newgrf_features.used_liveries) {
694 if (_livery_class[scheme] != this->livery_class) continue;
695 visible_schemes.Set(scheme);
696 }
697 }
698
699 void BuildGroupList(CompanyID owner)
700 {
701 if (!this->groups.NeedRebuild()) return;
702
703 this->groups.clear();
704
705 if (this->livery_class >= LiveryClass::GroupRail) {
706 VehicleType vtype = static_cast<VehicleType>(this->livery_class - LiveryClass::GroupRail);
707 BuildGuiGroupList(this->groups, false, owner, vtype);
708 }
709
710 this->groups.RebuildDone();
711 }
712
713 void SetRows()
714 {
715 if (this->livery_class < LiveryClass::GroupRail) {
716 this->rows = this->visible_schemes.Count();
717 } else {
718 this->rows = (uint)this->groups.size();
719 }
720
721 this->vscroll->SetCount(this->rows);
722 }
723
724public:
725 SelectCompanyLiveryWindow(WindowDesc &desc, CompanyID company, GroupID group) : Window(desc)
726 {
727 this->CreateNestedTree();
729 this->vscroll = this->GetScrollbar(WID_SCL_MATRIX_SCROLLBAR);
730
731 if (group == GroupID::Invalid()) {
732 this->livery_class = LiveryClass::Other;
733 this->sel.schemes = LiveryScheme::Default;
735 this->BuildLiveryList();
736 this->BuildGroupList(company);
737 this->SetRows();
738 } else {
739 this->SetSelectedGroup(company, group);
740 }
741
742 this->FinishInitNested(company);
743 this->owner = company;
744 this->InvalidateData(1);
745 }
746
747 void SetSelectedGroup(CompanyID company, GroupID group)
748 {
749 this->RaiseWidget(WID_SCL_CLASS_GENERAL + this->livery_class);
750 const Group *g = Group::Get(group);
751 switch (g->vehicle_type) {
752 case VehicleType::Train: this->livery_class = LiveryClass::GroupRail; break;
753 case VehicleType::Road: this->livery_class = LiveryClass::GroupRoad; break;
754 case VehicleType::Ship: this->livery_class = LiveryClass::GroupShip; break;
755 case VehicleType::Aircraft: this->livery_class = LiveryClass::GroupAircraft; break;
756 default: NOT_REACHED();
757 }
758 this->sel.group = group;
759 this->LowerWidget(WID_SCL_CLASS_GENERAL + this->livery_class);
760
761 this->groups.ForceRebuild();
762 this->BuildGroupList(company);
763 this->SetRows();
764
765 /* Position scrollbar to selected group */
766 for (uint i = 0; i < this->rows; i++) {
767 if (this->groups[i].group->index == this->sel.group) {
768 this->vscroll->SetPosition(i - this->vscroll->GetCapacity() / 2);
769 break;
770 }
771 }
772 }
773
774 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
775 {
776 switch (widget) {
778 /* The matrix widget below needs enough room to print all the schemes. */
779 Dimension d = {0, 0};
780 for (LiveryScheme scheme : _loaded_newgrf_features.used_liveries) {
781 d = maxdim(d, GetStringBoundingBox(STR_LIVERY_DEFAULT + to_underlying(scheme)));
782 }
783
784 size.width = std::max(size.width, 5 + d.width + padding.width);
785 break;
786 }
787
788 case WID_SCL_MATRIX: {
789 /* 11 items in the default rail class */
790 this->square = GetSpriteSize(SPR_SQUARE);
791 this->line_height = std::max(this->square.height, (uint)GetCharacterHeight(FontSize::Normal)) + padding.height;
792
793 size.height = 5 * this->line_height;
794 resize.width = 1;
795 fill.height = resize.height = this->line_height;
796 break;
797 }
798
800 if (!_loaded_newgrf_features.has_2CC) break;
801 [[fallthrough]];
802
804 this->square = GetSpriteSize(SPR_SQUARE);
805 int string_padding = this->square.width + WidgetDimensions::scaled.hsep_normal + padding.width;
806 for (Colours colour = Colours::Begin; colour != Colours::End; colour++) {
807 size.width = std::max(size.width, GetStringBoundingBox(STR_COLOUR_DARK_BLUE + to_underlying(colour)).width + string_padding);
808 }
809 size.width = std::max(size.width, GetStringBoundingBox(STR_COLOUR_DEFAULT).width + string_padding);
810 break;
811 }
812 }
813 }
814
815 void OnPaint() override
816 {
817 bool local = this->window_number == _local_company;
818
819 /* Disable dropdown controls if no scheme is selected */
820 bool disabled = this->livery_class < LiveryClass::GroupRail ? this->sel.schemes.None() : (this->sel.group == GroupID::Invalid());
821 this->SetWidgetDisabledState(WID_SCL_PRI_COL_DROPDOWN, !local || disabled);
822 this->SetWidgetDisabledState(WID_SCL_SEC_COL_DROPDOWN, !local || disabled);
823
824 this->BuildGroupList(this->window_number);
825
826 this->DrawWidgets();
827 }
828
829 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
830 {
831 switch (widget) {
832 case WID_SCL_CAPTION:
833 return GetString(STR_LIVERY_CAPTION, this->window_number);
834
837 const Company *c = Company::Get(this->window_number);
838 bool primary = widget == WID_SCL_PRI_COL_DROPDOWN;
839 StringID colour = STR_COLOUR_DEFAULT;
840
841 if (this->livery_class < LiveryClass::GroupRail) {
842 LiveryScheme scheme = this->sel.schemes.GetNthSetBit(0).value_or(LiveryScheme::End);
843 if (scheme != LiveryScheme::End) {
844 const Livery &livery = c->livery[scheme];
846 colour = STR_COLOUR_DARK_BLUE + GetColourOffset(livery, primary);
847 }
848 }
849 } else {
850 if (this->sel.group != GroupID::Invalid()) {
851 const Group *g = Group::Get(this->sel.group);
852 const Livery &livery = g->livery;
854 colour = STR_COLOUR_DARK_BLUE + GetColourOffset(livery, primary);
855 }
856 }
857 }
858 return GetString(colour);
859 }
860
861 default:
862 return this->Window::GetWidgetString(widget, stringid);
863 }
864 }
865
866 void DrawWidget(const Rect &r, WidgetID widget) const override
867 {
868 if (widget != WID_SCL_MATRIX) return;
869
870 bool rtl = _current_text_dir == TD_RTL;
871
872 /* Coordinates of scheme name column. */
874 Rect sch = nwi->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
875 /* Coordinates of first dropdown. */
877 Rect pri = nwi->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
878 /* Coordinates of second dropdown. */
880 Rect sec = nwi->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
881
882 Rect pri_squ = pri.WithWidth(this->square.width, rtl);
883 Rect sec_squ = sec.WithWidth(this->square.width, rtl);
884
885 pri = pri.Indent(this->square.width + WidgetDimensions::scaled.hsep_normal, rtl);
886 sec = sec.Indent(this->square.width + WidgetDimensions::scaled.hsep_normal, rtl);
887
888 Rect ir = r.WithHeight(this->resize.step_height).Shrink(WidgetDimensions::scaled.matrix);
889 int square_offs = (ir.Height() - this->square.height) / 2;
890 int text_offs = (ir.Height() - GetCharacterHeight(FontSize::Normal)) / 2;
891
892 int y = ir.top;
893
894 /* Helper function to draw livery info. */
895 auto draw_livery = [&](std::string_view str, const Livery &livery, bool is_selected, bool is_default_scheme, int indent) {
896 /* Livery Label. */
897 DrawString(sch.left + (rtl ? 0 : indent), sch.right - (rtl ? indent : 0), y + text_offs, str, is_selected ? TextColour::White : TextColour::Black);
898
899 /* Text below the first dropdown. */
900 DrawSprite(SPR_SQUARE, GetColourPalette(livery.colour1), pri_squ.left, y + square_offs);
901 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 ? TextColour::White : TextColour::Gold);
902
903 /* Text below the second dropdown. */
904 if (sec.right > sec.left) { // Second dropdown has non-zero size.
905 DrawSprite(SPR_SQUARE, GetColourPalette(livery.colour2), sec_squ.left, y + square_offs);
906 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 ? TextColour::White : TextColour::Gold);
907 }
908
909 y += this->line_height;
910 };
911
912 const Company *c = Company::Get(this->window_number);
913
914 if (livery_class < LiveryClass::GroupRail) {
915 int pos = this->vscroll->GetPosition();
916 for (LiveryScheme scheme : this->visible_schemes) {
917 if (pos-- > 0) continue;
918 draw_livery(GetString(STR_LIVERY_DEFAULT + to_underlying(scheme)), c->livery[scheme], this->sel.schemes.Test(scheme), scheme == LiveryScheme::Default, 0);
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.group == 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 = static_cast<VehicleType>(this->livery_class - LiveryClass::GroupRail);
930 DrawString(ir.left, ir.right, y + text_offs, empty_labels[vtype], TextColour::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 = static_cast<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 < LiveryClass::GroupRail) {
954 this->BuildLiveryList();
955 this->sel.schemes = this->visible_schemes.GetNthSetBit(0).value_or(LiveryScheme::Default);
956 } else {
957 this->sel.group = GroupID::Invalid();
958 this->groups.ForceRebuild();
959 this->BuildGroupList(this->window_number);
960
961 if (!this->groups.empty()) {
962 this->sel.group = this->groups[0].group->index;
963 }
964 }
965
966 this->SetRows();
967 this->SetDirty();
968 break;
969
970 case WID_SCL_PRI_COL_DROPDOWN: // First colour dropdown
971 ShowColourDropDownMenu(WID_SCL_PRI_COL_DROPDOWN);
972 break;
973
974 case WID_SCL_SEC_COL_DROPDOWN: // Second colour dropdown
975 ShowColourDropDownMenu(WID_SCL_SEC_COL_DROPDOWN);
976 break;
977
978 case WID_SCL_MATRIX: {
979 if (this->livery_class < LiveryClass::GroupRail) {
980 uint row = this->vscroll->GetScrolledRowFromWidget(pt.y, this, widget);
981 if (row >= this->rows) return;
982
983 LiveryScheme scheme = this->visible_schemes.GetNthSetBit(row).value();
984
985 if (_ctrl_pressed) {
986 this->sel.schemes.Flip(scheme);
987 } else {
988 this->sel.schemes = scheme;
989 }
990 } else {
991 auto it = this->vscroll->GetScrolledItemFromWidget(this->groups, pt.y, this, widget);
992 if (it == std::end(this->groups)) return;
993
994 this->sel.group = it->group->index;
995 }
996 this->SetDirty();
997 break;
998 }
999 }
1000 }
1001
1002 void OnResize() override
1003 {
1004 this->vscroll->SetCapacityFromWidget(this, WID_SCL_MATRIX);
1005 }
1006
1007 void OnDropdownSelect(WidgetID widget, int index, int) override
1008 {
1009 bool local = this->window_number == _local_company;
1010 if (!local) return;
1011
1012 Colours colour = static_cast<Colours>(index);
1013 if (colour >= Colours::End) colour = Colours::Invalid;
1014
1015 if (this->livery_class < LiveryClass::GroupRail) {
1016 /* Set company colour livery */
1017 for (LiveryScheme scheme : this->visible_schemes) {
1018 /* Changed colour for the selected scheme, or all visible schemes if CTRL is pressed. */
1019 if (this->sel.schemes.Test(scheme) || _ctrl_pressed) {
1020 Command<Commands::SetCompanyColour>::Post(scheme, widget == WID_SCL_PRI_COL_DROPDOWN, colour);
1021 }
1022 }
1023 } else {
1024 /* Setting group livery */
1025 Command<Commands::SetGroupLivery>::Post(this->sel.group, widget == WID_SCL_PRI_COL_DROPDOWN, colour);
1026 }
1027 }
1028
1034 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1035 {
1036 if (!gui_scope) return;
1037
1038 if (data != -1) {
1039 /* data contains a VehicleType, rebuild list if it is displayed */
1040 if (this->livery_class == static_cast<LiveryClass>(to_underlying(LiveryClass::GroupRail) + data)) {
1041 this->groups.ForceRebuild();
1042 this->BuildGroupList(this->window_number);
1043 this->SetRows();
1044
1045 if (!Group::IsValidID(this->sel.group)) {
1046 this->sel.group = GroupID::Invalid();
1047 if (!this->groups.empty()) this->sel.group = this->groups[0].group->index;
1048 }
1049
1050 this->SetDirty();
1051 }
1052 return;
1053 }
1054
1056
1057 bool current_class_valid = this->livery_class == LiveryClass::Other || this->livery_class >= LiveryClass::GroupRail;
1058 if (_settings_client.gui.liveries == LIT_ALL || (_settings_client.gui.liveries == LIT_COMPANY && this->window_number == _local_company)) {
1059 /* Clear selection of unused schemes. */
1060 this->sel.schemes &= _loaded_newgrf_features.used_liveries;
1061 for (LiveryScheme scheme : _loaded_newgrf_features.used_liveries) {
1062 if (_livery_class[scheme] == this->livery_class) current_class_valid = true;
1064 }
1065 }
1066
1067 if (!current_class_valid) {
1068 Point pt = {0, 0};
1069 this->OnClick(pt, WID_SCL_CLASS_GENERAL, 1);
1070 }
1071 }
1072};
1073
1074static constexpr std::initializer_list<NWidgetPart> _nested_select_company_livery_widgets = {
1081 EndContainer(),
1083 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCL_CLASS_GENERAL), SetToolbarMinimalSize(1), SetFill(0, 1), SetSpriteTip(SPR_IMG_COMPANY_GENERAL, STR_LIVERY_GENERAL_TOOLTIP),
1084 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCL_CLASS_RAIL), SetToolbarMinimalSize(1), SetFill(0, 1), SetSpriteTip(SPR_IMG_TRAINLIST, STR_LIVERY_TRAIN_TOOLTIP),
1085 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCL_CLASS_ROAD), SetToolbarMinimalSize(1), SetFill(0, 1), SetSpriteTip(SPR_IMG_TRUCKLIST, STR_LIVERY_ROAD_VEHICLE_TOOLTIP),
1086 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCL_CLASS_SHIP), SetToolbarMinimalSize(1), SetFill(0, 1), SetSpriteTip(SPR_IMG_SHIPLIST, STR_LIVERY_SHIP_TOOLTIP),
1087 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCL_CLASS_AIRCRAFT), SetToolbarMinimalSize(1), SetFill(0, 1), SetSpriteTip(SPR_IMG_AIRPLANESLIST, STR_LIVERY_AIRCRAFT_TOOLTIP),
1088 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCL_GROUPS_RAIL), SetToolbarMinimalSize(1), SetFill(0, 1), SetSpriteTip(SPR_GROUP_LIVERY_TRAIN, STR_LIVERY_TRAIN_GROUP_TOOLTIP),
1089 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),
1090 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCL_GROUPS_SHIP), SetToolbarMinimalSize(1), SetFill(0, 1), SetSpriteTip(SPR_GROUP_LIVERY_SHIP, STR_LIVERY_SHIP_GROUP_TOOLTIP),
1091 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCL_GROUPS_AIRCRAFT), SetToolbarMinimalSize(1), SetFill(0, 1), SetSpriteTip(SPR_GROUP_LIVERY_AIRCRAFT, STR_LIVERY_AIRCRAFT_GROUP_TOOLTIP),
1093 EndContainer(),
1097 EndContainer(),
1100 NWidget(WWT_DROPDOWN, Colours::Grey, WID_SCL_PRI_COL_DROPDOWN), SetFill(0, 1), SetToolTip(STR_LIVERY_PRIMARY_TOOLTIP),
1102 NWidget(WWT_DROPDOWN, Colours::Grey, WID_SCL_SEC_COL_DROPDOWN), SetFill(0, 1), SetToolTip(STR_LIVERY_SECONDARY_TOOLTIP),
1103 EndContainer(),
1105 EndContainer(),
1106};
1107
1110 WindowPosition::Automatic, "company_colour_scheme", 0, 0,
1111 WindowClass::CompanyLivery, WindowClass::None,
1112 {},
1113 _nested_select_company_livery_widgets
1114);
1115
1116void ShowCompanyLiveryWindow(CompanyID company, GroupID group)
1117{
1118 SelectCompanyLiveryWindow *w = (SelectCompanyLiveryWindow *)BringWindowToFrontById(WindowClass::CompanyLivery, company);
1119 if (w == nullptr) {
1121 } else if (group != GroupID::Invalid()) {
1122 w->SetSelectedGroup(company, group);
1123 }
1124}
1125
1132void DrawCompanyManagerFace(const CompanyManagerFace &cmf, Colours colour, const Rect &r)
1133{
1134 /* Determine offset from centre of drawing rect. */
1135 Dimension d = GetSpriteSize(SPR_GRADIENT);
1136 int x = CentreBounds(r.left, r.right, d.width);
1137 int y = CentreBounds(r.top, r.bottom, d.height);
1138
1139 FaceVars vars = GetCompanyManagerFaceVars(cmf.style);
1140
1141 /* First determine which parts are enabled. */
1142 uint64_t active_vars = GetActiveFaceVars(cmf, vars);
1143
1144 std::unordered_map<uint8_t, PaletteID> palettes;
1145
1146 /* Second, get palettes. */
1147 for (auto var : SetBitIterator(active_vars)) {
1148 if (vars[var].type != FaceVarType::Palette) continue;
1149
1150 PaletteID pal = PAL_NONE;
1151 switch (vars[var].GetBits(cmf)) {
1152 default: NOT_REACHED();
1153 case 0: pal = PALETTE_TO_BROWN; break;
1154 case 1: pal = PALETTE_TO_BLUE; break;
1155 case 2: pal = PALETTE_TO_GREEN; break;
1156 }
1157 for (uint8_t affected_var : SetBitIterator(std::get<uint64_t>(vars[var].data))) {
1158 palettes[affected_var] = pal;
1159 }
1160 }
1161
1162 /* Draw the gradient (background) */
1163 DrawSprite(SPR_GRADIENT, GetColourPalette(colour), x, y);
1164
1165 /* Thirdly, draw sprites. */
1166 for (auto var : SetBitIterator(active_vars)) {
1167 if (vars[var].type != FaceVarType::Sprite) continue;
1168
1169 auto it = palettes.find(var);
1170 PaletteID pal = (it == std::end(palettes)) ? PAL_NONE : it->second;
1171 DrawSprite(vars[var].GetSprite(cmf), pal, x, y);
1172 }
1173}
1174
1176static constexpr std::initializer_list<NWidgetPart> _nested_select_company_manager_face_widgets = {
1179 NWidget(WWT_CAPTION, Colours::Grey, WID_SCMF_CAPTION), SetStringTip(STR_FACE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1180 NWidget(WWT_IMGBTN, Colours::Grey, WID_SCMF_TOGGLE_LARGE_SMALL), SetSpriteTip(SPR_LARGE_SMALL_WINDOW, STR_FACE_ADVANCED_TOOLTIP), SetAspect(WidgetDimensions::ASPECT_TOGGLE_SIZE),
1181 EndContainer(),
1184 /* Left side */
1187 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SCMF_RANDOM_NEW_FACE), SetFill(1, 0), SetStringTip(STR_FACE_NEW_FACE_BUTTON, STR_FACE_NEW_FACE_TOOLTIP),
1188 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON), SetFill(1, 0), SetStringTip(STR_FACE_ADVANCED, STR_FACE_ADVANCED_TOOLTIP),
1189 NWidget(NWID_SELECTION, Colours::Invalid, WID_SCMF_SEL_LOADSAVE), // Load/number/save buttons under the portrait in the advanced view.
1191 NWidget(NWID_SPACER), SetFill(1, 1), SetResize(0, 1),
1192 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SCMF_LOAD), SetFill(1, 0), SetStringTip(STR_FACE_LOAD, STR_FACE_LOAD_TOOLTIP),
1193 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SCMF_FACECODE), SetFill(1, 0), SetStringTip(STR_FACE_FACECODE, STR_FACE_FACECODE_TOOLTIP),
1194 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SCMF_SAVE), SetFill(1, 0), SetStringTip(STR_FACE_SAVE, STR_FACE_SAVE_TOOLTIP),
1195 EndContainer(),
1196 EndContainer(),
1197 EndContainer(),
1198 EndContainer(),
1199 /* Right side */
1200 NWidget(NWID_SELECTION, Colours::Invalid, WID_SCMF_SEL_PARTS), // Advanced face parts setting.
1206 EndContainer(),
1207 EndContainer(),
1208 EndContainer(),
1209 EndContainer(),
1211 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SCMF_CANCEL), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_BUTTON_CANCEL, STR_FACE_CANCEL_TOOLTIP),
1212 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_SCMF_ACCEPT), SetFill(1, 0), SetResize(1, 0), SetStringTip(STR_BUTTON_OK, STR_FACE_OK_TOOLTIP),
1215 EndContainer(),
1216 EndContainer(),
1217};
1218
1220class SelectCompanyManagerFaceWindow : public Window
1221{
1223 bool advanced = false;
1224 uint selected_var = UINT_MAX;
1225 uint click_state = 0;
1226 int line_height = 0;
1227
1228 std::vector<const FaceVar *> face_vars;
1229
1234 {
1235 FaceVars vars = GetCompanyManagerFaceVars(this->face.style);
1236 ScaleAllCompanyManagerFaceBits(this->face, vars);
1237
1238 uint64_t active_vars = GetActiveFaceVars(this->face, vars);
1239 /* Exclude active parts which have no string. */
1240 for (auto var : SetBitIterator(active_vars)) {
1241 if (vars[var].name == STR_NULL) ClrBit(active_vars, var);
1242 }
1243
1244 /* Rebuild the sorted list of face variable pointers. */
1245 this->face_vars.clear();
1246 for (auto var : SetBitIterator(active_vars)) {
1247 this->face_vars.emplace_back(&vars[var]);
1248 }
1249 std::ranges::sort(this->face_vars, std::less{}, &FaceVar::position);
1250
1251 this->GetScrollbar(WID_SCMF_PARTS_SCROLLBAR)->SetCount(std::size(this->face_vars));
1252 }
1253
1254public:
1256 {
1257 this->CreateNestedTree();
1258 this->SelectDisplayPlanes(this->advanced);
1259 this->FinishInitNested(parent->window_number);
1260 this->parent = parent;
1261 this->owner = this->window_number;
1262 this->face = Company::Get(this->window_number)->face;
1263
1264 this->UpdateData();
1265 }
1266
1267 void OnInit() override
1268 {
1269 this->line_height = std::max(SETTING_BUTTON_HEIGHT, GetCharacterHeight(FontSize::Normal)) + WidgetDimensions::scaled.matrix.Vertical();
1270 }
1271
1277 {
1279 this->GetWidget<NWidgetStacked>(WID_SCMF_SEL_PARTS)->SetDisplayedPlane(advanced ? 0 : SZSP_NONE);
1280 this->GetWidget<NWidgetStacked>(WID_SCMF_SEL_RESIZE)->SetDisplayedPlane(advanced ? 0 : SZSP_NONE);
1281
1283 if (advanced) {
1284 wi->SetStringTip(STR_FACE_SIMPLE, STR_FACE_SIMPLE_TOOLTIP);
1285 } else {
1286 wi->SetStringTip(STR_FACE_ADVANCED, STR_FACE_ADVANCED_TOOLTIP);
1287 }
1288 }
1289
1290 static StringID GetLongestString(StringID a, StringID b)
1291 {
1292 return GetStringBoundingBox(a).width > GetStringBoundingBox(b).width ? a : b;
1293 }
1294
1295 static uint GetMaximumFacePartsWidth()
1296 {
1297 StringID yes_no = GetLongestString(STR_FACE_YES, STR_FACE_NO);
1298
1299 uint width = 0;
1300 for (uint style_index = 0; style_index != GetNumCompanyManagerFaceStyles(); ++style_index) {
1301 FaceVars vars = GetCompanyManagerFaceVars(style_index);
1302 for (const auto &info : vars) {
1303 if (info.name == STR_NULL) continue;
1304 if (info.type == FaceVarType::Toggle) {
1305 width = std::max(width, GetStringBoundingBox(GetString(STR_FACE_SETTING_TOGGLE, info.name, yes_no)).width);
1306 } else {
1307 uint64_t max_digits = GetParamMaxValue(info.valid_values);
1308 width = std::max(width, GetStringBoundingBox(GetString(STR_FACE_SETTING_NUMERIC, info.name, max_digits, max_digits)).width);
1309 }
1310 }
1311 }
1312
1313 /* Include width of button and spacing. */
1315 return width;
1316 }
1317
1318 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
1319 {
1320 switch (widget) {
1321 case WID_SCMF_FACE:
1322 size = maxdim(size, GetScaledSpriteSize(SPR_GRADIENT));
1323 break;
1324
1325 case WID_SCMF_STYLE:
1326 size.height = this->line_height;
1327 break;
1328
1329 case WID_SCMF_PARTS:
1330 fill.height = resize.height = this->line_height;
1331 size.width = GetMaximumFacePartsWidth();
1332 size.height = resize.height * 5;
1333 break;
1334 }
1335 }
1336
1337 void DrawWidget(const Rect &r, WidgetID widget) const override
1338 {
1339 switch (widget) {
1340 case WID_SCMF_FACE:
1341 DrawCompanyManagerFace(this->face, Company::Get(this->window_number)->colour, r);
1342 break;
1343
1344 case WID_SCMF_STYLE: {
1345 Rect ir = r.Shrink(WidgetDimensions::scaled.frametext, RectPadding::zero).WithHeight(this->line_height);
1346 bool rtl = _current_text_dir == TD_RTL;
1347
1350
1351 DrawArrowButtons(br.left, br.top, Colours::Yellow, this->selected_var == UINT_MAX - 1 ? this->click_state : 0, true, true);
1352 DrawString(tr, GetString(STR_FACE_SETTING_NUMERIC, STR_FACE_STYLE, this->face.style + 1, GetNumCompanyManagerFaceStyles()), TextColour::White);
1353 break;
1354 }
1355
1356 case WID_SCMF_PARTS: {
1357 Rect ir = r.Shrink(WidgetDimensions::scaled.frametext, RectPadding::zero).WithHeight(this->line_height);
1358 bool rtl = _current_text_dir == TD_RTL;
1359
1360 FaceVars vars = GetCompanyManagerFaceVars(this->face.style);
1361
1362 auto [first, last] = this->GetScrollbar(WID_SCMF_PARTS_SCROLLBAR)->GetVisibleRangeIterators(this->face_vars);
1363 for (auto it = first; it != last; ++it) {
1364 const uint8_t var = static_cast<uint8_t>(*it - vars.data());
1365 const FaceVar &facevar = **it;
1366
1369
1370 uint val = vars[var].GetBits(this->face);
1371 if (facevar.type == FaceVarType::Toggle) {
1372 DrawBoolButton(br.left, br.top, Colours::Yellow, Colours::Grey, val == 1, true);
1373 DrawString(tr, GetString(STR_FACE_SETTING_TOGGLE, facevar.name, val == 1 ? STR_FACE_YES : STR_FACE_NO), TextColour::White);
1374 } else {
1375 DrawArrowButtons(br.left, br.top, Colours::Yellow, this->selected_var == var ? this->click_state : 0, true, true);
1376 DrawString(tr, GetString(STR_FACE_SETTING_NUMERIC, facevar.name, val + 1, facevar.valid_values), TextColour::White);
1377 }
1378
1379 ir = ir.Translate(0, this->line_height);
1380 }
1381 break;
1382 }
1383 }
1384 }
1385
1386 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1387 {
1388 switch (widget) {
1389 /* Toggle size, advanced/simple face selection */
1392 this->advanced = !this->advanced;
1393 this->SelectDisplayPlanes(this->advanced);
1394 this->ReInit();
1395 break;
1396
1397 /* OK button */
1398 case WID_SCMF_ACCEPT:
1399 Command<Commands::SetCompanyManagerFace>::Post(this->face.style, this->face.bits);
1400 [[fallthrough]];
1401
1402 /* Cancel button */
1403 case WID_SCMF_CANCEL:
1404 this->Close();
1405 break;
1406
1407 /* Load button */
1408 case WID_SCMF_LOAD: {
1410 if (cmf.has_value()) this->face = *cmf;
1411 ShowErrorMessage(GetEncodedString(STR_FACE_LOAD_DONE), {}, WarningLevel::Info);
1412 this->UpdateData();
1413 this->SetDirty();
1414 break;
1415 }
1416
1417 /* 'Company manager face number' button, view and/or set company manager face number */
1418 case WID_SCMF_FACECODE:
1419 ShowQueryString(FormatCompanyManagerFaceCode(this->face), STR_FACE_FACECODE_CAPTION, 128, this, CS_ALPHANUMERAL, {});
1420 break;
1421
1422 /* Save button */
1423 case WID_SCMF_SAVE:
1425 ShowErrorMessage(GetEncodedString(STR_FACE_SAVE_DONE), {}, WarningLevel::Info);
1426 break;
1427
1428 /* Randomize face button */
1431 this->UpdateData();
1432 this->SetDirty();
1433 break;
1434
1435 case WID_SCMF_STYLE: {
1436 bool rtl = _current_text_dir == TD_RTL;
1437 Rect ir = this->GetWidget<NWidgetCore>(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.frametext, RectPadding::zero);
1438 Rect br = ir.WithWidth(SETTING_BUTTON_WIDTH, rtl);
1439
1440 uint num_styles = GetNumCompanyManagerFaceStyles();
1441 this->selected_var = UINT_MAX - 1;
1442 if (IsInsideBS(pt.x, br.left, SETTING_BUTTON_WIDTH / 2)) {
1443 SetCompanyManagerFaceStyle(this->face, (this->face.style + num_styles - 1) % num_styles);
1444 this->click_state = 1;
1445 } else if (IsInsideBS(pt.x, br.left + SETTING_BUTTON_WIDTH / 2, SETTING_BUTTON_WIDTH / 2)) {
1446 SetCompanyManagerFaceStyle(this->face, (this->face.style + 1) % num_styles);
1447 this->click_state = 2;
1448 }
1449
1450 this->UpdateData();
1451 this->SetTimeout();
1452 this->SetDirty();
1453 break;
1454 }
1455
1456 case WID_SCMF_PARTS: {
1457 bool rtl = _current_text_dir == TD_RTL;
1458 Rect ir = this->GetWidget<NWidgetCore>(widget)->GetCurrentRect().Shrink(WidgetDimensions::scaled.frametext, RectPadding::zero);
1459 Rect br = ir.WithWidth(SETTING_BUTTON_WIDTH, rtl);
1460
1461 this->selected_var = UINT_MAX;
1462
1463 FaceVars vars = GetCompanyManagerFaceVars(this->face.style);
1464 auto it = this->GetScrollbar(WID_SCMF_PARTS_SCROLLBAR)->GetScrolledItemFromWidget(this->face_vars, pt.y, this, widget, 0, this->line_height);
1465 if (it == std::end(this->face_vars)) break;
1466
1467 this->selected_var = static_cast<uint8_t>(*it - vars.data());
1468 const auto &facevar = **it;
1469
1470 if (facevar.type == FaceVarType::Toggle) {
1471 if (!IsInsideBS(pt.x, br.left, SETTING_BUTTON_WIDTH)) break;
1472 facevar.ChangeBits(this->face, 1);
1473 this->UpdateData();
1474 } else {
1475 if (IsInsideBS(pt.x, br.left, SETTING_BUTTON_WIDTH / 2)) {
1476 facevar.ChangeBits(this->face, -1);
1477 this->click_state = 1;
1478 } else if (IsInsideBS(pt.x, br.left + SETTING_BUTTON_WIDTH / 2, SETTING_BUTTON_WIDTH / 2)) {
1479 facevar.ChangeBits(this->face, 1);
1480 this->click_state = 2;
1481 } else {
1482 break;
1483 }
1484 }
1485
1486 this->SetTimeout();
1487 this->SetDirty();
1488 break;
1489 }
1490 }
1491 }
1492
1493 void OnResize() override
1494 {
1495 if (auto *wid = this->GetWidget<NWidgetResizeBase>(WID_SCMF_PARTS); wid != nullptr) {
1496 /* Workaround for automatic widget sizing ignoring resize steps. Manually ensure parts matrix is a
1497 * multiple of its resize step. This trick only works here as the window itself is not resizable. */
1498 if (wid->UpdateVerticalSize((wid->current_y + wid->resize_y - 1) / wid->resize_y * wid->resize_y)) {
1499 this->ReInit();
1500 return;
1501 }
1502 }
1503
1505 }
1506
1507 void OnTimeout() override
1508 {
1509 this->click_state = 0;
1510 this->selected_var = UINT_MAX;
1511 this->SetDirty();
1512 }
1513
1514 void OnQueryTextFinished(std::optional<std::string> str) override
1515 {
1516 if (!str.has_value()) return;
1517 /* Parse new company manager face number */
1518 auto cmf = ParseCompanyManagerFaceCode(*str);
1519 if (cmf.has_value()) {
1520 this->face = *cmf;
1521 ShowErrorMessage(GetEncodedString(STR_FACE_FACECODE_SET), {}, WarningLevel::Info);
1522 this->UpdateData();
1523 this->SetDirty();
1524 } else {
1525 ShowErrorMessage(GetEncodedString(STR_FACE_FACECODE_ERR), {}, WarningLevel::Info);
1526 }
1527 }
1528};
1529
1532 WindowPosition::Automatic, {}, 0, 0,
1533 WindowClass::CompanyManagerFace, WindowClass::None,
1536);
1537
1544{
1545 if (!Company::IsValidID(parent->window_number)) return;
1546
1547 if (BringWindowToFrontById(WindowClass::CompanyManagerFace, parent->window_number)) return;
1549}
1550
1551static constexpr std::initializer_list<NWidgetPart> _nested_company_infrastructure_widgets = {
1558 EndContainer(),
1562 EndContainer(),
1566 EndContainer(),
1567 EndContainer(),
1568};
1569
1573struct CompanyInfrastructureWindow : Window
1574{
1581
1584 StringID label;
1585 uint count;
1586 Money cost;
1587 };
1588
1589 uint count_width = 0;
1590 uint cost_width = 0;
1591
1592 mutable std::vector<InfrastructureItem> list;
1593
1594 CompanyInfrastructureWindow(WindowDesc &desc, WindowNumber window_number) : Window(desc)
1595 {
1596 this->InitNested(window_number);
1597 this->owner = this->window_number;
1598 }
1599
1600 void OnInit() override
1601 {
1602 this->UpdateInfrastructureList();
1603 }
1604
1605 void UpdateInfrastructureList()
1606 {
1607 this->list.clear();
1608
1609 const Company *c = Company::GetIfValid(this->window_number);
1610 if (c == nullptr) return;
1611
1612 Money total_monthly_cost = 0;
1613
1614 if (uint32_t rail_total = c->infrastructure.GetRailTotal(); rail_total > 0) {
1615 /* Rail types and signals. */
1616 this->list.emplace_back(InfrastructureItemType::Header, STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT);
1617
1618 for (const RailType &rt : _sorted_railtypes) {
1619 if (c->infrastructure.rail[rt] == 0) continue;
1620 Money monthly_cost = RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total);
1621 total_monthly_cost += monthly_cost;
1622 this->list.emplace_back(InfrastructureItemType::Value, GetRailTypeInfo(rt)->strings.name, c->infrastructure.rail[rt], monthly_cost);
1623 }
1624
1625 if (c->infrastructure.signal > 0) {
1626 Money monthly_cost = SignalMaintenanceCost(c->infrastructure.signal);
1627 total_monthly_cost += monthly_cost;
1628 this->list.emplace_back(InfrastructureItemType::Value, STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS, c->infrastructure.signal, monthly_cost);
1629 }
1630 }
1631
1632 if (uint32_t road_total = c->infrastructure.GetRoadTotal(); road_total > 0) {
1633 /* Road types. */
1634 if (!this->list.empty()) this->list.emplace_back(InfrastructureItemType::Spacer);
1635 this->list.emplace_back(InfrastructureItemType::Header, STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT);
1636
1637 for (const RoadType &rt : _sorted_roadtypes) {
1638 if (!RoadTypeIsRoad(rt)) continue;
1639 if (c->infrastructure.road[rt] == 0) continue;
1640 Money monthly_cost = RoadMaintenanceCost(rt, c->infrastructure.road[rt], road_total);
1641 total_monthly_cost += monthly_cost;
1642 this->list.emplace_back(InfrastructureItemType::Value, GetRoadTypeInfo(rt)->strings.name, c->infrastructure.road[rt], monthly_cost);
1643 }
1644 }
1645
1646 if (uint32_t tram_total = c->infrastructure.GetTramTotal(); tram_total > 0) {
1647 /* Tram types. */
1648 if (!this->list.empty()) this->list.emplace_back(InfrastructureItemType::Spacer);
1649 this->list.emplace_back(InfrastructureItemType::Header, STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT);
1650
1651 for (const RoadType &rt : _sorted_roadtypes) {
1652 if (!RoadTypeIsTram(rt)) continue;
1653 if (c->infrastructure.road[rt] == 0) continue;
1654 Money monthly_cost = RoadMaintenanceCost(rt, c->infrastructure.road[rt], tram_total);
1655 total_monthly_cost += monthly_cost;
1656 this->list.emplace_back(InfrastructureItemType::Value, GetRoadTypeInfo(rt)->strings.name, c->infrastructure.road[rt], monthly_cost);
1657 }
1658 }
1659
1660 if (c->infrastructure.water > 0) {
1661 /* Canals, locks, and ship depots (docks are counted as stations). */
1662 if (!this->list.empty()) this->list.emplace_back(InfrastructureItemType::Spacer);
1663 this->list.emplace_back(InfrastructureItemType::Header, STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT);
1664
1665 Money monthly_cost = CanalMaintenanceCost(c->infrastructure.water);
1666 total_monthly_cost += monthly_cost;
1667 this->list.emplace_back(InfrastructureItemType::Value, STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS, c->infrastructure.water, monthly_cost);
1668 }
1669
1670 if (Money airport_cost = AirportMaintenanceCost(c->index); airport_cost > 0 || c->infrastructure.station > 0) {
1671 /* Stations and airports. */
1672 if (!this->list.empty()) this->list.emplace_back(InfrastructureItemType::Spacer);
1673 this->list.emplace_back(InfrastructureItemType::Header, STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT);
1674
1675 if (c->infrastructure.station > 0) {
1676 Money monthly_cost = StationMaintenanceCost(c->infrastructure.station);
1677 total_monthly_cost += monthly_cost;
1678 this->list.emplace_back(InfrastructureItemType::Value, STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS, c->infrastructure.station, monthly_cost);
1679 }
1680
1681 if (airport_cost > 0) {
1682 Money monthly_cost = airport_cost;
1683 total_monthly_cost += monthly_cost;
1684 this->list.emplace_back(InfrastructureItemType::Value, STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS, c->infrastructure.airport, monthly_cost);
1685 }
1686 }
1687
1689 /* Total monthly maintenance cost. */
1690 this->list.emplace_back(InfrastructureItemType::Spacer);
1691 this->list.emplace_back(InfrastructureItemType::Total, STR_NULL, 0, total_monthly_cost);
1692 }
1693
1694 /* Update scrollbar. */
1695 this->GetScrollbar(WID_CI_SCROLLBAR)->SetCount(std::size(list));
1696 }
1697
1698 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
1699 {
1700 switch (widget) {
1701 case WID_CI_CAPTION:
1702 return GetString(STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION, this->window_number);
1703
1704 default:
1705 return this->Window::GetWidgetString(widget, stringid);
1706 }
1707 }
1708
1709 void FindWindowPlacementAndResize(int def_width, int def_height, bool allow_resize) override
1710 {
1711 if (def_height == 0) {
1712 /* Try to open the window with the exact required rows, but clamp to a reasonable limit. */
1713 int rows = (this->GetWidget<NWidgetBase>(WID_CI_LIST)->current_y - WidgetDimensions::scaled.framerect.Vertical()) / GetCharacterHeight(FontSize::Normal);
1714 int delta = std::min(20, static_cast<int>(std::size(this->list))) - rows;
1715 def_height = this->height + delta * GetCharacterHeight(FontSize::Normal);
1716 }
1717
1718 this->Window::FindWindowPlacementAndResize(def_width, def_height, allow_resize);
1719 }
1720
1721 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
1722 {
1723 if (widget != WID_CI_LIST) return;
1724
1725 uint max_count = 1000; // Some random number to reserve minimum space.
1726 Money max_cost = 1000000; // Some random number to reserve minimum space.
1727
1728 /* List of headers that might be used. */
1729 static constexpr StringID header_strings[] = {
1730 STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT,
1731 STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT,
1732 STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT,
1733 STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT,
1734 STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT,
1735 };
1736 /* List of labels that might be used. */
1737 static constexpr StringID label_strings[] = {
1738 STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS,
1739 STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS,
1740 STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS,
1741 STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS,
1742 };
1743
1744 uint max_header_width = GetStringListWidth(header_strings);
1745 uint max_label_width = GetStringListWidth(label_strings);
1746
1747 /* Include width of all possible rail and road types. */
1748 for (const RailType &rt : _sorted_railtypes) max_label_width = std::max(max_label_width, GetStringBoundingBox(GetRailTypeInfo(rt)->strings.name).width);
1749 for (const RoadType &rt : _sorted_roadtypes) max_label_width = std::max(max_label_width, GetStringBoundingBox(GetRoadTypeInfo(rt)->strings.name).width);
1750
1751 for (const InfrastructureItem &entry : this->list) {
1752 max_count = std::max(max_count, entry.count);
1753 max_cost = std::max(max_cost, entry.cost * 12);
1754 }
1755
1756 max_label_width += WidgetDimensions::scaled.hsep_indent;
1757 this->count_width = GetStringBoundingBox(GetString(STR_JUST_COMMA, max_count)).width;
1758
1759 if (_settings_game.economy.infrastructure_maintenance) {
1760 this->cost_width = GetStringBoundingBox(GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_PERIOD : STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_YEAR, max_cost)).width;
1761 } else {
1762 this->cost_width = 0;
1763 }
1764
1765 size.width = max_label_width + WidgetDimensions::scaled.hsep_wide + this->count_width + WidgetDimensions::scaled.hsep_wide + this->cost_width;
1766 size.width = std::max(size.width, max_header_width) + WidgetDimensions::scaled.framerect.Horizontal();
1767
1768 fill.height = resize.height = GetCharacterHeight(FontSize::Normal);
1769 }
1770
1771 void DrawWidget(const Rect &r, WidgetID widget) const override
1772 {
1773 if (widget != WID_CI_LIST) return;
1774
1775 bool rtl = _current_text_dir == TD_RTL; // We allocate space from end-to-start so the label fills.
1776 int line_height = GetCharacterHeight(FontSize::Normal);
1777
1778 Rect ir = r.Shrink(WidgetDimensions::scaled.framerect);
1779 Rect countr = ir.WithWidth(this->count_width, !rtl);
1780 Rect costr = ir.Indent(this->count_width + WidgetDimensions::scaled.hsep_wide, !rtl).WithWidth(this->cost_width, !rtl);
1781 Rect labelr = ir.Indent(this->count_width + WidgetDimensions::scaled.hsep_wide + this->cost_width + WidgetDimensions::scaled.hsep_wide, !rtl);
1782
1783 auto [first, last] = this->GetScrollbar(WID_CI_SCROLLBAR)->GetVisibleRangeIterators(this->list);
1784 for (auto it = first; it != last; ++it) {
1785 switch (it->type) {
1787 /* Header is allowed to fill the window's width. */
1788 DrawString(ir.left, ir.right, labelr.top, GetString(it->label), TextColour::Orange);
1789 break;
1790
1792 break;
1793
1795 /* Draw line in the spacer above the total. */
1797 DrawString(costr, GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_PERIOD : STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_YEAR, it->cost * 12), TextColour::Black, SA_RIGHT | SA_FORCE);
1798 break;
1799
1801 DrawString(labelr.Indent(WidgetDimensions::scaled.hsep_indent, rtl), GetString(it->label), TextColour::White);
1802 DrawString(countr, GetString(STR_JUST_COMMA, it->count), TextColour::White, SA_RIGHT | SA_FORCE);
1803 if (_settings_game.economy.infrastructure_maintenance) {
1804 DrawString(costr, GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_PERIOD : STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_YEAR, it->cost * 12), TextColour::Black, SA_RIGHT | SA_FORCE);
1805 }
1806 break;
1807 }
1808
1809 labelr.top += line_height;
1810 countr.top += line_height;
1811 costr.top += line_height;
1812 }
1813 }
1814
1815 const IntervalTimer<TimerWindow> redraw_interval = {std::chrono::seconds(1), [this](auto) {
1816 this->UpdateInfrastructureList();
1818 }};
1819
1820 void OnResize() override
1821 {
1823 }
1824
1830 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1831 {
1832 if (!gui_scope) return;
1833
1834 this->ReInit();
1835 }
1836};
1837
1840 WindowPosition::Automatic, "company_infrastructure", 0, 0,
1841 WindowClass::CompanyInfrastructure, WindowClass::None,
1842 {},
1843 _nested_company_infrastructure_widgets
1844);
1845
1850static void ShowCompanyInfrastructure(CompanyID company)
1851{
1852 if (!Company::IsValidID(company)) return;
1854}
1855
1856static constexpr std::initializer_list<NWidgetPart> _nested_company_widgets = {
1862 EndContainer(),
1868 EndContainer(),
1874 NWidget(WWT_LABEL, Colours::Invalid, WID_C_DESC_COLOUR_SCHEME), SetStringTip(STR_COMPANY_VIEW_COLOUR_SCHEME_TITLE),
1876 EndContainer(),
1880 EndContainer(),
1881 EndContainer(),
1884 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_C_VIEW_HQ), SetStringTip(STR_COMPANY_VIEW_VIEW_HQ_BUTTON, STR_COMPANY_VIEW_VIEW_HQ_TOOLTIP),
1885 NWidget(WWT_TEXTBTN, Colours::Grey, WID_C_BUILD_HQ), SetStringTip(STR_COMPANY_VIEW_BUILD_HQ_BUTTON, STR_COMPANY_VIEW_BUILD_HQ_TOOLTIP),
1886 EndContainer(),
1888 NWidget(WWT_TEXTBTN, Colours::Grey, WID_C_RELOCATE_HQ), SetStringTip(STR_COMPANY_VIEW_RELOCATE_HQ, STR_COMPANY_VIEW_RELOCATE_HQ_TOOLTIP),
1890 EndContainer(),
1891 EndContainer(),
1892 EndContainer(),
1893
1895
1900 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_C_VIEW_INFRASTRUCTURE), SetStringTip(STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON, STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP),
1901 EndContainer(),
1902 EndContainer(),
1903
1904 /* Multi player buttons. */
1908 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_C_HOSTILE_TAKEOVER), SetStringTip(STR_COMPANY_VIEW_HOSTILE_TAKEOVER_BUTTON, STR_COMPANY_VIEW_HOSTILE_TAKEOVER_TOOLTIP),
1909 EndContainer(),
1911 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_C_GIVE_MONEY), SetStringTip(STR_COMPANY_VIEW_GIVE_MONEY_BUTTON, STR_COMPANY_VIEW_GIVE_MONEY_TOOLTIP),
1912 EndContainer(),
1914 NWidget(WWT_PUSHTXTBTN, Colours::Grey, WID_C_COMPANY_JOIN), SetStringTip(STR_COMPANY_VIEW_JOIN, STR_COMPANY_VIEW_JOIN_TOOLTIP),
1915 EndContainer(),
1916 EndContainer(),
1917 EndContainer(),
1918 EndContainer(),
1919 EndContainer(),
1920 EndContainer(),
1921 /* Button bars at the bottom. */
1924 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),
1925 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),
1926 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),
1927 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),
1928 EndContainer(),
1929 EndContainer(),
1930};
1931
1934 STR_COMPANY_VIEW_TRAINS, STR_COMPANY_VIEW_ROAD_VEHICLES, STR_COMPANY_VIEW_SHIPS, STR_COMPANY_VIEW_AIRCRAFT
1935};
1936
1940struct CompanyWindow : Window
1941{
1944
1945 CompanyWidgets query_widget{};
1946
1948 enum CompanyWindowPlanes : uint8_t {
1949 /* Display planes of the #WID_C_SELECT_VIEW_BUILD_HQ selection widget. */
1952
1953 /* Display planes of the #WID_C_SELECT_RELOCATE selection widget. */
1956 };
1957
1959 {
1960 this->InitNested(window_number);
1961 this->owner = this->window_number;
1962 this->OnInvalidateData();
1963 }
1964
1965 void OnPaint() override
1966 {
1967 const Company *c = Company::Get(this->window_number);
1968 bool local = this->window_number == _local_company;
1969
1970 if (!this->IsShaded()) {
1971 bool reinit = false;
1972
1973 /* Button bar selection. */
1974 reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_BUTTONS)->SetDisplayedPlane(local ? 0 : SZSP_NONE);
1975
1976 /* Build HQ button handling. */
1977 reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_VIEW_BUILD_HQ)->SetDisplayedPlane((local && c->location_of_HQ == INVALID_TILE) ? CWP_VB_BUILD : CWP_VB_VIEW);
1978
1980
1981 /* Enable/disable 'Relocate HQ' button. */
1982 reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_RELOCATE)->SetDisplayedPlane((!local || c->location_of_HQ == INVALID_TILE) ? CWP_RELOCATE_HIDE : CWP_RELOCATE_SHOW);
1983 /* Enable/disable 'Give money' button. */
1984 reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_GIVE_MONEY)->SetDisplayedPlane((local || _local_company == COMPANY_SPECTATOR || !_settings_game.economy.give_money) ? SZSP_NONE : 0);
1985 /* Enable/disable 'Hostile Takeover' button. */
1986 reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_HOSTILE_TAKEOVER)->SetDisplayedPlane((local || _local_company == COMPANY_SPECTATOR || !c->is_ai || _networking) ? SZSP_NONE : 0);
1987
1988 /* Multiplayer buttons. */
1989 reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_MULTIPLAYER)->SetDisplayedPlane((!_networking || !NetworkCanJoinCompany(c->index) || _local_company == c->index) ? (int)SZSP_NONE : 0);
1990
1992
1993 if (reinit) {
1994 this->ReInit();
1995 return;
1996 }
1997 }
1998
1999 this->DrawWidgets();
2000 }
2001
2002 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2003 {
2004 switch (widget) {
2005 case WID_C_FACE:
2006 size = maxdim(size, GetScaledSpriteSize(SPR_GRADIENT));
2007 break;
2008
2010 Point offset;
2011 Dimension d = GetSpriteSize(SPR_VEH_BUS_SW_VIEW, &offset);
2012 d.width -= offset.x;
2013 d.height -= offset.y;
2014 size = maxdim(size, d);
2015 break;
2016 }
2017
2019 /* INT64_MAX is arguably the maximum company value */
2020 size.width = GetStringBoundingBox(GetString(STR_COMPANY_VIEW_COMPANY_VALUE, INT64_MAX)).width;
2021 break;
2022
2024 uint64_t max_value = GetParamMaxValue(5000); // Maximum number of vehicles
2025 for (const auto &count_string : _company_view_vehicle_count_strings) {
2026 size.width = std::max(size.width, GetStringBoundingBox(GetString(count_string, max_value)).width + padding.width);
2027 }
2028 break;
2029 }
2030
2032 uint64_t max_value = GetParamMaxValue(UINT_MAX);
2033 size.width = GetStringBoundingBox(GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL, max_value)).width;
2034 size.width = std::max(size.width, GetStringBoundingBox(GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD, max_value)).width);
2035 size.width = std::max(size.width, GetStringBoundingBox(GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_WATER, max_value)).width);
2036 size.width = std::max(size.width, GetStringBoundingBox(GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_STATION, max_value)).width);
2037 size.width = std::max(size.width, GetStringBoundingBox(GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT, max_value)).width);
2038 size.width = std::max(size.width, GetStringBoundingBox(GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_NONE, max_value)).width);
2039 size.width += padding.width;
2040 break;
2041 }
2042
2043 case WID_C_VIEW_HQ:
2044 case WID_C_BUILD_HQ:
2045 case WID_C_RELOCATE_HQ:
2047 case WID_C_GIVE_MONEY:
2049 case WID_C_COMPANY_JOIN:
2050 size.width = GetStringBoundingBox(STR_COMPANY_VIEW_VIEW_HQ_BUTTON).width;
2051 size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_BUILD_HQ_BUTTON).width);
2052 size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_RELOCATE_HQ).width);
2053 size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON).width);
2054 size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_GIVE_MONEY_BUTTON).width);
2055 size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_HOSTILE_TAKEOVER_BUTTON).width);
2056 size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_JOIN).width);
2057 size.width += padding.width;
2058 break;
2059 }
2060 }
2061
2062 void DrawVehicleCountsWidget(const Rect &r, const Company *c) const
2063 {
2064 int y = r.top;
2065 for (VehicleType type = VehicleType::Begin; type < VehicleType::CompanyEnd; type++) {
2066 uint amount = c->group_all[type].num_vehicle;
2067 if (amount != 0) {
2068 DrawString(r.left, r.right, y, GetString(_company_view_vehicle_count_strings[type], amount));
2070 }
2071 }
2072
2073 if (y == r.top) {
2074 /* No String was emitted before, so there must be no vehicles at all. */
2075 DrawString(r.left, r.right, y, STR_COMPANY_VIEW_VEHICLES_NONE);
2076 }
2077 }
2078
2079 void DrawInfrastructureCountsWidget(const Rect &r, const Company *c) const
2080 {
2081 int y = r.top;
2082
2083 uint rail_pieces = c->infrastructure.signal + c->infrastructure.GetRailTotal();
2084 if (rail_pieces != 0) {
2085 DrawString(r.left, r.right, y, GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL, rail_pieces));
2087 }
2088
2089 /* GetRoadTotal() skips tram pieces, but we actually want road and tram here. */
2090 uint road_pieces = std::accumulate(std::begin(c->infrastructure.road), std::end(c->infrastructure.road), 0U);
2091 if (road_pieces != 0) {
2092 DrawString(r.left, r.right, y, GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD, road_pieces));
2094 }
2095
2096 if (c->infrastructure.water != 0) {
2097 DrawString(r.left, r.right, y, GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_WATER, c->infrastructure.water));
2099 }
2100
2101 if (c->infrastructure.station != 0) {
2102 DrawString(r.left, r.right, y, GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_STATION, c->infrastructure.station));
2104 }
2105
2106 if (c->infrastructure.airport != 0) {
2107 DrawString(r.left, r.right, y, GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT, c->infrastructure.airport));
2109 }
2110
2111 if (y == r.top) {
2112 /* No String was emitted before, so there must be no infrastructure at all. */
2113 DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE);
2114 }
2115 }
2116
2117 void DrawWidget(const Rect &r, WidgetID widget) const override
2118 {
2119 const Company *c = Company::Get(this->window_number);
2120 switch (widget) {
2121 case WID_C_FACE:
2123 break;
2124
2125 case WID_C_FACE_TITLE:
2126 DrawStringMultiLine(r, GetString(STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE, c->index), TextColour::FromString, SA_HOR_CENTER);
2127 break;
2128
2130 Point offset;
2131 Dimension d = GetSpriteSize(SPR_VEH_BUS_SW_VIEW, &offset);
2132 d.height -= offset.y;
2133 DrawSprite(SPR_VEH_BUS_SW_VIEW, GetCompanyPalette(c->index), r.left - offset.x, CentreBounds(r.top, r.bottom, d.height) - offset.y);
2134 break;
2135 }
2136
2138 DrawVehicleCountsWidget(r, c);
2139 break;
2140
2142 DrawInfrastructureCountsWidget(r, c);
2143 break;
2144 }
2145 }
2146
2147 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
2148 {
2149 switch (widget) {
2150 case WID_C_CAPTION:
2151 return GetString(STR_COMPANY_VIEW_CAPTION, this->window_number, this->window_number);
2152
2154 const Company &c = *Company::Get(this->window_number);
2156 return GetString(STR_COMPANY_VIEW_INAUGURATED_TITLE_WALLCLOCK, c.inaugurated_year_calendar, c.inaugurated_year);
2157 }
2158 return GetString(STR_COMPANY_VIEW_INAUGURATED_TITLE, c.inaugurated_year);
2159 }
2160
2162 return GetString(STR_COMPANY_VIEW_COMPANY_VALUE, CalculateCompanyValue(Company::Get(this->window_number)));
2163
2164 default:
2165 return this->Window::GetWidgetString(widget, stringid);
2166 }
2167 }
2168
2169 void OnResize() override
2170 {
2172 int y = GetStringHeight(GetString(STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE, this->owner), wid->current_x);
2173 if (wid->UpdateVerticalSize(y)) this->ReInit(0, 0);
2174 }
2175
2176 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2177 {
2178 switch (widget) {
2179 case WID_C_NEW_FACE: DoSelectCompanyManagerFace(this); break;
2180
2182 ShowCompanyLiveryWindow(this->window_number, GroupID::Invalid());
2183 break;
2184
2186 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});
2187 this->query_widget = WID_C_PRESIDENT_NAME;
2188 break;
2189
2190 case WID_C_COMPANY_NAME:
2191 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});
2192 this->query_widget = WID_C_COMPANY_NAME;
2193 break;
2194
2195 case WID_C_VIEW_HQ: {
2196 TileIndex tile = Company::Get(this->window_number)->location_of_HQ;
2197 if (_ctrl_pressed) {
2199 } else {
2201 }
2202 break;
2203 }
2204
2205 case WID_C_BUILD_HQ:
2206 if (this->window_number != _local_company) return;
2207 if (this->IsWidgetLowered(WID_C_BUILD_HQ)) {
2209 this->RaiseButtons();
2210 break;
2211 }
2212 SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, HT_RECT, this);
2213 SetTileSelectSize(2, 2);
2216 break;
2217
2218 case WID_C_RELOCATE_HQ:
2221 this->RaiseButtons();
2222 break;
2223 }
2224 SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, HT_RECT, this);
2225 SetTileSelectSize(2, 2);
2228 break;
2229
2232 break;
2233
2234 case WID_C_GIVE_MONEY:
2235 ShowQueryString({}, STR_COMPANY_VIEW_GIVE_MONEY_QUERY_CAPTION, 30, this, CS_NUMERAL, {});
2236 this->query_widget = WID_C_GIVE_MONEY;
2237 break;
2238
2241 break;
2242
2243 case WID_C_COMPANY_JOIN: {
2244 this->query_widget = WID_C_COMPANY_JOIN;
2245 CompanyID company = this->window_number;
2246 if (_network_server) {
2249 } else {
2250 /* just send the join command */
2251 NetworkClientRequestMove(company);
2252 }
2253 break;
2254 }
2255 }
2256 }
2257
2259 const IntervalTimer<TimerWindow> redraw_interval = {std::chrono::seconds(3), [this](auto) {
2260 this->SetDirty();
2261 }};
2262
2263 void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
2264 {
2265 if (Command<Commands::BuildObject>::Post(STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS, tile, OBJECT_HQ, 0) && !_shift_pressed) {
2267 this->RaiseButtons();
2268 }
2269 }
2270
2271 void OnPlaceObjectAbort() override
2272 {
2273 this->RaiseButtons();
2274 }
2275
2276 void OnQueryTextFinished(std::optional<std::string> str) override
2277 {
2278 CompanyWidgets widget = this->query_widget;
2279 this->query_widget = CompanyWindow::INVALID_QUERY_WIDGET;
2280
2281 if (!str.has_value()) return;
2282
2283 switch (widget) {
2284 default: NOT_REACHED();
2285
2286 case WID_C_GIVE_MONEY: {
2287 auto value = ParseInteger<uint64_t>(*str, 10, true);
2288 if (!value.has_value()) return;
2289 Money money = *value / GetCurrency().rate;
2290 Command<Commands::GiveMoney>::Post(STR_ERROR_CAN_T_GIVE_MONEY, money, this->window_number);
2291 break;
2292 }
2293
2295 Command<Commands::RenamePresident>::Post(STR_ERROR_CAN_T_CHANGE_PRESIDENT, *str);
2296 break;
2297
2298 case WID_C_COMPANY_NAME:
2299 Command<Commands::RenameCompany>::Post(STR_ERROR_CAN_T_CHANGE_COMPANY_NAME, *str);
2300 break;
2301 }
2302 }
2303
2304 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
2305 {
2306 if (!gui_scope) return;
2307
2308 /* Manually call OnResize to adjust minimum height of president name widget. */
2309 if (data == WID_C_PRESIDENT_NAME) this->OnResize();
2310
2311 /* If a query string is visible, update its default value. */
2312 if (this->query_widget != CompanyWindow::INVALID_QUERY_WIDGET && data == this->query_widget) {
2313 UpdateQueryStringDefault(GetString(data == WID_C_COMPANY_NAME ? STR_COMPANY_NAME : STR_PRESIDENT_NAME, this->window_number));
2314 }
2315 }
2316};
2317
2320 WindowPosition::Automatic, "company", 0, 0,
2321 WindowClass::Company, WindowClass::None,
2322 {},
2323 _nested_company_widgets
2324);
2325
2330void ShowCompany(CompanyID company)
2331{
2332 if (!Company::IsValidID(company)) return;
2333
2335}
2336
2342{
2343 SetWindowDirty(WindowClass::Company, company);
2344 SetWindowDirty(WindowClass::CompanyInfrastructure, company);
2345}
2346
2347struct BuyCompanyWindow : Window {
2349 {
2350 this->InitNested(window_number);
2351
2352 const Company *c = Company::Get(this->window_number);
2353 this->company_value = hostile_takeover ? CalculateHostileTakeoverValue(c) : c->bankrupt_value;
2354 }
2355
2356 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2357 {
2358 switch (widget) {
2359 case WID_BC_FACE:
2360 size = GetScaledSpriteSize(SPR_GRADIENT);
2361 break;
2362
2363 case WID_BC_QUESTION:
2364 const Company *c = Company::Get(this->window_number);
2365 size.height = GetStringHeight(GetString(this->hostile_takeover ? STR_BUY_COMPANY_HOSTILE_TAKEOVER : STR_BUY_COMPANY_MESSAGE, c->index, this->company_value), size.width);
2366 break;
2367 }
2368 }
2369
2370 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
2371 {
2372 switch (widget) {
2373 case WID_BC_CAPTION:
2374 return GetString(STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY, Company::Get(this->window_number)->index);
2375
2376 default:
2377 return this->Window::GetWidgetString(widget, stringid);
2378 }
2379 }
2380
2381 void DrawWidget(const Rect &r, WidgetID widget) const override
2382 {
2383 switch (widget) {
2384 case WID_BC_FACE: {
2385 const Company *c = Company::Get(this->window_number);
2387 break;
2388 }
2389
2390 case WID_BC_QUESTION: {
2391 const Company *c = Company::Get(this->window_number);
2392 DrawStringMultiLine(r, GetString(this->hostile_takeover ? STR_BUY_COMPANY_HOSTILE_TAKEOVER : STR_BUY_COMPANY_MESSAGE, c->index, this->company_value), TextColour::FromString, SA_CENTER);
2393 break;
2394 }
2395 }
2396 }
2397
2398 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2399 {
2400 switch (widget) {
2401 case WID_BC_NO:
2402 this->Close();
2403 break;
2404
2405 case WID_BC_YES:
2406 Command<Commands::BuyCompany>::Post(STR_ERROR_CAN_T_BUY_COMPANY, this->window_number, this->hostile_takeover);
2407 break;
2408 }
2409 }
2410
2414 const IntervalTimer<TimerWindow> rescale_interval = {std::chrono::seconds(3), [this](auto) {
2415 /* Value can't change when in bankruptcy. */
2416 if (!this->hostile_takeover) return;
2417
2418 const Company *c = Company::Get(this->window_number);
2419 auto new_value = CalculateHostileTakeoverValue(c);
2420 if (new_value != this->company_value) {
2421 this->company_value = new_value;
2422 this->ReInit();
2423 }
2424 }};
2425
2426private:
2427 bool hostile_takeover = false;
2429};
2430
2431static constexpr std::initializer_list<NWidgetPart> _nested_buy_company_widgets = {
2435 EndContainer(),
2441 EndContainer(),
2445 EndContainer(),
2446 EndContainer(),
2447 EndContainer(),
2448};
2449
2452 WindowPosition::Automatic, {}, 0, 0,
2453 WindowClass::BuyCompany, WindowClass::None,
2455 _nested_buy_company_widgets
2456);
2457
2463void ShowBuyCompanyDialog(CompanyID company, bool hostile_takeover)
2464{
2465 auto window = BringWindowToFrontById(WindowClass::BuyCompany, company);
2466 if (window == nullptr) {
2467 new BuyCompanyWindow(_buy_company_desc, company, hostile_takeover);
2468 }
2469}
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.
std::optional< Tvalue_type > GetNthSetBit(uint n) const
Get the value of the Nth set bit.
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
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:2457
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:2531
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 WindowDesc _company_desc(WindowPosition::Automatic, "company", 0, 0, WindowClass::Company, WindowClass::None, {}, _nested_company_widgets)
Window definition for the company window.
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 _company_finances_desc(WindowPosition::Automatic, "company_finances", 0, 0, WindowClass::Finances, WindowClass::None, {}, _nested_company_finances_widgets)
Window definition for the company finances window.
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 const EnumIndexArray< LiveryClass, LiveryScheme, LiveryScheme::End > _livery_class
Association of liveries to livery classes.
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 _buy_company_desc(WindowPosition::Automatic, {}, 0, 0, WindowClass::BuyCompany, WindowClass::None, WindowDefaultFlag::Construction, _nested_buy_company_widgets)
Window definition for the window to buy a company.
static WindowDesc _select_company_manager_face_desc(WindowPosition::Automatic, {}, 0, 0, WindowClass::CompanyManagerFace, WindowClass::None, WindowDefaultFlag::Construction, _nested_select_company_manager_face_widgets)
Company manager face selection window description.
static WindowDesc _company_infrastructure_desc(WindowPosition::Automatic, "company_infrastructure", 0, 0, WindowClass::CompanyInfrastructure, WindowClass::None, {}, _nested_company_infrastructure_widgets)
Window definition for the company infrastructure statistics 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 const std::initializer_list< ExpensesType > _expenses_list_revenue
List of revenues.
static WindowDesc _select_company_livery_desc(WindowPosition::Automatic, "company_colour_scheme", 0, 0, WindowClass::CompanyLivery, WindowClass::None, {}, _nested_select_company_livery_widgets)
Window definition for the company livery configuration window.
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
EnumClassIndexContainer< std::array< T, to_underlying(N)>, Index > EnumIndexArray
A typedef for EnumClassIndexContainer using std::array as the backing container type.
Functions related to errors.
@ 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:716
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition gfx.cpp:971
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:899
bool _ctrl_pressed
Is Ctrl pressed?
Definition gfx.cpp:39
int DrawStringMultiLine(int left, int right, int top, int bottom, std::string_view str, ExtendedTextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly over multiple lines.
Definition gfx.cpp:787
uint GetStringListWidth(std::span< const StringID > list, FontSize fontsize)
Get maximum width of a list of strings.
Definition gfx.cpp:923
int DrawString(int left, int right, int top, std::string_view str, ExtendedTextColour colour, StringAlignment align, bool underline, FontSize fontsize)
Draw string, possibly truncated to make it fit in its allocated space.
Definition gfx.cpp:668
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:1037
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:439
@ SA_LEFT
Left align the text.
Definition gfx_type.h:434
@ SA_RIGHT
Right align the text (must be a single bit).
Definition gfx_type.h:436
@ SA_HOR_CENTER
Horizontally center the text.
Definition gfx_type.h:435
@ SA_FORCE
Force the alignment, i.e. don't swap for RTL languages.
Definition gfx_type.h:446
@ SA_CENTER
Center both horizontally and vertically.
Definition gfx_type.h:444
@ SA_VERT_CENTER
Vertically center the text.
Definition gfx_type.h:440
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:315
@ White
White colour.
Definition gfx_type.h:330
@ FromString
Marker for telling to use the colour from the string.
Definition gfx_type.h:317
@ Orange
Orange colour.
Definition gfx_type.h:324
@ Gold
Gold colour.
Definition gfx_type.h:320
@ Black
Black colour.
Definition gfx_type.h:334
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:1553
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
EnumBitSet< LiveryScheme, uint32_t, LiveryScheme::End > LiverySchemes
Bitset of LiveryScheme elements.
Definition livery.h:65
LiveryScheme
List of different livery schemes.
Definition livery.h:22
@ Default
Default scheme.
Definition livery.h:24
@ End
End marker.
Definition livery.h:58
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:68
@ Ship
Ship livery schemes.
Definition livery.h:72
@ GroupShip
Ship group.
Definition livery.h:76
@ Rail
Rail livery schemes.
Definition livery.h:70
@ Other
General livery schemes.
Definition livery.h:69
@ GroupRail
Rail group.
Definition livery.h:74
@ GroupAircraft
Aircraft group.
Definition livery.h:77
@ GroupRoad
Road group.
Definition livery.h:75
@ Aircraft
Aircraft livery schemes.
Definition livery.h:73
@ Road
Road livery schemes.
Definition livery.h:71
#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:107
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.
bool has_2CC
Set if any vehicle is loaded which uses 2cc (two company colours).
Definition newgrf.h:201
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:83
Flags in_use
Livery flags.
Definition livery.h:91
Colours colour2
Second colour, for vehicles with 2CC support.
Definition livery.h:93
Colours colour1
First colour, for all vehicles.
Definition livery.h:92
@ Primary
Primary colour is set.
Definition livery.h:86
@ Secondary
Secondary colour is set.
Definition livery.h:87
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.
LiverySchemes visible_schemes
Currently visible livery schemes.
void OnInvalidateData(int data=0, bool gui_scope=true) override
Some data on this window has become invalid.
void BuildLiveryList()
Build 'list' of visible livery schemes.
struct SelectCompanyLiveryWindow::@313207310206021013204234143253377076057020012134 sel
Current selection.
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.
LiverySchemes schemes
Selected schemes.
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.
GroupID group
Selected group.
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
Functions related to zooming.