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