OpenTTD Source  20241108-master-g80f628063a
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"
21 #include "network/network_func.h"
22 #include "newgrf.h"
23 #include "company_manager_face.h"
24 #include "strings_func.h"
26 #include "dropdown_type.h"
27 #include "dropdown_common_type.h"
28 #include "tilehighlight_func.h"
29 #include "company_base.h"
30 #include "core/geometry_func.hpp"
31 #include "object_type.h"
32 #include "rail.h"
33 #include "road.h"
34 #include "engine_base.h"
35 #include "window_func.h"
36 #include "road_func.h"
37 #include "water.h"
38 #include "station_func.h"
39 #include "zoom_func.h"
40 #include "sortlist_type.h"
41 #include "company_cmd.h"
42 #include "economy_cmd.h"
43 #include "group_cmd.h"
44 #include "group_gui.h"
45 #include "misc_cmd.h"
46 #include "object_cmd.h"
47 #include "timer/timer.h"
48 #include "timer/timer_window.h"
49 
50 #include "widgets/company_widget.h"
51 
52 #include "safeguards.h"
53 
54 
56 static void DoSelectCompanyManagerFace(Window *parent);
57 static void ShowCompanyInfrastructure(CompanyID company);
58 
60 static const std::initializer_list<ExpensesType> _expenses_list_revenue = {
65 };
66 
68 static const std::initializer_list<ExpensesType> _expenses_list_operating_costs = {
75 };
76 
78 static const std::initializer_list<ExpensesType> _expenses_list_capital_costs = {
82 };
83 
85 struct ExpensesList {
86  const StringID title;
87  const std::initializer_list<ExpensesType> &items;
88 
89  ExpensesList(StringID title, const std::initializer_list<ExpensesType> &list) : title(title), items(list)
90  {
91  }
92 
93  uint GetHeight() const
94  {
95  /* Add up the height of all the lines. */
96  return static_cast<uint>(this->items.size()) * GetCharacterHeight(FS_NORMAL);
97  }
98 
100  uint GetListWidth() const
101  {
102  uint width = 0;
103  for (const ExpensesType &et : this->items) {
104  width = std::max(width, GetStringBoundingBox(STR_FINANCES_SECTION_CONSTRUCTION + et).width);
105  }
106  return width;
107  }
108 };
109 
111 static const std::initializer_list<ExpensesList> _expenses_list_types = {
112  { STR_FINANCES_REVENUE_TITLE, _expenses_list_revenue },
113  { STR_FINANCES_OPERATING_EXPENSES_TITLE, _expenses_list_operating_costs },
114  { STR_FINANCES_CAPITAL_EXPENSES_TITLE, _expenses_list_capital_costs },
115 };
116 
122 {
123  /* There's an empty line and blockspace on the year row */
125 
126  for (const ExpensesList &list : _expenses_list_types) {
127  /* Title + expense list + total line + total + blockspace after category */
129  }
130 
131  /* Total income */
133 
134  return total_height;
135 }
136 
142 {
143  uint max_width = GetStringBoundingBox(TimerGameEconomy::UsingWallclockUnits() ? STR_FINANCES_PERIOD_CAPTION : STR_FINANCES_YEAR_CAPTION).width;
144 
145  /* Loop through categories to check max widths. */
146  for (const ExpensesList &list : _expenses_list_types) {
147  /* Title of category */
148  max_width = std::max(max_width, GetStringBoundingBox(list.title).width);
149  /* Entries in category */
150  max_width = std::max(max_width, list.GetListWidth() + WidgetDimensions::scaled.hsep_indent);
151  }
152 
153  return max_width;
154 }
155 
159 static void DrawCategory(const Rect &r, int start_y, const ExpensesList &list)
160 {
162 
163  tr.top = start_y;
164 
165  for (const ExpensesType &et : list.items) {
166  DrawString(tr, STR_FINANCES_SECTION_CONSTRUCTION + et);
167  tr.top += GetCharacterHeight(FS_NORMAL);
168  }
169 }
170 
176 static void DrawCategories(const Rect &r)
177 {
178  int y = r.top;
179  /* Draw description of 12-minute economic period. */
180  DrawString(r.left, r.right, y, (TimerGameEconomy::UsingWallclockUnits() ? STR_FINANCES_PERIOD_CAPTION : STR_FINANCES_YEAR_CAPTION), TC_FROMSTRING, SA_LEFT, true);
182 
183  for (const ExpensesList &list : _expenses_list_types) {
184  /* Draw category title and advance y */
185  DrawString(r.left, r.right, y, list.title, TC_FROMSTRING, SA_LEFT);
187 
188  /* Draw category items and advance y */
189  DrawCategory(r, y, list);
190  y += list.GetHeight();
191 
192  /* Advance y by the height of the horizontal line between amounts and subtotal */
194 
195  /* Draw category total and advance y */
196  DrawString(r.left, r.right, y, STR_FINANCES_TOTAL_CAPTION, TC_FROMSTRING, SA_RIGHT);
198 
199  /* Advance y by a blockspace after this category block */
201  }
202 
203  /* Draw total profit/loss */
205  DrawString(r.left, r.right, y, STR_FINANCES_PROFIT, TC_FROMSTRING, SA_LEFT);
206 }
207 
216 static void DrawPrice(Money amount, int left, int right, int top, TextColour colour)
217 {
218  StringID str = STR_FINANCES_NEGATIVE_INCOME;
219  if (amount == 0) {
220  str = STR_FINANCES_ZERO_INCOME;
221  } else if (amount < 0) {
222  amount = -amount;
223  str = STR_FINANCES_POSITIVE_INCOME;
224  }
225  SetDParam(0, amount);
226  DrawString(left, right, top, str, colour, SA_RIGHT);
227 }
228 
233 static Money DrawYearCategory(const Rect &r, int start_y, const ExpensesList &list, const Expenses &tbl)
234 {
235  int y = start_y;
236  Money sum = 0;
237 
238  for (const ExpensesType &et : list.items) {
239  Money cost = tbl[et];
240  sum += cost;
241  if (cost != 0) DrawPrice(cost, r.left, r.right, y, TC_BLACK);
243  }
244 
245  /* Draw the total at the bottom of the category. */
246  GfxFillRect(r.left, y, r.right, y + WidgetDimensions::scaled.bevel.top - 1, PC_BLACK);
248  if (sum != 0) DrawPrice(sum, r.left, r.right, y, TC_WHITE);
249 
250  /* Return the sum for the yearly total. */
251  return sum;
252 }
253 
254 
262 static void DrawYearColumn(const Rect &r, TimerGameEconomy::Year year, const Expenses &tbl)
263 {
264  int y = r.top;
265  Money sum;
266 
267  /* Year header */
268  SetDParam(0, year);
269  DrawString(r.left, r.right, y, STR_FINANCES_YEAR, TC_FROMSTRING, SA_RIGHT, true);
271 
272  /* Categories */
273  for (const ExpensesList &list : _expenses_list_types) {
275  sum += DrawYearCategory(r, y, list, tbl);
276  /* Expense list + expense category title + expense category total + blockspace after category */
278  }
279 
280  /* Total income. */
281  GfxFillRect(r.left, y, r.right, y + WidgetDimensions::scaled.bevel.top - 1, PC_BLACK);
283  DrawPrice(sum, r.left, r.right, y, TC_WHITE);
284 }
285 
286 static constexpr NWidgetPart _nested_company_finances_widgets[] = {
288  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
289  NWidget(WWT_CAPTION, COLOUR_GREY, WID_CF_CAPTION), SetDataTip(STR_FINANCES_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
290  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_CF_TOGGLE_SIZE), SetDataTip(SPR_LARGE_SMALL_WINDOW, STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW), SetAspect(WidgetDimensions::ASPECT_TOGGLE_SIZE),
291  NWidget(WWT_SHADEBOX, COLOUR_GREY),
292  NWidget(WWT_STICKYBOX, COLOUR_GREY),
293  EndContainer(),
294  NWidget(NWID_SELECTION, INVALID_COLOUR, WID_CF_SEL_PANEL),
295  NWidget(WWT_PANEL, COLOUR_GREY),
297  NWidget(WWT_EMPTY, COLOUR_GREY, WID_CF_EXPS_CATEGORY), SetMinimalSize(120, 0), SetFill(0, 0),
298  NWidget(WWT_EMPTY, COLOUR_GREY, WID_CF_EXPS_PRICE1), SetMinimalSize(86, 0), SetFill(0, 0),
299  NWidget(WWT_EMPTY, COLOUR_GREY, WID_CF_EXPS_PRICE2), SetMinimalSize(86, 0), SetFill(0, 0),
300  NWidget(WWT_EMPTY, COLOUR_GREY, WID_CF_EXPS_PRICE3), SetMinimalSize(86, 0), SetFill(0, 0),
301  EndContainer(),
302  EndContainer(),
303  EndContainer(),
304  NWidget(WWT_PANEL, COLOUR_GREY),
306  NWidget(NWID_VERTICAL), // Vertical column with 'bank balance', 'loan'
307  NWidget(WWT_TEXT, COLOUR_GREY), SetDataTip(STR_FINANCES_OWN_FUNDS_TITLE, STR_NULL),
308  NWidget(WWT_TEXT, COLOUR_GREY), SetDataTip(STR_FINANCES_LOAN_TITLE, STR_NULL),
309  NWidget(WWT_TEXT, COLOUR_GREY), SetDataTip(STR_FINANCES_BANK_BALANCE_TITLE, STR_NULL), SetPadding(WidgetDimensions::unscaled.vsep_normal, 0, 0, 0),
310  EndContainer(),
311  NWidget(NWID_VERTICAL), // Vertical column with bank balance amount, loan amount, and total.
312  NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_OWN_VALUE), SetDataTip(STR_FINANCES_TOTAL_CURRENCY, STR_NULL), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
313  NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_LOAN_VALUE), SetDataTip(STR_FINANCES_TOTAL_CURRENCY, STR_NULL), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
315  NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_BALANCE_VALUE), SetDataTip(STR_FINANCES_BANK_BALANCE, STR_NULL), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
316  EndContainer(),
317  NWidget(NWID_SELECTION, INVALID_COLOUR, WID_CF_SEL_MAXLOAN),
318  NWidget(NWID_VERTICAL), SetPIPRatio(0, 0, 1), // Max loan information
319  NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_INTEREST_RATE), SetDataTip(STR_FINANCES_INTEREST_RATE, STR_NULL),
320  NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_MAXLOAN_VALUE), SetDataTip(STR_FINANCES_MAX_LOAN, STR_NULL),
321  EndContainer(),
322  EndContainer(),
323  EndContainer(),
324  EndContainer(),
325  NWidget(NWID_SELECTION, INVALID_COLOUR, WID_CF_SEL_BUTTONS),
327  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_CF_INCREASE_LOAN), SetFill(1, 0), SetDataTip(STR_FINANCES_BORROW_BUTTON, STR_FINANCES_BORROW_TOOLTIP),
328  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_CF_REPAY_LOAN), SetFill(1, 0), SetDataTip(STR_FINANCES_REPAY_BUTTON, STR_FINANCES_REPAY_TOOLTIP),
329  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_CF_INFRASTRUCTURE), SetFill(1, 0), SetDataTip(STR_FINANCES_INFRASTRUCTURE_BUTTON, STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP),
330  EndContainer(),
331  EndContainer(),
332 };
333 
336  static Money max_money;
337  bool small;
338 
339  CompanyFinancesWindow(WindowDesc &desc, CompanyID company) : Window(desc)
340  {
341  this->small = false;
342  this->CreateNestedTree();
343  this->SetupWidgets();
344  this->FinishInitNested(company);
345 
346  this->owner = (Owner)this->window_number;
347  }
348 
349  void SetStringParameters(WidgetID widget) const override
350  {
351  switch (widget) {
352  case WID_CF_CAPTION:
353  SetDParam(0, (CompanyID)this->window_number);
354  SetDParam(1, (CompanyID)this->window_number);
355  break;
356 
357  case WID_CF_BALANCE_VALUE: {
358  const Company *c = Company::Get((CompanyID)this->window_number);
359  SetDParam(0, c->money);
360  break;
361  }
362 
363  case WID_CF_LOAN_VALUE: {
364  const Company *c = Company::Get((CompanyID)this->window_number);
365  SetDParam(0, c->current_loan);
366  break;
367  }
368 
369  case WID_CF_OWN_VALUE: {
370  const Company *c = Company::Get((CompanyID)this->window_number);
371  SetDParam(0, c->money - c->current_loan);
372  break;
373  }
374 
377  break;
378 
379  case WID_CF_MAXLOAN_VALUE: {
380  const Company *c = Company::Get((CompanyID)this->window_number);
381  SetDParam(0, c->GetMaxLoan());
382  break;
383  }
384 
386  case WID_CF_REPAY_LOAN:
388  break;
389  }
390  }
391 
392  void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
393  {
394  switch (widget) {
396  size.width = GetMaxCategoriesWidth();
397  size.height = GetTotalCategoriesHeight();
398  break;
399 
400  case WID_CF_EXPS_PRICE1:
401  case WID_CF_EXPS_PRICE2:
402  case WID_CF_EXPS_PRICE3:
403  size.height = GetTotalCategoriesHeight();
404  [[fallthrough]];
405 
407  case WID_CF_LOAN_VALUE:
408  case WID_CF_OWN_VALUE:
410  size.width = std::max(GetStringBoundingBox(STR_FINANCES_NEGATIVE_INCOME).width, GetStringBoundingBox(STR_FINANCES_POSITIVE_INCOME).width) + padding.width;
411  break;
412 
414  size.height = GetCharacterHeight(FS_NORMAL);
415  break;
416  }
417  }
418 
419  void DrawWidget(const Rect &r, WidgetID widget) const override
420  {
421  switch (widget) {
423  DrawCategories(r);
424  break;
425 
426  case WID_CF_EXPS_PRICE1:
427  case WID_CF_EXPS_PRICE2:
428  case WID_CF_EXPS_PRICE3: {
429  const Company *c = Company::Get((CompanyID)this->window_number);
430  auto age = std::min(TimerGameEconomy::year - c->inaugurated_year, TimerGameEconomy::Year(2));
431  int wid_offset = widget - WID_CF_EXPS_PRICE1;
432  if (wid_offset <= age) {
433  DrawYearColumn(r, TimerGameEconomy::year - (age - wid_offset), c->yearly_expenses[(age - wid_offset).base()]);
434  }
435  break;
436  }
437 
438  case WID_CF_BALANCE_LINE:
439  GfxFillRect(r.left, r.top, r.right, r.top + WidgetDimensions::scaled.bevel.top - 1, PC_BLACK);
440  break;
441  }
442  }
443 
449  {
450  int plane = this->small ? SZSP_NONE : 0;
451  this->GetWidget<NWidgetStacked>(WID_CF_SEL_PANEL)->SetDisplayedPlane(plane);
452  this->GetWidget<NWidgetStacked>(WID_CF_SEL_MAXLOAN)->SetDisplayedPlane(plane);
453 
454  CompanyID company = (CompanyID)this->window_number;
455  plane = (company != _local_company) ? SZSP_NONE : 0;
456  this->GetWidget<NWidgetStacked>(WID_CF_SEL_BUTTONS)->SetDisplayedPlane(plane);
457  }
458 
459  void OnPaint() override
460  {
461  if (!this->IsShaded()) {
462  if (!this->small) {
463  /* Check that the expenses panel height matches the height needed for the layout. */
464  if (GetTotalCategoriesHeight() != this->GetWidget<NWidgetBase>(WID_CF_EXPS_CATEGORY)->current_y) {
465  this->SetupWidgets();
466  this->ReInit();
467  return;
468  }
469  }
470 
471  /* Check that the loan buttons are shown only when the user owns the company. */
472  CompanyID company = (CompanyID)this->window_number;
473  int req_plane = (company != _local_company) ? SZSP_NONE : 0;
474  if (req_plane != this->GetWidget<NWidgetStacked>(WID_CF_SEL_BUTTONS)->shown_plane) {
475  this->SetupWidgets();
476  this->ReInit();
477  return;
478  }
479 
480  const Company *c = Company::Get(company);
481  this->SetWidgetDisabledState(WID_CF_INCREASE_LOAN, c->current_loan >= c->GetMaxLoan()); // Borrow button only shows when there is any more money to loan.
482  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.
483  }
484 
485  this->DrawWidgets();
486  }
487 
488  void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
489  {
490  switch (widget) {
491  case WID_CF_TOGGLE_SIZE: // toggle size
492  this->small = !this->small;
493  this->SetupWidgets();
494  if (this->IsShaded()) {
495  /* Finances window is not resizable, so size hints given during unshading have no effect
496  * on the changed appearance of the window. */
497  this->SetShaded(false);
498  } else {
499  this->ReInit();
500  }
501  break;
502 
503  case WID_CF_INCREASE_LOAN: // increase loan
504  Command<CMD_INCREASE_LOAN>::Post(STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY, _ctrl_pressed ? LoanCommand::Max : LoanCommand::Interval, 0);
505  break;
506 
507  case WID_CF_REPAY_LOAN: // repay loan
508  Command<CMD_DECREASE_LOAN>::Post(STR_ERROR_CAN_T_REPAY_LOAN, _ctrl_pressed ? LoanCommand::Max : LoanCommand::Interval, 0);
509  break;
510 
511  case WID_CF_INFRASTRUCTURE: // show infrastructure details
513  break;
514  }
515  }
516 
521  IntervalTimer<TimerWindow> rescale_interval = {std::chrono::seconds(3), [this](auto) {
522  const Company *c = Company::Get((CompanyID)this->window_number);
525  this->SetupWidgets();
526  this->ReInit();
527  }
528  }};
529 };
530 
533 
534 static WindowDesc _company_finances_desc(
535  WDP_AUTO, "company_finances", 0, 0,
537  0,
538  _nested_company_finances_widgets
539 );
540 
547 {
548  if (!Company::IsValidID(company)) return;
549  if (BringWindowToFrontById(WC_FINANCES, company)) return;
550 
551  new CompanyFinancesWindow(_company_finances_desc, company);
552 }
553 
554 /* Association of liveries to livery classes */
555 static const LiveryClass _livery_class[LS_END] = {
556  LC_OTHER,
557  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,
558  LC_ROAD, LC_ROAD,
559  LC_SHIP, LC_SHIP,
560  LC_AIRCRAFT, LC_AIRCRAFT, LC_AIRCRAFT,
561  LC_ROAD, LC_ROAD,
562 };
563 
568 template <SpriteID TSprite = SPR_SQUARE>
569 class DropDownListColourItem : public DropDownIcon<DropDownString<DropDownListItem>> {
570 public:
571  DropDownListColourItem(int colour, bool masked) : DropDownIcon<DropDownString<DropDownListItem>>(TSprite, GENERAL_SPRITE_COLOUR(colour % COLOUR_END), colour < COLOUR_END ? (STR_COLOUR_DARK_BLUE + colour) : STR_COLOUR_DEFAULT, colour, masked)
572  {
573  }
574 };
575 
578 private:
579  uint32_t sel;
580  LiveryClass livery_class;
581  Dimension square;
582  uint rows;
583  uint line_height;
584  GUIGroupList groups;
585  Scrollbar *vscroll;
586 
587  void ShowColourDropDownMenu(uint32_t widget)
588  {
589  uint32_t used_colours = 0;
590  const Livery *livery, *default_livery = nullptr;
591  bool primary = widget == WID_SCL_PRI_COL_DROPDOWN;
592  uint8_t default_col = 0;
593 
594  /* Disallow other company colours for the primary colour */
595  if (this->livery_class < LC_GROUP_RAIL && HasBit(this->sel, LS_DEFAULT) && primary) {
596  for (const Company *c : Company::Iterate()) {
597  if (c->index != _local_company) SetBit(used_colours, c->colour);
598  }
599  }
600 
601  const Company *c = Company::Get((CompanyID)this->window_number);
602 
603  if (this->livery_class < LC_GROUP_RAIL) {
604  /* Get the first selected livery to use as the default dropdown item */
605  LiveryScheme scheme;
606  for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
607  if (HasBit(this->sel, scheme)) break;
608  }
609  if (scheme == LS_END) scheme = LS_DEFAULT;
610  livery = &c->livery[scheme];
611  if (scheme != LS_DEFAULT) default_livery = &c->livery[LS_DEFAULT];
612  } else {
613  const Group *g = Group::Get(this->sel);
614  livery = &g->livery;
615  if (g->parent == INVALID_GROUP) {
616  default_livery = &c->livery[LS_DEFAULT];
617  } else {
618  const Group *pg = Group::Get(g->parent);
619  default_livery = &pg->livery;
620  }
621  }
622 
623  DropDownList list;
624  if (default_livery != nullptr) {
625  /* Add COLOUR_END to put the colour out of range, but also allow us to show what the default is */
626  default_col = (primary ? default_livery->colour1 : default_livery->colour2) + COLOUR_END;
627  list.push_back(std::make_unique<DropDownListColourItem<>>(default_col, false));
628  }
629  for (Colours colour = COLOUR_BEGIN; colour != COLOUR_END; colour++) {
630  list.push_back(std::make_unique<DropDownListColourItem<>>(colour, HasBit(used_colours, colour)));
631  }
632 
633  uint8_t sel;
634  if (default_livery == nullptr || HasBit(livery->in_use, primary ? 0 : 1)) {
635  sel = primary ? livery->colour1 : livery->colour2;
636  } else {
637  sel = default_col;
638  }
639  ShowDropDownList(this, std::move(list), sel, widget);
640  }
641 
642  void BuildGroupList(CompanyID owner)
643  {
644  if (!this->groups.NeedRebuild()) return;
645 
646  this->groups.clear();
647 
648  if (this->livery_class >= LC_GROUP_RAIL) {
649  VehicleType vtype = (VehicleType)(this->livery_class - LC_GROUP_RAIL);
650  BuildGuiGroupList(this->groups, false, owner, vtype);
651  }
652 
653  this->groups.RebuildDone();
654  }
655 
656  void SetRows()
657  {
658  if (this->livery_class < LC_GROUP_RAIL) {
659  this->rows = 0;
660  for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
661  if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
662  this->rows++;
663  }
664  }
665  } else {
666  this->rows = (uint)this->groups.size();
667  }
668 
669  this->vscroll->SetCount(this->rows);
670  }
671 
672 public:
673  SelectCompanyLiveryWindow(WindowDesc &desc, CompanyID company, GroupID group) : Window(desc)
674  {
675  this->CreateNestedTree();
676  this->vscroll = this->GetScrollbar(WID_SCL_MATRIX_SCROLLBAR);
677 
678  if (group == INVALID_GROUP) {
679  this->livery_class = LC_OTHER;
680  this->sel = 1;
682  this->BuildGroupList(company);
683  this->SetRows();
684  } else {
685  this->SetSelectedGroup(company, group);
686  }
687 
688  this->FinishInitNested(company);
689  this->owner = company;
690  this->InvalidateData(1);
691  }
692 
693  void SetSelectedGroup(CompanyID company, GroupID group)
694  {
695  this->RaiseWidget(WID_SCL_CLASS_GENERAL + this->livery_class);
696  const Group *g = Group::Get(group);
697  switch (g->vehicle_type) {
698  case VEH_TRAIN: this->livery_class = LC_GROUP_RAIL; break;
699  case VEH_ROAD: this->livery_class = LC_GROUP_ROAD; break;
700  case VEH_SHIP: this->livery_class = LC_GROUP_SHIP; break;
701  case VEH_AIRCRAFT: this->livery_class = LC_GROUP_AIRCRAFT; break;
702  default: NOT_REACHED();
703  }
704  this->sel = group;
705  this->LowerWidget(WID_SCL_CLASS_GENERAL + this->livery_class);
706 
707  this->groups.ForceRebuild();
708  this->BuildGroupList(company);
709  this->SetRows();
710 
711  /* Position scrollbar to selected group */
712  for (uint i = 0; i < this->rows; i++) {
713  if (this->groups[i].group->index == sel) {
714  this->vscroll->SetPosition(i - this->vscroll->GetCapacity() / 2);
715  break;
716  }
717  }
718  }
719 
720  void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
721  {
722  switch (widget) {
724  /* The matrix widget below needs enough room to print all the schemes. */
725  Dimension d = {0, 0};
726  for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
727  d = maxdim(d, GetStringBoundingBox(STR_LIVERY_DEFAULT + scheme));
728  }
729 
730  /* And group names */
731  for (const Group *g : Group::Iterate()) {
732  if (g->owner == (CompanyID)this->window_number) {
733  SetDParam(0, g->index);
734  d = maxdim(d, GetStringBoundingBox(STR_GROUP_NAME));
735  }
736  }
737 
738  size.width = std::max(size.width, 5 + d.width + padding.width);
739  break;
740  }
741 
742  case WID_SCL_MATRIX: {
743  /* 11 items in the default rail class */
744  this->square = GetSpriteSize(SPR_SQUARE);
745  this->line_height = std::max(this->square.height, (uint)GetCharacterHeight(FS_NORMAL)) + padding.height;
746 
747  size.height = 5 * this->line_height;
748  resize.width = 1;
749  resize.height = this->line_height;
750  break;
751  }
752 
755  size.width = 0;
756  break;
757  }
758  [[fallthrough]];
759 
761  this->square = GetSpriteSize(SPR_SQUARE);
762  int string_padding = this->square.width + WidgetDimensions::scaled.hsep_normal + padding.width;
763  for (Colours colour = COLOUR_BEGIN; colour != COLOUR_END; colour++) {
764  size.width = std::max(size.width, GetStringBoundingBox(STR_COLOUR_DARK_BLUE + colour).width + string_padding);
765  }
766  size.width = std::max(size.width, GetStringBoundingBox(STR_COLOUR_DEFAULT).width + string_padding);
767  break;
768  }
769  }
770  }
771 
772  void OnPaint() override
773  {
774  bool local = (CompanyID)this->window_number == _local_company;
775 
776  /* Disable dropdown controls if no scheme is selected */
777  bool disabled = this->livery_class < LC_GROUP_RAIL ? (this->sel == 0) : (this->sel == INVALID_GROUP);
778  this->SetWidgetDisabledState(WID_SCL_PRI_COL_DROPDOWN, !local || disabled);
779  this->SetWidgetDisabledState(WID_SCL_SEC_COL_DROPDOWN, !local || disabled);
780 
781  this->BuildGroupList((CompanyID)this->window_number);
782 
783  this->DrawWidgets();
784  }
785 
786  void SetStringParameters(WidgetID widget) const override
787  {
788  switch (widget) {
789  case WID_SCL_CAPTION:
790  SetDParam(0, (CompanyID)this->window_number);
791  break;
792 
795  const Company *c = Company::Get((CompanyID)this->window_number);
796  bool primary = widget == WID_SCL_PRI_COL_DROPDOWN;
797  StringID colour = STR_COLOUR_DEFAULT;
798 
799  if (this->livery_class < LC_GROUP_RAIL) {
800  if (this->sel != 0) {
801  LiveryScheme scheme = LS_DEFAULT;
802  for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
803  if (HasBit(this->sel, scheme)) break;
804  }
805  if (scheme == LS_END) scheme = LS_DEFAULT;
806  const Livery *livery = &c->livery[scheme];
807  if (scheme == LS_DEFAULT || HasBit(livery->in_use, primary ? 0 : 1)) {
808  colour = STR_COLOUR_DARK_BLUE + (primary ? livery->colour1 : livery->colour2);
809  }
810  }
811  } else {
812  if (this->sel != INVALID_GROUP) {
813  const Group *g = Group::Get(this->sel);
814  const Livery *livery = &g->livery;
815  if (HasBit(livery->in_use, primary ? 0 : 1)) {
816  colour = STR_COLOUR_DARK_BLUE + (primary ? livery->colour1 : livery->colour2);
817  }
818  }
819  }
820  SetDParam(0, colour);
821  break;
822  }
823  }
824  }
825 
826  void DrawWidget(const Rect &r, WidgetID widget) const override
827  {
828  if (widget != WID_SCL_MATRIX) return;
829 
830  bool rtl = _current_text_dir == TD_RTL;
831 
832  /* Coordinates of scheme name column. */
833  const NWidgetBase *nwi = this->GetWidget<NWidgetBase>(WID_SCL_SPACER_DROPDOWN);
834  Rect sch = nwi->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
835  /* Coordinates of first dropdown. */
836  nwi = this->GetWidget<NWidgetBase>(WID_SCL_PRI_COL_DROPDOWN);
837  Rect pri = nwi->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
838  /* Coordinates of second dropdown. */
839  nwi = this->GetWidget<NWidgetBase>(WID_SCL_SEC_COL_DROPDOWN);
840  Rect sec = nwi->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
841 
842  Rect pri_squ = pri.WithWidth(this->square.width, rtl);
843  Rect sec_squ = sec.WithWidth(this->square.width, rtl);
844 
845  pri = pri.Indent(this->square.width + WidgetDimensions::scaled.hsep_normal, rtl);
846  sec = sec.Indent(this->square.width + WidgetDimensions::scaled.hsep_normal, rtl);
847 
848  Rect ir = r.WithHeight(this->resize.step_height).Shrink(WidgetDimensions::scaled.matrix);
849  int square_offs = (ir.Height() - this->square.height) / 2;
850  int text_offs = (ir.Height() - GetCharacterHeight(FS_NORMAL)) / 2;
851 
852  int y = ir.top;
853 
854  /* Helper function to draw livery info. */
855  auto draw_livery = [&](StringID str, const Livery &livery, bool is_selected, bool is_default_scheme, int indent) {
856  /* Livery Label. */
857  DrawString(sch.left + (rtl ? 0 : indent), sch.right - (rtl ? indent : 0), y + text_offs, str, is_selected ? TC_WHITE : TC_BLACK);
858 
859  /* Text below the first dropdown. */
860  DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOUR(livery.colour1), pri_squ.left, y + square_offs);
861  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);
862 
863  /* Text below the second dropdown. */
864  if (sec.right > sec.left) { // Second dropdown has non-zero size.
865  DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOUR(livery.colour2), sec_squ.left, y + square_offs);
866  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);
867  }
868 
869  y += this->line_height;
870  };
871 
872  const Company *c = Company::Get((CompanyID)this->window_number);
873 
874  if (livery_class < LC_GROUP_RAIL) {
875  int pos = this->vscroll->GetPosition();
876  for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
877  if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
878  if (pos-- > 0) continue;
879  draw_livery(STR_LIVERY_DEFAULT + scheme, c->livery[scheme], HasBit(this->sel, scheme), scheme == LS_DEFAULT, 0);
880  }
881  }
882  } else {
883  auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->groups);
884  for (auto it = first; it != last; ++it) {
885  const Group *g = it->group;
886  SetDParam(0, g->index);
887  draw_livery(STR_GROUP_NAME, g->livery, this->sel == g->index, false, it->indent * WidgetDimensions::scaled.hsep_indent);
888  }
889 
890  if (this->vscroll->GetCount() == 0) {
891  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 };
892  VehicleType vtype = (VehicleType)(this->livery_class - LC_GROUP_RAIL);
893  DrawString(ir.left, ir.right, y + text_offs, empty_labels[vtype], TC_BLACK);
894  }
895  }
896  }
897 
898  void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
899  {
900  switch (widget) {
901  /* Livery Class buttons */
903  case WID_SCL_CLASS_RAIL:
904  case WID_SCL_CLASS_ROAD:
905  case WID_SCL_CLASS_SHIP:
907  case WID_SCL_GROUPS_RAIL:
908  case WID_SCL_GROUPS_ROAD:
909  case WID_SCL_GROUPS_SHIP:
911  this->RaiseWidget(WID_SCL_CLASS_GENERAL + this->livery_class);
912  this->livery_class = (LiveryClass)(widget - WID_SCL_CLASS_GENERAL);
913  this->LowerWidget(WID_SCL_CLASS_GENERAL + this->livery_class);
914 
915  /* Select the first item in the list */
916  if (this->livery_class < LC_GROUP_RAIL) {
917  this->sel = 0;
918  for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
919  if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
920  this->sel = 1 << scheme;
921  break;
922  }
923  }
924  } else {
925  this->sel = INVALID_GROUP;
926  this->groups.ForceRebuild();
927  this->BuildGroupList((CompanyID)this->window_number);
928 
929  if (!this->groups.empty()) {
930  this->sel = this->groups[0].group->index;
931  }
932  }
933 
934  this->SetRows();
935  this->SetDirty();
936  break;
937 
938  case WID_SCL_PRI_COL_DROPDOWN: // First colour dropdown
939  ShowColourDropDownMenu(WID_SCL_PRI_COL_DROPDOWN);
940  break;
941 
942  case WID_SCL_SEC_COL_DROPDOWN: // Second colour dropdown
943  ShowColourDropDownMenu(WID_SCL_SEC_COL_DROPDOWN);
944  break;
945 
946  case WID_SCL_MATRIX: {
947  if (this->livery_class < LC_GROUP_RAIL) {
948  uint row = this->vscroll->GetScrolledRowFromWidget(pt.y, this, widget);
949  if (row >= this->rows) return;
950 
951  LiveryScheme j = (LiveryScheme)row;
952 
953  for (LiveryScheme scheme = LS_BEGIN; scheme <= j && scheme < LS_END; scheme++) {
954  if (_livery_class[scheme] != this->livery_class || !HasBit(_loaded_newgrf_features.used_liveries, scheme)) j++;
955  }
956  assert(j < LS_END);
957 
958  if (_ctrl_pressed) {
959  ToggleBit(this->sel, j);
960  } else {
961  this->sel = 1 << j;
962  }
963  } else {
964  auto it = this->vscroll->GetScrolledItemFromWidget(this->groups, pt.y, this, widget);
965  if (it == std::end(this->groups)) return;
966 
967  this->sel = it->group->index;
968  }
969  this->SetDirty();
970  break;
971  }
972  }
973  }
974 
975  void OnResize() override
976  {
977  this->vscroll->SetCapacityFromWidget(this, WID_SCL_MATRIX);
978  }
979 
980  void OnDropdownSelect(WidgetID widget, int index) override
981  {
982  bool local = (CompanyID)this->window_number == _local_company;
983  if (!local) return;
984 
985  Colours colour = static_cast<Colours>(index);
986  if (colour >= COLOUR_END) colour = INVALID_COLOUR;
987 
988  if (this->livery_class < LC_GROUP_RAIL) {
989  /* Set company colour livery */
990  for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
991  /* Changed colour for the selected scheme, or all visible schemes if CTRL is pressed. */
992  if (HasBit(this->sel, scheme) || (_ctrl_pressed && _livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme))) {
994  }
995  }
996  } else {
997  /* Setting group livery */
999  }
1000  }
1001 
1007  void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
1008  {
1009  if (!gui_scope) return;
1010 
1011  if (data != -1) {
1012  /* data contains a VehicleType, rebuild list if it displayed */
1013  if (this->livery_class == data + LC_GROUP_RAIL) {
1014  this->groups.ForceRebuild();
1015  this->BuildGroupList((CompanyID)this->window_number);
1016  this->SetRows();
1017 
1018  if (!Group::IsValidID(this->sel)) {
1019  this->sel = INVALID_GROUP;
1020  if (!this->groups.empty()) this->sel = this->groups[0].group->index;
1021  }
1022 
1023  this->SetDirty();
1024  }
1025  return;
1026  }
1027 
1029 
1030  bool current_class_valid = this->livery_class == LC_OTHER || this->livery_class >= LC_GROUP_RAIL;
1031  if (_settings_client.gui.liveries == LIT_ALL || (_settings_client.gui.liveries == LIT_COMPANY && this->window_number == _local_company)) {
1032  for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
1034  if (_livery_class[scheme] == this->livery_class) current_class_valid = true;
1035  this->EnableWidget(WID_SCL_CLASS_GENERAL + _livery_class[scheme]);
1036  } else if (this->livery_class < LC_GROUP_RAIL) {
1037  ClrBit(this->sel, scheme);
1038  }
1039  }
1040  }
1041 
1042  if (!current_class_valid) {
1043  Point pt = {0, 0};
1044  this->OnClick(pt, WID_SCL_CLASS_GENERAL, 1);
1045  }
1046  }
1047 };
1048 
1049 static constexpr NWidgetPart _nested_select_company_livery_widgets[] = {
1051  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
1052  NWidget(WWT_CAPTION, COLOUR_GREY, WID_SCL_CAPTION), SetDataTip(STR_LIVERY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1053  NWidget(WWT_SHADEBOX, COLOUR_GREY),
1054  NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
1055  NWidget(WWT_STICKYBOX, COLOUR_GREY),
1056  EndContainer(),
1058  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_GENERAL), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_COMPANY_GENERAL, STR_LIVERY_GENERAL_TOOLTIP),
1059  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_RAIL), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_TRAINLIST, STR_LIVERY_TRAIN_TOOLTIP),
1060  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_ROAD), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_TRUCKLIST, STR_LIVERY_ROAD_VEHICLE_TOOLTIP),
1061  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_SHIP), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_SHIPLIST, STR_LIVERY_SHIP_TOOLTIP),
1062  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_AIRCRAFT), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_AIRPLANESLIST, STR_LIVERY_AIRCRAFT_TOOLTIP),
1063  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_GROUPS_RAIL), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_GROUP_LIVERY_TRAIN, STR_LIVERY_TRAIN_GROUP_TOOLTIP),
1064  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_GROUPS_ROAD), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_GROUP_LIVERY_ROADVEH, STR_LIVERY_ROAD_VEHICLE_GROUP_TOOLTIP),
1065  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_GROUPS_SHIP), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_GROUP_LIVERY_SHIP, STR_LIVERY_SHIP_GROUP_TOOLTIP),
1066  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_GROUPS_AIRCRAFT), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_GROUP_LIVERY_AIRCRAFT, STR_LIVERY_AIRCRAFT_GROUP_TOOLTIP),
1067  NWidget(WWT_PANEL, COLOUR_GREY), SetFill(1, 1), SetResize(1, 0), EndContainer(),
1068  EndContainer(),
1070  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),
1072  EndContainer(),
1074  NWidget(WWT_PANEL, COLOUR_GREY, WID_SCL_SPACER_DROPDOWN), SetFill(1, 1), SetResize(1, 0), EndContainer(),
1075  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SCL_PRI_COL_DROPDOWN), SetFill(0, 1), SetDataTip(STR_JUST_STRING, STR_LIVERY_PRIMARY_TOOLTIP),
1076  NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SCL_SEC_COL_DROPDOWN), SetFill(0, 1), SetDataTip(STR_JUST_STRING, STR_LIVERY_SECONDARY_TOOLTIP),
1077  NWidget(WWT_RESIZEBOX, COLOUR_GREY),
1078  EndContainer(),
1079 };
1080 
1081 static WindowDesc _select_company_livery_desc(
1082  WDP_AUTO, "company_color_scheme", 0, 0,
1084  0,
1085  _nested_select_company_livery_widgets
1086 );
1087 
1088 void ShowCompanyLiveryWindow(CompanyID company, GroupID group)
1089 {
1091  if (w == nullptr) {
1092  new SelectCompanyLiveryWindow(_select_company_livery_desc, company, group);
1093  } else if (group != INVALID_GROUP) {
1094  w->SetSelectedGroup(company, group);
1095  }
1096 }
1097 
1104 void DrawCompanyManagerFace(CompanyManagerFace cmf, Colours colour, const Rect &r)
1105 {
1107 
1108  /* Determine offset from centre of drawing rect. */
1109  Dimension d = GetSpriteSize(SPR_GRADIENT);
1110  int x = CenterBounds(r.left, r.right, d.width);
1111  int y = CenterBounds(r.top, r.bottom, d.height);
1112 
1113  bool has_moustache = !HasBit(ge, GENDER_FEMALE) && GetCompanyManagerFaceBits(cmf, CMFV_HAS_MOUSTACHE, ge) != 0;
1114  bool has_tie_earring = !HasBit(ge, GENDER_FEMALE) || GetCompanyManagerFaceBits(cmf, CMFV_HAS_TIE_EARRING, ge) != 0;
1115  bool has_glasses = GetCompanyManagerFaceBits(cmf, CMFV_HAS_GLASSES, ge) != 0;
1116  PaletteID pal;
1117 
1118  /* Modify eye colour palette only if 2 or more valid values exist */
1119  if (_cmf_info[CMFV_EYE_COLOUR].valid_values[ge] < 2) {
1120  pal = PAL_NONE;
1121  } else {
1122  switch (GetCompanyManagerFaceBits(cmf, CMFV_EYE_COLOUR, ge)) {
1123  default: NOT_REACHED();
1124  case 0: pal = PALETTE_TO_BROWN; break;
1125  case 1: pal = PALETTE_TO_BLUE; break;
1126  case 2: pal = PALETTE_TO_GREEN; break;
1127  }
1128  }
1129 
1130  /* Draw the gradient (background) */
1131  DrawSprite(SPR_GRADIENT, GENERAL_SPRITE_COLOUR(colour), x, y);
1132 
1133  for (CompanyManagerFaceVariable cmfv = CMFV_CHEEKS; cmfv < CMFV_END; cmfv++) {
1134  switch (cmfv) {
1135  case CMFV_MOUSTACHE: if (!has_moustache) continue; break;
1136  case CMFV_LIPS:
1137  case CMFV_NOSE: if (has_moustache) continue; break;
1138  case CMFV_TIE_EARRING: if (!has_tie_earring) continue; break;
1139  case CMFV_GLASSES: if (!has_glasses) continue; break;
1140  default: break;
1141  }
1142  DrawSprite(GetCompanyManagerFaceSprite(cmf, cmfv, ge), (cmfv == CMFV_EYEBROWS) ? pal : PAL_NONE, x, y);
1143  }
1144 }
1145 
1149  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
1150  NWidget(WWT_CAPTION, COLOUR_GREY, WID_SCMF_CAPTION), SetDataTip(STR_FACE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1151  NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCMF_TOGGLE_LARGE_SMALL), SetDataTip(SPR_LARGE_SMALL_WINDOW, STR_FACE_ADVANCED_TOOLTIP), SetAspect(WidgetDimensions::ASPECT_TOGGLE_SIZE),
1152  EndContainer(),
1153  NWidget(WWT_PANEL, COLOUR_GREY, WID_SCMF_SELECT_FACE),
1155  /* Left side */
1157  NWidget(NWID_HORIZONTAL), SetPIPRatio(1, 0, 1),
1158  NWidget(WWT_EMPTY, COLOUR_GREY, WID_SCMF_FACE), SetMinimalSize(92, 119), SetFill(1, 0),
1159  EndContainer(),
1160  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_RANDOM_NEW_FACE), SetFill(1, 0), SetDataTip(STR_FACE_NEW_FACE_BUTTON, STR_FACE_NEW_FACE_TOOLTIP),
1161  NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SCMF_SEL_LOADSAVE), // Load/number/save buttons under the portrait in the advanced view.
1162  NWidget(NWID_VERTICAL), SetPIP(0, 0, 0), SetPIPRatio(1, 0, 1),
1163  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_LOAD), SetFill(1, 0), SetDataTip(STR_FACE_LOAD, STR_FACE_LOAD_TOOLTIP),
1164  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_FACECODE), SetFill(1, 0), SetDataTip(STR_FACE_FACECODE, STR_FACE_FACECODE_TOOLTIP),
1165  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_SAVE), SetFill(1, 0), SetDataTip(STR_FACE_SAVE, STR_FACE_SAVE_TOOLTIP),
1166  EndContainer(),
1167  EndContainer(),
1168  EndContainer(),
1169  /* Right side */
1171  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON), SetFill(1, 0), SetDataTip(STR_FACE_ADVANCED, STR_FACE_ADVANCED_TOOLTIP),
1172  NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SCMF_SEL_MALEFEMALE), // Simple male/female face setting.
1173  NWidget(NWID_VERTICAL), SetPIPRatio(1, 0, 1),
1174  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_MALE), SetFill(1, 0), SetDataTip(STR_FACE_MALE_BUTTON, STR_FACE_MALE_TOOLTIP),
1175  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_FEMALE), SetFill(1, 0), SetDataTip(STR_FACE_FEMALE_BUTTON, STR_FACE_FEMALE_TOOLTIP),
1176  EndContainer(),
1177  EndContainer(),
1178  NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SCMF_SEL_PARTS), // Advanced face parts setting.
1181  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_MALE2), SetFill(1, 0), SetDataTip(STR_FACE_MALE_BUTTON, STR_FACE_MALE_TOOLTIP),
1182  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_FEMALE2), SetFill(1, 0), SetDataTip(STR_FACE_FEMALE_BUTTON, STR_FACE_FEMALE_TOOLTIP),
1183  EndContainer(),
1185  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_ETHNICITY_EUR), SetFill(1, 0), SetDataTip(STR_FACE_EUROPEAN, STR_FACE_SELECT_EUROPEAN),
1186  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_ETHNICITY_AFR), SetFill(1, 0), SetDataTip(STR_FACE_AFRICAN, STR_FACE_SELECT_AFRICAN),
1187  EndContainer(),
1191  SetDataTip(STR_FACE_EYECOLOUR, STR_NULL), SetTextStyle(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1192  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_MOUSTACHE_EARRING), SetDataTip(STR_JUST_STRING1, STR_FACE_MOUSTACHE_EARRING_TOOLTIP), SetTextStyle(TC_WHITE),
1193  EndContainer(),
1195  NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_HAS_GLASSES_TEXT), SetFill(1, 0),
1196  SetDataTip(STR_FACE_GLASSES, STR_NULL), SetTextStyle(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1197  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_GLASSES), SetDataTip(STR_JUST_STRING1, STR_FACE_GLASSES_TOOLTIP), SetTextStyle(TC_WHITE),
1198  EndContainer(),
1199  EndContainer(),
1202  NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_HAIR_TEXT), SetFill(1, 0),
1203  SetDataTip(STR_FACE_HAIR, STR_NULL), SetTextStyle(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1205  NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_HAIR_L), SetDataTip(AWV_DECREASE, STR_FACE_HAIR_TOOLTIP),
1206  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAIR), SetDataTip(STR_JUST_STRING1, STR_FACE_HAIR_TOOLTIP), SetTextStyle(TC_WHITE),
1207  NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_HAIR_R), SetDataTip(AWV_INCREASE, STR_FACE_HAIR_TOOLTIP),
1208  EndContainer(),
1209  EndContainer(),
1211  NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_EYEBROWS_TEXT), SetFill(1, 0),
1212  SetDataTip(STR_FACE_EYEBROWS, STR_NULL), SetTextStyle(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1214  NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYEBROWS_L), SetDataTip(AWV_DECREASE, STR_FACE_EYEBROWS_TOOLTIP),
1215  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYEBROWS), SetDataTip(STR_JUST_STRING1, STR_FACE_EYEBROWS_TOOLTIP), SetTextStyle(TC_WHITE),
1216  NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYEBROWS_R), SetDataTip(AWV_INCREASE, STR_FACE_EYEBROWS_TOOLTIP),
1217  EndContainer(),
1218  EndContainer(),
1220  NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_EYECOLOUR_TEXT), SetFill(1, 0),
1221  SetDataTip(STR_FACE_EYECOLOUR, STR_NULL), SetTextStyle(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1223  NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR_L), SetDataTip(AWV_DECREASE, STR_FACE_EYECOLOUR_TOOLTIP),
1224  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR), SetDataTip(STR_JUST_STRING1, STR_FACE_EYECOLOUR_TOOLTIP), SetTextStyle(TC_WHITE),
1225  NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR_R), SetDataTip(AWV_INCREASE, STR_FACE_EYECOLOUR_TOOLTIP),
1226  EndContainer(),
1227  EndContainer(),
1229  NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_GLASSES_TEXT), SetFill(1, 0),
1230  SetDataTip(STR_FACE_GLASSES, STR_NULL), SetTextStyle(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1232  NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_GLASSES_L), SetDataTip(AWV_DECREASE, STR_FACE_GLASSES_TOOLTIP_2),
1233  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_GLASSES), SetDataTip(STR_JUST_STRING1, STR_FACE_GLASSES_TOOLTIP_2), SetTextStyle(TC_WHITE),
1234  NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_GLASSES_R), SetDataTip(AWV_INCREASE, STR_FACE_GLASSES_TOOLTIP_2),
1235  EndContainer(),
1236  EndContainer(),
1238  NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_NOSE_TEXT), SetFill(1, 0),
1239  SetDataTip(STR_FACE_NOSE, STR_NULL), SetTextStyle(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1241  NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_NOSE_L), SetDataTip(AWV_DECREASE, STR_FACE_NOSE_TOOLTIP),
1242  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_NOSE), SetDataTip(STR_JUST_STRING1, STR_FACE_NOSE_TOOLTIP), SetTextStyle(TC_WHITE),
1243  NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_NOSE_R), SetDataTip(AWV_INCREASE, STR_FACE_NOSE_TOOLTIP),
1244  EndContainer(),
1245  EndContainer(),
1247  NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_LIPS_MOUSTACHE_TEXT), SetFill(1, 0),
1248  SetDataTip(STR_FACE_MOUSTACHE, STR_NULL), SetTextStyle(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1250  NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE_L), SetDataTip(AWV_DECREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP),
1251  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE), SetDataTip(STR_JUST_STRING1, STR_FACE_LIPS_MOUSTACHE_TOOLTIP), SetTextStyle(TC_WHITE),
1252  NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE_R), SetDataTip(AWV_INCREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP),
1253  EndContainer(),
1254  EndContainer(),
1256  NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_CHIN_TEXT), SetFill(1, 0),
1257  SetDataTip(STR_FACE_CHIN, STR_NULL), SetTextStyle(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1259  NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_CHIN_L), SetDataTip(AWV_DECREASE, STR_FACE_CHIN_TOOLTIP),
1260  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_CHIN), SetDataTip(STR_JUST_STRING1, STR_FACE_CHIN_TOOLTIP), SetTextStyle(TC_WHITE),
1261  NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_CHIN_R), SetDataTip(AWV_INCREASE, STR_FACE_CHIN_TOOLTIP),
1262  EndContainer(),
1263  EndContainer(),
1265  NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_JACKET_TEXT), SetFill(1, 0),
1266  SetDataTip(STR_FACE_JACKET, STR_NULL), SetTextStyle(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1268  NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_JACKET_L), SetDataTip(AWV_DECREASE, STR_FACE_JACKET_TOOLTIP),
1269  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_JACKET), SetDataTip(STR_JUST_STRING1, STR_FACE_JACKET_TOOLTIP), SetTextStyle(TC_WHITE),
1270  NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_JACKET_R), SetDataTip(AWV_INCREASE, STR_FACE_JACKET_TOOLTIP),
1271  EndContainer(),
1272  EndContainer(),
1274  NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_COLLAR_TEXT), SetFill(1, 0),
1275  SetDataTip(STR_FACE_COLLAR, STR_NULL), SetTextStyle(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1277  NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_COLLAR_L), SetDataTip(AWV_DECREASE, STR_FACE_COLLAR_TOOLTIP),
1278  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_COLLAR), SetDataTip(STR_JUST_STRING1, STR_FACE_COLLAR_TOOLTIP), SetTextStyle(TC_WHITE),
1279  NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_COLLAR_R), SetDataTip(AWV_INCREASE, STR_FACE_COLLAR_TOOLTIP),
1280  EndContainer(),
1281  EndContainer(),
1283  NWidget(WWT_TEXT, INVALID_COLOUR, WID_SCMF_TIE_EARRING_TEXT), SetFill(1, 0),
1284  SetDataTip(STR_FACE_EARRING, STR_NULL), SetTextStyle(TC_GOLD), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
1286  NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING_L), SetDataTip(AWV_DECREASE, STR_FACE_TIE_EARRING_TOOLTIP),
1287  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING), SetDataTip(STR_JUST_STRING1, STR_FACE_TIE_EARRING_TOOLTIP), SetTextStyle(TC_WHITE),
1288  NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING_R), SetDataTip(AWV_INCREASE, STR_FACE_TIE_EARRING_TOOLTIP),
1289  EndContainer(),
1290  EndContainer(),
1291  EndContainer(),
1292  EndContainer(),
1293  EndContainer(),
1294  EndContainer(),
1295  EndContainer(),
1296  EndContainer(),
1298  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_CANCEL), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_FACE_CANCEL_TOOLTIP),
1299  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_ACCEPT), SetFill(1, 0), SetDataTip(STR_BUTTON_OK, STR_FACE_OK_TOOLTIP),
1300  EndContainer(),
1301 };
1302 
1305 {
1307  bool advanced;
1308 
1310  bool is_female;
1312 
1315 
1323  void SetFaceStringParameters(WidgetID widget_index, uint8_t val, bool is_bool_widget) const
1324  {
1325  const NWidgetCore *nwi_widget = this->GetWidget<NWidgetCore>(widget_index);
1326  if (nwi_widget->IsDisabled()) {
1327  SetDParam(0, STR_EMPTY);
1328  } else {
1329  if (is_bool_widget) {
1330  /* if it a bool button write yes or no */
1331  SetDParam(0, (val != 0) ? STR_FACE_YES : STR_FACE_NO);
1332  } else {
1333  /* else write the value + 1 */
1334  SetDParam(0, STR_JUST_INT);
1335  SetDParam(1, val + 1);
1336  }
1337  }
1338  }
1339 
1340  void UpdateData()
1341  {
1342  this->ge = (GenderEthnicity)GB(this->face, _cmf_info[CMFV_GEN_ETHN].offset, _cmf_info[CMFV_GEN_ETHN].length); // get the gender and ethnicity
1343  this->is_female = HasBit(this->ge, GENDER_FEMALE); // get the gender: 0 == male and 1 == female
1344  this->is_moust_male = !is_female && GetCompanyManagerFaceBits(this->face, CMFV_HAS_MOUSTACHE, this->ge) != 0; // is a male face with moustache
1345 
1346  this->GetWidget<NWidgetCore>(WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT)->widget_data = this->is_female ? STR_FACE_EARRING : STR_FACE_MOUSTACHE;
1347  this->GetWidget<NWidgetCore>(WID_SCMF_TIE_EARRING_TEXT)->widget_data = this->is_female ? STR_FACE_EARRING : STR_FACE_TIE;
1348  this->GetWidget<NWidgetCore>(WID_SCMF_LIPS_MOUSTACHE_TEXT)->widget_data = this->is_moust_male ? STR_FACE_MOUSTACHE : STR_FACE_LIPS;
1349  }
1350 
1351 public:
1353  {
1354  this->advanced = false;
1355  this->CreateNestedTree();
1356  this->SelectDisplayPlanes(this->advanced);
1357  this->FinishInitNested(parent->window_number);
1358  this->parent = parent;
1359  this->owner = (Owner)this->window_number;
1360  this->face = Company::Get((CompanyID)this->window_number)->face;
1361 
1362  this->UpdateData();
1363  }
1364 
1370  {
1371  this->GetWidget<NWidgetStacked>(WID_SCMF_SEL_LOADSAVE)->SetDisplayedPlane(advanced ? 0 : SZSP_NONE);
1372  this->GetWidget<NWidgetStacked>(WID_SCMF_SEL_PARTS)->SetDisplayedPlane(advanced ? 0 : SZSP_NONE);
1373  this->GetWidget<NWidgetStacked>(WID_SCMF_SEL_MALEFEMALE)->SetDisplayedPlane(advanced ? SZSP_NONE : 0);
1374  this->GetWidget<NWidgetCore>(WID_SCMF_RANDOM_NEW_FACE)->widget_data = advanced ? STR_FACE_RANDOM : STR_FACE_NEW_FACE_BUTTON;
1375 
1376  NWidgetCore *wi = this->GetWidget<NWidgetCore>(WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON);
1377  if (advanced) {
1378  wi->SetDataTip(STR_FACE_SIMPLE, STR_FACE_SIMPLE_TOOLTIP);
1379  } else {
1380  wi->SetDataTip(STR_FACE_ADVANCED, STR_FACE_ADVANCED_TOOLTIP);
1381  }
1382  }
1383 
1384  void OnInit() override
1385  {
1386  /* Size of the boolean yes/no button. */
1387  Dimension yesno_dim = maxdim(GetStringBoundingBox(STR_FACE_YES), GetStringBoundingBox(STR_FACE_NO));
1390  /* Size of the number button + arrows. */
1391  Dimension number_dim = {0, 0};
1392  for (int val = 1; val <= 12; val++) {
1393  SetDParam(0, val);
1395  }
1396  uint arrows_width = GetSpriteSize(SPR_ARROW_LEFT).width + GetSpriteSize(SPR_ARROW_RIGHT).width + 2 * (WidgetDimensions::scaled.imgbtn.Horizontal());
1397  number_dim.width += WidgetDimensions::scaled.framerect.Horizontal() + arrows_width;
1399  /* Compute width of both buttons. */
1400  yesno_dim.width = std::max(yesno_dim.width, number_dim.width);
1401  number_dim.width = yesno_dim.width - arrows_width;
1402 
1403  this->yesno_dim = yesno_dim;
1404  this->number_dim = number_dim;
1405  }
1406 
1407  void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
1408  {
1409  switch (widget) {
1411  size = maxdim(size, GetStringBoundingBox(STR_FACE_EARRING));
1412  size = maxdim(size, GetStringBoundingBox(STR_FACE_MOUSTACHE));
1413  break;
1414 
1416  size = maxdim(size, GetStringBoundingBox(STR_FACE_EARRING));
1417  size = maxdim(size, GetStringBoundingBox(STR_FACE_TIE));
1418  break;
1419 
1421  size = maxdim(size, GetStringBoundingBox(STR_FACE_LIPS));
1422  size = maxdim(size, GetStringBoundingBox(STR_FACE_MOUSTACHE));
1423  break;
1424 
1425  case WID_SCMF_FACE:
1426  size = maxdim(size, GetScaledSpriteSize(SPR_GRADIENT));
1427  break;
1428 
1430  case WID_SCMF_HAS_GLASSES:
1431  size = this->yesno_dim;
1432  break;
1433 
1434  case WID_SCMF_EYECOLOUR:
1435  case WID_SCMF_CHIN:
1436  case WID_SCMF_EYEBROWS:
1438  case WID_SCMF_NOSE:
1439  case WID_SCMF_HAIR:
1440  case WID_SCMF_JACKET:
1441  case WID_SCMF_COLLAR:
1442  case WID_SCMF_TIE_EARRING:
1443  case WID_SCMF_GLASSES:
1444  size = this->number_dim;
1445  break;
1446  }
1447  }
1448 
1449  void OnPaint() override
1450  {
1451  /* lower the non-selected gender button */
1452  this->SetWidgetsLoweredState(!this->is_female, WID_SCMF_MALE, WID_SCMF_MALE2);
1453  this->SetWidgetsLoweredState( this->is_female, WID_SCMF_FEMALE, WID_SCMF_FEMALE2);
1454 
1455  /* advanced company manager face selection window */
1456 
1457  /* lower the non-selected ethnicity button */
1460 
1461 
1462  /* Disable dynamically the widgets which CompanyManagerFaceVariable has less than 2 options
1463  * (or in other words you haven't any choice).
1464  * If the widgets depend on a HAS-variable and this is false the widgets will be disabled, too. */
1465 
1466  /* Eye colour buttons */
1467  this->SetWidgetsDisabledState(_cmf_info[CMFV_EYE_COLOUR].valid_values[this->ge] < 2,
1469 
1470  /* Chin buttons */
1471  this->SetWidgetsDisabledState(_cmf_info[CMFV_CHIN].valid_values[this->ge] < 2,
1473 
1474  /* Eyebrows buttons */
1475  this->SetWidgetsDisabledState(_cmf_info[CMFV_EYEBROWS].valid_values[this->ge] < 2,
1477 
1478  /* Lips or (if it a male face with a moustache) moustache buttons */
1479  this->SetWidgetsDisabledState(_cmf_info[this->is_moust_male ? CMFV_MOUSTACHE : CMFV_LIPS].valid_values[this->ge] < 2,
1481 
1482  /* Nose buttons | male faces with moustache haven't any nose options */
1483  this->SetWidgetsDisabledState(_cmf_info[CMFV_NOSE].valid_values[this->ge] < 2 || this->is_moust_male,
1485 
1486  /* Hair buttons */
1487  this->SetWidgetsDisabledState(_cmf_info[CMFV_HAIR].valid_values[this->ge] < 2,
1489 
1490  /* Jacket buttons */
1491  this->SetWidgetsDisabledState(_cmf_info[CMFV_JACKET].valid_values[this->ge] < 2,
1493 
1494  /* Collar buttons */
1495  this->SetWidgetsDisabledState(_cmf_info[CMFV_COLLAR].valid_values[this->ge] < 2,
1497 
1498  /* Tie/earring buttons | female faces without earring haven't any earring options */
1499  this->SetWidgetsDisabledState(_cmf_info[CMFV_TIE_EARRING].valid_values[this->ge] < 2 ||
1500  (this->is_female && GetCompanyManagerFaceBits(this->face, CMFV_HAS_TIE_EARRING, this->ge) == 0),
1502 
1503  /* Glasses buttons | faces without glasses haven't any glasses options */
1504  this->SetWidgetsDisabledState(_cmf_info[CMFV_GLASSES].valid_values[this->ge] < 2 || GetCompanyManagerFaceBits(this->face, CMFV_HAS_GLASSES, this->ge) == 0,
1506 
1507  this->DrawWidgets();
1508  }
1509 
1510  void SetStringParameters(WidgetID widget) const override
1511  {
1512  switch (widget) {
1514  if (this->is_female) { // Only for female faces
1515  this->SetFaceStringParameters(WID_SCMF_HAS_MOUSTACHE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_HAS_TIE_EARRING, this->ge), true);
1516  } else { // Only for male faces
1517  this->SetFaceStringParameters(WID_SCMF_HAS_MOUSTACHE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_HAS_MOUSTACHE, this->ge), true);
1518  }
1519  break;
1520 
1521  case WID_SCMF_TIE_EARRING:
1522  this->SetFaceStringParameters(WID_SCMF_TIE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_TIE_EARRING, this->ge), false);
1523  break;
1524 
1526  if (this->is_moust_male) { // Only for male faces with moustache
1527  this->SetFaceStringParameters(WID_SCMF_LIPS_MOUSTACHE, GetCompanyManagerFaceBits(this->face, CMFV_MOUSTACHE, this->ge), false);
1528  } else { // Only for female faces or male faces without moustache
1529  this->SetFaceStringParameters(WID_SCMF_LIPS_MOUSTACHE, GetCompanyManagerFaceBits(this->face, CMFV_LIPS, this->ge), false);
1530  }
1531  break;
1532 
1533  case WID_SCMF_HAS_GLASSES:
1534  this->SetFaceStringParameters(WID_SCMF_HAS_GLASSES, GetCompanyManagerFaceBits(this->face, CMFV_HAS_GLASSES, this->ge), true );
1535  break;
1536 
1537  case WID_SCMF_HAIR:
1538  this->SetFaceStringParameters(WID_SCMF_HAIR, GetCompanyManagerFaceBits(this->face, CMFV_HAIR, this->ge), false);
1539  break;
1540 
1541  case WID_SCMF_EYEBROWS:
1542  this->SetFaceStringParameters(WID_SCMF_EYEBROWS, GetCompanyManagerFaceBits(this->face, CMFV_EYEBROWS, this->ge), false);
1543  break;
1544 
1545  case WID_SCMF_EYECOLOUR:
1546  this->SetFaceStringParameters(WID_SCMF_EYECOLOUR, GetCompanyManagerFaceBits(this->face, CMFV_EYE_COLOUR, this->ge), false);
1547  break;
1548 
1549  case WID_SCMF_GLASSES:
1550  this->SetFaceStringParameters(WID_SCMF_GLASSES, GetCompanyManagerFaceBits(this->face, CMFV_GLASSES, this->ge), false);
1551  break;
1552 
1553  case WID_SCMF_NOSE:
1554  this->SetFaceStringParameters(WID_SCMF_NOSE, GetCompanyManagerFaceBits(this->face, CMFV_NOSE, this->ge), false);
1555  break;
1556 
1557  case WID_SCMF_CHIN:
1558  this->SetFaceStringParameters(WID_SCMF_CHIN, GetCompanyManagerFaceBits(this->face, CMFV_CHIN, this->ge), false);
1559  break;
1560 
1561  case WID_SCMF_JACKET:
1562  this->SetFaceStringParameters(WID_SCMF_JACKET, GetCompanyManagerFaceBits(this->face, CMFV_JACKET, this->ge), false);
1563  break;
1564 
1565  case WID_SCMF_COLLAR:
1566  this->SetFaceStringParameters(WID_SCMF_COLLAR, GetCompanyManagerFaceBits(this->face, CMFV_COLLAR, this->ge), false);
1567  break;
1568  }
1569  }
1570 
1571  void DrawWidget(const Rect &r, WidgetID widget) const override
1572  {
1573  switch (widget) {
1574  case WID_SCMF_FACE:
1575  DrawCompanyManagerFace(this->face, Company::Get((CompanyID)this->window_number)->colour, r);
1576  break;
1577  }
1578  }
1579 
1580  void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
1581  {
1582  switch (widget) {
1583  /* Toggle size, advanced/simple face selection */
1586  this->advanced = !this->advanced;
1587  this->SelectDisplayPlanes(this->advanced);
1588  this->ReInit();
1589  break;
1590 
1591  /* OK button */
1592  case WID_SCMF_ACCEPT:
1594  [[fallthrough]];
1595 
1596  /* Cancel button */
1597  case WID_SCMF_CANCEL:
1598  this->Close();
1599  break;
1600 
1601  /* Load button */
1602  case WID_SCMF_LOAD:
1603  this->face = _company_manager_face;
1604  ScaleAllCompanyManagerFaceBits(this->face);
1605  ShowErrorMessage(STR_FACE_LOAD_DONE, INVALID_STRING_ID, WL_INFO);
1606  this->UpdateData();
1607  this->SetDirty();
1608  break;
1609 
1610  /* 'Company manager face number' button, view and/or set company manager face number */
1611  case WID_SCMF_FACECODE:
1612  SetDParam(0, this->face);
1613  ShowQueryString(STR_JUST_INT, STR_FACE_FACECODE_CAPTION, 10 + 1, this, CS_NUMERAL, QSF_NONE);
1614  break;
1615 
1616  /* Save button */
1617  case WID_SCMF_SAVE:
1618  _company_manager_face = this->face;
1619  ShowErrorMessage(STR_FACE_SAVE_DONE, INVALID_STRING_ID, WL_INFO);
1620  break;
1621 
1622  /* Toggle gender (male/female) button */
1623  case WID_SCMF_MALE:
1624  case WID_SCMF_FEMALE:
1625  case WID_SCMF_MALE2:
1626  case WID_SCMF_FEMALE2:
1627  SetCompanyManagerFaceBits(this->face, CMFV_GENDER, this->ge, (widget == WID_SCMF_FEMALE || widget == WID_SCMF_FEMALE2));
1628  ScaleAllCompanyManagerFaceBits(this->face);
1629  this->UpdateData();
1630  this->SetDirty();
1631  break;
1632 
1633  /* Randomize face button */
1635  RandomCompanyManagerFaceBits(this->face, this->ge, this->advanced, _interactive_random);
1636  this->UpdateData();
1637  this->SetDirty();
1638  break;
1639 
1640  /* Toggle ethnicity (european/african) button */
1643  SetCompanyManagerFaceBits(this->face, CMFV_ETHNICITY, this->ge, widget - WID_SCMF_ETHNICITY_EUR);
1644  ScaleAllCompanyManagerFaceBits(this->face);
1645  this->UpdateData();
1646  this->SetDirty();
1647  break;
1648 
1649  default:
1650  /* Here all buttons from WID_SCMF_HAS_MOUSTACHE_EARRING to WID_SCMF_GLASSES_R are handled.
1651  * First it checks which CompanyManagerFaceVariable is being changed, and then either
1652  * a: invert the value for boolean variables, or
1653  * b: it checks inside of IncreaseCompanyManagerFaceBits() if a left (_L) butten is pressed and then decrease else increase the variable */
1654  if (widget >= WID_SCMF_HAS_MOUSTACHE_EARRING && widget <= WID_SCMF_GLASSES_R) {
1655  CompanyManagerFaceVariable cmfv; // which CompanyManagerFaceVariable shall be edited
1656 
1657  if (widget < WID_SCMF_EYECOLOUR_L) { // Bool buttons
1658  switch (widget - WID_SCMF_HAS_MOUSTACHE_EARRING) {
1659  default: NOT_REACHED();
1660  case 0: cmfv = this->is_female ? CMFV_HAS_TIE_EARRING : CMFV_HAS_MOUSTACHE; break; // Has earring/moustache button
1661  case 1: cmfv = CMFV_HAS_GLASSES; break; // Has glasses button
1662  }
1663  SetCompanyManagerFaceBits(this->face, cmfv, this->ge, !GetCompanyManagerFaceBits(this->face, cmfv, this->ge));
1664  ScaleAllCompanyManagerFaceBits(this->face);
1665  } else { // Value buttons
1666  switch ((widget - WID_SCMF_EYECOLOUR_L) / 3) {
1667  default: NOT_REACHED();
1668  case 0: cmfv = CMFV_EYE_COLOUR; break; // Eye colour buttons
1669  case 1: cmfv = CMFV_CHIN; break; // Chin buttons
1670  case 2: cmfv = CMFV_EYEBROWS; break; // Eyebrows buttons
1671  case 3: cmfv = this->is_moust_male ? CMFV_MOUSTACHE : CMFV_LIPS; break; // Moustache or lips buttons
1672  case 4: cmfv = CMFV_NOSE; break; // Nose buttons
1673  case 5: cmfv = CMFV_HAIR; break; // Hair buttons
1674  case 6: cmfv = CMFV_JACKET; break; // Jacket buttons
1675  case 7: cmfv = CMFV_COLLAR; break; // Collar buttons
1676  case 8: cmfv = CMFV_TIE_EARRING; break; // Tie/earring buttons
1677  case 9: cmfv = CMFV_GLASSES; break; // Glasses buttons
1678  }
1679  /* 0 == left (_L), 1 == middle or 2 == right (_R) - button click */
1680  IncreaseCompanyManagerFaceBits(this->face, cmfv, this->ge, (((widget - WID_SCMF_EYECOLOUR_L) % 3) != 0) ? 1 : -1);
1681  }
1682  this->UpdateData();
1683  this->SetDirty();
1684  }
1685  break;
1686  }
1687  }
1688 
1689  void OnQueryTextFinished(std::optional<std::string> str) override
1690  {
1691  if (!str.has_value()) return;
1692  /* Set a new company manager face number */
1693  if (!str->empty()) {
1694  this->face = std::strtoul(str->c_str(), nullptr, 10);
1695  ScaleAllCompanyManagerFaceBits(this->face);
1696  ShowErrorMessage(STR_FACE_FACECODE_SET, INVALID_STRING_ID, WL_INFO);
1697  this->UpdateData();
1698  this->SetDirty();
1699  } else {
1700  ShowErrorMessage(STR_FACE_FACECODE_ERR, INVALID_STRING_ID, WL_INFO);
1701  }
1702  }
1703 };
1704 
1707  WDP_AUTO, nullptr, 0, 0,
1711 );
1712 
1719 {
1720  if (!Company::IsValidID((CompanyID)parent->window_number)) return;
1721 
1724 }
1725 
1726 static constexpr NWidgetPart _nested_company_infrastructure_widgets[] = {
1728  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
1729  NWidget(WWT_CAPTION, COLOUR_GREY, WID_CI_CAPTION), SetDataTip(STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
1730  NWidget(WWT_SHADEBOX, COLOUR_GREY),
1731  NWidget(WWT_STICKYBOX, COLOUR_GREY),
1732  EndContainer(),
1733  NWidget(WWT_PANEL, COLOUR_GREY),
1736  NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_RAIL_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0),
1737  NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_RAIL_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1),
1738  EndContainer(),
1740  NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_ROAD_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0),
1741  NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_ROAD_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1),
1742  EndContainer(),
1744  NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_TRAM_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0),
1745  NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_TRAM_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1),
1746  EndContainer(),
1748  NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_WATER_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0),
1749  NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_WATER_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1),
1750  EndContainer(),
1752  NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_STATION_DESC), SetMinimalTextLines(3, 0), SetFill(1, 0),
1753  NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_STATION_COUNT), SetMinimalTextLines(3, 0), SetFill(0, 1),
1754  EndContainer(),
1756  NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_TOTAL_DESC), SetFill(1, 0),
1757  NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_TOTAL), SetFill(0, 1),
1758  EndContainer(),
1759  EndContainer(),
1760  EndContainer(),
1761 };
1762 
1767 {
1770 
1772 
1774  {
1775  this->UpdateRailRoadTypes();
1776 
1777  this->InitNested(window_number);
1778  this->owner = (Owner)this->window_number;
1779  }
1780 
1781  void UpdateRailRoadTypes()
1782  {
1783  this->railtypes = RAILTYPES_NONE;
1784  this->roadtypes = ROADTYPES_NONE;
1785 
1786  /* Find the used railtypes. */
1787  for (const Engine *e : Engine::IterateType(VEH_TRAIN)) {
1788  if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue;
1789 
1790  this->railtypes |= GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes;
1791  }
1792 
1793  /* Get the date introduced railtypes as well. */
1794  this->railtypes = AddDateIntroducedRailTypes(this->railtypes, CalendarTime::MAX_DATE);
1795 
1796  /* Find the used roadtypes. */
1797  for (const Engine *e : Engine::IterateType(VEH_ROAD)) {
1798  if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue;
1799 
1800  this->roadtypes |= GetRoadTypeInfo(e->u.road.roadtype)->introduces_roadtypes;
1801  }
1802 
1803  /* Get the date introduced roadtypes as well. */
1804  this->roadtypes = AddDateIntroducedRoadTypes(this->roadtypes, CalendarTime::MAX_DATE);
1805  this->roadtypes &= ~_roadtypes_hidden_mask;
1806  }
1807 
1810  {
1811  const Company *c = Company::Get((CompanyID)this->window_number);
1812  Money total;
1813 
1814  uint32_t rail_total = c->infrastructure.GetRailTotal();
1815  for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
1816  if (HasBit(this->railtypes, rt)) total += RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total);
1817  }
1819 
1820  uint32_t road_total = c->infrastructure.GetRoadTotal();
1821  uint32_t tram_total = c->infrastructure.GetTramTotal();
1822  for (RoadType rt = ROADTYPE_BEGIN; rt != ROADTYPE_END; rt++) {
1823  if (HasBit(this->roadtypes, rt)) total += RoadMaintenanceCost(rt, c->infrastructure.road[rt], RoadTypeIsRoad(rt) ? road_total : tram_total);
1824  }
1825 
1828  total += AirportMaintenanceCost(c->index);
1829 
1830  return total;
1831  }
1832 
1833  void SetStringParameters(WidgetID widget) const override
1834  {
1835  switch (widget) {
1836  case WID_CI_CAPTION:
1837  SetDParam(0, (CompanyID)this->window_number);
1838  break;
1839  }
1840  }
1841 
1842  void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
1843  {
1844  const Company *c = Company::Get((CompanyID)this->window_number);
1845 
1846  switch (widget) {
1847  case WID_CI_RAIL_DESC: {
1848  uint lines = 1; // Starts at 1 because a line is also required for the section title
1849 
1850  size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT).width + padding.width);
1851 
1852  for (const auto &rt : _sorted_railtypes) {
1853  if (HasBit(this->railtypes, rt)) {
1854  lines++;
1855  size.width = std::max(size.width, GetStringBoundingBox(GetRailTypeInfo(rt)->strings.name).width + padding.width + WidgetDimensions::scaled.hsep_indent);
1856  }
1857  }
1858  if (this->railtypes != RAILTYPES_NONE) {
1859  lines++;
1860  size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS).width + padding.width + WidgetDimensions::scaled.hsep_indent);
1861  }
1862 
1863  size.height = std::max(size.height, lines * GetCharacterHeight(FS_NORMAL));
1864  break;
1865  }
1866 
1867  case WID_CI_ROAD_DESC:
1868  case WID_CI_TRAM_DESC: {
1869  uint lines = 1; // Starts at 1 because a line is also required for the section title
1870 
1871  size.width = std::max(size.width, GetStringBoundingBox(widget == WID_CI_ROAD_DESC ? STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT : STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT).width + padding.width);
1872 
1873  for (const auto &rt : _sorted_roadtypes) {
1874  if (HasBit(this->roadtypes, rt) && RoadTypeIsRoad(rt) == (widget == WID_CI_ROAD_DESC)) {
1875  lines++;
1876  size.width = std::max(size.width, GetStringBoundingBox(GetRoadTypeInfo(rt)->strings.name).width + padding.width + WidgetDimensions::scaled.hsep_indent);
1877  }
1878  }
1879 
1880  size.height = std::max(size.height, lines * GetCharacterHeight(FS_NORMAL));
1881  break;
1882  }
1883 
1884  case WID_CI_WATER_DESC:
1885  size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT).width + padding.width);
1886  size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS).width + padding.width + WidgetDimensions::scaled.hsep_indent);
1887  break;
1888 
1889  case WID_CI_STATION_DESC:
1890  size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT).width + padding.width);
1891  size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS).width + padding.width + WidgetDimensions::scaled.hsep_indent);
1892  size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS).width + padding.width + WidgetDimensions::scaled.hsep_indent);
1893  break;
1894 
1895  case WID_CI_RAIL_COUNT:
1896  case WID_CI_ROAD_COUNT:
1897  case WID_CI_TRAM_COUNT:
1898  case WID_CI_WATER_COUNT:
1899  case WID_CI_STATION_COUNT:
1900  case WID_CI_TOTAL: {
1901  /* Find the maximum count that is displayed. */
1902  uint32_t max_val = 1000; // Some random number to reserve enough space.
1903  Money max_cost = 10000; // Some random number to reserve enough space.
1904  uint32_t rail_total = c->infrastructure.GetRailTotal();
1905  for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) {
1906  max_val = std::max(max_val, c->infrastructure.rail[rt]);
1907  max_cost = std::max(max_cost, RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total));
1908  }
1909  max_val = std::max(max_val, c->infrastructure.signal);
1910  max_cost = std::max(max_cost, SignalMaintenanceCost(c->infrastructure.signal));
1911  uint32_t road_total = c->infrastructure.GetRoadTotal();
1912  uint32_t tram_total = c->infrastructure.GetTramTotal();
1913  for (RoadType rt = ROADTYPE_BEGIN; rt < ROADTYPE_END; rt++) {
1914  max_val = std::max(max_val, c->infrastructure.road[rt]);
1915  max_cost = std::max(max_cost, RoadMaintenanceCost(rt, c->infrastructure.road[rt], RoadTypeIsRoad(rt) ? road_total : tram_total));
1916 
1917  }
1918  max_val = std::max(max_val, c->infrastructure.water);
1919  max_cost = std::max(max_cost, CanalMaintenanceCost(c->infrastructure.water));
1920  max_val = std::max(max_val, c->infrastructure.station);
1921  max_cost = std::max(max_cost, StationMaintenanceCost(c->infrastructure.station));
1922  max_val = std::max(max_val, c->infrastructure.airport);
1923  max_cost = std::max(max_cost, AirportMaintenanceCost(c->index));
1924 
1925  SetDParamMaxValue(0, max_val);
1926  uint count_width = GetStringBoundingBox(STR_JUST_COMMA).width + WidgetDimensions::scaled.hsep_indent; // Reserve some wiggle room
1927 
1929  StringID str_total = TimerGameEconomy::UsingWallclockUnits() ? STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_PERIOD : STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_YEAR;
1930  SetDParamMaxValue(0, this->GetTotalMaintenanceCost() * 12); // Convert to per year
1931  this->total_width = GetStringBoundingBox(str_total).width + WidgetDimensions::scaled.hsep_indent * 2;
1932  size.width = std::max(size.width, this->total_width);
1933 
1934  SetDParamMaxValue(0, max_cost * 12); // Convert to per year
1935  count_width += std::max(this->total_width, GetStringBoundingBox(str_total).width);
1936  }
1937 
1938  size.width = std::max(size.width, count_width);
1939 
1940  /* Set height of the total line. */
1941  if (widget == WID_CI_TOTAL) {
1943  }
1944  break;
1945  }
1946  }
1947  }
1948 
1956  void DrawCountLine(const Rect &r, int &y, int count, Money monthly_cost) const
1957  {
1958  SetDParam(0, count);
1959  DrawString(r.left, r.right, y += GetCharacterHeight(FS_NORMAL), STR_JUST_COMMA, TC_WHITE, SA_RIGHT);
1960 
1962  SetDParam(0, monthly_cost * 12); // Convert to per year
1963  Rect tr = r.WithWidth(this->total_width, _current_text_dir == TD_RTL);
1964  DrawString(tr.left, tr.right, y,
1965  TimerGameEconomy::UsingWallclockUnits() ? STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_PERIOD : STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_YEAR,
1966  TC_FROMSTRING, SA_RIGHT);
1967  }
1968  }
1969 
1970  void DrawWidget(const Rect &r, WidgetID widget) const override
1971  {
1972  const Company *c = Company::Get((CompanyID)this->window_number);
1973 
1974  int y = r.top;
1975 
1977  switch (widget) {
1978  case WID_CI_RAIL_DESC:
1979  DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT);
1980 
1981  if (this->railtypes != RAILTYPES_NONE) {
1982  /* Draw name of each valid railtype. */
1983  for (const auto &rt : _sorted_railtypes) {
1984  if (HasBit(this->railtypes, rt)) {
1985  DrawString(ir.left, ir.right, y += GetCharacterHeight(FS_NORMAL), GetRailTypeInfo(rt)->strings.name, TC_WHITE);
1986  }
1987  }
1988  DrawString(ir.left, ir.right, y += GetCharacterHeight(FS_NORMAL), STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS);
1989  } else {
1990  /* No valid railtype. */
1991  DrawString(ir.left, ir.right, y += GetCharacterHeight(FS_NORMAL), STR_COMPANY_VIEW_INFRASTRUCTURE_NONE);
1992  }
1993 
1994  break;
1995 
1996  case WID_CI_RAIL_COUNT: {
1997  /* Draw infrastructure count for each valid railtype. */
1998  uint32_t rail_total = c->infrastructure.GetRailTotal();
1999  for (const auto &rt : _sorted_railtypes) {
2000  if (HasBit(this->railtypes, rt)) {
2001  this->DrawCountLine(r, y, c->infrastructure.rail[rt], RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total));
2002  }
2003  }
2004  if (this->railtypes != RAILTYPES_NONE) {
2006  }
2007  break;
2008  }
2009 
2010  case WID_CI_ROAD_DESC:
2011  case WID_CI_TRAM_DESC: {
2012  DrawString(r.left, r.right, y, widget == WID_CI_ROAD_DESC ? STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT : STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT);
2013 
2014  /* Draw name of each valid roadtype. */
2015  for (const auto &rt : _sorted_roadtypes) {
2016  if (HasBit(this->roadtypes, rt) && RoadTypeIsRoad(rt) == (widget == WID_CI_ROAD_DESC)) {
2017  DrawString(ir.left, ir.right, y += GetCharacterHeight(FS_NORMAL), GetRoadTypeInfo(rt)->strings.name, TC_WHITE);
2018  }
2019  }
2020 
2021  break;
2022  }
2023 
2024  case WID_CI_ROAD_COUNT:
2025  case WID_CI_TRAM_COUNT: {
2026  uint32_t road_tram_total = widget == WID_CI_ROAD_COUNT ? c->infrastructure.GetRoadTotal() : c->infrastructure.GetTramTotal();
2027  for (const auto &rt : _sorted_roadtypes) {
2028  if (HasBit(this->roadtypes, rt) && RoadTypeIsRoad(rt) == (widget == WID_CI_ROAD_COUNT)) {
2029  this->DrawCountLine(r, y, c->infrastructure.road[rt], RoadMaintenanceCost(rt, c->infrastructure.road[rt], road_tram_total));
2030  }
2031  }
2032  break;
2033  }
2034 
2035  case WID_CI_WATER_DESC:
2036  DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT);
2037  DrawString(ir.left, ir.right, y += GetCharacterHeight(FS_NORMAL), STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS);
2038  break;
2039 
2040  case WID_CI_WATER_COUNT:
2042  break;
2043 
2044  case WID_CI_TOTAL:
2046  Rect tr = r.WithWidth(this->total_width, _current_text_dir == TD_RTL);
2047  GfxFillRect(tr.left, y, tr.right, y + WidgetDimensions::scaled.bevel.top - 1, PC_WHITE);
2049  SetDParam(0, this->GetTotalMaintenanceCost() * 12); // Convert to per year
2050  DrawString(tr.left, tr.right, y,
2051  TimerGameEconomy::UsingWallclockUnits() ? STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_PERIOD : STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL_YEAR,
2052  TC_FROMSTRING, SA_RIGHT);
2053  }
2054  break;
2055 
2056  case WID_CI_STATION_DESC:
2057  DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT);
2058  DrawString(ir.left, ir.right, y += GetCharacterHeight(FS_NORMAL), STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS);
2059  DrawString(ir.left, ir.right, y += GetCharacterHeight(FS_NORMAL), STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS);
2060  break;
2061 
2062  case WID_CI_STATION_COUNT:
2065  break;
2066  }
2067  }
2068 
2074  void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
2075  {
2076  if (!gui_scope) return;
2077 
2078  this->UpdateRailRoadTypes();
2079  this->ReInit();
2080  }
2081 };
2082 
2083 static WindowDesc _company_infrastructure_desc(
2084  WDP_AUTO, "company_infrastructure", 0, 0,
2086  0,
2087  _nested_company_infrastructure_widgets
2088 );
2089 
2095 {
2096  if (!Company::IsValidID(company)) return;
2097  AllocateWindowDescFront<CompanyInfrastructureWindow>(_company_infrastructure_desc, company);
2098 }
2099 
2100 static constexpr NWidgetPart _nested_company_widgets[] = {
2102  NWidget(WWT_CLOSEBOX, COLOUR_GREY),
2103  NWidget(WWT_CAPTION, COLOUR_GREY, WID_C_CAPTION), SetDataTip(STR_COMPANY_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2104  NWidget(WWT_SHADEBOX, COLOUR_GREY),
2105  NWidget(WWT_STICKYBOX, COLOUR_GREY),
2106  EndContainer(),
2107  NWidget(WWT_PANEL, COLOUR_GREY),
2110  NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_FACE), SetMinimalSize(92, 119), SetFill(1, 0),
2111  NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_FACE_TITLE), SetFill(1, 1), SetMinimalTextLines(2, 0),
2112  EndContainer(),
2116  NWidget(WWT_TEXT, COLOUR_GREY, WID_C_DESC_INAUGURATION), SetDataTip(STR_JUST_STRING2, STR_NULL), SetFill(1, 0),
2118  NWidget(WWT_LABEL, COLOUR_GREY, WID_C_DESC_COLOUR_SCHEME), SetDataTip(STR_COMPANY_VIEW_COLOUR_SCHEME_TITLE, STR_NULL),
2119  NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_DESC_COLOUR_SCHEME_EXAMPLE), SetMinimalSize(30, 0), SetFill(1, 1),
2120  EndContainer(),
2122  NWidget(WWT_TEXT, COLOUR_GREY, WID_C_DESC_VEHICLE), SetDataTip(STR_COMPANY_VIEW_VEHICLES_TITLE, STR_NULL), SetAlignment(SA_LEFT | SA_TOP),
2123  NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_DESC_VEHICLE_COUNTS), SetMinimalTextLines(4, 0), SetFill(1, 1),
2124  EndContainer(),
2125  EndContainer(),
2128  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_VIEW_HQ), SetDataTip(STR_COMPANY_VIEW_VIEW_HQ_BUTTON, STR_COMPANY_VIEW_VIEW_HQ_TOOLTIP),
2129  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_C_BUILD_HQ), SetDataTip(STR_COMPANY_VIEW_BUILD_HQ_BUTTON, STR_COMPANY_VIEW_BUILD_HQ_TOOLTIP),
2130  EndContainer(),
2131  NWidget(NWID_SELECTION, INVALID_COLOUR, WID_C_SELECT_RELOCATE),
2132  NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_C_RELOCATE_HQ), SetDataTip(STR_COMPANY_VIEW_RELOCATE_HQ, STR_COMPANY_VIEW_RELOCATE_COMPANY_HEADQUARTERS),
2134  EndContainer(),
2135  EndContainer(),
2136  EndContainer(),
2137 
2138  NWidget(WWT_TEXT, COLOUR_GREY, WID_C_DESC_COMPANY_VALUE), SetDataTip(STR_COMPANY_VIEW_COMPANY_VALUE, STR_NULL), SetFill(1, 0),
2139 
2141  NWidget(WWT_TEXT, COLOUR_GREY, WID_C_DESC_INFRASTRUCTURE), SetDataTip(STR_COMPANY_VIEW_INFRASTRUCTURE, STR_NULL), SetAlignment(SA_LEFT | SA_TOP),
2143  NWidget(NWID_VERTICAL), SetPIPRatio(0, 0, 1),
2144  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_VIEW_INFRASTRUCTURE), SetDataTip(STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON, STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP),
2145  EndContainer(),
2146  EndContainer(),
2147 
2148  /* Multi player buttons. */
2149  NWidget(NWID_HORIZONTAL), SetPIP(0, WidgetDimensions::unscaled.hsep_normal, 0), SetPIPRatio(1, 0, 0),
2152  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_HOSTILE_TAKEOVER), SetDataTip(STR_COMPANY_VIEW_HOSTILE_TAKEOVER_BUTTON, STR_COMPANY_VIEW_HOSTILE_TAKEOVER_TOOLTIP),
2153  EndContainer(),
2155  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_GIVE_MONEY), SetDataTip(STR_COMPANY_VIEW_GIVE_MONEY_BUTTON, STR_COMPANY_VIEW_GIVE_MONEY_TOOLTIP),
2156  EndContainer(),
2158  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_COMPANY_JOIN), SetDataTip(STR_COMPANY_VIEW_JOIN, STR_COMPANY_VIEW_JOIN_TOOLTIP),
2159  EndContainer(),
2160  EndContainer(),
2161  EndContainer(),
2162  EndContainer(),
2163  EndContainer(),
2164  EndContainer(),
2165  /* Button bars at the bottom. */
2166  NWidget(NWID_SELECTION, INVALID_COLOUR, WID_C_SELECT_BUTTONS),
2168  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_NEW_FACE), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_NEW_FACE_BUTTON, STR_COMPANY_VIEW_NEW_FACE_TOOLTIP),
2169  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_COLOUR_SCHEME), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_COLOUR_SCHEME_BUTTON, STR_COMPANY_VIEW_COLOUR_SCHEME_TOOLTIP),
2170  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_PRESIDENT_NAME), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_PRESIDENT_NAME_BUTTON, STR_COMPANY_VIEW_PRESIDENT_NAME_TOOLTIP),
2171  NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_COMPANY_NAME), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_COMPANY_NAME_BUTTON, STR_COMPANY_VIEW_COMPANY_NAME_TOOLTIP),
2172  EndContainer(),
2173  EndContainer(),
2174 };
2175 
2178  STR_COMPANY_VIEW_TRAINS, STR_COMPANY_VIEW_ROAD_VEHICLES, STR_COMPANY_VIEW_SHIPS, STR_COMPANY_VIEW_AIRCRAFT
2179 };
2180 
2185 {
2186  CompanyWidgets query_widget;
2187 
2190  /* Display planes of the #WID_C_SELECT_VIEW_BUILD_HQ selection widget. */
2193 
2194  /* Display planes of the #WID_C_SELECT_RELOCATE selection widget. */
2197  };
2198 
2200  {
2201  this->InitNested(window_number);
2202  this->owner = (Owner)this->window_number;
2203  this->OnInvalidateData();
2204  }
2205 
2206  void OnPaint() override
2207  {
2208  const Company *c = Company::Get((CompanyID)this->window_number);
2209  bool local = this->window_number == _local_company;
2210 
2211  if (!this->IsShaded()) {
2212  bool reinit = false;
2213 
2214  /* Button bar selection. */
2215  reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_BUTTONS)->SetDisplayedPlane(local ? 0 : SZSP_NONE);
2216 
2217  /* Build HQ button handling. */
2218  reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_VIEW_BUILD_HQ)->SetDisplayedPlane((local && c->location_of_HQ == INVALID_TILE) ? CWP_VB_BUILD : CWP_VB_VIEW);
2219 
2221 
2222  /* Enable/disable 'Relocate HQ' button. */
2223  reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_RELOCATE)->SetDisplayedPlane((!local || c->location_of_HQ == INVALID_TILE) ? CWP_RELOCATE_HIDE : CWP_RELOCATE_SHOW);
2224  /* Enable/disable 'Give money' button. */
2225  reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_GIVE_MONEY)->SetDisplayedPlane((local || _local_company == COMPANY_SPECTATOR || !_settings_game.economy.give_money) ? SZSP_NONE : 0);
2226  /* Enable/disable 'Hostile Takeover' button. */
2227  reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_HOSTILE_TAKEOVER)->SetDisplayedPlane((local || _local_company == COMPANY_SPECTATOR || !c->is_ai || _networking) ? SZSP_NONE : 0);
2228 
2229  /* Multiplayer buttons. */
2230  reinit |= this->GetWidget<NWidgetStacked>(WID_C_SELECT_MULTIPLAYER)->SetDisplayedPlane((!_networking || !NetworkCanJoinCompany(c->index) || _local_company == c->index) ? (int)SZSP_NONE : 0);
2231 
2233 
2234  if (reinit) {
2235  this->ReInit();
2236  return;
2237  }
2238  }
2239 
2240  this->DrawWidgets();
2241  }
2242 
2243  void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2244  {
2245  switch (widget) {
2246  case WID_C_FACE:
2247  size = maxdim(size, GetScaledSpriteSize(SPR_GRADIENT));
2248  break;
2249 
2251  Point offset;
2252  Dimension d = GetSpriteSize(SPR_VEH_BUS_SW_VIEW, &offset);
2253  d.width -= offset.x;
2254  d.height -= offset.y;
2255  size = maxdim(size, d);
2256  break;
2257  }
2258 
2260  SetDParam(0, INT64_MAX); // Arguably the maximum company value
2261  size.width = GetStringBoundingBox(STR_COMPANY_VIEW_COMPANY_VALUE).width;
2262  break;
2263 
2265  SetDParamMaxValue(0, 5000); // Maximum number of vehicles
2266  for (const auto &count_string : _company_view_vehicle_count_strings) {
2267  size.width = std::max(size.width, GetStringBoundingBox(count_string).width + padding.width);
2268  }
2269  break;
2270 
2272  SetDParamMaxValue(0, UINT_MAX);
2273  size.width = GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL).width;
2274  size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD).width);
2275  size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_WATER).width);
2276  size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_STATION).width);
2277  size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT).width);
2278  size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_NONE).width);
2279  size.width += padding.width;
2280  break;
2281 
2282  case WID_C_VIEW_HQ:
2283  case WID_C_BUILD_HQ:
2284  case WID_C_RELOCATE_HQ:
2286  case WID_C_GIVE_MONEY:
2288  case WID_C_COMPANY_JOIN:
2289  size.width = GetStringBoundingBox(STR_COMPANY_VIEW_VIEW_HQ_BUTTON).width;
2290  size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_BUILD_HQ_BUTTON).width);
2291  size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_RELOCATE_HQ).width);
2292  size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON).width);
2293  size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_GIVE_MONEY_BUTTON).width);
2294  size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_HOSTILE_TAKEOVER_BUTTON).width);
2295  size.width = std::max(size.width, GetStringBoundingBox(STR_COMPANY_VIEW_JOIN).width);
2296  size.width += padding.width;
2297  break;
2298  }
2299  }
2300 
2301  void DrawVehicleCountsWidget(const Rect &r, const Company *c) const
2302  {
2304 
2305  int y = r.top;
2306  for (VehicleType type = VEH_BEGIN; type < VEH_COMPANY_END; type++) {
2307  uint amount = c->group_all[type].num_vehicle;
2308  if (amount != 0) {
2309  SetDParam(0, amount);
2310  DrawString(r.left, r.right, y, _company_view_vehicle_count_strings[type]);
2312  }
2313  }
2314 
2315  if (y == r.top) {
2316  /* No String was emited before, so there must be no vehicles at all. */
2317  DrawString(r.left, r.right, y, STR_COMPANY_VIEW_VEHICLES_NONE);
2318  }
2319  }
2320 
2321  void DrawInfrastructureCountsWidget(const Rect &r, const Company *c) const
2322  {
2323  int y = r.top;
2324 
2325  uint rail_pieces = c->infrastructure.signal + c->infrastructure.GetRailTotal();
2326  if (rail_pieces != 0) {
2327  SetDParam(0, rail_pieces);
2328  DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL);
2330  }
2331 
2332  /* GetRoadTotal() skips tram pieces, but we actually want road and tram here. */
2333  uint road_pieces = std::accumulate(std::begin(c->infrastructure.road), std::end(c->infrastructure.road), 0U);
2334  if (road_pieces != 0) {
2335  SetDParam(0, road_pieces);
2336  DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD);
2338  }
2339 
2340  if (c->infrastructure.water != 0) {
2342  DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_WATER);
2344  }
2345 
2346  if (c->infrastructure.station != 0) {
2348  DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_STATION);
2350  }
2351 
2352  if (c->infrastructure.airport != 0) {
2354  DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT);
2356  }
2357 
2358  if (y == r.top) {
2359  /* No String was emited before, so there must be no infrastructure at all. */
2360  DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE);
2361  }
2362  }
2363 
2364  void DrawWidget(const Rect &r, WidgetID widget) const override
2365  {
2366  const Company *c = Company::Get((CompanyID)this->window_number);
2367  switch (widget) {
2368  case WID_C_FACE:
2369  DrawCompanyManagerFace(c->face, c->colour, r);
2370  break;
2371 
2372  case WID_C_FACE_TITLE:
2373  SetDParam(0, c->index);
2374  DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE, TC_FROMSTRING, SA_HOR_CENTER);
2375  break;
2376 
2378  Point offset;
2379  Dimension d = GetSpriteSize(SPR_VEH_BUS_SW_VIEW, &offset);
2380  d.height -= offset.y;
2381  DrawSprite(SPR_VEH_BUS_SW_VIEW, COMPANY_SPRITE_COLOUR(c->index), r.left - offset.x, CenterBounds(r.top, r.bottom, d.height) - offset.y);
2382  break;
2383  }
2384 
2386  DrawVehicleCountsWidget(r, c);
2387  break;
2388 
2390  DrawInfrastructureCountsWidget(r, c);
2391  break;
2392  }
2393  }
2394 
2395  void SetStringParameters(WidgetID widget) const override
2396  {
2397  switch (widget) {
2398  case WID_C_CAPTION:
2399  SetDParam(0, (CompanyID)this->window_number);
2400  SetDParam(1, (CompanyID)this->window_number);
2401  break;
2402 
2405  SetDParam(0, STR_COMPANY_VIEW_INAUGURATED_TITLE_WALLCLOCK);
2406  SetDParam(1, Company::Get(static_cast<CompanyID>(this->window_number))->inaugurated_year_calendar);
2407  SetDParam(2, Company::Get(static_cast<CompanyID>(this->window_number))->inaugurated_year);
2408  } else {
2409  SetDParam(0, STR_COMPANY_VIEW_INAUGURATED_TITLE);
2410  SetDParam(1, Company::Get(static_cast<CompanyID>(this->window_number))->inaugurated_year);
2411  }
2412  break;
2413 
2416  break;
2417  }
2418  }
2419 
2420  void OnResize() override
2421  {
2422  NWidgetResizeBase *wid = this->GetWidget<NWidgetResizeBase>(WID_C_FACE_TITLE);
2423  SetDParam(0, this->owner);
2424  int y = GetStringHeight(STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE, wid->current_x);
2425  if (wid->UpdateVerticalSize(y)) this->ReInit(0, 0);
2426  }
2427 
2428  void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2429  {
2430  switch (widget) {
2431  case WID_C_NEW_FACE: DoSelectCompanyManagerFace(this); break;
2432 
2433  case WID_C_COLOUR_SCHEME:
2434  ShowCompanyLiveryWindow((CompanyID)this->window_number, INVALID_GROUP);
2435  break;
2436 
2437  case WID_C_PRESIDENT_NAME:
2438  this->query_widget = WID_C_PRESIDENT_NAME;
2439  SetDParam(0, this->window_number);
2440  ShowQueryString(STR_PRESIDENT_NAME, STR_COMPANY_VIEW_PRESIDENT_S_NAME_QUERY_CAPTION, MAX_LENGTH_PRESIDENT_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS);
2441  break;
2442 
2443  case WID_C_COMPANY_NAME:
2444  this->query_widget = WID_C_COMPANY_NAME;
2445  SetDParam(0, this->window_number);
2446  ShowQueryString(STR_COMPANY_NAME, STR_COMPANY_VIEW_COMPANY_NAME_QUERY_CAPTION, MAX_LENGTH_COMPANY_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS);
2447  break;
2448 
2449  case WID_C_VIEW_HQ: {
2450  TileIndex tile = Company::Get((CompanyID)this->window_number)->location_of_HQ;
2451  if (_ctrl_pressed) {
2453  } else {
2454  ScrollMainWindowToTile(tile);
2455  }
2456  break;
2457  }
2458 
2459  case WID_C_BUILD_HQ:
2460  if ((uint8_t)this->window_number != _local_company) return;
2461  if (this->IsWidgetLowered(WID_C_BUILD_HQ)) {
2463  this->RaiseButtons();
2464  break;
2465  }
2466  SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, HT_RECT, this);
2467  SetTileSelectSize(2, 2);
2468  this->LowerWidget(WID_C_BUILD_HQ);
2470  break;
2471 
2472  case WID_C_RELOCATE_HQ:
2473  if (this->IsWidgetLowered(WID_C_RELOCATE_HQ)) {
2475  this->RaiseButtons();
2476  break;
2477  }
2478  SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, HT_RECT, this);
2479  SetTileSelectSize(2, 2);
2482  break;
2483 
2486  break;
2487 
2488  case WID_C_GIVE_MONEY:
2489  this->query_widget = WID_C_GIVE_MONEY;
2490  ShowQueryString(STR_EMPTY, STR_COMPANY_VIEW_GIVE_MONEY_QUERY_CAPTION, 30, this, CS_NUMERAL, QSF_NONE);
2491  break;
2492 
2495  break;
2496 
2497  case WID_C_COMPANY_JOIN: {
2498  this->query_widget = WID_C_COMPANY_JOIN;
2499  CompanyID company = (CompanyID)this->window_number;
2500  if (_network_server) {
2503  } else {
2504  /* just send the join command */
2505  NetworkClientRequestMove(company);
2506  }
2507  break;
2508  }
2509  }
2510  }
2511 
2513  IntervalTimer<TimerWindow> redraw_interval = {std::chrono::seconds(3), [this](auto) {
2514  this->SetDirty();
2515  }};
2516 
2517  void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
2518  {
2519  if (Command<CMD_BUILD_OBJECT>::Post(STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS, tile, OBJECT_HQ, 0) && !_shift_pressed) {
2521  this->RaiseButtons();
2522  }
2523  }
2524 
2525  void OnPlaceObjectAbort() override
2526  {
2527  this->RaiseButtons();
2528  }
2529 
2530  void OnQueryTextFinished(std::optional<std::string> str) override
2531  {
2532  if (!str.has_value()) return;
2533 
2534  switch (this->query_widget) {
2535  default: NOT_REACHED();
2536 
2537  case WID_C_GIVE_MONEY: {
2538  Money money = std::strtoull(str->c_str(), nullptr, 10) / GetCurrency().rate;
2539  Command<CMD_GIVE_MONEY>::Post(STR_ERROR_CAN_T_GIVE_MONEY, money, (CompanyID)this->window_number);
2540  break;
2541  }
2542 
2543  case WID_C_PRESIDENT_NAME:
2544  Command<CMD_RENAME_PRESIDENT>::Post(STR_ERROR_CAN_T_CHANGE_PRESIDENT, *str);
2545  break;
2546 
2547  case WID_C_COMPANY_NAME:
2548  Command<CMD_RENAME_COMPANY>::Post(STR_ERROR_CAN_T_CHANGE_COMPANY_NAME, *str);
2549  break;
2550  }
2551  }
2552 
2553  void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
2554  {
2555  if (gui_scope && data == 1) {
2556  /* Manually call OnResize to adjust minimum height of president name widget. */
2557  OnResize();
2558  }
2559  }
2560 };
2561 
2562 static WindowDesc _company_desc(
2563  WDP_AUTO, "company", 0, 0,
2565  0,
2566  _nested_company_widgets
2567 );
2568 
2573 void ShowCompany(CompanyID company)
2574 {
2575  if (!Company::IsValidID(company)) return;
2576 
2577  AllocateWindowDescFront<CompanyWindow>(_company_desc, company);
2578 }
2579 
2585 {
2586  SetWindowDirty(WC_COMPANY, company);
2588 }
2589 
2592  {
2593  this->InitNested(window_number);
2594 
2595  const Company *c = Company::Get((CompanyID)this->window_number);
2596  this->company_value = hostile_takeover ? CalculateHostileTakeoverValue(c) : c->bankrupt_value;
2597  }
2598 
2599  void UpdateWidgetSize(WidgetID widget, Dimension &size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension &fill, [[maybe_unused]] Dimension &resize) override
2600  {
2601  switch (widget) {
2602  case WID_BC_FACE:
2603  size = GetScaledSpriteSize(SPR_GRADIENT);
2604  break;
2605 
2606  case WID_BC_QUESTION:
2607  const Company *c = Company::Get((CompanyID)this->window_number);
2608  SetDParam(0, c->index);
2609  SetDParam(1, this->company_value);
2610  size.height = GetStringHeight(this->hostile_takeover ? STR_BUY_COMPANY_HOSTILE_TAKEOVER : STR_BUY_COMPANY_MESSAGE, size.width);
2611  break;
2612  }
2613  }
2614 
2615  void SetStringParameters(WidgetID widget) const override
2616  {
2617  switch (widget) {
2618  case WID_BC_CAPTION:
2619  SetDParam(0, STR_COMPANY_NAME);
2620  SetDParam(1, Company::Get((CompanyID)this->window_number)->index);
2621  break;
2622  }
2623  }
2624 
2625  void DrawWidget(const Rect &r, WidgetID widget) const override
2626  {
2627  switch (widget) {
2628  case WID_BC_FACE: {
2629  const Company *c = Company::Get((CompanyID)this->window_number);
2630  DrawCompanyManagerFace(c->face, c->colour, r);
2631  break;
2632  }
2633 
2634  case WID_BC_QUESTION: {
2635  const Company *c = Company::Get((CompanyID)this->window_number);
2636  SetDParam(0, c->index);
2637  SetDParam(1, this->company_value);
2638  DrawStringMultiLine(r.left, r.right, r.top, r.bottom, this->hostile_takeover ? STR_BUY_COMPANY_HOSTILE_TAKEOVER : STR_BUY_COMPANY_MESSAGE, TC_FROMSTRING, SA_CENTER);
2639  break;
2640  }
2641  }
2642  }
2643 
2644  void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
2645  {
2646  switch (widget) {
2647  case WID_BC_NO:
2648  this->Close();
2649  break;
2650 
2651  case WID_BC_YES:
2652  Command<CMD_BUY_COMPANY>::Post(STR_ERROR_CAN_T_BUY_COMPANY, (CompanyID)this->window_number, this->hostile_takeover);
2653  break;
2654  }
2655  }
2656 
2660  IntervalTimer<TimerWindow> rescale_interval = {std::chrono::seconds(3), [this](auto) {
2661  /* Value can't change when in bankruptcy. */
2662  if (!this->hostile_takeover) return;
2663 
2664  const Company *c = Company::Get((CompanyID)this->window_number);
2665  auto new_value = CalculateHostileTakeoverValue(c);
2666  if (new_value != this->company_value) {
2667  this->company_value = new_value;
2668  this->ReInit();
2669  }
2670  }};
2671 
2672 private:
2675 };
2676 
2677 static constexpr NWidgetPart _nested_buy_company_widgets[] = {
2679  NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
2680  NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE, WID_BC_CAPTION), SetDataTip(STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
2681  EndContainer(),
2682  NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE),
2685  NWidget(WWT_EMPTY, INVALID_COLOUR, WID_BC_FACE), SetFill(0, 1),
2686  NWidget(WWT_EMPTY, INVALID_COLOUR, WID_BC_QUESTION), SetMinimalSize(240, 0), SetFill(1, 1),
2687  EndContainer(),
2689  NWidget(WWT_TEXTBTN, COLOUR_LIGHT_BLUE, WID_BC_NO), SetMinimalSize(60, 12), SetDataTip(STR_QUIT_NO, STR_NULL), SetFill(1, 0),
2690  NWidget(WWT_TEXTBTN, COLOUR_LIGHT_BLUE, WID_BC_YES), SetMinimalSize(60, 12), SetDataTip(STR_QUIT_YES, STR_NULL), SetFill(1, 0),
2691  EndContainer(),
2692  EndContainer(),
2693  EndContainer(),
2694 };
2695 
2696 static WindowDesc _buy_company_desc(
2697  WDP_AUTO, nullptr, 0, 0,
2700  _nested_buy_company_widgets
2701 );
2702 
2708 void ShowBuyCompanyDialog(CompanyID company, bool hostile_takeover)
2709 {
2710  auto window = BringWindowToFrontById(WC_BUY_COMPANY, company);
2711  if (window == nullptr) {
2712  new BuyCompanyWindow(_buy_company_desc, company, hostile_takeover);
2713  }
2714 }
constexpr debug_inline 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.
constexpr static debug_inline 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.
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.
Baseclass for nested widgets.
Definition: widget_type.h:144
uint current_x
Current horizontal size (after resizing).
Definition: widget_type.h:243
Base class for a 'real' widget.
Definition: widget_type.h:370
bool IsDisabled() const
Return whether the widget is disabled.
Definition: widget_type.h:449
void SetDataTip(uint32_t widget_data, StringID tool_tip)
Set data and tool tip of the nested widget.
Definition: widget.cpp:1130
Base class for a resizable nested widget.
Definition: widget_type.h:303
bool UpdateVerticalSize(uint min_y)
Set absolute (post-scaling) minimal size of the widget.
Definition: widget.cpp:1092
RailTypes introduces_railtypes
Bitmask of which other railtypes are introduced when this railtype is introduced.
Definition: rail.h:266
StringID name
Name of this rail type.
Definition: rail.h:176
RoadTypes introduces_roadtypes
Bitmask of which other roadtypes are introduced when this roadtype is introduced.
Definition: road.h:177
StringID name
Name of this rail type.
Definition: road.h:103
Scrollbar data structure.
Definition: widget_type.h:694
size_type GetCapacity() const
Gets the number of visible elements of the scrollbar.
Definition: widget_type.h:731
void SetCount(size_t num)
Sets the number of elements in the list.
Definition: widget_type.h:780
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.
Definition: widget_type.h:879
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:2320
bool SetPosition(size_type position)
Sets the position of the first visible element.
Definition: widget_type.h:810
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:2394
size_type GetCount() const
Gets the number of elements in the list.
Definition: widget_type.h:722
auto GetVisibleRangeIterators(Tcontainer &container) const
Get a pair of iterators for the range of visible elements in a container.
Definition: widget_type.h:860
size_type GetPosition() const
Gets the position of the first visible element in the list.
Definition: widget_type.h:740
Management class for customizing the face of the company manager.
void SelectDisplayPlanes(bool advanced)
Select planes to display to the user with the NWID_SELECTION widgets WID_SCMF_SEL_LOADSAVE,...
bool advanced
advanced company manager face selection window
bool is_moust_male
Male face with a moustache.
GenderEthnicity ge
Gender and ethnicity.
void SetFaceStringParameters(WidgetID widget_index, uint8_t val, bool is_bool_widget) const
Set parameters for value of face control buttons.
Dimension yesno_dim
Dimension of a yes/no button of a part in the advanced face window.
CompanyManagerFace face
company manager face bits
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 constexpr TimerGame< struct Calendar >::Date MAX_DATE
The date of the last day of the max year.
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:42
static WidgetDimensions scaled
Widget dimensions scaled for current zoom level.
Definition: window_gui.h:68
RectPadding imgbtn
Padding around image button image.
Definition: window_gui.h:36
int vsep_normal
Normal vertical spacing.
Definition: window_gui.h:60
int vsep_wide
Wide vertical spacing.
Definition: window_gui.h:62
static const WidgetDimensions unscaled
Unscaled widget dimensions.
Definition: window_gui.h:67
int hsep_normal
Normal horizontal spacing.
Definition: window_gui.h:63
RectPadding bevel
Bevel thickness, affected by "scaled bevels" game option.
Definition: window_gui.h:40
int hsep_indent
Width of identation for tree layouts.
Definition: window_gui.h:65
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:176
Money CalculateCompanyValue(const Company *c, bool including_loan=true)
Calculate the value of the company.
Definition: economy.cpp:149
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition: company_cmd.cpp:52
CompanyManagerFace _company_manager_face
for company manager face storage in openttd.cfg
Definition: company_cmd.cpp:55
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 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.
Definition: company_gui.cpp:78
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 WindowDesc _select_company_manager_face_desc(WDP_AUTO, nullptr, 0, 0, WC_COMPANY_MANAGER_FACE, WC_NONE, WDF_CONSTRUCTION, _nested_select_company_manager_face_widgets)
Company manager face selection window description.
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.
Definition: company_gui.cpp:68
static uint GetTotalCategoriesHeight()
Get the total height of the "categories" column.
static const std::initializer_list< ExpensesType > _expenses_list_revenue
List of revenues.
Definition: company_gui.cpp:60
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.
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.
uint GetCompanyManagerFaceBits(CompanyManagerFace cmf, CompanyManagerFaceVariable cmfv, [[maybe_unused]] GenderEthnicity ge)
Make sure the table's size is right.
static const CompanyManagerFaceBitsInfo _cmf_info[]
Lookup table for indices into the CompanyManagerFace, valid ranges and sprites.
void SetCompanyManagerFaceBits(CompanyManagerFace &cmf, CompanyManagerFaceVariable cmfv, [[maybe_unused]] GenderEthnicity ge, uint val)
Sets the company manager's face bits for the given company manager's face variable.
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'.
Definition: company_type.h:40
static const uint MAX_LENGTH_COMPANY_NAME_CHARS
The maximum length of a company name in characters including '\0'.
Definition: company_type.h:41
uint32_t CompanyManagerFace
Company manager face bits, info see in company_manager_face.h.
Definition: company_type.h:52
Owner
Enum for all companies/owners.
Definition: company_type.h:18
@ COMPANY_SPECTATOR
The client is spectating.
Definition: company_type.h:35
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_RAIL_COUNT
Count of rail.
@ WID_CI_WATER_DESC
Description of water.
@ WID_CI_TRAM_COUNT
Count of tram.
@ WID_CI_ROAD_DESC
Description of road.
@ WID_CI_CAPTION
Caption of window.
@ WID_CI_STATION_DESC
Description of station.
@ WID_CI_WATER_COUNT
Count of water.
@ WID_CI_TOTAL_DESC
Description of total.
@ WID_CI_TOTAL
Count of total.
@ WID_CI_STATION_COUNT
Count of station.
@ WID_CI_TRAM_DESC
Description of tram.
@ WID_CI_RAIL_DESC
Description of rail.
@ WID_CI_ROAD_COUNT
Count of road.
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:117
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:404
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.
Definition: dropdown_type.h:50
Command definitions related to the economy.
std::array< Money, EXPENSES_END > Expenses
Data type for storage of Money for each ExpensesType category.
Definition: economy_type.h:193
ExpensesType
Types of expenses.
Definition: economy_type.h:172
@ EXPENSES_ROADVEH_RUN
Running costs road vehicles.
Definition: economy_type.h:176
@ EXPENSES_TRAIN_RUN
Running costs trains.
Definition: economy_type.h:175
@ EXPENSES_AIRCRAFT_REVENUE
Revenue from aircraft.
Definition: economy_type.h:182
@ EXPENSES_CONSTRUCTION
Construction costs.
Definition: economy_type.h:173
@ EXPENSES_AIRCRAFT_RUN
Running costs aircraft.
Definition: economy_type.h:177
@ EXPENSES_ROADVEH_REVENUE
Revenue from road vehicles.
Definition: economy_type.h:181
@ EXPENSES_PROPERTY
Property costs.
Definition: economy_type.h:179
@ EXPENSES_OTHER
Other expenses.
Definition: economy_type.h:185
@ EXPENSES_SHIP_REVENUE
Revenue from ships.
Definition: economy_type.h:183
@ EXPENSES_LOAN_INTEREST
Interest payments over the loan.
Definition: economy_type.h:184
@ EXPENSES_TRAIN_REVENUE
Revenue from trains.
Definition: economy_type.h:180
@ EXPENSES_SHIP_RUN
Running costs ships.
Definition: economy_type.h:178
@ EXPENSES_NEW_VEHICLES
New vehicles.
Definition: economy_type.h:174
static const int LOAN_INTERVAL
The "steps" in loan size, in British Pounds!
Definition: economy_type.h:215
Base class for engines.
Functions related to errors.
void ShowErrorMessage(StringID summary_msg, int x, int y, CommandCost cc)
Display an error message in a window.
Definition: error_gui.cpp:367
@ WL_INFO
Used for DoCommand-like (and some non-fatal AI GUI) errors/information.
Definition: error.h:24
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 GetStringHeight(std::string_view str, int maxw, FontSize fontsize)
Calculates height of string (in pixels).
Definition: gfx.cpp:704
Dimension GetSpriteSize(SpriteID sprid, Point *offset, ZoomLevel zoom)
Get the size of a sprite.
Definition: gfx.cpp:922
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:851
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:657
bool _ctrl_pressed
Is Ctrl pressed?
Definition: gfx.cpp:38
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:114
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:988
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:774
Dimension GetScaledSpriteSize(SpriteID sprid)
Scale sprite size for GUI.
Definition: widget.cpp:54
int CenterBounds(int min, int max, int size)
Determine where to draw a centred object inside a widget.
Definition: gfx_func.h:166
@ SA_TOP
Top align the text.
Definition: gfx_type.h:348
@ SA_LEFT
Left align the text.
Definition: gfx_type.h:343
@ SA_RIGHT
Right align the text (must be a single bit).
Definition: gfx_type.h:345
@ SA_HOR_CENTER
Horizontally center the text.
Definition: gfx_type.h:344
@ SA_CENTER
Center both horizontally and vertically.
Definition: gfx_type.h:353
@ SA_VERT_CENTER
Vertically center the text.
Definition: gfx_type.h:349
@ FS_NORMAL
Index of the normal font in the font tables.
Definition: gfx_type.h:209
uint32_t PaletteID
The number of the palette.
Definition: gfx_type.h:19
TextColour
Colour of the strings, see _string_colourmap in table/string_colours.h or docs/ottd-colourtext-palett...
Definition: gfx_type.h:260
constexpr NWidgetPart SetFill(uint16_t fill_x, uint16_t fill_y)
Widget part function for setting filling.
Definition: widget_type.h:1181
constexpr NWidgetPart SetPIP(uint8_t pre, uint8_t inter, uint8_t post)
Widget part function for setting a pre/inter/post spaces.
Definition: widget_type.h:1260
constexpr NWidgetPart SetScrollbar(WidgetID index)
Attach a scrollbar to a widget.
Definition: widget_type.h:1284
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.
Definition: widget_type.h:1228
constexpr NWidgetPart SetDataTip(uint32_t data, StringID tip)
Widget part function for setting the data and tooltip.
Definition: widget_type.h:1202
constexpr NWidgetPart SetTextStyle(TextColour colour, FontSize size=FS_NORMAL)
Widget part function for setting the text style.
Definition: widget_type.h:1160
constexpr NWidgetPart SetMinimalSize(int16_t x, int16_t y)
Widget part function for setting the minimal size.
Definition: widget_type.h:1137
constexpr NWidgetPart NWidget(WidgetType tp, Colours col, WidgetID idx=-1)
Widget part function for starting a new 'real' widget.
Definition: widget_type.h:1309
constexpr NWidgetPart SetMatrixDataTip(uint8_t cols, uint8_t rows, StringID tip)
Widget part function for setting the data and tooltip of WWT_MATRIX widgets.
Definition: widget_type.h:1214
constexpr NWidgetPart EndContainer()
Widget part function for denoting the end of a container (horizontal, vertical, WWT_FRAME,...
Definition: widget_type.h:1191
constexpr NWidgetPart SetMinimalTextLines(uint8_t lines, uint8_t spacing, FontSize size=FS_NORMAL)
Widget part function for setting the minimal text lines.
Definition: widget_type.h:1149
constexpr NWidgetPart SetAlignment(StringAlignment align)
Widget part function for setting the alignment of text/images.
Definition: widget_type.h:1170
constexpr NWidgetPart SetAspect(float ratio, AspectFlags flags=AspectFlags::ResizeX)
Widget part function for setting the aspect ratio.
Definition: widget_type.h:1295
constexpr NWidgetPart SetResize(int16_t dx, int16_t dy)
Widget part function for setting the resize step.
Definition: widget_type.h:1126
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.
Definition: widget_type.h:1272
Command definitions related to engine groups.
void SetDirty() const
Mark entire window as dirty (in need of re-paint)
Definition: window.cpp:940
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition: gfx.cpp:1529
void BuildGuiGroupList(GUIGroupList &dst, bool fold, Owner owner, VehicleType veh_type)
Build GUI group list, a sorted hierarchical list of groups for owner and vehicle type.
Definition: group_gui.cpp:156
Functions/definitions that have something to do with groups.
uint16_t GroupID
Type for all group identifiers.
Definition: group_type.h:13
static const GroupID INVALID_GROUP
Sentinel for invalid groups.
Definition: group_type.h:18
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(StringID str, StringID caption, uint maxsize, Window *parent, CharSetFilter afilter, QueryStringFlags flags)
Show a query popup window with a textbox in it.
Definition: misc_gui.cpp:1079
bool _networking
are we in networking mode?
Definition: network.cpp:65
bool _network_server
network-server is active
Definition: network.cpp:66
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.
Definition: network_type.h:51
GRFLoadedFeatures _loaded_newgrf_features
Indicates which are the newgrf features currently loaded ingame.
Definition: newgrf.cpp:84
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:20
static const uint8_t PC_WHITE
White palette colour.
Definition: palette_func.h:70
static const uint8_t PC_BLACK
Black palette colour.
Definition: palette_func.h:67
RailTypes AddDateIntroducedRailTypes(RailTypes current, TimerGameCalendar::Date date)
Add the rail types that are to be introduced at the given date.
Definition: rail.cpp:218
Rail specific functions.
const RailTypeInfo * GetRailTypeInfo(RailType railtype)
Returns a pointer to the Railtype information for a given railtype.
Definition: rail.h:307
Money RailMaintenanceCost(RailType railtype, uint32_t num, uint32_t total_num)
Calculates the maintenance cost of a number of track bits.
Definition: rail.h:430
Money SignalMaintenanceCost(uint32_t num)
Calculates the maintenance cost of a number of signals.
Definition: rail.h:441
RailTypes
Allow incrementing of Track variables.
Definition: rail_type.h:44
@ RAILTYPES_NONE
No rail types.
Definition: rail_type.h:45
RailType
Enumeration for all possible railtypes.
Definition: rail_type.h:27
@ RAILTYPE_BEGIN
Used for iterations.
Definition: rail_type.h:28
@ RAILTYPE_END
Used for iterations.
Definition: rail_type.h:33
Randomizer _interactive_random
Random used everywhere else, where it does not (directly) influence the game state.
Definition: random_func.cpp:37
RoadTypes AddDateIntroducedRoadTypes(RoadTypes current, TimerGameCalendar::Date date)
Add the road types that are to be introduced at the given date.
Definition: road.cpp:166
Road specific functions.
const RoadTypeInfo * GetRoadTypeInfo(RoadType roadtype)
Returns a pointer to the Roadtype information for a given roadtype.
Definition: road.h:227
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
RoadTypes
The different roadtypes we support, but then a bitmask of them.
Definition: road_type.h:38
@ ROADTYPES_NONE
No roadtypes.
Definition: road_type.h:39
RoadType
The different roadtypes we support.
Definition: road_type.h:25
@ ROADTYPE_END
Used for iterations.
Definition: road_type.h:29
@ ROADTYPE_BEGIN
Used for iterations.
Definition: road_type.h:26
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:57
ClientSettings _settings_client
The current settings for this game.
Definition: settings.cpp:56
Base types for having sorted lists in GUIs.
Money AirportMaintenanceCost(Owner owner)
Calculates the maintenance cost of all airports of a company.
Definition: station.cpp:709
Functions related to stations.
Money StationMaintenanceCost(uint32_t num)
Calculates the maintenance cost of a number of station tiles.
Definition: station_func.h:60
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:280
@ 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
void SetDParamMaxValue(size_t n, uint64_t max_value, uint min_count, FontSize size)
Set DParam n to some number that is suitable for string size computations.
Definition: strings.cpp:127
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
Definition: strings.cpp:104
TextDirection _current_text_dir
Text direction of the currently selected language.
Definition: strings.cpp:56
Functions related to OTTD's strings.
@ TD_RTL
Text is written right-to-left by default.
Definition: strings_type.h:24
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:16
static const StringID INVALID_STRING_ID
Constant representing an invalid string (16bit in case it is used in savegames)
Definition: strings_type.h:17
Money company_value
The value of the company for which the user can buy it.
IntervalTimer< TimerWindow > rescale_interval
Check on a regular interval if the company value has changed.
bool hostile_takeover
Whether the window is showing a hostile takeover.
GUISettings gui
settings related to the GUI
Window class displaying the company finances.
bool small
Window is toggled to 'small'.
static Money max_money
The maximum amount of money a company has had this 'run'.
void SetupWidgets()
Setup the widgets in the nested tree, such that the finances window is displayed properly.
IntervalTimer< TimerWindow > rescale_interval
Check on a regular interval if the maximum amount of money has changed.
void OnPaint() override
The window must be repainted.
Window with detailed information about the company's infrastructure.
Money GetTotalMaintenanceCost() const
Get total infrastructure maintenance cost.
void DrawCountLine(const Rect &r, int &y, int count, Money monthly_cost) const
Helper for drawing the counts line.
RoadTypes roadtypes
Valid roadtypes.
uint total_width
String width of the total cost line.
RailTypes railtypes
Valid railtypes.
void OnInvalidateData([[maybe_unused]] int data=0, [[maybe_unused]] bool gui_scope=true) override
Some data on this window has become invalid.
std::array< uint32_t, ROADTYPE_END > road
Count of company owned track bits for each road type.
Definition: company_base.h:34
uint32_t GetRailTotal() const
Get total sum of all owned track bits.
Definition: company_base.h:43
uint32_t GetRoadTotal() const
Get total sum of all owned road bits.
uint32_t station
Count of company owned station tiles.
Definition: company_base.h:37
uint32_t signal
Count of company owned signals.
Definition: company_base.h:35
std::array< uint32_t, RAILTYPE_END > rail
Count of company owned track bits for each rail type.
Definition: company_base.h:33
uint32_t GetTramTotal() const
Get total sum of all owned tram bits.
uint32_t airport
Count of company owned airports.
Definition: company_base.h:38
uint32_t water
Count of company owned track bits for canals.
Definition: company_base.h:36
TileIndex location_of_HQ
Northern tile of HQ; INVALID_TILE when there is none.
Definition: company_base.h:91
bool is_ai
If true, the company is (also) controlled by the computer (a NoAI program).
Definition: company_base.h:112
Money current_loan
Amount of money borrowed from the bank.
Definition: company_base.h:84
TimerGameEconomy::Year inaugurated_year
Economy year of starting the company.
Definition: company_base.h:94
Colours colour
Company colour.
Definition: company_base.h:87
CompanyManagerFace face
Face description of the president.
Definition: company_base.h:80
std::array< Expenses, 3 > yearly_expenses
Expenses of the company for the last three years.
Definition: company_base.h:114
Money money
Money owned by the company.
Definition: company_base.h:82
Window with general information about a company.
void OnResize() override
Called after the window got resized.
IntervalTimer< TimerWindow > redraw_interval
Redraw the window on a regular interval.
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 OnPlaceObjectAbort() override
The user cancelled a tile highlight mode that has been set.
void OnPaint() override
The window must be repainted.
void OnInvalidateData([[maybe_unused]] int data=0, [[maybe_unused]] bool gui_scope=true) override
Some data on this window has become invalid.
Money GetMaxLoan() const
Calculate the max allowed loan for this company.
CompanyInfrastructure infrastructure
NOSAVE: Counts of company owned infrastructure.
Definition: company_base.h:147
GroupStatistics group_all[VEH_COMPANY_END]
NOSAVE: Statistics for the ALL_GROUP group.
Definition: company_base.h:144
uint16_t rate
The conversion rate compared to the base currency.
Definition: currency.h:76
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
static Pool::IterateWrapperFiltered< Engine, EngineTypeFilter > IterateType(VehicleType vt, size_t from=0)
Returns an iterable ensemble of all valid engines of the given type.
Definition: engine_base.h:186
Expense list container.
Definition: company_gui.cpp:85
uint GetListWidth() const
Compute width of the expenses categories in pixels.
const std::initializer_list< ExpensesType > & items
List of expenses types.
Definition: company_gui.cpp:87
const StringID title
StringID of list title.
Definition: company_gui.cpp:86
bool has_2CC
Set if any vehicle is loaded which uses 2cc (two company colours).
Definition: newgrf.h:178
uint64_t used_liveries
Bitmask of LiveryScheme used by the defined engines.
Definition: newgrf.h:179
uint8_t liveries
options for displaying company liveries, 0=none, 1=self, 2=all
uint8_t landscape
the landscape we're currently in
EconomySettings economy
settings to change the economy
DifficultySettings difficulty
settings related to the difficulty
GameCreationSettings game_creation
settings used during the creation of a game (map)
uint16_t num_vehicle
Number of vehicles.
Definition: group.h:28
Group data.
Definition: group.h:72
Livery livery
Custom colour scheme for vehicles in this group.
Definition: group.h:78
GroupID parent
Parent group.
Definition: group.h:83
VehicleType vehicle_type
Vehicle type of the group.
Definition: group.h:75
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.
Definition: widget_type.h:1075
Coordinates of a point in 2D.
Tindex index
Index of this pool item.
Definition: pool_type.hpp:238
static Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:339
static bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
Definition: pool_type.hpp:328
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
Definition: pool_type.hpp:388
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.
Company livery colour scheme window.
void OnInvalidateData([[maybe_unused]] int data=0, [[maybe_unused]] bool gui_scope=true) override
Some data on this window has become invalid.
void OnPaint() override
The window must be repainted.
void OnResize() override
Called after the window got resized.
High level window description.
Definition: window_gui.h:159
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:952
virtual void Close(int data=0)
Hide the window and all its child windows, and mark them for a later deletion.
Definition: window.cpp:1047
void FinishInitNested(WindowNumber window_number=0)
Perform the second part of the initialization of a nested widget tree.
Definition: window.cpp:1733
void DrawWidgets() const
Paint all widgets of a window.
Definition: widget.cpp:731
void InvalidateData(int data=0, bool gui_scope=true)
Mark this window's data as invalid (in need of re-computing)
Definition: window.cpp:3151
Window * parent
Parent window.
Definition: window_gui.h:328
void RaiseWidget(WidgetID widget_index)
Marks a widget as raised.
Definition: window_gui.h:475
void SetWidgetDirty(WidgetID widget_index) const
Invalidate a widget, i.e.
Definition: window.cpp:551
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:995
void SetWidgetsDisabledState(bool disab_stat, Args... widgets)
Sets the enabled/disabled status of a list of widgets.
Definition: window_gui.h:521
void CreateNestedTree()
Perform the first part of the initialization of a nested widget tree.
Definition: window.cpp:1723
bool IsWidgetLowered(WidgetID widget_index) const
Gets the lowered state of a widget.
Definition: window_gui.h:497
void RaiseButtons(bool autoraise=false)
Raise the buttons of the window.
Definition: window.cpp:525
void SetWidgetsLoweredState(bool lowered_stat, Args... widgets)
Sets the lowered/raised status of a list of widgets.
Definition: window_gui.h:532
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:447
void EnableWidget(WidgetID widget_index)
Sets a widget to Enabled.
Definition: window_gui.h:406
bool IsShaded() const
Is window shaded currently?
Definition: window_gui.h:563
Window(WindowDesc &desc)
Empty constructor, initialization has been moved to InitNested() called from the constructor of the d...
Definition: window.cpp:1756
void LowerWidget(WidgetID widget_index)
Marks a widget as lowered.
Definition: window_gui.h:466
void InitNested(WindowNumber number=0)
Perform complete initialization of the Window with nested widgets, to allow use.
Definition: window.cpp:1746
const Scrollbar * GetScrollbar(WidgetID widnum) const
Return the Scrollbar to a widget index.
Definition: window.cpp:314
void SetWidgetDisabledState(WidgetID widget_index, bool disab_stat)
Sets the enabled/disabled status of a widget.
Definition: window_gui.h:387
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.
@ QSF_ENABLE_DEFAULT
enable the 'Default' button ("\0" is returned)
Definition: textbuf_gui.h:21
@ QSF_LEN_IN_CHARS
the length of the string is counted in characters
Definition: textbuf_gui.h:22
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).
Definition: viewport.cpp:3498
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...
Definition: viewport.cpp:3435
@ 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.
Definition: vehicle_type.h:21
@ VEH_ROAD
Road vehicle type.
Definition: vehicle_type.h:25
@ VEH_AIRCRAFT
Aircraft vehicle type.
Definition: vehicle_type.h:27
@ VEH_SHIP
Ship vehicle type.
Definition: vehicle_type.h:26
@ VEH_TRAIN
Train vehicle type.
Definition: vehicle_type.h:24
@ VEH_COMPANY_END
Last company-ownable type.
Definition: vehicle_type.h:29
void SetTileSelectSize(int w, int h)
Highlight w by h tiles at the cursor.
Definition: viewport.cpp:2542
bool ScrollMainWindowToTile(TileIndex tile, bool instant)
Scrolls the viewport of the main window to a given location.
Definition: viewport.cpp:2515
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
@ SZSP_NONE
Display plane with zero size in both directions (none filling and resizing).
Definition: widget_type.h:483
@ AWV_DECREASE
Arrow to the left or in case of RTL to the right.
Definition: widget_type.h:31
@ AWV_INCREASE
Arrow to the right or in case of RTL to the left.
Definition: widget_type.h:32
@ NC_EQUALSIZE
Value of the NCB_EQUALSIZE flag.
Definition: widget_type.h:524
@ WWT_PUSHTXTBTN
Normal push-button (no toggle button) with text caption.
Definition: widget_type.h:112
@ WWT_IMGBTN
(Toggle) Button with image
Definition: widget_type.h:52
@ WWT_PUSHARROWBTN
Normal push-button (no toggle button) with arrow caption.
Definition: widget_type.h:114
@ WWT_LABEL
Centered label.
Definition: widget_type.h:57
@ NWID_SPACER
Invisible widget that takes some space.
Definition: widget_type.h:79
@ NWID_HORIZONTAL
Horizontal container.
Definition: widget_type.h:75
@ WWT_TEXTBTN
(Toggle) Button with text
Definition: widget_type.h:55
@ WWT_PANEL
Simple depressed panel.
Definition: widget_type.h:50
@ WWT_STICKYBOX
Sticky box (at top-right of a window, after WWT_DEFSIZEBOX)
Definition: widget_type.h:66
@ WWT_MATRIX
Grid of rows and columns.
Definition: widget_type.h:59
@ WWT_SHADEBOX
Shade box (at top-right of a window, between WWT_DEBUGBOX and WWT_DEFSIZEBOX)
Definition: widget_type.h:64
@ WWT_CAPTION
Window caption (window title between closebox and stickybox)
Definition: widget_type.h:61
@ NWID_VSCROLLBAR
Vertical scrollbar.
Definition: widget_type.h:84
@ NWID_VERTICAL
Vertical container.
Definition: widget_type.h:77
@ WWT_CLOSEBOX
Close box (at top-left of a window)
Definition: widget_type.h:69
@ WWT_EMPTY
Empty widget, place holder to reserve space in widget tree.
Definition: widget_type.h:48
@ WWT_RESIZEBOX
Resize box (normally at bottom-right of a window)
Definition: widget_type.h:68
@ WWT_DEFSIZEBOX
Default window size box (at top-right of a window, between WWT_SHADEBOX and WWT_STICKYBOX)
Definition: widget_type.h:65
@ WWT_DROPDOWN
Drop down list.
Definition: widget_type.h:70
@ WWT_TEXT
Pure simple text.
Definition: widget_type.h:58
@ NWID_SELECTION
Stacked widgets, only one visible at a time (eg in a panel with tabs).
Definition: widget_type.h:80
Window * BringWindowToFrontById(WindowClass cls, WindowNumber number)
Find a window and make it the relative top-window on the screen.
Definition: window.cpp:1223
void SetWindowDirty(WindowClass cls, WindowNumber number)
Mark window as dirty (in need of repainting)
Definition: window.cpp:3093
Window functions not directly related to making/drawing windows.
Functions, definitions and such used only by the GUI.
@ WDF_CONSTRUCTION
This window is used for construction; close it whenever changing company.
Definition: window_gui.h:203
@ WDP_AUTO
Find a place automatically.
Definition: window_gui.h:147
int WidgetID
Widget ID.
Definition: window_type.h:18
int32_t WindowNumber
Number to differentiate different windows of the same class.
Definition: window_type.h:737
@ WC_BUY_COMPANY
Buyout company (merger); Window numbers:
Definition: window_type.h:594
@ WC_COMPANY_INFRASTRUCTURE
Company infrastructure overview; Window numbers:
Definition: window_type.h:587
@ WC_COMPANY_COLOUR
Company colour selection; Window numbers:
Definition: window_type.h:230
@ WC_NONE
No window, redirects to WC_MAIN_WINDOW.
Definition: window_type.h:45
@ WC_FINANCES
Finances of a company; Window numbers:
Definition: window_type.h:527
@ WC_COMPANY_MANAGER_FACE
Alter company face window; Window numbers:
Definition: window_type.h:236
@ WC_COMPANY
Company view; Window numbers:
Definition: window_type.h:369
Functions related to zooming.