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/>.
8 /** @file company_gui.cpp %Company related GUIs. */
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"
23 #include "company_manager_face.h"
24 #include "strings_func.h"
25 #include "date_func.h"
26 #include "widgets/dropdown_type.h"
27 #include "tilehighlight_func.h"
28 #include "company_base.h"
29 #include "core/geometry_func.hpp"
30 #include "object_type.h"
33 #include "engine_base.h"
34 #include "window_func.h"
35 #include "road_func.h"
37 #include "station_func.h"
38 #include "zoom_func.h"
39 #include "sortlist_type.h"
40 #include "company_cmd.h"
41 #include "economy_cmd.h"
42 #include "group_cmd.h"
44 #include "object_cmd.h"
46 #include "widgets/company_widget.h"
48 #include "safeguards.h"
51 /** Company GUI constants. */
52 static const uint EXP_LINESPACE
= 2; ///< Amount of vertical space for a horizontal (sub-)total line.
53 static const uint EXP_BLOCKSPACE
= 10; ///< Amount of vertical space between two blocks of numbers.
54 static const int EXP_INDENT
= 10; ///< Amount of horizontal space for an indented line.
56 static void DoSelectCompanyManagerFace(Window
*parent
);
57 static void ShowCompanyInfrastructure(CompanyID company
);
59 /** List of revenues. */
60 static ExpensesType _expenses_list_revenue
[] = {
61 EXPENSES_TRAIN_REVENUE
,
62 EXPENSES_ROADVEH_REVENUE
,
63 EXPENSES_AIRCRAFT_REVENUE
,
64 EXPENSES_SHIP_REVENUE
,
67 /** List of operating expenses. */
68 static ExpensesType _expenses_list_operating_costs
[] = {
71 EXPENSES_AIRCRAFT_RUN
,
74 EXPENSES_LOAN_INTEREST
,
77 /** List of capital expenses. */
78 static ExpensesType _expenses_list_capital_costs
[] = {
79 EXPENSES_CONSTRUCTION
,
80 EXPENSES_NEW_VEHICLES
,
84 /** Expense list container. */
86 const ExpensesType
*et
; ///< Expenses items.
87 const uint length
; ///< Number of items in list.
89 ExpensesList(ExpensesType
*et
, int length
) : et(et
), length(length
)
93 uint
GetHeight() const
95 /* Add up the height of all the lines. */
96 return this->length
* FONT_HEIGHT_NORMAL
;
99 /** Compute width of the expenses categories in pixels. */
100 uint
GetListWidth() const
103 for (uint i
= 0; i
< this->length
; i
++) {
104 ExpensesType et
= this->et
[i
];
105 width
= std::max(width
, GetStringBoundingBox(STR_FINANCES_SECTION_CONSTRUCTION
+ et
).width
);
111 /** Types of expense lists */
112 static const ExpensesList _expenses_list_types
[] = {
113 ExpensesList(_expenses_list_revenue
, lengthof(_expenses_list_revenue
)),
114 ExpensesList(_expenses_list_operating_costs
, lengthof(_expenses_list_operating_costs
)),
115 ExpensesList(_expenses_list_capital_costs
, lengthof(_expenses_list_capital_costs
)),
119 * Get the total height of the "categories" column.
120 * @return The total height in pixels.
122 static uint
GetTotalCategoriesHeight()
124 /* There's an empty line and blockspace on the year row */
125 uint total_height
= FONT_HEIGHT_NORMAL
+ EXP_BLOCKSPACE
;
127 for (uint i
= 0; i
< lengthof(_expenses_list_types
); i
++) {
128 /* Title + expense list + total line + total + blockspace after category */
129 total_height
+= FONT_HEIGHT_NORMAL
+ _expenses_list_types
[i
].GetHeight() + EXP_LINESPACE
+ FONT_HEIGHT_NORMAL
+ EXP_BLOCKSPACE
;
133 total_height
+= EXP_LINESPACE
+ FONT_HEIGHT_NORMAL
+ EXP_BLOCKSPACE
;
139 * Get the required width of the "categories" column, equal to the widest element.
140 * @return The required width in pixels.
142 static uint
GetMaxCategoriesWidth()
146 /* Loop through categories to check max widths. */
147 for (uint i
= 0; i
< lengthof(_expenses_list_types
); i
++) {
148 /* Title of category */
149 max_width
= std::max(max_width
, GetStringBoundingBox(STR_FINANCES_REVENUE_TITLE
+ i
).width
);
150 /* Entries in category */
151 max_width
= std::max(max_width
, _expenses_list_types
[i
].GetListWidth());
158 * Draw a category of expenses (revenue, operating expenses, capital expenses).
160 static void DrawCategory(const Rect
&r
, int start_y
, ExpensesList list
)
162 int offs_left
= _current_text_dir
== TD_LTR
? EXP_INDENT
: 0;
163 int offs_right
= _current_text_dir
== TD_LTR
? 0 : EXP_INDENT
;
168 for (uint i
= 0; i
< list
.length
; i
++) {
170 DrawString(r
.left
+ offs_left
, r
.right
- offs_right
, y
, STR_FINANCES_SECTION_CONSTRUCTION
+ et
);
171 y
+= FONT_HEIGHT_NORMAL
;
176 * Draw the expenses categories.
177 * @param r Available space for drawing.
178 * @note The environment must provide padding at the left and right of \a r.
180 static void DrawCategories(const Rect
&r
)
182 /* Start with an empty space in the year row, plus the blockspace under the year. */
183 int y
= r
.top
+ FONT_HEIGHT_NORMAL
+ EXP_BLOCKSPACE
;
185 for (uint i
= 0; i
< lengthof(_expenses_list_types
); i
++) {
186 /* Draw category title and advance y */
187 DrawString(r
.left
, r
.right
, y
, (STR_FINANCES_REVENUE_TITLE
+ i
), TC_FROMSTRING
, SA_LEFT
);
188 y
+= FONT_HEIGHT_NORMAL
;
190 /* Draw category items and advance y */
191 DrawCategory(r
, y
, _expenses_list_types
[i
]);
192 y
+= _expenses_list_types
[i
].GetHeight();
194 /* Advance y by the height of the total and associated total line */
195 y
+= EXP_LINESPACE
+ FONT_HEIGHT_NORMAL
;
197 /* Advance y by a blockspace after this category block */
201 /* Draw total profit/loss */
203 DrawString(r
.left
, r
.right
, y
, STR_FINANCES_NET_PROFIT
, TC_FROMSTRING
, SA_LEFT
);
207 * Draw an amount of money.
208 * @param amount Amount of money to draw,
209 * @param left Left coordinate of the space to draw in.
210 * @param right Right coordinate of the space to draw in.
211 * @param top Top coordinate of the space to draw in.
212 * @param colour The TextColour of the string.
214 static void DrawPrice(Money amount
, int left
, int right
, int top
, TextColour colour
)
216 StringID str
= STR_FINANCES_NEGATIVE_INCOME
;
218 str
= STR_FINANCES_ZERO_INCOME
;
219 } else if (amount
< 0) {
221 str
= STR_FINANCES_POSITIVE_INCOME
;
223 SetDParam(0, amount
);
224 DrawString(left
, right
, top
, str
, colour
, SA_RIGHT
);
228 * Draw a category of expenses/revenues in the year column.
229 * @return The income sum of the category.
231 static Money
DrawYearCategory (const Rect
&r
, int start_y
, ExpensesList list
, const Money(*tbl
)[EXPENSES_END
])
237 for (uint i
= 0; i
< list
.length
; i
++) {
239 Money cost
= (*tbl
)[et
];
241 if (cost
!= 0) DrawPrice(cost
, r
.left
, r
.right
, y
, TC_BLACK
);
242 y
+= FONT_HEIGHT_NORMAL
;
245 /* Draw the total at the bottom of the category. */
246 GfxFillRect(r
.left
, y
, r
.right
, y
, PC_BLACK
);
248 if (sum
!= 0) DrawPrice(sum
, r
.left
, r
.right
, y
, TC_WHITE
);
250 /* Return the sum for the yearly total. */
256 * Draw a column with prices.
257 * @param r Available space for drawing.
258 * @param year Year being drawn.
259 * @param tbl Pointer to table of amounts for \a year.
260 * @note The environment must provide padding at the left and right of \a r.
262 static void DrawYearColumn(const Rect
&r
, int year
, const Money (*tbl
)[EXPENSES_END
])
269 DrawString(r
.left
, r
.right
, y
, STR_FINANCES_YEAR
, TC_FROMSTRING
, SA_RIGHT
, true);
270 y
+= FONT_HEIGHT_NORMAL
+ EXP_BLOCKSPACE
;
273 for (uint i
= 0; i
< lengthof(_expenses_list_types
); i
++) {
274 y
+= FONT_HEIGHT_NORMAL
;
275 sum
+= DrawYearCategory(r
, y
, _expenses_list_types
[i
], tbl
);
276 /* Expense list + expense category title + expense category total + blockspace after category */
277 y
+= _expenses_list_types
[i
].GetHeight() + EXP_LINESPACE
+ FONT_HEIGHT_NORMAL
+ EXP_BLOCKSPACE
;
281 GfxFillRect(r
.left
, y
, r
.right
, y
, PC_BLACK
);
283 DrawPrice(sum
, r
.left
, r
.right
, y
, TC_WHITE
);
286 static const NWidgetPart _nested_company_finances_widgets
[] = {
287 NWidget(NWID_HORIZONTAL
),
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
),
291 NWidget(WWT_SHADEBOX
, COLOUR_GREY
),
292 NWidget(WWT_STICKYBOX
, COLOUR_GREY
),
294 NWidget(NWID_SELECTION
, INVALID_COLOUR
, WID_CF_SEL_PANEL
),
295 NWidget(WWT_PANEL
, COLOUR_GREY
),
296 NWidget(NWID_HORIZONTAL
), SetPadding(WD_FRAMERECT_TOP
, WD_FRAMERECT_RIGHT
, WD_FRAMERECT_BOTTOM
, WD_FRAMERECT_LEFT
), SetPIP(0, 9, 0),
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),
304 NWidget(WWT_PANEL
, COLOUR_GREY
),
305 NWidget(NWID_HORIZONTAL
), SetPadding(WD_FRAMERECT_TOP
, WD_FRAMERECT_RIGHT
, WD_FRAMERECT_BOTTOM
, WD_FRAMERECT_LEFT
),
306 NWidget(NWID_VERTICAL
), // Vertical column with 'bank balance', 'loan'
307 NWidget(WWT_TEXT
, COLOUR_GREY
), SetDataTip(STR_FINANCES_OWN_FUNDS_TITLE
, STR_NULL
), SetFill(1, 0),
308 NWidget(WWT_TEXT
, COLOUR_GREY
), SetDataTip(STR_FINANCES_LOAN_TITLE
, STR_NULL
), SetFill(1, 0),
309 NWidget(NWID_SPACER
), SetMinimalSize(0, 2), SetFill(1, 0),
310 NWidget(WWT_TEXT
, COLOUR_GREY
), SetDataTip(STR_FINANCES_BANK_BALANCE_TITLE
, STR_NULL
), SetFill(1, 0),
311 NWidget(NWID_SPACER
), SetFill(0, 1),
313 NWidget(NWID_SPACER
), SetFill(0, 0), SetMinimalSize(30, 0),
314 NWidget(NWID_VERTICAL
), // Vertical column with bank balance amount, loan amount, and total.
315 NWidget(WWT_TEXT
, COLOUR_GREY
, WID_CF_OWN_VALUE
), SetDataTip(STR_FINANCES_TOTAL_CURRENCY
, STR_NULL
), SetAlignment(SA_VERT_CENTER
| SA_RIGHT
),
316 NWidget(WWT_TEXT
, COLOUR_GREY
, WID_CF_LOAN_VALUE
), SetDataTip(STR_FINANCES_TOTAL_CURRENCY
, STR_NULL
), SetAlignment(SA_VERT_CENTER
| SA_RIGHT
),
317 NWidget(WWT_EMPTY
, COLOUR_GREY
, WID_CF_BALANCE_LINE
), SetMinimalSize(0, 2), SetFill(1, 0),
318 NWidget(WWT_TEXT
, COLOUR_GREY
, WID_CF_BALANCE_VALUE
), SetDataTip(STR_FINANCES_TOTAL_CURRENCY
, STR_NULL
), SetAlignment(SA_VERT_CENTER
| SA_RIGHT
),
320 NWidget(NWID_SELECTION
, INVALID_COLOUR
, WID_CF_SEL_MAXLOAN
),
321 NWidget(NWID_HORIZONTAL
),
322 NWidget(NWID_SPACER
), SetFill(0, 1), SetMinimalSize(25, 0),
323 NWidget(NWID_VERTICAL
), // Max loan information
324 NWidget(WWT_TEXT
, COLOUR_GREY
, WID_CF_INTEREST_RATE
), SetDataTip(STR_FINANCES_INTEREST_RATE
, STR_NULL
),
325 NWidget(WWT_TEXT
, COLOUR_GREY
, WID_CF_MAXLOAN_VALUE
), SetDataTip(STR_FINANCES_MAX_LOAN
, STR_NULL
),
326 NWidget(NWID_SPACER
), SetFill(0, 1),
330 NWidget(NWID_SPACER
), SetFill(1, 1),
333 NWidget(NWID_SELECTION
, INVALID_COLOUR
, WID_CF_SEL_BUTTONS
),
334 NWidget(NWID_HORIZONTAL
, NC_EQUALSIZE
),
335 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_CF_INCREASE_LOAN
), SetFill(1, 0), SetDataTip(STR_FINANCES_BORROW_BUTTON
, STR_FINANCES_BORROW_TOOLTIP
),
336 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_CF_REPAY_LOAN
), SetFill(1, 0), SetDataTip(STR_FINANCES_REPAY_BUTTON
, STR_FINANCES_REPAY_TOOLTIP
),
337 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_CF_INFRASTRUCTURE
), SetFill(1, 0), SetDataTip(STR_FINANCES_INFRASTRUCTURE_BUTTON
, STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP
),
342 /** Window class displaying the company finances. */
343 struct CompanyFinancesWindow
: Window
{
344 static Money max_money
; ///< The maximum amount of money a company has had this 'run'
345 bool small
; ///< Window is toggled to 'small'.
347 CompanyFinancesWindow(WindowDesc
*desc
, CompanyID company
) : Window(desc
)
350 this->CreateNestedTree();
351 this->SetupWidgets();
352 this->FinishInitNested(company
);
354 this->owner
= (Owner
)this->window_number
;
357 void SetStringParameters(int widget
) const override
361 SetDParam(0, (CompanyID
)this->window_number
);
362 SetDParam(1, (CompanyID
)this->window_number
);
365 case WID_CF_BALANCE_VALUE
: {
366 const Company
*c
= Company::Get((CompanyID
)this->window_number
);
367 SetDParam(0, c
->money
);
371 case WID_CF_LOAN_VALUE
: {
372 const Company
*c
= Company::Get((CompanyID
)this->window_number
);
373 SetDParam(0, c
->current_loan
);
377 case WID_CF_OWN_VALUE
: {
378 const Company
*c
= Company::Get((CompanyID
)this->window_number
);
379 SetDParam(0, c
->money
- c
->current_loan
);
383 case WID_CF_INTEREST_RATE
:
384 SetDParam(0, _settings_game
.difficulty
.initial_interest
);
387 case WID_CF_MAXLOAN_VALUE
:
388 SetDParam(0, _economy
.max_loan
);
391 case WID_CF_INCREASE_LOAN
:
392 case WID_CF_REPAY_LOAN
:
393 SetDParam(0, LOAN_INTERVAL
);
398 void UpdateWidgetSize(int widget
, Dimension
*size
, const Dimension
&padding
, Dimension
*fill
, Dimension
*resize
) override
401 case WID_CF_EXPS_CATEGORY
:
402 size
->width
= GetMaxCategoriesWidth();
403 size
->height
= GetTotalCategoriesHeight();
406 case WID_CF_EXPS_PRICE1
:
407 case WID_CF_EXPS_PRICE2
:
408 case WID_CF_EXPS_PRICE3
:
409 size
->height
= GetTotalCategoriesHeight();
412 case WID_CF_BALANCE_VALUE
:
413 case WID_CF_LOAN_VALUE
:
414 case WID_CF_OWN_VALUE
:
415 SetDParamMaxValue(0, CompanyFinancesWindow::max_money
);
416 size
->width
= std::max(GetStringBoundingBox(STR_FINANCES_NEGATIVE_INCOME
).width
, GetStringBoundingBox(STR_FINANCES_POSITIVE_INCOME
).width
) + padding
.width
;
419 case WID_CF_INTEREST_RATE
:
420 size
->height
= FONT_HEIGHT_NORMAL
;
425 void DrawWidget(const Rect
&r
, int widget
) const override
428 case WID_CF_EXPS_CATEGORY
:
432 case WID_CF_EXPS_PRICE1
:
433 case WID_CF_EXPS_PRICE2
:
434 case WID_CF_EXPS_PRICE3
: {
435 const Company
*c
= Company::Get((CompanyID
)this->window_number
);
436 int age
= std::min(_cur_year
- c
->inaugurated_year
, 2);
437 int wid_offset
= widget
- WID_CF_EXPS_PRICE1
;
438 if (wid_offset
<= age
) {
439 DrawYearColumn(r
, _cur_year
- (age
- wid_offset
), c
->yearly_expenses
+ (age
- wid_offset
));
444 case WID_CF_BALANCE_LINE
:
445 GfxFillRect(r
.left
, r
.top
, r
.right
, r
.top
, PC_BLACK
);
451 * Setup the widgets in the nested tree, such that the finances window is displayed properly.
452 * @note After setup, the window must be (re-)initialized.
456 int plane
= this->small
? SZSP_NONE
: 0;
457 this->GetWidget
<NWidgetStacked
>(WID_CF_SEL_PANEL
)->SetDisplayedPlane(plane
);
458 this->GetWidget
<NWidgetStacked
>(WID_CF_SEL_MAXLOAN
)->SetDisplayedPlane(plane
);
460 CompanyID company
= (CompanyID
)this->window_number
;
461 plane
= (company
!= _local_company
) ? SZSP_NONE
: 0;
462 this->GetWidget
<NWidgetStacked
>(WID_CF_SEL_BUTTONS
)->SetDisplayedPlane(plane
);
465 void OnPaint() override
467 if (!this->IsShaded()) {
469 /* Check that the expenses panel height matches the height needed for the layout. */
470 if (GetTotalCategoriesHeight() != this->GetWidget
<NWidgetBase
>(WID_CF_EXPS_CATEGORY
)->current_y
) {
471 this->SetupWidgets();
477 /* Check that the loan buttons are shown only when the user owns the company. */
478 CompanyID company
= (CompanyID
)this->window_number
;
479 int req_plane
= (company
!= _local_company
) ? SZSP_NONE
: 0;
480 if (req_plane
!= this->GetWidget
<NWidgetStacked
>(WID_CF_SEL_BUTTONS
)->shown_plane
) {
481 this->SetupWidgets();
486 const Company
*c
= Company::Get(company
);
487 this->SetWidgetDisabledState(WID_CF_INCREASE_LOAN
, c
->current_loan
== _economy
.max_loan
); // Borrow button only shows when there is any more money to loan.
488 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.
494 void OnClick(Point pt
, int widget
, int click_count
) override
497 case WID_CF_TOGGLE_SIZE
: // toggle size
498 this->small
= !this->small
;
499 this->SetupWidgets();
500 if (this->IsShaded()) {
501 /* Finances window is not resizable, so size hints given during unshading have no effect
502 * on the changed appearance of the window. */
503 this->SetShaded(false);
509 case WID_CF_INCREASE_LOAN
: // increase loan
510 Command
<CMD_INCREASE_LOAN
>::Post(STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY
, _ctrl_pressed
? LoanCommand::Max
: LoanCommand::Interval
, 0);
513 case WID_CF_REPAY_LOAN
: // repay loan
514 Command
<CMD_DECREASE_LOAN
>::Post(STR_ERROR_CAN_T_REPAY_LOAN
, _ctrl_pressed
? LoanCommand::Max
: LoanCommand::Interval
, 0);
517 case WID_CF_INFRASTRUCTURE
: // show infrastructure details
518 ShowCompanyInfrastructure((CompanyID
)this->window_number
);
523 void OnHundredthTick() override
525 const Company
*c
= Company::Get((CompanyID
)this->window_number
);
526 if (c
->money
> CompanyFinancesWindow::max_money
) {
527 CompanyFinancesWindow::max_money
= std::max(c
->money
* 2, CompanyFinancesWindow::max_money
* 4);
528 this->SetupWidgets();
534 /** First conservative estimate of the maximum amount of money */
535 Money
CompanyFinancesWindow::max_money
= INT32_MAX
;
537 static WindowDesc
_company_finances_desc(
538 WDP_AUTO
, "company_finances", 0, 0,
539 WC_FINANCES
, WC_NONE
,
541 _nested_company_finances_widgets
, lengthof(_nested_company_finances_widgets
)
545 * Open the finances window of a company.
546 * @param company Company to show finances of.
547 * @pre is company a valid company.
549 void ShowCompanyFinances(CompanyID company
)
551 if (!Company::IsValidID(company
)) return;
552 if (BringWindowToFrontById(WC_FINANCES
, company
)) return;
554 new CompanyFinancesWindow(&_company_finances_desc
, company
);
557 /* List of colours for the livery window */
558 static const StringID _colour_dropdown
[] = {
559 STR_COLOUR_DARK_BLUE
,
560 STR_COLOUR_PALE_GREEN
,
564 STR_COLOUR_LIGHT_BLUE
,
566 STR_COLOUR_DARK_GREEN
,
577 /* Association of liveries to livery classes */
578 static const LiveryClass _livery_class
[LS_END
] = {
580 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
,
583 LC_AIRCRAFT
, LC_AIRCRAFT
, LC_AIRCRAFT
,
587 class DropDownListColourItem
: public DropDownListItem
{
589 DropDownListColourItem(int result
, bool masked
) : DropDownListItem(result
, masked
) {}
591 StringID
String() const
593 return this->result
>= COLOUR_END
? STR_COLOUR_DEFAULT
: _colour_dropdown
[this->result
];
596 uint
Height(uint width
) const override
598 return std::max(FONT_HEIGHT_NORMAL
, ScaleGUITrad(12) + 2);
601 bool Selectable() const override
606 void Draw(int left
, int right
, int top
, int bottom
, bool sel
, Colours bg_colour
) const override
608 bool rtl
= _current_text_dir
== TD_RTL
;
609 int height
= bottom
- top
;
610 int icon_y_offset
= height
/ 2;
611 int text_y_offset
= (height
- FONT_HEIGHT_NORMAL
) / 2 + 1;
612 DrawSprite(SPR_VEH_BUS_SIDE_VIEW
, PALETTE_RECOLOUR_START
+ (this->result
% COLOUR_END
),
613 rtl
? right
- 2 - ScaleGUITrad(14) : left
+ ScaleGUITrad(14) + 2,
614 top
+ icon_y_offset
);
615 DrawString(rtl
? left
+ 2 : left
+ ScaleGUITrad(28) + 4,
616 rtl
? right
- ScaleGUITrad(28) - 4 : right
- 2,
617 top
+ text_y_offset
, this->String(), sel
? TC_WHITE
: TC_BLACK
);
621 static const int LEVEL_WIDTH
= 10; ///< Indenting width of a sub-group in pixels
623 typedef GUIList
<const Group
*> GUIGroupList
;
625 /** Company livery colour scheme window. */
626 struct SelectCompanyLiveryWindow
: public Window
{
629 LiveryClass livery_class
;
634 std::vector
<int> indents
;
637 void ShowColourDropDownMenu(uint32 widget
)
639 uint32 used_colours
= 0;
641 const Livery
*livery
, *default_livery
= nullptr;
642 bool primary
= widget
== WID_SCL_PRI_COL_DROPDOWN
;
645 /* Disallow other company colours for the primary colour */
646 if (this->livery_class
< LC_GROUP_RAIL
&& HasBit(this->sel
, LS_DEFAULT
) && primary
) {
647 for (const Company
*c
: Company::Iterate()) {
648 if (c
->index
!= _local_company
) SetBit(used_colours
, c
->colour
);
652 c
= Company::Get((CompanyID
)this->window_number
);
654 if (this->livery_class
< LC_GROUP_RAIL
) {
655 /* Get the first selected livery to use as the default dropdown item */
657 for (scheme
= LS_BEGIN
; scheme
< LS_END
; scheme
++) {
658 if (HasBit(this->sel
, scheme
)) break;
660 if (scheme
== LS_END
) scheme
= LS_DEFAULT
;
661 livery
= &c
->livery
[scheme
];
662 if (scheme
!= LS_DEFAULT
) default_livery
= &c
->livery
[LS_DEFAULT
];
664 const Group
*g
= Group::Get(this->sel
);
666 if (g
->parent
== INVALID_GROUP
) {
667 default_livery
= &c
->livery
[LS_DEFAULT
];
669 const Group
*pg
= Group::Get(g
->parent
);
670 default_livery
= &pg
->livery
;
675 if (default_livery
!= nullptr) {
676 /* Add COLOUR_END to put the colour out of range, but also allow us to show what the default is */
677 default_col
= (primary
? default_livery
->colour1
: default_livery
->colour2
) + COLOUR_END
;
678 list
.emplace_back(new DropDownListColourItem(default_col
, false));
680 for (uint i
= 0; i
< lengthof(_colour_dropdown
); i
++) {
681 list
.emplace_back(new DropDownListColourItem(i
, HasBit(used_colours
, i
)));
684 byte sel
= (default_livery
== nullptr || HasBit(livery
->in_use
, primary
? 0 : 1)) ? (primary
? livery
->colour1
: livery
->colour2
) : default_col
;
685 ShowDropDownList(this, std::move(list
), sel
, widget
);
688 void AddChildren(GUIGroupList
*source
, GroupID parent
, int indent
)
690 for (const Group
*g
: *source
) {
691 if (g
->parent
!= parent
) continue;
692 this->groups
.push_back(g
);
693 this->indents
.push_back(indent
);
694 AddChildren(source
, g
->index
, indent
+ 1);
698 void BuildGroupList(CompanyID owner
)
700 if (!this->groups
.NeedRebuild()) return;
702 this->groups
.clear();
703 this->indents
.clear();
705 if (this->livery_class
>= LC_GROUP_RAIL
) {
707 VehicleType vtype
= (VehicleType
)(this->livery_class
- LC_GROUP_RAIL
);
709 for (const Group
*g
: Group::Iterate()) {
710 if (g
->owner
== owner
&& g
->vehicle_type
== vtype
) {
717 /* Sort the groups by their name */
718 const Group
*last_group
[2] = { nullptr, nullptr };
719 char last_name
[2][64] = { "", "" };
720 list
.Sort([&](const Group
* const &a
, const Group
* const &b
) -> bool {
721 if (a
!= last_group
[0]) {
723 SetDParam(0, a
->index
);
724 GetString(last_name
[0], STR_GROUP_NAME
, lastof(last_name
[0]));
727 if (b
!= last_group
[1]) {
729 SetDParam(0, b
->index
);
730 GetString(last_name
[1], STR_GROUP_NAME
, lastof(last_name
[1]));
733 int r
= strnatcmp(last_name
[0], last_name
[1]); // Sort by name (natural sorting).
734 if (r
== 0) return a
->index
< b
->index
;
738 AddChildren(&list
, INVALID_GROUP
, 0);
741 this->groups
.shrink_to_fit();
742 this->groups
.RebuildDone();
747 if (this->livery_class
< LC_GROUP_RAIL
) {
749 for (LiveryScheme scheme
= LS_DEFAULT
; scheme
< LS_END
; scheme
++) {
750 if (_livery_class
[scheme
] == this->livery_class
&& HasBit(_loaded_newgrf_features
.used_liveries
, scheme
)) {
755 this->rows
= (uint
)this->groups
.size();
758 this->vscroll
->SetCount(this->rows
);
762 SelectCompanyLiveryWindow(WindowDesc
*desc
, CompanyID company
, GroupID group
) : Window(desc
)
764 this->CreateNestedTree();
765 this->vscroll
= this->GetScrollbar(WID_SCL_MATRIX_SCROLLBAR
);
767 if (group
== INVALID_GROUP
) {
768 this->livery_class
= LC_OTHER
;
770 this->LowerWidget(WID_SCL_CLASS_GENERAL
);
771 this->BuildGroupList(company
);
774 this->SetSelectedGroup(company
, group
);
777 this->FinishInitNested(company
);
778 this->owner
= company
;
779 this->InvalidateData(1);
782 void SetSelectedGroup(CompanyID company
, GroupID group
)
784 this->RaiseWidget(this->livery_class
+ WID_SCL_CLASS_GENERAL
);
785 const Group
*g
= Group::Get(group
);
786 switch (g
->vehicle_type
) {
787 case VEH_TRAIN
: this->livery_class
= LC_GROUP_RAIL
; break;
788 case VEH_ROAD
: this->livery_class
= LC_GROUP_ROAD
; break;
789 case VEH_SHIP
: this->livery_class
= LC_GROUP_SHIP
; break;
790 case VEH_AIRCRAFT
: this->livery_class
= LC_GROUP_AIRCRAFT
; break;
791 default: NOT_REACHED();
794 this->LowerWidget(this->livery_class
+ WID_SCL_CLASS_GENERAL
);
796 this->groups
.ForceRebuild();
797 this->BuildGroupList(company
);
800 /* Position scrollbar to selected group */
801 for (uint i
= 0; i
< this->rows
; i
++) {
802 if (this->groups
[i
]->index
== sel
) {
803 this->vscroll
->SetPosition(Clamp(i
- this->vscroll
->GetCapacity() / 2, 0, std::max(this->vscroll
->GetCount() - this->vscroll
->GetCapacity(), 0)));
809 void UpdateWidgetSize(int widget
, Dimension
*size
, const Dimension
&padding
, Dimension
*fill
, Dimension
*resize
) override
812 case WID_SCL_SPACER_DROPDOWN
: {
813 /* The matrix widget below needs enough room to print all the schemes. */
814 Dimension d
= {0, 0};
815 for (LiveryScheme scheme
= LS_DEFAULT
; scheme
< LS_END
; scheme
++) {
816 d
= maxdim(d
, GetStringBoundingBox(STR_LIVERY_DEFAULT
+ scheme
));
819 /* And group names */
820 for (const Group
*g
: Group::Iterate()) {
821 if (g
->owner
== (CompanyID
)this->window_number
) {
822 SetDParam(0, g
->index
);
823 d
= maxdim(d
, GetStringBoundingBox(STR_GROUP_NAME
));
827 size
->width
= std::max(size
->width
, 5 + d
.width
+ WD_FRAMERECT_RIGHT
);
831 case WID_SCL_MATRIX
: {
832 /* 11 items in the default rail class */
833 this->square
= GetSpriteSize(SPR_SQUARE
);
834 this->line_height
= std::max(this->square
.height
, (uint
)FONT_HEIGHT_NORMAL
) + 4;
836 size
->height
= 11 * this->line_height
;
838 resize
->height
= this->line_height
;
842 case WID_SCL_SEC_COL_DROPDOWN
:
843 if (!_loaded_newgrf_features
.has_2CC
) {
849 case WID_SCL_PRI_COL_DROPDOWN
: {
850 this->square
= GetSpriteSize(SPR_SQUARE
);
851 int string_padding
= this->square
.width
+ NWidgetScrollbar::GetVerticalDimension().width
+ 10;
852 for (const StringID
*id
= _colour_dropdown
; id
!= endof(_colour_dropdown
); id
++) {
853 size
->width
= std::max(size
->width
, GetStringBoundingBox(*id
).width
+ string_padding
);
855 size
->width
= std::max(size
->width
, GetStringBoundingBox(STR_COLOUR_DEFAULT
).width
+ string_padding
);
861 void OnPaint() override
863 bool local
= (CompanyID
)this->window_number
== _local_company
;
865 /* Disable dropdown controls if no scheme is selected */
866 bool disabled
= this->livery_class
< LC_GROUP_RAIL
? (this->sel
== 0) : (this->sel
== INVALID_GROUP
);
867 this->SetWidgetDisabledState(WID_SCL_PRI_COL_DROPDOWN
, !local
|| disabled
);
868 this->SetWidgetDisabledState(WID_SCL_SEC_COL_DROPDOWN
, !local
|| disabled
);
870 this->BuildGroupList((CompanyID
)this->window_number
);
875 void SetStringParameters(int widget
) const override
878 case WID_SCL_CAPTION
:
879 SetDParam(0, (CompanyID
)this->window_number
);
882 case WID_SCL_PRI_COL_DROPDOWN
:
883 case WID_SCL_SEC_COL_DROPDOWN
: {
884 const Company
*c
= Company::Get((CompanyID
)this->window_number
);
885 bool primary
= widget
== WID_SCL_PRI_COL_DROPDOWN
;
886 StringID colour
= STR_COLOUR_DEFAULT
;
888 if (this->livery_class
< LC_GROUP_RAIL
) {
889 if (this->sel
!= 0) {
890 LiveryScheme scheme
= LS_DEFAULT
;
891 for (scheme
= LS_BEGIN
; scheme
< LS_END
; scheme
++) {
892 if (HasBit(this->sel
, scheme
)) break;
894 if (scheme
== LS_END
) scheme
= LS_DEFAULT
;
895 const Livery
*livery
= &c
->livery
[scheme
];
896 if (scheme
== LS_DEFAULT
|| HasBit(livery
->in_use
, primary
? 0 : 1)) {
897 colour
= STR_COLOUR_DARK_BLUE
+ (primary
? livery
->colour1
: livery
->colour2
);
901 if (this->sel
!= INVALID_GROUP
) {
902 const Group
*g
= Group::Get(this->sel
);
903 const Livery
*livery
= &g
->livery
;
904 if (HasBit(livery
->in_use
, primary
? 0 : 1)) {
905 colour
= STR_COLOUR_DARK_BLUE
+ (primary
? livery
->colour1
: livery
->colour2
);
909 SetDParam(0, colour
);
915 void DrawWidget(const Rect
&r
, int widget
) const override
917 if (widget
!= WID_SCL_MATRIX
) return;
919 bool rtl
= _current_text_dir
== TD_RTL
;
921 /* Horizontal coordinates of scheme name column. */
922 const NWidgetBase
*nwi
= this->GetWidget
<NWidgetBase
>(WID_SCL_SPACER_DROPDOWN
);
923 int sch_left
= nwi
->pos_x
;
924 int sch_right
= sch_left
+ nwi
->current_x
- 1;
925 /* Horizontal coordinates of first dropdown. */
926 nwi
= this->GetWidget
<NWidgetBase
>(WID_SCL_PRI_COL_DROPDOWN
);
927 int pri_left
= nwi
->pos_x
;
928 int pri_right
= pri_left
+ nwi
->current_x
- 1;
929 /* Horizontal coordinates of second dropdown. */
930 nwi
= this->GetWidget
<NWidgetBase
>(WID_SCL_SEC_COL_DROPDOWN
);
931 int sec_left
= nwi
->pos_x
;
932 int sec_right
= sec_left
+ nwi
->current_x
- 1;
934 int text_left
= (rtl
? (uint
)WD_FRAMERECT_LEFT
: (this->square
.width
+ 5));
935 int text_right
= (rtl
? (this->square
.width
+ 5) : (uint
)WD_FRAMERECT_RIGHT
);
937 int square_offs
= (this->line_height
- this->square
.height
) / 2 + 1;
938 int text_offs
= (this->line_height
- FONT_HEIGHT_NORMAL
) / 2 + 1;
942 /* Helper function to draw livery info. */
943 auto draw_livery
= [&](StringID str
, const Livery
&liv
, bool sel
, bool def
, int indent
) {
945 DrawString(sch_left
+ WD_FRAMERECT_LEFT
+ (rtl
? 0 : indent
), sch_right
- WD_FRAMERECT_RIGHT
- (rtl
? indent
: 0), y
+ text_offs
, str
, sel
? TC_WHITE
: TC_BLACK
);
947 /* Text below the first dropdown. */
948 DrawSprite(SPR_SQUARE
, GENERAL_SPRITE_COLOUR(liv
.colour1
), (rtl
? pri_right
- (this->square
.width
+ 5) + WD_FRAMERECT_RIGHT
: pri_left
) + WD_FRAMERECT_LEFT
, y
+ square_offs
);
949 DrawString(pri_left
+ text_left
, pri_right
- text_right
, y
+ text_offs
, (def
|| HasBit(liv
.in_use
, 0)) ? STR_COLOUR_DARK_BLUE
+ liv
.colour1
: STR_COLOUR_DEFAULT
, sel
? TC_WHITE
: TC_GOLD
);
951 /* Text below the second dropdown. */
952 if (sec_right
> sec_left
) { // Second dropdown has non-zero size.
953 DrawSprite(SPR_SQUARE
, GENERAL_SPRITE_COLOUR(liv
.colour2
), (rtl
? sec_right
- (this->square
.width
+ 5) + WD_FRAMERECT_RIGHT
: sec_left
) + WD_FRAMERECT_LEFT
, y
+ square_offs
);
954 DrawString(sec_left
+ text_left
, sec_right
- text_right
, y
+ text_offs
, (def
|| HasBit(liv
.in_use
, 1)) ? STR_COLOUR_DARK_BLUE
+ liv
.colour2
: STR_COLOUR_DEFAULT
, sel
? TC_WHITE
: TC_GOLD
);
957 y
+= this->line_height
;
960 if (livery_class
< LC_GROUP_RAIL
) {
961 int pos
= this->vscroll
->GetPosition();
962 const Company
*c
= Company::Get((CompanyID
)this->window_number
);
963 for (LiveryScheme scheme
= LS_DEFAULT
; scheme
< LS_END
; scheme
++) {
964 if (_livery_class
[scheme
] == this->livery_class
&& HasBit(_loaded_newgrf_features
.used_liveries
, scheme
)) {
965 if (pos
-- > 0) continue;
966 draw_livery(STR_LIVERY_DEFAULT
+ scheme
, c
->livery
[scheme
], HasBit(this->sel
, scheme
), scheme
== LS_DEFAULT
, 0);
970 uint max
= static_cast<uint
>(std::min
<size_t>(this->vscroll
->GetPosition() + this->vscroll
->GetCapacity(), this->groups
.size()));
971 for (uint i
= this->vscroll
->GetPosition(); i
< max
; ++i
) {
972 const Group
*g
= this->groups
[i
];
973 SetDParam(0, g
->index
);
974 draw_livery(STR_GROUP_NAME
, g
->livery
, this->sel
== g
->index
, false, this->indents
[i
] * LEVEL_WIDTH
);
979 void OnClick(Point pt
, int widget
, int click_count
) override
982 /* Livery Class buttons */
983 case WID_SCL_CLASS_GENERAL
:
984 case WID_SCL_CLASS_RAIL
:
985 case WID_SCL_CLASS_ROAD
:
986 case WID_SCL_CLASS_SHIP
:
987 case WID_SCL_CLASS_AIRCRAFT
:
988 case WID_SCL_GROUPS_RAIL
:
989 case WID_SCL_GROUPS_ROAD
:
990 case WID_SCL_GROUPS_SHIP
:
991 case WID_SCL_GROUPS_AIRCRAFT
:
992 this->RaiseWidget(this->livery_class
+ WID_SCL_CLASS_GENERAL
);
993 this->livery_class
= (LiveryClass
)(widget
- WID_SCL_CLASS_GENERAL
);
994 this->LowerWidget(this->livery_class
+ WID_SCL_CLASS_GENERAL
);
996 /* Select the first item in the list */
997 if (this->livery_class
< LC_GROUP_RAIL
) {
999 for (LiveryScheme scheme
= LS_DEFAULT
; scheme
< LS_END
; scheme
++) {
1000 if (_livery_class
[scheme
] == this->livery_class
&& HasBit(_loaded_newgrf_features
.used_liveries
, scheme
)) {
1001 this->sel
= 1 << scheme
;
1006 this->sel
= INVALID_GROUP
;
1007 this->groups
.ForceRebuild();
1008 this->BuildGroupList((CompanyID
)this->window_number
);
1010 if (this->groups
.size() > 0) {
1011 this->sel
= this->groups
[0]->index
;
1019 case WID_SCL_PRI_COL_DROPDOWN
: // First colour dropdown
1020 ShowColourDropDownMenu(WID_SCL_PRI_COL_DROPDOWN
);
1023 case WID_SCL_SEC_COL_DROPDOWN
: // Second colour dropdown
1024 ShowColourDropDownMenu(WID_SCL_SEC_COL_DROPDOWN
);
1027 case WID_SCL_MATRIX
: {
1028 uint row
= this->vscroll
->GetScrolledRowFromWidget(pt
.y
, this, WID_SCL_MATRIX
);
1029 if (row
>= this->rows
) return;
1031 if (this->livery_class
< LC_GROUP_RAIL
) {
1032 LiveryScheme j
= (LiveryScheme
)row
;
1034 for (LiveryScheme scheme
= LS_BEGIN
; scheme
<= j
&& scheme
< LS_END
; scheme
++) {
1035 if (_livery_class
[scheme
] != this->livery_class
|| !HasBit(_loaded_newgrf_features
.used_liveries
, scheme
)) j
++;
1039 if (_ctrl_pressed
) {
1040 ToggleBit(this->sel
, j
);
1045 this->sel
= this->groups
[row
]->index
;
1053 void OnResize() override
1055 this->vscroll
->SetCapacityFromWidget(this, WID_SCL_MATRIX
);
1058 void OnDropdownSelect(int widget
, int index
) override
1060 bool local
= (CompanyID
)this->window_number
== _local_company
;
1063 if (index
>= COLOUR_END
) index
= INVALID_COLOUR
;
1065 if (this->livery_class
< LC_GROUP_RAIL
) {
1066 /* Set company colour livery */
1067 for (LiveryScheme scheme
= LS_DEFAULT
; scheme
< LS_END
; scheme
++) {
1068 /* Changed colour for the selected scheme, or all visible schemes if CTRL is pressed. */
1069 if (HasBit(this->sel
, scheme
) || (_ctrl_pressed
&& _livery_class
[scheme
] == this->livery_class
&& HasBit(_loaded_newgrf_features
.used_liveries
, scheme
))) {
1070 Command
<CMD_SET_COMPANY_COLOUR
>::Post(scheme
, widget
== WID_SCL_PRI_COL_DROPDOWN
, (Colours
)index
);
1074 /* Setting group livery */
1075 Command
<CMD_SET_GROUP_LIVERY
>::Post(this->sel
, widget
== WID_SCL_PRI_COL_DROPDOWN
, (Colours
)index
);
1080 * Some data on this window has become invalid.
1081 * @param data Information about the changed data.
1082 * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
1084 void OnInvalidateData(int data
= 0, bool gui_scope
= true) override
1086 if (!gui_scope
) return;
1089 /* data contains a VehicleType, rebuild list if it displayed */
1090 if (this->livery_class
== data
+ LC_GROUP_RAIL
) {
1091 this->groups
.ForceRebuild();
1092 this->BuildGroupList((CompanyID
)this->window_number
);
1095 if (!Group::IsValidID(this->sel
)) {
1096 this->sel
= INVALID_GROUP
;
1097 if (this->groups
.size() > 0) this->sel
= this->groups
[0]->index
;
1105 this->SetWidgetsDisabledState(true, WID_SCL_CLASS_RAIL
, WID_SCL_CLASS_ROAD
, WID_SCL_CLASS_SHIP
, WID_SCL_CLASS_AIRCRAFT
, WIDGET_LIST_END
);
1107 bool current_class_valid
= this->livery_class
== LC_OTHER
|| this->livery_class
>= LC_GROUP_RAIL
;
1108 if (_settings_client
.gui
.liveries
== LIT_ALL
|| (_settings_client
.gui
.liveries
== LIT_COMPANY
&& this->window_number
== _local_company
)) {
1109 for (LiveryScheme scheme
= LS_DEFAULT
; scheme
< LS_END
; scheme
++) {
1110 if (HasBit(_loaded_newgrf_features
.used_liveries
, scheme
)) {
1111 if (_livery_class
[scheme
] == this->livery_class
) current_class_valid
= true;
1112 this->EnableWidget(WID_SCL_CLASS_GENERAL
+ _livery_class
[scheme
]);
1113 } else if (this->livery_class
< LC_GROUP_RAIL
) {
1114 ClrBit(this->sel
, scheme
);
1119 if (!current_class_valid
) {
1121 this->OnClick(pt
, WID_SCL_CLASS_GENERAL
, 1);
1126 static const NWidgetPart _nested_select_company_livery_widgets
[] = {
1127 NWidget(NWID_HORIZONTAL
),
1128 NWidget(WWT_CLOSEBOX
, COLOUR_GREY
),
1129 NWidget(WWT_CAPTION
, COLOUR_GREY
, WID_SCL_CAPTION
), SetDataTip(STR_LIVERY_CAPTION
, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS
),
1131 NWidget(NWID_HORIZONTAL
),
1132 NWidget(WWT_IMGBTN
, COLOUR_GREY
, WID_SCL_CLASS_GENERAL
), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_COMPANY_GENERAL
, STR_LIVERY_GENERAL_TOOLTIP
),
1133 NWidget(WWT_IMGBTN
, COLOUR_GREY
, WID_SCL_CLASS_RAIL
), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_TRAINLIST
, STR_LIVERY_TRAIN_TOOLTIP
),
1134 NWidget(WWT_IMGBTN
, COLOUR_GREY
, WID_SCL_CLASS_ROAD
), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_TRUCKLIST
, STR_LIVERY_ROAD_VEHICLE_TOOLTIP
),
1135 NWidget(WWT_IMGBTN
, COLOUR_GREY
, WID_SCL_CLASS_SHIP
), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_SHIPLIST
, STR_LIVERY_SHIP_TOOLTIP
),
1136 NWidget(WWT_IMGBTN
, COLOUR_GREY
, WID_SCL_CLASS_AIRCRAFT
), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_AIRPLANESLIST
, STR_LIVERY_AIRCRAFT_TOOLTIP
),
1137 NWidget(WWT_IMGBTN
, COLOUR_GREY
, WID_SCL_GROUPS_RAIL
), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_GROUP_LIVERY_TRAIN
, STR_LIVERY_TRAIN_TOOLTIP
),
1138 NWidget(WWT_IMGBTN
, COLOUR_GREY
, WID_SCL_GROUPS_ROAD
), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_GROUP_LIVERY_ROADVEH
, STR_LIVERY_ROAD_VEHICLE_TOOLTIP
),
1139 NWidget(WWT_IMGBTN
, COLOUR_GREY
, WID_SCL_GROUPS_SHIP
), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_GROUP_LIVERY_SHIP
, STR_LIVERY_SHIP_TOOLTIP
),
1140 NWidget(WWT_IMGBTN
, COLOUR_GREY
, WID_SCL_GROUPS_AIRCRAFT
), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_GROUP_LIVERY_AIRCRAFT
, STR_LIVERY_AIRCRAFT_TOOLTIP
),
1141 NWidget(WWT_PANEL
, COLOUR_GREY
), SetMinimalSize(90, 22), SetFill(1, 1), EndContainer(),
1143 NWidget(NWID_HORIZONTAL
),
1144 NWidget(WWT_PANEL
, COLOUR_GREY
, WID_SCL_SPACER_DROPDOWN
), SetMinimalSize(150, 12), SetFill(1, 1), EndContainer(),
1145 NWidget(WWT_DROPDOWN
, COLOUR_GREY
, WID_SCL_PRI_COL_DROPDOWN
), SetMinimalSize(125, 12), SetFill(0, 1), SetDataTip(STR_BLACK_STRING
, STR_LIVERY_PRIMARY_TOOLTIP
),
1146 NWidget(WWT_DROPDOWN
, COLOUR_GREY
, WID_SCL_SEC_COL_DROPDOWN
), SetMinimalSize(125, 12), SetFill(0, 1),
1147 SetDataTip(STR_BLACK_STRING
, STR_LIVERY_SECONDARY_TOOLTIP
),
1149 NWidget(NWID_HORIZONTAL
),
1150 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
),
1151 NWidget(NWID_VERTICAL
),
1152 NWidget(NWID_VSCROLLBAR
, COLOUR_GREY
, WID_SCL_MATRIX_SCROLLBAR
),
1153 NWidget(WWT_RESIZEBOX
, COLOUR_GREY
),
1158 static WindowDesc
_select_company_livery_desc(
1159 WDP_AUTO
, "company_livery", 0, 0,
1160 WC_COMPANY_COLOUR
, WC_NONE
,
1162 _nested_select_company_livery_widgets
, lengthof(_nested_select_company_livery_widgets
)
1165 void ShowCompanyLiveryWindow(CompanyID company
, GroupID group
)
1167 SelectCompanyLiveryWindow
*w
= (SelectCompanyLiveryWindow
*)BringWindowToFrontById(WC_COMPANY_COLOUR
, company
);
1169 new SelectCompanyLiveryWindow(&_select_company_livery_desc
, company
, group
);
1170 } else if (group
!= INVALID_GROUP
) {
1171 w
->SetSelectedGroup(company
, group
);
1176 * Draws the face of a company manager's face.
1177 * @param cmf the company manager's face
1178 * @param colour the (background) colour of the gradient
1179 * @param x x-position to draw the face
1180 * @param y y-position to draw the face
1182 void DrawCompanyManagerFace(CompanyManagerFace cmf
, int colour
, int x
, int y
)
1184 GenderEthnicity ge
= (GenderEthnicity
)GetCompanyManagerFaceBits(cmf
, CMFV_GEN_ETHN
, GE_WM
);
1186 bool has_moustache
= !HasBit(ge
, GENDER_FEMALE
) && GetCompanyManagerFaceBits(cmf
, CMFV_HAS_MOUSTACHE
, ge
) != 0;
1187 bool has_tie_earring
= !HasBit(ge
, GENDER_FEMALE
) || GetCompanyManagerFaceBits(cmf
, CMFV_HAS_TIE_EARRING
, ge
) != 0;
1188 bool has_glasses
= GetCompanyManagerFaceBits(cmf
, CMFV_HAS_GLASSES
, ge
) != 0;
1191 /* Modify eye colour palette only if 2 or more valid values exist */
1192 if (_cmf_info
[CMFV_EYE_COLOUR
].valid_values
[ge
] < 2) {
1195 switch (GetCompanyManagerFaceBits(cmf
, CMFV_EYE_COLOUR
, ge
)) {
1196 default: NOT_REACHED();
1197 case 0: pal
= PALETTE_TO_BROWN
; break;
1198 case 1: pal
= PALETTE_TO_BLUE
; break;
1199 case 2: pal
= PALETTE_TO_GREEN
; break;
1203 /* Draw the gradient (background) */
1204 DrawSprite(SPR_GRADIENT
, GENERAL_SPRITE_COLOUR(colour
), x
, y
);
1206 for (CompanyManagerFaceVariable cmfv
= CMFV_CHEEKS
; cmfv
< CMFV_END
; cmfv
++) {
1208 case CMFV_MOUSTACHE
: if (!has_moustache
) continue; break;
1210 case CMFV_NOSE
: if (has_moustache
) continue; break;
1211 case CMFV_TIE_EARRING
: if (!has_tie_earring
) continue; break;
1212 case CMFV_GLASSES
: if (!has_glasses
) continue; break;
1215 DrawSprite(GetCompanyManagerFaceSprite(cmf
, cmfv
, ge
), (cmfv
== CMFV_EYEBROWS
) ? pal
: PAL_NONE
, x
, y
);
1219 /** Nested widget description for the company manager face selection dialog */
1220 static const NWidgetPart _nested_select_company_manager_face_widgets
[] = {
1221 NWidget(NWID_HORIZONTAL
),
1222 NWidget(WWT_CLOSEBOX
, COLOUR_GREY
),
1223 NWidget(WWT_CAPTION
, COLOUR_GREY
, WID_SCMF_CAPTION
), SetDataTip(STR_FACE_CAPTION
, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS
),
1224 NWidget(WWT_IMGBTN
, COLOUR_GREY
, WID_SCMF_TOGGLE_LARGE_SMALL
), SetDataTip(SPR_LARGE_SMALL_WINDOW
, STR_FACE_ADVANCED_TOOLTIP
),
1226 NWidget(WWT_PANEL
, COLOUR_GREY
, WID_SCMF_SELECT_FACE
),
1227 NWidget(NWID_SPACER
), SetMinimalSize(0, 2),
1228 NWidget(NWID_HORIZONTAL
), SetPIP(2, 2, 2),
1229 NWidget(NWID_VERTICAL
),
1230 NWidget(NWID_HORIZONTAL
),
1231 NWidget(NWID_SPACER
), SetFill(1, 0),
1232 NWidget(WWT_EMPTY
, COLOUR_GREY
, WID_SCMF_FACE
), SetMinimalSize(92, 119),
1233 NWidget(NWID_SPACER
), SetFill(1, 0),
1235 NWidget(NWID_SPACER
), SetMinimalSize(0, 2),
1236 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_SCMF_RANDOM_NEW_FACE
), SetFill(1, 0), SetDataTip(STR_FACE_NEW_FACE_BUTTON
, STR_FACE_NEW_FACE_TOOLTIP
),
1237 NWidget(NWID_SELECTION
, INVALID_COLOUR
, WID_SCMF_SEL_LOADSAVE
), // Load/number/save buttons under the portrait in the advanced view.
1238 NWidget(NWID_VERTICAL
),
1239 NWidget(NWID_SPACER
), SetMinimalSize(0, 5), SetFill(0, 1),
1240 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_SCMF_LOAD
), SetFill(1, 0), SetDataTip(STR_FACE_LOAD
, STR_FACE_LOAD_TOOLTIP
),
1241 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_SCMF_FACECODE
), SetFill(1, 0), SetDataTip(STR_FACE_FACECODE
, STR_FACE_FACECODE_TOOLTIP
),
1242 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_SCMF_SAVE
), SetFill(1, 0), SetDataTip(STR_FACE_SAVE
, STR_FACE_SAVE_TOOLTIP
),
1243 NWidget(NWID_SPACER
), SetMinimalSize(0, 5), SetFill(0, 1),
1247 NWidget(NWID_VERTICAL
),
1248 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON
), SetFill(1, 0), SetDataTip(STR_FACE_ADVANCED
, STR_FACE_ADVANCED_TOOLTIP
),
1249 NWidget(NWID_SPACER
), SetMinimalSize(0, 2),
1250 NWidget(NWID_SELECTION
, INVALID_COLOUR
, WID_SCMF_SEL_MALEFEMALE
), // Simple male/female face setting.
1251 NWidget(NWID_VERTICAL
),
1252 NWidget(NWID_SPACER
), SetFill(0, 1),
1253 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_SCMF_MALE
), SetFill(1, 0), SetDataTip(STR_FACE_MALE_BUTTON
, STR_FACE_MALE_TOOLTIP
),
1254 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_SCMF_FEMALE
), SetFill(1, 0), SetDataTip(STR_FACE_FEMALE_BUTTON
, STR_FACE_FEMALE_TOOLTIP
),
1255 NWidget(NWID_SPACER
), SetFill(0, 1),
1258 NWidget(NWID_SELECTION
, INVALID_COLOUR
, WID_SCMF_SEL_PARTS
), // Advanced face parts setting.
1259 NWidget(NWID_VERTICAL
),
1260 NWidget(NWID_SPACER
), SetMinimalSize(0, 2),
1261 NWidget(NWID_HORIZONTAL
, NC_EQUALSIZE
),
1262 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_SCMF_MALE2
), SetFill(1, 0), SetDataTip(STR_FACE_MALE_BUTTON
, STR_FACE_MALE_TOOLTIP
),
1263 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_SCMF_FEMALE2
), SetFill(1, 0), SetDataTip(STR_FACE_FEMALE_BUTTON
, STR_FACE_FEMALE_TOOLTIP
),
1265 NWidget(NWID_SPACER
), SetMinimalSize(0, 2),
1266 NWidget(NWID_HORIZONTAL
, NC_EQUALSIZE
),
1267 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_SCMF_ETHNICITY_EUR
), SetFill(1, 0), SetDataTip(STR_FACE_EUROPEAN
, STR_FACE_SELECT_EUROPEAN
),
1268 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_SCMF_ETHNICITY_AFR
), SetFill(1, 0), SetDataTip(STR_FACE_AFRICAN
, STR_FACE_SELECT_AFRICAN
),
1270 NWidget(NWID_SPACER
), SetMinimalSize(0, 4),
1271 NWidget(NWID_HORIZONTAL
),
1272 NWidget(WWT_TEXT
, INVALID_COLOUR
, WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT
), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT
, 0, WD_FRAMERECT_LEFT
),
1273 SetDataTip(STR_FACE_EYECOLOUR
, STR_NULL
), SetTextColour(TC_GOLD
), SetAlignment(SA_VERT_CENTER
| SA_RIGHT
),
1274 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_SCMF_HAS_MOUSTACHE_EARRING
), SetDataTip(STR_WHITE_STRING
, STR_FACE_MOUSTACHE_EARRING_TOOLTIP
),
1276 NWidget(NWID_HORIZONTAL
),
1277 NWidget(WWT_TEXT
, INVALID_COLOUR
, WID_SCMF_HAS_GLASSES_TEXT
), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT
, 0, WD_FRAMERECT_LEFT
),
1278 SetDataTip(STR_FACE_GLASSES
, STR_NULL
), SetTextColour(TC_GOLD
), SetAlignment(SA_VERT_CENTER
| SA_RIGHT
),
1279 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_SCMF_HAS_GLASSES
), SetDataTip(STR_WHITE_STRING
, STR_FACE_GLASSES_TOOLTIP
),
1281 NWidget(NWID_SPACER
), SetMinimalSize(0, 2), SetFill(1, 0),
1282 NWidget(NWID_HORIZONTAL
),
1283 NWidget(WWT_TEXT
, INVALID_COLOUR
, WID_SCMF_HAIR_TEXT
), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT
, 0, WD_FRAMERECT_LEFT
),
1284 SetDataTip(STR_FACE_HAIR
, STR_NULL
), SetTextColour(TC_GOLD
), SetAlignment(SA_VERT_CENTER
| SA_RIGHT
),
1285 NWidget(WWT_PUSHARROWBTN
, COLOUR_GREY
, WID_SCMF_HAIR_L
), SetDataTip(AWV_DECREASE
, STR_FACE_HAIR_TOOLTIP
),
1286 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_SCMF_HAIR
), SetDataTip(STR_WHITE_STRING
, STR_FACE_HAIR_TOOLTIP
),
1287 NWidget(WWT_PUSHARROWBTN
, COLOUR_GREY
, WID_SCMF_HAIR_R
), SetDataTip(AWV_INCREASE
, STR_FACE_HAIR_TOOLTIP
),
1289 NWidget(NWID_HORIZONTAL
),
1290 NWidget(WWT_TEXT
, INVALID_COLOUR
, WID_SCMF_EYEBROWS_TEXT
), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT
, 0, WD_FRAMERECT_LEFT
),
1291 SetDataTip(STR_FACE_EYEBROWS
, STR_NULL
), SetTextColour(TC_GOLD
), SetAlignment(SA_VERT_CENTER
| SA_RIGHT
),
1292 NWidget(WWT_PUSHARROWBTN
, COLOUR_GREY
, WID_SCMF_EYEBROWS_L
), SetDataTip(AWV_DECREASE
, STR_FACE_EYEBROWS_TOOLTIP
),
1293 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_SCMF_EYEBROWS
), SetDataTip(STR_WHITE_STRING
, STR_FACE_EYEBROWS_TOOLTIP
),
1294 NWidget(WWT_PUSHARROWBTN
, COLOUR_GREY
, WID_SCMF_EYEBROWS_R
), SetDataTip(AWV_INCREASE
, STR_FACE_EYEBROWS_TOOLTIP
),
1296 NWidget(NWID_HORIZONTAL
),
1297 NWidget(WWT_TEXT
, INVALID_COLOUR
, WID_SCMF_EYECOLOUR_TEXT
), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT
, 0, WD_FRAMERECT_LEFT
),
1298 SetDataTip(STR_FACE_EYECOLOUR
, STR_NULL
), SetTextColour(TC_GOLD
), SetAlignment(SA_VERT_CENTER
| SA_RIGHT
),
1299 NWidget(WWT_PUSHARROWBTN
, COLOUR_GREY
, WID_SCMF_EYECOLOUR_L
), SetDataTip(AWV_DECREASE
, STR_FACE_EYECOLOUR_TOOLTIP
),
1300 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_SCMF_EYECOLOUR
), SetDataTip(STR_WHITE_STRING
, STR_FACE_EYECOLOUR_TOOLTIP
),
1301 NWidget(WWT_PUSHARROWBTN
, COLOUR_GREY
, WID_SCMF_EYECOLOUR_R
), SetDataTip(AWV_INCREASE
, STR_FACE_EYECOLOUR_TOOLTIP
),
1303 NWidget(NWID_HORIZONTAL
),
1304 NWidget(WWT_TEXT
, INVALID_COLOUR
, WID_SCMF_GLASSES_TEXT
), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT
, 0, WD_FRAMERECT_LEFT
),
1305 SetDataTip(STR_FACE_GLASSES
, STR_NULL
), SetTextColour(TC_GOLD
), SetAlignment(SA_VERT_CENTER
| SA_RIGHT
),
1306 NWidget(WWT_PUSHARROWBTN
, COLOUR_GREY
, WID_SCMF_GLASSES_L
), SetDataTip(AWV_DECREASE
, STR_FACE_GLASSES_TOOLTIP_2
),
1307 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_SCMF_GLASSES
), SetDataTip(STR_WHITE_STRING
, STR_FACE_GLASSES_TOOLTIP_2
),
1308 NWidget(WWT_PUSHARROWBTN
, COLOUR_GREY
, WID_SCMF_GLASSES_R
), SetDataTip(AWV_INCREASE
, STR_FACE_GLASSES_TOOLTIP_2
),
1310 NWidget(NWID_HORIZONTAL
),
1311 NWidget(WWT_TEXT
, INVALID_COLOUR
, WID_SCMF_NOSE_TEXT
), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT
, 0, WD_FRAMERECT_LEFT
),
1312 SetDataTip(STR_FACE_NOSE
, STR_NULL
), SetTextColour(TC_GOLD
), SetAlignment(SA_VERT_CENTER
| SA_RIGHT
),
1313 NWidget(WWT_PUSHARROWBTN
, COLOUR_GREY
, WID_SCMF_NOSE_L
), SetDataTip(AWV_DECREASE
, STR_FACE_NOSE_TOOLTIP
),
1314 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_SCMF_NOSE
), SetDataTip(STR_WHITE_STRING
, STR_FACE_NOSE_TOOLTIP
),
1315 NWidget(WWT_PUSHARROWBTN
, COLOUR_GREY
, WID_SCMF_NOSE_R
), SetDataTip(AWV_INCREASE
, STR_FACE_NOSE_TOOLTIP
),
1317 NWidget(NWID_HORIZONTAL
),
1318 NWidget(WWT_TEXT
, INVALID_COLOUR
, WID_SCMF_LIPS_MOUSTACHE_TEXT
), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT
, 0, WD_FRAMERECT_LEFT
),
1319 SetDataTip(STR_FACE_MOUSTACHE
, STR_NULL
), SetTextColour(TC_GOLD
), SetAlignment(SA_VERT_CENTER
| SA_RIGHT
),
1320 NWidget(WWT_PUSHARROWBTN
, COLOUR_GREY
, WID_SCMF_LIPS_MOUSTACHE_L
), SetDataTip(AWV_DECREASE
, STR_FACE_LIPS_MOUSTACHE_TOOLTIP
),
1321 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_SCMF_LIPS_MOUSTACHE
), SetDataTip(STR_WHITE_STRING
, STR_FACE_LIPS_MOUSTACHE_TOOLTIP
),
1322 NWidget(WWT_PUSHARROWBTN
, COLOUR_GREY
, WID_SCMF_LIPS_MOUSTACHE_R
), SetDataTip(AWV_INCREASE
, STR_FACE_LIPS_MOUSTACHE_TOOLTIP
),
1324 NWidget(NWID_HORIZONTAL
),
1325 NWidget(WWT_TEXT
, INVALID_COLOUR
, WID_SCMF_CHIN_TEXT
), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT
, 0, WD_FRAMERECT_LEFT
),
1326 SetDataTip(STR_FACE_CHIN
, STR_NULL
), SetTextColour(TC_GOLD
), SetAlignment(SA_VERT_CENTER
| SA_RIGHT
),
1327 NWidget(WWT_PUSHARROWBTN
, COLOUR_GREY
, WID_SCMF_CHIN_L
), SetDataTip(AWV_DECREASE
, STR_FACE_CHIN_TOOLTIP
),
1328 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_SCMF_CHIN
), SetDataTip(STR_WHITE_STRING
, STR_FACE_CHIN_TOOLTIP
),
1329 NWidget(WWT_PUSHARROWBTN
, COLOUR_GREY
, WID_SCMF_CHIN_R
), SetDataTip(AWV_INCREASE
, STR_FACE_CHIN_TOOLTIP
),
1331 NWidget(NWID_HORIZONTAL
),
1332 NWidget(WWT_TEXT
, INVALID_COLOUR
, WID_SCMF_JACKET_TEXT
), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT
, 0, WD_FRAMERECT_LEFT
),
1333 SetDataTip(STR_FACE_JACKET
, STR_NULL
), SetTextColour(TC_GOLD
), SetAlignment(SA_VERT_CENTER
| SA_RIGHT
),
1334 NWidget(WWT_PUSHARROWBTN
, COLOUR_GREY
, WID_SCMF_JACKET_L
), SetDataTip(AWV_DECREASE
, STR_FACE_JACKET_TOOLTIP
),
1335 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_SCMF_JACKET
), SetDataTip(STR_WHITE_STRING
, STR_FACE_JACKET_TOOLTIP
),
1336 NWidget(WWT_PUSHARROWBTN
, COLOUR_GREY
, WID_SCMF_JACKET_R
), SetDataTip(AWV_INCREASE
, STR_FACE_JACKET_TOOLTIP
),
1338 NWidget(NWID_HORIZONTAL
),
1339 NWidget(WWT_TEXT
, INVALID_COLOUR
, WID_SCMF_COLLAR_TEXT
), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT
, 0, WD_FRAMERECT_LEFT
),
1340 SetDataTip(STR_FACE_COLLAR
, STR_NULL
), SetTextColour(TC_GOLD
), SetAlignment(SA_VERT_CENTER
| SA_RIGHT
),
1341 NWidget(WWT_PUSHARROWBTN
, COLOUR_GREY
, WID_SCMF_COLLAR_L
), SetDataTip(AWV_DECREASE
, STR_FACE_COLLAR_TOOLTIP
),
1342 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_SCMF_COLLAR
), SetDataTip(STR_WHITE_STRING
, STR_FACE_COLLAR_TOOLTIP
),
1343 NWidget(WWT_PUSHARROWBTN
, COLOUR_GREY
, WID_SCMF_COLLAR_R
), SetDataTip(AWV_INCREASE
, STR_FACE_COLLAR_TOOLTIP
),
1345 NWidget(NWID_HORIZONTAL
),
1346 NWidget(WWT_TEXT
, INVALID_COLOUR
, WID_SCMF_TIE_EARRING_TEXT
), SetFill(1, 0), SetPadding(0, WD_FRAMERECT_RIGHT
, 0, WD_FRAMERECT_LEFT
),
1347 SetDataTip(STR_FACE_EARRING
, STR_NULL
), SetTextColour(TC_GOLD
), SetAlignment(SA_VERT_CENTER
| SA_RIGHT
),
1348 NWidget(WWT_PUSHARROWBTN
, COLOUR_GREY
, WID_SCMF_TIE_EARRING_L
), SetDataTip(AWV_DECREASE
, STR_FACE_TIE_EARRING_TOOLTIP
),
1349 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_SCMF_TIE_EARRING
), SetDataTip(STR_WHITE_STRING
, STR_FACE_TIE_EARRING_TOOLTIP
),
1350 NWidget(WWT_PUSHARROWBTN
, COLOUR_GREY
, WID_SCMF_TIE_EARRING_R
), SetDataTip(AWV_INCREASE
, STR_FACE_TIE_EARRING_TOOLTIP
),
1352 NWidget(NWID_SPACER
), SetFill(0, 1),
1357 NWidget(NWID_SPACER
), SetMinimalSize(0, 2),
1359 NWidget(NWID_HORIZONTAL
, NC_EQUALSIZE
),
1360 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_SCMF_CANCEL
), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL
, STR_FACE_CANCEL_TOOLTIP
),
1361 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_SCMF_ACCEPT
), SetFill(1, 0), SetDataTip(STR_BUTTON_OK
, STR_FACE_OK_TOOLTIP
),
1365 /** Management class for customizing the face of the company manager. */
1366 class SelectCompanyManagerFaceWindow
: public Window
1368 CompanyManagerFace face
; ///< company manager face bits
1369 bool advanced
; ///< advanced company manager face selection window
1371 GenderEthnicity ge
; ///< Gender and ethnicity.
1372 bool is_female
; ///< Female face.
1373 bool is_moust_male
; ///< Male face with a moustache.
1375 Dimension yesno_dim
; ///< Dimension of a yes/no button of a part in the advanced face window.
1376 Dimension number_dim
; ///< Dimension of a number widget of a part in the advanced face window.
1379 * Set parameters for value of face control buttons.
1381 * @param widget_index index of this widget in the window
1382 * @param val the value which will be displayed
1383 * @param is_bool_widget is it a bool button
1385 void SetFaceStringParameters(byte widget_index
, uint8 val
, bool is_bool_widget
) const
1387 const NWidgetCore
*nwi_widget
= this->GetWidget
<NWidgetCore
>(widget_index
);
1388 if (nwi_widget
->IsDisabled()) {
1389 SetDParam(0, STR_EMPTY
);
1391 if (is_bool_widget
) {
1392 /* if it a bool button write yes or no */
1393 SetDParam(0, (val
!= 0) ? STR_FACE_YES
: STR_FACE_NO
);
1395 /* else write the value + 1 */
1396 SetDParam(0, STR_JUST_INT
);
1397 SetDParam(1, val
+ 1);
1404 this->ge
= (GenderEthnicity
)GB(this->face
, _cmf_info
[CMFV_GEN_ETHN
].offset
, _cmf_info
[CMFV_GEN_ETHN
].length
); // get the gender and ethnicity
1405 this->is_female
= HasBit(this->ge
, GENDER_FEMALE
); // get the gender: 0 == male and 1 == female
1406 this->is_moust_male
= !is_female
&& GetCompanyManagerFaceBits(this->face
, CMFV_HAS_MOUSTACHE
, this->ge
) != 0; // is a male face with moustache
1408 this->GetWidget
<NWidgetCore
>(WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT
)->widget_data
= this->is_female
? STR_FACE_EARRING
: STR_FACE_MOUSTACHE
;
1409 this->GetWidget
<NWidgetCore
>(WID_SCMF_TIE_EARRING_TEXT
)->widget_data
= this->is_female
? STR_FACE_EARRING
: STR_FACE_TIE
;
1410 this->GetWidget
<NWidgetCore
>(WID_SCMF_LIPS_MOUSTACHE_TEXT
)->widget_data
= this->is_moust_male
? STR_FACE_MOUSTACHE
: STR_FACE_LIPS
;
1414 SelectCompanyManagerFaceWindow(WindowDesc
*desc
, Window
*parent
) : Window(desc
)
1416 this->advanced
= false;
1417 this->CreateNestedTree();
1418 this->SelectDisplayPlanes(this->advanced
);
1419 this->FinishInitNested(parent
->window_number
);
1420 this->parent
= parent
;
1421 this->owner
= (Owner
)this->window_number
;
1422 this->face
= Company::Get((CompanyID
)this->window_number
)->face
;
1428 * Select planes to display to the user with the #NWID_SELECTION widgets #WID_SCMF_SEL_LOADSAVE, #WID_SCMF_SEL_MALEFEMALE, and #WID_SCMF_SEL_PARTS.
1429 * @param advanced Display advanced face management window.
1431 void SelectDisplayPlanes(bool advanced
)
1433 this->GetWidget
<NWidgetStacked
>(WID_SCMF_SEL_LOADSAVE
)->SetDisplayedPlane(advanced
? 0 : SZSP_NONE
);
1434 this->GetWidget
<NWidgetStacked
>(WID_SCMF_SEL_PARTS
)->SetDisplayedPlane(advanced
? 0 : SZSP_NONE
);
1435 this->GetWidget
<NWidgetStacked
>(WID_SCMF_SEL_MALEFEMALE
)->SetDisplayedPlane(advanced
? SZSP_NONE
: 0);
1436 this->GetWidget
<NWidgetCore
>(WID_SCMF_RANDOM_NEW_FACE
)->widget_data
= advanced
? STR_FACE_RANDOM
: STR_FACE_NEW_FACE_BUTTON
;
1438 NWidgetCore
*wi
= this->GetWidget
<NWidgetCore
>(WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON
);
1440 wi
->SetDataTip(STR_FACE_SIMPLE
, STR_FACE_SIMPLE_TOOLTIP
);
1442 wi
->SetDataTip(STR_FACE_ADVANCED
, STR_FACE_ADVANCED_TOOLTIP
);
1446 void OnInit() override
1448 /* Size of the boolean yes/no button. */
1449 Dimension yesno_dim
= maxdim(GetStringBoundingBox(STR_FACE_YES
), GetStringBoundingBox(STR_FACE_NO
));
1450 yesno_dim
.width
+= WD_FRAMERECT_LEFT
+ WD_FRAMERECT_RIGHT
;
1451 yesno_dim
.height
+= WD_FRAMERECT_TOP
+ WD_FRAMERECT_BOTTOM
;
1452 /* Size of the number button + arrows. */
1453 Dimension number_dim
= {0, 0};
1454 for (int val
= 1; val
<= 12; val
++) {
1456 number_dim
= maxdim(number_dim
, GetStringBoundingBox(STR_JUST_INT
));
1458 uint arrows_width
= GetSpriteSize(SPR_ARROW_LEFT
).width
+ GetSpriteSize(SPR_ARROW_RIGHT
).width
+ 2 * (WD_IMGBTN_LEFT
+ WD_IMGBTN_RIGHT
);
1459 number_dim
.width
+= WD_FRAMERECT_LEFT
+ WD_FRAMERECT_RIGHT
+ arrows_width
;
1460 number_dim
.height
+= WD_FRAMERECT_TOP
+ WD_FRAMERECT_BOTTOM
;
1461 /* Compute width of both buttons. */
1462 yesno_dim
.width
= std::max(yesno_dim
.width
, number_dim
.width
);
1463 number_dim
.width
= yesno_dim
.width
- arrows_width
;
1465 this->yesno_dim
= yesno_dim
;
1466 this->number_dim
= number_dim
;
1469 void UpdateWidgetSize(int widget
, Dimension
*size
, const Dimension
&padding
, Dimension
*fill
, Dimension
*resize
) override
1472 case WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT
:
1473 *size
= maxdim(*size
, GetStringBoundingBox(STR_FACE_EARRING
));
1474 *size
= maxdim(*size
, GetStringBoundingBox(STR_FACE_MOUSTACHE
));
1477 case WID_SCMF_TIE_EARRING_TEXT
:
1478 *size
= maxdim(*size
, GetStringBoundingBox(STR_FACE_EARRING
));
1479 *size
= maxdim(*size
, GetStringBoundingBox(STR_FACE_TIE
));
1482 case WID_SCMF_LIPS_MOUSTACHE_TEXT
:
1483 *size
= maxdim(*size
, GetStringBoundingBox(STR_FACE_LIPS
));
1484 *size
= maxdim(*size
, GetStringBoundingBox(STR_FACE_MOUSTACHE
));
1487 case WID_SCMF_FACE
: {
1488 Dimension face_size
= GetSpriteSize(SPR_GRADIENT
);
1489 size
->width
= std::max(size
->width
, face_size
.width
);
1490 size
->height
= std::max(size
->height
, face_size
.height
);
1494 case WID_SCMF_HAS_MOUSTACHE_EARRING
:
1495 case WID_SCMF_HAS_GLASSES
:
1496 *size
= this->yesno_dim
;
1499 case WID_SCMF_EYECOLOUR
:
1501 case WID_SCMF_EYEBROWS
:
1502 case WID_SCMF_LIPS_MOUSTACHE
:
1505 case WID_SCMF_JACKET
:
1506 case WID_SCMF_COLLAR
:
1507 case WID_SCMF_TIE_EARRING
:
1508 case WID_SCMF_GLASSES
:
1509 *size
= this->number_dim
;
1514 void OnPaint() override
1516 /* lower the non-selected gender button */
1517 this->SetWidgetsLoweredState(!this->is_female
, WID_SCMF_MALE
, WID_SCMF_MALE2
, WIDGET_LIST_END
);
1518 this->SetWidgetsLoweredState( this->is_female
, WID_SCMF_FEMALE
, WID_SCMF_FEMALE2
, WIDGET_LIST_END
);
1520 /* advanced company manager face selection window */
1522 /* lower the non-selected ethnicity button */
1523 this->SetWidgetLoweredState(WID_SCMF_ETHNICITY_EUR
, !HasBit(this->ge
, ETHNICITY_BLACK
));
1524 this->SetWidgetLoweredState(WID_SCMF_ETHNICITY_AFR
, HasBit(this->ge
, ETHNICITY_BLACK
));
1527 /* Disable dynamically the widgets which CompanyManagerFaceVariable has less than 2 options
1528 * (or in other words you haven't any choice).
1529 * If the widgets depend on a HAS-variable and this is false the widgets will be disabled, too. */
1531 /* Eye colour buttons */
1532 this->SetWidgetsDisabledState(_cmf_info
[CMFV_EYE_COLOUR
].valid_values
[this->ge
] < 2,
1533 WID_SCMF_EYECOLOUR
, WID_SCMF_EYECOLOUR_L
, WID_SCMF_EYECOLOUR_R
, WIDGET_LIST_END
);
1536 this->SetWidgetsDisabledState(_cmf_info
[CMFV_CHIN
].valid_values
[this->ge
] < 2,
1537 WID_SCMF_CHIN
, WID_SCMF_CHIN_L
, WID_SCMF_CHIN_R
, WIDGET_LIST_END
);
1539 /* Eyebrows buttons */
1540 this->SetWidgetsDisabledState(_cmf_info
[CMFV_EYEBROWS
].valid_values
[this->ge
] < 2,
1541 WID_SCMF_EYEBROWS
, WID_SCMF_EYEBROWS_L
, WID_SCMF_EYEBROWS_R
, WIDGET_LIST_END
);
1543 /* Lips or (if it a male face with a moustache) moustache buttons */
1544 this->SetWidgetsDisabledState(_cmf_info
[this->is_moust_male
? CMFV_MOUSTACHE
: CMFV_LIPS
].valid_values
[this->ge
] < 2,
1545 WID_SCMF_LIPS_MOUSTACHE
, WID_SCMF_LIPS_MOUSTACHE_L
, WID_SCMF_LIPS_MOUSTACHE_R
, WIDGET_LIST_END
);
1547 /* Nose buttons | male faces with moustache haven't any nose options */
1548 this->SetWidgetsDisabledState(_cmf_info
[CMFV_NOSE
].valid_values
[this->ge
] < 2 || this->is_moust_male
,
1549 WID_SCMF_NOSE
, WID_SCMF_NOSE_L
, WID_SCMF_NOSE_R
, WIDGET_LIST_END
);
1552 this->SetWidgetsDisabledState(_cmf_info
[CMFV_HAIR
].valid_values
[this->ge
] < 2,
1553 WID_SCMF_HAIR
, WID_SCMF_HAIR_L
, WID_SCMF_HAIR_R
, WIDGET_LIST_END
);
1555 /* Jacket buttons */
1556 this->SetWidgetsDisabledState(_cmf_info
[CMFV_JACKET
].valid_values
[this->ge
] < 2,
1557 WID_SCMF_JACKET
, WID_SCMF_JACKET_L
, WID_SCMF_JACKET_R
, WIDGET_LIST_END
);
1559 /* Collar buttons */
1560 this->SetWidgetsDisabledState(_cmf_info
[CMFV_COLLAR
].valid_values
[this->ge
] < 2,
1561 WID_SCMF_COLLAR
, WID_SCMF_COLLAR_L
, WID_SCMF_COLLAR_R
, WIDGET_LIST_END
);
1563 /* Tie/earring buttons | female faces without earring haven't any earring options */
1564 this->SetWidgetsDisabledState(_cmf_info
[CMFV_TIE_EARRING
].valid_values
[this->ge
] < 2 ||
1565 (this->is_female
&& GetCompanyManagerFaceBits(this->face
, CMFV_HAS_TIE_EARRING
, this->ge
) == 0),
1566 WID_SCMF_TIE_EARRING
, WID_SCMF_TIE_EARRING_L
, WID_SCMF_TIE_EARRING_R
, WIDGET_LIST_END
);
1568 /* Glasses buttons | faces without glasses haven't any glasses options */
1569 this->SetWidgetsDisabledState(_cmf_info
[CMFV_GLASSES
].valid_values
[this->ge
] < 2 || GetCompanyManagerFaceBits(this->face
, CMFV_HAS_GLASSES
, this->ge
) == 0,
1570 WID_SCMF_GLASSES
, WID_SCMF_GLASSES_L
, WID_SCMF_GLASSES_R
, WIDGET_LIST_END
);
1572 this->DrawWidgets();
1575 void SetStringParameters(int widget
) const override
1578 case WID_SCMF_HAS_MOUSTACHE_EARRING
:
1579 if (this->is_female
) { // Only for female faces
1580 this->SetFaceStringParameters(WID_SCMF_HAS_MOUSTACHE_EARRING
, GetCompanyManagerFaceBits(this->face
, CMFV_HAS_TIE_EARRING
, this->ge
), true);
1581 } else { // Only for male faces
1582 this->SetFaceStringParameters(WID_SCMF_HAS_MOUSTACHE_EARRING
, GetCompanyManagerFaceBits(this->face
, CMFV_HAS_MOUSTACHE
, this->ge
), true);
1586 case WID_SCMF_TIE_EARRING
:
1587 this->SetFaceStringParameters(WID_SCMF_TIE_EARRING
, GetCompanyManagerFaceBits(this->face
, CMFV_TIE_EARRING
, this->ge
), false);
1590 case WID_SCMF_LIPS_MOUSTACHE
:
1591 if (this->is_moust_male
) { // Only for male faces with moustache
1592 this->SetFaceStringParameters(WID_SCMF_LIPS_MOUSTACHE
, GetCompanyManagerFaceBits(this->face
, CMFV_MOUSTACHE
, this->ge
), false);
1593 } else { // Only for female faces or male faces without moustache
1594 this->SetFaceStringParameters(WID_SCMF_LIPS_MOUSTACHE
, GetCompanyManagerFaceBits(this->face
, CMFV_LIPS
, this->ge
), false);
1598 case WID_SCMF_HAS_GLASSES
:
1599 this->SetFaceStringParameters(WID_SCMF_HAS_GLASSES
, GetCompanyManagerFaceBits(this->face
, CMFV_HAS_GLASSES
, this->ge
), true );
1603 this->SetFaceStringParameters(WID_SCMF_HAIR
, GetCompanyManagerFaceBits(this->face
, CMFV_HAIR
, this->ge
), false);
1606 case WID_SCMF_EYEBROWS
:
1607 this->SetFaceStringParameters(WID_SCMF_EYEBROWS
, GetCompanyManagerFaceBits(this->face
, CMFV_EYEBROWS
, this->ge
), false);
1610 case WID_SCMF_EYECOLOUR
:
1611 this->SetFaceStringParameters(WID_SCMF_EYECOLOUR
, GetCompanyManagerFaceBits(this->face
, CMFV_EYE_COLOUR
, this->ge
), false);
1614 case WID_SCMF_GLASSES
:
1615 this->SetFaceStringParameters(WID_SCMF_GLASSES
, GetCompanyManagerFaceBits(this->face
, CMFV_GLASSES
, this->ge
), false);
1619 this->SetFaceStringParameters(WID_SCMF_NOSE
, GetCompanyManagerFaceBits(this->face
, CMFV_NOSE
, this->ge
), false);
1623 this->SetFaceStringParameters(WID_SCMF_CHIN
, GetCompanyManagerFaceBits(this->face
, CMFV_CHIN
, this->ge
), false);
1626 case WID_SCMF_JACKET
:
1627 this->SetFaceStringParameters(WID_SCMF_JACKET
, GetCompanyManagerFaceBits(this->face
, CMFV_JACKET
, this->ge
), false);
1630 case WID_SCMF_COLLAR
:
1631 this->SetFaceStringParameters(WID_SCMF_COLLAR
, GetCompanyManagerFaceBits(this->face
, CMFV_COLLAR
, this->ge
), false);
1636 void DrawWidget(const Rect
&r
, int widget
) const override
1640 DrawCompanyManagerFace(this->face
, Company::Get((CompanyID
)this->window_number
)->colour
, r
.left
, r
.top
);
1645 void OnClick(Point pt
, int widget
, int click_count
) override
1648 /* Toggle size, advanced/simple face selection */
1649 case WID_SCMF_TOGGLE_LARGE_SMALL
:
1650 case WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON
:
1651 this->advanced
= !this->advanced
;
1652 this->SelectDisplayPlanes(this->advanced
);
1657 case WID_SCMF_ACCEPT
:
1658 Command
<CMD_SET_COMPANY_MANAGER_FACE
>::Post(this->face
);
1662 case WID_SCMF_CANCEL
:
1668 this->face
= _company_manager_face
;
1669 ScaleAllCompanyManagerFaceBits(this->face
);
1670 ShowErrorMessage(STR_FACE_LOAD_DONE
, INVALID_STRING_ID
, WL_INFO
);
1675 /* 'Company manager face number' button, view and/or set company manager face number */
1676 case WID_SCMF_FACECODE
:
1677 SetDParam(0, this->face
);
1678 ShowQueryString(STR_JUST_INT
, STR_FACE_FACECODE_CAPTION
, 10 + 1, this, CS_NUMERAL
, QSF_NONE
);
1683 _company_manager_face
= this->face
;
1684 ShowErrorMessage(STR_FACE_SAVE_DONE
, INVALID_STRING_ID
, WL_INFO
);
1687 /* Toggle gender (male/female) button */
1689 case WID_SCMF_FEMALE
:
1690 case WID_SCMF_MALE2
:
1691 case WID_SCMF_FEMALE2
:
1692 SetCompanyManagerFaceBits(this->face
, CMFV_GENDER
, this->ge
, (widget
== WID_SCMF_FEMALE
|| widget
== WID_SCMF_FEMALE2
));
1693 ScaleAllCompanyManagerFaceBits(this->face
);
1698 /* Randomize face button */
1699 case WID_SCMF_RANDOM_NEW_FACE
:
1700 RandomCompanyManagerFaceBits(this->face
, this->ge
, this->advanced
);
1705 /* Toggle ethnicity (european/african) button */
1706 case WID_SCMF_ETHNICITY_EUR
:
1707 case WID_SCMF_ETHNICITY_AFR
:
1708 SetCompanyManagerFaceBits(this->face
, CMFV_ETHNICITY
, this->ge
, widget
- WID_SCMF_ETHNICITY_EUR
);
1709 ScaleAllCompanyManagerFaceBits(this->face
);
1715 /* Here all buttons from WID_SCMF_HAS_MOUSTACHE_EARRING to WID_SCMF_GLASSES_R are handled.
1716 * First it checks which CompanyManagerFaceVariable is being changed, and then either
1717 * a: invert the value for boolean variables, or
1718 * b: it checks inside of IncreaseCompanyManagerFaceBits() if a left (_L) butten is pressed and then decrease else increase the variable */
1719 if (widget
>= WID_SCMF_HAS_MOUSTACHE_EARRING
&& widget
<= WID_SCMF_GLASSES_R
) {
1720 CompanyManagerFaceVariable cmfv
; // which CompanyManagerFaceVariable shall be edited
1722 if (widget
< WID_SCMF_EYECOLOUR_L
) { // Bool buttons
1723 switch (widget
- WID_SCMF_HAS_MOUSTACHE_EARRING
) {
1724 default: NOT_REACHED();
1725 case 0: cmfv
= this->is_female
? CMFV_HAS_TIE_EARRING
: CMFV_HAS_MOUSTACHE
; break; // Has earring/moustache button
1726 case 1: cmfv
= CMFV_HAS_GLASSES
; break; // Has glasses button
1728 SetCompanyManagerFaceBits(this->face
, cmfv
, this->ge
, !GetCompanyManagerFaceBits(this->face
, cmfv
, this->ge
));
1729 ScaleAllCompanyManagerFaceBits(this->face
);
1730 } else { // Value buttons
1731 switch ((widget
- WID_SCMF_EYECOLOUR_L
) / 3) {
1732 default: NOT_REACHED();
1733 case 0: cmfv
= CMFV_EYE_COLOUR
; break; // Eye colour buttons
1734 case 1: cmfv
= CMFV_CHIN
; break; // Chin buttons
1735 case 2: cmfv
= CMFV_EYEBROWS
; break; // Eyebrows buttons
1736 case 3: cmfv
= this->is_moust_male
? CMFV_MOUSTACHE
: CMFV_LIPS
; break; // Moustache or lips buttons
1737 case 4: cmfv
= CMFV_NOSE
; break; // Nose buttons
1738 case 5: cmfv
= CMFV_HAIR
; break; // Hair buttons
1739 case 6: cmfv
= CMFV_JACKET
; break; // Jacket buttons
1740 case 7: cmfv
= CMFV_COLLAR
; break; // Collar buttons
1741 case 8: cmfv
= CMFV_TIE_EARRING
; break; // Tie/earring buttons
1742 case 9: cmfv
= CMFV_GLASSES
; break; // Glasses buttons
1744 /* 0 == left (_L), 1 == middle or 2 == right (_R) - button click */
1745 IncreaseCompanyManagerFaceBits(this->face
, cmfv
, this->ge
, (((widget
- WID_SCMF_EYECOLOUR_L
) % 3) != 0) ? 1 : -1);
1754 void OnQueryTextFinished(char *str
) override
1756 if (str
== nullptr) return;
1757 /* Set a new company manager face number */
1758 if (!StrEmpty(str
)) {
1759 this->face
= strtoul(str
, nullptr, 10);
1760 ScaleAllCompanyManagerFaceBits(this->face
);
1761 ShowErrorMessage(STR_FACE_FACECODE_SET
, INVALID_STRING_ID
, WL_INFO
);
1765 ShowErrorMessage(STR_FACE_FACECODE_ERR
, INVALID_STRING_ID
, WL_INFO
);
1770 /** Company manager face selection window description */
1771 static WindowDesc
_select_company_manager_face_desc(
1772 WDP_AUTO
, "company_face", 0, 0,
1773 WC_COMPANY_MANAGER_FACE
, WC_NONE
,
1775 _nested_select_company_manager_face_widgets
, lengthof(_nested_select_company_manager_face_widgets
)
1779 * Open the simple/advanced company manager face selection window
1781 * @param parent the parent company window
1783 static void DoSelectCompanyManagerFace(Window
*parent
)
1785 if (!Company::IsValidID((CompanyID
)parent
->window_number
)) return;
1787 if (BringWindowToFrontById(WC_COMPANY_MANAGER_FACE
, parent
->window_number
)) return;
1788 new SelectCompanyManagerFaceWindow(&_select_company_manager_face_desc
, parent
);
1791 static const NWidgetPart _nested_company_infrastructure_widgets
[] = {
1792 NWidget(NWID_HORIZONTAL
),
1793 NWidget(WWT_CLOSEBOX
, COLOUR_GREY
),
1794 NWidget(WWT_CAPTION
, COLOUR_GREY
, WID_CI_CAPTION
), SetDataTip(STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION
, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS
),
1795 NWidget(WWT_SHADEBOX
, COLOUR_GREY
),
1796 NWidget(WWT_STICKYBOX
, COLOUR_GREY
),
1798 NWidget(WWT_PANEL
, COLOUR_GREY
),
1799 NWidget(NWID_VERTICAL
), SetPIP(WD_FRAMERECT_TOP
, 4, WD_FRAMETEXT_BOTTOM
),
1800 NWidget(NWID_HORIZONTAL
), SetPIP(2, 4, 2),
1801 NWidget(WWT_EMPTY
, COLOUR_GREY
, WID_CI_RAIL_DESC
), SetMinimalTextLines(2, 0), SetFill(1, 0),
1802 NWidget(WWT_EMPTY
, COLOUR_GREY
, WID_CI_RAIL_COUNT
), SetMinimalTextLines(2, 0), SetFill(0, 1),
1804 NWidget(NWID_HORIZONTAL
), SetPIP(2, 4, 2),
1805 NWidget(WWT_EMPTY
, COLOUR_GREY
, WID_CI_ROAD_DESC
), SetMinimalTextLines(2, 0), SetFill(1, 0),
1806 NWidget(WWT_EMPTY
, COLOUR_GREY
, WID_CI_ROAD_COUNT
), SetMinimalTextLines(2, 0), SetFill(0, 1),
1808 NWidget(NWID_HORIZONTAL
), SetPIP(2, 4, 2),
1809 NWidget(WWT_EMPTY
, COLOUR_GREY
, WID_CI_TRAM_DESC
), SetMinimalTextLines(2, 0), SetFill(1, 0),
1810 NWidget(WWT_EMPTY
, COLOUR_GREY
, WID_CI_TRAM_COUNT
), SetMinimalTextLines(2, 0), SetFill(0, 1),
1812 NWidget(NWID_HORIZONTAL
), SetPIP(2, 4, 2),
1813 NWidget(WWT_EMPTY
, COLOUR_GREY
, WID_CI_WATER_DESC
), SetMinimalTextLines(2, 0), SetFill(1, 0),
1814 NWidget(WWT_EMPTY
, COLOUR_GREY
, WID_CI_WATER_COUNT
), SetMinimalTextLines(2, 0), SetFill(0, 1),
1816 NWidget(NWID_HORIZONTAL
), SetPIP(2, 4, 2),
1817 NWidget(WWT_EMPTY
, COLOUR_GREY
, WID_CI_STATION_DESC
), SetMinimalTextLines(3, 0), SetFill(1, 0),
1818 NWidget(WWT_EMPTY
, COLOUR_GREY
, WID_CI_STATION_COUNT
), SetMinimalTextLines(3, 0), SetFill(0, 1),
1820 NWidget(NWID_HORIZONTAL
), SetPIP(2, 4, 2),
1821 NWidget(WWT_EMPTY
, COLOUR_GREY
, WID_CI_TOTAL_DESC
), SetFill(1, 0),
1822 NWidget(WWT_EMPTY
, COLOUR_GREY
, WID_CI_TOTAL
), SetFill(0, 1),
1829 * Window with detailed information about the company's infrastructure.
1831 struct CompanyInfrastructureWindow
: Window
1833 RailTypes railtypes
; ///< Valid railtypes.
1834 RoadTypes roadtypes
; ///< Valid roadtypes.
1836 uint total_width
; ///< String width of the total cost line.
1838 CompanyInfrastructureWindow(WindowDesc
*desc
, WindowNumber window_number
) : Window(desc
)
1840 this->UpdateRailRoadTypes();
1842 this->InitNested(window_number
);
1843 this->owner
= (Owner
)this->window_number
;
1846 void UpdateRailRoadTypes()
1848 this->railtypes
= RAILTYPES_NONE
;
1849 this->roadtypes
= ROADTYPES_NONE
;
1851 /* Find the used railtypes. */
1852 for (const Engine
*e
: Engine::IterateType(VEH_TRAIN
)) {
1853 if (!HasBit(e
->info
.climates
, _settings_game
.game_creation
.landscape
)) continue;
1855 this->railtypes
|= GetRailTypeInfo(e
->u
.rail
.railtype
)->introduces_railtypes
;
1858 /* Get the date introduced railtypes as well. */
1859 this->railtypes
= AddDateIntroducedRailTypes(this->railtypes
, MAX_DAY
);
1861 /* Find the used roadtypes. */
1862 for (const Engine
*e
: Engine::IterateType(VEH_ROAD
)) {
1863 if (!HasBit(e
->info
.climates
, _settings_game
.game_creation
.landscape
)) continue;
1865 this->roadtypes
|= GetRoadTypeInfo(e
->u
.road
.roadtype
)->introduces_roadtypes
;
1868 /* Get the date introduced roadtypes as well. */
1869 this->roadtypes
= AddDateIntroducedRoadTypes(this->roadtypes
, MAX_DAY
);
1870 this->roadtypes
&= ~_roadtypes_hidden_mask
;
1873 /** Get total infrastructure maintenance cost. */
1874 Money
GetTotalMaintenanceCost() const
1876 const Company
*c
= Company::Get((CompanyID
)this->window_number
);
1879 uint32 rail_total
= c
->infrastructure
.GetRailTotal();
1880 for (RailType rt
= RAILTYPE_BEGIN
; rt
!= RAILTYPE_END
; rt
++) {
1881 if (HasBit(this->railtypes
, rt
)) total
+= RailMaintenanceCost(rt
, c
->infrastructure
.rail
[rt
], rail_total
);
1883 total
+= SignalMaintenanceCost(c
->infrastructure
.signal
);
1885 uint32 road_total
= c
->infrastructure
.GetRoadTotal();
1886 uint32 tram_total
= c
->infrastructure
.GetTramTotal();
1887 for (RoadType rt
= ROADTYPE_BEGIN
; rt
!= ROADTYPE_END
; rt
++) {
1888 if (HasBit(this->roadtypes
, rt
)) total
+= RoadMaintenanceCost(rt
, c
->infrastructure
.road
[rt
], RoadTypeIsRoad(rt
) ? road_total
: tram_total
);
1891 total
+= CanalMaintenanceCost(c
->infrastructure
.water
);
1892 total
+= StationMaintenanceCost(c
->infrastructure
.station
);
1893 total
+= AirportMaintenanceCost(c
->index
);
1898 void SetStringParameters(int widget
) const override
1901 case WID_CI_CAPTION
:
1902 SetDParam(0, (CompanyID
)this->window_number
);
1907 void UpdateWidgetSize(int widget
, Dimension
*size
, const Dimension
&padding
, Dimension
*fill
, Dimension
*resize
) override
1909 const Company
*c
= Company::Get((CompanyID
)this->window_number
);
1912 case WID_CI_RAIL_DESC
: {
1913 uint lines
= 1; // Starts at 1 because a line is also required for the section title
1915 size
->width
= std::max(size
->width
, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT
).width
);
1917 for (const auto &rt
: _sorted_railtypes
) {
1918 if (HasBit(this->railtypes
, rt
)) {
1920 SetDParam(0, GetRailTypeInfo(rt
)->strings
.name
);
1921 size
->width
= std::max(size
->width
, GetStringBoundingBox(STR_WHITE_STRING
).width
+ WD_FRAMERECT_LEFT
);
1924 if (this->railtypes
!= RAILTYPES_NONE
) {
1926 size
->width
= std::max(size
->width
, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS
).width
+ WD_FRAMERECT_LEFT
);
1929 size
->height
= std::max(size
->height
, lines
* FONT_HEIGHT_NORMAL
);
1933 case WID_CI_ROAD_DESC
:
1934 case WID_CI_TRAM_DESC
: {
1935 uint lines
= 1; // Starts at 1 because a line is also required for the section title
1937 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
);
1939 for (const auto &rt
: _sorted_roadtypes
) {
1940 if (HasBit(this->roadtypes
, rt
) && RoadTypeIsRoad(rt
) == (widget
== WID_CI_ROAD_DESC
)) {
1942 SetDParam(0, GetRoadTypeInfo(rt
)->strings
.name
);
1943 size
->width
= std::max(size
->width
, GetStringBoundingBox(STR_WHITE_STRING
).width
+ WD_FRAMERECT_LEFT
);
1947 size
->height
= std::max(size
->height
, lines
* FONT_HEIGHT_NORMAL
);
1951 case WID_CI_WATER_DESC
:
1952 size
->width
= std::max(size
->width
, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT
).width
);
1953 size
->width
= std::max(size
->width
, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS
).width
+ WD_FRAMERECT_LEFT
);
1956 case WID_CI_STATION_DESC
:
1957 size
->width
= std::max(size
->width
, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT
).width
);
1958 size
->width
= std::max(size
->width
, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS
).width
+ WD_FRAMERECT_LEFT
);
1959 size
->width
= std::max(size
->width
, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS
).width
+ WD_FRAMERECT_LEFT
);
1962 case WID_CI_RAIL_COUNT
:
1963 case WID_CI_ROAD_COUNT
:
1964 case WID_CI_TRAM_COUNT
:
1965 case WID_CI_WATER_COUNT
:
1966 case WID_CI_STATION_COUNT
:
1967 case WID_CI_TOTAL
: {
1968 /* Find the maximum count that is displayed. */
1969 uint32 max_val
= 1000; // Some random number to reserve enough space.
1970 Money max_cost
= 10000; // Some random number to reserve enough space.
1971 uint32 rail_total
= c
->infrastructure
.GetRailTotal();
1972 for (RailType rt
= RAILTYPE_BEGIN
; rt
< RAILTYPE_END
; rt
++) {
1973 max_val
= std::max(max_val
, c
->infrastructure
.rail
[rt
]);
1974 max_cost
= std::max(max_cost
, RailMaintenanceCost(rt
, c
->infrastructure
.rail
[rt
], rail_total
));
1976 max_val
= std::max(max_val
, c
->infrastructure
.signal
);
1977 max_cost
= std::max(max_cost
, SignalMaintenanceCost(c
->infrastructure
.signal
));
1978 uint32 road_total
= c
->infrastructure
.GetRoadTotal();
1979 uint32 tram_total
= c
->infrastructure
.GetTramTotal();
1980 for (RoadType rt
= ROADTYPE_BEGIN
; rt
< ROADTYPE_END
; rt
++) {
1981 max_val
= std::max(max_val
, c
->infrastructure
.road
[rt
]);
1982 max_cost
= std::max(max_cost
, RoadMaintenanceCost(rt
, c
->infrastructure
.road
[rt
], RoadTypeIsRoad(rt
) ? road_total
: tram_total
));
1985 max_val
= std::max(max_val
, c
->infrastructure
.water
);
1986 max_cost
= std::max(max_cost
, CanalMaintenanceCost(c
->infrastructure
.water
));
1987 max_val
= std::max(max_val
, c
->infrastructure
.station
);
1988 max_cost
= std::max(max_cost
, StationMaintenanceCost(c
->infrastructure
.station
));
1989 max_val
= std::max(max_val
, c
->infrastructure
.airport
);
1990 max_cost
= std::max(max_cost
, AirportMaintenanceCost(c
->index
));
1992 SetDParamMaxValue(0, max_val
);
1993 uint count_width
= GetStringBoundingBox(STR_WHITE_COMMA
).width
+ 20; // Reserve some wiggle room
1995 if (_settings_game
.economy
.infrastructure_maintenance
) {
1996 SetDParamMaxValue(0, this->GetTotalMaintenanceCost() * 12); // Convert to per year
1997 this->total_width
= GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL
).width
+ 20;
1998 size
->width
= std::max(size
->width
, this->total_width
);
2000 SetDParamMaxValue(0, max_cost
* 12); // Convert to per year
2001 count_width
+= std::max(this->total_width
, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL
).width
);
2004 size
->width
= std::max(size
->width
, count_width
);
2006 /* Set height of the total line. */
2007 if (widget
== WID_CI_TOTAL
) {
2008 size
->height
= _settings_game
.economy
.infrastructure_maintenance
? std::max(size
->height
, EXP_LINESPACE
+ FONT_HEIGHT_NORMAL
) : 0;
2016 * Helper for drawing the counts line.
2017 * @param r The bounds to draw in.
2018 * @param y The y position to draw at.
2019 * @param count The count to show on this line.
2020 * @param monthly_cost The monthly costs.
2022 void DrawCountLine(const Rect
&r
, int &y
, int count
, Money monthly_cost
) const
2024 SetDParam(0, count
);
2025 DrawString(r
.left
, r
.right
, y
+= FONT_HEIGHT_NORMAL
, STR_WHITE_COMMA
, TC_FROMSTRING
, SA_RIGHT
);
2027 if (_settings_game
.economy
.infrastructure_maintenance
) {
2028 SetDParam(0, monthly_cost
* 12); // Convert to per year
2029 int left
= _current_text_dir
== TD_RTL
? r
.right
- this->total_width
: r
.left
;
2030 DrawString(left
, left
+ this->total_width
, y
, STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL
, TC_FROMSTRING
, SA_RIGHT
);
2034 void DrawWidget(const Rect
&r
, int widget
) const override
2036 const Company
*c
= Company::Get((CompanyID
)this->window_number
);
2039 int offs_left
= _current_text_dir
== TD_LTR
? WD_FRAMERECT_LEFT
: 0;
2040 int offs_right
= _current_text_dir
== TD_LTR
? 0 : WD_FRAMERECT_LEFT
;
2043 case WID_CI_RAIL_DESC
:
2044 DrawString(r
.left
, r
.right
, y
, STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT
);
2046 if (this->railtypes
!= RAILTYPES_NONE
) {
2047 /* Draw name of each valid railtype. */
2048 for (const auto &rt
: _sorted_railtypes
) {
2049 if (HasBit(this->railtypes
, rt
)) {
2050 SetDParam(0, GetRailTypeInfo(rt
)->strings
.name
);
2051 DrawString(r
.left
+ offs_left
, r
.right
- offs_right
, y
+= FONT_HEIGHT_NORMAL
, STR_WHITE_STRING
);
2054 DrawString(r
.left
+ offs_left
, r
.right
- offs_right
, y
+= FONT_HEIGHT_NORMAL
, STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS
);
2056 /* No valid railtype. */
2057 DrawString(r
.left
+ offs_left
, r
.right
- offs_right
, y
+= FONT_HEIGHT_NORMAL
, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE
);
2062 case WID_CI_RAIL_COUNT
: {
2063 /* Draw infrastructure count for each valid railtype. */
2064 uint32 rail_total
= c
->infrastructure
.GetRailTotal();
2065 for (const auto &rt
: _sorted_railtypes
) {
2066 if (HasBit(this->railtypes
, rt
)) {
2067 this->DrawCountLine(r
, y
, c
->infrastructure
.rail
[rt
], RailMaintenanceCost(rt
, c
->infrastructure
.rail
[rt
], rail_total
));
2070 if (this->railtypes
!= RAILTYPES_NONE
) {
2071 this->DrawCountLine(r
, y
, c
->infrastructure
.signal
, SignalMaintenanceCost(c
->infrastructure
.signal
));
2076 case WID_CI_ROAD_DESC
:
2077 case WID_CI_TRAM_DESC
: {
2078 DrawString(r
.left
, r
.right
, y
, widget
== WID_CI_ROAD_DESC
? STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT
: STR_COMPANY_INFRASTRUCTURE_VIEW_TRAM_SECT
);
2080 /* Draw name of each valid roadtype. */
2081 for (const auto &rt
: _sorted_roadtypes
) {
2082 if (HasBit(this->roadtypes
, rt
) && RoadTypeIsRoad(rt
) == (widget
== WID_CI_ROAD_DESC
)) {
2083 SetDParam(0, GetRoadTypeInfo(rt
)->strings
.name
);
2084 DrawString(r
.left
+ offs_left
, r
.right
- offs_right
, y
+= FONT_HEIGHT_NORMAL
, STR_WHITE_STRING
);
2091 case WID_CI_ROAD_COUNT
:
2092 case WID_CI_TRAM_COUNT
: {
2093 uint32 road_tram_total
= widget
== WID_CI_ROAD_COUNT
? c
->infrastructure
.GetRoadTotal() : c
->infrastructure
.GetTramTotal();
2094 for (const auto &rt
: _sorted_roadtypes
) {
2095 if (HasBit(this->roadtypes
, rt
) && RoadTypeIsRoad(rt
) == (widget
== WID_CI_ROAD_COUNT
)) {
2096 this->DrawCountLine(r
, y
, c
->infrastructure
.road
[rt
], RoadMaintenanceCost(rt
, c
->infrastructure
.road
[rt
], road_tram_total
));
2102 case WID_CI_WATER_DESC
:
2103 DrawString(r
.left
, r
.right
, y
, STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT
);
2104 DrawString(r
.left
+ offs_left
, r
.right
- offs_right
, y
+= FONT_HEIGHT_NORMAL
, STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS
);
2107 case WID_CI_WATER_COUNT
:
2108 this->DrawCountLine(r
, y
, c
->infrastructure
.water
, CanalMaintenanceCost(c
->infrastructure
.water
));
2112 if (_settings_game
.economy
.infrastructure_maintenance
) {
2113 int left
= _current_text_dir
== TD_RTL
? r
.right
- this->total_width
: r
.left
;
2114 GfxFillRect(left
, y
, left
+ this->total_width
, y
, PC_WHITE
);
2116 SetDParam(0, this->GetTotalMaintenanceCost() * 12); // Convert to per year
2117 DrawString(left
, left
+ this->total_width
, y
, STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL
, TC_FROMSTRING
, SA_RIGHT
);
2121 case WID_CI_STATION_DESC
:
2122 DrawString(r
.left
, r
.right
, y
, STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT
);
2123 DrawString(r
.left
+ offs_left
, r
.right
- offs_right
, y
+= FONT_HEIGHT_NORMAL
, STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS
);
2124 DrawString(r
.left
+ offs_left
, r
.right
- offs_right
, y
+= FONT_HEIGHT_NORMAL
, STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS
);
2127 case WID_CI_STATION_COUNT
:
2128 this->DrawCountLine(r
, y
, c
->infrastructure
.station
, StationMaintenanceCost(c
->infrastructure
.station
));
2129 this->DrawCountLine(r
, y
, c
->infrastructure
.airport
, AirportMaintenanceCost(c
->index
));
2135 * Some data on this window has become invalid.
2136 * @param data Information about the changed data.
2137 * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
2139 void OnInvalidateData(int data
= 0, bool gui_scope
= true) override
2141 if (!gui_scope
) return;
2143 this->UpdateRailRoadTypes();
2148 static WindowDesc
_company_infrastructure_desc(
2149 WDP_AUTO
, "company_infrastructure", 0, 0,
2150 WC_COMPANY_INFRASTRUCTURE
, WC_NONE
,
2152 _nested_company_infrastructure_widgets
, lengthof(_nested_company_infrastructure_widgets
)
2156 * Open the infrastructure window of a company.
2157 * @param company Company to show infrastructure of.
2159 static void ShowCompanyInfrastructure(CompanyID company
)
2161 if (!Company::IsValidID(company
)) return;
2162 AllocateWindowDescFront
<CompanyInfrastructureWindow
>(&_company_infrastructure_desc
, company
);
2165 static const NWidgetPart _nested_company_widgets
[] = {
2166 NWidget(NWID_HORIZONTAL
),
2167 NWidget(WWT_CLOSEBOX
, COLOUR_GREY
),
2168 NWidget(WWT_CAPTION
, COLOUR_GREY
, WID_C_CAPTION
), SetDataTip(STR_COMPANY_VIEW_CAPTION
, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS
),
2169 NWidget(WWT_SHADEBOX
, COLOUR_GREY
),
2170 NWidget(WWT_STICKYBOX
, COLOUR_GREY
),
2172 NWidget(WWT_PANEL
, COLOUR_GREY
),
2173 NWidget(NWID_HORIZONTAL
), SetPIP(4, 6, 4),
2174 NWidget(NWID_VERTICAL
), SetPIP(4, 2, 4),
2175 NWidget(WWT_EMPTY
, INVALID_COLOUR
, WID_C_FACE
), SetMinimalSize(92, 119), SetFill(1, 0),
2176 NWidget(WWT_EMPTY
, INVALID_COLOUR
, WID_C_FACE_TITLE
), SetFill(1, 1), SetMinimalTextLines(2, 0),
2178 NWidget(NWID_VERTICAL
),
2179 NWidget(NWID_HORIZONTAL
),
2180 NWidget(NWID_VERTICAL
), SetPIP(4, 5, 5),
2181 NWidget(WWT_TEXT
, COLOUR_GREY
, WID_C_DESC_INAUGURATION
), SetDataTip(STR_COMPANY_VIEW_INAUGURATED_TITLE
, STR_NULL
), SetFill(1, 0),
2182 NWidget(NWID_HORIZONTAL
), SetPIP(0, 5, 0),
2183 NWidget(WWT_LABEL
, COLOUR_GREY
, WID_C_DESC_COLOUR_SCHEME
), SetDataTip(STR_COMPANY_VIEW_COLOUR_SCHEME_TITLE
, STR_NULL
),
2184 NWidget(WWT_EMPTY
, INVALID_COLOUR
, WID_C_DESC_COLOUR_SCHEME_EXAMPLE
), SetMinimalSize(30, 0), SetFill(0, 1),
2185 NWidget(NWID_SPACER
), SetFill(1, 0),
2187 NWidget(NWID_HORIZONTAL
), SetPIP(0, 4, 0),
2188 NWidget(NWID_VERTICAL
),
2189 NWidget(WWT_TEXT
, COLOUR_GREY
, WID_C_DESC_VEHICLE
), SetDataTip(STR_COMPANY_VIEW_VEHICLES_TITLE
, STR_NULL
),
2190 NWidget(NWID_SPACER
), SetFill(0, 1),
2192 NWidget(WWT_EMPTY
, INVALID_COLOUR
, WID_C_DESC_VEHICLE_COUNTS
), SetMinimalTextLines(4, 0),
2193 NWidget(NWID_SPACER
), SetFill(1, 0),
2196 NWidget(NWID_VERTICAL
), SetPIP(4, 2, 4),
2197 NWidget(NWID_SELECTION
, INVALID_COLOUR
, WID_C_SELECT_VIEW_BUILD_HQ
),
2198 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_C_VIEW_HQ
), SetDataTip(STR_COMPANY_VIEW_VIEW_HQ_BUTTON
, STR_COMPANY_VIEW_VIEW_HQ_TOOLTIP
),
2199 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_C_BUILD_HQ
), SetDataTip(STR_COMPANY_VIEW_BUILD_HQ_BUTTON
, STR_COMPANY_VIEW_BUILD_HQ_TOOLTIP
),
2201 NWidget(NWID_SELECTION
, INVALID_COLOUR
, WID_C_SELECT_RELOCATE
),
2202 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_C_RELOCATE_HQ
), SetDataTip(STR_COMPANY_VIEW_RELOCATE_HQ
, STR_COMPANY_VIEW_RELOCATE_COMPANY_HEADQUARTERS
),
2203 NWidget(NWID_SPACER
),
2205 NWidget(NWID_SPACER
), SetFill(0, 1),
2208 NWidget(WWT_TEXT
, COLOUR_GREY
, WID_C_DESC_COMPANY_VALUE
), SetDataTip(STR_COMPANY_VIEW_COMPANY_VALUE
, STR_NULL
), SetFill(1, 0),
2209 NWidget(NWID_VERTICAL
), SetPIP(4, 2, 4),
2210 NWidget(NWID_HORIZONTAL
), SetPIP(0, 4, 0),
2211 NWidget(NWID_VERTICAL
),
2212 NWidget(WWT_TEXT
, COLOUR_GREY
, WID_C_DESC_INFRASTRUCTURE
), SetDataTip(STR_COMPANY_VIEW_INFRASTRUCTURE
, STR_NULL
),
2213 NWidget(NWID_SPACER
), SetFill(0, 1),
2215 NWidget(WWT_EMPTY
, INVALID_COLOUR
, WID_C_DESC_INFRASTRUCTURE_COUNTS
), SetMinimalTextLines(5, 0), SetFill(1, 0),
2216 NWidget(NWID_VERTICAL
),
2217 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_C_VIEW_INFRASTRUCTURE
), SetDataTip(STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON
, STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP
),
2218 NWidget(NWID_SPACER
),
2222 NWidget(NWID_HORIZONTAL
),
2223 NWidget(NWID_SELECTION
, INVALID_COLOUR
, WID_C_SELECT_DESC_OWNERS
),
2224 NWidget(NWID_VERTICAL
), SetPIP(5, 5, 4),
2225 NWidget(WWT_EMPTY
, INVALID_COLOUR
, WID_C_DESC_OWNERS
), SetMinimalTextLines(MAX_COMPANY_SHARE_OWNERS
, 0),
2226 NWidget(NWID_SPACER
), SetFill(0, 1),
2229 /* Multi player buttons. */
2230 NWidget(NWID_VERTICAL
), SetPIP(4, 2, 4),
2231 NWidget(NWID_SPACER
), SetFill(0, 1),
2232 NWidget(NWID_HORIZONTAL
), SetPIP(0, 4, 0),
2233 NWidget(NWID_SPACER
), SetFill(1, 0),
2234 NWidget(NWID_SELECTION
, INVALID_COLOUR
, WID_C_SELECT_GIVE_MONEY
),
2235 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_C_GIVE_MONEY
), SetDataTip(STR_COMPANY_VIEW_GIVE_MONEY_BUTTON
, STR_COMPANY_VIEW_GIVE_MONEY_TOOLTIP
),
2238 NWidget(NWID_HORIZONTAL
), SetPIP(0, 4, 0),
2239 NWidget(WWT_EMPTY
, COLOUR_GREY
, WID_C_HAS_PASSWORD
),
2240 NWidget(NWID_SELECTION
, INVALID_COLOUR
, WID_C_SELECT_MULTIPLAYER
),
2241 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_C_COMPANY_PASSWORD
), SetDataTip(STR_COMPANY_VIEW_PASSWORD
, STR_COMPANY_VIEW_PASSWORD_TOOLTIP
),
2242 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_C_COMPANY_JOIN
), SetDataTip(STR_COMPANY_VIEW_JOIN
, STR_COMPANY_VIEW_JOIN_TOOLTIP
),
2250 /* Button bars at the bottom. */
2251 NWidget(NWID_SELECTION
, INVALID_COLOUR
, WID_C_SELECT_BUTTONS
),
2252 NWidget(NWID_HORIZONTAL
, NC_EQUALSIZE
),
2253 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
),
2254 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
),
2255 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
),
2256 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
),
2258 NWidget(NWID_HORIZONTAL
, NC_EQUALSIZE
),
2259 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_C_BUY_SHARE
), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_BUY_SHARE_BUTTON
, STR_COMPANY_VIEW_BUY_SHARE_TOOLTIP
),
2260 NWidget(WWT_PUSHTXTBTN
, COLOUR_GREY
, WID_C_SELL_SHARE
), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_SELL_SHARE_BUTTON
, STR_COMPANY_VIEW_SELL_SHARE_TOOLTIP
),
2265 int GetAmountOwnedBy(const Company
*c
, Owner owner
)
2267 auto share_owned_by
= [owner
](auto share_owner
) { return share_owner
== owner
; };
2268 return std::count_if(c
->share_owners
.begin(), c
->share_owners
.end(), share_owned_by
);
2271 /** Strings for the company vehicle counts */
2272 static const StringID _company_view_vehicle_count_strings
[] = {
2273 STR_COMPANY_VIEW_TRAINS
, STR_COMPANY_VIEW_ROAD_VEHICLES
, STR_COMPANY_VIEW_SHIPS
, STR_COMPANY_VIEW_AIRCRAFT
2277 * Window with general information about a company
2279 struct CompanyWindow
: Window
2281 CompanyWidgets query_widget
;
2283 /** Display planes in the company window. */
2284 enum CompanyWindowPlanes
{
2285 /* Display planes of the #WID_C_SELECT_MULTIPLAYER selection widget. */
2286 CWP_MP_C_PWD
= 0, ///< Display the company password button.
2287 CWP_MP_C_JOIN
, ///< Display the join company button.
2289 /* Display planes of the #WID_C_SELECT_VIEW_BUILD_HQ selection widget. */
2290 CWP_VB_VIEW
= 0, ///< Display the view button
2291 CWP_VB_BUILD
, ///< Display the build button
2293 /* Display planes of the #WID_C_SELECT_RELOCATE selection widget. */
2294 CWP_RELOCATE_SHOW
= 0, ///< Show the relocate HQ button.
2295 CWP_RELOCATE_HIDE
, ///< Hide the relocate HQ button.
2297 /* Display planes of the #WID_C_SELECT_BUTTONS selection widget. */
2298 CWP_BUTTONS_LOCAL
= 0, ///< Buttons of the local company.
2299 CWP_BUTTONS_OTHER
, ///< Buttons of the other companies.
2302 CompanyWindow(WindowDesc
*desc
, WindowNumber window_number
) : Window(desc
)
2304 this->InitNested(window_number
);
2305 this->owner
= (Owner
)this->window_number
;
2306 this->OnInvalidateData();
2309 void OnPaint() override
2311 const Company
*c
= Company::Get((CompanyID
)this->window_number
);
2312 bool local
= this->window_number
== _local_company
;
2314 if (!this->IsShaded()) {
2315 bool reinit
= false;
2317 /* Button bar selection. */
2318 int plane
= local
? CWP_BUTTONS_LOCAL
: CWP_BUTTONS_OTHER
;
2319 NWidgetStacked
*wi
= this->GetWidget
<NWidgetStacked
>(WID_C_SELECT_BUTTONS
);
2320 if (plane
!= wi
->shown_plane
) {
2321 wi
->SetDisplayedPlane(plane
);
2322 this->InvalidateData();
2326 /* Build HQ button handling. */
2327 plane
= (local
&& c
->location_of_HQ
== INVALID_TILE
) ? CWP_VB_BUILD
: CWP_VB_VIEW
;
2328 wi
= this->GetWidget
<NWidgetStacked
>(WID_C_SELECT_VIEW_BUILD_HQ
);
2329 if (plane
!= wi
->shown_plane
) {
2330 wi
->SetDisplayedPlane(plane
);
2334 this->SetWidgetDisabledState(WID_C_VIEW_HQ
, c
->location_of_HQ
== INVALID_TILE
);
2336 /* Enable/disable 'Relocate HQ' button. */
2337 plane
= (!local
|| c
->location_of_HQ
== INVALID_TILE
) ? CWP_RELOCATE_HIDE
: CWP_RELOCATE_SHOW
;
2338 wi
= this->GetWidget
<NWidgetStacked
>(WID_C_SELECT_RELOCATE
);
2339 if (plane
!= wi
->shown_plane
) {
2340 wi
->SetDisplayedPlane(plane
);
2344 /* Owners of company */
2345 auto invalid_owner
= [](auto owner
) { return owner
== INVALID_COMPANY
; };
2346 plane
= std::all_of(c
->share_owners
.begin(), c
->share_owners
.end(), invalid_owner
) ? SZSP_HORIZONTAL
: 0;
2347 wi
= this->GetWidget
<NWidgetStacked
>(WID_C_SELECT_DESC_OWNERS
);
2348 if (plane
!= wi
->shown_plane
) {
2349 wi
->SetDisplayedPlane(plane
);
2353 /* Enable/disable 'Give money' button. */
2354 plane
= ((local
|| _local_company
== COMPANY_SPECTATOR
|| !_settings_game
.economy
.give_money
) ? SZSP_NONE
: 0);
2355 wi
= this->GetWidget
<NWidgetStacked
>(WID_C_SELECT_GIVE_MONEY
);
2356 if (plane
!= wi
->shown_plane
) {
2357 wi
->SetDisplayedPlane(plane
);
2361 /* Multiplayer buttons. */
2362 plane
= ((!_networking
) ? (int)SZSP_NONE
: (int)(local
? CWP_MP_C_PWD
: CWP_MP_C_JOIN
));
2363 wi
= this->GetWidget
<NWidgetStacked
>(WID_C_SELECT_MULTIPLAYER
);
2364 if (plane
!= wi
->shown_plane
) {
2365 wi
->SetDisplayedPlane(plane
);
2368 this->SetWidgetDisabledState(WID_C_COMPANY_JOIN
, c
->is_ai
);
2376 this->DrawWidgets();
2379 void UpdateWidgetSize(int widget
, Dimension
*size
, const Dimension
&padding
, Dimension
*fill
, Dimension
*resize
) override
2383 Dimension face_size
= GetSpriteSize(SPR_GRADIENT
);
2384 size
->width
= std::max(size
->width
, face_size
.width
);
2385 size
->height
= std::max(size
->height
, face_size
.height
);
2389 case WID_C_DESC_COLOUR_SCHEME_EXAMPLE
: {
2391 Dimension d
= GetSpriteSize(SPR_VEH_BUS_SW_VIEW
, &offset
);
2392 d
.width
-= offset
.x
;
2393 d
.height
-= offset
.y
;
2394 *size
= maxdim(*size
, d
);
2398 case WID_C_DESC_COMPANY_VALUE
:
2399 SetDParam(0, INT64_MAX
); // Arguably the maximum company value
2400 size
->width
= GetStringBoundingBox(STR_COMPANY_VIEW_COMPANY_VALUE
).width
;
2403 case WID_C_DESC_VEHICLE_COUNTS
:
2404 SetDParamMaxValue(0, 5000); // Maximum number of vehicles
2405 for (uint i
= 0; i
< lengthof(_company_view_vehicle_count_strings
); i
++) {
2406 size
->width
= std::max(size
->width
, GetStringBoundingBox(_company_view_vehicle_count_strings
[i
]).width
);
2410 case WID_C_DESC_INFRASTRUCTURE_COUNTS
:
2411 SetDParamMaxValue(0, UINT_MAX
);
2412 size
->width
= std::max(size
->width
, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL
).width
);
2413 size
->width
= std::max(size
->width
, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD
).width
);
2414 size
->width
= std::max(size
->width
, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_WATER
).width
);
2415 size
->width
= std::max(size
->width
, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_STATION
).width
);
2416 size
->width
= std::max(size
->width
, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT
).width
);
2417 size
->width
= std::max(size
->width
, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_NONE
).width
);
2420 case WID_C_DESC_OWNERS
: {
2421 for (const Company
*c2
: Company::Iterate()) {
2422 SetDParamMaxValue(0, 75);
2423 SetDParam(1, c2
->index
);
2425 size
->width
= std::max(size
->width
, GetStringBoundingBox(STR_COMPANY_VIEW_SHARES_OWNED_BY
).width
);
2431 case WID_C_BUILD_HQ
:
2432 case WID_C_RELOCATE_HQ
:
2433 case WID_C_VIEW_INFRASTRUCTURE
:
2434 case WID_C_GIVE_MONEY
:
2435 case WID_C_COMPANY_PASSWORD
:
2436 case WID_C_COMPANY_JOIN
:
2437 size
->width
= std::max(size
->width
, GetStringBoundingBox(STR_COMPANY_VIEW_VIEW_HQ_BUTTON
).width
);
2438 size
->width
= std::max(size
->width
, GetStringBoundingBox(STR_COMPANY_VIEW_BUILD_HQ_BUTTON
).width
);
2439 size
->width
= std::max(size
->width
, GetStringBoundingBox(STR_COMPANY_VIEW_RELOCATE_HQ
).width
);
2440 size
->width
= std::max(size
->width
, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON
).width
);
2441 size
->width
= std::max(size
->width
, GetStringBoundingBox(STR_COMPANY_VIEW_GIVE_MONEY_BUTTON
).width
);
2442 size
->width
= std::max(size
->width
, GetStringBoundingBox(STR_COMPANY_VIEW_PASSWORD
).width
);
2443 size
->width
= std::max(size
->width
, GetStringBoundingBox(STR_COMPANY_VIEW_JOIN
).width
);
2446 case WID_C_HAS_PASSWORD
:
2447 *size
= maxdim(*size
, GetSpriteSize(SPR_LOCK
));
2452 void DrawWidget(const Rect
&r
, int widget
) const override
2454 const Company
*c
= Company::Get((CompanyID
)this->window_number
);
2457 DrawCompanyManagerFace(c
->face
, c
->colour
, r
.left
, r
.top
);
2460 case WID_C_FACE_TITLE
:
2461 SetDParam(0, c
->index
);
2462 DrawStringMultiLine(r
.left
, r
.right
, r
.top
, r
.bottom
, STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE
, TC_FROMSTRING
, SA_HOR_CENTER
);
2465 case WID_C_DESC_COLOUR_SCHEME_EXAMPLE
: {
2467 Dimension d
= GetSpriteSize(SPR_VEH_BUS_SW_VIEW
, &offset
);
2468 d
.height
-= offset
.y
;
2469 DrawSprite(SPR_VEH_BUS_SW_VIEW
, COMPANY_SPRITE_COLOUR(c
->index
), r
.left
- offset
.x
, (r
.top
+ r
.bottom
- d
.height
) / 2 - offset
.y
);
2473 case WID_C_DESC_VEHICLE_COUNTS
: {
2475 amounts
[0] = c
->group_all
[VEH_TRAIN
].num_vehicle
;
2476 amounts
[1] = c
->group_all
[VEH_ROAD
].num_vehicle
;
2477 amounts
[2] = c
->group_all
[VEH_SHIP
].num_vehicle
;
2478 amounts
[3] = c
->group_all
[VEH_AIRCRAFT
].num_vehicle
;
2481 if (amounts
[0] + amounts
[1] + amounts
[2] + amounts
[3] == 0) {
2482 DrawString(r
.left
, r
.right
, y
, STR_COMPANY_VIEW_VEHICLES_NONE
);
2484 static_assert(lengthof(amounts
) == lengthof(_company_view_vehicle_count_strings
));
2486 for (uint i
= 0; i
< lengthof(amounts
); i
++) {
2487 if (amounts
[i
] != 0) {
2488 SetDParam(0, amounts
[i
]);
2489 DrawString(r
.left
, r
.right
, y
, _company_view_vehicle_count_strings
[i
]);
2490 y
+= FONT_HEIGHT_NORMAL
;
2497 case WID_C_DESC_INFRASTRUCTURE_COUNTS
: {
2500 /* Collect rail and road counts. */
2501 uint rail_pieces
= c
->infrastructure
.signal
;
2502 uint road_pieces
= 0;
2503 for (uint i
= 0; i
< lengthof(c
->infrastructure
.rail
); i
++) rail_pieces
+= c
->infrastructure
.rail
[i
];
2504 for (uint i
= 0; i
< lengthof(c
->infrastructure
.road
); i
++) road_pieces
+= c
->infrastructure
.road
[i
];
2506 if (rail_pieces
== 0 && road_pieces
== 0 && c
->infrastructure
.water
== 0 && c
->infrastructure
.station
== 0 && c
->infrastructure
.airport
== 0) {
2507 DrawString(r
.left
, r
.right
, y
, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE
);
2509 if (rail_pieces
!= 0) {
2510 SetDParam(0, rail_pieces
);
2511 DrawString(r
.left
, r
.right
, y
, STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL
);
2512 y
+= FONT_HEIGHT_NORMAL
;
2514 if (road_pieces
!= 0) {
2515 SetDParam(0, road_pieces
);
2516 DrawString(r
.left
, r
.right
, y
, STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD
);
2517 y
+= FONT_HEIGHT_NORMAL
;
2519 if (c
->infrastructure
.water
!= 0) {
2520 SetDParam(0, c
->infrastructure
.water
);
2521 DrawString(r
.left
, r
.right
, y
, STR_COMPANY_VIEW_INFRASTRUCTURE_WATER
);
2522 y
+= FONT_HEIGHT_NORMAL
;
2524 if (c
->infrastructure
.station
!= 0) {
2525 SetDParam(0, c
->infrastructure
.station
);
2526 DrawString(r
.left
, r
.right
, y
, STR_COMPANY_VIEW_INFRASTRUCTURE_STATION
);
2527 y
+= FONT_HEIGHT_NORMAL
;
2529 if (c
->infrastructure
.airport
!= 0) {
2530 SetDParam(0, c
->infrastructure
.airport
);
2531 DrawString(r
.left
, r
.right
, y
, STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT
);
2538 case WID_C_DESC_OWNERS
: {
2541 for (const Company
*c2
: Company::Iterate()) {
2542 uint amt
= GetAmountOwnedBy(c
, c2
->index
);
2544 SetDParam(0, amt
* 25);
2545 SetDParam(1, c2
->index
);
2547 DrawString(r
.left
, r
.right
, y
, STR_COMPANY_VIEW_SHARES_OWNED_BY
);
2548 y
+= FONT_HEIGHT_NORMAL
;
2554 case WID_C_HAS_PASSWORD
:
2555 if (_networking
&& NetworkCompanyIsPassworded(c
->index
)) {
2556 DrawSprite(SPR_LOCK
, PAL_NONE
, r
.left
, r
.top
);
2562 void SetStringParameters(int widget
) const override
2566 SetDParam(0, (CompanyID
)this->window_number
);
2567 SetDParam(1, (CompanyID
)this->window_number
);
2570 case WID_C_DESC_INAUGURATION
:
2571 SetDParam(0, Company::Get((CompanyID
)this->window_number
)->inaugurated_year
);
2574 case WID_C_DESC_COMPANY_VALUE
:
2575 SetDParam(0, CalculateCompanyValue(Company::Get((CompanyID
)this->window_number
)));
2580 void OnClick(Point pt
, int widget
, int click_count
) override
2583 case WID_C_NEW_FACE
: DoSelectCompanyManagerFace(this); break;
2585 case WID_C_COLOUR_SCHEME
:
2586 ShowCompanyLiveryWindow((CompanyID
)this->window_number
, INVALID_GROUP
);
2589 case WID_C_PRESIDENT_NAME
:
2590 this->query_widget
= WID_C_PRESIDENT_NAME
;
2591 SetDParam(0, this->window_number
);
2592 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
);
2595 case WID_C_COMPANY_NAME
:
2596 this->query_widget
= WID_C_COMPANY_NAME
;
2597 SetDParam(0, this->window_number
);
2598 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
);
2601 case WID_C_VIEW_HQ
: {
2602 TileIndex tile
= Company::Get((CompanyID
)this->window_number
)->location_of_HQ
;
2603 if (_ctrl_pressed
) {
2604 ShowExtraViewportWindow(tile
);
2606 ScrollMainWindowToTile(tile
);
2611 case WID_C_BUILD_HQ
:
2612 if ((byte
)this->window_number
!= _local_company
) return;
2613 if (this->IsWidgetLowered(WID_C_BUILD_HQ
)) {
2614 ResetObjectToPlace();
2615 this->RaiseButtons();
2618 SetObjectToPlaceWnd(SPR_CURSOR_HQ
, PAL_NONE
, HT_RECT
, this);
2619 SetTileSelectSize(2, 2);
2620 this->LowerWidget(WID_C_BUILD_HQ
);
2621 this->SetWidgetDirty(WID_C_BUILD_HQ
);
2624 case WID_C_RELOCATE_HQ
:
2625 if (this->IsWidgetLowered(WID_C_RELOCATE_HQ
)) {
2626 ResetObjectToPlace();
2627 this->RaiseButtons();
2630 SetObjectToPlaceWnd(SPR_CURSOR_HQ
, PAL_NONE
, HT_RECT
, this);
2631 SetTileSelectSize(2, 2);
2632 this->LowerWidget(WID_C_RELOCATE_HQ
);
2633 this->SetWidgetDirty(WID_C_RELOCATE_HQ
);
2636 case WID_C_VIEW_INFRASTRUCTURE
:
2637 ShowCompanyInfrastructure((CompanyID
)this->window_number
);
2640 case WID_C_GIVE_MONEY
:
2641 this->query_widget
= WID_C_GIVE_MONEY
;
2642 ShowQueryString(STR_EMPTY
, STR_COMPANY_VIEW_GIVE_MONEY_QUERY_CAPTION
, 30, this, CS_NUMERAL
, QSF_NONE
);
2645 case WID_C_BUY_SHARE
:
2646 Command
<CMD_BUY_SHARE_IN_COMPANY
>::Post(STR_ERROR_CAN_T_BUY_25_SHARE_IN_THIS
, (CompanyID
)this->window_number
);
2649 case WID_C_SELL_SHARE
:
2650 Command
<CMD_SELL_SHARE_IN_COMPANY
>::Post(STR_ERROR_CAN_T_SELL_25_SHARE_IN
, (CompanyID
)this->window_number
);
2653 case WID_C_COMPANY_PASSWORD
:
2654 if (this->window_number
== _local_company
) ShowNetworkCompanyPasswordWindow(this);
2657 case WID_C_COMPANY_JOIN
: {
2658 this->query_widget
= WID_C_COMPANY_JOIN
;
2659 CompanyID company
= (CompanyID
)this->window_number
;
2660 if (_network_server
) {
2661 NetworkServerDoMove(CLIENT_ID_SERVER
, company
);
2662 MarkWholeScreenDirty();
2663 } else if (NetworkCompanyIsPassworded(company
)) {
2664 /* ask for the password */
2665 ShowQueryString(STR_EMPTY
, STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION
, NETWORK_PASSWORD_LENGTH
, this, CS_ALPHANUMERAL
, QSF_PASSWORD
);
2667 /* just send the join command */
2668 NetworkClientRequestMove(company
);
2675 void OnHundredthTick() override
2677 /* redraw the window every now and then */
2681 void OnPlaceObject(Point pt
, TileIndex tile
) override
2683 if (Command
<CMD_BUILD_OBJECT
>::Post(STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS
, tile
, OBJECT_HQ
, 0) && !_shift_pressed
) {
2684 ResetObjectToPlace();
2685 this->RaiseButtons();
2689 void OnPlaceObjectAbort() override
2691 this->RaiseButtons();
2694 void OnQueryTextFinished(char *str
) override
2696 if (str
== nullptr) return;
2698 switch (this->query_widget
) {
2699 default: NOT_REACHED();
2701 case WID_C_GIVE_MONEY
: {
2702 Money money
= (Money
)(strtoull(str
, nullptr, 10) / _currency
->rate
);
2703 uint32 money_c
= Clamp(ClampToI32(money
), 0, 20000000); // Clamp between 20 million and 0
2705 Command
<CMD_GIVE_MONEY
>::Post(STR_ERROR_CAN_T_GIVE_MONEY
, money_c
, (CompanyID
)this->window_number
);
2709 case WID_C_PRESIDENT_NAME
:
2710 Command
<CMD_RENAME_PRESIDENT
>::Post(STR_ERROR_CAN_T_CHANGE_PRESIDENT
, str
);
2713 case WID_C_COMPANY_NAME
:
2714 Command
<CMD_RENAME_COMPANY
>::Post(STR_ERROR_CAN_T_CHANGE_COMPANY_NAME
, str
);
2717 case WID_C_COMPANY_JOIN
:
2718 NetworkClientRequestMove((CompanyID
)this->window_number
, str
);
2725 * Some data on this window has become invalid.
2726 * @param data Information about the changed data.
2727 * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
2729 void OnInvalidateData(int data
= 0, bool gui_scope
= true) override
2731 if (this->window_number
== _local_company
) return;
2733 if (_settings_game
.economy
.allow_shares
) { // Shares are allowed
2734 const Company
*c
= Company::Get(this->window_number
);
2736 /* If all shares are owned by someone (none by nobody), disable buy button */
2737 this->SetWidgetDisabledState(WID_C_BUY_SHARE
, GetAmountOwnedBy(c
, INVALID_OWNER
) == 0 ||
2738 /* Only 25% left to buy. If the company is human, disable buying it up.. TODO issues! */
2739 (GetAmountOwnedBy(c
, INVALID_OWNER
) == 1 && !c
->is_ai
) ||
2740 /* Spectators cannot do anything of course */
2741 _local_company
== COMPANY_SPECTATOR
);
2743 /* If the company doesn't own any shares, disable sell button */
2744 this->SetWidgetDisabledState(WID_C_SELL_SHARE
, (GetAmountOwnedBy(c
, _local_company
) == 0) ||
2745 /* Spectators cannot do anything of course */
2746 _local_company
== COMPANY_SPECTATOR
);
2747 } else { // Shares are not allowed, disable buy/sell buttons
2748 this->DisableWidget(WID_C_BUY_SHARE
);
2749 this->DisableWidget(WID_C_SELL_SHARE
);
2754 static WindowDesc
_company_desc(
2755 WDP_AUTO
, "company", 0, 0,
2756 WC_COMPANY
, WC_NONE
,
2758 _nested_company_widgets
, lengthof(_nested_company_widgets
)
2762 * Show the window with the overview of the company.
2763 * @param company The company to show the window for.
2765 void ShowCompany(CompanyID company
)
2767 if (!Company::IsValidID(company
)) return;
2769 AllocateWindowDescFront
<CompanyWindow
>(&_company_desc
, company
);
2773 * Redraw all windows with company infrastructure counts.
2774 * @param company The company to redraw the windows of.
2776 void DirtyCompanyInfrastructureWindows(CompanyID company
)
2778 SetWindowDirty(WC_COMPANY
, company
);
2779 SetWindowDirty(WC_COMPANY_INFRASTRUCTURE
, company
);
2782 struct BuyCompanyWindow
: Window
{
2783 BuyCompanyWindow(WindowDesc
*desc
, WindowNumber window_number
) : Window(desc
)
2785 this->InitNested(window_number
);
2788 void UpdateWidgetSize(int widget
, Dimension
*size
, const Dimension
&padding
, Dimension
*fill
, Dimension
*resize
) override
2792 *size
= GetSpriteSize(SPR_GRADIENT
);
2795 case WID_BC_QUESTION
:
2796 const Company
*c
= Company::Get((CompanyID
)this->window_number
);
2797 SetDParam(0, c
->index
);
2798 SetDParam(1, c
->bankrupt_value
);
2799 size
->height
= GetStringHeight(STR_BUY_COMPANY_MESSAGE
, size
->width
);
2804 void SetStringParameters(int widget
) const override
2807 case WID_BC_CAPTION
:
2808 SetDParam(0, STR_COMPANY_NAME
);
2809 SetDParam(1, Company::Get((CompanyID
)this->window_number
)->index
);
2814 void DrawWidget(const Rect
&r
, int widget
) const override
2818 const Company
*c
= Company::Get((CompanyID
)this->window_number
);
2819 DrawCompanyManagerFace(c
->face
, c
->colour
, r
.left
, r
.top
);
2823 case WID_BC_QUESTION
: {
2824 const Company
*c
= Company::Get((CompanyID
)this->window_number
);
2825 SetDParam(0, c
->index
);
2826 SetDParam(1, c
->bankrupt_value
);
2827 DrawStringMultiLine(r
.left
, r
.right
, r
.top
, r
.bottom
, STR_BUY_COMPANY_MESSAGE
, TC_FROMSTRING
, SA_CENTER
);
2833 void OnClick(Point pt
, int widget
, int click_count
) override
2841 Command
<CMD_BUY_COMPANY
>::Post(STR_ERROR_CAN_T_BUY_COMPANY
, (CompanyID
)this->window_number
);
2847 static const NWidgetPart _nested_buy_company_widgets
[] = {
2848 NWidget(NWID_HORIZONTAL
),
2849 NWidget(WWT_CLOSEBOX
, COLOUR_LIGHT_BLUE
),
2850 NWidget(WWT_CAPTION
, COLOUR_LIGHT_BLUE
, WID_BC_CAPTION
), SetDataTip(STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY
, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS
),
2852 NWidget(WWT_PANEL
, COLOUR_LIGHT_BLUE
),
2853 NWidget(NWID_VERTICAL
), SetPIP(8, 8, 8),
2854 NWidget(NWID_HORIZONTAL
), SetPIP(8, 10, 8),
2855 NWidget(WWT_EMPTY
, INVALID_COLOUR
, WID_BC_FACE
), SetFill(0, 1),
2856 NWidget(WWT_EMPTY
, INVALID_COLOUR
, WID_BC_QUESTION
), SetMinimalSize(240, 0), SetFill(1, 1),
2858 NWidget(NWID_HORIZONTAL
, NC_EQUALSIZE
), SetPIP(100, 10, 100),
2859 NWidget(WWT_TEXTBTN
, COLOUR_LIGHT_BLUE
, WID_BC_NO
), SetMinimalSize(60, 12), SetDataTip(STR_QUIT_NO
, STR_NULL
), SetFill(1, 0),
2860 NWidget(WWT_TEXTBTN
, COLOUR_LIGHT_BLUE
, WID_BC_YES
), SetMinimalSize(60, 12), SetDataTip(STR_QUIT_YES
, STR_NULL
), SetFill(1, 0),
2866 static WindowDesc
_buy_company_desc(
2867 WDP_AUTO
, nullptr, 0, 0,
2868 WC_BUY_COMPANY
, WC_NONE
,
2870 _nested_buy_company_widgets
, lengthof(_nested_buy_company_widgets
)
2874 * Show the query to buy another company.
2875 * @param company The company to buy.
2877 void ShowBuyCompanyDialog(CompanyID company
)
2879 AllocateWindowDescFront
<BuyCompanyWindow
>(&_buy_company_desc
, company
);