# 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         SetDParamMaxValue(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   0,
    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       /* Changed colour for the selected scheme, or all visible schemes if CTRL is pressed. */
    00785       if (HasBit(this->sel, scheme) || (_ctrl_pressed && _livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme))) {
    00786         DoCommandP(0, scheme | (widget == WID_SCL_PRI_COL_DROPDOWN ? 0 : 256), index, CMD_SET_COMPANY_COLOUR);
    00787       }
    00788     }
    00789   }
    00790
    00796   virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
    00797   {
    00798     if (!gui_scope) return;
    00799     this->SetWidgetsDisabledState(true, WID_SCL_CLASS_RAIL, WID_SCL_CLASS_ROAD, WID_SCL_CLASS_SHIP, WID_SCL_CLASS_AIRCRAFT, WIDGET_LIST_END);
    00800
    00801     bool current_class_valid = this->livery_class == LC_OTHER;
    00802     if (_settings_client.gui.liveries == LIT_ALL || (_settings_client.gui.liveries == LIT_COMPANY && this->window_number == _local_company)) {
    00803       for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
    00804         if (HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
    00805           if (_livery_class[scheme] == this->livery_class) current_class_valid = true;
    00806           this->EnableWidget(WID_SCL_CLASS_GENERAL + _livery_class[scheme]);
    00807         } else {
    00808           ClrBit(this->sel, scheme);
    00809         }
    00810       }
    00811     }
    00812
    00813     if (!current_class_valid) {
    00814       Point pt = {0, 0};
    00815       this->OnClick(pt, WID_SCL_CLASS_GENERAL, 1);
    00816     } else if (data == 0) {
    00817       this->ReInit();
    00818     }
    00819   }
    00820 };
    00821
    00822 static const NWidgetPart _nested_select_company_livery_widgets [] = {
    00823   NWidget(NWID_HORIZONTAL),
    00824     NWidget(WWT_CLOSEBOX, COLOUR_GREY),
    00825     NWidget(WWT_CAPTION, COLOUR_GREY, WID_SCL_CAPTION), SetDataTip(STR_LIVERY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    00826   EndContainer(),
    00827   NWidget(NWID_HORIZONTAL),
    00828     NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_GENERAL), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_COMPANY_GENERAL, STR_LIVERY_GENERAL_TOOLTIP),
    00829     NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_RAIL), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_TRAINLIST, STR_LIVERY_TRAIN_TOOLTIP),
    00830     NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_ROAD), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_TRUCKLIST, STR_LIVERY_ROAD_VEHICLE_TOOLTIP),
    00831     NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_SHIP), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_SHIPLIST, STR_LIVERY_SHIP_TOOLTIP),
    00832     NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCL_CLASS_AIRCRAFT), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_AIRPLANESLIST, STR_LIVERY_AIRCRAFT_TOOLTIP),
    00833     NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(90, 22), SetFill(1, 1), EndContainer(),
    00834   EndContainer(),
    00835   NWidget(NWID_HORIZONTAL),
    00836     NWidget(WWT_PANEL, COLOUR_GREY, WID_SCL_SPACER_DROPDOWN), SetMinimalSize(150, 12), SetFill(1, 1), EndContainer(),
    00837     NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SCL_PRI_COL_DROPDOWN), SetMinimalSize(125, 12), SetFill(0, 1), SetDataTip(STR_BLACK_STRING, STR_LIVERY_PRIMARY_TOOLTIP),
    00838     NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_SCL_SEC_COL_DROPDOWN), SetMinimalSize(125, 12), SetFill(0, 1),
    00839         SetDataTip(STR_BLACK_STRING, STR_LIVERY_SECONDARY_TOOLTIP),
    00840   EndContainer(),
    00841   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),
    00842 };
    00843
    00844 static const WindowDesc _select_company_livery_desc(
    00845   WDP_AUTO, 0, 0,
    00846   WC_COMPANY_COLOUR, WC_NONE,
    00847   0,
    00848   _nested_select_company_livery_widgets, lengthof(_nested_select_company_livery_widgets)
    00849 );
    00850
    00858 void DrawCompanyManagerFace(CompanyManagerFace cmf, int colour, int x, int y)
    00859 {
    00860   GenderEthnicity ge = (GenderEthnicity)GetCompanyManagerFaceBits(cmf, CMFV_GEN_ETHN, GE_WM);
    00861
    00862   bool has_moustache   = !HasBit(ge, GENDER_FEMALE) && GetCompanyManagerFaceBits(cmf, CMFV_HAS_MOUSTACHE,   ge) != 0;
    00863   bool has_tie_earring = !HasBit(ge, GENDER_FEMALE) || GetCompanyManagerFaceBits(cmf, CMFV_HAS_TIE_EARRING, ge) != 0;
    00864   bool has_glasses     = GetCompanyManagerFaceBits(cmf, CMFV_HAS_GLASSES, ge) != 0;
    00865   PaletteID pal;
    00866
    00867   /* Modify eye colour palette only if 2 or more valid values exist */
    00868   if (_cmf_info[CMFV_EYE_COLOUR].valid_values[ge] < 2) {
    00869     pal = PAL_NONE;
    00870   } else {
    00871     switch (GetCompanyManagerFaceBits(cmf, CMFV_EYE_COLOUR, ge)) {
    00872       default: NOT_REACHED();
    00873       case 0: pal = PALETTE_TO_BROWN; break;
    00874       case 1: pal = PALETTE_TO_BLUE;  break;
    00875       case 2: pal = PALETTE_TO_GREEN; break;
    00876     }
    00877   }
    00878
    00879   /* Draw the gradient (background) */
    00880   DrawSprite(SPR_GRADIENT, GENERAL_SPRITE_COLOUR(colour), x, y);
    00881
    00882   for (CompanyManagerFaceVariable cmfv = CMFV_CHEEKS; cmfv < CMFV_END; cmfv++) {
    00883     switch (cmfv) {
    00884       case CMFV_MOUSTACHE:   if (!has_moustache)   continue; break;
    00885       case CMFV_LIPS:        // FALL THROUGH
    00886       case CMFV_NOSE:        if (has_moustache)    continue; break;
    00887       case CMFV_TIE_EARRING: if (!has_tie_earring) continue; break;
    00888       case CMFV_GLASSES:     if (!has_glasses)     continue; break;
    00889       default: break;
    00890     }
    00891     DrawSprite(GetCompanyManagerFaceSprite(cmf, cmfv, ge), (cmfv == CMFV_EYEBROWS) ? pal : PAL_NONE, x, y);
    00892   }
    00893 }
    00894
    00896 static const NWidgetPart _nested_select_company_manager_face_widgets[] = {
    00897   NWidget(NWID_HORIZONTAL),
    00898     NWidget(WWT_CLOSEBOX, COLOUR_GREY),
    00899     NWidget(WWT_CAPTION, COLOUR_GREY, WID_SCMF_CAPTION), SetDataTip(STR_FACE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    00900     NWidget(WWT_IMGBTN, COLOUR_GREY, WID_SCMF_TOGGLE_LARGE_SMALL), SetDataTip(SPR_LARGE_SMALL_WINDOW, STR_FACE_ADVANCED_TOOLTIP),
    00901   EndContainer(),
    00902   NWidget(WWT_PANEL, COLOUR_GREY, WID_SCMF_SELECT_FACE),
    00903     NWidget(NWID_SPACER), SetMinimalSize(0, 2),
    00904     NWidget(NWID_HORIZONTAL), SetPIP(2, 2, 2),
    00905       NWidget(NWID_VERTICAL),
    00906         NWidget(NWID_HORIZONTAL),
    00907           NWidget(NWID_SPACER), SetFill(1, 0),
    00908           NWidget(WWT_EMPTY, COLOUR_GREY, WID_SCMF_FACE), SetMinimalSize(92, 119),
    00909           NWidget(NWID_SPACER), SetFill(1, 0),
    00910         EndContainer(),
    00911         NWidget(NWID_SPACER), SetMinimalSize(0, 2),
    00912         NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_RANDOM_NEW_FACE), SetFill(1, 0), SetDataTip(STR_FACE_NEW_FACE_BUTTON, STR_FACE_NEW_FACE_TOOLTIP),
    00913         NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SCMF_SEL_LOADSAVE), // Load/number/save buttons under the portrait in the advanced view.
    00914           NWidget(NWID_VERTICAL),
    00915             NWidget(NWID_SPACER), SetMinimalSize(0, 5), SetFill(0, 1),
    00916             NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_LOAD), SetFill(1, 0), SetDataTip(STR_FACE_LOAD, STR_FACE_LOAD_TOOLTIP),
    00917             NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_FACECODE), SetFill(1, 0), SetDataTip(STR_FACE_FACECODE, STR_FACE_FACECODE_TOOLTIP),
    00918             NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_SAVE), SetFill(1, 0), SetDataTip(STR_FACE_SAVE, STR_FACE_SAVE_TOOLTIP),
    00919             NWidget(NWID_SPACER), SetMinimalSize(0, 5), SetFill(0, 1),
    00920           EndContainer(),
    00921         EndContainer(),
    00922       EndContainer(),
    00923       NWidget(NWID_VERTICAL),
    00924         NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON), SetFill(1, 0), SetDataTip(STR_FACE_ADVANCED, STR_FACE_ADVANCED_TOOLTIP),
    00925         NWidget(NWID_SPACER), SetMinimalSize(0, 2),
    00926         NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SCMF_SEL_MALEFEMALE), // Simple male/female face setting.
    00927           NWidget(NWID_VERTICAL),
    00928             NWidget(NWID_SPACER), SetFill(0, 1),
    00929             NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_MALE), SetFill(1, 0), SetDataTip(STR_FACE_MALE_BUTTON, STR_FACE_MALE_TOOLTIP),
    00930             NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_FEMALE), SetFill(1, 0), SetDataTip(STR_FACE_FEMALE_BUTTON, STR_FACE_FEMALE_TOOLTIP),
    00931             NWidget(NWID_SPACER), SetFill(0, 1),
    00932           EndContainer(),
    00933         EndContainer(),
    00934         NWidget(NWID_SELECTION, INVALID_COLOUR, WID_SCMF_SEL_PARTS), // Advanced face parts setting.
    00935           NWidget(NWID_VERTICAL),
    00936             NWidget(NWID_SPACER), SetMinimalSize(0, 2),
    00937             NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
    00938               NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_MALE2), SetFill(1, 0), SetDataTip(STR_FACE_MALE_BUTTON, STR_FACE_MALE_TOOLTIP),
    00939               NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_FEMALE2), SetFill(1, 0), SetDataTip(STR_FACE_FEMALE_BUTTON, STR_FACE_FEMALE_TOOLTIP),
    00940             EndContainer(),
    00941             NWidget(NWID_SPACER), SetMinimalSize(0, 2),
    00942             NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
    00943               NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_ETHNICITY_EUR), SetFill(1, 0), SetDataTip(STR_FACE_EUROPEAN, STR_FACE_SELECT_EUROPEAN),
    00944               NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_SCMF_ETHNICITY_AFR), SetFill(1, 0), SetDataTip(STR_FACE_AFRICAN, STR_FACE_SELECT_AFRICAN),
    00945             EndContainer(),
    00946             NWidget(NWID_SPACER), SetMinimalSize(0, 4),
    00947             NWidget(NWID_HORIZONTAL),
    00948               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT), SetFill(1, 0),
    00949               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_MOUSTACHE_EARRING), SetDataTip(STR_EMPTY, STR_FACE_MOUSTACHE_EARRING_TOOLTIP),
    00950             EndContainer(),
    00951             NWidget(NWID_HORIZONTAL),
    00952               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_HAS_GLASSES_TEXT), SetFill(1, 0),
    00953               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAS_GLASSES), SetDataTip(STR_EMPTY, STR_FACE_GLASSES_TOOLTIP),
    00954             EndContainer(),
    00955             NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetFill(1, 0),
    00956             NWidget(NWID_HORIZONTAL),
    00957               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_HAIR_TEXT), SetFill(1, 0),
    00958               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_HAIR_L), SetDataTip(AWV_DECREASE, STR_FACE_HAIR_TOOLTIP),
    00959               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_HAIR), SetDataTip(STR_EMPTY, STR_FACE_HAIR_TOOLTIP),
    00960               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_HAIR_R), SetDataTip(AWV_INCREASE, STR_FACE_HAIR_TOOLTIP),
    00961             EndContainer(),
    00962             NWidget(NWID_HORIZONTAL),
    00963               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_EYEBROWS_TEXT), SetFill(1, 0),
    00964               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYEBROWS_L), SetDataTip(AWV_DECREASE, STR_FACE_EYEBROWS_TOOLTIP),
    00965               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYEBROWS), SetDataTip(STR_EMPTY, STR_FACE_EYEBROWS_TOOLTIP),
    00966               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYEBROWS_R), SetDataTip(AWV_INCREASE, STR_FACE_EYEBROWS_TOOLTIP),
    00967             EndContainer(),
    00968             NWidget(NWID_HORIZONTAL),
    00969               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_EYECOLOUR_TEXT), SetFill(1, 0),
    00970               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR_L), SetDataTip(AWV_DECREASE, STR_FACE_EYECOLOUR_TOOLTIP),
    00971               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR), SetDataTip(STR_EMPTY, STR_FACE_EYECOLOUR_TOOLTIP),
    00972               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_EYECOLOUR_R), SetDataTip(AWV_INCREASE, STR_FACE_EYECOLOUR_TOOLTIP),
    00973             EndContainer(),
    00974             NWidget(NWID_HORIZONTAL),
    00975               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_GLASSES_TEXT), SetFill(1, 0),
    00976               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_GLASSES_L), SetDataTip(AWV_DECREASE, STR_FACE_GLASSES_TOOLTIP_2),
    00977               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_GLASSES), SetDataTip(STR_EMPTY, STR_FACE_GLASSES_TOOLTIP_2),
    00978               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_GLASSES_R), SetDataTip(AWV_INCREASE, STR_FACE_GLASSES_TOOLTIP_2),
    00979             EndContainer(),
    00980             NWidget(NWID_HORIZONTAL),
    00981               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_NOSE_TEXT), SetFill(1, 0),
    00982               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_NOSE_L), SetDataTip(AWV_DECREASE, STR_FACE_NOSE_TOOLTIP),
    00983               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_NOSE), SetDataTip(STR_EMPTY, STR_FACE_NOSE_TOOLTIP),
    00984               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_NOSE_R), SetDataTip(AWV_INCREASE, STR_FACE_NOSE_TOOLTIP),
    00985             EndContainer(),
    00986             NWidget(NWID_HORIZONTAL),
    00987               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_LIPS_MOUSTACHE_TEXT), SetFill(1, 0),
    00988               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE_L), SetDataTip(AWV_DECREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP),
    00989               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE), SetDataTip(STR_EMPTY, STR_FACE_LIPS_MOUSTACHE_TOOLTIP),
    00990               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_LIPS_MOUSTACHE_R), SetDataTip(AWV_INCREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP),
    00991             EndContainer(),
    00992             NWidget(NWID_HORIZONTAL),
    00993               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_CHIN_TEXT), SetFill(1, 0),
    00994               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_CHIN_L), SetDataTip(AWV_DECREASE, STR_FACE_CHIN_TOOLTIP),
    00995               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_CHIN), SetDataTip(STR_EMPTY, STR_FACE_CHIN_TOOLTIP),
    00996               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_CHIN_R), SetDataTip(AWV_INCREASE, STR_FACE_CHIN_TOOLTIP),
    00997             EndContainer(),
    00998             NWidget(NWID_HORIZONTAL),
    00999               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_JACKET_TEXT), SetFill(1, 0),
    01000               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_JACKET_L), SetDataTip(AWV_DECREASE, STR_FACE_JACKET_TOOLTIP),
    01001               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_JACKET), SetDataTip(STR_EMPTY, STR_FACE_JACKET_TOOLTIP),
    01002               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_JACKET_R), SetDataTip(AWV_INCREASE, STR_FACE_JACKET_TOOLTIP),
    01003             EndContainer(),
    01004             NWidget(NWID_HORIZONTAL),
    01005               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_COLLAR_TEXT), SetFill(1, 0),
    01006               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_COLLAR_L), SetDataTip(AWV_DECREASE, STR_FACE_COLLAR_TOOLTIP),
    01007               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_COLLAR), SetDataTip(STR_EMPTY, STR_FACE_COLLAR_TOOLTIP),
    01008               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_COLLAR_R), SetDataTip(AWV_INCREASE, STR_FACE_COLLAR_TOOLTIP),
    01009             EndContainer(),
    01010             NWidget(NWID_HORIZONTAL),
    01011               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SCMF_TIE_EARRING_TEXT), SetFill(1, 0),
    01012               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING_L), SetDataTip(AWV_DECREASE, STR_FACE_TIE_EARRING_TOOLTIP),
    01013               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING), SetDataTip(STR_EMPTY, STR_FACE_TIE_EARRING_TOOLTIP),
    01014               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_SCMF_TIE_EARRING_R), SetDataTip(AWV_INCREASE, STR_FACE_TIE_EARRING_TOOLTIP),
    01015             EndContainer(),
    01016             NWidget(NWID_SPACER), SetFill(0, 1),
    01017           EndContainer(),
    01018         EndContainer(),
    01019       EndContainer(),
    01020     EndContainer(),
    01021     NWidget(NWID_SPACER), SetMinimalSize(0, 2),
    01022   EndContainer(),
    01023   NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
    01024     NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_CANCEL), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_FACE_CANCEL_TOOLTIP),
    01025     NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_SCMF_ACCEPT), SetFill(1, 0), SetDataTip(STR_BUTTON_OK, STR_FACE_OK_TOOLTIP),
    01026   EndContainer(),
    01027 };
    01028
    01030 class SelectCompanyManagerFaceWindow : public Window
    01031 {
    01032   CompanyManagerFace face;
    01033   bool advanced;
    01034
    01035   GenderEthnicity ge;
    01036   bool is_female;
    01037   bool is_moust_male;
    01038
    01039   Dimension yesno_dim;
    01040   Dimension number_dim;
    01041
    01042   static const StringID PART_TEXTS_IS_FEMALE[];
    01043   static const StringID PART_TEXTS[];
    01044
    01052   void DrawFaceStringLabel(byte widget_index, uint8 val, bool is_bool_widget) const
    01053   {
    01054     StringID str;
    01055     const NWidgetCore *nwi_widget = this->GetWidget<NWidgetCore>(widget_index);
    01056     if (!nwi_widget->IsDisabled()) {
    01057       if (is_bool_widget) {
    01058         /* if it a bool button write yes or no */
    01059         str = (val != 0) ? STR_FACE_YES : STR_FACE_NO;
    01060       } else {
    01061         /* else write the value + 1 */
    01062         SetDParam(0, val + 1);
    01063         str = STR_JUST_INT;
    01064       }
    01065
    01066       /* Draw the value/bool in white (0xC). If the button clicked adds 1px to x and y text coordinates (IsWindowWidgetLowered()). */
    01067       DrawString(nwi_widget->pos_x + nwi_widget->IsLowered(), nwi_widget->pos_x + nwi_widget->current_x - 1 - nwi_widget->IsLowered(),
    01068           nwi_widget->pos_y + 1 + nwi_widget->IsLowered(), str, TC_WHITE, SA_HOR_CENTER);
    01069     }
    01070   }
    01071
    01072   void UpdateData()
    01073   {
    01074     this->ge = (GenderEthnicity)GB(this->face, _cmf_info[CMFV_GEN_ETHN].offset, _cmf_info[CMFV_GEN_ETHN].length); // get the gender and ethnicity
    01075     this->is_female = HasBit(this->ge, GENDER_FEMALE); // get the gender: 0 == male and 1 == female
    01076     this->is_moust_male = !is_female && GetCompanyManagerFaceBits(this->face, CMFV_HAS_MOUSTACHE, this->ge) != 0; // is a male face with moustache
    01077   }
    01078
    01079 public:
    01080   SelectCompanyManagerFaceWindow(const WindowDesc *desc, Window *parent) : Window()
    01081   {
    01082     this->advanced = false;
    01083     this->CreateNestedTree(desc);
    01084     this->SelectDisplayPlanes(this->advanced);
    01085     this->FinishInitNested(desc, parent->window_number);
    01086     this->parent = parent;
    01087     this->owner = (Owner)this->window_number;
    01088     this->face = Company::Get((CompanyID)this->window_number)->face;
    01089
    01090     this->UpdateData();
    01091   }
    01092
    01097   void SelectDisplayPlanes(bool advanced)
    01098   {
    01099     this->GetWidget<NWidgetStacked>(WID_SCMF_SEL_LOADSAVE)->SetDisplayedPlane(advanced ? 0 : SZSP_NONE);
    01100     this->GetWidget<NWidgetStacked>(WID_SCMF_SEL_PARTS)->SetDisplayedPlane(advanced ? 0 : SZSP_NONE);
    01101     this->GetWidget<NWidgetStacked>(WID_SCMF_SEL_MALEFEMALE)->SetDisplayedPlane(advanced ? SZSP_NONE : 0);
    01102     this->GetWidget<NWidgetCore>(WID_SCMF_RANDOM_NEW_FACE)->widget_data = advanced ? STR_MAPGEN_RANDOM : STR_FACE_NEW_FACE_BUTTON;
    01103
    01104     NWidgetCore *wi = this->GetWidget<NWidgetCore>(WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON);
    01105     if (advanced) {
    01106       wi->SetDataTip(STR_FACE_SIMPLE, STR_FACE_SIMPLE_TOOLTIP);
    01107     } else {
    01108       wi->SetDataTip(STR_FACE_ADVANCED, STR_FACE_ADVANCED_TOOLTIP);
    01109     }
    01110   }
    01111
    01112   virtual void OnInit()
    01113   {
    01114     /* Size of the boolean yes/no button. */
    01115     Dimension yesno_dim = maxdim(GetStringBoundingBox(STR_FACE_YES), GetStringBoundingBox(STR_FACE_NO));
    01116     yesno_dim.width  += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
    01117     yesno_dim.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
    01118     /* Size of the number button + arrows. */
    01119     Dimension number_dim = {0, 0};
    01120     for (int val = 1; val <= 12; val++) {
    01121       SetDParam(0, val);
    01122       number_dim = maxdim(number_dim, GetStringBoundingBox(STR_JUST_INT));
    01123     }
    01124     uint arrows_width = GetSpriteSize(SPR_ARROW_LEFT).width + GetSpriteSize(SPR_ARROW_RIGHT).width + 2 * (WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT);
    01125     number_dim.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT + arrows_width;
    01126     number_dim.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
    01127     /* Compute width of both buttons. */
    01128     yesno_dim.width = max(yesno_dim.width, number_dim.width);
    01129     number_dim.width = yesno_dim.width - arrows_width;
    01130
    01131     this->yesno_dim = yesno_dim;
    01132     this->number_dim = number_dim;
    01133   }
    01134
    01135   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
    01136   {
    01137     switch (widget) {
    01138       case WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT:
    01139       case WID_SCMF_TIE_EARRING_TEXT: {
    01140         int offset = (widget - WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT) * 2;
    01141         *size = maxdim(GetStringBoundingBox(PART_TEXTS_IS_FEMALE[offset]), GetStringBoundingBox(PART_TEXTS_IS_FEMALE[offset + 1]));
    01142         size->width  += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
    01143         size->height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
    01144         break;
    01145       }
    01146
    01147       case WID_SCMF_LIPS_MOUSTACHE_TEXT:
    01148         *size = maxdim(GetStringBoundingBox(STR_FACE_LIPS), GetStringBoundingBox(STR_FACE_MOUSTACHE));
    01149         size->width  += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
    01150         size->height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
    01151         break;
    01152
    01153       case WID_SCMF_HAS_GLASSES_TEXT:
    01154       case WID_SCMF_HAIR_TEXT:
    01155       case WID_SCMF_EYEBROWS_TEXT:
    01156       case WID_SCMF_EYECOLOUR_TEXT:
    01157       case WID_SCMF_GLASSES_TEXT:
    01158       case WID_SCMF_NOSE_TEXT:
    01159       case WID_SCMF_CHIN_TEXT:
    01160       case WID_SCMF_JACKET_TEXT:
    01161       case WID_SCMF_COLLAR_TEXT:
    01162         *size = GetStringBoundingBox(PART_TEXTS[widget - WID_SCMF_HAS_GLASSES_TEXT]);
    01163         size->width  += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
    01164         size->height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
    01165         break;
    01166
    01167       case WID_SCMF_HAS_MOUSTACHE_EARRING:
    01168       case WID_SCMF_HAS_GLASSES:
    01169         *size = this->yesno_dim;
    01170         break;
    01171
    01172       case WID_SCMF_EYECOLOUR:
    01173       case WID_SCMF_CHIN:
    01174       case WID_SCMF_EYEBROWS:
    01175       case WID_SCMF_LIPS_MOUSTACHE:
    01176       case WID_SCMF_NOSE:
    01177       case WID_SCMF_HAIR:
    01178       case WID_SCMF_JACKET:
    01179       case WID_SCMF_COLLAR:
    01180       case WID_SCMF_TIE_EARRING:
    01181       case WID_SCMF_GLASSES:
    01182         *size = this->number_dim;
    01183         break;
    01184     }
    01185   }
    01186
    01187   virtual void OnPaint()
    01188   {
    01189     /* lower the non-selected gender button */
    01190     this->SetWidgetsLoweredState(!this->is_female, WID_SCMF_MALE, WID_SCMF_MALE2, WIDGET_LIST_END);
    01191     this->SetWidgetsLoweredState( this->is_female, WID_SCMF_FEMALE, WID_SCMF_FEMALE2, WIDGET_LIST_END);
    01192
    01193     /* advanced company manager face selection window */
    01194
    01195     /* lower the non-selected ethnicity button */
    01196     this->SetWidgetLoweredState(WID_SCMF_ETHNICITY_EUR, !HasBit(this->ge, ETHNICITY_BLACK));
    01197     this->SetWidgetLoweredState(WID_SCMF_ETHNICITY_AFR,  HasBit(this->ge, ETHNICITY_BLACK));
    01198
    01199
    01200     /* Disable dynamically the widgets which CompanyManagerFaceVariable has less than 2 options
    01201      * (or in other words you haven't any choice).
    01202      * If the widgets depend on a HAS-variable and this is false the widgets will be disabled, too. */
    01203
    01204     /* Eye colour buttons */
    01205     this->SetWidgetsDisabledState(_cmf_info[CMFV_EYE_COLOUR].valid_values[this->ge] < 2,
    01206         WID_SCMF_EYECOLOUR, WID_SCMF_EYECOLOUR_L, WID_SCMF_EYECOLOUR_R, WIDGET_LIST_END);
    01207
    01208     /* Chin buttons */
    01209     this->SetWidgetsDisabledState(_cmf_info[CMFV_CHIN].valid_values[this->ge] < 2,
    01210         WID_SCMF_CHIN, WID_SCMF_CHIN_L, WID_SCMF_CHIN_R, WIDGET_LIST_END);
    01211
    01212     /* Eyebrows buttons */
    01213     this->SetWidgetsDisabledState(_cmf_info[CMFV_EYEBROWS].valid_values[this->ge] < 2,
    01214         WID_SCMF_EYEBROWS, WID_SCMF_EYEBROWS_L, WID_SCMF_EYEBROWS_R, WIDGET_LIST_END);
    01215
    01216     /* Lips or (if it a male face with a moustache) moustache buttons */
    01217     this->SetWidgetsDisabledState(_cmf_info[this->is_moust_male ? CMFV_MOUSTACHE : CMFV_LIPS].valid_values[this->ge] < 2,
    01218         WID_SCMF_LIPS_MOUSTACHE, WID_SCMF_LIPS_MOUSTACHE_L, WID_SCMF_LIPS_MOUSTACHE_R, WIDGET_LIST_END);
    01219
    01220     /* Nose buttons | male faces with moustache haven't any nose options */
    01221     this->SetWidgetsDisabledState(_cmf_info[CMFV_NOSE].valid_values[this->ge] < 2 || this->is_moust_male,
    01222         WID_SCMF_NOSE, WID_SCMF_NOSE_L, WID_SCMF_NOSE_R, WIDGET_LIST_END);
    01223
    01224     /* Hair buttons */
    01225     this->SetWidgetsDisabledState(_cmf_info[CMFV_HAIR].valid_values[this->ge] < 2,
    01226         WID_SCMF_HAIR, WID_SCMF_HAIR_L, WID_SCMF_HAIR_R, WIDGET_LIST_END);
    01227
    01228     /* Jacket buttons */
    01229     this->SetWidgetsDisabledState(_cmf_info[CMFV_JACKET].valid_values[this->ge] < 2,
    01230         WID_SCMF_JACKET, WID_SCMF_JACKET_L, WID_SCMF_JACKET_R, WIDGET_LIST_END);
    01231
    01232     /* Collar buttons */
    01233     this->SetWidgetsDisabledState(_cmf_info[CMFV_COLLAR].valid_values[this->ge] < 2,
    01234         WID_SCMF_COLLAR, WID_SCMF_COLLAR_L, WID_SCMF_COLLAR_R, WIDGET_LIST_END);
    01235
    01236     /* Tie/earring buttons | female faces without earring haven't any earring options */
    01237     this->SetWidgetsDisabledState(_cmf_info[CMFV_TIE_EARRING].valid_values[this->ge] < 2 ||
    01238           (this->is_female && GetCompanyManagerFaceBits(this->face, CMFV_HAS_TIE_EARRING, this->ge) == 0),
    01239         WID_SCMF_TIE_EARRING, WID_SCMF_TIE_EARRING_L, WID_SCMF_TIE_EARRING_R, WIDGET_LIST_END);
    01240
    01241     /* Glasses buttons | faces without glasses haven't any glasses options */
    01242     this->SetWidgetsDisabledState(_cmf_info[CMFV_GLASSES].valid_values[this->ge] < 2 || GetCompanyManagerFaceBits(this->face, CMFV_HAS_GLASSES, this->ge) == 0,
    01243         WID_SCMF_GLASSES, WID_SCMF_GLASSES_L, WID_SCMF_GLASSES_R, WIDGET_LIST_END);
    01244
    01245     this->DrawWidgets();
    01246   }
    01247
    01248   virtual void DrawWidget(const Rect &r, int widget) const
    01249   {
    01250     switch (widget) {
    01251       case WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT:
    01252       case WID_SCMF_TIE_EARRING_TEXT: {
    01253         StringID str = PART_TEXTS_IS_FEMALE[(widget - WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT) * 2 + this->is_female];
    01254         DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, str, TC_GOLD, SA_RIGHT);
    01255         break;
    01256       }
    01257
    01258       case WID_SCMF_LIPS_MOUSTACHE_TEXT:
    01259         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);
    01260         break;
    01261
    01262       case WID_SCMF_HAS_GLASSES_TEXT:
    01263       case WID_SCMF_HAIR_TEXT:
    01264       case WID_SCMF_EYEBROWS_TEXT:
    01265       case WID_SCMF_EYECOLOUR_TEXT:
    01266       case WID_SCMF_GLASSES_TEXT:
    01267       case WID_SCMF_NOSE_TEXT:
    01268       case WID_SCMF_CHIN_TEXT:
    01269       case WID_SCMF_JACKET_TEXT:
    01270       case WID_SCMF_COLLAR_TEXT:
    01271         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);
    01272         break;
    01273
    01274
    01275       case WID_SCMF_HAS_MOUSTACHE_EARRING:
    01276         if (this->is_female) { // Only for female faces
    01277           this->DrawFaceStringLabel(WID_SCMF_HAS_MOUSTACHE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_HAS_TIE_EARRING, this->ge), true);
    01278         } else { // Only for male faces
    01279           this->DrawFaceStringLabel(WID_SCMF_HAS_MOUSTACHE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_HAS_MOUSTACHE,   this->ge), true);
    01280         }
    01281         break;
    01282
    01283       case WID_SCMF_TIE_EARRING:
    01284         this->DrawFaceStringLabel(WID_SCMF_TIE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_TIE_EARRING, this->ge), false);
    01285         break;
    01286
    01287       case WID_SCMF_LIPS_MOUSTACHE:
    01288         if (this->is_moust_male) { // Only for male faces with moustache
    01289           this->DrawFaceStringLabel(WID_SCMF_LIPS_MOUSTACHE, GetCompanyManagerFaceBits(this->face, CMFV_MOUSTACHE, this->ge), false);
    01290         } else { // Only for female faces or male faces without moustache
    01291           this->DrawFaceStringLabel(WID_SCMF_LIPS_MOUSTACHE, GetCompanyManagerFaceBits(this->face, CMFV_LIPS,      this->ge), false);
    01292         }
    01293         break;
    01294
    01295       case WID_SCMF_HAS_GLASSES:
    01296         this->DrawFaceStringLabel(WID_SCMF_HAS_GLASSES, GetCompanyManagerFaceBits(this->face, CMFV_HAS_GLASSES, this->ge), true );
    01297         break;
    01298
    01299       case WID_SCMF_HAIR:
    01300         this->DrawFaceStringLabel(WID_SCMF_HAIR,        GetCompanyManagerFaceBits(this->face, CMFV_HAIR,        this->ge), false);
    01301         break;
    01302
    01303       case WID_SCMF_EYEBROWS:
    01304         this->DrawFaceStringLabel(WID_SCMF_EYEBROWS,    GetCompanyManagerFaceBits(this->face, CMFV_EYEBROWS,    this->ge), false);
    01305         break;
    01306
    01307       case WID_SCMF_EYECOLOUR:
    01308         this->DrawFaceStringLabel(WID_SCMF_EYECOLOUR,   GetCompanyManagerFaceBits(this->face, CMFV_EYE_COLOUR,  this->ge), false);
    01309         break;
    01310
    01311       case WID_SCMF_GLASSES:
    01312         this->DrawFaceStringLabel(WID_SCMF_GLASSES,     GetCompanyManagerFaceBits(this->face, CMFV_GLASSES,     this->ge), false);
    01313         break;
    01314
    01315       case WID_SCMF_NOSE:
    01316         this->DrawFaceStringLabel(WID_SCMF_NOSE,        GetCompanyManagerFaceBits(this->face, CMFV_NOSE,        this->ge), false);
    01317         break;
    01318
    01319       case WID_SCMF_CHIN:
    01320         this->DrawFaceStringLabel(WID_SCMF_CHIN,        GetCompanyManagerFaceBits(this->face, CMFV_CHIN,        this->ge), false);
    01321         break;
    01322
    01323       case WID_SCMF_JACKET:
    01324         this->DrawFaceStringLabel(WID_SCMF_JACKET,      GetCompanyManagerFaceBits(this->face, CMFV_JACKET,      this->ge), false);
    01325         break;
    01326
    01327       case WID_SCMF_COLLAR:
    01328         this->DrawFaceStringLabel(WID_SCMF_COLLAR,      GetCompanyManagerFaceBits(this->face, CMFV_COLLAR,      this->ge), false);
    01329         break;
    01330
    01331       case WID_SCMF_FACE:
    01332         DrawCompanyManagerFace(this->face, Company::Get((CompanyID)this->window_number)->colour, r.left, r.top);
    01333         break;
    01334     }
    01335   }
    01336
    01337   virtual void OnClick(Point pt, int widget, int click_count)
    01338   {
    01339     switch (widget) {
    01340       /* Toggle size, advanced/simple face selection */
    01341       case WID_SCMF_TOGGLE_LARGE_SMALL:
    01342       case WID_SCMF_TOGGLE_LARGE_SMALL_BUTTON:
    01343         this->advanced = !this->advanced;
    01344         this->SelectDisplayPlanes(this->advanced);
    01345         this->ReInit();
    01346         break;
    01347
    01348       /* OK button */
    01349       case WID_SCMF_ACCEPT:
    01350         DoCommandP(0, 0, this->face, CMD_SET_COMPANY_MANAGER_FACE);
    01351         /* FALL THROUGH */
    01352
    01353       /* Cancel button */
    01354       case WID_SCMF_CANCEL:
    01355         delete this;
    01356         break;
    01357
    01358       /* Load button */
    01359       case WID_SCMF_LOAD:
    01360         this->face = _company_manager_face;
    01361         ScaleAllCompanyManagerFaceBits(this->face);
    01362         ShowErrorMessage(STR_FACE_LOAD_DONE, INVALID_STRING_ID, WL_INFO);
    01363         this->UpdateData();
    01364         this->SetDirty();
    01365         break;
    01366
    01367       /* 'Company manager face number' button, view and/or set company manager face number */
    01368       case WID_SCMF_FACECODE:
    01369         SetDParam(0, this->face);
    01370         ShowQueryString(STR_JUST_INT, STR_FACE_FACECODE_CAPTION, 10 + 1, this, CS_NUMERAL, QSF_NONE);
    01371         break;
    01372
    01373       /* Save button */
    01374       case WID_SCMF_SAVE:
    01375         _company_manager_face = this->face;
    01376         ShowErrorMessage(STR_FACE_SAVE_DONE, INVALID_STRING_ID, WL_INFO);
    01377         break;
    01378
    01379       /* Toggle gender (male/female) button */
    01380       case WID_SCMF_MALE:
    01381       case WID_SCMF_FEMALE:
    01382       case WID_SCMF_MALE2:
    01383       case WID_SCMF_FEMALE2:
    01384         SetCompanyManagerFaceBits(this->face, CMFV_GENDER, this->ge, (widget == WID_SCMF_FEMALE || widget == WID_SCMF_FEMALE2));
    01385         ScaleAllCompanyManagerFaceBits(this->face);
    01386         this->UpdateData();
    01387         this->SetDirty();
    01388         break;
    01389
    01390       /* Randomize face button */
    01391       case WID_SCMF_RANDOM_NEW_FACE:
    01392         RandomCompanyManagerFaceBits(this->face, this->ge, this->advanced);
    01393         this->UpdateData();
    01394         this->SetDirty();
    01395         break;
    01396
    01397       /* Toggle ethnicity (european/african) button */
    01398       case WID_SCMF_ETHNICITY_EUR:
    01399       case WID_SCMF_ETHNICITY_AFR:
    01400         SetCompanyManagerFaceBits(this->face, CMFV_ETHNICITY, this->ge, widget - WID_SCMF_ETHNICITY_EUR);
    01401         ScaleAllCompanyManagerFaceBits(this->face);
    01402         this->UpdateData();
    01403         this->SetDirty();
    01404         break;
    01405
    01406       default:
    01407         /* Here all buttons from WID_SCMF_HAS_MOUSTACHE_EARRING to WID_SCMF_GLASSES_R are handled.
    01408          * First it checks which CompanyManagerFaceVariable is being changed, and then either
    01409          * a: invert the value for boolean variables, or
    01410          * b: it checks inside of IncreaseCompanyManagerFaceBits() if a left (_L) butten is pressed and then decrease else increase the variable */
    01411         if (widget >= WID_SCMF_HAS_MOUSTACHE_EARRING && widget <= WID_SCMF_GLASSES_R) {
    01412           CompanyManagerFaceVariable cmfv; // which CompanyManagerFaceVariable shall be edited
    01413
    01414           if (widget < WID_SCMF_EYECOLOUR_L) { // Bool buttons
    01415             switch (widget - WID_SCMF_HAS_MOUSTACHE_EARRING) {
    01416               default: NOT_REACHED();
    01417               case 0: cmfv = this->is_female ? CMFV_HAS_TIE_EARRING : CMFV_HAS_MOUSTACHE; break; // Has earring/moustache button
    01418               case 1: cmfv = CMFV_HAS_GLASSES; break; // Has glasses button
    01419             }
    01420             SetCompanyManagerFaceBits(this->face, cmfv, this->ge, !GetCompanyManagerFaceBits(this->face, cmfv, this->ge));
    01421             ScaleAllCompanyManagerFaceBits(this->face);
    01422           } else { // Value buttons
    01423             switch ((widget - WID_SCMF_EYECOLOUR_L) / 3) {
    01424               default: NOT_REACHED();
    01425               case 0: cmfv = CMFV_EYE_COLOUR; break;  // Eye colour buttons
    01426               case 1: cmfv = CMFV_CHIN; break;        // Chin buttons
    01427               case 2: cmfv = CMFV_EYEBROWS; break;    // Eyebrows buttons
    01428               case 3: cmfv = this->is_moust_male ? CMFV_MOUSTACHE : CMFV_LIPS; break; // Moustache or lips buttons
    01429               case 4: cmfv = CMFV_NOSE; break;        // Nose buttons
    01430               case 5: cmfv = CMFV_HAIR; break;        // Hair buttons
    01431               case 6: cmfv = CMFV_JACKET; break;      // Jacket buttons
    01432               case 7: cmfv = CMFV_COLLAR; break;      // Collar buttons
    01433               case 8: cmfv = CMFV_TIE_EARRING; break; // Tie/earring buttons
    01434               case 9: cmfv = CMFV_GLASSES; break;     // Glasses buttons
    01435             }
    01436             /* 0 == left (_L), 1 == middle or 2 == right (_R) - button click */
    01437             IncreaseCompanyManagerFaceBits(this->face, cmfv, this->ge, (((widget - WID_SCMF_EYECOLOUR_L) % 3) != 0) ? 1 : -1);
    01438           }
    01439           this->UpdateData();
    01440           this->SetDirty();
    01441         }
    01442         break;
    01443     }
    01444   }
    01445
    01446   virtual void OnQueryTextFinished(char *str)
    01447   {
    01448     if (str == NULL) return;
    01449     /* Set a new company manager face number */
    01450     if (!StrEmpty(str)) {
    01451       this->face = strtoul(str, NULL, 10);
    01452       ScaleAllCompanyManagerFaceBits(this->face);
    01453       ShowErrorMessage(STR_FACE_FACECODE_SET, INVALID_STRING_ID, WL_INFO);
    01454       this->UpdateData();
    01455       this->SetDirty();
    01456     } else {
    01457       ShowErrorMessage(STR_FACE_FACECODE_ERR, INVALID_STRING_ID, WL_INFO);
    01458     }
    01459   }
    01460 };
    01461
    01463 const StringID SelectCompanyManagerFaceWindow::PART_TEXTS_IS_FEMALE[] = {
    01464   STR_FACE_MOUSTACHE, STR_FACE_EARRING, // WID_SCMF_HAS_MOUSTACHE_EARRING_TEXT
    01465   STR_FACE_TIE,       STR_FACE_EARRING, // WID_SCMF_TIE_EARRING_TEXT
    01466 };
    01467
    01469 const StringID SelectCompanyManagerFaceWindow::PART_TEXTS[] = {
    01470   STR_FACE_GLASSES,   // WID_SCMF_HAS_GLASSES_TEXT
    01471   STR_FACE_HAIR,      // WID_SCMF_HAIR_TEXT
    01472   STR_FACE_EYEBROWS,  // WID_SCMF_EYEBROWS_TEXT
    01473   STR_FACE_EYECOLOUR, // WID_SCMF_EYECOLOUR_TEXT
    01474   STR_FACE_GLASSES,   // WID_SCMF_GLASSES_TEXT
    01475   STR_FACE_NOSE,      // WID_SCMF_NOSE_TEXT
    01476   STR_FACE_CHIN,      // WID_SCMF_CHIN_TEXT
    01477   STR_FACE_JACKET,    // WID_SCMF_JACKET_TEXT
    01478   STR_FACE_COLLAR,    // WID_SCMF_COLLAR_TEXT
    01479 };
    01480
    01482 static const WindowDesc _select_company_manager_face_desc(
    01483   WDP_AUTO, 0, 0,
    01484   WC_COMPANY_MANAGER_FACE, WC_NONE,
    01485   WDF_CONSTRUCTION,
    01486   _nested_select_company_manager_face_widgets, lengthof(_nested_select_company_manager_face_widgets)
    01487 );
    01488
    01497 static void DoSelectCompanyManagerFace(Window *parent)
    01498 {
    01499   if (!Company::IsValidID((CompanyID)parent->window_number)) return;
    01500
    01501   if (BringWindowToFrontById(WC_COMPANY_MANAGER_FACE, parent->window_number)) return;
    01502   new SelectCompanyManagerFaceWindow(&_select_company_manager_face_desc, parent);
    01503 }
    01504
    01505 static const NWidgetPart _nested_company_infrastructure_widgets[] = {
    01506   NWidget(NWID_HORIZONTAL),
    01507     NWidget(WWT_CLOSEBOX, COLOUR_GREY),
    01508     NWidget(WWT_CAPTION, COLOUR_GREY, WID_CI_CAPTION), SetDataTip(STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    01509     NWidget(WWT_SHADEBOX, COLOUR_GREY),
    01510     NWidget(WWT_STICKYBOX, COLOUR_GREY),
    01511   EndContainer(),
    01512   NWidget(WWT_PANEL, COLOUR_GREY),
    01513     NWidget(NWID_VERTICAL), SetPIP(WD_FRAMERECT_TOP, 4, WD_FRAMETEXT_BOTTOM),
    01514       NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
    01515         NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_RAIL_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0),
    01516         NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_RAIL_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1),
    01517       EndContainer(),
    01518       NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
    01519         NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_ROAD_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0),
    01520         NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_ROAD_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1),
    01521       EndContainer(),
    01522       NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
    01523         NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_WATER_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0),
    01524         NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_WATER_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1),
    01525       EndContainer(),
    01526       NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
    01527         NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_STATION_DESC), SetMinimalTextLines(3, 0), SetFill(1, 0),
    01528         NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_STATION_COUNT), SetMinimalTextLines(3, 0), SetFill(0, 1),
    01529       EndContainer(),
    01530       NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
    01531         NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_TOTAL_DESC), SetFill(1, 0),
    01532         NWidget(WWT_EMPTY, COLOUR_GREY, WID_CI_TOTAL), SetFill(0, 1),
    01533       EndContainer(),
    01534     EndContainer(),
    01535   EndContainer(),
    01536 };
    01537
    01541 struct CompanyInfrastructureWindow : Window
    01542 {
    01543   RailTypes railtypes;
    01544   RoadTypes roadtypes;
    01545
    01546   uint total_width;
    01547
    01548   CompanyInfrastructureWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
    01549   {
    01550     this->UpdateRailRoadTypes();
    01551
    01552     this->InitNested(desc, window_number);
    01553     this->owner = (Owner)this->window_number;
    01554   }
    01555
    01556   void UpdateRailRoadTypes()
    01557   {
    01558     this->railtypes = RAILTYPES_NONE;
    01559     this->roadtypes = ROADTYPES_ROAD; // Road is always available.
    01560
    01561     /* Find the used railtypes. */
    01562     Engine *e;
    01563     FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) {
    01564       if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue;
    01565
    01566       this->railtypes |= GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes;
    01567     }
    01568
    01569     /* Get the date introduced railtypes as well. */
    01570     this->railtypes = AddDateIntroducedRailTypes(this->railtypes, MAX_DAY);
    01571
    01572     /* Tram is only visible when there will be a tram. */
    01573     FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) {
    01574       if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue;
    01575       if (!HasBit(e->info.misc_flags, EF_ROAD_TRAM)) continue;
    01576
    01577       this->roadtypes |= ROADTYPES_TRAM;
    01578       break;
    01579     }
    01580   }
    01581
    01583   Money GetTotalMaintenanceCost() const
    01584   {
    01585     const Company *c = Company::Get((CompanyID)this->window_number);
    01586     Money total;
    01587
    01588     uint32 rail_total = c->infrastructure.GetRailTotal();
    01589     for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
    01590       if (HasBit(this->railtypes, rt)) total += RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total);
    01591     }
    01592     total += SignalMaintenanceCost(c->infrastructure.signal);
    01593
    01594     if (HasBit(this->roadtypes, ROADTYPE_ROAD)) total += RoadMaintenanceCost(ROADTYPE_ROAD, c->infrastructure.road[ROADTYPE_ROAD]);
    01595     if (HasBit(this->roadtypes, ROADTYPE_TRAM)) total += RoadMaintenanceCost(ROADTYPE_TRAM, c->infrastructure.road[ROADTYPE_TRAM]);
    01596
    01597     total += CanalMaintenanceCost(c->infrastructure.water);
    01598     total += StationMaintenanceCost(c->infrastructure.station);
    01599     total += AirportMaintenanceCost(c->index);
    01600
    01601     return total;
    01602   }
    01603
    01604   virtual void SetStringParameters(int widget) const
    01605   {
    01606     switch (widget) {
    01607       case WID_CI_CAPTION:
    01608         SetDParam(0, (CompanyID)this->window_number);
    01609         break;
    01610     }
    01611   }
    01612
    01613   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
    01614   {
    01615     const Company *c = Company::Get((CompanyID)this->window_number);
    01616
    01617     switch (widget) {
    01618       case WID_CI_RAIL_DESC: {
    01619         uint lines = 1;
    01620
    01621         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT).width);
    01622
    01623         for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) {
    01624           if (HasBit(this->railtypes, rt)) {
    01625             lines++;
    01626             SetDParam(0, GetRailTypeInfo(rt)->strings.name);
    01627             size->width = max(size->width, GetStringBoundingBox(STR_WHITE_STRING).width + WD_FRAMERECT_LEFT);
    01628           }
    01629         }
    01630         if (this->railtypes != RAILTYPES_NONE) {
    01631           lines++;
    01632           size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS).width + WD_FRAMERECT_LEFT);
    01633         }
    01634
    01635         size->height = max(size->height, lines * FONT_HEIGHT_NORMAL);
    01636         break;
    01637       }
    01638
    01639       case WID_CI_ROAD_DESC: {
    01640         uint lines = 1;
    01641
    01642         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT).width);
    01643
    01644         if (HasBit(this->roadtypes, ROADTYPE_ROAD)) {
    01645           lines++;
    01646           size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD).width + WD_FRAMERECT_LEFT);
    01647         }
    01648         if (HasBit(this->roadtypes, ROADTYPE_TRAM)) {
    01649           lines++;
    01650           size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY).width + WD_FRAMERECT_LEFT);
    01651         }
    01652
    01653         size->height = max(size->height, lines * FONT_HEIGHT_NORMAL);
    01654         break;
    01655       }
    01656
    01657       case WID_CI_WATER_DESC:
    01658         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT).width);
    01659         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS).width + WD_FRAMERECT_LEFT);
    01660         break;
    01661
    01662       case WID_CI_STATION_DESC:
    01663         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT).width);
    01664         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS).width + WD_FRAMERECT_LEFT);
    01665         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS).width + WD_FRAMERECT_LEFT);
    01666         break;
    01667
    01668       case WID_CI_RAIL_COUNT:
    01669       case WID_CI_ROAD_COUNT:
    01670       case WID_CI_WATER_COUNT:
    01671       case WID_CI_STATION_COUNT:
    01672       case WID_CI_TOTAL: {
    01673         /* Find the maximum count that is displayed. */
    01674         uint32 max_val = 1000;  // Some random number to reserve enough space.
    01675         Money max_cost = 10000; // Some random number to reserve enough space.
    01676         uint32 rail_total = c->infrastructure.GetRailTotal();
    01677         for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) {
    01678           max_val = max(max_val, c->infrastructure.rail[rt]);
    01679           max_cost = max(max_cost, RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total));
    01680         }
    01681         max_val = max(max_val, c->infrastructure.signal);
    01682         max_cost = max(max_cost, SignalMaintenanceCost(c->infrastructure.signal));
    01683         for (RoadType rt = ROADTYPE_BEGIN; rt < ROADTYPE_END; rt++) {
    01684           max_val = max(max_val, c->infrastructure.road[rt]);
    01685           max_cost = max(max_cost, RoadMaintenanceCost(rt, c->infrastructure.road[rt]));
    01686         }
    01687         max_val = max(max_val, c->infrastructure.water);
    01688         max_cost = max(max_cost, CanalMaintenanceCost(c->infrastructure.water));
    01689         max_val = max(max_val, c->infrastructure.station);
    01690         max_cost = max(max_cost, StationMaintenanceCost(c->infrastructure.station));
    01691         max_val = max(max_val, c->infrastructure.airport);
    01692         max_cost = max(max_cost, AirportMaintenanceCost(c->index));
    01693
    01694         SetDParamMaxValue(0, max_val);
    01695         SetDParamMaxValue(1, max_cost * 12); // Convert to per year
    01696         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.
    01697
    01698         if (_settings_game.economy.infrastructure_maintenance) {
    01699           SetDParamMaxValue(0, this->GetTotalMaintenanceCost() * 12); // Convert to per year
    01700           this->total_width = GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL).width + 20;
    01701           size->width = max(size->width, this->total_width);
    01702         }
    01703
    01704         /* Set height of the total line. */
    01705         if (widget == WID_CI_TOTAL) {
    01706           size->height = _settings_game.economy.infrastructure_maintenance ? max(size->height, EXP_LINESPACE + FONT_HEIGHT_NORMAL) : 0;
    01707         }
    01708         break;
    01709       }
    01710     }
    01711   }
    01712
    01713   virtual void DrawWidget(const Rect &r, int widget) const
    01714   {
    01715     const Company *c = Company::Get((CompanyID)this->window_number);
    01716     int y = r.top;
    01717
    01718     int offs_left = _current_text_dir == TD_LTR ? WD_FRAMERECT_LEFT : 0;
    01719     int offs_right = _current_text_dir == TD_LTR ? 0 : WD_FRAMERECT_LEFT;
    01720
    01721     switch (widget) {
    01722       case WID_CI_RAIL_DESC:
    01723         DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT);
    01724
    01725         if (this->railtypes != RAILTYPES_NONE) {
    01726           /* Draw name of each valid railtype. */
    01727           for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
    01728             if (HasBit(this->railtypes, rt)) {
    01729               SetDParam(0, GetRailTypeInfo(rt)->strings.name);
    01730               DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_WHITE_STRING);
    01731             }
    01732           }
    01733           DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS);
    01734         } else {
    01735           /* No valid railtype. */
    01736           DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE);
    01737         }
    01738
    01739         break;
    01740
    01741       case WID_CI_RAIL_COUNT: {
    01742         /* Draw infrastructure count for each valid railtype. */
    01743         uint32 rail_total = c->infrastructure.GetRailTotal();
    01744         for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
    01745           if (HasBit(this->railtypes, rt)) {
    01746             SetDParam(0, c->infrastructure.rail[rt]);
    01747             SetDParam(1, RailMaintenanceCost(rt, c->infrastructure.rail[rt], rail_total) * 12); // Convert to per year
    01748             DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA);
    01749           }
    01750         }
    01751         if (this->railtypes != RAILTYPES_NONE) {
    01752           SetDParam(0, c->infrastructure.signal);
    01753           SetDParam(1, SignalMaintenanceCost(c->infrastructure.signal) * 12); // Convert to per year
    01754           DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA);
    01755         }
    01756         break;
    01757       }
    01758
    01759       case WID_CI_ROAD_DESC:
    01760         DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT);
    01761
    01762         if (this->roadtypes != ROADTYPES_NONE) {
    01763           if (HasBit(this->roadtypes, ROADTYPE_ROAD)) DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD);
    01764           if (HasBit(this->roadtypes, ROADTYPE_TRAM)) DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY);
    01765         } else {
    01766           /* No valid roadtypes. */
    01767           DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE);
    01768         }
    01769
    01770         break;
    01771
    01772       case WID_CI_ROAD_COUNT:
    01773         if (HasBit(this->roadtypes, ROADTYPE_ROAD)) {
    01774           SetDParam(0, c->infrastructure.road[ROADTYPE_ROAD]);
    01775           SetDParam(1, RoadMaintenanceCost(ROADTYPE_ROAD, c->infrastructure.road[ROADTYPE_ROAD]) * 12); // Convert to per year
    01776           DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA);
    01777         }
    01778         if (HasBit(this->roadtypes, ROADTYPE_TRAM)) {
    01779           SetDParam(0, c->infrastructure.road[ROADTYPE_TRAM]);
    01780           SetDParam(1, RoadMaintenanceCost(ROADTYPE_TRAM, c->infrastructure.road[ROADTYPE_TRAM]) * 12); // Convert to per year
    01781           DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA);
    01782         }
    01783         break;
    01784
    01785       case WID_CI_WATER_DESC:
    01786         DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT);
    01787         DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS);
    01788         break;
    01789
    01790       case WID_CI_WATER_COUNT:
    01791         SetDParam(0, c->infrastructure.water);
    01792         SetDParam(1, CanalMaintenanceCost(c->infrastructure.water) * 12); // Convert to per year
    01793         DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA);
    01794         break;
    01795
    01796       case WID_CI_TOTAL:
    01797         if (_settings_game.economy.infrastructure_maintenance) {
    01798           GfxFillRect(r.left, y, r.left + this->total_width, y, PC_WHITE);
    01799           y += EXP_LINESPACE;
    01800           SetDParam(0, this->GetTotalMaintenanceCost() * 12); // Convert to per year
    01801           DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL);
    01802         }
    01803         break;
    01804
    01805       case WID_CI_STATION_DESC:
    01806         DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT);
    01807         DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS);
    01808         DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS);
    01809         break;
    01810
    01811       case WID_CI_STATION_COUNT:
    01812         SetDParam(0, c->infrastructure.station);
    01813         SetDParam(1, StationMaintenanceCost(c->infrastructure.station) * 12); // Convert to per year
    01814         DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA);
    01815         SetDParam(0, c->infrastructure.airport);
    01816         SetDParam(1, AirportMaintenanceCost(c->index) * 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         break;
    01819     }
    01820   }
    01821
    01827   virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
    01828   {
    01829     if (!gui_scope) return;
    01830
    01831     this->UpdateRailRoadTypes();
    01832     this->ReInit();
    01833   }
    01834 };
    01835
    01836 static const WindowDesc _company_infrastructure_desc(
    01837   WDP_AUTO, 0, 0,
    01838   WC_COMPANY_INFRASTRUCTURE, WC_NONE,
    01839   0,
    01840   _nested_company_infrastructure_widgets, lengthof(_nested_company_infrastructure_widgets)
    01841 );
    01842
    01847 static void ShowCompanyInfrastructure(CompanyID company)
    01848 {
    01849   if (!Company::IsValidID(company)) return;
    01850   AllocateWindowDescFront<CompanyInfrastructureWindow>(&_company_infrastructure_desc, company);
    01851 }
    01852
    01853 static const NWidgetPart _nested_company_widgets[] = {
    01854   NWidget(NWID_HORIZONTAL),
    01855     NWidget(WWT_CLOSEBOX, COLOUR_GREY),
    01856     NWidget(WWT_CAPTION, COLOUR_GREY, WID_C_CAPTION), SetDataTip(STR_COMPANY_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    01857     NWidget(WWT_SHADEBOX, COLOUR_GREY),
    01858     NWidget(WWT_STICKYBOX, COLOUR_GREY),
    01859   EndContainer(),
    01860   NWidget(WWT_PANEL, COLOUR_GREY),
    01861     NWidget(NWID_HORIZONTAL), SetPIP(4, 6, 4),
    01862       NWidget(NWID_VERTICAL), SetPIP(4, 2, 4),
    01863         NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_FACE), SetMinimalSize(92, 119), SetFill(1, 0),
    01864         NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_FACE_TITLE), SetFill(1, 1), SetMinimalTextLines(2, 0),
    01865       EndContainer(),
    01866       NWidget(NWID_VERTICAL),
    01867         NWidget(NWID_HORIZONTAL),
    01868           NWidget(NWID_VERTICAL), SetPIP(4, 5, 5),
    01869             NWidget(WWT_TEXT, COLOUR_GREY, WID_C_DESC_INAUGURATION), SetDataTip(STR_COMPANY_VIEW_INAUGURATED_TITLE, STR_NULL), SetFill(1, 0),
    01870             NWidget(NWID_HORIZONTAL), SetPIP(0, 5, 0),
    01871               NWidget(WWT_LABEL, COLOUR_GREY, WID_C_DESC_COLOUR_SCHEME), SetDataTip(STR_COMPANY_VIEW_COLOUR_SCHEME_TITLE, STR_NULL),
    01872               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_DESC_COLOUR_SCHEME_EXAMPLE), SetMinimalSize(30, 0), SetFill(0, 1),
    01873               NWidget(NWID_SPACER), SetFill(1, 0),
    01874             EndContainer(),
    01875             NWidget(NWID_HORIZONTAL), SetPIP(0, 4, 0),
    01876               NWidget(NWID_VERTICAL),
    01877                 NWidget(WWT_TEXT, COLOUR_GREY, WID_C_DESC_VEHICLE), SetDataTip(STR_COMPANY_VIEW_VEHICLES_TITLE, STR_NULL),
    01878                 NWidget(NWID_SPACER), SetFill(0, 1),
    01879               EndContainer(),
    01880               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_DESC_VEHICLE_COUNTS), SetMinimalTextLines(4, 0),
    01881               NWidget(NWID_SPACER), SetFill(1, 0),
    01882             EndContainer(),
    01883           EndContainer(),
    01884           NWidget(NWID_VERTICAL), SetPIP(4, 2, 4),
    01885             NWidget(NWID_SELECTION, INVALID_COLOUR, WID_C_SELECT_VIEW_BUILD_HQ),
    01886               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),
    01887               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),
    01888             EndContainer(),
    01889             NWidget(NWID_SELECTION, INVALID_COLOUR, WID_C_SELECT_RELOCATE),
    01890               NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_C_RELOCATE_HQ), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_RELOCATE_HQ, STR_COMPANY_VIEW_RELOCATE_COMPANY_HEADQUARTERS),
    01891               NWidget(NWID_SPACER), SetMinimalSize(90, 0),
    01892             EndContainer(),
    01893             NWidget(NWID_SPACER), SetFill(0, 1),
    01894           EndContainer(),
    01895         EndContainer(),
    01896         NWidget(WWT_TEXT, COLOUR_GREY, WID_C_DESC_COMPANY_VALUE), SetDataTip(STR_COMPANY_VIEW_COMPANY_VALUE, STR_NULL), SetFill(1, 0),
    01897           NWidget(NWID_VERTICAL), SetPIP(4, 2, 4),
    01898             NWidget(NWID_HORIZONTAL), SetPIP(0, 4, 0),
    01899               NWidget(NWID_VERTICAL),
    01900                 NWidget(WWT_TEXT, COLOUR_GREY, WID_C_DESC_INFRASTRUCTURE), SetDataTip(STR_COMPANY_VIEW_INFRASTRUCTURE, STR_NULL),
    01901                 NWidget(NWID_SPACER), SetFill(0, 1),
    01902               EndContainer(),
    01903               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_DESC_INFRASTRUCTURE_COUNTS), SetMinimalTextLines(5, 0), SetFill(1, 0),
    01904               NWidget(NWID_VERTICAL),
    01905                 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_VIEW_INFRASTRUCTURE), SetDataTip(STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON, STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP),
    01906                 NWidget(NWID_SPACER), SetFill(0, 1), SetMinimalSize(90, 0),
    01907               EndContainer(),
    01908             EndContainer(),
    01909           EndContainer(),
    01910         NWidget(NWID_HORIZONTAL),
    01911           NWidget(NWID_SELECTION, INVALID_COLOUR, WID_C_SELECT_DESC_OWNERS),
    01912             NWidget(NWID_VERTICAL), SetPIP(5, 5, 4),
    01913               NWidget(WWT_EMPTY, INVALID_COLOUR, WID_C_DESC_OWNERS), SetMinimalTextLines(3, 0),
    01914               NWidget(NWID_SPACER), SetFill(0, 1),
    01915             EndContainer(),
    01916           EndContainer(),
    01917           NWidget(NWID_VERTICAL), SetPIP(4, 2, 4),
    01918             NWidget(NWID_SPACER), SetMinimalSize(90, 0), SetFill(0, 1),
    01919             /* Multi player buttons. */
    01920             NWidget(NWID_HORIZONTAL),
    01921               NWidget(WWT_EMPTY, COLOUR_GREY, WID_C_HAS_PASSWORD),
    01922               NWidget(NWID_SELECTION, INVALID_COLOUR, WID_C_SELECT_MULTIPLAYER),
    01923                 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_COMPANY_PASSWORD), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_PASSWORD, STR_COMPANY_VIEW_PASSWORD_TOOLTIP),
    01924                 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_C_COMPANY_JOIN), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_JOIN, STR_COMPANY_VIEW_JOIN_TOOLTIP),
    01925               EndContainer(),
    01926             EndContainer(),
    01927           EndContainer(),
    01928         EndContainer(),
    01929       EndContainer(),
    01930     EndContainer(),
    01931   EndContainer(),
    01932   /* Button bars at the bottom. */
    01933   NWidget(NWID_SELECTION, INVALID_COLOUR, WID_C_SELECT_BUTTONS),
    01934     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
    01935       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),
    01936       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),
    01937       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),
    01938       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),
    01939     EndContainer(),
    01940     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
    01941       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),
    01942       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),
    01943     EndContainer(),
    01944   EndContainer(),
    01945 };
    01946
    01947 int GetAmountOwnedBy(const Company *c, Owner owner)
    01948 {
    01949   return (c->share_owners[0] == owner) +
    01950          (c->share_owners[1] == owner) +
    01951          (c->share_owners[2] == owner) +
    01952          (c->share_owners[3] == owner);
    01953 }
    01954
    01956 static const StringID _company_view_vehicle_count_strings[] = {
    01957   STR_COMPANY_VIEW_TRAINS, STR_COMPANY_VIEW_ROAD_VEHICLES, STR_COMPANY_VIEW_SHIPS, STR_COMPANY_VIEW_AIRCRAFT
    01958 };
    01959
    01963 struct CompanyWindow : Window
    01964 {
    01965   CompanyWidgets query_widget;
    01966
    01968   enum CompanyWindowPlanes {
    01969     /* Display planes of the #WID_C_SELECT_MULTIPLAYER selection widget. */
    01970     CWP_MP_C_PWD = 0,
    01971     CWP_MP_C_JOIN,
    01972
    01973     /* Display planes of the #WID_C_SELECT_VIEW_BUILD_HQ selection widget. */
    01974     CWP_VB_VIEW = 0,
    01975     CWP_VB_BUILD,
    01976
    01977     /* Display planes of the #WID_C_SELECT_RELOCATE selection widget. */
    01978     CWP_RELOCATE_SHOW = 0,
    01979     CWP_RELOCATE_HIDE,
    01980
    01981     /* Display planes of the #WID_C_SELECT_BUTTONS selection widget. */
    01982     CWP_BUTTONS_LOCAL = 0,
    01983     CWP_BUTTONS_OTHER,
    01984   };
    01985
    01986   CompanyWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
    01987   {
    01988     this->InitNested(desc, window_number);
    01989     this->owner = (Owner)this->window_number;
    01990     this->OnInvalidateData();
    01991   }
    01992
    01993   virtual void OnPaint()
    01994   {
    01995     const Company *c = Company::Get((CompanyID)this->window_number);
    01996     bool local = this->window_number == _local_company;
    01997
    01998     if (!this->IsShaded()) {
    01999       bool reinit = false;
    02000
    02001       /* Button bar selection. */
    02002       int plane = local ? CWP_BUTTONS_LOCAL : CWP_BUTTONS_OTHER;
    02003       NWidgetStacked *wi = this->GetWidget<NWidgetStacked>(WID_C_SELECT_BUTTONS);
    02004       if (plane != wi->shown_plane) {
    02005         wi->SetDisplayedPlane(plane);
    02006         this->SetDirty();
    02007         return;
    02008       }
    02009
    02010       /* Build HQ button handling. */
    02011       plane = (local && c->location_of_HQ == INVALID_TILE) ? CWP_VB_BUILD : CWP_VB_VIEW;
    02012       wi = this->GetWidget<NWidgetStacked>(WID_C_SELECT_VIEW_BUILD_HQ);
    02013       if (plane != wi->shown_plane) {
    02014         wi->SetDisplayedPlane(plane);
    02015         this->SetDirty();
    02016         return;
    02017       }
    02018
    02019       this->SetWidgetDisabledState(WID_C_VIEW_HQ, c->location_of_HQ == INVALID_TILE);
    02020
    02021       /* Enable/disable 'Relocate HQ' button. */
    02022       plane = (!local || c->location_of_HQ == INVALID_TILE) ? CWP_RELOCATE_HIDE : CWP_RELOCATE_SHOW;
    02023       wi = this->GetWidget<NWidgetStacked>(WID_C_SELECT_RELOCATE);
    02024       if (plane != wi->shown_plane) {
    02025         wi->SetDisplayedPlane(plane);
    02026         this->SetDirty();
    02027         return;
    02028       }
    02029
    02030       /* Owners of company */
    02031       plane = SZSP_HORIZONTAL;
    02032       for (uint i = 0; i < lengthof(c->share_owners); i++) {
    02033         if (c->share_owners[i] != INVALID_COMPANY) {
    02034           plane = 0;
    02035           break;
    02036         }
    02037       }
    02038       wi = this->GetWidget<NWidgetStacked>(WID_C_SELECT_DESC_OWNERS);
    02039       if (plane != wi->shown_plane) {
    02040         wi->SetDisplayedPlane(plane);
    02041         reinit = true;
    02042       }
    02043
    02044       /* Multiplayer buttons. */
    02045       plane = ((!_networking) ? (int)SZSP_NONE : (int)(local ? CWP_MP_C_PWD : CWP_MP_C_JOIN));
    02046       wi = this->GetWidget<NWidgetStacked>(WID_C_SELECT_MULTIPLAYER);
    02047       if (plane != wi->shown_plane) {
    02048         wi->SetDisplayedPlane(plane);
    02049         reinit = true;
    02050       }
    02051       this->SetWidgetDisabledState(WID_C_COMPANY_JOIN,   c->is_ai);
    02052
    02053       if (reinit) {
    02054         this->ReInit();
    02055         return;
    02056       }
    02057     }
    02058
    02059     this->DrawWidgets();
    02060   }
    02061
    02062   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
    02063   {
    02064     switch (widget) {
    02065       case WID_C_DESC_COLOUR_SCHEME_EXAMPLE: {
    02066         Point offset;
    02067         Dimension d = GetSpriteSize(SPR_VEH_BUS_SW_VIEW, &offset);
    02068         d.width -= offset.x;
    02069         d.height -= offset.y;
    02070         *size = maxdim(*size, d);
    02071         break;
    02072       }
    02073
    02074       case WID_C_DESC_COMPANY_VALUE:
    02075         SetDParam(0, INT64_MAX); // Arguably the maximum company value
    02076         size->width = GetStringBoundingBox(STR_COMPANY_VIEW_COMPANY_VALUE).width;
    02077         break;
    02078
    02079       case WID_C_DESC_VEHICLE_COUNTS:
    02080         SetDParamMaxValue(0, 5000); // Maximum number of vehicles
    02081         for (uint i = 0; i < lengthof(_company_view_vehicle_count_strings); i++) {
    02082           size->width = max(size->width, GetStringBoundingBox(_company_view_vehicle_count_strings[i]).width);
    02083         }
    02084         break;
    02085
    02086       case WID_C_DESC_INFRASTRUCTURE_COUNTS:
    02087         SetDParamMaxValue(0, UINT_MAX);
    02088         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL).width);
    02089         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD).width);
    02090         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_WATER).width);
    02091         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_STATION).width);
    02092         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT).width);
    02093         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_NONE).width);
    02094         break;
    02095
    02096       case WID_C_DESC_OWNERS: {
    02097         const Company *c2;
    02098
    02099         FOR_ALL_COMPANIES(c2) {
    02100           SetDParamMaxValue(0, 75);
    02101           SetDParam(1, c2->index);
    02102
    02103           size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_SHARES_OWNED_BY).width);
    02104         }
    02105         break;
    02106       }
    02107
    02108 #ifdef ENABLE_NETWORK
    02109       case WID_C_HAS_PASSWORD:
    02110         *size = maxdim(*size, GetSpriteSize(SPR_LOCK));
    02111         break;
    02112 #endif /* ENABLE_NETWORK */
    02113     }
    02114   }
    02115
    02116   virtual void DrawWidget(const Rect &r, int widget) const
    02117   {
    02118     const Company *c = Company::Get((CompanyID)this->window_number);
    02119     switch (widget) {
    02120       case WID_C_FACE:
    02121         DrawCompanyManagerFace(c->face, c->colour, r.left, r.top);
    02122         break;
    02123
    02124       case WID_C_FACE_TITLE:
    02125         SetDParam(0, c->index);
    02126         DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE, TC_FROMSTRING, SA_HOR_CENTER);
    02127         break;
    02128
    02129       case WID_C_DESC_COLOUR_SCHEME_EXAMPLE: {
    02130         Point offset;
    02131         Dimension d = GetSpriteSize(SPR_VEH_BUS_SW_VIEW, &offset);
    02132         d.height -= offset.y;
    02133         DrawSprite(SPR_VEH_BUS_SW_VIEW, COMPANY_SPRITE_COLOUR(c->index), r.left - offset.x, (r.top + r.bottom - d.height) / 2 - offset.y);
    02134         break;
    02135       }
    02136
    02137       case WID_C_DESC_VEHICLE_COUNTS: {
    02138         uint amounts[4];
    02139         amounts[0] = c->group_all[VEH_TRAIN].num_vehicle;
    02140         amounts[1] = c->group_all[VEH_ROAD].num_vehicle;
    02141         amounts[2] = c->group_all[VEH_SHIP].num_vehicle;
    02142         amounts[3] = c->group_all[VEH_AIRCRAFT].num_vehicle;
    02143
    02144         int y = r.top;
    02145         if (amounts[0] + amounts[1] + amounts[2] + amounts[3] == 0) {
    02146           DrawString(r.left, r.right, y, STR_COMPANY_VIEW_VEHICLES_NONE);
    02147         } else {
    02148           assert_compile(lengthof(amounts) == lengthof(_company_view_vehicle_count_strings));
    02149
    02150           for (uint i = 0; i < lengthof(amounts); i++) {
    02151             if (amounts[i] != 0) {
    02152               SetDParam(0, amounts[i]);
    02153               DrawString(r.left, r.right, y, _company_view_vehicle_count_strings[i]);
    02154               y += FONT_HEIGHT_NORMAL;
    02155             }
    02156           }
    02157         }
    02158         break;
    02159       }
    02160
    02161       case WID_C_DESC_INFRASTRUCTURE_COUNTS: {
    02162         uint y = r.top;
    02163
    02164         /* Collect rail and road counts. */
    02165         uint rail_pices = c->infrastructure.signal;
    02166         uint road_pieces = 0;
    02167         for (uint i = 0; i < lengthof(c->infrastructure.rail); i++) rail_pices += c->infrastructure.rail[i];
    02168         for (uint i = 0; i < lengthof(c->infrastructure.road); i++) road_pieces += c->infrastructure.road[i];
    02169
    02170         if (rail_pices == 0 && road_pieces == 0 && c->infrastructure.water == 0 && c->infrastructure.station == 0 && c->infrastructure.airport == 0) {
    02171           DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE);
    02172         } else {
    02173           if (rail_pices != 0) {
    02174             SetDParam(0, rail_pices);
    02175             DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL);
    02176             y += FONT_HEIGHT_NORMAL;
    02177           }
    02178           if (road_pieces != 0) {
    02179             SetDParam(0, road_pieces);
    02180             DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD);
    02181             y += FONT_HEIGHT_NORMAL;
    02182           }
    02183           if (c->infrastructure.water != 0) {
    02184             SetDParam(0, c->infrastructure.water);
    02185             DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_WATER);
    02186             y += FONT_HEIGHT_NORMAL;
    02187           }
    02188           if (c->infrastructure.station != 0) {
    02189             SetDParam(0, c->infrastructure.station);
    02190             DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_STATION);
    02191             y += FONT_HEIGHT_NORMAL;
    02192           }
    02193           if (c->infrastructure.airport != 0) {
    02194             SetDParam(0, c->infrastructure.airport);
    02195             DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT);
    02196           }
    02197         }
    02198
    02199         break;
    02200       }
    02201
    02202       case WID_C_DESC_OWNERS: {
    02203         const Company *c2;
    02204         uint y = r.top;
    02205
    02206         FOR_ALL_COMPANIES(c2) {
    02207           uint amt = GetAmountOwnedBy(c, c2->index);
    02208           if (amt != 0) {
    02209             SetDParam(0, amt * 25);
    02210             SetDParam(1, c2->index);
    02211
    02212             DrawString(r.left, r.right, y, STR_COMPANY_VIEW_SHARES_OWNED_BY);
    02213             y += FONT_HEIGHT_NORMAL;
    02214           }
    02215         }
    02216         break;
    02217       }
    02218
    02219 #ifdef ENABLE_NETWORK
    02220       case WID_C_HAS_PASSWORD:
    02221         if (_networking && NetworkCompanyIsPassworded(c->index)) {
    02222           DrawSprite(SPR_LOCK, PAL_NONE, r.left, r.top);
    02223         }
    02224         break;
    02225 #endif /* ENABLE_NETWORK */
    02226     }
    02227   }
    02228
    02229   virtual void SetStringParameters(int widget) const
    02230   {
    02231     switch (widget) {
    02232       case WID_C_CAPTION:
    02233         SetDParam(0, (CompanyID)this->window_number);
    02234         SetDParam(1, (CompanyID)this->window_number);
    02235         break;
    02236
    02237       case WID_C_DESC_INAUGURATION:
    02238         SetDParam(0, Company::Get((CompanyID)this->window_number)->inaugurated_year);
    02239         break;
    02240
    02241       case WID_C_DESC_COMPANY_VALUE:
    02242         SetDParam(0, CalculateCompanyValue(Company::Get((CompanyID)this->window_number)));
    02243         break;
    02244     }
    02245   }
    02246
    02247   virtual void OnClick(Point pt, int widget, int click_count)
    02248   {
    02249     switch (widget) {
    02250       case WID_C_NEW_FACE: DoSelectCompanyManagerFace(this); break;
    02251
    02252       case WID_C_COLOUR_SCHEME:
    02253         if (BringWindowToFrontById(WC_COMPANY_COLOUR, this->window_number)) break;
    02254         new SelectCompanyLiveryWindow(&_select_company_livery_desc, (CompanyID)this->window_number);
    02255         break;
    02256
    02257       case WID_C_PRESIDENT_NAME:
    02258         this->query_widget = WID_C_PRESIDENT_NAME;
    02259         SetDParam(0, this->window_number);
    02260         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);
    02261         break;
    02262
    02263       case WID_C_COMPANY_NAME:
    02264         this->query_widget = WID_C_COMPANY_NAME;
    02265         SetDParam(0, this->window_number);
    02266         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);
    02267         break;
    02268
    02269       case WID_C_VIEW_HQ: {
    02270         TileIndex tile = Company::Get((CompanyID)this->window_number)->location_of_HQ;
    02271         if (_ctrl_pressed) {
    02272           ShowExtraViewPortWindow(tile);
    02273         } else {
    02274           ScrollMainWindowToTile(tile);
    02275         }
    02276         break;
    02277       }
    02278
    02279       case WID_C_BUILD_HQ:
    02280         if ((byte)this->window_number != _local_company) return;
    02281         if (this->IsWidgetLowered(WID_C_BUILD_HQ)) {
    02282           ResetObjectToPlace();
    02283           this->RaiseButtons();
    02284           break;
    02285         }
    02286         SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, HT_RECT, this);
    02287         SetTileSelectSize(2, 2);
    02288         this->LowerWidget(WID_C_BUILD_HQ);
    02289         this->SetWidgetDirty(WID_C_BUILD_HQ);
    02290         break;
    02291
    02292       case WID_C_RELOCATE_HQ:
    02293         if (this->IsWidgetLowered(WID_C_RELOCATE_HQ)) {
    02294           ResetObjectToPlace();
    02295           this->RaiseButtons();
    02296           break;
    02297         }
    02298         SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, HT_RECT, this);
    02299         SetTileSelectSize(2, 2);
    02300         this->LowerWidget(WID_C_RELOCATE_HQ);
    02301         this->SetWidgetDirty(WID_C_RELOCATE_HQ);
    02302         break;
    02303
    02304       case WID_C_VIEW_INFRASTRUCTURE:
    02305         ShowCompanyInfrastructure((CompanyID)this->window_number);
    02306         break;
    02307
    02308       case WID_C_BUY_SHARE:
    02309         DoCommandP(0, this->window_number, 0, CMD_BUY_SHARE_IN_COMPANY | CMD_MSG(STR_ERROR_CAN_T_BUY_25_SHARE_IN_THIS));
    02310         break;
    02311
    02312       case WID_C_SELL_SHARE:
    02313         DoCommandP(0, this->window_number, 0, CMD_SELL_SHARE_IN_COMPANY | CMD_MSG(STR_ERROR_CAN_T_SELL_25_SHARE_IN));
    02314         break;
    02315
    02316 #ifdef ENABLE_NETWORK
    02317       case WID_C_COMPANY_PASSWORD:
    02318         if (this->window_number == _local_company) ShowNetworkCompanyPasswordWindow(this);
    02319         break;
    02320
    02321       case WID_C_COMPANY_JOIN: {
    02322         this->query_widget = WID_C_COMPANY_JOIN;
    02323         CompanyID company = (CompanyID)this->window_number;
    02324         if (_network_server) {
    02325           NetworkServerDoMove(CLIENT_ID_SERVER, company);
    02326           MarkWholeScreenDirty();
    02327         } else if (NetworkCompanyIsPassworded(company)) {
    02328           /* ask for the password */
    02329           ShowQueryString(STR_EMPTY, STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION, NETWORK_PASSWORD_LENGTH, this, CS_ALPHANUMERAL, QSF_NONE);
    02330         } else {
    02331           /* just send the join command */
    02332           NetworkClientRequestMove(company);
    02333         }
    02334         break;
    02335       }
    02336 #endif /* ENABLE_NETWORK */
    02337     }
    02338   }
    02339
    02340   virtual void OnHundredthTick()
    02341   {
    02342     /* redraw the window every now and then */
    02343     this->SetDirty();
    02344   }
    02345
    02346   virtual void OnPlaceObject(Point pt, TileIndex tile)
    02347   {
    02348     if (DoCommandP(tile, OBJECT_HQ, 0, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS))) {
    02349       ResetObjectToPlace();
    02350       this->RaiseButtons();
    02351     }
    02352   }
    02353
    02354   virtual void OnPlaceObjectAbort()
    02355   {
    02356     this->RaiseButtons();
    02357   }
    02358
    02359   virtual void OnQueryTextFinished(char *str)
    02360   {
    02361     if (str == NULL) return;
    02362
    02363     switch (this->query_widget) {
    02364       default: NOT_REACHED();
    02365
    02366       case WID_C_PRESIDENT_NAME:
    02367         DoCommandP(0, 0, 0, CMD_RENAME_PRESIDENT | CMD_MSG(STR_ERROR_CAN_T_CHANGE_PRESIDENT), NULL, str);
    02368         break;
    02369
    02370       case WID_C_COMPANY_NAME:
    02371         DoCommandP(0, 0, 0, CMD_RENAME_COMPANY | CMD_MSG(STR_ERROR_CAN_T_CHANGE_COMPANY_NAME), NULL, str);
    02372         break;
    02373
    02374 #ifdef ENABLE_NETWORK
    02375       case WID_C_COMPANY_JOIN:
    02376         NetworkClientRequestMove((CompanyID)this->window_number, str);
    02377         break;
    02378 #endif /* ENABLE_NETWORK */
    02379     }
    02380   }
    02381
    02382
    02388   virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
    02389   {
    02390     if (this->window_number == _local_company) return;
    02391
    02392     if (_settings_game.economy.allow_shares) { // Shares are allowed
    02393       const Company *c = Company::Get(this->window_number);
    02394
    02395       /* If all shares are owned by someone (none by nobody), disable buy button */
    02396       this->SetWidgetDisabledState(WID_C_BUY_SHARE, GetAmountOwnedBy(c, INVALID_OWNER) == 0 ||
    02397           /* Only 25% left to buy. If the company is human, disable buying it up.. TODO issues! */
    02398           (GetAmountOwnedBy(c, INVALID_OWNER) == 1 && !c->is_ai) ||
    02399           /* Spectators cannot do anything of course */
    02400           _local_company == COMPANY_SPECTATOR);
    02401
    02402       /* If the company doesn't own any shares, disable sell button */
    02403       this->SetWidgetDisabledState(WID_C_SELL_SHARE, (GetAmountOwnedBy(c, _local_company) == 0) ||
    02404           /* Spectators cannot do anything of course */
    02405           _local_company == COMPANY_SPECTATOR);
    02406     } else { // Shares are not allowed, disable buy/sell buttons
    02407       this->DisableWidget(WID_C_BUY_SHARE);
    02408       this->DisableWidget(WID_C_SELL_SHARE);
    02409     }
    02410   }
    02411 };
    02412
    02413 static const WindowDesc _company_desc(
    02414   WDP_AUTO, 0, 0,
    02415   WC_COMPANY, WC_NONE,
    02416   0,
    02417   _nested_company_widgets, lengthof(_nested_company_widgets)
    02418 );
    02419
    02424 void ShowCompany(CompanyID company)
    02425 {
    02426   if (!Company::IsValidID(company)) return;
    02427
    02428   AllocateWindowDescFront<CompanyWindow>(&_company_desc, company);
    02429 }
    02430
    02435 void DirtyCompanyInfrastructureWindows(CompanyID company)
    02436 {
    02437   SetWindowDirty(WC_COMPANY, company);
    02438   SetWindowDirty(WC_COMPANY_INFRASTRUCTURE, company);
    02439 }
    02440
    02441 struct BuyCompanyWindow : Window {
    02442   BuyCompanyWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
    02443   {
    02444     this->InitNested(desc, window_number);
    02445   }
    02446
    02447   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
    02448   {
    02449     switch (widget) {
    02450       case WID_BC_FACE:
    02451         *size = GetSpriteSize(SPR_GRADIENT);
    02452         break;
    02453
    02454       case WID_BC_QUESTION:
    02455         const Company *c = Company::Get((CompanyID)this->window_number);
    02456         SetDParam(0, c->index);
    02457         SetDParam(1, c->bankrupt_value);
    02458         size->height = GetStringHeight(STR_BUY_COMPANY_MESSAGE, size->width);
    02459         break;
    02460     }
    02461   }
    02462
    02463   virtual void SetStringParameters(int widget) const
    02464   {
    02465     switch (widget) {
    02466       case WID_BC_CAPTION:
    02467         SetDParam(0, STR_COMPANY_NAME);
    02468         SetDParam(1, Company::Get((CompanyID)this->window_number)->index);
    02469         break;
    02470     }
    02471   }
    02472
    02473   virtual void DrawWidget(const Rect &r, int widget) const
    02474   {
    02475     switch (widget) {
    02476       case WID_BC_FACE: {
    02477         const Company *c = Company::Get((CompanyID)this->window_number);
    02478         DrawCompanyManagerFace(c->face, c->colour, r.left, r.top);
    02479         break;
    02480       }
    02481
    02482       case WID_BC_QUESTION: {
    02483         const Company *c = Company::Get((CompanyID)this->window_number);
    02484         SetDParam(0, c->index);
    02485         SetDParam(1, c->bankrupt_value);
    02486         DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_BUY_COMPANY_MESSAGE, TC_FROMSTRING, SA_CENTER);
    02487         break;
    02488       }
    02489     }
    02490   }
    02491
    02492   virtual void OnClick(Point pt, int widget, int click_count)
    02493   {
    02494     switch (widget) {
    02495       case WID_BC_NO:
    02496         delete this;
    02497         break;
    02498
    02499       case WID_BC_YES:
    02500         DoCommandP(0, this->window_number, 0, CMD_BUY_COMPANY | CMD_MSG(STR_ERROR_CAN_T_BUY_COMPANY));
    02501         break;
    02502     }
    02503   }
    02504 };
    02505
    02506 static const NWidgetPart _nested_buy_company_widgets[] = {
    02507   NWidget(NWID_HORIZONTAL),
    02508     NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
    02509     NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE, WID_BC_CAPTION), SetDataTip(STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    02510   EndContainer(),
    02511   NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE),
    02512     NWidget(NWID_VERTICAL), SetPIP(8, 8, 8),
    02513       NWidget(NWID_HORIZONTAL), SetPIP(8, 10, 8),
    02514         NWidget(WWT_EMPTY, INVALID_COLOUR, WID_BC_FACE), SetFill(0, 1),
    02515         NWidget(WWT_EMPTY, INVALID_COLOUR, WID_BC_QUESTION), SetMinimalSize(240, 0), SetFill(1, 1),
    02516       EndContainer(),
    02517       NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(100, 10, 100),
    02518         NWidget(WWT_TEXTBTN, COLOUR_LIGHT_BLUE, WID_BC_NO), SetMinimalSize(60, 12), SetDataTip(STR_QUIT_NO, STR_NULL), SetFill(1, 0),
    02519         NWidget(WWT_TEXTBTN, COLOUR_LIGHT_BLUE, WID_BC_YES), SetMinimalSize(60, 12), SetDataTip(STR_QUIT_YES, STR_NULL), SetFill(1, 0),
    02520       EndContainer(),
    02521     EndContainer(),
    02522   EndContainer(),
    02523 };
    02524
    02525 static const WindowDesc _buy_company_desc(
    02526   WDP_AUTO, 0, 0,
    02527   WC_BUY_COMPANY, WC_NONE,
    02528   WDF_CONSTRUCTION,
    02529   _nested_buy_company_widgets, lengthof(_nested_buy_company_widgets)
    02530 );
    02531
    02536 void ShowBuyCompanyDialog(CompanyID company)
    02537 {
    02538   AllocateWindowDescFront<BuyCompanyWindow>(&_buy_company_desc, company);
    02539 }