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