OpenTTD Source 20250529-master-g10c159a79f
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 <http://www.gnu.org/licenses/>.
6 */
7
10#include "stdafx.h"
11#include "currency.h"
12#include "error.h"
13#include "gui.h"
14#include "window_gui.h"
15#include "textbuf_gui.h"
16#include "viewport_func.h"
17#include "company_func.h"
18#include "command_func.h"
19#include "network/network.h"
20#include "network/network_gui.h"
22#include "newgrf.h"
24#include "strings_func.h"
26#include "dropdown_type.h"
27#include "tilehighlight_func.h"
28#include "company_base.h"
30#include "object_type.h"
31#include "rail.h"
32#include "road.h"
33#include "engine_base.h"
34#include "window_func.h"
35#include "road_func.h"
36#include "water.h"
37#include "station_func.h"
38#include "zoom_func.h"
39#include "sortlist_type.h"
40#include "company_cmd.h"
41#include "economy_cmd.h"
42#include "group_cmd.h"
43#include "group_gui.h"
44#include "misc_cmd.h"
45#include "object_cmd.h"
46#include "timer/timer.h"
47#include "timer/timer_window.h"
49
51
52#include "table/strings.h"
53
55
56#include "safeguards.h"
57
58
60static void DoSelectCompanyManagerFace(Window *parent);
61static void ShowCompanyInfrastructure(CompanyID company);
62
64static const std::initializer_list<ExpensesType> _expenses_list_revenue = {
69};
70
80
82static const std::initializer_list<ExpensesType> _expenses_list_capital_costs = {
86};
87
91 const std::initializer_list<ExpensesType> &items;
92
93 ExpensesList(StringID title, const std::initializer_list<ExpensesType> &list) : title(title), items(list)
94 {
95 }
96
97 uint GetHeight() const
98 {
99 /* Add up the height of all the lines. */
100 return static_cast<uint>(this->items.size()) * GetCharacterHeight(FS_NORMAL);
101 }
102
104 uint GetListWidth() const
105 {
106 uint width = 0;
107 for (const ExpensesType &et : this->items) {
108 width = std::max(width, GetStringBoundingBox(STR_FINANCES_SECTION_CONSTRUCTION + et).width);
109 }
110 return width;
111 }
112};
113
115static const std::initializer_list<ExpensesList> _expenses_list_types = {
116 { STR_FINANCES_REVENUE_TITLE, _expenses_list_revenue },
117 { STR_FINANCES_OPERATING_EXPENSES_TITLE, _expenses_list_operating_costs },
118 { STR_FINANCES_CAPITAL_EXPENSES_TITLE, _expenses_list_capital_costs },
119};
120
126{
127 /* There's an empty line and blockspace on the year row */
129
130 for (const ExpensesList &list : _expenses_list_types) {
131 /* Title + expense list + total line + total + blockspace after category */
133 }
134
135 /* Total income */
137
138 return total_height;
139}
140
146{
147 uint max_width = GetStringBoundingBox(TimerGameEconomy::UsingWallclockUnits() ? STR_FINANCES_PERIOD_CAPTION : STR_FINANCES_YEAR_CAPTION).width;
148
149 /* Loop through categories to check max widths. */
150 for (const ExpensesList &list : _expenses_list_types) {
151 /* Title of category */
152 max_width = std::max(max_width, GetStringBoundingBox(list.title).width);
153 /* Entries in category */
154 max_width = std::max(max_width, list.GetListWidth() + WidgetDimensions::scaled.hsep_indent);
155 }
156
157 return max_width;
158}
159
163static void DrawCategory(const Rect &r, int start_y, const ExpensesList &list)
164{
166
167 tr.top = start_y;
168
169 for (const ExpensesType &et : list.items) {
170 DrawString(tr, STR_FINANCES_SECTION_CONSTRUCTION + et);
171 tr.top += GetCharacterHeight(FS_NORMAL);
172 }
173}
174
180static void DrawCategories(const Rect &r)
181{
182 int y = r.top;
183 /* Draw description of 12-minute economic period. */
184 DrawString(r.left, r.right, y, (TimerGameEconomy::UsingWallclockUnits() ? STR_FINANCES_PERIOD_CAPTION : STR_FINANCES_YEAR_CAPTION), TC_FROMSTRING, SA_LEFT, true);
186
187 for (const ExpensesList &list : _expenses_list_types) {
188 /* Draw category title and advance y */
189 DrawString(r.left, r.right, y, list.title, TC_FROMSTRING, SA_LEFT);
191
192 /* Draw category items and advance y */
193 DrawCategory(r, y, list);
194 y += list.GetHeight();
195
196 /* Advance y by the height of the horizontal line between amounts and subtotal */
198
199 /* Draw category total and advance y */
200 DrawString(r.left, r.right, y, STR_FINANCES_TOTAL_CAPTION, TC_FROMSTRING, SA_RIGHT);
202
203 /* Advance y by a blockspace after this category block */
205 }
206
207 /* Draw total profit/loss */
209 DrawString(r.left, r.right, y, STR_FINANCES_PROFIT, TC_FROMSTRING, SA_LEFT);
210}
211
220static void DrawPrice(Money amount, int left, int right, int top, TextColour colour)
221{
222 StringID str = STR_FINANCES_NEGATIVE_INCOME;
223 if (amount == 0) {
224 str = STR_FINANCES_ZERO_INCOME;
225 } else if (amount < 0) {
226 amount = -amount;
227 str = STR_FINANCES_POSITIVE_INCOME;
228 }
229 DrawString(left, right, top, GetString(str, amount), colour, SA_RIGHT | SA_FORCE);
230}
231
236static Money DrawYearCategory(const Rect &r, int start_y, const ExpensesList &list, const Expenses &tbl)
237{
238 int y = start_y;
239 Money sum = 0;
240
241 for (const ExpensesType &et : list.items) {
242 Money cost = tbl[et];
243 sum += cost;
244 if (cost != 0) DrawPrice(cost, r.left, r.right, y, TC_BLACK);
246 }
247
248 /* Draw the total at the bottom of the category. */
249 GfxFillRect(r.left, y, r.right, y + WidgetDimensions::scaled.bevel.top - 1, PC_BLACK);
251 if (sum != 0) DrawPrice(sum, r.left, r.right, y, TC_WHITE);
252
253 /* Return the sum for the yearly total. */
254 return sum;
255}
256
257
265static void DrawYearColumn(const Rect &r, TimerGameEconomy::Year year, const Expenses &tbl)
266{
267 int y = r.top;
268 Money sum;
269
270 /* Year header */
271 DrawString(r.left, r.right, y, GetString(STR_FINANCES_YEAR, year), TC_FROMSTRING, SA_RIGHT | SA_FORCE, true);
273
274 /* Categories */
275 for (const ExpensesList &list : _expenses_list_types) {
277 sum += DrawYearCategory(r, y, list, tbl);
278 /* Expense list + expense category title + expense category total + blockspace after category */
280 }
281
282 /* Total income. */
283 GfxFillRect(r.left, y, r.right, y + WidgetDimensions::scaled.bevel.top - 1, PC_BLACK);
285 DrawPrice(sum, r.left, r.right, y, TC_WHITE);
286}
287
288static constexpr NWidgetPart _nested_company_finances_widgets[] = {
290 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
291 NWidget(WWT_CAPTION, COLOUR_GREY, WID_CF_CAPTION),
292 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),
293 NWidget(WWT_SHADEBOX, COLOUR_GREY),
294 NWidget(WWT_STICKYBOX, COLOUR_GREY),
295 EndContainer(),
296 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_CF_SEL_PANEL),
297 NWidget(WWT_PANEL, COLOUR_GREY),
299 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_CF_EXPS_CATEGORY), SetMinimalSize(120, 0), SetFill(0, 0),
300 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_CF_EXPS_PRICE1), SetMinimalSize(86, 0), SetFill(0, 0),
301 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_CF_EXPS_PRICE2), SetMinimalSize(86, 0), SetFill(0, 0),
302 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_CF_EXPS_PRICE3), SetMinimalSize(86, 0), SetFill(0, 0),
303 EndContainer(),
304 EndContainer(),
305 EndContainer(),
306 NWidget(WWT_PANEL, COLOUR_GREY),
308 NWidget(NWID_VERTICAL), // Vertical column with 'bank balance', 'loan'
309 NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_FINANCES_OWN_FUNDS_TITLE),
310 NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_FINANCES_LOAN_TITLE),
311 NWidget(WWT_TEXT, INVALID_COLOUR), SetStringTip(STR_FINANCES_BANK_BALANCE_TITLE), SetPadding(WidgetDimensions::unscaled.vsep_normal, 0, 0, 0),
312 EndContainer(),
313 NWidget(NWID_VERTICAL), // Vertical column with bank balance amount, loan amount, and total.
318 EndContainer(),
319 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_CF_SEL_MAXLOAN),
320 NWidget(NWID_VERTICAL), SetPIPRatio(0, 0, 1), // Max loan information
321 NWidget(WWT_TEXT, INVALID_COLOUR, WID_CF_INTEREST_RATE),
322 NWidget(WWT_TEXT, INVALID_COLOUR, WID_CF_MAXLOAN_VALUE),
323 EndContainer(),
324 EndContainer(),
325 EndContainer(),
326 EndContainer(),
327 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_CF_SEL_BUTTONS),
329 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_CF_INCREASE_LOAN), SetFill(1, 0), SetToolTip(STR_FINANCES_BORROW_TOOLTIP),
330 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_CF_REPAY_LOAN), SetFill(1, 0), SetToolTip(STR_FINANCES_REPAY_TOOLTIP),
331 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_CF_INFRASTRUCTURE), SetFill(1, 0), SetStringTip(STR_FINANCES_INFRASTRUCTURE_BUTTON, STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP),
332 EndContainer(),
333 EndContainer(),
334};
335
338 static constexpr int NUM_PERIODS = WID_CF_EXPS_PRICE3 - WID_CF_EXPS_PRICE1 + 1;
339
341 bool small = false;
342 uint8_t first_visible = NUM_PERIODS - 1;
343
344 CompanyFinancesWindow(WindowDesc &desc, CompanyID company) : Window(desc)
345 {
346 this->CreateNestedTree();
347 this->SetupWidgets();
348 this->FinishInitNested(company);
349
350 this->owner = this->window_number;
351 this->InvalidateData();
352 }
353
354 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
355 {
356 switch (widget) {
357 case WID_CF_CAPTION:
358 return GetString(STR_FINANCES_CAPTION, this->window_number, this->window_number);
359
361 const Company *c = Company::Get(this->window_number);
362 return GetString(STR_FINANCES_BANK_BALANCE, c->money);
363 }
364
365 case WID_CF_LOAN_VALUE: {
366 const Company *c = Company::Get(this->window_number);
367 return GetString(STR_FINANCES_TOTAL_CURRENCY, c->current_loan);
368 }
369
370 case WID_CF_OWN_VALUE: {
371 const Company *c = Company::Get(this->window_number);
372 return GetString(STR_FINANCES_TOTAL_CURRENCY, c->money - c->current_loan);
373 }
374
376 return GetString(STR_FINANCES_INTEREST_RATE, _settings_game.difficulty.initial_interest);
377
379 const Company *c = Company::Get(this->window_number);
380 return GetString(STR_FINANCES_MAX_LOAN, c->GetMaxLoan());
381 }
382
384 return GetString(STR_FINANCES_BORROW_BUTTON, LOAN_INTERVAL);
385
387 return GetString(STR_FINANCES_REPAY_BUTTON, LOAN_INTERVAL);
388
389 default:
390 return this->Window::GetWidgetString(widget, stringid);
391 }
392 }
393
394 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
395 {
396 switch (widget) {
398 size.width = GetMaxCategoriesWidth();
399 size.height = GetTotalCategoriesHeight();
400 break;
401
405 size.height = GetTotalCategoriesHeight();
406 [[fallthrough]];
407
410 case WID_CF_OWN_VALUE: {
412 size.width = std::max(GetStringBoundingBox(GetString(STR_FINANCES_NEGATIVE_INCOME, max_value)).width, GetStringBoundingBox(GetString(STR_FINANCES_POSITIVE_INCOME, max_value)).width);
413 size.width += padding.width;
414 break;
415 }
416
418 size.height = GetCharacterHeight(FS_NORMAL);
419 break;
420 }
421 }
422
423 void DrawWidget(const Rect &r, WidgetID widget) const override
424 {
425 switch (widget) {
428 break;
429
432 case WID_CF_EXPS_PRICE3: {
433 int period = widget - WID_CF_EXPS_PRICE1;
434 if (period < this->first_visible) break;
435
436 const Company *c = Company::Get(this->window_number);
437 const auto &expenses = c->yearly_expenses[NUM_PERIODS - period - 1];
438 DrawYearColumn(r, TimerGameEconomy::year - (NUM_PERIODS - period - 1), expenses);
439 break;
440 }
441
443 GfxFillRect(r.left, r.top, r.right, r.top + WidgetDimensions::scaled.bevel.top - 1, PC_BLACK);
444 break;
445 }
446 }
447
453 {
454 int plane = this->small ? SZSP_NONE : 0;
455 this->GetWidget<NWidgetStacked>(WID_CF_SEL_PANEL)->SetDisplayedPlane(plane);
456 this->GetWidget<NWidgetStacked>(WID_CF_SEL_MAXLOAN)->SetDisplayedPlane(plane);
457
458 CompanyID company = this->window_number;
459 plane = (company != _local_company) ? SZSP_NONE : 0;
460 this->GetWidget<NWidgetStacked>(WID_CF_SEL_BUTTONS)->SetDisplayedPlane(plane);
461 }
462
463 void OnPaint() override
464 {
465 if (!this->IsShaded()) {
466 if (!this->small) {
467 /* Check that the expenses panel height matches the height needed for the layout. */
468 if (GetTotalCategoriesHeight() != this->GetWidget<NWidgetBase>(WID_CF_EXPS_CATEGORY)->current_y) {
469 this->SetupWidgets();
470 this->ReInit();
471 return;
472 }
473 }
474
475 /* Check that the loan buttons are shown only when the user owns the company. */
476 CompanyID company = this->window_number;
477 int req_plane = (company != _local_company) ? SZSP_NONE : 0;
478 if (req_plane != this->GetWidget<NWidgetStacked>(WID_CF_SEL_BUTTONS)->shown_plane) {
479 this->SetupWidgets();
480 this->ReInit();
481 return;
482 }
483
484 const Company *c = Company::Get(company);
485 this->SetWidgetDisabledState(WID_CF_INCREASE_LOAN, c->current_loan >= c->GetMaxLoan()); // Borrow button only shows when there is any more money to loan.
486 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.
487 }
488
489 this->DrawWidgets();
490 }
491
492 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
493 {
494 switch (widget) {
495 case WID_CF_TOGGLE_SIZE: // toggle size
496 this->small = !this->small;
497 this->SetupWidgets();
498 if (this->IsShaded()) {
499 /* Finances window is not resizable, so size hints given during unshading have no effect
500 * on the changed appearance of the window. */
501 this->SetShaded(false);
502 } else {
503 this->ReInit();
504 }
505 break;
506
507 case WID_CF_INCREASE_LOAN: // increase loan
508 Command<CMD_INCREASE_LOAN>::Post(STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY, _ctrl_pressed ? LoanCommand::Max : LoanCommand::Interval, 0);
509 break;
510
511 case WID_CF_REPAY_LOAN: // repay loan
512 Command<CMD_DECREASE_LOAN>::Post(STR_ERROR_CAN_T_REPAY_LOAN, _ctrl_pressed ? LoanCommand::Max : LoanCommand::Interval, 0);
513 break;
514
515 case WID_CF_INFRASTRUCTURE: // show infrastructure details
517 break;
518 }
519 }
520
521 void RefreshVisibleColumns()
522 {
523 for (uint period = 0; period < this->first_visible; ++period) {
524 const Company *c = Company::Get(this->window_number);
525 const Expenses &expenses = c->yearly_expenses[NUM_PERIODS - period - 1];
526 /* Show expenses column if it has any non-zero value in it. */
527 if (std::ranges::any_of(expenses, [](const Money &value) { return value != 0; })) {
528 this->first_visible = period;
529 break;
530 }
531 }
532 }
533
534 void OnInvalidateData(int, bool) override
535 {
536 this->RefreshVisibleColumns();
537 }
538
543 const IntervalTimer<TimerWindow> rescale_interval = {std::chrono::seconds(3), [this](auto) {
544 const Company *c = Company::Get(this->window_number);
547 this->SetupWidgets();
548 this->ReInit();
549 }
550 }};
551};
552
555
556static WindowDesc _company_finances_desc(
557 WDP_AUTO, "company_finances", 0, 0,
559 {},
560 _nested_company_finances_widgets
561);
562
569{
570 if (!Company::IsValidID(company)) return;
571 if (BringWindowToFrontById(WC_FINANCES, company)) return;
572
573 new CompanyFinancesWindow(_company_finances_desc, company);
574}
575
576/* Association of liveries to livery classes */
577static const LiveryClass _livery_class[LS_END] = {
578 LC_OTHER,
579 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,
580 LC_ROAD, LC_ROAD,
581 LC_SHIP, LC_SHIP,
582 LC_AIRCRAFT, LC_AIRCRAFT, LC_AIRCRAFT,
583 LC_ROAD, LC_ROAD,
584};
585
590template <SpriteID TSprite = SPR_SQUARE>
591class DropDownListColourItem : public DropDownIcon<DropDownString<DropDownListItem>> {
592public:
593 DropDownListColourItem(int colour, bool masked) :
594 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)
595 {
596 }
597};
598
601private:
602 uint32_t sel = 0;
603 LiveryClass livery_class{};
604 Dimension square{};
605 uint rows = 0;
606 uint line_height = 0;
607 GUIGroupList groups{};
608 Scrollbar *vscroll = nullptr;
609
610 void ShowColourDropDownMenu(uint32_t widget)
611 {
612 uint32_t used_colours = 0;
613 const Livery *livery, *default_livery = nullptr;
614 bool primary = widget == WID_SCL_PRI_COL_DROPDOWN;
615 uint8_t default_col = 0;
616
617 /* Disallow other company colours for the primary colour */
618 if (this->livery_class < LC_GROUP_RAIL && HasBit(this->sel, LS_DEFAULT) && primary) {
619 for (const Company *c : Company::Iterate()) {
620 if (c->index != _local_company) SetBit(used_colours, c->colour);
621 }
622 }
623
624 const Company *c = Company::Get(this->window_number);
625
626 if (this->livery_class < LC_GROUP_RAIL) {
627 /* Get the first selected livery to use as the default dropdown item */
628 LiveryScheme scheme;
629 for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
630 if (HasBit(this->sel, scheme)) break;
631 }
632 if (scheme == LS_END) scheme = LS_DEFAULT;
633 livery = &c->livery[scheme];
634 if (scheme != LS_DEFAULT) default_livery = &c->livery[LS_DEFAULT];
635 } else {
636 const Group *g = Group::Get(this->sel);
637 livery = &g->livery;
638 if (g->parent == GroupID::Invalid()) {
639 default_livery = &c->livery[LS_DEFAULT];
640 } else {
641 const Group *pg = Group::Get(g->parent);
642 default_livery = &pg->livery;
643 }
644 }
645
646 DropDownList list;
647 if (default_livery != nullptr) {
648 /* Add COLOUR_END to put the colour out of range, but also allow us to show what the default is */
649 default_col = (primary ? default_livery->colour1 : default_livery->colour2) + COLOUR_END;
650 list.push_back(std::make_unique<DropDownListColourItem<>>(default_col, false));
651 }
652 for (Colours colour = COLOUR_BEGIN; colour != COLOUR_END; colour++) {
653 list.push_back(std::make_unique<DropDownListColourItem<>>(colour, HasBit(used_colours, colour)));
654 }
655
656 uint8_t sel;
657 if (default_livery == nullptr || HasBit(livery->in_use, primary ? 0 : 1)) {
658 sel = primary ? livery->colour1 : livery->colour2;
659 } else {
660 sel = default_col;
661 }
662 ShowDropDownList(this, std::move(list), sel, widget);
663 }
664
665 void BuildGroupList(CompanyID owner)
666 {
667 if (!this->groups.NeedRebuild()) return;
668
669 this->groups.clear();
670
671 if (this->livery_class >= LC_GROUP_RAIL) {
672 VehicleType vtype = (VehicleType)(this->livery_class - LC_GROUP_RAIL);
673 BuildGuiGroupList(this->groups, false, owner, vtype);
674 }
675
676 this->groups.RebuildDone();
677 }
678
679 void SetRows()
680 {
681 if (this->livery_class < LC_GROUP_RAIL) {
682 this->rows = 0;
683 for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
684 if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
685 this->rows++;
686 }
687 }
688 } else {
689 this->rows = (uint)this->groups.size();
690 }
691
692 this->vscroll->SetCount(this->rows);
693 }
694
695public:
696 SelectCompanyLiveryWindow(WindowDesc &desc, CompanyID company, GroupID group) : Window(desc)
697 {
698 this->CreateNestedTree();
699 this->vscroll = this->GetScrollbar(WID_SCL_MATRIX_SCROLLBAR);
700
701 if (group == GroupID::Invalid()) {
702 this->livery_class = LC_OTHER;
703 this->sel = 1;
705 this->BuildGroupList(company);
706 this->SetRows();
707 } else {
708 this->SetSelectedGroup(company, group);
709 }
710
711 this->FinishInitNested(company);
712 this->owner = company;
713 this->InvalidateData(1);
714 }
715
716 void SetSelectedGroup(CompanyID company, GroupID group)
717 {
718 this->RaiseWidget(WID_SCL_CLASS_GENERAL + this->livery_class);
719 const Group *g = Group::Get(group);
720 switch (g->vehicle_type) {
721 case VEH_TRAIN: this->livery_class = LC_GROUP_RAIL; break;
722 case VEH_ROAD: this->livery_class = LC_GROUP_ROAD; break;
723 case VEH_SHIP: this->livery_class = LC_GROUP_SHIP; break;
724 case VEH_AIRCRAFT: this->livery_class = LC_GROUP_AIRCRAFT; break;
725 default: NOT_REACHED();
726 }
727 this->sel = group.base();
728 this->LowerWidget(WID_SCL_CLASS_GENERAL + this->livery_class);
729
730 this->groups.ForceRebuild();
731 this->BuildGroupList(company);
732 this->SetRows();
733
734 /* Position scrollbar to selected group */
735 for (uint i = 0; i < this->rows; i++) {
736 if (this->groups[i].group->index == sel) {
737 this->vscroll->SetPosition(i - this->vscroll->GetCapacity() / 2);
738 break;
739 }
740 }
741 }
742
743 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
744 {
745 switch (widget) {
747 /* The matrix widget below needs enough room to print all the schemes. */
748 Dimension d = {0, 0};
749 for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
750 d = maxdim(d, GetStringBoundingBox(STR_LIVERY_DEFAULT + scheme));
751 }
752
753 size.width = std::max(size.width, 5 + d.width + padding.width);
754 break;
755 }
756
757 case WID_SCL_MATRIX: {
758 /* 11 items in the default rail class */
759 this->square = GetSpriteSize(SPR_SQUARE);
760 this->line_height = std::max(this->square.height, (uint)GetCharacterHeight(FS_NORMAL)) + padding.height;
761
762 size.height = 5 * this->line_height;
763 resize.width = 1;
764 resize.height = this->line_height;
765 break;
766 }
767
770 size.width = 0;
771 break;
772 }
773 [[fallthrough]];
774
776 this->square = GetSpriteSize(SPR_SQUARE);
777 int string_padding = this->square.width + WidgetDimensions::scaled.hsep_normal + padding.width;
778 for (Colours colour = COLOUR_BEGIN; colour != COLOUR_END; colour++) {
779 size.width = std::max(size.width, GetStringBoundingBox(STR_COLOUR_DARK_BLUE + colour).width + string_padding);
780 }
781 size.width = std::max(size.width, GetStringBoundingBox(STR_COLOUR_DEFAULT).width + string_padding);
782 break;
783 }
784 }
785 }
786
787 void OnPaint() override
788 {
789 bool local = this->window_number == _local_company;
790
791 /* Disable dropdown controls if no scheme is selected */
792 bool disabled = this->livery_class < LC_GROUP_RAIL ? (this->sel == 0) : (this->sel == GroupID::Invalid());
793 this->SetWidgetDisabledState(WID_SCL_PRI_COL_DROPDOWN, !local || disabled);
794 this->SetWidgetDisabledState(WID_SCL_SEC_COL_DROPDOWN, !local || disabled);
795
796 this->BuildGroupList(this->window_number);
797
798 this->DrawWidgets();
799 }
800
801 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
802 {
803 switch (widget) {
804 case WID_SCL_CAPTION:
805 return GetString(STR_LIVERY_CAPTION, this->window_number);
806
809 const Company *c = Company::Get(this->window_number);
810 bool primary = widget == WID_SCL_PRI_COL_DROPDOWN;
811 StringID colour = STR_COLOUR_DEFAULT;
812
813 if (this->livery_class < LC_GROUP_RAIL) {
814 if (this->sel != 0) {
815 LiveryScheme scheme = LS_DEFAULT;
816 for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
817 if (HasBit(this->sel, scheme)) break;
818 }
819 if (scheme == LS_END) scheme = LS_DEFAULT;
820 const Livery *livery = &c->livery[scheme];
821 if (scheme == LS_DEFAULT || HasBit(livery->in_use, primary ? 0 : 1)) {
822 colour = STR_COLOUR_DARK_BLUE + (primary ? livery->colour1 : livery->colour2);
823 }
824 }
825 } else {
826 if (this->sel != GroupID::Invalid()) {
827 const Group *g = Group::Get(this->sel);
828 const Livery *livery = &g->livery;
829 if (HasBit(livery->in_use, primary ? 0 : 1)) {
830 colour = STR_COLOUR_DARK_BLUE + (primary ? livery->colour1 : livery->colour2);
831 }
832 }
833 }
834 return GetString(colour);
835 }
836
837 default:
838 return this->Window::GetWidgetString(widget, stringid);
839 }
840 }
841
842 void DrawWidget(const Rect &r, WidgetID widget) const override
843 {
844 if (widget != WID_SCL_MATRIX) return;
845
846 bool rtl = _current_text_dir == TD_RTL;
847
848 /* Coordinates of scheme name column. */
849 const NWidgetBase *nwi = this->GetWidget<NWidgetBase>(WID_SCL_SPACER_DROPDOWN);
850 Rect sch = nwi->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
851 /* Coordinates of first dropdown. */
852 nwi = this->GetWidget<NWidgetBase>(WID_SCL_PRI_COL_DROPDOWN);
853 Rect pri = nwi->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
854 /* Coordinates of second dropdown. */
855 nwi = this->GetWidget<NWidgetBase>(WID_SCL_SEC_COL_DROPDOWN);
856 Rect sec = nwi->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
857
858 Rect pri_squ = pri.WithWidth(this->square.width, rtl);
859 Rect sec_squ = sec.WithWidth(this->square.width, rtl);
860
861 pri = pri.Indent(this->square.width + WidgetDimensions::scaled.hsep_normal, rtl);
862 sec = sec.Indent(this->square.width + WidgetDimensions::scaled.hsep_normal, rtl);
863
865 int square_offs = (ir.Height() - this->square.height) / 2;
866 int text_offs = (ir.Height() - GetCharacterHeight(FS_NORMAL)) / 2;
867
868 int y = ir.top;
869
870 /* Helper function to draw livery info. */
871 auto draw_livery = [&](std::string_view str, const Livery &livery, bool is_selected, bool is_default_scheme, int indent) {
872 /* Livery Label. */
873 DrawString(sch.left + (rtl ? 0 : indent), sch.right - (rtl ? indent : 0), y + text_offs, str, is_selected ? TC_WHITE : TC_BLACK);
874
875 /* Text below the first dropdown. */
876 DrawSprite(SPR_SQUARE, GetColourPalette(livery.colour1), pri_squ.left, y + square_offs);
877 DrawString(pri.left, pri.right, y + text_offs, (is_default_scheme || HasBit(livery.in_use, 0)) ? STR_COLOUR_DARK_BLUE + livery.colour1 : STR_COLOUR_DEFAULT, is_selected ? TC_WHITE : TC_GOLD);
878
879 /* Text below the second dropdown. */
880 if (sec.right > sec.left) { // Second dropdown has non-zero size.
881 DrawSprite(SPR_SQUARE, GetColourPalette(livery.colour2), sec_squ.left, y + square_offs);
882 DrawString(sec.left, sec.right, y + text_offs, (is_default_scheme || HasBit(livery.in_use, 1)) ? STR_COLOUR_DARK_BLUE + livery.colour2 : STR_COLOUR_DEFAULT, is_selected ? TC_WHITE : TC_GOLD);
883 }
884
885 y += this->line_height;
886 };
887
888 const Company *c = Company::Get(this->window_number);
889
890 if (livery_class < LC_GROUP_RAIL) {
891 int pos = this->vscroll->GetPosition();
892 for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
893 if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
894 if (pos-- > 0) continue;
895 draw_livery(GetString(STR_LIVERY_DEFAULT + scheme), c->livery[scheme], HasBit(this->sel, scheme), scheme == LS_DEFAULT, 0);
896 }
897 }
898 } else {
899 auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->groups);
900 for (auto it = first; it != last; ++it) {
901 const Group *g = it->group;
902 draw_livery(GetString(STR_GROUP_NAME, g->index), g->livery, this->sel == g->index, false, it->indent * WidgetDimensions::scaled.hsep_indent);
903 }
904
905 if (this->vscroll->GetCount() == 0) {
906 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 };
907 VehicleType vtype = (VehicleType)(this->livery_class - LC_GROUP_RAIL);
908 DrawString(ir.left, ir.right, y + text_offs, empty_labels[vtype], TC_BLACK);
909 }
910 }
911 }
912
913 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
914 {
915 switch (widget) {
916 /* Livery Class buttons */
926 this->RaiseWidget(WID_SCL_CLASS_GENERAL + this->livery_class);
927 this->livery_class = (LiveryClass)(widget - WID_SCL_CLASS_GENERAL);
928 this->LowerWidget(WID_SCL_CLASS_GENERAL + this->livery_class);
929
930 /* Select the first item in the list */
931 if (this->livery_class < LC_GROUP_RAIL) {
932 this->sel = 0;
933 for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
934 if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
935 this->sel = 1 << scheme;
936 break;
937 }
938 }
939 } else {
940 this->sel = GroupID::Invalid().base();
941 this->groups.ForceRebuild();
942 this->BuildGroupList(this->window_number);
943
944 if (!this->groups.empty()) {
945 this->sel = this->groups[0].group->index.base();
946 }
947 }
948
949 this->SetRows();
950 this->SetDirty();
951 break;
952
953 case WID_SCL_PRI_COL_DROPDOWN: // First colour dropdown
954 ShowColourDropDownMenu(WID_SCL_PRI_COL_DROPDOWN);
955 break;
956
957 case WID_SCL_SEC_COL_DROPDOWN: // Second colour dropdown
958 ShowColourDropDownMenu(WID_SCL_SEC_COL_DROPDOWN);
959 break;
960
961 case WID_SCL_MATRIX: {
962 if (this->livery_class < LC_GROUP_RAIL) {
963 uint row = this->vscroll->GetScrolledRowFromWidget(pt.y, this, widget);
964 if (row >= this->rows) return;
965
966 LiveryScheme j = (LiveryScheme)row;
967
968 for (LiveryScheme scheme = LS_BEGIN; scheme <= j && scheme < LS_END; scheme++) {
969 if (_livery_class[scheme] != this->livery_class || !HasBit(_loaded_newgrf_features.used_liveries, scheme)) j++;
970 }
971 assert(j < LS_END);
972
973 if (_ctrl_pressed) {
974 ToggleBit(this->sel, j);
975 } else {
976 this->sel = 1 << j;
977 }
978 } else {
979 auto it = this->vscroll->GetScrolledItemFromWidget(this->groups, pt.y, this, widget);
980 if (it == std::end(this->groups)) return;
981
982 this->sel = it->group->index.base();
983 }
984 this->SetDirty();
985 break;
986 }
987 }
988 }
989
990 void OnResize() override
991 {
992 this->vscroll->SetCapacityFromWidget(this, WID_SCL_MATRIX);
993 }
994
995 void OnDropdownSelect(WidgetID widget, int index, int) override
996 {
997 bool local = this->window_number == _local_company;
998 if (!local) return;
999
1000 Colours colour = static_cast<Colours>(index);
1001 if (colour >= COLOUR_END) colour = INVALID_COLOUR;
1002
1003 if (this->livery_class < LC_GROUP_RAIL) {
1004 /* Set company colour livery */
1005 for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
1006 /* Changed colour for the selected scheme, or all visible schemes if CTRL is pressed. */
1007 if (HasBit(this->sel, scheme) || (_ctrl_pressed && _livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme))) {
1009 }
1010 }
1011 } else {
1012 /* Setting group livery */
1013 Command<CMD_SET_GROUP_LIVERY>::Post(static_cast<GroupID>(this->sel), widget == WID_SCL_PRI_COL_DROPDOWN, colour);
1014 }
1015 }
1016
1022 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1023 {
1024 if (!gui_scope) return;
1025
1026 if (data != -1) {
1027 /* data contains a VehicleType, rebuild list if it displayed */
1028 if (this->livery_class == data + LC_GROUP_RAIL) {
1029 this->groups.ForceRebuild();
1030 this->BuildGroupList(this->window_number);
1031 this->SetRows();
1032
1033 if (!Group::IsValidID(this->sel)) {
1034 this->sel = GroupID::Invalid().base();
1035 if (!this->groups.empty()) this->sel = this->groups[0].group->index.base();
1036 }
1037
1038 this->SetDirty();
1039 }
1040 return;
1041 }
1042
1044
1045 bool current_class_valid = this->livery_class == LC_OTHER || this->livery_class >= LC_GROUP_RAIL;
1046 if (_settings_client.gui.liveries == LIT_ALL || (_settings_client.gui.liveries == LIT_COMPANY && this->window_number == _local_company)) {
1047 for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
1049 if (_livery_class[scheme] == this->livery_class) current_class_valid = true;
1050 this->EnableWidget(WID_SCL_CLASS_GENERAL + _livery_class[scheme]);
1051 } else if (this->livery_class < LC_GROUP_RAIL) {
1052 ClrBit(this->sel, scheme);
1053 }
1054 }
1055 }
1056
1057 if (!current_class_valid) {
1058 Point pt = {0, 0};
1059 this->OnClick(pt, WID_SCL_CLASS_GENERAL, 1);
1060 }
1061 }
1062};
1063
1064static constexpr NWidgetPart _nested_select_company_livery_widgets[] = {
1066 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
1067 NWidget(WWT_CAPTION, COLOUR_GREY, WID_SCL_CAPTION),
1068 NWidget(WWT_SHADEBOX, COLOUR_GREY),
1069 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
1070 NWidget(WWT_STICKYBOX, COLOUR_GREY),
1071 EndContainer(),
1073 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_GENERAL), SetMinimalSize(22, 22), SetFill(0, 1), SetSpriteTip(SPR_IMG_COMPANY_GENERAL, STR_LIVERY_GENERAL_TOOLTIP),
1074 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_RAIL), SetMinimalSize(22, 22), SetFill(0, 1), SetSpriteTip(SPR_IMG_TRAINLIST, STR_LIVERY_TRAIN_TOOLTIP),
1075 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_ROAD), SetMinimalSize(22, 22), SetFill(0, 1), SetSpriteTip(SPR_IMG_TRUCKLIST, STR_LIVERY_ROAD_VEHICLE_TOOLTIP),
1076 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_SHIP), SetMinimalSize(22, 22), SetFill(0, 1), SetSpriteTip(SPR_IMG_SHIPLIST, STR_LIVERY_SHIP_TOOLTIP),
1077 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_AIRCRAFT), SetMinimalSize(22, 22), SetFill(0, 1), SetSpriteTip(SPR_IMG_AIRPLANESLIST, STR_LIVERY_AIRCRAFT_TOOLTIP),
1078 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_GROUPS_RAIL), SetMinimalSize(22, 22), SetFill(0, 1), SetSpriteTip(SPR_GROUP_LIVERY_TRAIN, STR_LIVERY_TRAIN_GROUP_TOOLTIP),
1079 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_GROUPS_ROAD), SetMinimalSize(22, 22), SetFill(0, 1), SetSpriteTip(SPR_GROUP_LIVERY_ROADVEH, STR_LIVERY_ROAD_VEHICLE_GROUP_TOOLTIP),
1080 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_GROUPS_SHIP), SetMinimalSize(22, 22), SetFill(0, 1), SetSpriteTip(SPR_GROUP_LIVERY_SHIP, STR_LIVERY_SHIP_GROUP_TOOLTIP),
1081 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_GROUPS_AIRCRAFT), SetMinimalSize(22, 22), SetFill(0, 1), SetSpriteTip(SPR_GROUP_LIVERY_AIRCRAFT, STR_LIVERY_AIRCRAFT_GROUP_TOOLTIP),
1082 NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), SetResize(1, 0), EndContainer(),
1083 EndContainer(),
1085 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),
1087 EndContainer(),
1090 NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SCL_PRI_COL_DROPDOWN), SetFill(0, 1), SetToolTip(STR_LIVERY_PRIMARY_TOOLTIP),
1091 NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SCL_SEC_COL_DROPDOWN), SetFill(0, 1), SetToolTip(STR_LIVERY_SECONDARY_TOOLTIP),
1092 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
1093 EndContainer(),
1094};
1095
1096static WindowDesc _select_company_livery_desc(
1097 WDP_AUTO, "company_color_scheme", 0, 0,
1099 {},
1100 _nested_select_company_livery_widgets
1101);
1102
1103void ShowCompanyLiveryWindow(CompanyID company, GroupID group)
1104{
1106 if (w == nullptr) {
1107 new SelectCompanyLiveryWindow(_select_company_livery_desc, company, group);
1108 } else if (group != GroupID::Invalid()) {
1109 w->SetSelectedGroup(company, group);
1110 }
1111}
1112
1119void DrawCompanyManagerFace(CompanyManagerFace cmf, Colours colour, const Rect &r)
1120{
1122
1123 /* Determine offset from centre of drawing rect. */
1124 Dimension d = GetSpriteSize(SPR_GRADIENT);
1125 int x = CentreBounds(r.left, r.right, d.width);
1126 int y = CentreBounds(r.top, r.bottom, d.height);
1127
1128 bool has_moustache = !HasBit(ge, GENDER_FEMALE) && GetCompanyManagerFaceBits(cmf, CMFV_HAS_MOUSTACHE, ge) != 0;
1129 bool has_tie_earring = !HasBit(ge, GENDER_FEMALE) || GetCompanyManagerFaceBits(cmf, CMFV_HAS_TIE_EARRING, ge) != 0;
1130 bool has_glasses = GetCompanyManagerFaceBits(cmf, CMFV_HAS_GLASSES, ge) != 0;
1131 PaletteID pal;
1132
1133 /* Modify eye colour palette only if 2 or more valid values exist */
1134 if (_cmf_info[CMFV_EYE_COLOUR].valid_values[ge] < 2) {
1135 pal = PAL_NONE;
1136 } else {
1137 switch (GetCompanyManagerFaceBits(cmf, CMFV_EYE_COLOUR, ge)) {
1138 default: NOT_REACHED();
1139 case 0: pal = PALETTE_TO_BROWN; break;
1140 case 1: pal = PALETTE_TO_BLUE; break;
1141 case 2: pal = PALETTE_TO_GREEN; break;
1142 }
1143 }
1144
1145 /* Draw the gradient (background) */
1146 DrawSprite(SPR_GRADIENT, GetColourPalette(colour), x, y);
1147
1148 for (CompanyManagerFaceVariable cmfv = CMFV_CHEEKS; cmfv < CMFV_END; cmfv++) {
1149 switch (cmfv) {
1150 case CMFV_MOUSTACHE: if (!has_moustache) continue; break;
1151 case CMFV_LIPS:
1152 case CMFV_NOSE: if (has_moustache) continue; break;
1153 case CMFV_TIE_EARRING: if (!has_tie_earring) continue; break;
1154 case CMFV_GLASSES: if (!has_glasses) continue; break;
1155 default: break;
1156 }
1157 DrawSprite(GetCompanyManagerFaceSprite(cmf, cmfv, ge), (cmfv == CMFV_EYEBROWS) ? pal : PAL_NONE, x, y);
1158 }
1159}
1160
1164 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
1165 NWidget(WWT_CAPTION, COLOUR_GREY, WID_SCMF_CAPTION), SetStringTip(STR_FACE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1166 NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCMF_TOGGLE_LARGE_SMALL), SetSpriteTip(SPR_LARGE_SMALL_WINDOW, STR_FACE_ADVANCED_TOOLTIP), SetAspect(WidgetDimensions::ASPECT_TOGGLE_SIZE),
1167 EndContainer(),
1168 NWidget(WWT_PANEL, COLOUR_GREY, WID_SCMF_SELECT_FACE),
1170 /* Left side */
1173 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_FACE), SetMinimalSize(92, 119), SetFill(1, 0),
1174 EndContainer(),
1175 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_RANDOM_NEW_FACE), SetFill(1, 0), SetStringTip(STR_FACE_NEW_FACE_BUTTON, STR_FACE_NEW_FACE_TOOLTIP),
1176 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SCMF_SEL_LOADSAVE), // Load/number/save buttons under the portrait in the advanced view.
1177 NWidget(NWID_VERTICAL), SetPIP(0, 0, 0), SetPIPRatio(1, 0, 1),
1178 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_LOAD), SetFill(1, 0), SetStringTip(STR_FACE_LOAD, STR_FACE_LOAD_TOOLTIP),
1179 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_FACECODE), SetFill(1, 0), SetStringTip(STR_FACE_FACECODE, STR_FACE_FACECODE_TOOLTIP),
1180 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_SAVE), SetFill(1, 0), SetStringTip(STR_FACE_SAVE, STR_FACE_SAVE_TOOLTIP),
1181 EndContainer(),
1182 EndContainer(),
1183 EndContainer(),
1184 /* Right side */
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_MALEFEMALE), // Simple male/female face setting.
1189 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_MALE), SetFill(1, 0), SetStringTip(STR_FACE_MALE_BUTTON, STR_FACE_MALE_TOOLTIP),
1190 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_FEMALE), SetFill(1, 0), SetStringTip(STR_FACE_FEMALE_BUTTON, STR_FACE_FEMALE_TOOLTIP),
1191 EndContainer(),
1192 EndContainer(),
1193 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SCMF_SEL_PARTS), // Advanced face parts setting.
1196 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_MALE2), SetFill(1, 0), SetStringTip(STR_FACE_MALE_BUTTON, STR_FACE_MALE_TOOLTIP),
1197 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_FEMALE2), SetFill(1, 0), SetStringTip(STR_FACE_FEMALE_BUTTON, STR_FACE_FEMALE_TOOLTIP),
1198 EndContainer(),
1200 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_ETHNICITY_EUR), SetFill(1, 0), SetStringTip(STR_FACE_EUROPEAN, STR_FACE_EUROPEAN_TOOLTIP),
1201 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_ETHNICITY_AFR), SetFill(1, 0), SetStringTip(STR_FACE_AFRICAN, STR_FACE_AFRICAN_TOOLTIP),
1202 EndContainer(),
1206 SetStringTip(STR_FACE_EYECOLOUR), SetTextStyle(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1207 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_MOUSTACHE_EARRING), SetToolTip(STR_FACE_MOUSTACHE_EARRING_TOOLTIP), SetTextStyle(TC_WHITE),
1208 EndContainer(),
1210 NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_HAS_GLASSES_TEXT), SetFill(1, 0),
1211 SetStringTip(STR_FACE_GLASSES), SetTextStyle(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1212 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_GLASSES), SetToolTip(STR_FACE_GLASSES_TOOLTIP), SetTextStyle(TC_WHITE),
1213 EndContainer(),
1214 EndContainer(),
1217 NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_HAIR_TEXT), SetFill(1, 0),
1218 SetStringTip(STR_FACE_HAIR), SetTextStyle(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1220 NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_HAIR_L), SetArrowWidgetTypeTip(AWV_DECREASE, STR_FACE_HAIR_TOOLTIP),
1221 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAIR), SetToolTip(STR_FACE_HAIR_TOOLTIP), SetTextStyle(TC_WHITE),
1222 NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_HAIR_R), SetArrowWidgetTypeTip(AWV_INCREASE, STR_FACE_HAIR_TOOLTIP),
1223 EndContainer(),
1224 EndContainer(),
1226 NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_EYEBROWS_TEXT), SetFill(1, 0),
1227 SetStringTip(STR_FACE_EYEBROWS), SetTextStyle(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1229 NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYEBROWS_L), SetArrowWidgetTypeTip(AWV_DECREASE, STR_FACE_EYEBROWS_TOOLTIP),
1230 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYEBROWS), SetToolTip(STR_FACE_EYEBROWS_TOOLTIP), SetTextStyle(TC_WHITE),
1231 NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYEBROWS_R), SetArrowWidgetTypeTip(AWV_INCREASE, STR_FACE_EYEBROWS_TOOLTIP),
1232 EndContainer(),
1233 EndContainer(),
1235 NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_EYECOLOUR_TEXT), SetFill(1, 0),
1236 SetStringTip(STR_FACE_EYECOLOUR), SetTextStyle(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1238 NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR_L), SetArrowWidgetTypeTip(AWV_DECREASE, STR_FACE_EYECOLOUR_TOOLTIP),
1239 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR), SetToolTip(STR_FACE_EYECOLOUR_TOOLTIP), SetTextStyle(TC_WHITE),
1240 NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR_R), SetArrowWidgetTypeTip(AWV_INCREASE, STR_FACE_EYECOLOUR_TOOLTIP),
1241 EndContainer(),
1242 EndContainer(),
1244 NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_GLASSES_TEXT), SetFill(1, 0),
1245 SetStringTip(STR_FACE_GLASSES), SetTextStyle(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1247 NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_GLASSES_L), SetArrowWidgetTypeTip(AWV_DECREASE, STR_FACE_GLASSES_TOOLTIP_2),
1248 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_GLASSES), SetToolTip(STR_FACE_GLASSES_TOOLTIP_2), SetTextStyle(TC_WHITE),
1249 NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_GLASSES_R), SetArrowWidgetTypeTip(AWV_INCREASE, STR_FACE_GLASSES_TOOLTIP_2),
1250 EndContainer(),
1251 EndContainer(),
1253 NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_NOSE_TEXT), SetFill(1, 0),
1254 SetStringTip(STR_FACE_NOSE), SetTextStyle(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1256 NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_NOSE_L), SetArrowWidgetTypeTip(AWV_DECREASE, STR_FACE_NOSE_TOOLTIP),
1257 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_NOSE), SetToolTip(STR_FACE_NOSE_TOOLTIP), SetTextStyle(TC_WHITE),
1258 NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_NOSE_R), SetArrowWidgetTypeTip(AWV_INCREASE, STR_FACE_NOSE_TOOLTIP),
1259 EndContainer(),
1260 EndContainer(),
1262 NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_LIPS_MOUSTACHE_TEXT), SetFill(1, 0),
1263 SetStringTip(STR_FACE_MOUSTACHE), SetTextStyle(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1265 NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE_L), SetArrowWidgetTypeTip(AWV_DECREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP),
1266 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE), SetToolTip(STR_FACE_LIPS_MOUSTACHE_TOOLTIP), SetTextStyle(TC_WHITE),
1267 NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE_R), SetArrowWidgetTypeTip(AWV_INCREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP),
1268 EndContainer(),
1269 EndContainer(),
1271 NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_CHIN_TEXT), SetFill(1, 0),
1272 SetStringTip(STR_FACE_CHIN), SetTextStyle(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1274 NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_CHIN_L), SetArrowWidgetTypeTip(AWV_DECREASE, STR_FACE_CHIN_TOOLTIP),
1275 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_CHIN), SetToolTip(STR_FACE_CHIN_TOOLTIP), SetTextStyle(TC_WHITE),
1276 NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_CHIN_R), SetArrowWidgetTypeTip(AWV_INCREASE, STR_FACE_CHIN_TOOLTIP),
1277 EndContainer(),
1278 EndContainer(),
1280 NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_JACKET_TEXT), SetFill(1, 0),
1281 SetStringTip(STR_FACE_JACKET), SetTextStyle(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1283 NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_JACKET_L), SetArrowWidgetTypeTip(AWV_DECREASE, STR_FACE_JACKET_TOOLTIP),
1284 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_JACKET), SetToolTip(STR_FACE_JACKET_TOOLTIP), SetTextStyle(TC_WHITE),
1285 NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_JACKET_R), SetArrowWidgetTypeTip(AWV_INCREASE, STR_FACE_JACKET_TOOLTIP),
1286 EndContainer(),
1287 EndContainer(),
1289 NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_COLLAR_TEXT), SetFill(1, 0),
1290 SetStringTip(STR_FACE_COLLAR), SetTextStyle(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1292 NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_COLLAR_L), SetArrowWidgetTypeTip(AWV_DECREASE, STR_FACE_COLLAR_TOOLTIP),
1293 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_COLLAR), SetToolTip(STR_FACE_COLLAR_TOOLTIP), SetTextStyle(TC_WHITE),
1294 NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_COLLAR_R), SetArrowWidgetTypeTip(AWV_INCREASE, STR_FACE_COLLAR_TOOLTIP),
1295 EndContainer(),
1296 EndContainer(),
1298 NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_TIE_EARRING_TEXT), SetFill(1, 0),
1299 SetStringTip(STR_FACE_EARRING), SetTextStyle(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1301 NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING_L), SetArrowWidgetTypeTip(AWV_DECREASE, STR_FACE_TIE_EARRING_TOOLTIP),
1302 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING), SetToolTip(STR_FACE_TIE_EARRING_TOOLTIP), SetTextStyle(TC_WHITE),
1303 NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING_R), SetArrowWidgetTypeTip(AWV_INCREASE, STR_FACE_TIE_EARRING_TOOLTIP),
1304 EndContainer(),
1305 EndContainer(),
1306 EndContainer(),
1307 EndContainer(),
1308 EndContainer(),
1309 EndContainer(),
1310 EndContainer(),
1311 EndContainer(),
1313 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_CANCEL), SetFill(1, 0), SetStringTip(STR_BUTTON_CANCEL, STR_FACE_CANCEL_TOOLTIP),
1314 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_ACCEPT), SetFill(1, 0), SetStringTip(STR_BUTTON_OK, STR_FACE_OK_TOOLTIP),
1315 EndContainer(),
1316};
1317
1320{
1322 bool advanced = false;
1323
1325 bool is_female = false;
1326 bool is_moust_male = false;
1327
1330
1339 std::string GetFaceString(WidgetID widget_index, uint8_t val, bool is_bool_widget) const
1340 {
1341 const NWidgetCore *nwi_widget = this->GetWidget<NWidgetCore>(widget_index);
1342 if (nwi_widget->IsDisabled()) return {};
1343
1344 /* If it a bool button write yes or no. */
1345 if (is_bool_widget) return GetString((val != 0) ? STR_FACE_YES : STR_FACE_NO);
1346
1347 /* Else write the value + 1. */
1348 return GetString(STR_JUST_INT, val + 1);
1349 }
1350
1351 void UpdateData()
1352 {
1353 this->ge = (GenderEthnicity)GB(this->face, _cmf_info[CMFV_GEN_ETHN].offset, _cmf_info[CMFV_GEN_ETHN].length); // get the gender and ethnicity
1354 this->is_female = HasBit(this->ge, GENDER_FEMALE); // get the gender: 0 == male and 1 == female
1355 this->is_moust_male = !is_female && GetCompanyManagerFaceBits(this->face, CMFV_HAS_MOUSTACHE, this->ge) != 0; // is a male face with moustache
1356
1357 this->GetWidget<NWidgetCore>(WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT)->SetString(this->is_female ? STR_FACE_EARRING : STR_FACE_MOUSTACHE);
1358 this->GetWidget<NWidgetCore>(WID_SCMF_TIE_EARRING_TEXT)->SetString(this->is_female ? STR_FACE_EARRING : STR_FACE_TIE);
1359 this->GetWidget<NWidgetCore>(WID_SCMF_LIPS_MOUSTACHE_TEXT)->SetString(this->is_moust_male ? STR_FACE_MOUSTACHE : STR_FACE_LIPS);
1360 }
1361
1362public:
1364 {
1365 this->CreateNestedTree();
1366 this->SelectDisplayPlanes(this->advanced);
1367 this->FinishInitNested(parent->window_number);
1368 this->parent = parent;
1369 this->owner = this->window_number;
1370 this->face = Company::Get(this->window_number)->face;
1371
1372 this->UpdateData();
1373 }
1374
1380 {
1381 this->GetWidget<NWidgetStacked>(WID_SCMF_SEL_LOADSAVE)->SetDisplayedPlane(advanced ? 0 : SZSP_NONE);
1382 this->GetWidget<NWidgetStacked>(WID_SCMF_SEL_PARTS)->SetDisplayedPlane(advanced ? 0 : SZSP_NONE);
1383 this->GetWidget<NWidgetStacked>(WID_SCMF_SEL_MALEFEMALE)->SetDisplayedPlane(advanced ? SZSP_NONE : 0);
1384 this->GetWidget<NWidgetCore>(WID_SCMF_RANDOM_NEW_FACE)->SetString(advanced ? STR_FACE_RANDOM : STR_FACE_NEW_FACE_BUTTON);
1385
1386 NWidgetCore *wi = this->GetWidget<NWidgetCore>(WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON);
1387 if (advanced) {
1388 wi->SetStringTip(STR_FACE_SIMPLE, STR_FACE_SIMPLE_TOOLTIP);
1389 } else {
1390 wi->SetStringTip(STR_FACE_ADVANCED, STR_FACE_ADVANCED_TOOLTIP);
1391 }
1392 }
1393
1394 void OnInit() override
1395 {
1396 /* Size of the boolean yes/no button. */
1400 /* Size of the number button + arrows. */
1401 Dimension number_dim = {0, 0};
1402 for (int val = 1; val <= 12; val++) {
1404 }
1405 uint arrows_width = GetSpriteSize(SPR_ARROW_LEFT).width + GetSpriteSize(SPR_ARROW_RIGHT).width + 2 * (WidgetDimensions::scaled.imgbtn.Horizontal());
1406 number_dim.width += WidgetDimensions::scaled.framerect.Horizontal() + arrows_width;
1408 /* Compute width of both buttons. */
1409 yesno_dim.width = std::max(yesno_dim.width, number_dim.width);
1410 number_dim.width = yesno_dim.width - arrows_width;
1411
1412 this->yesno_dim = yesno_dim;
1413 this->number_dim = number_dim;
1414 }
1415
1416 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
1417 {
1418 switch (widget) {
1420 size = maxdim(size, GetStringBoundingBox(STR_FACE_EARRING));
1421 size = maxdim(size, GetStringBoundingBox(STR_FACE_MOUSTACHE));
1422 break;
1423
1425 size = maxdim(size, GetStringBoundingBox(STR_FACE_EARRING));
1426 size = maxdim(size, GetStringBoundingBox(STR_FACE_TIE));
1427 break;
1428
1430 size = maxdim(size, GetStringBoundingBox(STR_FACE_LIPS));
1431 size = maxdim(size, GetStringBoundingBox(STR_FACE_MOUSTACHE));
1432 break;
1433
1434 case WID_SCMF_FACE:
1435 size = maxdim(size, GetScaledSpriteSize(SPR_GRADIENT));
1436 break;
1437
1440 size = this->yesno_dim;
1441 break;
1442
1443 case WID_SCMF_EYECOLOUR:
1444 case WID_SCMF_CHIN:
1445 case WID_SCMF_EYEBROWS:
1447 case WID_SCMF_NOSE:
1448 case WID_SCMF_HAIR:
1449 case WID_SCMF_JACKET:
1450 case WID_SCMF_COLLAR:
1452 case WID_SCMF_GLASSES:
1453 size = this->number_dim;
1454 break;
1455 }
1456 }
1457
1458 void OnPaint() override
1459 {
1460 /* lower the non-selected gender button */
1461 this->SetWidgetsLoweredState(!this->is_female, WID_SCMF_MALE, WID_SCMF_MALE2);
1463
1464 /* advanced company manager face selection window */
1465
1466 /* lower the non-selected ethnicity button */
1469
1470
1471 /* Disable dynamically the widgets which CompanyManagerFaceVariable has less than 2 options
1472 * (or in other words you haven't any choice).
1473 * If the widgets depend on a HAS-variable and this is false the widgets will be disabled, too. */
1474
1475 /* Eye colour buttons */
1476 this->SetWidgetsDisabledState(_cmf_info[CMFV_EYE_COLOUR].valid_values[this->ge] < 2,
1478
1479 /* Chin buttons */
1480 this->SetWidgetsDisabledState(_cmf_info[CMFV_CHIN].valid_values[this->ge] < 2,
1482
1483 /* Eyebrows buttons */
1484 this->SetWidgetsDisabledState(_cmf_info[CMFV_EYEBROWS].valid_values[this->ge] < 2,
1486
1487 /* Lips or (if it a male face with a moustache) moustache buttons */
1488 this->SetWidgetsDisabledState(_cmf_info[this->is_moust_male ? CMFV_MOUSTACHE : CMFV_LIPS].valid_values[this->ge] < 2,
1490
1491 /* Nose buttons | male faces with moustache haven't any nose options */
1492 this->SetWidgetsDisabledState(_cmf_info[CMFV_NOSE].valid_values[this->ge] < 2 || this->is_moust_male,
1494
1495 /* Hair buttons */
1496 this->SetWidgetsDisabledState(_cmf_info[CMFV_HAIR].valid_values[this->ge] < 2,
1498
1499 /* Jacket buttons */
1500 this->SetWidgetsDisabledState(_cmf_info[CMFV_JACKET].valid_values[this->ge] < 2,
1502
1503 /* Collar buttons */
1504 this->SetWidgetsDisabledState(_cmf_info[CMFV_COLLAR].valid_values[this->ge] < 2,
1506
1507 /* Tie/earring buttons | female faces without earring haven't any earring options */
1508 this->SetWidgetsDisabledState(_cmf_info[CMFV_TIE_EARRING].valid_values[this->ge] < 2 ||
1509 (this->is_female && GetCompanyManagerFaceBits(this->face, CMFV_HAS_TIE_EARRING, this->ge) == 0),
1511
1512 /* Glasses buttons | faces without glasses haven't any glasses options */
1513 this->SetWidgetsDisabledState(_cmf_info[CMFV_GLASSES].valid_values[this->ge] < 2 || GetCompanyManagerFaceBits(this->face, CMFV_HAS_GLASSES, this->ge) == 0,
1515
1516 this->DrawWidgets();
1517 }
1518
1519 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
1520 {
1521 switch (widget) {
1523 CompanyManagerFaceVariable facepart = this->is_female ? CMFV_HAS_TIE_EARRING : CMFV_HAS_MOUSTACHE;
1524 return this->GetFaceString(widget, GetCompanyManagerFaceBits(this->face, facepart, this->ge), true);
1525 }
1526
1528 return this->GetFaceString(widget, GetCompanyManagerFaceBits(this->face, CMFV_TIE_EARRING, this->ge), false);
1529
1531 CompanyManagerFaceVariable facepart = this->is_moust_male ? CMFV_MOUSTACHE : CMFV_LIPS;
1532 return this->GetFaceString(widget, GetCompanyManagerFaceBits(this->face, facepart, this->ge), false);
1533 }
1534
1536 return this->GetFaceString(widget, GetCompanyManagerFaceBits(this->face, CMFV_HAS_GLASSES, this->ge), true );
1537
1538 case WID_SCMF_HAIR:
1539 return this->GetFaceString(widget, GetCompanyManagerFaceBits(this->face, CMFV_HAIR, this->ge), false);
1540
1541 case WID_SCMF_EYEBROWS:
1542 return this->GetFaceString(widget, GetCompanyManagerFaceBits(this->face, CMFV_EYEBROWS, this->ge), false);
1543
1544 case WID_SCMF_EYECOLOUR:
1545 return this->GetFaceString(widget, GetCompanyManagerFaceBits(this->face, CMFV_EYE_COLOUR, this->ge), false);
1546
1547 case WID_SCMF_GLASSES:
1548 return this->GetFaceString(widget, GetCompanyManagerFaceBits(this->face, CMFV_GLASSES, this->ge), false);
1549
1550 case WID_SCMF_NOSE:
1551 return this->GetFaceString(widget, GetCompanyManagerFaceBits(this->face, CMFV_NOSE, this->ge), false);
1552
1553 case WID_SCMF_CHIN:
1554 return this->GetFaceString(widget, GetCompanyManagerFaceBits(this->face, CMFV_CHIN, this->ge), false);
1555
1556 case WID_SCMF_JACKET:
1557 return this->GetFaceString(widget, GetCompanyManagerFaceBits(this->face, CMFV_JACKET, this->ge), false);
1558
1559 case WID_SCMF_COLLAR:
1560 return this->GetFaceString(widget, GetCompanyManagerFaceBits(this->face, CMFV_COLLAR, this->ge), false);
1561
1562 default:
1563 return this->Window::GetWidgetString(widget, stringid);
1564 }
1565 }
1566
1567 void DrawWidget(const Rect &r, WidgetID widget) const override
1568 {
1569 switch (widget) {
1570 case WID_SCMF_FACE:
1571 DrawCompanyManagerFace(this->face, Company::Get(this->window_number)->colour, r);
1572 break;
1573 }
1574 }
1575
1576 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1577 {
1578 switch (widget) {
1579 /* Toggle size, advanced/simple face selection */
1582 this->advanced = !this->advanced;
1583 this->SelectDisplayPlanes(this->advanced);
1584 this->ReInit();
1585 break;
1586
1587 /* OK button */
1588 case WID_SCMF_ACCEPT:
1590 [[fallthrough]];
1591
1592 /* Cancel button */
1593 case WID_SCMF_CANCEL:
1594 this->Close();
1595 break;
1596
1597 /* Load button */
1598 case WID_SCMF_LOAD:
1601 ShowErrorMessage(GetEncodedString(STR_FACE_LOAD_DONE), {}, WL_INFO);
1602 this->UpdateData();
1603 this->SetDirty();
1604 break;
1605
1606 /* 'Company manager face number' button, view and/or set company manager face number */
1607 case WID_SCMF_FACECODE:
1608 ShowQueryString(GetString(STR_JUST_INT, this->face), STR_FACE_FACECODE_CAPTION, 10 + 1, this, CS_NUMERAL, {});
1609 break;
1610
1611 /* Save button */
1612 case WID_SCMF_SAVE:
1614 ShowErrorMessage(GetEncodedString(STR_FACE_SAVE_DONE), {}, WL_INFO);
1615 break;
1616
1617 /* Toggle gender (male/female) button */
1618 case WID_SCMF_MALE:
1619 case WID_SCMF_FEMALE:
1620 case WID_SCMF_MALE2:
1621 case WID_SCMF_FEMALE2:
1622 SetCompanyManagerFaceBits(this->face, CMFV_GENDER, this->ge, (widget == WID_SCMF_FEMALE || widget == WID_SCMF_FEMALE2));
1624 this->UpdateData();
1625 this->SetDirty();
1626 break;
1627
1628 /* Randomize face button */
1630 RandomCompanyManagerFaceBits(this->face, this->ge, this->advanced, _interactive_random);
1631 this->UpdateData();
1632 this->SetDirty();
1633 break;
1634
1635 /* Toggle ethnicity (european/african) button */
1638 SetCompanyManagerFaceBits(this->face, CMFV_ETHNICITY, this->ge, widget - WID_SCMF_ETHNICITY_EUR);
1640 this->UpdateData();
1641 this->SetDirty();
1642 break;
1643
1644 default:
1645 /* Here all buttons from WID_SCMF_HAS_MOUSTACHE_EARRING to WID_SCMF_GLASSES_R are handled.
1646 * First it checks which CompanyManagerFaceVariable is being changed, and then either
1647 * a: invert the value for boolean variables, or
1648 * b: it checks inside of IncreaseCompanyManagerFaceBits() if a left (_L) butten is pressed and then decrease else increase the variable */
1649 if (widget >= WID_SCMF_HAS_MOUSTACHE_EARRING && widget <= WID_SCMF_GLASSES_R) {
1650 CompanyManagerFaceVariable cmfv; // which CompanyManagerFaceVariable shall be edited
1651
1652 if (widget < WID_SCMF_EYECOLOUR_L) { // Bool buttons
1653 switch (widget - WID_SCMF_HAS_MOUSTACHE_EARRING) {
1654 default: NOT_REACHED();
1655 case 0: cmfv = this->is_female ? CMFV_HAS_TIE_EARRING : CMFV_HAS_MOUSTACHE; break; // Has earring/moustache button
1656 case 1: cmfv = CMFV_HAS_GLASSES; break; // Has glasses button
1657 }
1658 SetCompanyManagerFaceBits(this->face, cmfv, this->ge, !GetCompanyManagerFaceBits(this->face, cmfv, this->ge));
1660 } else { // Value buttons
1661 switch ((widget - WID_SCMF_EYECOLOUR_L) / 3) {
1662 default: NOT_REACHED();
1663 case 0: cmfv = CMFV_EYE_COLOUR; break; // Eye colour buttons
1664 case 1: cmfv = CMFV_CHIN; break; // Chin buttons
1665 case 2: cmfv = CMFV_EYEBROWS; break; // Eyebrows buttons
1666 case 3: cmfv = this->is_moust_male ? CMFV_MOUSTACHE : CMFV_LIPS; break; // Moustache or lips buttons
1667 case 4: cmfv = CMFV_NOSE; break; // Nose buttons
1668 case 5: cmfv = CMFV_HAIR; break; // Hair buttons
1669 case 6: cmfv = CMFV_JACKET; break; // Jacket buttons
1670 case 7: cmfv = CMFV_COLLAR; break; // Collar buttons
1671 case 8: cmfv = CMFV_TIE_EARRING; break; // Tie/earring buttons
1672 case 9: cmfv = CMFV_GLASSES; break; // Glasses buttons
1673 }
1674 /* 0 == left (_L), 1 == middle or 2 == right (_R) - button click */
1675 IncreaseCompanyManagerFaceBits(this->face, cmfv, this->ge, (((widget - WID_SCMF_EYECOLOUR_L) % 3) != 0) ? 1 : -1);
1676 }
1677 this->UpdateData();
1678 this->SetDirty();
1679 }
1680 break;
1681 }
1682 }
1683
1684 void OnQueryTextFinished(std::optional<std::string> str) override
1685 {
1686 if (!str.has_value()) return;
1687 /* Set a new company manager face number */
1688 if (!str->empty()) {
1689 auto val = ParseInteger(*str, 10, true);
1690 if (!val.has_value()) return;
1691 this->face = *val;
1693 ShowErrorMessage(GetEncodedString(STR_FACE_FACECODE_SET), {}, WL_INFO);
1694 this->UpdateData();
1695 this->SetDirty();
1696 } else {
1697 ShowErrorMessage(GetEncodedString(STR_FACE_FACECODE_ERR), {}, WL_INFO);
1698 }
1699 }
1700};
1701
1704 WDP_AUTO, {}, 0, 0,
1708);
1709
1722
1723static constexpr NWidgetPart _nested_company_infrastructure_widgets[] = {
1725 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
1726 NWidget(WWT_CAPTION, COLOUR_GREY, WID_CI_CAPTION),
1727 NWidget(WWT_SHADEBOX, COLOUR_GREY),
1728 NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
1729 NWidget(WWT_STICKYBOX, COLOUR_GREY),
1730 EndContainer(),
1732 NWidget(WWT_PANEL, COLOUR_GREY, WID_CI_LIST), SetFill(1, 1), SetResize(0, 1),
1734 EndContainer(),
1737 NWidget(WWT_RESIZEBOX, COLOUR_GREY),
1738 EndContainer(),
1739 EndContainer(),
1740};
1741
1746{
1747 enum class InfrastructureItemType : uint8_t {
1748 Header,
1749 Spacer,
1750 Value,
1751 Total,
1752 };
1753
1756 StringID label;
1757 uint count;
1758 Money cost;
1759 };
1760
1761 uint count_width = 0;
1762 uint cost_width = 0;
1763
1764 mutable std::vector<InfrastructureItem> list;
1765
1767 {
1768 this->InitNested(window_number);
1769 this->owner = this->window_number;
1770 }
1771
1772 void OnInit() override
1773 {
1774 this->UpdateInfrastructureList();
1775 }
1776
1777 void UpdateInfrastructureList()
1778 {
1779 this->list.clear();
1780
1781 const Company *c = Company::GetIfValid(this->window_number);
1782 if (c == nullptr) return;
1783
1784 Money total_monthly_cost = 0;
1785
1786 if (uint32_t rail_total = c->infrastructure.GetRailTotal(); rail_total > 0) {
1787 /* Rail types and signals. */
1788 this->list.emplace_back(InfrastructureItemType::Header, STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT);
1789
1790 for (const RailType &rt : _sorted_railtypes) {
1791 if (c->infrastructure.rail[rt] == 0) continue;
1792 Money monthly_cost = RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total);
1793 total_monthly_cost += monthly_cost;
1794 this->list.emplace_back(InfrastructureItemType::Value, GetRailTypeInfo(rt)->strings.name, c->infrastructure.rail[rt], monthly_cost);
1795 }
1796
1797 if (c->infrastructure.signal > 0) {
1799 total_monthly_cost += monthly_cost;
1800 this->list.emplace_back(InfrastructureItemType::Value, STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS, c->infrastructure.signal, monthly_cost);
1801 }
1802 }
1803
1804 if (uint32_t road_total = c->infrastructure.GetRoadTotal(); road_total > 0) {
1805 /* Road types. */
1806 if (!this->list.empty()) this->list.emplace_back(InfrastructureItemType::Spacer);
1807 this->list.emplace_back(InfrastructureItemType::Header, STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT);
1808
1809 for (const RoadType &rt : _sorted_roadtypes) {
1810 if (!RoadTypeIsRoad(rt)) continue;
1811 if (c->infrastructure.road[rt] == 0) continue;
1812 Money monthly_cost = RoadMaintenanceCost(rt, c->infrastructure.road[rt], road_total);
1813 total_monthly_cost += monthly_cost;
1814 this->list.emplace_back(InfrastructureItemType::Value, GetRoadTypeInfo(rt)->strings.name, c->infrastructure.road[rt], monthly_cost);
1815 }
1816 }
1817
1818 if (uint32_t tram_total = c->infrastructure.GetTramTotal(); tram_total > 0) {
1819 /* Tram types. */
1820 if (!this->list.empty()) this->list.emplace_back(InfrastructureItemType::Spacer);
1821 this->list.emplace_back(InfrastructureItemType::Header, STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT);
1822
1823 for (const RoadType &rt : _sorted_roadtypes) {
1824 if (!RoadTypeIsTram(rt)) continue;
1825 if (c->infrastructure.road[rt] == 0) continue;
1826 Money monthly_cost = RoadMaintenanceCost(rt, c->infrastructure.road[rt], tram_total);
1827 total_monthly_cost += monthly_cost;
1828 this->list.emplace_back(InfrastructureItemType::Value, GetRoadTypeInfo(rt)->strings.name, c->infrastructure.road[rt], monthly_cost);
1829 }
1830 }
1831
1832 if (c->infrastructure.water > 0) {
1833 /* Canals, locks, and ship depots (docks are counted as stations). */
1834 if (!this->list.empty()) this->list.emplace_back(InfrastructureItemType::Spacer);
1835 this->list.emplace_back(InfrastructureItemType::Header, STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT);
1836
1838 total_monthly_cost += monthly_cost;
1839 this->list.emplace_back(InfrastructureItemType::Value, STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS, c->infrastructure.water, monthly_cost);
1840 }
1841
1842 if (Money airport_cost = AirportMaintenanceCost(c->index); airport_cost > 0 || c->infrastructure.station > 0) {
1843 /* Stations and airports. */
1844 if (!this->list.empty()) this->list.emplace_back(InfrastructureItemType::Spacer);
1845 this->list.emplace_back(InfrastructureItemType::Header, STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT);
1846
1847 if (c->infrastructure.station > 0) {
1849 total_monthly_cost += monthly_cost;
1850 this->list.emplace_back(InfrastructureItemType::Value, STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS, c->infrastructure.station, monthly_cost);
1851 }
1852
1853 if (airport_cost > 0) {
1854 Money monthly_cost = airport_cost;
1855 total_monthly_cost += monthly_cost;
1856 this->list.emplace_back(InfrastructureItemType::Value, STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS, c->infrastructure.airport, monthly_cost);
1857 }
1858 }
1859
1861 /* Total monthly maintenance cost. */
1862 this->list.emplace_back(InfrastructureItemType::Spacer);
1863 this->list.emplace_back(InfrastructureItemType::Total, STR_NULL, 0, total_monthly_cost);
1864 }
1865
1866 /* Update scrollbar. */
1867 this->GetScrollbar(WID_CI_SCROLLBAR)->SetCount(std::size(list));
1868 }
1869
1870 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
1871 {
1872 switch (widget) {
1873 case WID_CI_CAPTION:
1874 return GetString(STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION, this->window_number);
1875
1876 default:
1877 return this->Window::GetWidgetString(widget, stringid);
1878 }
1879 }
1880
1881 void FindWindowPlacementAndResize(int def_width, int def_height, bool allow_resize) override
1882 {
1883 if (def_height == 0) {
1884 /* Try to open the window with the exact required rows, but clamp to a reasonable limit. */
1885 int rows = (this->GetWidget<NWidgetBase>(WID_CI_LIST)->current_y - WidgetDimensions::scaled.framerect.Vertical()) / GetCharacterHeight(FS_NORMAL);
1886 int delta = std::min(20, static_cast<int>(std::size(this->list))) - rows;
1887 def_height = this->height + delta * GetCharacterHeight(FS_NORMAL);
1888 }
1889
1890 this->Window::FindWindowPlacementAndResize(def_width, def_height, allow_resize);
1891 }
1892
1893 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
1894 {
1895 if (widget != WID_CI_LIST) return;
1896
1897 uint max_count = 1000; // Some random number to reserve minimum space.
1898 Money max_cost = 1000000; // Some random number to reserve minimum space.
1899
1900 /* List of headers that might be used. */
1901 static constexpr StringID header_strings[] = {
1902 STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT,
1903 STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT,
1904 STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT,
1905 STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT,
1906 STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT,
1907 };
1908 /* List of labels that might be used. */
1909 static constexpr StringID label_strings[] = {
1910 STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS,
1911 STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS,
1912 STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS,
1913 STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS,
1914 };
1915
1916 uint max_header_width = GetStringListWidth(header_strings);
1917 uint max_label_width = GetStringListWidth(label_strings);
1918
1919 /* Include width of all possible rail and road types. */
1920 for (const RailType &rt : _sorted_railtypes) max_label_width = std::max(max_label_width, GetStringBoundingBox(GetRailTypeInfo(rt)->strings.name).width);
1921 for (const RoadType &rt : _sorted_roadtypes) max_label_width = std::max(max_label_width, GetStringBoundingBox(GetRoadTypeInfo(rt)->strings.name).width);
1922
1923 for (const InfrastructureItem &entry : this->list) {
1924 max_count = std::max(max_count, entry.count);
1925 max_cost = std::max(max_cost, entry.cost * 12);
1926 }
1927
1928 max_label_width += WidgetDimensions::scaled.hsep_indent;
1929 this->count_width = GetStringBoundingBox(GetString(STR_JUST_COMMA, max_count)).width;
1930
1932 this->cost_width = GetStringBoundingBox(GetString(TimerGameEconomy::UsingWallclockUnits() ? STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_PERIOD : STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_YEAR, max_cost)).width;
1933 } else {
1934 this->cost_width = 0;
1935 }
1936
1937 size.width = max_label_width + WidgetDimensions::scaled.hsep_wide + this->count_width + WidgetDimensions::scaled.hsep_wide + this->cost_width;
1938 size.width = std::max(size.width, max_header_width) + WidgetDimensions::scaled.framerect.Horizontal();
1939
1941 }
1942
1943 void DrawWidget(const Rect &r, WidgetID widget) const override
1944 {
1945 if (widget != WID_CI_LIST) return;
1946
1947 bool rtl = _current_text_dir == TD_RTL; // We allocate space from end-to-start so the label fills.
1948 int line_height = GetCharacterHeight(FS_NORMAL);
1949
1950 Rect ir = r.Shrink(WidgetDimensions::scaled.framerect);
1951 Rect countr = ir.WithWidth(this->count_width, !rtl);
1952 Rect costr = ir.Indent(this->count_width + WidgetDimensions::scaled.hsep_wide, !rtl).WithWidth(this->cost_width, !rtl);
1953 Rect labelr = ir.Indent(this->count_width + WidgetDimensions::scaled.hsep_wide + this->cost_width + WidgetDimensions::scaled.hsep_wide, !rtl);
1954
1955 auto [first, last] = this->GetScrollbar(WID_CI_SCROLLBAR)->GetVisibleRangeIterators(this->list);
1956 for (auto it = first; it != last; ++it) {
1957 switch (it->type) {
1959 /* Header is allowed to fill the window's width. */
1960 DrawString(ir.left, ir.right, labelr.top, GetString(it->label), TC_ORANGE);
1961 break;
1962
1964 break;
1965
1967 /* Draw line in the spacer above the total. */
1969 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);
1970 break;
1971
1973 DrawString(labelr.Indent(WidgetDimensions::scaled.hsep_indent, rtl), GetString(it->label), TC_WHITE);
1974 DrawString(countr, GetString(STR_JUST_COMMA, it->count), TC_WHITE, SA_RIGHT | SA_FORCE);
1976 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);
1977 }
1978 break;
1979 }
1980
1981 labelr.top += line_height;
1982 countr.top += line_height;
1983 costr.top += line_height;
1984 }
1985 }
1986
1987 const IntervalTimer<TimerWindow> redraw_interval = {std::chrono::seconds(1), [this](auto) {
1988 this->UpdateInfrastructureList();
1990 }};
1991
1992 void OnResize() override
1993 {
1995 }
1996
2002 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
2003 {
2004 if (!gui_scope) return;
2005
2006 this->ReInit();
2007 }
2008};
2009
2010static WindowDesc _company_infrastructure_desc(
2011 WDP_AUTO, "company_infrastructure", 0, 0,
2013 {},
2014 _nested_company_infrastructure_widgets
2015);
2016
2022{
2023 if (!Company::IsValidID(company)) return;
2024 AllocateWindowDescFront<CompanyInfrastructureWindow>(_company_infrastructure_desc, company);
2025}
2026
2027static constexpr NWidgetPart _nested_company_widgets[] = {
2029 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
2030 NWidget(WWT_CAPTION, COLOUR_GREY, WID_C_CAPTION),
2031 NWidget(WWT_SHADEBOX, COLOUR_GREY),
2032 NWidget(WWT_STICKYBOX, COLOUR_GREY),
2033 EndContainer(),
2034 NWidget(WWT_PANEL, COLOUR_GREY),
2037 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_FACE), SetMinimalSize(92, 119), SetFill(1, 0),
2038 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_FACE_TITLE), SetFill(1, 1), SetMinimalTextLines(2, 0),
2039 EndContainer(),
2043 NWidget(WWT_TEXT, INVALID_COLOUR, WID_C_DESC_INAUGURATION), SetFill(1, 0),
2045 NWidget(WWT_LABEL, INVALID_COLOUR, WID_C_DESC_COLOUR_SCHEME), SetStringTip(STR_COMPANY_VIEW_COLOUR_SCHEME_TITLE),
2047 EndContainer(),
2049 NWidget(WWT_TEXT, INVALID_COLOUR, WID_C_DESC_VEHICLE), SetStringTip(STR_COMPANY_VIEW_VEHICLES_TITLE), SetAlignment(SA_LEFT | SA_TOP),
2051 EndContainer(),
2052 EndContainer(),
2055 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_VIEW_HQ), SetStringTip(STR_COMPANY_VIEW_VIEW_HQ_BUTTON, STR_COMPANY_VIEW_VIEW_HQ_TOOLTIP),
2056 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_C_BUILD_HQ), SetStringTip(STR_COMPANY_VIEW_BUILD_HQ_BUTTON, STR_COMPANY_VIEW_BUILD_HQ_TOOLTIP),
2057 EndContainer(),
2059 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_C_RELOCATE_HQ), SetStringTip(STR_COMPANY_VIEW_RELOCATE_HQ, STR_COMPANY_VIEW_RELOCATE_HQ_TOOLTIP),
2061 EndContainer(),
2062 EndContainer(),
2063 EndContainer(),
2064
2065 NWidget(WWT_TEXT, INVALID_COLOUR, WID_C_DESC_COMPANY_VALUE), SetFill(1, 0),
2066
2068 NWidget(WWT_TEXT, INVALID_COLOUR, WID_C_DESC_INFRASTRUCTURE), SetStringTip(STR_COMPANY_VIEW_INFRASTRUCTURE), SetAlignment(SA_LEFT | SA_TOP),
2071 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_VIEW_INFRASTRUCTURE), SetStringTip(STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON, STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP),
2072 EndContainer(),
2073 EndContainer(),
2074
2075 /* Multi player buttons. */
2079 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_HOSTILE_TAKEOVER), SetStringTip(STR_COMPANY_VIEW_HOSTILE_TAKEOVER_BUTTON, STR_COMPANY_VIEW_HOSTILE_TAKEOVER_TOOLTIP),
2080 EndContainer(),
2082 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_GIVE_MONEY), SetStringTip(STR_COMPANY_VIEW_GIVE_MONEY_BUTTON, STR_COMPANY_VIEW_GIVE_MONEY_TOOLTIP),
2083 EndContainer(),
2085 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_COMPANY_JOIN), SetStringTip(STR_COMPANY_VIEW_JOIN, STR_COMPANY_VIEW_JOIN_TOOLTIP),
2086 EndContainer(),
2087 EndContainer(),
2088 EndContainer(),
2089 EndContainer(),
2090 EndContainer(),
2091 EndContainer(),
2092 /* Button bars at the bottom. */
2095 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),
2096 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),
2097 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),
2098 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),
2099 EndContainer(),
2100 EndContainer(),
2101};
2102
2105 STR_COMPANY_VIEW_TRAINS, STR_COMPANY_VIEW_ROAD_VEHICLES, STR_COMPANY_VIEW_SHIPS, STR_COMPANY_VIEW_AIRCRAFT
2106};
2107
2112{
2113 CompanyWidgets query_widget{};
2114
2116 enum CompanyWindowPlanes : uint8_t {
2117 /* Display planes of the #WID_C_SELECT_VIEW_BUILD_HQ selection widget. */
2120
2121 /* Display planes of the #WID_C_SELECT_RELOCATE selection widget. */
2124 };
2125
2127 {
2128 this->InitNested(window_number);
2129 this->owner = this->window_number;
2130 this->OnInvalidateData();
2131 }
2132
2133 void OnPaint() override
2134 {
2135 const Company *c = Company::Get(this->window_number);
2136 bool local = this->window_number == _local_company;
2137
2138 if (!this->IsShaded()) {
2139 bool reinit = false;
2140
2141 /* Button bar selection. */
2142 reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_BUTTONS)->SetDisplayedPlane(local ? 0 : SZSP_NONE);
2143
2144 /* Build HQ button handling. */
2145 reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_VIEW_BUILD_HQ)->SetDisplayedPlane((local && c->location_of_HQ == INVALID_TILE) ? CWP_VB_BUILD : CWP_VB_VIEW);
2146
2148
2149 /* Enable/disable 'Relocate HQ' button. */
2150 reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_RELOCATE)->SetDisplayedPlane((!local || c->location_of_HQ == INVALID_TILE) ? CWP_RELOCATE_HIDE : CWP_RELOCATE_SHOW);
2151 /* Enable/disable 'Give money' button. */
2152 reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_GIVE_MONEY)->SetDisplayedPlane((local || _local_company == COMPANY_SPECTATOR || !_settings_game.economy.give_money) ? SZSP_NONE : 0);
2153 /* Enable/disable 'Hostile Takeover' button. */
2154 reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_HOSTILE_TAKEOVER)->SetDisplayedPlane((local || _local_company == COMPANY_SPECTATOR || !c->is_ai || _networking) ? SZSP_NONE : 0);
2155
2156 /* Multiplayer buttons. */
2157 reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_MULTIPLAYER)->SetDisplayedPlane((!_networking || !NetworkCanJoinCompany(c->index) || _local_company == c->index) ? (int)SZSP_NONE : 0);
2158
2160
2161 if (reinit) {
2162 this->ReInit();
2163 return;
2164 }
2165 }
2166
2167 this->DrawWidgets();
2168 }
2169
2170 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2171 {
2172 switch (widget) {
2173 case WID_C_FACE:
2174 size = maxdim(size, GetScaledSpriteSize(SPR_GRADIENT));
2175 break;
2176
2178 Point offset;
2179 Dimension d = GetSpriteSize(SPR_VEH_BUS_SW_VIEW, &offset);
2180 d.width -= offset.x;
2181 d.height -= offset.y;
2182 size = maxdim(size, d);
2183 break;
2184 }
2185
2187 /* INT64_MAX is arguably the maximum company value */
2188 size.width = GetStringBoundingBox(GetString(STR_COMPANY_VIEW_COMPANY_VALUE, INT64_MAX)).width;
2189 break;
2190
2192 uint64_t max_value = GetParamMaxValue(5000); // Maximum number of vehicles
2193 for (const auto &count_string : _company_view_vehicle_count_strings) {
2194 size.width = std::max(size.width, GetStringBoundingBox(GetString(count_string, max_value)).width + padding.width);
2195 }
2196 break;
2197 }
2198
2200 uint64_t max_value = GetParamMaxValue(UINT_MAX);
2201 size.width = GetStringBoundingBox(GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL, max_value)).width;
2202 size.width = std::max(size.width, GetStringBoundingBox(GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD, max_value)).width);
2203 size.width = std::max(size.width, GetStringBoundingBox(GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_WATER, max_value)).width);
2204 size.width = std::max(size.width, GetStringBoundingBox(GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_STATION, max_value)).width);
2205 size.width = std::max(size.width, GetStringBoundingBox(GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT, max_value)).width);
2206 size.width = std::max(size.width, GetStringBoundingBox(GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_NONE, max_value)).width);
2207 size.width += padding.width;
2208 break;
2209 }
2210
2211 case WID_C_VIEW_HQ:
2212 case WID_C_BUILD_HQ:
2213 case WID_C_RELOCATE_HQ:
2215 case WID_C_GIVE_MONEY:
2217 case WID_C_COMPANY_JOIN:
2218 size.width = GetStringBoundingBox(STR_COMPANY_VIEW_VIEW_HQ_BUTTON).width;
2219 size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_BUILD_HQ_BUTTON).width);
2220 size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_RELOCATE_HQ).width);
2221 size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON).width);
2222 size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_GIVE_MONEY_BUTTON).width);
2223 size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_HOSTILE_TAKEOVER_BUTTON).width);
2224 size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_JOIN).width);
2225 size.width += padding.width;
2226 break;
2227 }
2228 }
2229
2230 void DrawVehicleCountsWidget(const Rect &r, const Company *c) const
2231 {
2233
2234 int y = r.top;
2235 for (VehicleType type = VEH_BEGIN; type < VEH_COMPANY_END; type++) {
2236 uint amount = c->group_all[type].num_vehicle;
2237 if (amount != 0) {
2238 DrawString(r.left, r.right, y, GetString(_company_view_vehicle_count_strings[type], amount));
2240 }
2241 }
2242
2243 if (y == r.top) {
2244 /* No String was emitted before, so there must be no vehicles at all. */
2245 DrawString(r.left, r.right, y, STR_COMPANY_VIEW_VEHICLES_NONE);
2246 }
2247 }
2248
2249 void DrawInfrastructureCountsWidget(const Rect &r, const Company *c) const
2250 {
2251 int y = r.top;
2252
2253 uint rail_pieces = c->infrastructure.signal + c->infrastructure.GetRailTotal();
2254 if (rail_pieces != 0) {
2255 DrawString(r.left, r.right, y, GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL, rail_pieces));
2257 }
2258
2259 /* GetRoadTotal() skips tram pieces, but we actually want road and tram here. */
2260 uint road_pieces = std::accumulate(std::begin(c->infrastructure.road), std::end(c->infrastructure.road), 0U);
2261 if (road_pieces != 0) {
2262 DrawString(r.left, r.right, y, GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD, road_pieces));
2264 }
2265
2266 if (c->infrastructure.water != 0) {
2267 DrawString(r.left, r.right, y, GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_WATER, c->infrastructure.water));
2269 }
2270
2271 if (c->infrastructure.station != 0) {
2272 DrawString(r.left, r.right, y, GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_STATION, c->infrastructure.station));
2274 }
2275
2276 if (c->infrastructure.airport != 0) {
2277 DrawString(r.left, r.right, y, GetString(STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT, c->infrastructure.airport));
2279 }
2280
2281 if (y == r.top) {
2282 /* No String was emitted before, so there must be no infrastructure at all. */
2283 DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE);
2284 }
2285 }
2286
2287 void DrawWidget(const Rect &r, WidgetID widget) const override
2288 {
2289 const Company *c = Company::Get(this->window_number);
2290 switch (widget) {
2291 case WID_C_FACE:
2293 break;
2294
2295 case WID_C_FACE_TITLE:
2296 DrawStringMultiLine(r, GetString(STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE, c->index), TC_FROMSTRING, SA_HOR_CENTER);
2297 break;
2298
2300 Point offset;
2301 Dimension d = GetSpriteSize(SPR_VEH_BUS_SW_VIEW, &offset);
2302 d.height -= offset.y;
2303 DrawSprite(SPR_VEH_BUS_SW_VIEW, GetCompanyPalette(c->index), r.left - offset.x, CentreBounds(r.top, r.bottom, d.height) - offset.y);
2304 break;
2305 }
2306
2308 DrawVehicleCountsWidget(r, c);
2309 break;
2310
2312 DrawInfrastructureCountsWidget(r, c);
2313 break;
2314 }
2315 }
2316
2317 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
2318 {
2319 switch (widget) {
2320 case WID_C_CAPTION:
2321 return GetString(STR_COMPANY_VIEW_CAPTION, this->window_number, this->window_number);
2322
2324 const Company &c = *Company::Get(this->window_number);
2326 return GetString(STR_COMPANY_VIEW_INAUGURATED_TITLE_WALLCLOCK, c.inaugurated_year_calendar, c.inaugurated_year);
2327 }
2328 return GetString(STR_COMPANY_VIEW_INAUGURATED_TITLE, c.inaugurated_year);
2329 }
2330
2332 return GetString(STR_COMPANY_VIEW_COMPANY_VALUE, CalculateCompanyValue(Company::Get(this->window_number)));
2333
2334 default:
2335 return this->Window::GetWidgetString(widget, stringid);
2336 }
2337 }
2338
2339 void OnResize() override
2340 {
2341 NWidgetResizeBase *wid = this->GetWidget<NWidgetResizeBase>(WID_C_FACE_TITLE);
2342 int y = GetStringHeight(GetString(STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE, this->owner), wid->current_x);
2343 if (wid->UpdateVerticalSize(y)) this->ReInit(0, 0);
2344 }
2345
2346 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2347 {
2348 switch (widget) {
2349 case WID_C_NEW_FACE: DoSelectCompanyManagerFace(this); break;
2350
2352 ShowCompanyLiveryWindow(this->window_number, GroupID::Invalid());
2353 break;
2354
2356 this->query_widget = WID_C_PRESIDENT_NAME;
2357 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});
2358 break;
2359
2360 case WID_C_COMPANY_NAME:
2361 this->query_widget = WID_C_COMPANY_NAME;
2362 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});
2363 break;
2364
2365 case WID_C_VIEW_HQ: {
2366 TileIndex tile = Company::Get(this->window_number)->location_of_HQ;
2367 if (_ctrl_pressed) {
2369 } else {
2371 }
2372 break;
2373 }
2374
2375 case WID_C_BUILD_HQ:
2376 if (this->window_number != _local_company) return;
2377 if (this->IsWidgetLowered(WID_C_BUILD_HQ)) {
2379 this->RaiseButtons();
2380 break;
2381 }
2382 SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, HT_RECT, this);
2383 SetTileSelectSize(2, 2);
2386 break;
2387
2388 case WID_C_RELOCATE_HQ:
2391 this->RaiseButtons();
2392 break;
2393 }
2394 SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, HT_RECT, this);
2395 SetTileSelectSize(2, 2);
2398 break;
2399
2402 break;
2403
2404 case WID_C_GIVE_MONEY:
2405 this->query_widget = WID_C_GIVE_MONEY;
2406 ShowQueryString({}, STR_COMPANY_VIEW_GIVE_MONEY_QUERY_CAPTION, 30, this, CS_NUMERAL, {});
2407 break;
2408
2411 break;
2412
2413 case WID_C_COMPANY_JOIN: {
2414 this->query_widget = WID_C_COMPANY_JOIN;
2415 CompanyID company = this->window_number;
2416 if (_network_server) {
2419 } else {
2420 /* just send the join command */
2421 NetworkClientRequestMove(company);
2422 }
2423 break;
2424 }
2425 }
2426 }
2427
2429 const IntervalTimer<TimerWindow> redraw_interval = {std::chrono::seconds(3), [this](auto) {
2430 this->SetDirty();
2431 }};
2432
2433 void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
2434 {
2435 if (Command<CMD_BUILD_OBJECT>::Post(STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS, tile, OBJECT_HQ, 0) && !_shift_pressed) {
2437 this->RaiseButtons();
2438 }
2439 }
2440
2441 void OnPlaceObjectAbort() override
2442 {
2443 this->RaiseButtons();
2444 }
2445
2446 void OnQueryTextFinished(std::optional<std::string> str) override
2447 {
2448 if (!str.has_value()) return;
2449
2450 switch (this->query_widget) {
2451 default: NOT_REACHED();
2452
2453 case WID_C_GIVE_MONEY: {
2454 auto value = ParseInteger<uint64_t>(*str, 10, true);
2455 if (!value.has_value()) return;
2456 Money money = *value / GetCurrency().rate;
2457 Command<CMD_GIVE_MONEY>::Post(STR_ERROR_CAN_T_GIVE_MONEY, money, this->window_number);
2458 break;
2459 }
2460
2462 Command<CMD_RENAME_PRESIDENT>::Post(STR_ERROR_CAN_T_CHANGE_PRESIDENT, *str);
2463 break;
2464
2465 case WID_C_COMPANY_NAME:
2466 Command<CMD_RENAME_COMPANY>::Post(STR_ERROR_CAN_T_CHANGE_COMPANY_NAME, *str);
2467 break;
2468 }
2469 }
2470
2471 void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
2472 {
2473 if (gui_scope && data == 1) {
2474 /* Manually call OnResize to adjust minimum height of president name widget. */
2475 OnResize();
2476 }
2477 }
2478};
2479
2480static WindowDesc _company_desc(
2481 WDP_AUTO, "company", 0, 0,
2483 {},
2484 _nested_company_widgets
2485);
2486
2492{
2493 if (!Company::IsValidID(company)) return;
2494
2495 AllocateWindowDescFront<CompanyWindow>(_company_desc, company);
2496}
2497
2507
2510 {
2511 this->InitNested(window_number);
2512
2513 const Company *c = Company::Get(this->window_number);
2514 this->company_value = hostile_takeover ? CalculateHostileTakeoverValue(c) : c->bankrupt_value;
2515 }
2516
2517 void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2518 {
2519 switch (widget) {
2520 case WID_BC_FACE:
2521 size = GetScaledSpriteSize(SPR_GRADIENT);
2522 break;
2523
2524 case WID_BC_QUESTION:
2525 const Company *c = Company::Get(this->window_number);
2526 size.height = GetStringHeight(GetString(this->hostile_takeover ? STR_BUY_COMPANY_HOSTILE_TAKEOVER : STR_BUY_COMPANY_MESSAGE, c->index, this->company_value), size.width);
2527 break;
2528 }
2529 }
2530
2531 std::string GetWidgetString(WidgetID widget, StringID stringid) const override
2532 {
2533 switch (widget) {
2534 case WID_BC_CAPTION:
2535 return GetString(STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY, Company::Get(this->window_number)->index);
2536
2537 default:
2538 return this->Window::GetWidgetString(widget, stringid);
2539 }
2540 }
2541
2542 void DrawWidget(const Rect &r, WidgetID widget) const override
2543 {
2544 switch (widget) {
2545 case WID_BC_FACE: {
2546 const Company *c = Company::Get(this->window_number);
2548 break;
2549 }
2550
2551 case WID_BC_QUESTION: {
2552 const Company *c = Company::Get(this->window_number);
2553 DrawStringMultiLine(r, GetString(this->hostile_takeover ? STR_BUY_COMPANY_HOSTILE_TAKEOVER : STR_BUY_COMPANY_MESSAGE, c->index, this->company_value), TC_FROMSTRING, SA_CENTER);
2554 break;
2555 }
2556 }
2557 }
2558
2559 void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2560 {
2561 switch (widget) {
2562 case WID_BC_NO:
2563 this->Close();
2564 break;
2565
2566 case WID_BC_YES:
2567 Command<CMD_BUY_COMPANY>::Post(STR_ERROR_CAN_T_BUY_COMPANY, this->window_number, this->hostile_takeover);
2568 break;
2569 }
2570 }
2571
2575 const IntervalTimer<TimerWindow> rescale_interval = {std::chrono::seconds(3), [this](auto) {
2576 /* Value can't change when in bankruptcy. */
2577 if (!this->hostile_takeover) return;
2578
2579 const Company *c = Company::Get(this->window_number);
2580 auto new_value = CalculateHostileTakeoverValue(c);
2581 if (new_value != this->company_value) {
2582 this->company_value = new_value;
2583 this->ReInit();
2584 }
2585 }};
2586
2587private:
2588 bool hostile_takeover = false;
2590};
2591
2592static constexpr NWidgetPart _nested_buy_company_widgets[] = {
2594 NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
2595 NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE, WID_BC_CAPTION),
2596 EndContainer(),
2597 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE),
2600 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_BC_FACE), SetFill(0, 1),
2601 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_BC_QUESTION), SetMinimalSize(240, 0), SetFill(1, 1),
2602 EndContainer(),
2604 NWidget(WWT_TEXTBTN, COLOUR_LIGHT_BLUE, WID_BC_NO), SetMinimalSize(60, 12), SetStringTip(STR_QUIT_NO), SetFill(1, 0),
2605 NWidget(WWT_TEXTBTN, COLOUR_LIGHT_BLUE, WID_BC_YES), SetMinimalSize(60, 12), SetStringTip(STR_QUIT_YES), SetFill(1, 0),
2606 EndContainer(),
2607 EndContainer(),
2608 EndContainer(),
2609};
2610
2611static WindowDesc _buy_company_desc(
2612 WDP_AUTO, {}, 0, 0,
2615 _nested_buy_company_widgets
2616);
2617
2623void ShowBuyCompanyDialog(CompanyID company, bool hostile_takeover)
2624{
2625 auto window = BringWindowToFrontById(WC_BUY_COMPANY, company);
2626 if (window == nullptr) {
2627 new BuyCompanyWindow(_buy_company_desc, company, hostile_takeover);
2628 }
2629}
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
debug_inline static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
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.
Drop down icon component.
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.
bool IsDisabled() const
Return whether the widget is disabled.
void SetStringTip(StringID string, StringID tool_tip)
Set string and tool tip of the nested widget.
Definition widget.cpp:1171
Base class for a resizable nested widget.
bool UpdateVerticalSize(uint min_y)
Set absolute (post-scaling) minimal size of the widget.
Definition widget.cpp:1127
StringID name
Name of this rail type.
Definition rail.h:167
StringID name
Name of this rail type.
Definition road.h:94
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:2482
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:2556
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.
std::string GetFaceString(WidgetID widget_index, uint8_t val, bool is_bool_widget) const
Get the string for the value of face control buttons.
void SelectDisplayPlanes(bool advanced)
Select planes to display to the user with the NWID_SELECTION widgets WID_SCMF_SEL_LOADSAVE,...
std::string GetWidgetString(WidgetID widget, StringID stringid) const override
Get the raw string for a 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.
bool advanced
advanced company manager face selection window
bool is_moust_male
Male face with a moustache.
GenderEthnicity ge
Gender and ethnicity.
Dimension yesno_dim
Dimension of a yes/no button of a part in the advanced face window.
void DrawWidget(const Rect &r, WidgetID widget) const override
Draw the contents of a nested widget.
CompanyManagerFace face
company manager face bits
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 OnInit() override
Notification that the nested widget tree gets initialized.
void OnPaint() override
The window must be repainted.
Dimension number_dim
Dimension of a number widget of a part in the advanced face window.
static Year year
Current year, starting at 0.
static bool UsingWallclockUnits(bool newgame=false)
Check if we are using wallclock units.
RectPadding framerect
Standard padding inside many panels.
Definition window_gui.h:40
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition window_gui.h:30
RectPadding imgbtn
Padding around image button image.
Definition window_gui.h:34
int vsep_normal
Normal vertical spacing.
Definition window_gui.h:58
int vsep_wide
Wide vertical spacing.
Definition window_gui.h:60
int hsep_wide
Wide horizontal spacing.
Definition window_gui.h:62
RectPadding fullbevel
Always-scaled bevel thickness.
Definition window_gui.h:39
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition window_gui.h:93
int hsep_normal
Normal horizontal spacing.
Definition window_gui.h:61
RectPadding bevel
Bevel thickness, affected by "scaled bevels" game option.
Definition window_gui.h:38
int hsep_indent
Width of indentation for tree layouts.
Definition window_gui.h:63
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
PaletteID GetCompanyPalette(CompanyID company)
Get the palette for recolouring with a company colour.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
CompanyManagerFace _company_manager_face
for company manager face storage in openttd.cfg
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 constexpr 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_operating_costs
List of operating expenses.
static uint GetTotalCategoriesHeight()
Get the total height of the "categories" column.
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(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.
uint GetCompanyManagerFaceBits(CompanyManagerFace cmf, CompanyManagerFaceVariable cmfv, GenderEthnicity ge)
Make sure the table's size is right.
void SetCompanyManagerFaceBits(CompanyManagerFace &cmf, CompanyManagerFaceVariable cmfv, GenderEthnicity ge, uint val)
Sets the company manager's face bits for the given company manager's face variable.
GenderEthnicity
The gender/race combinations that we have faces for.
@ GE_WM
A male of Caucasian origin (white)
@ ETHNICITY_BLACK
This bit set means black, otherwise white.
@ GENDER_FEMALE
This bit set means a female, otherwise male.
void RandomCompanyManagerFaceBits(CompanyManagerFace &cmf, GenderEthnicity ge, bool adv, Randomizer &randomizer)
Make a random new face.
void ScaleAllCompanyManagerFaceBits(CompanyManagerFace &cmf)
Scales all company manager's face bits to the correct scope.
CompanyManagerFaceVariable
Bitgroups of the CompanyManagerFace variable.
static const CompanyManagerFaceBitsInfo _cmf_info[]
Lookup table for indices into the CompanyManagerFace, valid ranges and sprites.
void IncreaseCompanyManagerFaceBits(CompanyManagerFace &cmf, CompanyManagerFaceVariable cmfv, GenderEthnicity ge, int8_t amount)
Increase/Decrease the company manager's face variable by the given amount.
SpriteID GetCompanyManagerFaceSprite(CompanyManagerFace cmf, CompanyManagerFaceVariable cmfv, GenderEthnicity ge)
Gets the sprite to draw for the given company manager's face variable.
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.
uint32_t CompanyManagerFace
Company manager face bits, info see in company_manager_face.h.
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_NOSE_L
Nose left.
@ WID_SCMF_COLLAR_TEXT
Text about collar.
@ WID_SCMF_HAIR
Hair.
@ WID_SCMF_EYECOLOUR_L
Eyecolour left.
@ WID_SCMF_CAPTION
Caption of window.
@ WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON
Toggle for large or small.
@ WID_SCMF_ETHNICITY_EUR
Text about ethnicity european.
@ WID_SCMF_CHIN_R
Chin right.
@ WID_SCMF_EYEBROWS
Eyebrows.
@ WID_SCMF_COLLAR
Collar.
@ WID_SCMF_GLASSES_R
Glasses right.
@ WID_SCMF_JACKET_L
Jacket left.
@ WID_SCMF_CHIN
Chin.
@ WID_SCMF_LIPS_MOUSTACHE_TEXT
Text about lips and moustache.
@ WID_SCMF_SELECT_FACE
Select face.
@ WID_SCMF_LIPS_MOUSTACHE
Lips / Moustache.
@ WID_SCMF_RANDOM_NEW_FACE
Create random new face.
@ WID_SCMF_GLASSES_TEXT
Text about glasses.
@ WID_SCMF_EYEBROWS_L
Eyebrows left.
@ WID_SCMF_GLASSES
Glasses.
@ WID_SCMF_LIPS_MOUSTACHE_L
Lips / Moustache left.
@ WID_SCMF_EYEBROWS_R
Eyebrows right.
@ WID_SCMF_SEL_PARTS
Selection to display the buttons for setting each part of the face in the advanced view.
@ WID_SCMF_CHIN_L
Chin left.
@ WID_SCMF_GLASSES_L
Glasses left.
@ WID_SCMF_FEMALE2
Female button in the advanced view.
@ WID_SCMF_NOSE
Nose.
@ WID_SCMF_TIE_EARRING_R
Tie / Earring right.
@ WID_SCMF_CANCEL
Cancel.
@ WID_SCMF_HAIR_TEXT
Text about hair.
@ WID_SCMF_EYECOLOUR_R
Eyecolour right.
@ WID_SCMF_NOSE_R
Nose right.
@ WID_SCMF_CHIN_TEXT
Text about chin.
@ WID_SCMF_TIE_EARRING
Tie / Earring.
@ WID_SCMF_SAVE
Save face.
@ WID_SCMF_NOSE_TEXT
Text about nose.
@ WID_SCMF_MALE
Male button in the simple view.
@ WID_SCMF_SEL_LOADSAVE
Selection to display the load/save/number buttons in the advanced view.
@ WID_SCMF_ETHNICITY_AFR
Text about ethnicity african.
@ WID_SCMF_FACE
Current face.
@ WID_SCMF_JACKET_R
Jacket right.
@ WID_SCMF_TIE_EARRING_L
Tie / Earring left.
@ WID_SCMF_LOAD
Load face.
@ WID_SCMF_ACCEPT
Accept.
@ WID_SCMF_MALE2
Male button in the advanced view.
@ WID_SCMF_EYECOLOUR_TEXT
Text about eyecolour.
@ WID_SCMF_COLLAR_L
Collar left.
@ WID_SCMF_HAS_GLASSES_TEXT
Text about glasses.
@ WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT
Text about moustache and earring.
@ WID_SCMF_JACKET
Jacket.
@ WID_SCMF_SEL_MALEFEMALE
Selection to display the male/female buttons in the simple view.
@ WID_SCMF_JACKET_TEXT
Text about jacket.
@ WID_SCMF_TOGGLE_LARGE_SMALL
Toggle for large or small.
@ WID_SCMF_FACECODE
Get the face code.
@ WID_SCMF_EYECOLOUR
Eyecolour.
@ WID_SCMF_EYEBROWS_TEXT
Text about eyebrows.
@ WID_SCMF_HAIR_L
Hair left.
@ WID_SCMF_LIPS_MOUSTACHE_R
Lips / Moustache right.
@ WID_SCMF_TIE_EARRING_TEXT
Text about tie and earring.
@ WID_SCMF_FEMALE
Female button in the simple view.
@ WID_SCMF_HAS_GLASSES
Has glasses.
@ WID_SCMF_COLLAR_R
Collar right.
@ WID_SCMF_HAS_MOUSTACHE_EARRING
Has moustache or earring.
@ WID_SCMF_HAIR_R
Hair right.
@ WID_SCL_CLASS_AIRCRAFT
Class aircraft.
@ WID_SCL_MATRIX_SCROLLBAR
Matrix scrollbar.
@ WID_SCL_CLASS_SHIP
Class ship.
@ 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:118
void ShowDropDownList(Window *w, DropDownList &&list, int selected, WidgetID button, uint width, bool instant_close, bool persist)
Show a drop down list.
Definition dropdown.cpp:414
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:77
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:705
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition gfx.cpp:958
bool _shift_pressed
Is Shift pressed?
Definition gfx.cpp:39
Dimension GetStringBoundingBox(std::string_view str, FontSize start_fontsize)
Return the string dimension in pixels.
Definition gfx.cpp:887
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:658
bool _ctrl_pressed
Is Ctrl pressed?
Definition gfx.cpp:38
uint GetStringListWidth(std::span< const StringID > list, FontSize fontsize)
Get maximum width of a list of strings.
Definition gfx.cpp:910
void GfxFillRect(int left, int top, int right, int bottom, int colour, FillRectMode mode)
Applies a certain FillRectMode-operation to a rectangle [left, right] x [top, bottom] on the screen.
Definition gfx.cpp:115
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:1024
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:775
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:251
@ SA_TOP
Top align the text.
Definition gfx_type.h:388
@ SA_LEFT
Left align the text.
Definition gfx_type.h:383
@ SA_RIGHT
Right align the text (must be a single bit).
Definition gfx_type.h:385
@ SA_HOR_CENTER
Horizontally center the text.
Definition gfx_type.h:384
@ SA_FORCE
Force the alignment, i.e. don't swap for RTL languages.
Definition gfx_type.h:395
@ SA_CENTER
Center both horizontally and vertically.
Definition gfx_type.h:393
@ SA_VERT_CENTER
Vertically center the text.
Definition gfx_type.h:389
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:302
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 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 SetTextStyle(TextColour colour, FontSize size=FS_NORMAL)
Widget part function for setting the text style.
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=-1)
Widget part function for starting a new 'real' widget.
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 SetArrowWidgetTypeTip(ArrowWidgetValues widget_type, StringID tip={})
Widget part function for setting the arrow widget type and tooltip.
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:955
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition gfx.cpp:1535
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:18
LiveryScheme
List of different livery schemes.
Definition livery.h:21
static const uint8_t LIT_COMPANY
Show the liveries of your own company.
Definition livery.h:17
LiveryClass
List of different livery classes, used only by the livery GUI.
Definition livery.h:63
Miscellaneous command definitions.
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.
bool _networking
are we in networking mode?
Definition network.cpp:67
bool _network_server
network-server is active
Definition network.cpp:68
bool NetworkCanJoinCompany(CompanyID company_id)
Returns whether the given company can be joined by this client.
Definition network.cpp:143
Basic functions/variables used all over the place.
void NetworkClientRequestMove(CompanyID company_id)
Notify the server of this client wanting to be moved to another company.
Network functions used by other parts of OpenTTD.
void NetworkServerDoMove(ClientID client_id, CompanyID company_id)
Handle the tid-bits of moving a client from one company to another.
GUIs related to networking.
@ CLIENT_ID_SERVER
Servers always have this ID.
GRFLoadedFeatures _loaded_newgrf_features
Indicates which are the newgrf features currently loaded ingame.
Definition newgrf.cpp:73
Base for the NewGRF implementation.
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 const uint8_t PC_WHITE
White palette colour.
static const uint8_t PC_BLACK
Black 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:436
Money SignalMaintenanceCost(uint32_t num)
Calculates the maintenance cost of a number of signals.
Definition rail.h:447
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:230
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
Base types for having sorted lists in GUIs.
static PaletteID GetColourPalette(Colours colour)
Get recolour palette for a colour.
Definition sprite.h:184
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:237
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:91
std::string GetString(StringID string)
Resolve the given StringID into a std::string with formatting but no parameters.
Definition strings.cpp:415
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition strings.cpp:57
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.
GUISettings gui
settings related to the GUI
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.
Window with detailed information about the company's infrastructure.
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 GetRoadTotal() const
Get total sum of all owned road 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 GetTramTotal() const
Get total sum of all owned tram bits.
uint32_t airport
Count of company owned airports.
uint32_t water
Count of company owned track bits for canals.
uint8_t valid_values[GE_END]
The number of valid values per gender/ethnicity.
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.
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.
uint16_t rate
The conversion rate compared to the base currency.
Definition currency.h:77
uint8_t initial_interest
amount of interest (to pay over the loan)
Dimensions (a width and height) of a rectangle in 2D.
bool infrastructure_maintenance
enable monthly maintenance fee for owner infrastructure
bool give_money
allow giving other companies money
Expense list container.
uint GetListWidth() const
Compute width of the expenses categories in pixels.
const std::initializer_list< ExpensesType > & items
List of expenses types.
const StringID title
StringID of list title.
bool has_2CC
Set if any vehicle is loaded which uses 2cc (two company colours).
Definition newgrf.h:189
uint64_t used_liveries
Bitmask of LiveryScheme used by the defined engines.
Definition newgrf.h:190
uint8_t liveries
options for displaying company liveries, 0=none, 1=self, 2=all
EconomySettings economy
settings to change the economy
DifficultySettings difficulty
settings related to the difficulty
Group data.
Definition group.h:73
Livery livery
Custom colour scheme for vehicles in this group.
Definition group.h:79
GroupID parent
Parent group.
Definition group.h:85
VehicleType vehicle_type
Vehicle type of the group.
Definition group.h:76
Information about a particular livery.
Definition livery.h:78
Colours colour2
Second colour, for vehicles with 2CC support.
Definition livery.h:81
Colours colour1
First colour, for all vehicles.
Definition livery.h:80
uint8_t in_use
Bit 0 set if this livery should override the default livery first colour, Bit 1 for the second colour...
Definition livery.h:79
Partial widget specification to allow NWidgets to be written nested.
Coordinates of a point in 2D.
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static Titem * Get(auto index)
Returns Titem with given index.
Tindex index
Index of this pool item.
static bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
static Titem * GetIfValid(auto index)
Returns Titem with given index.
constexpr uint Horizontal() const
Get total horizontal padding of RectPadding.
constexpr uint Vertical() const
Get total vertical padding of RectPadding.
Specification of a rectangle with absolute coordinates of all edges.
Rect WithWidth(int width, bool end) const
Copy Rect and set its width.
Rect Shrink(int s) const
Copy and shrink Rect by s pixels.
Rect WithHeight(int height, bool end=false) const
Copy Rect and set its height.
Rect Indent(int indent, bool end) const
Copy Rect and indent it from its position.
int Height() const
Get height of Rect.
Rect Translate(int x, int y) const
Copy and translate Rect by x,y pixels.
uint step_height
Step-size of height resize changes.
Definition window_gui.h:212
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.
Templated helper to make a type-safe 'typedef' representing a single POD value.
High level window description.
Definition window_gui.h:167
Number to differentiate different windows of the same class.
Data structure for an opened window.
Definition window_gui.h:273
void ReInit(int rx=0, int ry=0, bool reposition=false)
Re-initialize a window, and optionally change its size.
Definition window.cpp:967
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
Definition window.cpp:1091
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition window.cpp:1778
void DrawWidgets() const
Paint all widgets of a window.
Definition widget.cpp:777
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing)
Definition window.cpp:3205
Window * parent
Parent window.
Definition window_gui.h:328
void RaiseWidget(WidgetID widget_index)
Marks a widget as raised.
Definition window_gui.h:469
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition window.cpp:555
virtual std::string GetWidgetString(WidgetID widget, StringID stringid) const
Get the raw string for a widget.
Definition window.cpp:503
ResizeInfo resize
Resize information.
Definition window_gui.h:314
void SetShaded(bool make_shaded)
Set the shaded state of the window to make_shaded.
Definition window.cpp:1010
void SetWidgetsDisabledState(bool disab_stat, Args... widgets)
Sets the enabled/disabled status of a list of widgets.
Definition window_gui.h:515
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition window.cpp:1768
bool IsWidgetLowered(WidgetID widget_index) const
Gets the lowered state of a widget.
Definition window_gui.h:491
void RaiseButtons(bool autoraise=false)
Raise the buttons of the window.
Definition window.cpp:529
void SetWidgetsLoweredState(bool lowered_stat, Args... widgets)
Sets the lowered/raised status of a list of widgets.
Definition window_gui.h:526
Owner owner
The owner of the content shown in this window. Company colour is acquired from this variable.
Definition window_gui.h:316
void SetWidgetLoweredState(WidgetID widget_index, bool lowered_stat)
Sets the lowered/raised status of a widget.
Definition window_gui.h:441
void EnableWidget(WidgetID widget_index)
Sets a widget to Enabled.
Definition window_gui.h:400
virtual void FindWindowPlacementAndResize(int def_width, int def_height, bool allow_resize)
Resize window towards the default size.
Definition window.cpp:1463
bool IsShaded() const
Is window shaded currently?
Definition window_gui.h:559
void LowerWidget(WidgetID widget_index)
Marks a widget as lowered.
Definition window_gui.h:460
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition window.cpp:1791
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition window.cpp:312
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition window_gui.h:381
int height
Height of the window (number of pixels down in y direction)
Definition window_gui.h:312
int width
width of the window (number of pixels to the right in x direction)
Definition window_gui.h:311
WindowNumber window_number
Window number within the window class.
Definition window_gui.h:302
Stuff related to the text buffer GUI.
@ EnableDefault
enable the 'Default' button ("\0" is returned)
@ LengthIsInChars
the length of the string is counted in characters
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:95
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:51
@ WWT_PUSHTXTBTN
Normal push-button (no toggle button) with text caption.
@ WWT_IMGBTN
(Toggle) Button with image
Definition widget_type.h:42
@ WWT_PUSHARROWBTN
Normal push-button (no toggle button) with arrow caption.
@ WWT_LABEL
Centered label.
Definition widget_type.h:49
@ NWID_SPACER
Invisible widget that takes some space.
Definition widget_type.h:71
@ NWID_HORIZONTAL
Horizontal container.
Definition widget_type.h:67
@ WWT_TEXTBTN
(Toggle) Button with text
Definition widget_type.h:45
@ WWT_PANEL
Simple depressed panel.
Definition widget_type.h:40
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition widget_type.h:58
@ WWT_MATRIX
Grid of rows and columns.
Definition widget_type.h:51
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition widget_type.h:56
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition widget_type.h:53
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition widget_type.h:77
@ NWID_VERTICAL
Vertical container.
Definition widget_type.h:69
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition widget_type.h:61
@ WWT_EMPTY
Empty widget, place holder to reserve space in widget tree.
Definition widget_type.h:38
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition widget_type.h:60
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition widget_type.h:57
@ WWT_DROPDOWN
Drop down list.
Definition widget_type.h:62
@ WWT_TEXT
Pure simple text.
Definition widget_type.h:50
@ NWID_SELECTION
Stacked widgets, only one visible at a time (eg in a panel with tabs).
Definition widget_type.h:72
@ SZSP_NONE
Display plane with zero size in both directions (none filling and resizing).
@ EqualSize
Containers should keep all their (resizing) children equally large.
@ AWV_DECREASE
Arrow to the left or in case of RTL to the right.
Definition widget_type.h:21
@ AWV_INCREASE
Arrow to the right or in case of RTL to the left.
Definition widget_type.h:22
Window * BringWindowToFrontById(WindowClass cls, WindowNumber number)
Find a window and make it the relative top-window on the screen.
Definition window.cpp:1265
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition window.cpp:3147
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.
@ 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:47
@ 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.