# company_gui.cpp

Go to the documentation of this file.

    00001 /* $Id$ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * 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.
    00006  * 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.
    00007  * 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/>.
    00008  */
    00009
    00012 #include "stdafx.h"
    00013 #include "error.h"
    00014 #include "gui.h"
    00015 #include "window_gui.h"
    00016 #include "textbuf_gui.h"
    00017 #include "viewport_func.h"
    00018 #include "company_func.h"
    00019 #include "command_func.h"
    00020 #include "network/network.h"
    00021 #include "network/network_gui.h"
    00022 #include "network/network_func.h"
    00023 #include "newgrf.h"
    00024 #include "company_manager_face.h"
    00025 #include "strings_func.h"
    00026 #include "date_func.h"
    00027 #include "widgets/dropdown_type.h"
    00028 #include "tilehighlight_func.h"
    00029 #include "company_base.h"
    00030 #include "core/geometry_func.hpp"
    00031 #include "object_type.h"
    00032 #include "rail.h"
    00033 #include "engine_base.h"
    00034 #include "window_func.h"
    00035 #include "road_func.h"
    00036 #include "water.h"
    00037 #include "station_func.h"
    00038
    00039 #include "widgets/company_widget.h"
    00040
    00041
    00043 static const uint EXP_LINESPACE  = 2;
    00044 static const uint EXP_BLOCKSPACE = 10;
    00045
    00046 static void DoSelectCompanyManagerFace(Window *parent);
    00047 static void ShowCompanyInfrastructure(CompanyID company);
    00048
    00050 static ExpensesType _expenses_list_1[] = {
    00051   EXPENSES_CONSTRUCTION,
    00052   EXPENSES_NEW_VEHICLES,
    00053   EXPENSES_TRAIN_RUN,
    00054   EXPENSES_ROADVEH_RUN,
    00055   EXPENSES_AIRCRAFT_RUN,
    00056   EXPENSES_SHIP_RUN,
    00057   EXPENSES_PROPERTY,
    00058   EXPENSES_TRAIN_INC,
    00059   EXPENSES_ROADVEH_INC,
    00060   EXPENSES_AIRCRAFT_INC,
    00061   EXPENSES_SHIP_INC,
    00062   EXPENSES_LOAN_INT,
    00063   EXPENSES_OTHER,
    00064 };
    00065
    00067 static ExpensesType _expenses_list_2[] = {
    00068   EXPENSES_TRAIN_INC,
    00069   EXPENSES_ROADVEH_INC,
    00070   EXPENSES_AIRCRAFT_INC,
    00071   EXPENSES_SHIP_INC,
    00072   INVALID_EXPENSES,
    00073   EXPENSES_TRAIN_RUN,
    00074   EXPENSES_ROADVEH_RUN,
    00075   EXPENSES_AIRCRAFT_RUN,
    00076   EXPENSES_SHIP_RUN,
    00077   EXPENSES_PROPERTY,
    00078   EXPENSES_LOAN_INT,
    00079   INVALID_EXPENSES,
    00080   EXPENSES_CONSTRUCTION,
    00081   EXPENSES_NEW_VEHICLES,
    00082   EXPENSES_OTHER,
    00083   INVALID_EXPENSES,
    00084 };
    00085
    00087 struct ExpensesList {
    00088   const ExpensesType *et;
    00089   const uint length;
    00090   const uint num_subtotals;
    00091
    00092   ExpensesList(ExpensesType *et, int length, int num_subtotals) : et(et), length(length), num_subtotals(num_subtotals)
    00093   {
    00094   }
    00095
    00096   uint GetHeight() const
    00097   {
    00098     /* heading + line + texts of expenses + sub-totals + total line + total text */
    00099     return FONT_HEIGHT_NORMAL + EXP_LINESPACE + this->length * FONT_HEIGHT_NORMAL + num_subtotals * (EXP_BLOCKSPACE + EXP_LINESPACE) + EXP_LINESPACE + FONT_HEIGHT_NORMAL;
    00100   }
    00101
    00103   uint GetCategoriesWidth() const
    00104   {
    00105     uint width = 0;
    00106     bool invalid_expenses_measured = false; // Measure 'Total' width only once.
    00107     for (uint i = 0; i < this->length; i++) {
    00108       ExpensesType et = this->et[i];
    00109       if (et == INVALID_EXPENSES) {
    00110         if (!invalid_expenses_measured) {
    00111           width = max(width, GetStringBoundingBox(STR_FINANCES_TOTAL_CAPTION).width);
    00112           invalid_expenses_measured = true;
    00113         }
    00114       } else {
    00115         width = max(width, GetStringBoundingBox(STR_FINANCES_SECTION_CONSTRUCTION + et).width);
    00116       }
    00117     }
    00118     return width;
    00119   }
    00120 };
    00121
    00122 static const ExpensesList _expenses_list_types[] = {
    00123   ExpensesList(_expenses_list_1, lengthof(_expenses_list_1), 0),
    00124   ExpensesList(_expenses_list_2, lengthof(_expenses_list_2), 3),
    00125 };
    00126
    00132 static void DrawCategories(const Rect &r)
    00133 {
    00134   int y = r.top;
    00135
    00136   DrawString(r.left, r.right, y, STR_FINANCES_EXPENDITURE_INCOME_TITLE, TC_FROMSTRING, SA_HOR_CENTER, true);
    00137   y += FONT_HEIGHT_NORMAL + EXP_LINESPACE;
    00138
    00139   int type = _settings_client.gui.expenses_layout;
    00140   for (uint i = 0; i < _expenses_list_types[type].length; i++) {
    00141     const ExpensesType et = _expenses_list_types[type].et[i];
    00142     if (et == INVALID_EXPENSES) {
    00143       y += EXP_LINESPACE;
    00144       DrawString(r.left, r.right, y, STR_FINANCES_TOTAL_CAPTION, TC_FROMSTRING, SA_RIGHT);
    00145       y += FONT_HEIGHT_NORMAL + EXP_BLOCKSPACE;
    00146     } else {
    00147       DrawString(r.left, r.right, y, STR_FINANCES_SECTION_CONSTRUCTION + et);
    00148       y += FONT_HEIGHT_NORMAL;
    00149     }
    00150   }
    00151
    00152   DrawString(r.left, r.right, y + EXP_LINESPACE, STR_FINANCES_TOTAL_CAPTION, TC_FROMSTRING, SA_RIGHT);
    00153 }
    00154
    00162 static void DrawPrice(Money amount, int left, int right, int top)
    00163 {
    00164   StringID str = STR_FINANCES_NEGATIVE_INCOME;
    00165   if (amount < 0) {
    00166     amount = -amount;
    00167     str++;
    00168   }
    00169   SetDParam(0, amount);
    00170   DrawString(left, right, top, str, TC_FROMSTRING, SA_RIGHT);
    00171 }
    00172
    00180 static void DrawYearColumn(const Rect &r, int year, const Money (*tbl)[EXPENSES_END])
    00181 {
    00182   int y = r.top;
    00183
    00184   SetDParam(0, year);
    00185   DrawString(r.left, r.right, y, STR_FINANCES_YEAR, TC_FROMSTRING, SA_RIGHT, true);
    00186   y += FONT_HEIGHT_NORMAL + EXP_LINESPACE;
    00187
    00188   Money sum = 0;
    00189   Money subtotal = 0;
    00190   int type = _settings_client.gui.expenses_layout;
    00191   for (uint i = 0; i < _expenses_list_types[type].length; i++) {
    00192     const ExpensesType et = _expenses_list_types[type].et[i];
    00193     if (et == INVALID_EXPENSES) {
    00194       Money cost = subtotal;
    00195       subtotal = 0;
    00196       GfxFillRect(r.left, y, r.right, y, PC_BLACK);
    00197       y += EXP_LINESPACE;
    00198       DrawPrice(cost, r.left, r.right, y);
    00199       y += FONT_HEIGHT_NORMAL + EXP_BLOCKSPACE;
    00200     } else {
    00201       Money cost = (*tbl)[et];
    00202       subtotal += cost;
    00203       sum += cost;
    00204       if (cost != 0) DrawPrice(cost, r.left, r.right, y);
    00205       y += FONT_HEIGHT_NORMAL;
    00206     }
    00207   }
    00208
    00209   GfxFillRect(r.left, y, r.right, y, PC_BLACK);
    00210   y += EXP_LINESPACE;
    00211   DrawPrice(sum, r.left, r.right, y);
    00212 }
    00213
    00214 static const NWidgetPart _nested_company_finances_widgets[] = {
    00215   NWidget(NWID_HORIZONTAL),
    00216     NWidget(WWT_CLOSEBOX, COLOUR_GREY),
    00217     NWidget(WWT_CAPTION, COLOUR_GREY, WID_CF_CAPTION), SetDataTip(STR_FINANCES_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    00218     NWidget(WWT_IMGBTN, COLOUR_GREY, WID_CF_TOGGLE_SIZE), SetDataTip(SPR_LARGE_SMALL_WINDOW, STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW),
    00219     NWidget(WWT_SHADEBOX, COLOUR_GREY),
    00220     NWidget(WWT_STICKYBOX, COLOUR_GREY),
    00221   EndContainer(),
    00222   NWidget(NWID_SELECTION, INVALID_COLOUR, WID_CF_SEL_PANEL),
    00223     NWidget(WWT_PANEL, COLOUR_GREY),
    00224       NWidget(NWID_HORIZONTAL), SetPadding(WD_FRAMERECT_TOP, WD_FRAMERECT_RIGHT, WD_FRAMERECT_BOTTOM, WD_FRAMERECT_LEFT), SetPIP(0, 9, 0),
    00225         NWidget(WWT_EMPTY, COLOUR_GREY, WID_CF_EXPS_CATEGORY), SetMinimalSize(120, 0), SetFill(0, 0),
    00226         NWidget(WWT_EMPTY, COLOUR_GREY, WID_CF_EXPS_PRICE1), SetMinimalSize(86, 0), SetFill(0, 0),
    00227         NWidget(WWT_EMPTY, COLOUR_GREY, WID_CF_EXPS_PRICE2), SetMinimalSize(86, 0), SetFill(0, 0),
    00228         NWidget(WWT_EMPTY, COLOUR_GREY, WID_CF_EXPS_PRICE3), SetMinimalSize(86, 0), SetFill(0, 0),
    00229       EndContainer(),
    00230     EndContainer(),
    00231   EndContainer(),
    00232   NWidget(WWT_PANEL, COLOUR_GREY),
    00233     NWidget(NWID_HORIZONTAL), SetPadding(WD_FRAMERECT_TOP, WD_FRAMERECT_RIGHT, WD_FRAMERECT_BOTTOM, WD_FRAMERECT_LEFT),
    00234       NWidget(NWID_VERTICAL), // Vertical column with 'bank balance', 'loan'
    00235         NWidget(WWT_TEXT, COLOUR_GREY), SetDataTip(STR_FINANCES_BANK_BALANCE_TITLE, STR_NULL), SetFill(1, 0),
    00236         NWidget(WWT_TEXT, COLOUR_GREY), SetDataTip(STR_FINANCES_LOAN_TITLE, STR_NULL), SetFill(1, 0),
    00237         NWidget(NWID_SPACER), SetFill(0, 1),
    00238       EndContainer(),
    00239       NWidget(NWID_SPACER), SetFill(0, 0), SetMinimalSize(30, 0),
    00240       NWidget(NWID_VERTICAL), // Vertical column with bank balance amount, loan amount, and total.
    00241         NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_BALANCE_VALUE), SetDataTip(STR_NULL, STR_NULL),
    00242         NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_LOAN_VALUE), SetDataTip(STR_NULL, STR_NULL),
    00243         NWidget(WWT_EMPTY, COLOUR_GREY, WID_CF_LOAN_LINE), SetMinimalSize(0, 2), SetFill(1, 0),
    00244         NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_TOTAL_VALUE), SetDataTip(STR_NULL, STR_NULL),
    00245       EndContainer(),
    00246       NWidget(NWID_SELECTION, INVALID_COLOUR, WID_CF_SEL_MAXLOAN),
    00247         NWidget(NWID_HORIZONTAL),
    00248           NWidget(NWID_SPACER), SetFill(0, 1), SetMinimalSize(25, 0),
    00249           NWidget(NWID_VERTICAL), // Max loan information
    00250             NWidget(WWT_EMPTY, COLOUR_GREY, WID_CF_MAXLOAN_GAP), SetFill(0, 0),
    00251             NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_MAXLOAN_VALUE), SetDataTip(STR_FINANCES_MAX_LOAN, STR_NULL),
    00252             NWidget(NWID_SPACER), SetFill(0, 1),
    00253           EndContainer(),
    00254         EndContainer(),
    00255       EndContainer(),
    00256       NWidget(NWID_SPACER), SetFill(1, 1),
    00257     EndContainer(),
    00258   EndContainer(),
    00259   NWidget(NWID_SELECTION, INVALID_COLOUR, WID_CF_SEL_BUTTONS),
    00260     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
    00261       NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_CF_INCREASE_LOAN), SetFill(1, 0), SetDataTip(STR_FINANCES_BORROW_BUTTON, STR_FINANCES_BORROW_TOOLTIP),
    00262       NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_CF_REPAY_LOAN), SetFill(1, 0), SetDataTip(STR_FINANCES_REPAY_BUTTON, STR_FINANCES_REPAY_TOOLTIP),
    00263       NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_CF_INFRASTRUCTURE), SetFill(1, 0), SetDataTip(STR_FINANCES_INFRASTRUCTURE_BUTTON, STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP),
    00264     EndContainer(),
    00265   EndContainer(),
    00266 };
    00267
    00272 struct CompanyFinancesWindow : Window {
    00273   static Money max_money;
    00274   bool small;
    00275
    00276   CompanyFinancesWindow(const WindowDesc *desc, CompanyID company) : Window()
    00277   {
    00278     this->small = false;
    00279     this->CreateNestedTree(desc);
    00280     this->SetupWidgets();
    00281     this->FinishInitNested(desc, company);
    00282
    00283     this->owner = (Owner)this->window_number;
    00284   }
    00285
    00286   virtual void SetStringParameters(int widget) const
    00287   {
    00288     switch (widget) {
    00289       case WID_CF_CAPTION:
    00290         SetDParam(0, (CompanyID)this->window_number);
    00291         SetDParam(1, (CompanyID)this->window_number);
    00292         break;
    00293
    00294       case WID_CF_MAXLOAN_VALUE:
    00295         SetDParam(0, _economy.max_loan);
    00296         break;
    00297
    00298       case WID_CF_INCREASE_LOAN:
    00299       case WID_CF_REPAY_LOAN:
    00300         SetDParam(0, LOAN_INTERVAL);
    00301         break;
    00302     }
    00303   }
    00304
    00305   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
    00306   {
    00307     int type = _settings_client.gui.expenses_layout;
    00308     switch (widget) {
    00309       case WID_CF_EXPS_CATEGORY:
    00310         size->width  = _expenses_list_types[type].GetCategoriesWidth();
    00311         size->height = _expenses_list_types[type].GetHeight();
    00312         break;
    00313
    00314       case WID_CF_EXPS_PRICE1:
    00315       case WID_CF_EXPS_PRICE2:
    00316       case WID_CF_EXPS_PRICE3:
    00317         size->height = _expenses_list_types[type].GetHeight();
    00318         /* FALL THROUGH */
    00319       case WID_CF_BALANCE_VALUE:
    00320       case WID_CF_LOAN_VALUE:
    00321       case WID_CF_TOTAL_VALUE:
    00322         SetDParam(0, CompanyFinancesWindow::max_money);
    00323         size->width = max(GetStringBoundingBox(STR_FINANCES_NEGATIVE_INCOME).width, GetStringBoundingBox(STR_FINANCES_POSITIVE_INCOME).width) + padding.width;
    00324         break;
    00325
    00326       case WID_CF_MAXLOAN_GAP:
    00327         size->height = FONT_HEIGHT_NORMAL;
    00328         break;
    00329     }
    00330   }
    00331
    00332   virtual void DrawWidget(const Rect &r, int widget) const
    00333   {
    00334     switch (widget) {
    00335       case WID_CF_EXPS_CATEGORY:
    00336         DrawCategories(r);
    00337         break;
    00338
    00339       case WID_CF_EXPS_PRICE1:
    00340       case WID_CF_EXPS_PRICE2:
    00341       case WID_CF_EXPS_PRICE3: {
    00342         const Company *c = Company::Get((CompanyID)this->window_number);
    00343         int age = min(_cur_year - c->inaugurated_year, 2);
    00344         int wid_offset = widget - WID_CF_EXPS_PRICE1;
    00345         if (wid_offset <= age) {
    00346           DrawYearColumn(r, _cur_year - (age - wid_offset), c->yearly_expenses + (age - wid_offset));
    00347         }
    00348         break;
    00349       }
    00350
    00351       case WID_CF_BALANCE_VALUE: {
    00352         const Company *c = Company::Get((CompanyID)this->window_number);
    00353         SetDParam(0, c->money);
    00354         DrawString(r.left, r.right, r.top, STR_FINANCES_TOTAL_CURRENCY, TC_FROMSTRING, SA_RIGHT);
    00355         break;
    00356       }
    00357
    00358       case WID_CF_LOAN_VALUE: {
    00359         const Company *c = Company::Get((CompanyID)this->window_number);
    00360         SetDParam(0, c->current_loan);
    00361         DrawString(r.left, r.right, r.top, STR_FINANCES_TOTAL_CURRENCY, TC_FROMSTRING, SA_RIGHT);
    00362         break;
    00363       }
    00364
    00365       case WID_CF_TOTAL_VALUE: {
    00366         const Company *c = Company::Get((CompanyID)this->window_number);
    00367         SetDParam(0, c->money - c->current_loan);
    00368         DrawString(r.left, r.right, r.top, STR_FINANCES_TOTAL_CURRENCY, TC_FROMSTRING, SA_RIGHT);
    00369         break;
    00370       }
    00371
    00372       case WID_CF_LOAN_LINE:
    00373         GfxFillRect(r.left, r.top, r.right, r.top, PC_BLACK);
    00374         break;
    00375     }
    00376   }
    00377
    00382   void SetupWidgets()
    00383   {
    00384     int plane = this->small ? SZSP_NONE : 0;
    00385     this->GetWidget<NWidgetStacked>(WID_CF_SEL_PANEL)->SetDisplayedPlane(plane);
    00386     this->GetWidget<NWidgetStacked>(WID_CF_SEL_MAXLOAN)->SetDisplayedPlane(plane);
    00387
    00388     CompanyID company = (CompanyID)this->window_number;
    00389     plane = (company != _local_company) ? SZSP_NONE : 0;
    00390     this->GetWidget<NWidgetStacked>(WID_CF_SEL_BUTTONS)->SetDisplayedPlane(plane);
    00391   }
    00392
    00393   virtual void OnPaint()
    00394   {
    00395     if (!this->IsShaded()) {
    00396       if (!this->small) {
    00397         /* Check that the expenses panel height matches the height needed for the layout. */
    00398         int type = _settings_client.gui.expenses_layout;
    00399         if (_expenses_list_types[type].GetHeight() != this->GetWidget<NWidgetBase>(WID_CF_EXPS_CATEGORY)->current_y) {
    00400           this->SetupWidgets();
    00401           this->ReInit();
    00402           return;
    00403         }
    00404       }
    00405
    00406       /* Check that the loan buttons are shown only when the user owns the company. */
    00407       CompanyID company = (CompanyID)this->window_number;
    00408       int req_plane = (company != _local_company) ? SZSP_NONE : 0;
    00409       if (req_plane != this->GetWidget<NWidgetStacked>(WID_CF_SEL_BUTTONS)->shown_plane) {
    00410         this->SetupWidgets();
    00411         this->ReInit();
    00412         return;
    00413       }
    00414
    00415       const Company *c = Company::Get(company);
    00416       this->SetWidgetDisabledState(WID_CF_INCREASE_LOAN, c->current_loan == _economy.max_loan); // Borrow button only shows when there is any more money to loan.
    00417       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.
    00418     }
    00419
    00420     this->DrawWidgets();
    00421   }
    00422
    00423   virtual void OnClick(Point pt, int widget, int click_count)
    00424   {
    00425     switch (widget) {
    00426       case WID_CF_TOGGLE_SIZE: // toggle size
    00427         this->small = !this->small;
    00428         this->SetupWidgets();
    00429         if (this->IsShaded()) {
    00430           /* Finances window is not resizable, so size hints given during unshading have no effect
    00431            * on the changed appearance of the window. */
    00432           this->SetShaded(false);
    00433         } else {
    00434           this->ReInit();
    00435         }
    00436         break;
    00437
    00438       case WID_CF_INCREASE_LOAN: // increase loan
    00439         DoCommandP(0, 0, _ctrl_pressed, CMD_INCREASE_LOAN | CMD_MSG(STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY));
    00440         break;
    00441
    00442       case WID_CF_REPAY_LOAN: // repay loan
    00443         DoCommandP(0, 0, _ctrl_pressed, CMD_DECREASE_LOAN | CMD_MSG(STR_ERROR_CAN_T_REPAY_LOAN));
    00444         break;
    00445
    00446       case WID_CF_INFRASTRUCTURE: // show infrastructure details
    00447         ShowCompanyInfrastructure((CompanyID)this->window_number);
    00448         break;
    00449     }
    00450   }
    00451
    00452   virtual void OnHundredthTick()
    00453   {
    00454     const Company *c = Company::Get((CompanyID)this->window_number);
    00455     if (c->money > CompanyFinancesWindow::max_money) {
    00456       CompanyFinancesWindow::max_money = max(c->money * 2, CompanyFinancesWindow::max_money * 4);
    00457       this->SetupWidgets();
    00458       this->ReInit();
    00459     }
    00460   }
    00461 };
    00462
    00464 Money CompanyFinancesWindow::max_money = INT32_MAX;
    00465
    00466 static const WindowDesc _company_finances_desc(
    00467   WDP_AUTO, 0, 0,
    00468   WC_FINANCES, WC_NONE,
    00469   WDF_UNCLICK_BUTTONS,
    00470   _nested_company_finances_widgets, lengthof(_nested_company_finances_widgets)
    00471 );
    00472
    00478 void ShowCompanyFinances(CompanyID company)
    00479 {
    00480   if (!Company::IsValidID(company)) return;
    00481   if (BringWindowToFrontById(WC_FINANCES, company)) return;
    00482
    00483   new CompanyFinancesWindow(&_company_finances_desc, company);
    00484 }
    00485
    00486 /* List of colours for the livery window */
    00487 static const StringID _colour_dropdown[] = {
    00488   STR_COLOUR_DARK_BLUE,
    00489   STR_COLOUR_PALE_GREEN,
    00490   STR_COLOUR_PINK,
    00491   STR_COLOUR_YELLOW,
    00492   STR_COLOUR_RED,
    00493   STR_COLOUR_LIGHT_BLUE,
    00494   STR_COLOUR_GREEN,
    00495   STR_COLOUR_DARK_GREEN,
    00496   STR_COLOUR_BLUE,
    00497   STR_COLOUR_CREAM,
    00498   STR_COLOUR_MAUVE,
    00499   STR_COLOUR_PURPLE,
    00500   STR_COLOUR_ORANGE,
    00501   STR_COLOUR_BROWN,
    00502   STR_COLOUR_GREY,
    00503   STR_COLOUR_WHITE,
    00504 };
    00505
    00506 /* Association of liveries to livery classes */
    00507 static const LiveryClass _livery_class[LS_END] = {
    00508   LC_OTHER,
    00509   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,
    00510   LC_ROAD, LC_ROAD,
    00511   LC_SHIP, LC_SHIP,
    00512   LC_AIRCRAFT, LC_AIRCRAFT, LC_AIRCRAFT,
    00513   LC_ROAD, LC_ROAD,
    00514 };
    00515
    00516 class DropDownListColourItem : public DropDownListItem {
    00517 public:
    00518   DropDownListColourItem(int result, bool masked) : DropDownListItem(result, masked) {}
    00519
    00520   virtual ~DropDownListColourItem() {}
    00521
    00522   StringID String() const
    00523   {
    00524     return _colour_dropdown[this->result];
    00525   }
    00526
    00527   uint Height(uint width) const
    00528   {
    00529     return max(FONT_HEIGHT_NORMAL, (byte)14);
    00530   }
    00531
    00532   bool Selectable() const
    00533   {
    00534     return true;
    00535   }
    00536
    00537   void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const
    00538   {
    00539     bool rtl = _current_text_dir == TD_RTL;
    00540     DrawSprite(SPR_VEH_BUS_SIDE_VIEW, PALETTE_RECOLOUR_START + this->result, rtl ? right - 16 : left + 16, top + 7);
    00541     DrawString(rtl ? left + 2 : left + 32, rtl ? right - 32 : right - 2, top + max(0, 13 - FONT_HEIGHT_NORMAL), this->String(), sel ? TC_WHITE : TC_BLACK);
    00542   }
    00543 };
    00544
    00546 struct SelectCompanyLiveryWindow : public Window {
    00547 private:
    00548   uint32 sel;
    00549   LiveryClass livery_class;
    00550   Dimension square;
    00551   Dimension box;
    00552   uint line_height;
    00553
    00554   void ShowColourDropDownMenu(uint32 widget)
    00555   {
    00556     uint32 used_colours = 0;
    00557     const Livery *livery;
    00558     LiveryScheme scheme;
    00559
    00560     /* Disallow other company colours for the primary colour */
    00561     if (HasBit(this->sel, LS_DEFAULT) && widget == WID_SCL_PRI_COL_DROPDOWN) {
    00562       const Company *c;
    00563       FOR_ALL_COMPANIES(c) {
    00564         if (c->index != _local_company) SetBit(used_colours, c->colour);
    00565       }
    00566     }
    00567
    00568     /* Get the first selected livery to use as the default dropdown item */
    00569     for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
    00570       if (HasBit(this->sel, scheme)) break;
    00571     }
    00572     if (scheme == LS_END) scheme = LS_DEFAULT;
    00573     livery = &Company::Get((CompanyID)this->window_number)->livery[scheme];
    00574
    00575     DropDownList *list = new DropDownList();
    00576     for (uint i = 0; i < lengthof(_colour_dropdown); i++) {
    00577       list->push_back(new DropDownListColourItem(i, HasBit(used_colours, i)));
    00578     }
    00579
    00580     ShowDropDownList(this, list, widget == WID_SCL_PRI_COL_DROPDOWN ? livery->colour1 : livery->colour2, widget);
    00581   }
    00582
    00583 public:
    00584   SelectCompanyLiveryWindow(const WindowDesc *desc, CompanyID company) : Window()
    00585   {
    00586     this->livery_class = LC_OTHER;
    00587     this->sel = 1;
    00588
    00589     this->square = GetSpriteSize(SPR_SQUARE);
    00590     this->box    = maxdim(GetSpriteSize(SPR_BOX_CHECKED), GetSpriteSize(SPR_BOX_EMPTY));
    00591     this->line_height = max(max(this->square.height, this->box.height), (uint)FONT_HEIGHT_NORMAL) + 4;
    00592
    00593     this->InitNested(desc, company);
    00594     this->owner = company;
    00595     this->LowerWidget(WID_SCL_CLASS_GENERAL);
    00596     this->InvalidateData(1);
    00597   }
    00598
    00599   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
    00600   {
    00601     switch (widget) {
    00602       case WID_SCL_SPACER_DROPDOWN: {
    00603         /* The matrix widget below needs enough room to print all the schemes. */
    00604         Dimension d = {0, 0};
    00605         for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
    00606           d = maxdim(d, GetStringBoundingBox(STR_LIVERY_DEFAULT + scheme));
    00607         }
    00608         size->width = max(size->width, 5 + this->box.width + d.width + WD_FRAMERECT_RIGHT);
    00609         break;
    00610       }
    00611
    00612       case WID_SCL_MATRIX: {
    00613         uint livery_height = 0;
    00614         for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
    00615           if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
    00616             livery_height++;
    00617           }
    00618         }
    00619         size->height = livery_height * this->line_height;
    00620         this->GetWidget<NWidgetCore>(WID_SCL_MATRIX)->widget_data = (livery_height << MAT_ROW_START) | (1 << MAT_COL_START);
    00621         break;
    00622       }
    00623
    00624       case WID_SCL_SEC_COL_DROPDOWN:
    00625         if (!_loaded_newgrf_features.has_2CC) {
    00626           size->width = 0;
    00627           break;
    00628         }
    00629         /* FALL THROUGH */
    00630       case WID_SCL_PRI_COL_DROPDOWN: {
    00631         int padding = this->square.width + NWidgetScrollbar::GetVerticalDimension().width + 10;
    00632         for (const StringID *id = _colour_dropdown; id != endof(_colour_dropdown); id++) {
    00633           size->width = max(size->width, GetStringBoundingBox(*id).width + padding);
    00634         }
    00635         break;
    00636       }
    00637     }
    00638   }
    00639
    00640   virtual void OnPaint()
    00641   {
    00642     /* Disable dropdown controls if no scheme is selected */
    00643     this->SetWidgetDisabledState(WID_SCL_PRI_COL_DROPDOWN, this->sel == 0);
    00644     this->SetWidgetDisabledState(WID_SCL_SEC_COL_DROPDOWN, this->sel == 0);
    00645
    00646     this->DrawWidgets();
    00647   }
    00648
    00649   virtual void SetStringParameters(int widget) const
    00650   {
    00651     switch (widget) {
    00652       case WID_SCL_PRI_COL_DROPDOWN:
    00653       case WID_SCL_SEC_COL_DROPDOWN: {
    00654         const Company *c = Company::Get((CompanyID)this->window_number);
    00655         LiveryScheme scheme = LS_DEFAULT;
    00656
    00657         if (this->sel != 0) {
    00658           for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
    00659             if (HasBit(this->sel, scheme)) break;
    00660           }
    00661           if (scheme == LS_END) scheme = LS_DEFAULT;
    00662         }
    00663         SetDParam(0, STR_COLOUR_DARK_BLUE + ((widget == WID_SCL_PRI_COL_DROPDOWN) ? c->livery[scheme].colour1 : c->livery[scheme].colour2));
    00664         break;
    00665       }
    00666     }
    00667   }
    00668
    00669   virtual void DrawWidget(const Rect &r, int widget) const
    00670   {
    00671     if (widget != WID_SCL_MATRIX) return;
    00672
    00673     bool rtl = _current_text_dir == TD_RTL;
    00674
    00675     /* Horizontal coordinates of scheme name column. */
    00676     const NWidgetBase *nwi = this->GetWidget<NWidgetBase>(WID_SCL_SPACER_DROPDOWN);
    00677     int sch_left = nwi->pos_x;
    00678     int sch_right = sch_left + nwi->current_x - 1;
    00679     /* Horizontal coordinates of first dropdown. */
    00680     nwi = this->GetWidget<NWidgetBase>(WID_SCL_PRI_COL_DROPDOWN);
    00681     int pri_left = nwi->pos_x;
    00682     int pri_right = pri_left + nwi->current_x - 1;
    00683     /* Horizontal coordinates of second dropdown. */
    00684     nwi = this->GetWidget<NWidgetBase>(WID_SCL_SEC_COL_DROPDOWN);
    00685     int sec_left = nwi->pos_x;
    00686     int sec_right = sec_left + nwi->current_x - 1;
    00687
    00688     int text_left  = (rtl ? (uint)WD_FRAMERECT_LEFT : (this->box.width + 5));
    00689     int text_right = (rtl ? (this->box.width + 5) : (uint)WD_FRAMERECT_RIGHT);
    00690
    00691     int box_offs    = (this->line_height - this->box.height) / 2;
    00692     int square_offs = (this->line_height - this->square.height) / 2 + 1;
    00693     int text_offs   = (this->line_height - FONT_HEIGHT_NORMAL) / 2 + 1;
    00694
    00695     int y = r.top;
    00696     const Company *c = Company::Get((CompanyID)this->window_number);
    00697     for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
    00698       if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
    00699         bool sel = HasBit(this->sel, scheme) != 0;
    00700
    00701         /* Optional check box + scheme name. */
    00702         if (scheme != LS_DEFAULT) {
    00703           DrawSprite(c->livery[scheme].in_use ? SPR_BOX_CHECKED : SPR_BOX_EMPTY, PAL_NONE, (rtl ? sch_right - (this->box.width + 5) + WD_FRAMERECT_RIGHT : sch_left) + WD_FRAMERECT_LEFT, y + box_offs);
    00704         }
    00705         DrawString(sch_left + text_left, sch_right - text_right, y + text_offs, STR_LIVERY_DEFAULT + scheme, sel ? TC_WHITE : TC_BLACK);
    00706
    00707         /* Text below the first dropdown. */
    00708         DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOUR(c->livery[scheme].colour1), (rtl ? pri_right - (this->box.width + 5) + WD_FRAMERECT_RIGHT : pri_left) + WD_FRAMERECT_LEFT, y + square_offs);
    00709         DrawString(pri_left + text_left, pri_right - text_right, y + text_offs, STR_COLOUR_DARK_BLUE + c->livery[scheme].colour1, sel ? TC_WHITE : TC_GOLD);
    00710
    00711         /* Text below the second dropdown. */
    00712         if (sec_right > sec_left) { // Second dropdown has non-zero size.
    00713           DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOUR(c->livery[scheme].colour2), (rtl ? sec_right - (this->box.width + 5) + WD_FRAMERECT_RIGHT : sec_left) + WD_FRAMERECT_LEFT, y + square_offs);
    00714           DrawString(sec_left + text_left, sec_right - text_right, y + text_offs, STR_COLOUR_DARK_BLUE + c->livery[scheme].colour2, sel ? TC_WHITE : TC_GOLD);
    00715         }
    00716
    00717         y += this->line_height;
    00718       }
    00719     }
    00720   }
    00721
    00722   virtual void OnClick(Point pt, int widget, int click_count)
    00723   {
    00724     switch (widget) {
    00725       /* Livery Class buttons */
    00726       case WID_SCL_CLASS_GENERAL:
    00727       case WID_SCL_CLASS_RAIL:
    00728       case WID_SCL_CLASS_ROAD:
    00729       case WID_SCL_CLASS_SHIP:
    00730       case WID_SCL_CLASS_AIRCRAFT:
    00731         this->RaiseWidget(this->livery_class + WID_SCL_CLASS_GENERAL);
    00732         this->livery_class = (LiveryClass)(widget - WID_SCL_CLASS_GENERAL);
    00733         this->LowerWidget(this->livery_class + WID_SCL_CLASS_GENERAL);
    00734
    00735         /* Select the first item in the list */
    00736         this->sel = 0;
    00737         for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
    00738           if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
    00739             this->sel = 1 << scheme;
    00740             break;
    00741           }
    00742         }
    00743
    00744         this->ReInit();
    00745         break;
    00746
    00747       case WID_SCL_PRI_COL_DROPDOWN: // First colour dropdown
    00748         ShowColourDropDownMenu(WID_SCL_PRI_COL_DROPDOWN);
    00749         break;
    00750
    00751       case WID_SCL_SEC_COL_DROPDOWN: // Second colour dropdown
    00752         ShowColourDropDownMenu(WID_SCL_SEC_COL_DROPDOWN);
    00753         break;
    00754
    00755       case WID_SCL_MATRIX: {
    00756         const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_SCL_MATRIX);
    00757         LiveryScheme j = (LiveryScheme)((pt.y - wid->pos_y) / this->line_height);
    00758
    00759         for (LiveryScheme scheme = LS_BEGIN; scheme <= j; scheme++) {
    00760           if (_livery_class[scheme] != this->livery_class || !HasBit(_loaded_newgrf_features.used_liveries, scheme)) j++;
    00761           if (scheme >= LS_END) return;
    00762         }
    00763         if (j >= LS_END) return;
    00764
    00765         /* If clicking on the left edge, toggle using the livery */
    00766         if (_current_text_dir == TD_RTL ? pt.x - wid->pos_x > wid->current_x - (this->box.width + 5) : pt.x - wid->pos_x < (this->box.width + 5)) {
    00767           DoCommandP(0, j | (2 << 8), !Company::Get((CompanyID)this->window_number)->livery[j].in_use, CMD_SET_COMPANY_COLOUR);
    00768         }
    00769
    00770         if (_ctrl_pressed) {
    00771           ToggleBit(this->sel, j);
    00772         } else {
    00773           this->sel = 1 << j;
    00774         }
    00775         this->SetDirty();
    00776         break;
    00777       }
    00778     }
    00779   }
    00780
    00781   virtual void OnDropdownSelect(int widget, int index)
    00782   {
    00783     for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
    00784       if (HasBit(this->sel, scheme)) {
    00785         DoCommandP(0, scheme | (widget == WID_SCL_PRI_COL_DROPDOWN ? 0 : 256), index, CMD_SET_COMPANY_COLOUR);
    00786       }
    00787     }
    00788   }
    00789
    00795   virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
    00796   {
    00797     if (!gui_scope) return;
    00798     this->SetWidgetsDisabledState(true, WID_SCL_CLASS_RAIL, WID_SCL_CLASS_ROAD, WID_SCL_CLASS_SHIP, WID_SCL_CLASS_AIRCRAFT, WIDGET_LIST_END);
    00799
    00800     bool current_class_valid = this->livery_class == LC_OTHER;
    00801     if (_settings_client.gui.liveries == LIT_ALL || (_settings_client.gui.liveries == LIT_COMPANY && this->window_number == _local_company)) {
    00802       for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
    00803         if (HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
    00804           if (_livery_class[scheme] == this->livery_class) current_class_valid = true;
    00805           this->EnableWidget(WID_SCL_CLASS_GENERAL + _livery_class[scheme]);
    00806         } else {
    00807           ClrBit(this->sel, scheme);
    00808         }
    00809       }
    00810     }
    00811
    00812     if (!current_class_valid) {
    00813       Point pt = {0, 0};
    00814       this->OnClick(pt, WID_SCL_CLASS_GENERAL, 1);
    00815     } else if (data == 0) {
    00816       this->ReInit();
    00817     }
    00818   }
    00819 };
    00820
    00821 static const NWidgetPart _nested_select_company_livery_widgets [] = {
    00822   NWidget(NWID_HORIZONTAL),
    00823     NWidget(WWT_CLOSEBOX, COLOUR_GREY),
    00824     NWidget(WWT_CAPTION, COLOUR_GREY, WID_SCL_CAPTION), SetDataTip(STR_LIVERY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    00825   EndContainer(),
    00826   NWidget(NWID_HORIZONTAL),
    00827     NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_GENERAL), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_COMPANY_GENERAL, STR_LIVERY_GENERAL_TOOLTIP),
    00828     NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_RAIL), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_TRAINLIST, STR_LIVERY_TRAIN_TOOLTIP),
    00829     NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_ROAD), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_TRUCKLIST, STR_LIVERY_ROAD_VEHICLE_TOOLTIP),
    00830     NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_SHIP), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_SHIPLIST, STR_LIVERY_SHIP_TOOLTIP),
    00831     NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_AIRCRAFT), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_AIRPLANESLIST, STR_LIVERY_AIRCRAFT_TOOLTIP),
    00832     NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(90, 22), SetFill(1, 1), EndContainer(),
    00833   EndContainer(),
    00834   NWidget(NWID_HORIZONTAL),
    00835     NWidget(WWT_PANEL, COLOUR_GREY, WID_SCL_SPACER_DROPDOWN), SetMinimalSize(150, 12), SetFill(1, 1), EndContainer(),
    00836     NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SCL_PRI_COL_DROPDOWN), SetMinimalSize(125, 12), SetFill(0, 1), SetDataTip(STR_BLACK_STRING, STR_LIVERY_PRIMARY_TOOLTIP),
    00837     NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SCL_SEC_COL_DROPDOWN), SetMinimalSize(125, 12), SetFill(0, 1),
    00838         SetDataTip(STR_BLACK_STRING, STR_LIVERY_SECONDARY_TOOLTIP),
    00839   EndContainer(),
    00840   NWidget(WWT_MATRIX, COLOUR_GREY, WID_SCL_MATRIX), SetMinimalSize(275, 15), SetFill(1, 0), SetDataTip((1 << MAT_ROW_START) | (1 << MAT_COL_START), STR_LIVERY_PANEL_TOOLTIP),
    00841 };
    00842
    00843 static const WindowDesc _select_company_livery_desc(
    00844   WDP_AUTO, 0, 0,
    00845   WC_COMPANY_COLOUR, WC_NONE,
    00846   0,
    00847   _nested_select_company_livery_widgets, lengthof(_nested_select_company_livery_widgets)
    00848 );
    00849
    00857 void DrawCompanyManagerFace(CompanyManagerFace cmf, int colour, int x, int y)
    00858 {
    00859   GenderEthnicity ge = (GenderEthnicity)GetCompanyManagerFaceBits(cmf, CMFV_GEN_ETHN, GE_WM);
    00860
    00861   bool has_moustache   = !HasBit(ge, GENDER_FEMALE) && GetCompanyManagerFaceBits(cmf, CMFV_HAS_MOUSTACHE,   ge) != 0;
    00862   bool has_tie_earring = !HasBit(ge, GENDER_FEMALE) || GetCompanyManagerFaceBits(cmf, CMFV_HAS_TIE_EARRING, ge) != 0;
    00863   bool has_glasses     = GetCompanyManagerFaceBits(cmf, CMFV_HAS_GLASSES, ge) != 0;
    00864   PaletteID pal;
    00865
    00866   /* Modify eye colour palette only if 2 or more valid values exist */
    00867   if (_cmf_info[CMFV_EYE_COLOUR].valid_values[ge] < 2) {
    00868     pal = PAL_NONE;
    00869   } else {
    00870     switch (GetCompanyManagerFaceBits(cmf, CMFV_EYE_COLOUR, ge)) {
    00871       default: NOT_REACHED();
    00872       case 0: pal = PALETTE_TO_BROWN; break;
    00873       case 1: pal = PALETTE_TO_BLUE;  break;
    00874       case 2: pal = PALETTE_TO_GREEN; break;
    00875     }
    00876   }
    00877
    00878   /* Draw the gradient (background) */
    00879   DrawSprite(SPR_GRADIENT, GENERAL_SPRITE_COLOUR(colour), x, y);
    00880
    00881   for (CompanyManagerFaceVariable cmfv = CMFV_CHEEKS; cmfv < CMFV_END; cmfv++) {
    00882     switch (cmfv) {
    00883       case CMFV_MOUSTACHE:   if (!has_moustache)   continue; break;
    00884       case CMFV_LIPS:        // FALL THROUGH
    00885       case CMFV_NOSE:        if (has_moustache)    continue; break;
    00886       case CMFV_TIE_EARRING: if (!has_tie_earring) continue; break;
    00887       case CMFV_GLASSES:     if (!has_glasses)     continue; break;
    00888       default: break;
    00889     }
    00890     DrawSprite(GetCompanyManagerFaceSprite(cmf, cmfv, ge), (cmfv == CMFV_EYEBROWS) ? pal : PAL_NONE, x, y);
    00891   }
    00892 }
    00893
    00895 static const NWidgetPart _nested_select_company_manager_face_widgets[] = {
    00896   NWidget(NWID_HORIZONTAL),
    00897     NWidget(WWT_CLOSEBOX, COLOUR_GREY),
    00898     NWidget(WWT_CAPTION, COLOUR_GREY, WID_SCMF_CAPTION), SetDataTip(STR_FACE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    00899     NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCMF_TOGGLE_LARGE_SMALL), SetDataTip(SPR_LARGE_SMALL_WINDOW, STR_FACE_ADVANCED_TOOLTIP),
    00900   EndContainer(),
    00901   NWidget(WWT_PANEL, COLOUR_GREY, WID_SCMF_SELECT_FACE),
    00902     NWidget(NWID_SPACER), SetMinimalSize(0, 2),
    00903     NWidget(NWID_HORIZONTAL), SetPIP(2, 2, 2),
    00904       NWidget(NWID_VERTICAL),
    00905         NWidget(NWID_HORIZONTAL),
    00906           NWidget(NWID_SPACER), SetFill(1, 0),
    00907           NWidget(WWT_EMPTY, COLOUR_GREY, WID_SCMF_FACE), SetMinimalSize(92, 119),
    00908           NWidget(NWID_SPACER), SetFill(1, 0),
    00909         EndContainer(),
    00910         NWidget(NWID_SPACER), SetMinimalSize(0, 2),
    00911         NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_RANDOM_NEW_FACE), SetFill(1, 0), SetDataTip(STR_FACE_NEW_FACE_BUTTON, STR_FACE_NEW_FACE_TOOLTIP),
    00912         NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SCMF_SEL_LOADSAVE), // Load/number/save buttons under the portrait in the advanced view.
    00913           NWidget(NWID_VERTICAL),
    00914             NWidget(NWID_SPACER), SetMinimalSize(0, 5), SetFill(0, 1),
    00915             NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_LOAD), SetFill(1, 0), SetDataTip(STR_FACE_LOAD, STR_FACE_LOAD_TOOLTIP),
    00916             NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_FACECODE), SetFill(1, 0), SetDataTip(STR_FACE_FACECODE, STR_FACE_FACECODE_TOOLTIP),
    00917             NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_SAVE), SetFill(1, 0), SetDataTip(STR_FACE_SAVE, STR_FACE_SAVE_TOOLTIP),
    00918             NWidget(NWID_SPACER), SetMinimalSize(0, 5), SetFill(0, 1),
    00919           EndContainer(),
    00920         EndContainer(),
    00921       EndContainer(),
    00922       NWidget(NWID_VERTICAL),
    00923         NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON), SetFill(1, 0), SetDataTip(STR_FACE_ADVANCED, STR_FACE_ADVANCED_TOOLTIP),
    00924         NWidget(NWID_SPACER), SetMinimalSize(0, 2),
    00925         NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SCMF_SEL_MALEFEMALE), // Simple male/female face setting.
    00926           NWidget(NWID_VERTICAL),
    00927             NWidget(NWID_SPACER), SetFill(0, 1),
    00928             NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_MALE), SetFill(1, 0), SetDataTip(STR_FACE_MALE_BUTTON, STR_FACE_MALE_TOOLTIP),
    00929             NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_FEMALE), SetFill(1, 0), SetDataTip(STR_FACE_FEMALE_BUTTON, STR_FACE_FEMALE_TOOLTIP),
    00930             NWidget(NWID_SPACER), SetFill(0, 1),
    00931           EndContainer(),
    00932         EndContainer(),
    00933         NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SCMF_SEL_PARTS), // Advanced face parts setting.
    00934           NWidget(NWID_VERTICAL),
    00935             NWidget(NWID_SPACER), SetMinimalSize(0, 2),
    00936             NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
    00937               NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_MALE2), SetFill(1, 0), SetDataTip(STR_FACE_MALE_BUTTON, STR_FACE_MALE_TOOLTIP),
    00938               NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_FEMALE2), SetFill(1, 0), SetDataTip(STR_FACE_FEMALE_BUTTON, STR_FACE_FEMALE_TOOLTIP),
    00939             EndContainer(),
    00940             NWidget(NWID_SPACER), SetMinimalSize(0, 2),
    00941             NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
    00942               NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_ETHNICITY_EUR), SetFill(1, 0), SetDataTip(STR_FACE_EUROPEAN, STR_FACE_SELECT_EUROPEAN),
    00943               NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_ETHNICITY_AFR), SetFill(1, 0), SetDataTip(STR_FACE_AFRICAN, STR_FACE_SELECT_AFRICAN),
    00944             EndContainer(),
    00945             NWidget(NWID_SPACER), SetMinimalSize(0, 4),
    00946             NWidget(NWID_HORIZONTAL),
    00947               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT), SetFill(1, 0),
    00948               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_MOUSTACHE_EARRING), SetDataTip(STR_EMPTY, STR_FACE_MOUSTACHE_EARRING_TOOLTIP),
    00949             EndContainer(),
    00950             NWidget(NWID_HORIZONTAL),
    00951               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_HAS_GLASSES_TEXT), SetFill(1, 0),
    00952               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_GLASSES), SetDataTip(STR_EMPTY, STR_FACE_GLASSES_TOOLTIP),
    00953             EndContainer(),
    00954             NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetFill(1, 0),
    00955             NWidget(NWID_HORIZONTAL),
    00956               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_HAIR_TEXT), SetFill(1, 0),
    00957               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_HAIR_L), SetDataTip(AWV_DECREASE, STR_FACE_HAIR_TOOLTIP),
    00958               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAIR), SetDataTip(STR_EMPTY, STR_FACE_HAIR_TOOLTIP),
    00959               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_HAIR_R), SetDataTip(AWV_INCREASE, STR_FACE_HAIR_TOOLTIP),
    00960             EndContainer(),
    00961             NWidget(NWID_HORIZONTAL),
    00962               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_EYEBROWS_TEXT), SetFill(1, 0),
    00963               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYEBROWS_L), SetDataTip(AWV_DECREASE, STR_FACE_EYEBROWS_TOOLTIP),
    00964               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYEBROWS), SetDataTip(STR_EMPTY, STR_FACE_EYEBROWS_TOOLTIP),
    00965               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYEBROWS_R), SetDataTip(AWV_INCREASE, STR_FACE_EYEBROWS_TOOLTIP),
    00966             EndContainer(),
    00967             NWidget(NWID_HORIZONTAL),
    00968               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_EYECOLOUR_TEXT), SetFill(1, 0),
    00969               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR_L), SetDataTip(AWV_DECREASE, STR_FACE_EYECOLOUR_TOOLTIP),
    00970               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR), SetDataTip(STR_EMPTY, STR_FACE_EYECOLOUR_TOOLTIP),
    00971               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR_R), SetDataTip(AWV_INCREASE, STR_FACE_EYECOLOUR_TOOLTIP),
    00972             EndContainer(),
    00973             NWidget(NWID_HORIZONTAL),
    00974               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_GLASSES_TEXT), SetFill(1, 0),
    00975               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_GLASSES_L), SetDataTip(AWV_DECREASE, STR_FACE_GLASSES_TOOLTIP_2),
    00976               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_GLASSES), SetDataTip(STR_EMPTY, STR_FACE_GLASSES_TOOLTIP_2),
    00977               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_GLASSES_R), SetDataTip(AWV_INCREASE, STR_FACE_GLASSES_TOOLTIP_2),
    00978             EndContainer(),
    00979             NWidget(NWID_HORIZONTAL),
    00980               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_NOSE_TEXT), SetFill(1, 0),
    00981               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_NOSE_L), SetDataTip(AWV_DECREASE, STR_FACE_NOSE_TOOLTIP),
    00982               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_NOSE), SetDataTip(STR_EMPTY, STR_FACE_NOSE_TOOLTIP),
    00983               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_NOSE_R), SetDataTip(AWV_INCREASE, STR_FACE_NOSE_TOOLTIP),
    00984             EndContainer(),
    00985             NWidget(NWID_HORIZONTAL),
    00986               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_LIPS_MOUSTACHE_TEXT), SetFill(1, 0),
    00987               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE_L), SetDataTip(AWV_DECREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP),
    00988               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE), SetDataTip(STR_EMPTY, STR_FACE_LIPS_MOUSTACHE_TOOLTIP),
    00989               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE_R), SetDataTip(AWV_INCREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP),
    00990             EndContainer(),
    00991             NWidget(NWID_HORIZONTAL),
    00992               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_CHIN_TEXT), SetFill(1, 0),
    00993               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_CHIN_L), SetDataTip(AWV_DECREASE, STR_FACE_CHIN_TOOLTIP),
    00994               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_CHIN), SetDataTip(STR_EMPTY, STR_FACE_CHIN_TOOLTIP),
    00995               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_CHIN_R), SetDataTip(AWV_INCREASE, STR_FACE_CHIN_TOOLTIP),
    00996             EndContainer(),
    00997             NWidget(NWID_HORIZONTAL),
    00998               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_JACKET_TEXT), SetFill(1, 0),
    00999               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_JACKET_L), SetDataTip(AWV_DECREASE, STR_FACE_JACKET_TOOLTIP),
    01000               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_JACKET), SetDataTip(STR_EMPTY, STR_FACE_JACKET_TOOLTIP),
    01001               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_JACKET_R), SetDataTip(AWV_INCREASE, STR_FACE_JACKET_TOOLTIP),
    01002             EndContainer(),
    01003             NWidget(NWID_HORIZONTAL),
    01004               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_COLLAR_TEXT), SetFill(1, 0),
    01005               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_COLLAR_L), SetDataTip(AWV_DECREASE, STR_FACE_COLLAR_TOOLTIP),
    01006               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_COLLAR), SetDataTip(STR_EMPTY, STR_FACE_COLLAR_TOOLTIP),
    01007               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_COLLAR_R), SetDataTip(AWV_INCREASE, STR_FACE_COLLAR_TOOLTIP),
    01008             EndContainer(),
    01009             NWidget(NWID_HORIZONTAL),
    01010               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_TIE_EARRING_TEXT), SetFill(1, 0),
    01011               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING_L), SetDataTip(AWV_DECREASE, STR_FACE_TIE_EARRING_TOOLTIP),
    01012               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING), SetDataTip(STR_EMPTY, STR_FACE_TIE_EARRING_TOOLTIP),
    01013               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING_R), SetDataTip(AWV_INCREASE, STR_FACE_TIE_EARRING_TOOLTIP),
    01014             EndContainer(),
    01015             NWidget(NWID_SPACER), SetFill(0, 1),
    01016           EndContainer(),
    01017         EndContainer(),
    01018       EndContainer(),
    01019     EndContainer(),
    01020     NWidget(NWID_SPACER), SetMinimalSize(0, 2),
    01021   EndContainer(),
    01022   NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
    01023     NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_CANCEL), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_FACE_CANCEL_TOOLTIP),
    01024     NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_ACCEPT), SetFill(1, 0), SetDataTip(STR_BUTTON_OK, STR_FACE_OK_TOOLTIP),
    01025   EndContainer(),
    01026 };
    01027
    01029 class SelectCompanyManagerFaceWindow : public Window
    01030 {
    01031   CompanyManagerFace face;
    01032   bool advanced;
    01033
    01034   GenderEthnicity ge;
    01035   bool is_female;
    01036   bool is_moust_male;
    01037
    01038   Dimension yesno_dim;
    01039   Dimension number_dim;
    01040
    01041   static const StringID PART_TEXTS_IS_FEMALE[];
    01042   static const StringID PART_TEXTS[];
    01043
    01051   void DrawFaceStringLabel(byte widget_index, uint8 val, bool is_bool_widget) const
    01052   {
    01053     StringID str;
    01054     const NWidgetCore *nwi_widget = this->GetWidget<NWidgetCore>(widget_index);
    01055     if (!nwi_widget->IsDisabled()) {
    01056       if (is_bool_widget) {
    01057         /* if it a bool button write yes or no */
    01058         str = (val != 0) ? STR_FACE_YES : STR_FACE_NO;
    01059       } else {
    01060         /* else write the value + 1 */
    01061         SetDParam(0, val + 1);
    01062         str = STR_JUST_INT;
    01063       }
    01064
    01065       /* Draw the value/bool in white (0xC). If the button clicked adds 1px to x and y text coordinates (IsWindowWidgetLowered()). */
    01066       DrawString(nwi_widget->pos_x + nwi_widget->IsLowered(), nwi_widget->pos_x + nwi_widget->current_x - 1 - nwi_widget->IsLowered(),
    01067           nwi_widget->pos_y + 1 + nwi_widget->IsLowered(), str, TC_WHITE, SA_HOR_CENTER);
    01068     }
    01069   }
    01070
    01071   void UpdateData()
    01072   {
    01073     this->ge = (GenderEthnicity)GB(this->face, _cmf_info[CMFV_GEN_ETHN].offset, _cmf_info[CMFV_GEN_ETHN].length); // get the gender and ethnicity
    01074     this->is_female = HasBit(this->ge, GENDER_FEMALE); // get the gender: 0 == male and 1 == female
    01075     this->is_moust_male = !is_female && GetCompanyManagerFaceBits(this->face, CMFV_HAS_MOUSTACHE, this->ge) != 0; // is a male face with moustache
    01076   }
    01077
    01078 public:
    01079   SelectCompanyManagerFaceWindow(const WindowDesc *desc, Window *parent) : Window()
    01080   {
    01081     this->advanced = false;
    01082     this->CreateNestedTree(desc);
    01083     this->SelectDisplayPlanes(this->advanced);
    01084     this->FinishInitNested(desc, parent->window_number);
    01085     this->parent = parent;
    01086     this->owner = (Owner)this->window_number;
    01087     this->face = Company::Get((CompanyID)this->window_number)->face;
    01088
    01089     this->UpdateData();
    01090   }
    01091
    01096   void SelectDisplayPlanes(bool advanced)
    01097   {
    01098     this->GetWidget<NWidgetStacked>(WID_SCMF_SEL_LOADSAVE)->SetDisplayedPlane(advanced ? 0 : SZSP_NONE);
    01099     this->GetWidget<NWidgetStacked>(WID_SCMF_SEL_PARTS)->SetDisplayedPlane(advanced ? 0 : SZSP_NONE);
    01100     this->GetWidget<NWidgetStacked>(WID_SCMF_SEL_MALEFEMALE)->SetDisplayedPlane(advanced ? SZSP_NONE : 0);
    01101     this->GetWidget<NWidgetCore>(WID_SCMF_RANDOM_NEW_FACE)->widget_data = advanced ? STR_MAPGEN_RANDOM : STR_FACE_NEW_FACE_BUTTON;
    01102
    01103     NWidgetCore *wi = this->GetWidget<NWidgetCore>(WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON);
    01104     if (advanced) {
    01105       wi->SetDataTip(STR_FACE_SIMPLE, STR_FACE_SIMPLE_TOOLTIP);
    01106     } else {
    01107       wi->SetDataTip(STR_FACE_ADVANCED, STR_FACE_ADVANCED_TOOLTIP);
    01108     }
    01109   }
    01110
    01111   virtual void OnInit()
    01112   {
    01113     /* Size of the boolean yes/no button. */
    01114     Dimension yesno_dim = maxdim(GetStringBoundingBox(STR_FACE_YES), GetStringBoundingBox(STR_FACE_NO));
    01115     yesno_dim.width  += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
    01116     yesno_dim.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
    01117     /* Size of the number button + arrows. */
    01118     Dimension number_dim = {0, 0};
    01119     for (int val = 1; val <= 12; val++) {
    01120       SetDParam(0, val);
    01121       number_dim = maxdim(number_dim, GetStringBoundingBox(STR_JUST_INT));
    01122     }
    01123     uint arrows_width = GetSpriteSize(SPR_ARROW_LEFT).width + GetSpriteSize(SPR_ARROW_RIGHT).width + 2 * (WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT);
    01124     number_dim.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT + arrows_width;
    01125     number_dim.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
    01126     /* Compute width of both buttons. */
    01127     yesno_dim.width = max(yesno_dim.width, number_dim.width);
    01128     number_dim.width = yesno_dim.width - arrows_width;
    01129
    01130     this->yesno_dim = yesno_dim;
    01131     this->number_dim = number_dim;
    01132   }
    01133
    01134   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
    01135   {
    01136     switch (widget) {
    01137       case WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT:
    01138       case WID_SCMF_TIE_EARRING_TEXT: {
    01139         int offset = (widget - WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT) * 2;
    01140         *size = maxdim(GetStringBoundingBox(PART_TEXTS_IS_FEMALE[offset]), GetStringBoundingBox(PART_TEXTS_IS_FEMALE[offset + 1]));
    01141         size->width  += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
    01142         size->height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
    01143         break;
    01144       }
    01145
    01146       case WID_SCMF_LIPS_MOUSTACHE_TEXT:
    01147         *size = maxdim(GetStringBoundingBox(STR_FACE_LIPS), GetStringBoundingBox(STR_FACE_MOUSTACHE));
    01148         size->width  += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
    01149         size->height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
    01150         break;
    01151
    01152       case WID_SCMF_HAS_GLASSES_TEXT:
    01153       case WID_SCMF_HAIR_TEXT:
    01154       case WID_SCMF_EYEBROWS_TEXT:
    01155       case WID_SCMF_EYECOLOUR_TEXT:
    01156       case WID_SCMF_GLASSES_TEXT:
    01157       case WID_SCMF_NOSE_TEXT:
    01158       case WID_SCMF_CHIN_TEXT:
    01159       case WID_SCMF_JACKET_TEXT:
    01160       case WID_SCMF_COLLAR_TEXT:
    01161         *size = GetStringBoundingBox(PART_TEXTS[widget - WID_SCMF_HAS_GLASSES_TEXT]);
    01162         size->width  += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
    01163         size->height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
    01164         break;
    01165
    01166       case WID_SCMF_HAS_MOUSTACHE_EARRING:
    01167       case WID_SCMF_HAS_GLASSES:
    01168         *size = this->yesno_dim;
    01169         break;
    01170
    01171       case WID_SCMF_EYECOLOUR:
    01172       case WID_SCMF_CHIN:
    01173       case WID_SCMF_EYEBROWS:
    01174       case WID_SCMF_LIPS_MOUSTACHE:
    01175       case WID_SCMF_NOSE:
    01176       case WID_SCMF_HAIR:
    01177       case WID_SCMF_JACKET:
    01178       case WID_SCMF_COLLAR:
    01179       case WID_SCMF_TIE_EARRING:
    01180       case WID_SCMF_GLASSES:
    01181         *size = this->number_dim;
    01182         break;
    01183     }
    01184   }
    01185
    01186   virtual void OnPaint()
    01187   {
    01188     /* lower the non-selected gender button */
    01189     this->SetWidgetsLoweredState(!this->is_female, WID_SCMF_MALE, WID_SCMF_MALE2, WIDGET_LIST_END);
    01190     this->SetWidgetsLoweredState( this->is_female, WID_SCMF_FEMALE, WID_SCMF_FEMALE2, WIDGET_LIST_END);
    01191
    01192     /* advanced company manager face selection window */
    01193
    01194     /* lower the non-selected ethnicity button */
    01195     this->SetWidgetLoweredState(WID_SCMF_ETHNICITY_EUR, !HasBit(this->ge, ETHNICITY_BLACK));
    01196     this->SetWidgetLoweredState(WID_SCMF_ETHNICITY_AFR,  HasBit(this->ge, ETHNICITY_BLACK));
    01197
    01198
    01199     /* Disable dynamically the widgets which CompanyManagerFaceVariable has less than 2 options
    01200      * (or in other words you haven't any choice).
    01201      * If the widgets depend on a HAS-variable and this is false the widgets will be disabled, too. */
    01202
    01203     /* Eye colour buttons */
    01204     this->SetWidgetsDisabledState(_cmf_info[CMFV_EYE_COLOUR].valid_values[this->ge] < 2,
    01205         WID_SCMF_EYECOLOUR, WID_SCMF_EYECOLOUR_L, WID_SCMF_EYECOLOUR_R, WIDGET_LIST_END);
    01206
    01207     /* Chin buttons */
    01208     this->SetWidgetsDisabledState(_cmf_info[CMFV_CHIN].valid_values[this->ge] < 2,
    01209         WID_SCMF_CHIN, WID_SCMF_CHIN_L, WID_SCMF_CHIN_R, WIDGET_LIST_END);
    01210
    01211     /* Eyebrows buttons */
    01212     this->SetWidgetsDisabledState(_cmf_info[CMFV_EYEBROWS].valid_values[this->ge] < 2,
    01213         WID_SCMF_EYEBROWS, WID_SCMF_EYEBROWS_L, WID_SCMF_EYEBROWS_R, WIDGET_LIST_END);
    01214
    01215     /* Lips or (if it a male face with a moustache) moustache buttons */
    01216     this->SetWidgetsDisabledState(_cmf_info[this->is_moust_male ? CMFV_MOUSTACHE : CMFV_LIPS].valid_values[this->ge] < 2,
    01217         WID_SCMF_LIPS_MOUSTACHE, WID_SCMF_LIPS_MOUSTACHE_L, WID_SCMF_LIPS_MOUSTACHE_R, WIDGET_LIST_END);
    01218
    01219     /* Nose buttons | male faces with moustache haven't any nose options */
    01220     this->SetWidgetsDisabledState(_cmf_info[CMFV_NOSE].valid_values[this->ge] < 2 || this->is_moust_male,
    01221         WID_SCMF_NOSE, WID_SCMF_NOSE_L, WID_SCMF_NOSE_R, WIDGET_LIST_END);
    01222
    01223     /* Hair buttons */
    01224     this->SetWidgetsDisabledState(_cmf_info[CMFV_HAIR].valid_values[this->ge] < 2,
    01225         WID_SCMF_HAIR, WID_SCMF_HAIR_L, WID_SCMF_HAIR_R, WIDGET_LIST_END);
    01226
    01227     /* Jacket buttons */
    01228     this->SetWidgetsDisabledState(_cmf_info[CMFV_JACKET].valid_values[this->ge] < 2,
    01229         WID_SCMF_JACKET, WID_SCMF_JACKET_L, WID_SCMF_JACKET_R, WIDGET_LIST_END);
    01230
    01231     /* Collar buttons */
    01232     this->SetWidgetsDisabledState(_cmf_info[CMFV_COLLAR].valid_values[this->ge] < 2,
    01233         WID_SCMF_COLLAR, WID_SCMF_COLLAR_L, WID_SCMF_COLLAR_R, WIDGET_LIST_END);
    01234
    01235     /* Tie/earring buttons | female faces without earring haven't any earring options */
    01236     this->SetWidgetsDisabledState(_cmf_info[CMFV_TIE_EARRING].valid_values[this->ge] < 2 ||
    01237           (this->is_female && GetCompanyManagerFaceBits(this->face, CMFV_HAS_TIE_EARRING, this->ge) == 0),
    01238         WID_SCMF_TIE_EARRING, WID_SCMF_TIE_EARRING_L, WID_SCMF_TIE_EARRING_R, WIDGET_LIST_END);
    01239
    01240     /* Glasses buttons | faces without glasses haven't any glasses options */
    01241     this->SetWidgetsDisabledState(_cmf_info[CMFV_GLASSES].valid_values[this->ge] < 2 || GetCompanyManagerFaceBits(this->face, CMFV_HAS_GLASSES, this->ge) == 0,
    01242         WID_SCMF_GLASSES, WID_SCMF_GLASSES_L, WID_SCMF_GLASSES_R, WIDGET_LIST_END);
    01243
    01244     this->DrawWidgets();
    01245   }
    01246
    01247   virtual void DrawWidget(const Rect &r, int widget) const
    01248   {
    01249     switch (widget) {
    01250       case WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT:
    01251       case WID_SCMF_TIE_EARRING_TEXT: {
    01252         StringID str = PART_TEXTS_IS_FEMALE[(widget - WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT) * 2 + this->is_female];
    01253         DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, str, TC_GOLD, SA_RIGHT);
    01254         break;
    01255       }
    01256
    01257       case WID_SCMF_LIPS_MOUSTACHE_TEXT:
    01258         DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, (this->is_moust_male) ? STR_FACE_MOUSTACHE : STR_FACE_LIPS, TC_GOLD, SA_RIGHT);
    01259         break;
    01260
    01261       case WID_SCMF_HAS_GLASSES_TEXT:
    01262       case WID_SCMF_HAIR_TEXT:
    01263       case WID_SCMF_EYEBROWS_TEXT:
    01264       case WID_SCMF_EYECOLOUR_TEXT:
    01265       case WID_SCMF_GLASSES_TEXT:
    01266       case WID_SCMF_NOSE_TEXT:
    01267       case WID_SCMF_CHIN_TEXT:
    01268       case WID_SCMF_JACKET_TEXT:
    01269       case WID_SCMF_COLLAR_TEXT:
    01270         DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, PART_TEXTS[widget - WID_SCMF_HAS_GLASSES_TEXT], TC_GOLD, SA_RIGHT);
    01271         break;
    01272
    01273
    01274       case WID_SCMF_HAS_MOUSTACHE_EARRING:
    01275         if (this->is_female) { // Only for female faces
    01276           this->DrawFaceStringLabel(WID_SCMF_HAS_MOUSTACHE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_HAS_TIE_EARRING, this->ge), true);
    01277         } else { // Only for male faces
    01278           this->DrawFaceStringLabel(WID_SCMF_HAS_MOUSTACHE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_HAS_MOUSTACHE,   this->ge), true);
    01279         }
    01280         break;
    01281
    01282       case WID_SCMF_TIE_EARRING:
    01283         if (this->is_female) { // Only for female faces
    01284           this->DrawFaceStringLabel(WID_SCMF_TIE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_TIE_EARRING, this->ge), false);
    01285         } else { // Only for male faces
    01286           this->DrawFaceStringLabel(WID_SCMF_TIE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_TIE_EARRING, this->ge), false);
    01287         }
    01288         break;
    01289
    01290       case WID_SCMF_LIPS_MOUSTACHE:
    01291         if (this->is_moust_male) { // Only for male faces with moustache
    01292           this->DrawFaceStringLabel(WID_SCMF_LIPS_MOUSTACHE, GetCompanyManagerFaceBits(this->face, CMFV_MOUSTACHE, this->ge), false);
    01293         } else { // Only for female faces or male faces without moustache
    01294           this->DrawFaceStringLabel(WID_SCMF_LIPS_MOUSTACHE, GetCompanyManagerFaceBits(this->face, CMFV_LIPS,      this->ge), false);
    01295         }
    01296         break;
    01297
    01298       case WID_SCMF_HAS_GLASSES:
    01299         this->DrawFaceStringLabel(WID_SCMF_HAS_GLASSES, GetCompanyManagerFaceBits(this->face, CMFV_HAS_GLASSES, this->ge), true );
    01300         break;
    01301
    01302       case WID_SCMF_HAIR:
    01303         this->DrawFaceStringLabel(WID_SCMF_HAIR,        GetCompanyManagerFaceBits(this->face, CMFV_HAIR,        this->ge), false);
    01304         break;
    01305
    01306       case WID_SCMF_EYEBROWS:
    01307         this->DrawFaceStringLabel(WID_SCMF_EYEBROWS,    GetCompanyManagerFaceBits(this->face, CMFV_EYEBROWS,    this->ge), false);
    01308         break;
    01309
    01310       case WID_SCMF_EYECOLOUR:
    01311         this->DrawFaceStringLabel(WID_SCMF_EYECOLOUR,   GetCompanyManagerFaceBits(this->face, CMFV_EYE_COLOUR,  this->ge), false);
    01312         break;
    01313
    01314       case WID_SCMF_GLASSES:
    01315         this->DrawFaceStringLabel(WID_SCMF_GLASSES,     GetCompanyManagerFaceBits(this->face, CMFV_GLASSES,     this->ge), false);
    01316         break;
    01317
    01318       case WID_SCMF_NOSE:
    01319         this->DrawFaceStringLabel(WID_SCMF_NOSE,        GetCompanyManagerFaceBits(this->face, CMFV_NOSE,        this->ge), false);
    01320         break;
    01321
    01322       case WID_SCMF_CHIN:
    01323         this->DrawFaceStringLabel(WID_SCMF_CHIN,        GetCompanyManagerFaceBits(this->face, CMFV_CHIN,        this->ge), false);
    01324         break;
    01325
    01326       case WID_SCMF_JACKET:
    01327         this->DrawFaceStringLabel(WID_SCMF_JACKET,      GetCompanyManagerFaceBits(this->face, CMFV_JACKET,      this->ge), false);
    01328         break;
    01329
    01330       case WID_SCMF_COLLAR:
    01331         this->DrawFaceStringLabel(WID_SCMF_COLLAR,      GetCompanyManagerFaceBits(this->face, CMFV_COLLAR,      this->ge), false);
    01332         break;
    01333
    01334       case WID_SCMF_FACE:
    01335         DrawCompanyManagerFace(this->face, Company::Get((CompanyID)this->window_number)->colour, r.left, r.top);
    01336         break;
    01337     }
    01338   }
    01339
    01340   virtual void OnClick(Point pt, int widget, int click_count)
    01341   {
    01342     switch (widget) {
    01343       /* Toggle size, advanced/simple face selection */
    01344       case WID_SCMF_TOGGLE_LARGE_SMALL:
    01345       case WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON:
    01346         this->advanced = !this->advanced;
    01347         this->SelectDisplayPlanes(this->advanced);
    01348         this->ReInit();
    01349         break;
    01350
    01351       /* OK button */
    01352       case WID_SCMF_ACCEPT:
    01353         DoCommandP(0, 0, this->face, CMD_SET_COMPANY_MANAGER_FACE);
    01354         /* FALL THROUGH */
    01355
    01356       /* Cancel button */
    01357       case WID_SCMF_CANCEL:
    01358         delete this;
    01359         break;
    01360
    01361       /* Load button */
    01362       case WID_SCMF_LOAD:
    01363         this->face = _company_manager_face;
    01364         ScaleAllCompanyManagerFaceBits(this->face);
    01365         ShowErrorMessage(STR_FACE_LOAD_DONE, INVALID_STRING_ID, WL_INFO);
    01366         this->UpdateData();
    01367         this->SetDirty();
    01368         break;
    01369
    01370       /* 'Company manager face number' button, view and/or set company manager face number */
    01371       case WID_SCMF_FACECODE:
    01372         SetDParam(0, this->face);
    01373         ShowQueryString(STR_JUST_INT, STR_FACE_FACECODE_CAPTION, 10 + 1, this, CS_NUMERAL, QSF_NONE);
    01374         break;
    01375
    01376       /* Save button */
    01377       case WID_SCMF_SAVE:
    01378         _company_manager_face = this->face;
    01379         ShowErrorMessage(STR_FACE_SAVE_DONE, INVALID_STRING_ID, WL_INFO);
    01380         break;
    01381
    01382       /* Toggle gender (male/female) button */
    01383       case WID_SCMF_MALE:
    01384       case WID_SCMF_FEMALE:
    01385       case WID_SCMF_MALE2:
    01386       case WID_SCMF_FEMALE2:
    01387         SetCompanyManagerFaceBits(this->face, CMFV_GENDER, this->ge, (widget == WID_SCMF_FEMALE || widget == WID_SCMF_FEMALE2));
    01388         ScaleAllCompanyManagerFaceBits(this->face);
    01389         this->UpdateData();
    01390         this->SetDirty();
    01391         break;
    01392
    01393       /* Randomize face button */
    01394       case WID_SCMF_RANDOM_NEW_FACE:
    01395         RandomCompanyManagerFaceBits(this->face, this->ge, this->advanced);
    01396         this->UpdateData();
    01397         this->SetDirty();
    01398         break;
    01399
    01400       /* Toggle ethnicity (european/african) button */
    01401       case WID_SCMF_ETHNICITY_EUR:
    01402       case WID_SCMF_ETHNICITY_AFR:
    01403         SetCompanyManagerFaceBits(this->face, CMFV_ETHNICITY, this->ge, widget - WID_SCMF_ETHNICITY_EUR);
    01404         ScaleAllCompanyManagerFaceBits(this->face);
    01405         this->UpdateData();
    01406         this->SetDirty();
    01407         break;
    01408
    01409       default:
    01410         /* Here all buttons from WID_SCMF_HAS_MOUSTACHE_EARRING to WID_SCMF_GLASSES_R are handled.
    01411          * First it checks which CompanyManagerFaceVariable is being changed, and then either
    01412          * a: invert the value for boolean variables, or
    01413          * b: it checks inside of IncreaseCompanyManagerFaceBits() if a left (_L) butten is pressed and then decrease else increase the variable */
    01414         if (widget >= WID_SCMF_HAS_MOUSTACHE_EARRING && widget <= WID_SCMF_GLASSES_R) {
    01415           CompanyManagerFaceVariable cmfv; // which CompanyManagerFaceVariable shall be edited
    01416
    01417           if (widget < WID_SCMF_EYECOLOUR_L) { // Bool buttons
    01418             switch (widget - WID_SCMF_HAS_MOUSTACHE_EARRING) {
    01419               default: NOT_REACHED();
    01420               case 0: cmfv = this->is_female ? CMFV_HAS_TIE_EARRING : CMFV_HAS_MOUSTACHE; break; // Has earring/moustache button
    01421               case 1: cmfv = CMFV_HAS_GLASSES; break; // Has glasses button
    01422             }
    01423             SetCompanyManagerFaceBits(this->face, cmfv, this->ge, !GetCompanyManagerFaceBits(this->face, cmfv, this->ge));
    01424             ScaleAllCompanyManagerFaceBits(this->face);
    01425           } else { // Value buttons
    01426             switch ((widget - WID_SCMF_EYECOLOUR_L) / 3) {
    01427               default: NOT_REACHED();
    01428               case 0: cmfv = CMFV_EYE_COLOUR; break;  // Eye colour buttons
    01429               case 1: cmfv = CMFV_CHIN; break;        // Chin buttons
    01430               case 2: cmfv = CMFV_EYEBROWS; break;    // Eyebrows buttons
    01431               case 3: cmfv = this->is_moust_male ? CMFV_MOUSTACHE : CMFV_LIPS; break; // Moustache or lips buttons
    01432               case 4: cmfv = CMFV_NOSE; break;        // Nose buttons
    01433               case 5: cmfv = CMFV_HAIR; break;        // Hair buttons
    01434               case 6: cmfv = CMFV_JACKET; break;      // Jacket buttons
    01435               case 7: cmfv = CMFV_COLLAR; break;      // Collar buttons
    01436               case 8: cmfv = CMFV_TIE_EARRING; break; // Tie/earring buttons
    01437               case 9: cmfv = CMFV_GLASSES; break;     // Glasses buttons
    01438             }
    01439             /* 0 == left (_L), 1 == middle or 2 == right (_R) - button click */
    01440             IncreaseCompanyManagerFaceBits(this->face, cmfv, this->ge, (((widget - WID_SCMF_EYECOLOUR_L) % 3) != 0) ? 1 : -1);
    01441           }
    01442           this->UpdateData();
    01443           this->SetDirty();
    01444         }
    01445         break;
    01446     }
    01447   }
    01448
    01449   virtual void OnQueryTextFinished(char *str)
    01450   {
    01451     if (str == NULL) return;
    01452     /* Set a new company manager face number */
    01453     if (!StrEmpty(str)) {
    01454       this->face = strtoul(str, NULL, 10);
    01455       ScaleAllCompanyManagerFaceBits(this->face);
    01456       ShowErrorMessage(STR_FACE_FACECODE_SET, INVALID_STRING_ID, WL_INFO);
    01457       this->UpdateData();
    01458       this->SetDirty();
    01459     } else {
    01460       ShowErrorMessage(STR_FACE_FACECODE_ERR, INVALID_STRING_ID, WL_INFO);
    01461     }
    01462   }
    01463 };
    01464
    01466 const StringID SelectCompanyManagerFaceWindow::PART_TEXTS_IS_FEMALE[] = {
    01467   STR_FACE_MOUSTACHE, STR_FACE_EARRING, // WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT
    01468   STR_FACE_TIE,       STR_FACE_EARRING, // WID_SCMF_TIE_EARRING_TEXT
    01469 };
    01470
    01472 const StringID SelectCompanyManagerFaceWindow::PART_TEXTS[] = {
    01473   STR_FACE_GLASSES,   // WID_SCMF_HAS_GLASSES_TEXT
    01474   STR_FACE_HAIR,      // WID_SCMF_HAIR_TEXT
    01475   STR_FACE_EYEBROWS,  // WID_SCMF_EYEBROWS_TEXT
    01476   STR_FACE_EYECOLOUR, // WID_SCMF_EYECOLOUR_TEXT
    01477   STR_FACE_GLASSES,   // WID_SCMF_GLASSES_TEXT
    01478   STR_FACE_NOSE,      // WID_SCMF_NOSE_TEXT
    01479   STR_FACE_CHIN,      // WID_SCMF_CHIN_TEXT
    01480   STR_FACE_JACKET,    // WID_SCMF_JACKET_TEXT
    01481   STR_FACE_COLLAR,    // WID_SCMF_COLLAR_TEXT
    01482 };
    01483
    01485 static const WindowDesc _select_company_manager_face_desc(
    01486   WDP_AUTO, 0, 0,
    01487   WC_COMPANY_MANAGER_FACE, WC_NONE,
    01488   WDF_UNCLICK_BUTTONS | WDF_CONSTRUCTION,
    01489   _nested_select_company_manager_face_widgets, lengthof(_nested_select_company_manager_face_widgets)
    01490 );
    01491
    01500 static void DoSelectCompanyManagerFace(Window *parent)
    01501 {
    01502   if (!Company::IsValidID((CompanyID)parent->window_number)) return;
    01503
    01504   if (BringWindowToFrontById(WC_COMPANY_MANAGER_FACE, parent->window_number)) return;
    01505   new SelectCompanyManagerFaceWindow(&_select_company_manager_face_desc, parent);
    01506 }
    01507
    01508 static const NWidgetPart _nested_company_infrastructure_widgets[] = {
    01509   NWidget(NWID_HORIZONTAL),
    01510     NWidget(WWT_CLOSEBOX, COLOUR_GREY),
    01511     NWidget(WWT_CAPTION, COLOUR_GREY, WID_CI_CAPTION), SetDataTip(STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    01512     NWidget(WWT_SHADEBOX, COLOUR_GREY),
    01513     NWidget(WWT_STICKYBOX, COLOUR_GREY),
    01514   EndContainer(),
    01515   NWidget(WWT_PANEL, COLOUR_GREY),
    01516     NWidget(NWID_VERTICAL), SetPIP(WD_FRAMERECT_TOP, 4, WD_FRAMETEXT_BOTTOM),
    01517       NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
    01518         NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_RAIL_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0),
    01519         NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_RAIL_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1),
    01520       EndContainer(),
    01521       NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
    01522         NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_ROAD_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0),
    01523         NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_ROAD_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1),
    01524       EndContainer(),
    01525       NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
    01526         NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_WATER_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0),
    01527         NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_WATER_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1),
    01528       EndContainer(),
    01529       NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
    01530         NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_STATION_DESC), SetMinimalTextLines(3, 0), SetFill(1, 0),
    01531         NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_STATION_COUNT), SetMinimalTextLines(3, 0), SetFill(0, 1),
    01532       EndContainer(),
    01533       NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
    01534         NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_TOTAL_DESC), SetFill(1, 0),
    01535         NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_TOTAL), SetFill(0, 1),
    01536       EndContainer(),
    01537     EndContainer(),
    01538   EndContainer(),
    01539 };
    01540
    01544 struct CompanyInfrastructureWindow : Window
    01545 {
    01546   RailTypes railtypes;
    01547   RoadTypes roadtypes;
    01548
    01549   uint total_width;
    01550
    01551   CompanyInfrastructureWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
    01552   {
    01553     this->UpdateRailRoadTypes();
    01554
    01555     this->InitNested(desc, window_number);
    01556     this->owner = (Owner)this->window_number;
    01557   }
    01558
    01559   void UpdateRailRoadTypes()
    01560   {
    01561     this->railtypes = RAILTYPES_NONE;
    01562     this->roadtypes = ROADTYPES_ROAD; // Road is always available.
    01563
    01564     /* Find the used railtypes. */
    01565     Engine *e;
    01566     FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) {
    01567       if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue;
    01568
    01569       this->railtypes |= GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes;
    01570     }
    01571
    01572     /* Get the date introduced railtypes as well. */
    01573     this->railtypes = AddDateIntroducedRailTypes(this->railtypes, MAX_DAY);
    01574
    01575     /* Tram is only visible when there will be a tram. */
    01576     FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) {
    01577       if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue;
    01578       if (!HasBit(e->info.misc_flags, EF_ROAD_TRAM)) continue;
    01579
    01580       this->roadtypes |= ROADTYPES_TRAM;
    01581       break;
    01582     }
    01583   }
    01584
    01586   Money GetTotalMaintenanceCost() const
    01587   {
    01588     const Company *c = Company::Get((CompanyID)this->window_number);
    01589     Money total;
    01590
    01591     uint32 rail_total = c->infrastructure.GetRailTotal();
    01592     for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
    01593       if (HasBit(this->railtypes, rt)) total += RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total);
    01594     }
    01595     total += SignalMaintenanceCost(c->infrastructure.signal);
    01596
    01597     if (HasBit(this->roadtypes, ROADTYPE_ROAD)) total += RoadMaintenanceCost(ROADTYPE_ROAD, c->infrastructure.road[ROADTYPE_ROAD]);
    01598     if (HasBit(this->roadtypes, ROADTYPE_TRAM)) total += RoadMaintenanceCost(ROADTYPE_TRAM, c->infrastructure.road[ROADTYPE_TRAM]);
    01599
    01600     total += CanalMaintenanceCost(c->infrastructure.water);
    01601     total += StationMaintenanceCost(c->infrastructure.station);
    01602     total += AirportMaintenanceCost(c->index);
    01603
    01604     return total;
    01605   }
    01606
    01607   virtual void SetStringParameters(int widget) const
    01608   {
    01609     switch (widget) {
    01610       case WID_CI_CAPTION:
    01611         SetDParam(0, (CompanyID)this->window_number);
    01612         break;
    01613     }
    01614   }
    01615
    01616   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
    01617   {
    01618     const Company *c = Company::Get((CompanyID)this->window_number);
    01619
    01620     switch (widget) {
    01621       case WID_CI_RAIL_DESC: {
    01622         uint lines = 1;
    01623
    01624         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT).width);
    01625
    01626         for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) {
    01627           if (HasBit(this->railtypes, rt)) {
    01628             lines++;
    01629             SetDParam(0, GetRailTypeInfo(rt)->strings.name);
    01630             size->width = max(size->width, GetStringBoundingBox(STR_WHITE_STRING).width + WD_FRAMERECT_LEFT);
    01631           }
    01632         }
    01633         if (this->railtypes != RAILTYPES_NONE) {
    01634           lines++;
    01635           size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS).width + WD_FRAMERECT_LEFT);
    01636         }
    01637
    01638         size->height = max(size->height, lines * FONT_HEIGHT_NORMAL);
    01639         break;
    01640       }
    01641
    01642       case WID_CI_ROAD_DESC: {
    01643         uint lines = 1;
    01644
    01645         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT).width);
    01646
    01647         if (HasBit(this->roadtypes, ROADTYPE_ROAD)) {
    01648           lines++;
    01649           size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD).width + WD_FRAMERECT_LEFT);
    01650         }
    01651         if (HasBit(this->roadtypes, ROADTYPE_TRAM)) {
    01652           lines++;
    01653           size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY).width + WD_FRAMERECT_LEFT);
    01654         }
    01655
    01656         size->height = max(size->height, lines * FONT_HEIGHT_NORMAL);
    01657         break;
    01658       }
    01659
    01660       case WID_CI_WATER_DESC:
    01661         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT).width);
    01662         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS).width + WD_FRAMERECT_LEFT);
    01663         break;
    01664
    01665       case WID_CI_STATION_DESC:
    01666         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT).width);
    01667         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS).width + WD_FRAMERECT_LEFT);
    01668         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS).width + WD_FRAMERECT_LEFT);
    01669         break;
    01670
    01671       case WID_CI_RAIL_COUNT:
    01672       case WID_CI_ROAD_COUNT:
    01673       case WID_CI_WATER_COUNT:
    01674       case WID_CI_STATION_COUNT:
    01675       case WID_CI_TOTAL: {
    01676         /* Find the maximum count that is displayed. */
    01677         uint32 max_val = 1000;  // Some random number to reserve enough space.
    01678         Money max_cost = 10000; // Some random number to reserve enough space.
    01679         uint32 rail_total = c->infrastructure.GetRailTotal();
    01680         for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) {
    01681           max_val = max(max_val, c->infrastructure.rail[rt]);
    01682           max_cost = max(max_cost, RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total));
    01683         }
    01684         max_val = max(max_val, c->infrastructure.signal);
    01685         max_cost = max(max_cost, SignalMaintenanceCost(c->infrastructure.signal));
    01686         for (RoadType rt = ROADTYPE_BEGIN; rt < ROADTYPE_END; rt++) {
    01687           max_val = max(max_val, c->infrastructure.road[rt]);
    01688           max_cost = max(max_cost, RoadMaintenanceCost(rt, c->infrastructure.road[rt]));
    01689         }
    01690         max_val = max(max_val, c->infrastructure.water);
    01691         max_cost = max(max_cost, CanalMaintenanceCost(c->infrastructure.water));
    01692         max_val = max(max_val, c->infrastructure.station);
    01693         max_cost = max(max_cost, StationMaintenanceCost(c->infrastructure.station));
    01694         max_val = max(max_val, c->infrastructure.airport);
    01695         max_cost = max(max_cost, AirportMaintenanceCost(c->index));
    01696
    01697         SetDParam(0, max_val);
    01698         SetDParam(1, max_cost * 12); // Convert to per year
    01699         size->width = max(size->width, GetStringBoundingBox(_settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA).width + 20); // Reserve some wiggle room.
    01700
    01701         if (_settings_game.economy.infrastructure_maintenance) {
    01702           SetDParam(0, this->GetTotalMaintenanceCost() * 12); // Convert to per year
    01703           this->total_width = GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL).width + 20;
    01704           size->width = max(size->width, this->total_width);
    01705         }
    01706
    01707         /* Set height of the total line. */
    01708         if (widget == WID_CI_TOTAL) {
    01709           size->height = _settings_game.economy.infrastructure_maintenance ? max(size->height, EXP_LINESPACE + FONT_HEIGHT_NORMAL) : 0;
    01710         }
    01711         break;
    01712       }
    01713     }
    01714   }
    01715
    01716   virtual void DrawWidget(const Rect &r, int widget) const
    01717   {
    01718     const Company *c = Company::Get((CompanyID)this->window_number);
    01719     int y = r.top;
    01720
    01721     int offs_left = _current_text_dir == TD_LTR ? WD_FRAMERECT_LEFT : 0;
    01722     int offs_right = _current_text_dir == TD_LTR ? 0 : WD_FRAMERECT_LEFT;
    01723
    01724     switch (widget) {
    01725       case WID_CI_RAIL_DESC:
    01726         DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT);
    01727
    01728         if (this->railtypes != RAILTYPES_NONE) {
    01729           /* Draw name of each valid railtype. */
    01730           for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
    01731             if (HasBit(this->railtypes, rt)) {
    01732               SetDParam(0, GetRailTypeInfo(rt)->strings.name);
    01733               DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_WHITE_STRING);
    01734             }
    01735           }
    01736           DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS);
    01737         } else {
    01738           /* No valid railtype. */
    01739           DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE);
    01740         }
    01741
    01742         break;
    01743
    01744       case WID_CI_RAIL_COUNT: {
    01745         /* Draw infrastructure count for each valid railtype. */
    01746         uint32 rail_total = c->infrastructure.GetRailTotal();
    01747         for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
    01748           if (HasBit(this->railtypes, rt)) {
    01749             SetDParam(0, c->infrastructure.rail[rt]);
    01750             SetDParam(1, RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total) * 12); // Convert to per year
    01751             DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA);
    01752           }
    01753         }
    01754         if (this->railtypes != RAILTYPES_NONE) {
    01755           SetDParam(0, c->infrastructure.signal);
    01756           SetDParam(1, SignalMaintenanceCost(c->infrastructure.signal) * 12); // Convert to per year
    01757           DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA);
    01758         }
    01759         break;
    01760       }
    01761
    01762       case WID_CI_ROAD_DESC:
    01763         DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT);
    01764
    01765         if (this->roadtypes != ROADTYPES_NONE) {
    01766           if (HasBit(this->roadtypes, ROADTYPE_ROAD)) DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD);
    01767           if (HasBit(this->roadtypes, ROADTYPE_TRAM)) DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY);
    01768         } else {
    01769           /* No valid roadtypes. */
    01770           DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE);
    01771         }
    01772
    01773         break;
    01774
    01775       case WID_CI_ROAD_COUNT:
    01776         if (HasBit(this->roadtypes, ROADTYPE_ROAD)) {
    01777           SetDParam(0, c->infrastructure.road[ROADTYPE_ROAD]);
    01778           SetDParam(1, RoadMaintenanceCost(ROADTYPE_ROAD, c->infrastructure.road[ROADTYPE_ROAD]) * 12); // Convert to per year
    01779           DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA);
    01780         }
    01781         if (HasBit(this->roadtypes, ROADTYPE_TRAM)) {
    01782           SetDParam(0, c->infrastructure.road[ROADTYPE_TRAM]);
    01783           SetDParam(1, RoadMaintenanceCost(ROADTYPE_TRAM, c->infrastructure.road[ROADTYPE_TRAM]) * 12); // Convert to per year
    01784           DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA);
    01785         }
    01786         break;
    01787
    01788       case WID_CI_WATER_DESC:
    01789         DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT);
    01790         DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS);
    01791         break;
    01792
    01793       case WID_CI_WATER_COUNT:
    01794         SetDParam(0, c->infrastructure.water);
    01795         SetDParam(1, CanalMaintenanceCost(c->infrastructure.water) * 12); // Convert to per year
    01796         DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA);
    01797         break;
    01798
    01799       case WID_CI_TOTAL:
    01800         if (_settings_game.economy.infrastructure_maintenance) {
    01801           GfxFillRect(r.left, y, r.left + this->total_width, y, PC_WHITE);
    01802           y += EXP_LINESPACE;
    01803           SetDParam(0, this->GetTotalMaintenanceCost() * 12); // Convert to per year
    01804           DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL);
    01805         }
    01806         break;
    01807
    01808       case WID_CI_STATION_DESC:
    01809         DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT);
    01810         DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS);
    01811         DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS);
    01812         break;
    01813
    01814       case WID_CI_STATION_COUNT:
    01815         SetDParam(0, c->infrastructure.station);
    01816         SetDParam(1, StationMaintenanceCost(c->infrastructure.station) * 12); // Convert to per year
    01817         DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA);
    01818         SetDParam(0, c->infrastructure.airport);
    01819         SetDParam(1, AirportMaintenanceCost(c->index) * 12); // Convert to per year
    01820         DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA);
    01821         break;
    01822     }
    01823   }
    01824
    01830   virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
    01831   {
    01832     if (!gui_scope) return;
    01833
    01834     this->UpdateRailRoadTypes();
    01835     this->ReInit();
    01836   }
    01837 };
    01838
    01839 static const WindowDesc _company_infrastructure_desc(
    01840   WDP_AUTO, 0, 0,
    01841   WC_COMPANY_INFRASTRUCTURE, WC_NONE,
    01842   WDF_UNCLICK_BUTTONS,
    01843   _nested_company_infrastructure_widgets, lengthof(_nested_company_infrastructure_widgets)
    01844 );
    01845
    01850 static void ShowCompanyInfrastructure(CompanyID company)
    01851 {
    01852   if (!Company::IsValidID(company)) return;
    01853   AllocateWindowDescFront<CompanyInfrastructureWindow>(&_company_infrastructure_desc, company);
    01854 }
    01855
    01856 static const NWidgetPart _nested_company_widgets[] = {
    01857   NWidget(NWID_HORIZONTAL),
    01858     NWidget(WWT_CLOSEBOX, COLOUR_GREY),
    01859     NWidget(WWT_CAPTION, COLOUR_GREY, WID_C_CAPTION), SetDataTip(STR_COMPANY_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    01860     NWidget(WWT_SHADEBOX, COLOUR_GREY),
    01861     NWidget(WWT_STICKYBOX, COLOUR_GREY),
    01862   EndContainer(),
    01863   NWidget(WWT_PANEL, COLOUR_GREY),
    01864     NWidget(NWID_HORIZONTAL), SetPIP(4, 6, 4),
    01865       NWidget(NWID_VERTICAL), SetPIP(4, 2, 4),
    01866         NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_FACE), SetMinimalSize(92, 119), SetFill(1, 0),
    01867         NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_FACE_TITLE), SetFill(1, 1), SetMinimalTextLines(2, 0),
    01868       EndContainer(),
    01869       NWidget(NWID_VERTICAL),
    01870         NWidget(NWID_HORIZONTAL),
    01871           NWidget(NWID_VERTICAL), SetPIP(4, 5, 5),
    01872             NWidget(WWT_TEXT, COLOUR_GREY, WID_C_DESC_INAUGURATION), SetDataTip(STR_COMPANY_VIEW_INAUGURATED_TITLE, STR_NULL), SetFill(1, 0),
    01873             NWidget(NWID_HORIZONTAL), SetPIP(0, 5, 0),
    01874               NWidget(WWT_LABEL, COLOUR_GREY, WID_C_DESC_COLOUR_SCHEME), SetDataTip(STR_COMPANY_VIEW_COLOUR_SCHEME_TITLE, STR_NULL),
    01875               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_DESC_COLOUR_SCHEME_EXAMPLE), SetMinimalSize(30, 0), SetFill(0, 1),
    01876               NWidget(NWID_SPACER), SetFill(1, 0),
    01877             EndContainer(),
    01878             NWidget(NWID_HORIZONTAL), SetPIP(0, 4, 0),
    01879               NWidget(NWID_VERTICAL),
    01880                 NWidget(WWT_TEXT, COLOUR_GREY, WID_C_DESC_VEHICLE), SetDataTip(STR_COMPANY_VIEW_VEHICLES_TITLE, STR_NULL),
    01881                 NWidget(NWID_SPACER), SetFill(0, 1),
    01882               EndContainer(),
    01883               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_DESC_VEHICLE_COUNTS), SetMinimalTextLines(4, 0),
    01884               NWidget(NWID_SPACER), SetFill(1, 0),
    01885             EndContainer(),
    01886           EndContainer(),
    01887           NWidget(NWID_VERTICAL), SetPIP(4, 2, 4),
    01888             NWidget(NWID_SELECTION, INVALID_COLOUR, WID_C_SELECT_VIEW_BUILD_HQ),
    01889               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_VIEW_HQ), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_VIEW_HQ_BUTTON, STR_COMPANY_VIEW_VIEW_HQ_TOOLTIP),
    01890               NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_C_BUILD_HQ), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_BUILD_HQ_BUTTON, STR_COMPANY_VIEW_BUILD_HQ_TOOLTIP),
    01891             EndContainer(),
    01892             NWidget(NWID_SELECTION, INVALID_COLOUR, WID_C_SELECT_RELOCATE),
    01893               NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_C_RELOCATE_HQ), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_RELOCATE_HQ, STR_COMPANY_VIEW_RELOCATE_COMPANY_HEADQUARTERS),
    01894               NWidget(NWID_SPACER), SetMinimalSize(90, 0),
    01895             EndContainer(),
    01896             NWidget(NWID_SPACER), SetFill(0, 1),
    01897           EndContainer(),
    01898         EndContainer(),
    01899         NWidget(WWT_TEXT, COLOUR_GREY, WID_C_DESC_COMPANY_VALUE), SetDataTip(STR_COMPANY_VIEW_COMPANY_VALUE, STR_NULL), SetFill(1, 0),
    01900           NWidget(NWID_VERTICAL), SetPIP(4, 2, 4),
    01901             NWidget(NWID_HORIZONTAL), SetPIP(0, 4, 0),
    01902               NWidget(NWID_VERTICAL),
    01903                 NWidget(WWT_TEXT, COLOUR_GREY, WID_C_DESC_INFRASTRUCTURE), SetDataTip(STR_COMPANY_VIEW_INFRASTRUCTURE, STR_NULL),
    01904                 NWidget(NWID_SPACER), SetFill(0, 1),
    01905               EndContainer(),
    01906               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_DESC_INFRASTRUCTURE_COUNTS), SetMinimalTextLines(5, 0), SetFill(1, 0),
    01907               NWidget(NWID_VERTICAL),
    01908                 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_VIEW_INFRASTRUCTURE), SetDataTip(STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON, STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP),
    01909                 NWidget(NWID_SPACER), SetFill(0, 1), SetMinimalSize(90, 0),
    01910               EndContainer(),
    01911             EndContainer(),
    01912           EndContainer(),
    01913         NWidget(NWID_HORIZONTAL),
    01914           NWidget(NWID_SELECTION, INVALID_COLOUR, WID_C_SELECT_DESC_OWNERS),
    01915             NWidget(NWID_VERTICAL), SetPIP(5, 5, 4),
    01916               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_DESC_OWNERS), SetMinimalTextLines(3, 0),
    01917               NWidget(NWID_SPACER), SetFill(0, 1),
    01918             EndContainer(),
    01919           EndContainer(),
    01920           NWidget(NWID_VERTICAL), SetPIP(4, 2, 4),
    01921             NWidget(NWID_SPACER), SetMinimalSize(90, 0), SetFill(0, 1),
    01922             /* Multi player buttons. */
    01923             NWidget(NWID_HORIZONTAL),
    01924               NWidget(WWT_EMPTY, COLOUR_GREY, WID_C_HAS_PASSWORD),
    01925               NWidget(NWID_SELECTION, INVALID_COLOUR, WID_C_SELECT_MULTIPLAYER),
    01926                 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_COMPANY_PASSWORD), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_PASSWORD, STR_COMPANY_VIEW_PASSWORD_TOOLTIP),
    01927                 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_COMPANY_JOIN), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_JOIN, STR_COMPANY_VIEW_JOIN_TOOLTIP),
    01928               EndContainer(),
    01929             EndContainer(),
    01930           EndContainer(),
    01931         EndContainer(),
    01932       EndContainer(),
    01933     EndContainer(),
    01934   EndContainer(),
    01935   /* Button bars at the bottom. */
    01936   NWidget(NWID_SELECTION, INVALID_COLOUR, WID_C_SELECT_BUTTONS),
    01937     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
    01938       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),
    01939       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),
    01940       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),
    01941       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),
    01942     EndContainer(),
    01943     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
    01944       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),
    01945       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),
    01946     EndContainer(),
    01947   EndContainer(),
    01948 };
    01949
    01950 int GetAmountOwnedBy(const Company *c, Owner owner)
    01951 {
    01952   return (c->share_owners[0] == owner) +
    01953          (c->share_owners[1] == owner) +
    01954          (c->share_owners[2] == owner) +
    01955          (c->share_owners[3] == owner);
    01956 }
    01957
    01959 static const StringID _company_view_vehicle_count_strings[] = {
    01960   STR_COMPANY_VIEW_TRAINS, STR_COMPANY_VIEW_ROAD_VEHICLES, STR_COMPANY_VIEW_SHIPS, STR_COMPANY_VIEW_AIRCRAFT
    01961 };
    01962
    01966 struct CompanyWindow : Window
    01967 {
    01968   CompanyWidgets query_widget;
    01969
    01971   enum CompanyWindowPlanes {
    01972     /* Display planes of the #WID_C_SELECT_MULTIPLAYER selection widget. */
    01973     CWP_MP_C_PWD = 0,
    01974     CWP_MP_C_JOIN,
    01975
    01976     /* Display planes of the #WID_C_SELECT_VIEW_BUILD_HQ selection widget. */
    01977     CWP_VB_VIEW = 0,
    01978     CWP_VB_BUILD,
    01979
    01980     /* Display planes of the #WID_C_SELECT_RELOCATE selection widget. */
    01981     CWP_RELOCATE_SHOW = 0,
    01982     CWP_RELOCATE_HIDE,
    01983
    01984     /* Display planes of the #WID_C_SELECT_BUTTONS selection widget. */
    01985     CWP_BUTTONS_LOCAL = 0,
    01986     CWP_BUTTONS_OTHER,
    01987   };
    01988
    01989   CompanyWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
    01990   {
    01991     this->InitNested(desc, window_number);
    01992     this->owner = (Owner)this->window_number;
    01993   }
    01994
    01995   virtual void OnPaint()
    01996   {
    01997     const Company *c = Company::Get((CompanyID)this->window_number);
    01998     bool local = this->window_number == _local_company;
    01999
    02000     if (!this->IsShaded()) {
    02001       bool reinit = false;
    02002
    02003       /* Button bar selection. */
    02004       int plane = local ? CWP_BUTTONS_LOCAL : CWP_BUTTONS_OTHER;
    02005       NWidgetStacked *wi = this->GetWidget<NWidgetStacked>(WID_C_SELECT_BUTTONS);
    02006       if (plane != wi->shown_plane) {
    02007         wi->SetDisplayedPlane(plane);
    02008         this->SetDirty();
    02009         return;
    02010       }
    02011
    02012       /* Build HQ button handling. */
    02013       plane = (local && c->location_of_HQ == INVALID_TILE) ? CWP_VB_BUILD : CWP_VB_VIEW;
    02014       wi = this->GetWidget<NWidgetStacked>(WID_C_SELECT_VIEW_BUILD_HQ);
    02015       if (plane != wi->shown_plane) {
    02016         wi->SetDisplayedPlane(plane);
    02017         this->SetDirty();
    02018         return;
    02019       }
    02020
    02021       this->SetWidgetDisabledState(WID_C_VIEW_HQ, c->location_of_HQ == INVALID_TILE);
    02022
    02023       /* Enable/disable 'Relocate HQ' button. */
    02024       plane = (!local || c->location_of_HQ == INVALID_TILE) ? CWP_RELOCATE_HIDE : CWP_RELOCATE_SHOW;
    02025       wi = this->GetWidget<NWidgetStacked>(WID_C_SELECT_RELOCATE);
    02026       if (plane != wi->shown_plane) {
    02027         wi->SetDisplayedPlane(plane);
    02028         this->SetDirty();
    02029         return;
    02030       }
    02031
    02032       /* Owners of company */
    02033       plane = SZSP_HORIZONTAL;
    02034       for (uint i = 0; i < lengthof(c->share_owners); i++) {
    02035         if (c->share_owners[i] != INVALID_COMPANY) {
    02036           plane = 0;
    02037           break;
    02038         }
    02039       }
    02040       wi = this->GetWidget<NWidgetStacked>(WID_C_SELECT_DESC_OWNERS);
    02041       if (plane != wi->shown_plane) {
    02042         wi->SetDisplayedPlane(plane);
    02043         reinit = true;
    02044       }
    02045
    02046       /* Multiplayer buttons. */
    02047       plane = ((!_networking) ? (int)SZSP_NONE : (int)(local ? CWP_MP_C_PWD : CWP_MP_C_JOIN));
    02048       wi = this->GetWidget<NWidgetStacked>(WID_C_SELECT_MULTIPLAYER);
    02049       if (plane != wi->shown_plane) {
    02050         wi->SetDisplayedPlane(plane);
    02051         reinit = true;
    02052       }
    02053       this->SetWidgetDisabledState(WID_C_COMPANY_JOIN,   c->is_ai);
    02054
    02055       if (reinit) {
    02056         this->ReInit();
    02057         return;
    02058       }
    02059     }
    02060
    02061     if (!local) {
    02062       if (_settings_game.economy.allow_shares) { // Shares are allowed
    02063         /* If all shares are owned by someone (none by nobody), disable buy button */
    02064         this->SetWidgetDisabledState(WID_C_BUY_SHARE, GetAmountOwnedBy(c, INVALID_OWNER) == 0 ||
    02065             /* Only 25% left to buy. If the company is human, disable buying it up.. TODO issues! */
    02066             (GetAmountOwnedBy(c, INVALID_OWNER) == 1 && !c->is_ai) ||
    02067             /* Spectators cannot do anything of course */
    02068             _local_company == COMPANY_SPECTATOR);
    02069
    02070         /* If the company doesn't own any shares, disable sell button */
    02071         this->SetWidgetDisabledState(WID_C_SELL_SHARE, (GetAmountOwnedBy(c, _local_company) == 0) ||
    02072             /* Spectators cannot do anything of course */
    02073             _local_company == COMPANY_SPECTATOR);
    02074       } else { // Shares are not allowed, disable buy/sell buttons
    02075         this->DisableWidget(WID_C_BUY_SHARE);
    02076         this->DisableWidget(WID_C_SELL_SHARE);
    02077       }
    02078     }
    02079
    02080     this->DrawWidgets();
    02081   }
    02082
    02083   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
    02084   {
    02085     switch (widget) {
    02086       case WID_C_DESC_COLOUR_SCHEME_EXAMPLE: {
    02087         Point offset;
    02088         Dimension d = GetSpriteSize(SPR_VEH_BUS_SW_VIEW, &offset);
    02089         d.width -= offset.x;
    02090         d.height -= offset.y;
    02091         *size = maxdim(*size, d);
    02092         break;
    02093       }
    02094
    02095       case WID_C_DESC_COMPANY_VALUE:
    02096         SetDParam(0, INT64_MAX); // Arguably the maximum company value
    02097         size->width = GetStringBoundingBox(STR_COMPANY_VIEW_COMPANY_VALUE).width;
    02098         break;
    02099
    02100       case WID_C_DESC_VEHICLE_COUNTS:
    02101         SetDParam(0, 5000); // Maximum number of vehicles
    02102         for (uint i = 0; i < lengthof(_company_view_vehicle_count_strings); i++) {
    02103           size->width = max(size->width, GetStringBoundingBox(_company_view_vehicle_count_strings[i]).width);
    02104         }
    02105         break;
    02106
    02107       case WID_C_DESC_INFRASTRUCTURE_COUNTS:
    02108         SetDParam(0, UINT_MAX);
    02109         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL).width);
    02110         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD).width);
    02111         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_WATER).width);
    02112         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_STATION).width);
    02113         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT).width);
    02114         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_NONE).width);
    02115         break;
    02116
    02117       case WID_C_DESC_OWNERS: {
    02118         const Company *c2;
    02119
    02120         FOR_ALL_COMPANIES(c2) {
    02121           SetDParam(0, 25);
    02122           SetDParam(1, c2->index);
    02123
    02124           size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_SHARES_OWNED_BY).width);
    02125         }
    02126         break;
    02127       }
    02128
    02129 #ifdef ENABLE_NETWORK
    02130       case WID_C_HAS_PASSWORD:
    02131         *size = maxdim(*size, GetSpriteSize(SPR_LOCK));
    02132         break;
    02133 #endif /* ENABLE_NETWORK */
    02134     }
    02135   }
    02136
    02137   virtual void DrawWidget(const Rect &r, int widget) const
    02138   {
    02139     const Company *c = Company::Get((CompanyID)this->window_number);
    02140     switch (widget) {
    02141       case WID_C_FACE:
    02142         DrawCompanyManagerFace(c->face, c->colour, r.left, r.top);
    02143         break;
    02144
    02145       case WID_C_FACE_TITLE:
    02146         SetDParam(0, c->index);
    02147         DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE, TC_FROMSTRING, SA_HOR_CENTER);
    02148         break;
    02149
    02150       case WID_C_DESC_COLOUR_SCHEME_EXAMPLE: {
    02151         Point offset;
    02152         Dimension d = GetSpriteSize(SPR_VEH_BUS_SW_VIEW, &offset);
    02153         d.height -= offset.y;
    02154         DrawSprite(SPR_VEH_BUS_SW_VIEW, COMPANY_SPRITE_COLOUR(c->index), r.left - offset.x, (r.top + r.bottom - d.height) / 2 - offset.y);
    02155         break;
    02156       }
    02157
    02158       case WID_C_DESC_VEHICLE_COUNTS: {
    02159         uint amounts[4];
    02160         amounts[0] = c->group_all[VEH_TRAIN].num_vehicle;
    02161         amounts[1] = c->group_all[VEH_ROAD].num_vehicle;
    02162         amounts[2] = c->group_all[VEH_SHIP].num_vehicle;
    02163         amounts[3] = c->group_all[VEH_AIRCRAFT].num_vehicle;
    02164
    02165         int y = r.top;
    02166         if (amounts[0] + amounts[1] + amounts[2] + amounts[3] == 0) {
    02167           DrawString(r.left, r.right, y, STR_COMPANY_VIEW_VEHICLES_NONE);
    02168         } else {
    02169           assert_compile(lengthof(amounts) == lengthof(_company_view_vehicle_count_strings));
    02170
    02171           for (uint i = 0; i < lengthof(amounts); i++) {
    02172             if (amounts[i] != 0) {
    02173               SetDParam(0, amounts[i]);
    02174               DrawString(r.left, r.right, y, _company_view_vehicle_count_strings[i]);
    02175               y += FONT_HEIGHT_NORMAL;
    02176             }
    02177           }
    02178         }
    02179         break;
    02180       }
    02181
    02182       case WID_C_DESC_INFRASTRUCTURE_COUNTS: {
    02183         uint y = r.top;
    02184
    02185         /* Collect rail and road counts. */
    02186         uint rail_pices = c->infrastructure.signal;
    02187         uint road_pieces = 0;
    02188         for (uint i = 0; i < lengthof(c->infrastructure.rail); i++) rail_pices += c->infrastructure.rail[i];
    02189         for (uint i = 0; i < lengthof(c->infrastructure.road); i++) road_pieces += c->infrastructure.road[i];
    02190
    02191         if (rail_pices == 0 && road_pieces == 0 && c->infrastructure.water == 0 && c->infrastructure.station == 0 && c->infrastructure.airport == 0) {
    02192           DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE);
    02193         } else {
    02194           if (rail_pices != 0) {
    02195             SetDParam(0, rail_pices);
    02196             DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL);
    02197             y += FONT_HEIGHT_NORMAL;
    02198           }
    02199           if (road_pieces != 0) {
    02200             SetDParam(0, road_pieces);
    02201             DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD);
    02202             y += FONT_HEIGHT_NORMAL;
    02203           }
    02204           if (c->infrastructure.water != 0) {
    02205             SetDParam(0, c->infrastructure.water);
    02206             DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_WATER);
    02207             y += FONT_HEIGHT_NORMAL;
    02208           }
    02209           if (c->infrastructure.station != 0) {
    02210             SetDParam(0, c->infrastructure.station);
    02211             DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_STATION);
    02212             y += FONT_HEIGHT_NORMAL;
    02213           }
    02214           if (c->infrastructure.airport != 0) {
    02215             SetDParam(0, c->infrastructure.airport);
    02216             DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT);
    02217           }
    02218         }
    02219
    02220         break;
    02221       }
    02222
    02223       case WID_C_DESC_OWNERS: {
    02224         const Company *c2;
    02225         uint y = r.top;
    02226
    02227         FOR_ALL_COMPANIES(c2) {
    02228           uint amt = GetAmountOwnedBy(c, c2->index);
    02229           if (amt != 0) {
    02230             SetDParam(0, amt * 25);
    02231             SetDParam(1, c2->index);
    02232
    02233             DrawString(r.left, r.right, y, STR_COMPANY_VIEW_SHARES_OWNED_BY);
    02234             y += FONT_HEIGHT_NORMAL;
    02235           }
    02236         }
    02237         break;
    02238       }
    02239
    02240 #ifdef ENABLE_NETWORK
    02241       case WID_C_HAS_PASSWORD:
    02242         if (_networking && NetworkCompanyIsPassworded(c->index)) {
    02243           DrawSprite(SPR_LOCK, PAL_NONE, r.left, r.top);
    02244         }
    02245         break;
    02246 #endif /* ENABLE_NETWORK */
    02247     }
    02248   }
    02249
    02250   virtual void SetStringParameters(int widget) const
    02251   {
    02252     switch (widget) {
    02253       case WID_C_CAPTION:
    02254         SetDParam(0, (CompanyID)this->window_number);
    02255         SetDParam(1, (CompanyID)this->window_number);
    02256         break;
    02257
    02258       case WID_C_DESC_INAUGURATION:
    02259         SetDParam(0, Company::Get((CompanyID)this->window_number)->inaugurated_year);
    02260         break;
    02261
    02262       case WID_C_DESC_COMPANY_VALUE:
    02263         SetDParam(0, CalculateCompanyValue(Company::Get((CompanyID)this->window_number)));
    02264         break;
    02265     }
    02266   }
    02267
    02268   virtual void OnClick(Point pt, int widget, int click_count)
    02269   {
    02270     switch (widget) {
    02271       case WID_C_NEW_FACE: DoSelectCompanyManagerFace(this); break;
    02272
    02273       case WID_C_COLOUR_SCHEME:
    02274         if (BringWindowToFrontById(WC_COMPANY_COLOUR, this->window_number)) break;
    02275         new SelectCompanyLiveryWindow(&_select_company_livery_desc, (CompanyID)this->window_number);
    02276         break;
    02277
    02278       case WID_C_PRESIDENT_NAME:
    02279         this->query_widget = WID_C_PRESIDENT_NAME;
    02280         SetDParam(0, this->window_number);
    02281         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);
    02282         break;
    02283
    02284       case WID_C_COMPANY_NAME:
    02285         this->query_widget = WID_C_COMPANY_NAME;
    02286         SetDParam(0, this->window_number);
    02287         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);
    02288         break;
    02289
    02290       case WID_C_VIEW_HQ: {
    02291         TileIndex tile = Company::Get((CompanyID)this->window_number)->location_of_HQ;
    02292         if (_ctrl_pressed) {
    02293           ShowExtraViewPortWindow(tile);
    02294         } else {
    02295           ScrollMainWindowToTile(tile);
    02296         }
    02297         break;
    02298       }
    02299
    02300       case WID_C_BUILD_HQ:
    02301         if ((byte)this->window_number != _local_company) return;
    02302         if (this->IsWidgetLowered(WID_C_BUILD_HQ)) {
    02303           ResetObjectToPlace();
    02304           this->RaiseButtons();
    02305           break;
    02306         }
    02307         SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, HT_RECT, this);
    02308         SetTileSelectSize(2, 2);
    02309         this->LowerWidget(WID_C_BUILD_HQ);
    02310         this->SetWidgetDirty(WID_C_BUILD_HQ);
    02311         break;
    02312
    02313       case WID_C_RELOCATE_HQ:
    02314         if (this->IsWidgetLowered(WID_C_RELOCATE_HQ)) {
    02315           ResetObjectToPlace();
    02316           this->RaiseButtons();
    02317           break;
    02318         }
    02319         SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, HT_RECT, this);
    02320         SetTileSelectSize(2, 2);
    02321         this->LowerWidget(WID_C_RELOCATE_HQ);
    02322         this->SetWidgetDirty(WID_C_RELOCATE_HQ);
    02323         break;
    02324
    02325       case WID_C_VIEW_INFRASTRUCTURE:
    02326         ShowCompanyInfrastructure((CompanyID)this->window_number);
    02327         break;
    02328
    02329       case WID_C_BUY_SHARE:
    02330         DoCommandP(0, this->window_number, 0, CMD_BUY_SHARE_IN_COMPANY | CMD_MSG(STR_ERROR_CAN_T_BUY_25_SHARE_IN_THIS));
    02331         break;
    02332
    02333       case WID_C_SELL_SHARE:
    02334         DoCommandP(0, this->window_number, 0, CMD_SELL_SHARE_IN_COMPANY | CMD_MSG(STR_ERROR_CAN_T_SELL_25_SHARE_IN));
    02335         break;
    02336
    02337 #ifdef ENABLE_NETWORK
    02338       case WID_C_COMPANY_PASSWORD:
    02339         if (this->window_number == _local_company) ShowNetworkCompanyPasswordWindow(this);
    02340         break;
    02341
    02342       case WID_C_COMPANY_JOIN: {
    02343         this->query_widget = WID_C_COMPANY_JOIN;
    02344         CompanyID company = (CompanyID)this->window_number;
    02345         if (_network_server) {
    02346           NetworkServerDoMove(CLIENT_ID_SERVER, company);
    02347           MarkWholeScreenDirty();
    02348         } else if (NetworkCompanyIsPassworded(company)) {
    02349           /* ask for the password */
    02350           ShowQueryString(STR_EMPTY, STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION, NETWORK_PASSWORD_LENGTH, this, CS_ALPHANUMERAL, QSF_NONE);
    02351         } else {
    02352           /* just send the join command */
    02353           NetworkClientRequestMove(company);
    02354         }
    02355         break;
    02356       }
    02357 #endif /* ENABLE_NETWORK */
    02358     }
    02359   }
    02360
    02361   virtual void OnHundredthTick()
    02362   {
    02363     /* redraw the window every now and then */
    02364     this->SetDirty();
    02365   }
    02366
    02367   virtual void OnPlaceObject(Point pt, TileIndex tile)
    02368   {
    02369     if (DoCommandP(tile, OBJECT_HQ, 0, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS))) {
    02370       ResetObjectToPlace();
    02371       this->RaiseButtons();
    02372     }
    02373   }
    02374
    02375   virtual void OnPlaceObjectAbort()
    02376   {
    02377     this->RaiseButtons();
    02378   }
    02379
    02380   virtual void OnQueryTextFinished(char *str)
    02381   {
    02382     if (str == NULL) return;
    02383
    02384     switch (this->query_widget) {
    02385       default: NOT_REACHED();
    02386
    02387       case WID_C_PRESIDENT_NAME:
    02388         DoCommandP(0, 0, 0, CMD_RENAME_PRESIDENT | CMD_MSG(STR_ERROR_CAN_T_CHANGE_PRESIDENT), NULL, str);
    02389         break;
    02390
    02391       case WID_C_COMPANY_NAME:
    02392         DoCommandP(0, 0, 0, CMD_RENAME_COMPANY | CMD_MSG(STR_ERROR_CAN_T_CHANGE_COMPANY_NAME), NULL, str);
    02393         break;
    02394
    02395 #ifdef ENABLE_NETWORK
    02396       case WID_C_COMPANY_JOIN:
    02397         NetworkClientRequestMove((CompanyID)this->window_number, str);
    02398         break;
    02399 #endif /* ENABLE_NETWORK */
    02400     }
    02401   }
    02402 };
    02403
    02404 static const WindowDesc _company_desc(
    02405   WDP_AUTO, 0, 0,
    02406   WC_COMPANY, WC_NONE,
    02407   WDF_UNCLICK_BUTTONS,
    02408   _nested_company_widgets, lengthof(_nested_company_widgets)
    02409 );
    02410
    02415 void ShowCompany(CompanyID company)
    02416 {
    02417   if (!Company::IsValidID(company)) return;
    02418
    02419   AllocateWindowDescFront<CompanyWindow>(&_company_desc, company);
    02420 }
    02421
    02426 void DirtyCompanyInfrastructureWindows(CompanyID company)
    02427 {
    02428   SetWindowDirty(WC_COMPANY, company);
    02429   SetWindowDirty(WC_COMPANY_INFRASTRUCTURE, company);
    02430 }
    02431
    02432 struct BuyCompanyWindow : Window {
    02433   BuyCompanyWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
    02434   {
    02435     this->InitNested(desc, window_number);
    02436   }
    02437
    02438   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
    02439   {
    02440     switch (widget) {
    02441       case WID_BC_FACE:
    02442         *size = GetSpriteSize(SPR_GRADIENT);
    02443         break;
    02444
    02445       case WID_BC_QUESTION:
    02446         const Company *c = Company::Get((CompanyID)this->window_number);
    02447         SetDParam(0, c->index);
    02448         SetDParam(1, c->bankrupt_value);
    02449         size->height = GetStringHeight(STR_BUY_COMPANY_MESSAGE, size->width);
    02450         break;
    02451     }
    02452   }
    02453
    02454   virtual void SetStringParameters(int widget) const
    02455   {
    02456     switch (widget) {
    02457       case WID_BC_CAPTION:
    02458         SetDParam(0, STR_COMPANY_NAME);
    02459         SetDParam(1, Company::Get((CompanyID)this->window_number)->index);
    02460         break;
    02461     }
    02462   }
    02463
    02464   virtual void DrawWidget(const Rect &r, int widget) const
    02465   {
    02466     switch (widget) {
    02467       case WID_BC_FACE: {
    02468         const Company *c = Company::Get((CompanyID)this->window_number);
    02469         DrawCompanyManagerFace(c->face, c->colour, r.left, r.top);
    02470         break;
    02471       }
    02472
    02473       case WID_BC_QUESTION: {
    02474         const Company *c = Company::Get((CompanyID)this->window_number);
    02475         SetDParam(0, c->index);
    02476         SetDParam(1, c->bankrupt_value);
    02477         DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_BUY_COMPANY_MESSAGE, TC_FROMSTRING, SA_CENTER);
    02478         break;
    02479       }
    02480     }
    02481   }
    02482
    02483   virtual void OnClick(Point pt, int widget, int click_count)
    02484   {
    02485     switch (widget) {
    02486       case WID_BC_NO:
    02487         delete this;
    02488         break;
    02489
    02490       case WID_BC_YES:
    02491         DoCommandP(0, this->window_number, 0, CMD_BUY_COMPANY | CMD_MSG(STR_ERROR_CAN_T_BUY_COMPANY));
    02492         break;
    02493     }
    02494   }
    02495 };
    02496
    02497 static const NWidgetPart _nested_buy_company_widgets[] = {
    02498   NWidget(NWID_HORIZONTAL),
    02499     NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
    02500     NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE, WID_BC_CAPTION), SetDataTip(STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    02501   EndContainer(),
    02502   NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE),
    02503     NWidget(NWID_VERTICAL), SetPIP(8, 8, 8),
    02504       NWidget(NWID_HORIZONTAL), SetPIP(8, 10, 8),
    02505         NWidget(WWT_EMPTY, INVALID_COLOUR, WID_BC_FACE), SetFill(0, 1),
    02506         NWidget(WWT_EMPTY, INVALID_COLOUR, WID_BC_QUESTION), SetMinimalSize(240, 0), SetFill(1, 1),
    02507       EndContainer(),
    02508       NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(100, 10, 100),
    02509         NWidget(WWT_TEXTBTN, COLOUR_LIGHT_BLUE, WID_BC_NO), SetMinimalSize(60, 12), SetDataTip(STR_QUIT_NO, STR_NULL), SetFill(1, 0),
    02510         NWidget(WWT_TEXTBTN, COLOUR_LIGHT_BLUE, WID_BC_YES), SetMinimalSize(60, 12), SetDataTip(STR_QUIT_YES, STR_NULL), SetFill(1, 0),
    02511       EndContainer(),
    02512     EndContainer(),
    02513   EndContainer(),
    02514 };
    02515
    02516 static const WindowDesc _buy_company_desc(
    02517   WDP_AUTO, 0, 0,
    02518   WC_BUY_COMPANY, WC_NONE,
    02519   WDF_CONSTRUCTION,
    02520   _nested_buy_company_widgets, lengthof(_nested_buy_company_widgets)
    02521 );
    02522
    02527 void ShowBuyCompanyDialog(CompanyID company)
    02528 {
    02529   AllocateWindowDescFront<BuyCompanyWindow>(&_buy_company_desc, company);
    02530 }