# 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
    00035 #include "table/strings.h"
    00036
    00038 static const uint EXP_LINESPACE  = 2;
    00039 static const uint EXP_BLOCKSPACE = 10;
    00040
    00041 static void DoSelectCompanyManagerFace(Window *parent);
    00042
    00044 static ExpensesType _expenses_list_1[] = {
    00045   EXPENSES_CONSTRUCTION,
    00046   EXPENSES_NEW_VEHICLES,
    00047   EXPENSES_TRAIN_RUN,
    00048   EXPENSES_ROADVEH_RUN,
    00049   EXPENSES_AIRCRAFT_RUN,
    00050   EXPENSES_SHIP_RUN,
    00051   EXPENSES_PROPERTY,
    00052   EXPENSES_TRAIN_INC,
    00053   EXPENSES_ROADVEH_INC,
    00054   EXPENSES_AIRCRAFT_INC,
    00055   EXPENSES_SHIP_INC,
    00056   EXPENSES_LOAN_INT,
    00057   EXPENSES_SHARING_INC,
    00058   EXPENSES_SHARING_COST,
    00059   EXPENSES_OTHER,
    00060 };
    00061
    00063 static ExpensesType _expenses_list_2[] = {
    00064   EXPENSES_TRAIN_INC,
    00065   EXPENSES_ROADVEH_INC,
    00066   EXPENSES_AIRCRAFT_INC,
    00067   EXPENSES_SHIP_INC,
    00068   EXPENSES_SHARING_INC,
    00069   INVALID_EXPENSES,
    00070   EXPENSES_TRAIN_RUN,
    00071   EXPENSES_ROADVEH_RUN,
    00072   EXPENSES_AIRCRAFT_RUN,
    00073   EXPENSES_SHIP_RUN,
    00074   EXPENSES_PROPERTY,
    00075   EXPENSES_LOAN_INT,
    00076   EXPENSES_SHARING_COST,
    00077   INVALID_EXPENSES,
    00078   EXPENSES_CONSTRUCTION,
    00079   EXPENSES_NEW_VEHICLES,
    00080   EXPENSES_OTHER,
    00081   INVALID_EXPENSES,
    00082 };
    00083
    00085 struct ExpensesList {
    00086   const ExpensesType *et;
    00087   const uint length;
    00088   const uint num_subtotals;
    00089
    00090   ExpensesList(ExpensesType *et, int length, int num_subtotals) : et(et), length(length), num_subtotals(num_subtotals)
    00091   {
    00092   }
    00093
    00094   uint GetHeight() const
    00095   {
    00096     /* heading + line + texts of expenses + sub-totals + total line + total text */
    00097     return FONT_HEIGHT_NORMAL + EXP_LINESPACE + this->length * FONT_HEIGHT_NORMAL + num_subtotals * (EXP_BLOCKSPACE + EXP_LINESPACE) + EXP_LINESPACE + FONT_HEIGHT_NORMAL;
    00098   }
    00099
    00101   uint GetCategoriesWidth() const
    00102   {
    00103     uint width = 0;
    00104     bool invalid_expenses_measured = false; // Measure 'Total' width only once.
    00105     for (uint i = 0; i < this->length; i++) {
    00106       ExpensesType et = this->et[i];
    00107       if (et == INVALID_EXPENSES) {
    00108         if (!invalid_expenses_measured) {
    00109           width = max(width, GetStringBoundingBox(STR_FINANCES_TOTAL_CAPTION).width);
    00110           invalid_expenses_measured = true;
    00111         }
    00112       } else {
    00113         width = max(width, GetStringBoundingBox(STR_FINANCES_SECTION_CONSTRUCTION + et).width);
    00114       }
    00115     }
    00116     return width;
    00117   }
    00118 };
    00119
    00120 static const ExpensesList _expenses_list_types[] = {
    00121   ExpensesList(_expenses_list_1, lengthof(_expenses_list_1), 0),
    00122   ExpensesList(_expenses_list_2, lengthof(_expenses_list_2), 3),
    00123 };
    00124
    00126 enum CompanyFinancesWindowWidgets {
    00127   CFW_CAPTION,
    00128   CFW_TOGGLE_SIZE,
    00129   CFW_SEL_PANEL,
    00130   CFW_EXPS_CATEGORY,
    00131   CFW_EXPS_PRICE1,
    00132   CFW_EXPS_PRICE2,
    00133   CFW_EXPS_PRICE3,
    00134   CFW_TOTAL_PANEL,
    00135   CFW_SEL_MAXLOAN,
    00136   CFW_BALANCE_VALUE,
    00137   CFW_LOAN_VALUE,
    00138   CFW_LOAN_LINE,
    00139   CFW_TOTAL_VALUE,
    00140   CFW_MAXLOAN_GAP,
    00141   CFW_MAXLOAN_VALUE,
    00142   CFW_SEL_BUTTONS,
    00143   CFW_INCREASE_LOAN,
    00144   CFW_REPAY_LOAN,
    00145 };
    00146
    00152 static void DrawCategories(const Rect &r)
    00153 {
    00154   int y = r.top;
    00155
    00156   DrawString(r.left, r.right, y, STR_FINANCES_EXPENDITURE_INCOME_TITLE, TC_FROMSTRING, SA_HOR_CENTER, true);
    00157   y += FONT_HEIGHT_NORMAL + EXP_LINESPACE;
    00158
    00159   int type = _settings_client.gui.expenses_layout;
    00160   for (uint i = 0; i < _expenses_list_types[type].length; i++) {
    00161     const ExpensesType et = _expenses_list_types[type].et[i];
    00162     if (et == INVALID_EXPENSES) {
    00163       y += EXP_LINESPACE;
    00164       DrawString(r.left, r.right, y, STR_FINANCES_TOTAL_CAPTION, TC_FROMSTRING, SA_RIGHT);
    00165       y += FONT_HEIGHT_NORMAL + EXP_BLOCKSPACE;
    00166     } else {
    00167       DrawString(r.left, r.right, y, STR_FINANCES_SECTION_CONSTRUCTION + et);
    00168       y += FONT_HEIGHT_NORMAL;
    00169     }
    00170   }
    00171
    00172   DrawString(r.left, r.right, y + EXP_LINESPACE, STR_FINANCES_TOTAL_CAPTION, TC_FROMSTRING, SA_RIGHT);
    00173 }
    00174
    00182 static void DrawPrice(Money amount, int left, int right, int top)
    00183 {
    00184   StringID str = STR_FINANCES_NEGATIVE_INCOME;
    00185   if (amount < 0) {
    00186     amount = -amount;
    00187     str++;
    00188   }
    00189   SetDParam(0, amount);
    00190   DrawString(left, right, top, str, TC_FROMSTRING, SA_RIGHT);
    00191 }
    00192
    00200 static void DrawYearColumn(const Rect &r, int year, const Money (*tbl)[EXPENSES_END])
    00201 {
    00202   int y = r.top;
    00203
    00204   SetDParam(0, year);
    00205   DrawString(r.left, r.right, y, STR_FINANCES_YEAR, TC_FROMSTRING, SA_RIGHT, true);
    00206   y += FONT_HEIGHT_NORMAL + EXP_LINESPACE;
    00207
    00208   Money sum = 0;
    00209   Money subtotal = 0;
    00210   int type = _settings_client.gui.expenses_layout;
    00211   for (uint i = 0; i < _expenses_list_types[type].length; i++) {
    00212     const ExpensesType et = _expenses_list_types[type].et[i];
    00213     if (et == INVALID_EXPENSES) {
    00214       Money cost = subtotal;
    00215       subtotal = 0;
    00216       GfxFillRect(r.left, y, r.right, y, PC_BLACK);
    00217       y += EXP_LINESPACE;
    00218       DrawPrice(cost, r.left, r.right, y);
    00219       y += FONT_HEIGHT_NORMAL + EXP_BLOCKSPACE;
    00220     } else {
    00221       Money cost = (*tbl)[et];
    00222       subtotal += cost;
    00223       sum += cost;
    00224       if (cost != 0) DrawPrice(cost, r.left, r.right, y);
    00225       y += FONT_HEIGHT_NORMAL;
    00226     }
    00227   }
    00228
    00229   GfxFillRect(r.left, y, r.right, y, PC_BLACK);
    00230   y += EXP_LINESPACE;
    00231   DrawPrice(sum, r.left, r.right, y);
    00232 }
    00233
    00234 static const NWidgetPart _nested_company_finances_widgets[] = {
    00235   NWidget(NWID_HORIZONTAL),
    00236     NWidget(WWT_CLOSEBOX, COLOUR_GREY),
    00237     NWidget(WWT_CAPTION, COLOUR_GREY, CFW_CAPTION), SetDataTip(STR_FINANCES_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    00238     NWidget(WWT_IMGBTN, COLOUR_GREY, CFW_TOGGLE_SIZE), SetDataTip(SPR_LARGE_SMALL_WINDOW, STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW),
    00239     NWidget(WWT_SHADEBOX, COLOUR_GREY),
    00240     NWidget(WWT_STICKYBOX, COLOUR_GREY),
    00241   EndContainer(),
    00242   NWidget(NWID_SELECTION, INVALID_COLOUR, CFW_SEL_PANEL),
    00243     NWidget(WWT_PANEL, COLOUR_GREY),
    00244       NWidget(NWID_HORIZONTAL), SetPadding(WD_FRAMERECT_TOP, WD_FRAMERECT_RIGHT, WD_FRAMERECT_BOTTOM, WD_FRAMERECT_LEFT), SetPIP(0, 9, 0),
    00245         NWidget(WWT_EMPTY, COLOUR_GREY, CFW_EXPS_CATEGORY), SetMinimalSize(120, 0), SetFill(0, 0),
    00246         NWidget(WWT_EMPTY, COLOUR_GREY, CFW_EXPS_PRICE1), SetMinimalSize(86, 0), SetFill(0, 0),
    00247         NWidget(WWT_EMPTY, COLOUR_GREY, CFW_EXPS_PRICE2), SetMinimalSize(86, 0), SetFill(0, 0),
    00248         NWidget(WWT_EMPTY, COLOUR_GREY, CFW_EXPS_PRICE3), SetMinimalSize(86, 0), SetFill(0, 0),
    00249       EndContainer(),
    00250     EndContainer(),
    00251   EndContainer(),
    00252   NWidget(WWT_PANEL, COLOUR_GREY),
    00253     NWidget(NWID_HORIZONTAL), SetPadding(WD_FRAMERECT_TOP, WD_FRAMERECT_RIGHT, WD_FRAMERECT_BOTTOM, WD_FRAMERECT_LEFT),
    00254       NWidget(NWID_VERTICAL), // Vertical column with 'bank balance', 'loan'
    00255         NWidget(WWT_TEXT, COLOUR_GREY), SetDataTip(STR_FINANCES_BANK_BALANCE_TITLE, STR_NULL), SetFill(1, 0),
    00256         NWidget(WWT_TEXT, COLOUR_GREY), SetDataTip(STR_FINANCES_LOAN_TITLE, STR_NULL), SetFill(1, 0),
    00257         NWidget(NWID_SPACER), SetFill(0, 1),
    00258       EndContainer(),
    00259       NWidget(NWID_SPACER), SetFill(0, 0), SetMinimalSize(30, 0),
    00260       NWidget(NWID_VERTICAL), // Vertical column with bank balance amount, loan amount, and total.
    00261         NWidget(WWT_TEXT, COLOUR_GREY, CFW_BALANCE_VALUE), SetDataTip(STR_NULL, STR_NULL),
    00262         NWidget(WWT_TEXT, COLOUR_GREY, CFW_LOAN_VALUE), SetDataTip(STR_NULL, STR_NULL),
    00263         NWidget(WWT_EMPTY, COLOUR_GREY, CFW_LOAN_LINE), SetMinimalSize(0, 2), SetFill(1, 0),
    00264         NWidget(WWT_TEXT, COLOUR_GREY, CFW_TOTAL_VALUE), SetDataTip(STR_NULL, STR_NULL),
    00265       EndContainer(),
    00266       NWidget(NWID_SELECTION, INVALID_COLOUR, CFW_SEL_MAXLOAN),
    00267         NWidget(NWID_HORIZONTAL),
    00268           NWidget(NWID_SPACER), SetFill(0, 1), SetMinimalSize(25, 0),
    00269           NWidget(NWID_VERTICAL), // Max loan information
    00270             NWidget(WWT_EMPTY, COLOUR_GREY, CFW_MAXLOAN_GAP), SetFill(0, 0),
    00271             NWidget(WWT_TEXT, COLOUR_GREY, CFW_MAXLOAN_VALUE), SetDataTip(STR_FINANCES_MAX_LOAN, STR_NULL),
    00272             NWidget(NWID_SPACER), SetFill(0, 1),
    00273           EndContainer(),
    00274         EndContainer(),
    00275       EndContainer(),
    00276       NWidget(NWID_SPACER), SetFill(1, 1),
    00277     EndContainer(),
    00278   EndContainer(),
    00279   NWidget(NWID_SELECTION, INVALID_COLOUR, CFW_SEL_BUTTONS),
    00280     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
    00281       NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CFW_INCREASE_LOAN), SetFill(1, 0), SetDataTip(STR_FINANCES_BORROW_BUTTON, STR_FINANCES_BORROW_TOOLTIP),
    00282       NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CFW_REPAY_LOAN), SetFill(1, 0), SetDataTip(STR_FINANCES_REPAY_BUTTON, STR_FINANCES_REPAY_TOOLTIP),
    00283     EndContainer(),
    00284   EndContainer(),
    00285 };
    00286
    00291 struct CompanyFinancesWindow : Window {
    00292   static Money max_money;
    00293   bool small;
    00294
    00295   CompanyFinancesWindow(const WindowDesc *desc, CompanyID company) : Window()
    00296   {
    00297     this->small = false;
    00298     this->CreateNestedTree(desc);
    00299     this->SetupWidgets();
    00300     this->FinishInitNested(desc, company);
    00301
    00302     this->owner = (Owner)this->window_number;
    00303   }
    00304
    00305   virtual void SetStringParameters(int widget) const
    00306   {
    00307     switch (widget) {
    00308       case CFW_CAPTION:
    00309         SetDParam(0, (CompanyID)this->window_number);
    00310         SetDParam(1, (CompanyID)this->window_number);
    00311         break;
    00312
    00313       case CFW_MAXLOAN_VALUE:
    00314         SetDParam(0, _economy.max_loan);
    00315         break;
    00316
    00317       case CFW_INCREASE_LOAN:
    00318       case CFW_REPAY_LOAN:
    00319         SetDParam(0, LOAN_INTERVAL);
    00320         break;
    00321     }
    00322   }
    00323
    00324   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
    00325   {
    00326     int type = _settings_client.gui.expenses_layout;
    00327     switch (widget) {
    00328       case CFW_EXPS_CATEGORY:
    00329         size->width  = _expenses_list_types[type].GetCategoriesWidth();
    00330         size->height = _expenses_list_types[type].GetHeight();
    00331         break;
    00332
    00333       case CFW_EXPS_PRICE1:
    00334       case CFW_EXPS_PRICE2:
    00335       case CFW_EXPS_PRICE3:
    00336         size->height = _expenses_list_types[type].GetHeight();
    00337         /* FALL THROUGH */
    00338       case CFW_BALANCE_VALUE:
    00339       case CFW_LOAN_VALUE:
    00340       case CFW_TOTAL_VALUE:
    00341         SetDParam(0, CompanyFinancesWindow::max_money);
    00342         size->width = max(GetStringBoundingBox(STR_FINANCES_NEGATIVE_INCOME).width, GetStringBoundingBox(STR_FINANCES_POSITIVE_INCOME).width) + padding.width;
    00343         break;
    00344
    00345       case CFW_MAXLOAN_GAP:
    00346         size->height = FONT_HEIGHT_NORMAL;
    00347         break;
    00348     }
    00349   }
    00350
    00351   virtual void DrawWidget(const Rect &r, int widget) const
    00352   {
    00353     switch (widget) {
    00354       case CFW_EXPS_CATEGORY:
    00355         DrawCategories(r);
    00356         break;
    00357
    00358       case CFW_EXPS_PRICE1:
    00359       case CFW_EXPS_PRICE2:
    00360       case CFW_EXPS_PRICE3: {
    00361         const Company *c = Company::Get((CompanyID)this->window_number);
    00362         int age = min(_cur_year - c->inaugurated_year, 2);
    00363         int wid_offset = widget - CFW_EXPS_PRICE1;
    00364         if (wid_offset <= age) {
    00365           DrawYearColumn(r, _cur_year - (age - wid_offset), c->yearly_expenses + (age - wid_offset));
    00366         }
    00367         break;
    00368       }
    00369
    00370       case CFW_BALANCE_VALUE: {
    00371         const Company *c = Company::Get((CompanyID)this->window_number);
    00372         SetDParam(0, c->money);
    00373         DrawString(r.left, r.right, r.top, STR_FINANCES_TOTAL_CURRENCY, TC_FROMSTRING, SA_RIGHT);
    00374         break;
    00375       }
    00376
    00377       case CFW_LOAN_VALUE: {
    00378         const Company *c = Company::Get((CompanyID)this->window_number);
    00379         SetDParam(0, c->current_loan);
    00380         DrawString(r.left, r.right, r.top, STR_FINANCES_TOTAL_CURRENCY, TC_FROMSTRING, SA_RIGHT);
    00381         break;
    00382       }
    00383
    00384       case CFW_TOTAL_VALUE: {
    00385         const Company *c = Company::Get((CompanyID)this->window_number);
    00386         SetDParam(0, c->money - c->current_loan);
    00387         DrawString(r.left, r.right, r.top, STR_FINANCES_TOTAL_CURRENCY, TC_FROMSTRING, SA_RIGHT);
    00388         break;
    00389       }
    00390
    00391       case CFW_LOAN_LINE:
    00392         GfxFillRect(r.left, r.top, r.right, r.top, PC_BLACK);
    00393         break;
    00394     }
    00395   }
    00396
    00401   void SetupWidgets()
    00402   {
    00403     int plane = this->small ? SZSP_NONE : 0;
    00404     this->GetWidget<NWidgetStacked>(CFW_SEL_PANEL)->SetDisplayedPlane(plane);
    00405     this->GetWidget<NWidgetStacked>(CFW_SEL_MAXLOAN)->SetDisplayedPlane(plane);
    00406
    00407     CompanyID company = (CompanyID)this->window_number;
    00408     plane = (company != _local_company) ? SZSP_NONE : 0;
    00409     this->GetWidget<NWidgetStacked>(CFW_SEL_BUTTONS)->SetDisplayedPlane(plane);
    00410   }
    00411
    00412   virtual void OnPaint()
    00413   {
    00414     if (!this->IsShaded()) {
    00415       if (!this->small) {
    00416         /* Check that the expenses panel height matches the height needed for the layout. */
    00417         int type = _settings_client.gui.expenses_layout;
    00418         if (_expenses_list_types[type].GetHeight() != this->GetWidget<NWidgetBase>(CFW_EXPS_CATEGORY)->current_y) {
    00419           this->SetupWidgets();
    00420           this->ReInit();
    00421           return;
    00422         }
    00423       }
    00424
    00425       /* Check that the loan buttons are shown only when the user owns the company. */
    00426       CompanyID company = (CompanyID)this->window_number;
    00427       int req_plane = (company != _local_company) ? SZSP_NONE : 0;
    00428       if (req_plane != this->GetWidget<NWidgetStacked>(CFW_SEL_BUTTONS)->shown_plane) {
    00429         this->SetupWidgets();
    00430         this->ReInit();
    00431         return;
    00432       }
    00433
    00434       const Company *c = Company::Get(company);
    00435       this->SetWidgetDisabledState(CFW_INCREASE_LOAN, c->current_loan == _economy.max_loan); // Borrow button only shows when there is any more money to loan.
    00436       this->SetWidgetDisabledState(CFW_REPAY_LOAN, company != _local_company || c->current_loan == 0); // Repay button only shows when there is any more money to repay.
    00437     }
    00438
    00439     this->DrawWidgets();
    00440   }
    00441
    00442   virtual void OnClick(Point pt, int widget, int click_count)
    00443   {
    00444     switch (widget) {
    00445       case CFW_TOGGLE_SIZE: // toggle size
    00446         this->small = !this->small;
    00447         this->SetupWidgets();
    00448         if (this->IsShaded()) {
    00449           /* Finances window is not resizable, so size hints given during unshading have no effect
    00450            * on the changed appearance of the window. */
    00451           this->SetShaded(false);
    00452         } else {
    00453           this->ReInit();
    00454         }
    00455         break;
    00456
    00457       case CFW_INCREASE_LOAN: // increase loan
    00458         DoCommandP(0, 0, _ctrl_pressed, CMD_INCREASE_LOAN | CMD_MSG(STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY));
    00459         break;
    00460
    00461       case CFW_REPAY_LOAN: // repay loan
    00462         DoCommandP(0, 0, _ctrl_pressed, CMD_DECREASE_LOAN | CMD_MSG(STR_ERROR_CAN_T_REPAY_LOAN));
    00463         break;
    00464     }
    00465   }
    00466
    00467   virtual void OnHundredthTick()
    00468   {
    00469     const Company *c = Company::Get((CompanyID)this->window_number);
    00470     if (c->money > CompanyFinancesWindow::max_money) {
    00471       CompanyFinancesWindow::max_money = max(c->money * 2, CompanyFinancesWindow::max_money * 4);
    00472       this->SetupWidgets();
    00473       this->ReInit();
    00474     }
    00475   }
    00476 };
    00477
    00479 Money CompanyFinancesWindow::max_money = INT32_MAX;
    00480
    00481 static const WindowDesc _company_finances_desc(
    00482   WDP_AUTO, 0, 0,
    00483   WC_FINANCES, WC_NONE,
    00484   WDF_UNCLICK_BUTTONS,
    00485   _nested_company_finances_widgets, lengthof(_nested_company_finances_widgets)
    00486 );
    00487
    00493 void ShowCompanyFinances(CompanyID company)
    00494 {
    00495   if (!Company::IsValidID(company)) return;
    00496   if (BringWindowToFrontById(WC_FINANCES, company)) return;
    00497
    00498   new CompanyFinancesWindow(&_company_finances_desc, company);
    00499 }
    00500
    00501 /* List of colours for the livery window */
    00502 static const StringID _colour_dropdown[] = {
    00503   STR_COLOUR_DARK_BLUE,
    00504   STR_COLOUR_PALE_GREEN,
    00505   STR_COLOUR_PINK,
    00506   STR_COLOUR_YELLOW,
    00507   STR_COLOUR_RED,
    00508   STR_COLOUR_LIGHT_BLUE,
    00509   STR_COLOUR_GREEN,
    00510   STR_COLOUR_DARK_GREEN,
    00511   STR_COLOUR_BLUE,
    00512   STR_COLOUR_CREAM,
    00513   STR_COLOUR_MAUVE,
    00514   STR_COLOUR_PURPLE,
    00515   STR_COLOUR_ORANGE,
    00516   STR_COLOUR_BROWN,
    00517   STR_COLOUR_GREY,
    00518   STR_COLOUR_WHITE,
    00519 };
    00520
    00521 /* Association of liveries to livery classes */
    00522 static const LiveryClass _livery_class[LS_END] = {
    00523   LC_OTHER,
    00524   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,
    00525   LC_ROAD, LC_ROAD,
    00526   LC_SHIP, LC_SHIP,
    00527   LC_AIRCRAFT, LC_AIRCRAFT, LC_AIRCRAFT,
    00528   LC_ROAD, LC_ROAD,
    00529 };
    00530
    00531 class DropDownListColourItem : public DropDownListItem {
    00532 public:
    00533   DropDownListColourItem(int result, bool masked) : DropDownListItem(result, masked) {}
    00534
    00535   virtual ~DropDownListColourItem() {}
    00536
    00537   StringID String() const
    00538   {
    00539     return _colour_dropdown[this->result];
    00540   }
    00541
    00542   uint Height(uint width) const
    00543   {
    00544     return max(FONT_HEIGHT_NORMAL, (byte)14);
    00545   }
    00546
    00547   bool Selectable() const
    00548   {
    00549     return true;
    00550   }
    00551
    00552   void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const
    00553   {
    00554     bool rtl = _current_text_dir == TD_RTL;
    00555     DrawSprite(SPR_VEH_BUS_SIDE_VIEW, PALETTE_RECOLOUR_START + this->result, rtl ? right - 16 : left + 16, top + 7);
    00556     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);
    00557   }
    00558 };
    00559
    00561 enum SelectCompanyLiveryWindowWidgets {
    00562   SCLW_WIDGET_CAPTION,
    00563   SCLW_WIDGET_CLASS_GENERAL,
    00564   SCLW_WIDGET_CLASS_RAIL,
    00565   SCLW_WIDGET_CLASS_ROAD,
    00566   SCLW_WIDGET_CLASS_SHIP,
    00567   SCLW_WIDGET_CLASS_AIRCRAFT,
    00568   SCLW_WIDGET_SPACER_DROPDOWN,
    00569   SCLW_WIDGET_PRI_COL_DROPDOWN,
    00570   SCLW_WIDGET_SEC_COL_DROPDOWN,
    00571   SCLW_WIDGET_MATRIX,
    00572 };
    00573
    00575 struct SelectCompanyLiveryWindow : public Window {
    00576 private:
    00577   static const uint TEXT_INDENT = 15;
    00578   uint32 sel;
    00579   LiveryClass livery_class;
    00580
    00581   void ShowColourDropDownMenu(uint32 widget)
    00582   {
    00583     uint32 used_colours = 0;
    00584     const Livery *livery;
    00585     LiveryScheme scheme;
    00586
    00587     /* Disallow other company colours for the primary colour */
    00588     if (HasBit(this->sel, LS_DEFAULT) && widget == SCLW_WIDGET_PRI_COL_DROPDOWN) {
    00589       const Company *c;
    00590       FOR_ALL_COMPANIES(c) {
    00591         if (c->index != _local_company) SetBit(used_colours, c->colour);
    00592       }
    00593     }
    00594
    00595     /* Get the first selected livery to use as the default dropdown item */
    00596     for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
    00597       if (HasBit(this->sel, scheme)) break;
    00598     }
    00599     if (scheme == LS_END) scheme = LS_DEFAULT;
    00600     livery = &Company::Get((CompanyID)this->window_number)->livery[scheme];
    00601
    00602     DropDownList *list = new DropDownList();
    00603     for (uint i = 0; i < lengthof(_colour_dropdown); i++) {
    00604       list->push_back(new DropDownListColourItem(i, HasBit(used_colours, i)));
    00605     }
    00606
    00607     ShowDropDownList(this, list, widget == SCLW_WIDGET_PRI_COL_DROPDOWN ? livery->colour1 : livery->colour2, widget);
    00608   }
    00609
    00610 public:
    00611   SelectCompanyLiveryWindow(const WindowDesc *desc, CompanyID company) : Window()
    00612   {
    00613     this->livery_class = LC_OTHER;
    00614     this->sel = 1;
    00615     this->InitNested(desc, company);
    00616     this->owner = company;
    00617     this->LowerWidget(SCLW_WIDGET_CLASS_GENERAL);
    00618     this->InvalidateData(1);
    00619   }
    00620
    00621   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
    00622   {
    00623     switch (widget) {
    00624       case SCLW_WIDGET_SPACER_DROPDOWN: {
    00625         /* The matrix widget below needs enough room to print all the schemes. */
    00626         Dimension d = {0, 0};
    00627         for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
    00628           d = maxdim(d, GetStringBoundingBox(STR_LIVERY_DEFAULT + scheme));
    00629         }
    00630         size->width = max(size->width, TEXT_INDENT + d.width + WD_FRAMERECT_RIGHT);
    00631         break;
    00632       }
    00633
    00634       case SCLW_WIDGET_MATRIX: {
    00635         uint livery_height = 0;
    00636         for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
    00637           if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
    00638             livery_height++;
    00639           }
    00640         }
    00641         size->height = livery_height * (4 + FONT_HEIGHT_NORMAL);
    00642         this->GetWidget<NWidgetCore>(SCLW_WIDGET_MATRIX)->widget_data = (livery_height << MAT_ROW_START) | (1 << MAT_COL_START);
    00643         break;
    00644       }
    00645
    00646       case SCLW_WIDGET_SEC_COL_DROPDOWN:
    00647         if (!_loaded_newgrf_features.has_2CC) {
    00648           size->width = 0;
    00649           break;
    00650         }
    00651         /* FALL THROUGH */
    00652       case SCLW_WIDGET_PRI_COL_DROPDOWN: {
    00653         for (const StringID *id = _colour_dropdown; id != endof(_colour_dropdown); id++) {
    00654           size->width = max(size->width, GetStringBoundingBox(*id).width + 34);
    00655         }
    00656         break;
    00657       }
    00658     }
    00659   }
    00660
    00661   virtual void OnPaint()
    00662   {
    00663     /* Disable dropdown controls if no scheme is selected */
    00664     this->SetWidgetDisabledState(SCLW_WIDGET_PRI_COL_DROPDOWN, this->sel == 0);
    00665     this->SetWidgetDisabledState(SCLW_WIDGET_SEC_COL_DROPDOWN, this->sel == 0);
    00666
    00667     this->DrawWidgets();
    00668   }
    00669
    00670   virtual void SetStringParameters(int widget) const
    00671   {
    00672     switch (widget) {
    00673       case SCLW_WIDGET_PRI_COL_DROPDOWN:
    00674       case SCLW_WIDGET_SEC_COL_DROPDOWN: {
    00675         const Company *c = Company::Get((CompanyID)this->window_number);
    00676         LiveryScheme scheme = LS_DEFAULT;
    00677
    00678         if (this->sel != 0) {
    00679           for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
    00680             if (HasBit(this->sel, scheme)) break;
    00681           }
    00682           if (scheme == LS_END) scheme = LS_DEFAULT;
    00683         }
    00684         SetDParam(0, STR_COLOUR_DARK_BLUE + ((widget == SCLW_WIDGET_PRI_COL_DROPDOWN) ? c->livery[scheme].colour1 : c->livery[scheme].colour2));
    00685         break;
    00686       }
    00687     }
    00688   }
    00689
    00690   virtual void DrawWidget(const Rect &r, int widget) const
    00691   {
    00692     if (widget != SCLW_WIDGET_MATRIX) return;
    00693
    00694     bool rtl = _current_text_dir == TD_RTL;
    00695
    00696     /* Horizontal coordinates of scheme name column. */
    00697     const NWidgetBase *nwi = this->GetWidget<NWidgetBase>(SCLW_WIDGET_SPACER_DROPDOWN);
    00698     int sch_left = nwi->pos_x;
    00699     int sch_right = sch_left + nwi->current_x - 1;
    00700     /* Horizontal coordinates of first dropdown. */
    00701     nwi = this->GetWidget<NWidgetBase>(SCLW_WIDGET_PRI_COL_DROPDOWN);
    00702     int pri_left = nwi->pos_x;
    00703     int pri_right = pri_left + nwi->current_x - 1;
    00704     /* Horizontal coordinates of second dropdown. */
    00705     nwi = this->GetWidget<NWidgetBase>(SCLW_WIDGET_SEC_COL_DROPDOWN);
    00706     int sec_left = nwi->pos_x;
    00707     int sec_right = sec_left + nwi->current_x - 1;
    00708
    00709     int text_left  = (rtl ? (uint)WD_FRAMERECT_LEFT : TEXT_INDENT);
    00710     int text_right = (rtl ? TEXT_INDENT : (uint)WD_FRAMERECT_RIGHT);
    00711
    00712     int y = r.top + 3;
    00713     const Company *c = Company::Get((CompanyID)this->window_number);
    00714     for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
    00715       if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
    00716         bool sel = HasBit(this->sel, scheme) != 0;
    00717
    00718         /* Optional check box + scheme name. */
    00719         if (scheme != LS_DEFAULT) {
    00720           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);
    00721         }
    00722         DrawString(sch_left + text_left, sch_right - text_right, y, STR_LIVERY_DEFAULT + scheme, sel ? TC_WHITE : TC_BLACK);
    00723
    00724         /* Text below the first dropdown. */
    00725         DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOUR(c->livery[scheme].colour1), (rtl ? pri_right - TEXT_INDENT + WD_FRAMERECT_RIGHT : pri_left) + WD_FRAMERECT_LEFT, y);
    00726         DrawString(pri_left + text_left, pri_right - text_right, y, STR_COLOUR_DARK_BLUE + c->livery[scheme].colour1, sel ? TC_WHITE : TC_GOLD);
    00727
    00728         /* Text below the second dropdown. */
    00729         if (sec_right > sec_left) { // Second dropdown has non-zero size.
    00730           DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOUR(c->livery[scheme].colour2), (rtl ? sec_right - TEXT_INDENT + WD_FRAMERECT_RIGHT : sec_left) + WD_FRAMERECT_LEFT, y);
    00731           DrawString(sec_left + text_left, sec_right - text_right, y, STR_COLOUR_DARK_BLUE + c->livery[scheme].colour2, sel ? TC_WHITE : TC_GOLD);
    00732         }
    00733
    00734         y += 4 + FONT_HEIGHT_NORMAL;
    00735       }
    00736     }
    00737   }
    00738
    00739   virtual void OnClick(Point pt, int widget, int click_count)
    00740   {
    00741     switch (widget) {
    00742       /* Livery Class buttons */
    00743       case SCLW_WIDGET_CLASS_GENERAL:
    00744       case SCLW_WIDGET_CLASS_RAIL:
    00745       case SCLW_WIDGET_CLASS_ROAD:
    00746       case SCLW_WIDGET_CLASS_SHIP:
    00747       case SCLW_WIDGET_CLASS_AIRCRAFT:
    00748         this->RaiseWidget(this->livery_class + SCLW_WIDGET_CLASS_GENERAL);
    00749         this->livery_class = (LiveryClass)(widget - SCLW_WIDGET_CLASS_GENERAL);
    00750         this->LowerWidget(this->livery_class + SCLW_WIDGET_CLASS_GENERAL);
    00751
    00752         /* Select the first item in the list */
    00753         this->sel = 0;
    00754         for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
    00755           if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
    00756             this->sel = 1 << scheme;
    00757             break;
    00758           }
    00759         }
    00760
    00761         this->ReInit();
    00762         break;
    00763
    00764       case SCLW_WIDGET_PRI_COL_DROPDOWN: // First colour dropdown
    00765         ShowColourDropDownMenu(SCLW_WIDGET_PRI_COL_DROPDOWN);
    00766         break;
    00767
    00768       case SCLW_WIDGET_SEC_COL_DROPDOWN: // Second colour dropdown
    00769         ShowColourDropDownMenu(SCLW_WIDGET_SEC_COL_DROPDOWN);
    00770         break;
    00771
    00772       case SCLW_WIDGET_MATRIX: {
    00773         const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SCLW_WIDGET_MATRIX);
    00774         LiveryScheme j = (LiveryScheme)((pt.y - wid->pos_y) / (4 + FONT_HEIGHT_NORMAL));
    00775
    00776         for (LiveryScheme scheme = LS_BEGIN; scheme <= j; scheme++) {
    00777           if (_livery_class[scheme] != this->livery_class || !HasBit(_loaded_newgrf_features.used_liveries, scheme)) j++;
    00778           if (scheme >= LS_END) return;
    00779         }
    00780         if (j >= LS_END) return;
    00781
    00782         /* If clicking on the left edge, toggle using the livery */
    00783         if (_current_text_dir == TD_RTL ? pt.x - wid->pos_x > wid->current_x - TEXT_INDENT : pt.x - wid->pos_x < TEXT_INDENT) {
    00784           DoCommandP(0, j | (2 << 8), !Company::Get((CompanyID)this->window_number)->livery[j].in_use, CMD_SET_COMPANY_COLOUR);
    00785         }
    00786
    00787         if (_ctrl_pressed) {
    00788           ToggleBit(this->sel, j);
    00789         } else {
    00790           this->sel = 1 << j;
    00791         }
    00792         this->SetDirty();
    00793         break;
    00794       }
    00795     }
    00796   }
    00797
    00798   virtual void OnDropdownSelect(int widget, int index)
    00799   {
    00800     for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
    00801       if (HasBit(this->sel, scheme)) {
    00802         DoCommandP(0, scheme | (widget == SCLW_WIDGET_PRI_COL_DROPDOWN ? 0 : 256), index, CMD_SET_COMPANY_COLOUR);
    00803       }
    00804     }
    00805   }
    00806
    00812   virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
    00813   {
    00814     if (!gui_scope) return;
    00815     this->SetWidgetsDisabledState(true, SCLW_WIDGET_CLASS_RAIL, SCLW_WIDGET_CLASS_ROAD, SCLW_WIDGET_CLASS_SHIP, SCLW_WIDGET_CLASS_AIRCRAFT, WIDGET_LIST_END);
    00816
    00817     bool current_class_valid = this->livery_class == LC_OTHER;
    00818     if (_settings_client.gui.liveries == LIT_ALL || (_settings_client.gui.liveries == LIT_COMPANY && this->window_number == _local_company)) {
    00819       for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
    00820         if (HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
    00821           if (_livery_class[scheme] == this->livery_class) current_class_valid = true;
    00822           this->EnableWidget(SCLW_WIDGET_CLASS_GENERAL + _livery_class[scheme]);
    00823         } else {
    00824           ClrBit(this->sel, scheme);
    00825         }
    00826       }
    00827     }
    00828
    00829     if (!current_class_valid) {
    00830       Point pt = {0, 0};
    00831       this->OnClick(pt, SCLW_WIDGET_CLASS_GENERAL, 1);
    00832     } else if (data == 0) {
    00833       this->ReInit();
    00834     }
    00835   }
    00836 };
    00837
    00838 static const NWidgetPart _nested_select_company_livery_widgets [] = {
    00839   NWidget(NWID_HORIZONTAL),
    00840     NWidget(WWT_CLOSEBOX, COLOUR_GREY),
    00841     NWidget(WWT_CAPTION, COLOUR_GREY, SCLW_WIDGET_CAPTION), SetDataTip(STR_LIVERY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    00842   EndContainer(),
    00843   NWidget(NWID_HORIZONTAL),
    00844     NWidget(WWT_IMGBTN, COLOUR_GREY, SCLW_WIDGET_CLASS_GENERAL), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_COMPANY_GENERAL, STR_LIVERY_GENERAL_TOOLTIP),
    00845     NWidget(WWT_IMGBTN, COLOUR_GREY, SCLW_WIDGET_CLASS_RAIL), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_TRAINLIST, STR_LIVERY_TRAIN_TOOLTIP),
    00846     NWidget(WWT_IMGBTN, COLOUR_GREY, SCLW_WIDGET_CLASS_ROAD), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_TRUCKLIST, STR_LIVERY_ROAD_VEHICLE_TOOLTIP),
    00847     NWidget(WWT_IMGBTN, COLOUR_GREY, SCLW_WIDGET_CLASS_SHIP), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_SHIPLIST, STR_LIVERY_SHIP_TOOLTIP),
    00848     NWidget(WWT_IMGBTN, COLOUR_GREY, SCLW_WIDGET_CLASS_AIRCRAFT), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_AIRPLANESLIST, STR_LIVERY_AIRCRAFT_TOOLTIP),
    00849     NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(90, 22), SetFill(1, 1), EndContainer(),
    00850   EndContainer(),
    00851   NWidget(NWID_HORIZONTAL),
    00852     NWidget(WWT_PANEL, COLOUR_GREY, SCLW_WIDGET_SPACER_DROPDOWN), SetMinimalSize(150, 12), SetFill(1, 1), EndContainer(),
    00853     NWidget(WWT_DROPDOWN, COLOUR_GREY, SCLW_WIDGET_PRI_COL_DROPDOWN), SetMinimalSize(125, 12), SetFill(0, 1), SetDataTip(STR_BLACK_STRING, STR_LIVERY_PRIMARY_TOOLTIP),
    00854     NWidget(WWT_DROPDOWN, COLOUR_GREY, SCLW_WIDGET_SEC_COL_DROPDOWN), SetMinimalSize(125, 12), SetFill(0, 1),
    00855         SetDataTip(STR_BLACK_STRING, STR_LIVERY_SECONDARY_TOOLTIP),
    00856   EndContainer(),
    00857   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),
    00858 };
    00859
    00860 static const WindowDesc _select_company_livery_desc(
    00861   WDP_AUTO, 0, 0,
    00862   WC_COMPANY_COLOUR, WC_NONE,
    00863   0,
    00864   _nested_select_company_livery_widgets, lengthof(_nested_select_company_livery_widgets)
    00865 );
    00866
    00874 void DrawCompanyManagerFace(CompanyManagerFace cmf, int colour, int x, int y)
    00875 {
    00876   GenderEthnicity ge = (GenderEthnicity)GetCompanyManagerFaceBits(cmf, CMFV_GEN_ETHN, GE_WM);
    00877
    00878   bool has_moustache   = !HasBit(ge, GENDER_FEMALE) && GetCompanyManagerFaceBits(cmf, CMFV_HAS_MOUSTACHE,   ge) != 0;
    00879   bool has_tie_earring = !HasBit(ge, GENDER_FEMALE) || GetCompanyManagerFaceBits(cmf, CMFV_HAS_TIE_EARRING, ge) != 0;
    00880   bool has_glasses     = GetCompanyManagerFaceBits(cmf, CMFV_HAS_GLASSES, ge) != 0;
    00881   PaletteID pal;
    00882
    00883   /* Modify eye colour palette only if 2 or more valid values exist */
    00884   if (_cmf_info[CMFV_EYE_COLOUR].valid_values[ge] < 2) {
    00885     pal = PAL_NONE;
    00886   } else {
    00887     switch (GetCompanyManagerFaceBits(cmf, CMFV_EYE_COLOUR, ge)) {
    00888       default: NOT_REACHED();
    00889       case 0: pal = PALETTE_TO_BROWN; break;
    00890       case 1: pal = PALETTE_TO_BLUE;  break;
    00891       case 2: pal = PALETTE_TO_GREEN; break;
    00892     }
    00893   }
    00894
    00895   /* Draw the gradient (background) */
    00896   DrawSprite(SPR_GRADIENT, GENERAL_SPRITE_COLOUR(colour), x, y);
    00897
    00898   for (CompanyManagerFaceVariable cmfv = CMFV_CHEEKS; cmfv < CMFV_END; cmfv++) {
    00899     switch (cmfv) {
    00900       case CMFV_MOUSTACHE:   if (!has_moustache)   continue; break;
    00901       case CMFV_LIPS:        // FALL THROUGH
    00902       case CMFV_NOSE:        if (has_moustache)    continue; break;
    00903       case CMFV_TIE_EARRING: if (!has_tie_earring) continue; break;
    00904       case CMFV_GLASSES:     if (!has_glasses)     continue; break;
    00905       default: break;
    00906     }
    00907     DrawSprite(GetCompanyManagerFaceSprite(cmf, cmfv, ge), (cmfv == CMFV_EYEBROWS) ? pal : PAL_NONE, x, y);
    00908   }
    00909 }
    00910
    00916 enum SelectCompanyManagerFaceWidgets {
    00917   SCMFW_WIDGET_CAPTION,
    00918   SCMFW_WIDGET_TOGGLE_LARGE_SMALL,
    00919   SCMFW_WIDGET_SELECT_FACE,
    00920   SCMFW_WIDGET_CANCEL,
    00921   SCMFW_WIDGET_ACCEPT,
    00922   SCMFW_WIDGET_MALE,
    00923   SCMFW_WIDGET_FEMALE,
    00924   SCMFW_WIDGET_MALE2,
    00925   SCMFW_WIDGET_FEMALE2,
    00926   SCMFW_WIDGET_SEL_LOADSAVE,
    00927   SCMFW_WIDGET_SEL_MALEFEMALE,
    00928   SCMFW_WIDGET_SEL_PARTS,
    00929   SCMFW_WIDGET_RANDOM_NEW_FACE,
    00930   SCMFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON,
    00931   SCMFM_WIDGET_FACE,
    00932   SCMFW_WIDGET_LOAD,
    00933   SCMFW_WIDGET_FACECODE,
    00934   SCMFW_WIDGET_SAVE,
    00935   SCMFW_WIDGET_HAS_MOUSTACHE_EARRING_TEXT,
    00936   SCMFW_WIDGET_TIE_EARRING_TEXT,
    00937   SCMFW_WIDGET_LIPS_MOUSTACHE_TEXT,
    00938   SCMFW_WIDGET_HAS_GLASSES_TEXT,
    00939   SCMFW_WIDGET_HAIR_TEXT,
    00940   SCMFW_WIDGET_EYEBROWS_TEXT,
    00941   SCMFW_WIDGET_EYECOLOUR_TEXT,
    00942   SCMFW_WIDGET_GLASSES_TEXT,
    00943   SCMFW_WIDGET_NOSE_TEXT,
    00944   SCMFW_WIDGET_CHIN_TEXT,
    00945   SCMFW_WIDGET_JACKET_TEXT,
    00946   SCMFW_WIDGET_COLLAR_TEXT,
    00947   SCMFW_WIDGET_ETHNICITY_EUR,
    00948   SCMFW_WIDGET_ETHNICITY_AFR,
    00949   SCMFW_WIDGET_HAS_MOUSTACHE_EARRING,
    00950   SCMFW_WIDGET_HAS_GLASSES,
    00951   SCMFW_WIDGET_EYECOLOUR_L,
    00952   SCMFW_WIDGET_EYECOLOUR,
    00953   SCMFW_WIDGET_EYECOLOUR_R,
    00954   SCMFW_WIDGET_CHIN_L,
    00955   SCMFW_WIDGET_CHIN,
    00956   SCMFW_WIDGET_CHIN_R,
    00957   SCMFW_WIDGET_EYEBROWS_L,
    00958   SCMFW_WIDGET_EYEBROWS,
    00959   SCMFW_WIDGET_EYEBROWS_R,
    00960   SCMFW_WIDGET_LIPS_MOUSTACHE_L,
    00961   SCMFW_WIDGET_LIPS_MOUSTACHE,
    00962   SCMFW_WIDGET_LIPS_MOUSTACHE_R,
    00963   SCMFW_WIDGET_NOSE_L,
    00964   SCMFW_WIDGET_NOSE,
    00965   SCMFW_WIDGET_NOSE_R,
    00966   SCMFW_WIDGET_HAIR_L,
    00967   SCMFW_WIDGET_HAIR,
    00968   SCMFW_WIDGET_HAIR_R,
    00969   SCMFW_WIDGET_JACKET_L,
    00970   SCMFW_WIDGET_JACKET,
    00971   SCMFW_WIDGET_JACKET_R,
    00972   SCMFW_WIDGET_COLLAR_L,
    00973   SCMFW_WIDGET_COLLAR,
    00974   SCMFW_WIDGET_COLLAR_R,
    00975   SCMFW_WIDGET_TIE_EARRING_L,
    00976   SCMFW_WIDGET_TIE_EARRING,
    00977   SCMFW_WIDGET_TIE_EARRING_R,
    00978   SCMFW_WIDGET_GLASSES_L,
    00979   SCMFW_WIDGET_GLASSES,
    00980   SCMFW_WIDGET_GLASSES_R,
    00981 };
    00982
    00984 static const NWidgetPart _nested_select_company_manager_face_widgets[] = {
    00985   NWidget(NWID_HORIZONTAL),
    00986     NWidget(WWT_CLOSEBOX, COLOUR_GREY),
    00987     NWidget(WWT_CAPTION, COLOUR_GREY, SCMFW_WIDGET_CAPTION), SetDataTip(STR_FACE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    00988     NWidget(WWT_IMGBTN, COLOUR_GREY, SCMFW_WIDGET_TOGGLE_LARGE_SMALL), SetDataTip(SPR_LARGE_SMALL_WINDOW, STR_FACE_ADVANCED_TOOLTIP),
    00989   EndContainer(),
    00990   NWidget(WWT_PANEL, COLOUR_GREY, SCMFW_WIDGET_SELECT_FACE),
    00991     NWidget(NWID_SPACER), SetMinimalSize(0, 2),
    00992     NWidget(NWID_HORIZONTAL), SetPIP(2, 2, 2),
    00993       NWidget(NWID_VERTICAL),
    00994         NWidget(NWID_HORIZONTAL),
    00995           NWidget(NWID_SPACER), SetFill(1, 0),
    00996           NWidget(WWT_EMPTY, COLOUR_GREY, SCMFM_WIDGET_FACE), SetMinimalSize(92, 119),
    00997           NWidget(NWID_SPACER), SetFill(1, 0),
    00998         EndContainer(),
    00999         NWidget(NWID_SPACER), SetMinimalSize(0, 2),
    01000         NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_RANDOM_NEW_FACE), SetFill(1, 0), SetDataTip(STR_FACE_NEW_FACE_BUTTON, STR_FACE_NEW_FACE_TOOLTIP),
    01001         NWidget(NWID_SELECTION, INVALID_COLOUR, SCMFW_WIDGET_SEL_LOADSAVE), // Load/number/save buttons under the portrait in the advanced view.
    01002           NWidget(NWID_VERTICAL),
    01003             NWidget(NWID_SPACER), SetMinimalSize(0, 5), SetFill(0, 1),
    01004             NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_LOAD), SetFill(1, 0), SetDataTip(STR_FACE_LOAD, STR_FACE_LOAD_TOOLTIP),
    01005             NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_FACECODE), SetFill(1, 0), SetDataTip(STR_FACE_FACECODE, STR_FACE_FACECODE_TOOLTIP),
    01006             NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_SAVE), SetFill(1, 0), SetDataTip(STR_FACE_SAVE, STR_FACE_SAVE_TOOLTIP),
    01007             NWidget(NWID_SPACER), SetMinimalSize(0, 5), SetFill(0, 1),
    01008           EndContainer(),
    01009         EndContainer(),
    01010       EndContainer(),
    01011       NWidget(NWID_VERTICAL),
    01012         NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON), SetFill(1, 0), SetDataTip(STR_FACE_ADVANCED, STR_FACE_ADVANCED_TOOLTIP),
    01013         NWidget(NWID_SPACER), SetMinimalSize(0, 2),
    01014         NWidget(NWID_SELECTION, INVALID_COLOUR, SCMFW_WIDGET_SEL_MALEFEMALE), // Simple male/female face setting.
    01015           NWidget(NWID_VERTICAL),
    01016             NWidget(NWID_SPACER), SetFill(0, 1),
    01017             NWidget(WWT_TEXTBTN, COLOUR_GREY, SCMFW_WIDGET_MALE), SetFill(1, 0), SetDataTip(STR_FACE_MALE_BUTTON, STR_FACE_MALE_TOOLTIP),
    01018             NWidget(WWT_TEXTBTN, COLOUR_GREY, SCMFW_WIDGET_FEMALE), SetFill(1, 0), SetDataTip(STR_FACE_FEMALE_BUTTON, STR_FACE_FEMALE_TOOLTIP),
    01019             NWidget(NWID_SPACER), SetFill(0, 1),
    01020           EndContainer(),
    01021         EndContainer(),
    01022         NWidget(NWID_SELECTION, INVALID_COLOUR, SCMFW_WIDGET_SEL_PARTS), // Advanced face parts setting.
    01023           NWidget(NWID_VERTICAL),
    01024             NWidget(NWID_SPACER), SetMinimalSize(0, 2),
    01025             NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
    01026               NWidget(WWT_TEXTBTN, COLOUR_GREY, SCMFW_WIDGET_MALE2), SetFill(1, 0), SetDataTip(STR_FACE_MALE_BUTTON, STR_FACE_MALE_TOOLTIP),
    01027               NWidget(WWT_TEXTBTN, COLOUR_GREY, SCMFW_WIDGET_FEMALE2), SetFill(1, 0), SetDataTip(STR_FACE_FEMALE_BUTTON, STR_FACE_FEMALE_TOOLTIP),
    01028             EndContainer(),
    01029             NWidget(NWID_SPACER), SetMinimalSize(0, 2),
    01030             NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
    01031               NWidget(WWT_TEXTBTN, COLOUR_GREY, SCMFW_WIDGET_ETHNICITY_EUR), SetFill(1, 0), SetDataTip(STR_FACE_EUROPEAN, STR_FACE_SELECT_EUROPEAN),
    01032               NWidget(WWT_TEXTBTN, COLOUR_GREY, SCMFW_WIDGET_ETHNICITY_AFR), SetFill(1, 0), SetDataTip(STR_FACE_AFRICAN, STR_FACE_SELECT_AFRICAN),
    01033             EndContainer(),
    01034             NWidget(NWID_SPACER), SetMinimalSize(0, 4),
    01035             NWidget(NWID_HORIZONTAL),
    01036               NWidget(WWT_EMPTY, INVALID_COLOUR, SCMFW_WIDGET_HAS_MOUSTACHE_EARRING_TEXT), SetFill(1, 0),
    01037               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_HAS_MOUSTACHE_EARRING), SetDataTip(STR_EMPTY, STR_FACE_MOUSTACHE_EARRING_TOOLTIP),
    01038             EndContainer(),
    01039             NWidget(NWID_HORIZONTAL),
    01040               NWidget(WWT_EMPTY, INVALID_COLOUR, SCMFW_WIDGET_HAS_GLASSES_TEXT), SetFill(1, 0),
    01041               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_HAS_GLASSES), SetDataTip(STR_EMPTY, STR_FACE_GLASSES_TOOLTIP),
    01042             EndContainer(),
    01043             NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetFill(1, 0),
    01044             NWidget(NWID_HORIZONTAL),
    01045               NWidget(WWT_EMPTY, INVALID_COLOUR, SCMFW_WIDGET_HAIR_TEXT), SetFill(1, 0),
    01046               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_HAIR_L), SetDataTip(AWV_DECREASE, STR_FACE_HAIR_TOOLTIP),
    01047               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_HAIR), SetDataTip(STR_EMPTY, STR_FACE_HAIR_TOOLTIP),
    01048               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_HAIR_R), SetDataTip(AWV_INCREASE, STR_FACE_HAIR_TOOLTIP),
    01049             EndContainer(),
    01050             NWidget(NWID_HORIZONTAL),
    01051               NWidget(WWT_EMPTY, INVALID_COLOUR, SCMFW_WIDGET_EYEBROWS_TEXT), SetFill(1, 0),
    01052               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_EYEBROWS_L), SetDataTip(AWV_DECREASE, STR_FACE_EYEBROWS_TOOLTIP),
    01053               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_EYEBROWS), SetDataTip(STR_EMPTY, STR_FACE_EYEBROWS_TOOLTIP),
    01054               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_EYEBROWS_R), SetDataTip(AWV_INCREASE, STR_FACE_EYEBROWS_TOOLTIP),
    01055             EndContainer(),
    01056             NWidget(NWID_HORIZONTAL),
    01057               NWidget(WWT_EMPTY, INVALID_COLOUR, SCMFW_WIDGET_EYECOLOUR_TEXT), SetFill(1, 0),
    01058               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_EYECOLOUR_L), SetDataTip(AWV_DECREASE, STR_FACE_EYECOLOUR_TOOLTIP),
    01059               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_EYECOLOUR), SetDataTip(STR_EMPTY, STR_FACE_EYECOLOUR_TOOLTIP),
    01060               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_EYECOLOUR_R), SetDataTip(AWV_INCREASE, STR_FACE_EYECOLOUR_TOOLTIP),
    01061             EndContainer(),
    01062             NWidget(NWID_HORIZONTAL),
    01063               NWidget(WWT_EMPTY, INVALID_COLOUR, SCMFW_WIDGET_GLASSES_TEXT), SetFill(1, 0),
    01064               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_GLASSES_L), SetDataTip(AWV_DECREASE, STR_FACE_GLASSES_TOOLTIP_2),
    01065               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_GLASSES), SetDataTip(STR_EMPTY, STR_FACE_GLASSES_TOOLTIP_2),
    01066               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_GLASSES_R), SetDataTip(AWV_INCREASE, STR_FACE_GLASSES_TOOLTIP_2),
    01067             EndContainer(),
    01068             NWidget(NWID_HORIZONTAL),
    01069               NWidget(WWT_EMPTY, INVALID_COLOUR, SCMFW_WIDGET_NOSE_TEXT), SetFill(1, 0),
    01070               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_NOSE_L), SetDataTip(AWV_DECREASE, STR_FACE_NOSE_TOOLTIP),
    01071               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_NOSE), SetDataTip(STR_EMPTY, STR_FACE_NOSE_TOOLTIP),
    01072               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_NOSE_R), SetDataTip(AWV_INCREASE, STR_FACE_NOSE_TOOLTIP),
    01073             EndContainer(),
    01074             NWidget(NWID_HORIZONTAL),
    01075               NWidget(WWT_EMPTY, INVALID_COLOUR, SCMFW_WIDGET_LIPS_MOUSTACHE_TEXT), SetFill(1, 0),
    01076               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_LIPS_MOUSTACHE_L), SetDataTip(AWV_DECREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP),
    01077               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_LIPS_MOUSTACHE), SetDataTip(STR_EMPTY, STR_FACE_LIPS_MOUSTACHE_TOOLTIP),
    01078               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_LIPS_MOUSTACHE_R), SetDataTip(AWV_INCREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP),
    01079             EndContainer(),
    01080             NWidget(NWID_HORIZONTAL),
    01081               NWidget(WWT_EMPTY, INVALID_COLOUR, SCMFW_WIDGET_CHIN_TEXT), SetFill(1, 0),
    01082               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_CHIN_L), SetDataTip(AWV_DECREASE, STR_FACE_CHIN_TOOLTIP),
    01083               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_CHIN), SetDataTip(STR_EMPTY, STR_FACE_CHIN_TOOLTIP),
    01084               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_CHIN_R), SetDataTip(AWV_INCREASE, STR_FACE_CHIN_TOOLTIP),
    01085             EndContainer(),
    01086             NWidget(NWID_HORIZONTAL),
    01087               NWidget(WWT_EMPTY, INVALID_COLOUR, SCMFW_WIDGET_JACKET_TEXT), SetFill(1, 0),
    01088               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_JACKET_L), SetDataTip(AWV_DECREASE, STR_FACE_JACKET_TOOLTIP),
    01089               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_JACKET), SetDataTip(STR_EMPTY, STR_FACE_JACKET_TOOLTIP),
    01090               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_JACKET_R), SetDataTip(AWV_INCREASE, STR_FACE_JACKET_TOOLTIP),
    01091             EndContainer(),
    01092             NWidget(NWID_HORIZONTAL),
    01093               NWidget(WWT_EMPTY, INVALID_COLOUR, SCMFW_WIDGET_COLLAR_TEXT), SetFill(1, 0),
    01094               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_COLLAR_L), SetDataTip(AWV_DECREASE, STR_FACE_COLLAR_TOOLTIP),
    01095               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_COLLAR), SetDataTip(STR_EMPTY, STR_FACE_COLLAR_TOOLTIP),
    01096               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_COLLAR_R), SetDataTip(AWV_INCREASE, STR_FACE_COLLAR_TOOLTIP),
    01097             EndContainer(),
    01098             NWidget(NWID_HORIZONTAL),
    01099               NWidget(WWT_EMPTY, INVALID_COLOUR, SCMFW_WIDGET_TIE_EARRING_TEXT), SetFill(1, 0),
    01100               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_TIE_EARRING_L), SetDataTip(AWV_DECREASE, STR_FACE_TIE_EARRING_TOOLTIP),
    01101               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_TIE_EARRING), SetDataTip(STR_EMPTY, STR_FACE_TIE_EARRING_TOOLTIP),
    01102               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_TIE_EARRING_R), SetDataTip(AWV_INCREASE, STR_FACE_TIE_EARRING_TOOLTIP),
    01103             EndContainer(),
    01104             NWidget(NWID_SPACER), SetFill(0, 1),
    01105           EndContainer(),
    01106         EndContainer(),
    01107       EndContainer(),
    01108     EndContainer(),
    01109     NWidget(NWID_SPACER), SetMinimalSize(0, 2),
    01110   EndContainer(),
    01111   NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
    01112     NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_CANCEL), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_FACE_CANCEL_TOOLTIP),
    01113     NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_ACCEPT), SetFill(1, 0), SetDataTip(STR_BUTTON_OK, STR_FACE_OK_TOOLTIP),
    01114   EndContainer(),
    01115 };
    01116
    01118 class SelectCompanyManagerFaceWindow : public Window
    01119 {
    01120   CompanyManagerFace face;
    01121   bool advanced;
    01122
    01123   GenderEthnicity ge;
    01124   bool is_female;
    01125   bool is_moust_male;
    01126
    01127   Dimension yesno_dim;
    01128   Dimension number_dim;
    01129
    01130   static const StringID PART_TEXTS_IS_FEMALE[];
    01131   static const StringID PART_TEXTS[];
    01132
    01140   void DrawFaceStringLabel(byte widget_index, uint8 val, bool is_bool_widget) const
    01141   {
    01142     StringID str;
    01143     const NWidgetCore *nwi_widget = this->GetWidget<NWidgetCore>(widget_index);
    01144     if (!nwi_widget->IsDisabled()) {
    01145       if (is_bool_widget) {
    01146         /* if it a bool button write yes or no */
    01147         str = (val != 0) ? STR_FACE_YES : STR_FACE_NO;
    01148       } else {
    01149         /* else write the value + 1 */
    01150         SetDParam(0, val + 1);
    01151         str = STR_JUST_INT;
    01152       }
    01153
    01154       /* Draw the value/bool in white (0xC). If the button clicked adds 1px to x and y text coordinates (IsWindowWidgetLowered()). */
    01155       DrawString(nwi_widget->pos_x + nwi_widget->IsLowered(), nwi_widget->pos_x + nwi_widget->current_x - 1 - nwi_widget->IsLowered(),
    01156           nwi_widget->pos_y + 1 + nwi_widget->IsLowered(), str, TC_WHITE, SA_HOR_CENTER);
    01157     }
    01158   }
    01159
    01160   void UpdateData()
    01161   {
    01162     this->ge = (GenderEthnicity)GB(this->face, _cmf_info[CMFV_GEN_ETHN].offset, _cmf_info[CMFV_GEN_ETHN].length); // get the gender and ethnicity
    01163     this->is_female = HasBit(this->ge, GENDER_FEMALE); // get the gender: 0 == male and 1 == female
    01164     this->is_moust_male = !is_female && GetCompanyManagerFaceBits(this->face, CMFV_HAS_MOUSTACHE, this->ge) != 0; // is a male face with moustache
    01165   }
    01166
    01167 public:
    01168   SelectCompanyManagerFaceWindow(const WindowDesc *desc, Window *parent) : Window()
    01169   {
    01170     this->advanced = false;
    01171     this->CreateNestedTree(desc);
    01172     this->SelectDisplayPlanes(this->advanced);
    01173     this->FinishInitNested(desc, parent->window_number);
    01174     this->parent = parent;
    01175     this->owner = (Owner)this->window_number;
    01176     this->face = Company::Get((CompanyID)this->window_number)->face;
    01177
    01178     this->UpdateData();
    01179   }
    01180
    01185   void SelectDisplayPlanes(bool advanced)
    01186   {
    01187     this->GetWidget<NWidgetStacked>(SCMFW_WIDGET_SEL_LOADSAVE)->SetDisplayedPlane(advanced ? 0 : SZSP_NONE);
    01188     this->GetWidget<NWidgetStacked>(SCMFW_WIDGET_SEL_PARTS)->SetDisplayedPlane(advanced ? 0 : SZSP_NONE);
    01189     this->GetWidget<NWidgetStacked>(SCMFW_WIDGET_SEL_MALEFEMALE)->SetDisplayedPlane(advanced ? SZSP_NONE : 0);
    01190     this->GetWidget<NWidgetCore>(SCMFW_WIDGET_RANDOM_NEW_FACE)->widget_data = advanced ? STR_MAPGEN_RANDOM : STR_FACE_NEW_FACE_BUTTON;
    01191
    01192     NWidgetCore *wi = this->GetWidget<NWidgetCore>(SCMFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON);
    01193     if (advanced) {
    01194       wi->SetDataTip(STR_FACE_SIMPLE, STR_FACE_SIMPLE_TOOLTIP);
    01195     } else {
    01196       wi->SetDataTip(STR_FACE_ADVANCED, STR_FACE_ADVANCED_TOOLTIP);
    01197     }
    01198   }
    01199
    01200   virtual void OnInit()
    01201   {
    01202     /* Size of the boolean yes/no button. */
    01203     Dimension yesno_dim = maxdim(GetStringBoundingBox(STR_FACE_YES), GetStringBoundingBox(STR_FACE_NO));
    01204     yesno_dim.width  += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
    01205     yesno_dim.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
    01206     /* Size of the number button + arrows. */
    01207     Dimension number_dim = {0, 0};
    01208     for (int val = 1; val <= 12; val++) {
    01209       SetDParam(0, val);
    01210       number_dim = maxdim(number_dim, GetStringBoundingBox(STR_JUST_INT));
    01211     }
    01212     uint arrows_width = GetSpriteSize(SPR_ARROW_LEFT).width + GetSpriteSize(SPR_ARROW_RIGHT).width + 2 * (WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT);
    01213     number_dim.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT + arrows_width;
    01214     number_dim.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
    01215     /* Compute width of both buttons. */
    01216     yesno_dim.width = max(yesno_dim.width, number_dim.width);
    01217     number_dim.width = yesno_dim.width - arrows_width;
    01218
    01219     this->yesno_dim = yesno_dim;
    01220     this->number_dim = number_dim;
    01221   }
    01222
    01223   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
    01224   {
    01225     switch (widget) {
    01226       case SCMFW_WIDGET_HAS_MOUSTACHE_EARRING_TEXT:
    01227       case SCMFW_WIDGET_TIE_EARRING_TEXT: {
    01228         int offset = (widget - SCMFW_WIDGET_HAS_MOUSTACHE_EARRING_TEXT) * 2;
    01229         *size = maxdim(GetStringBoundingBox(PART_TEXTS_IS_FEMALE[offset]), GetStringBoundingBox(PART_TEXTS_IS_FEMALE[offset + 1]));
    01230         size->width  += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
    01231         size->height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
    01232         break;
    01233       }
    01234
    01235       case SCMFW_WIDGET_LIPS_MOUSTACHE_TEXT:
    01236         *size = maxdim(GetStringBoundingBox(STR_FACE_LIPS), GetStringBoundingBox(STR_FACE_MOUSTACHE));
    01237         size->width  += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
    01238         size->height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
    01239         break;
    01240
    01241       case SCMFW_WIDGET_HAS_GLASSES_TEXT:
    01242       case SCMFW_WIDGET_HAIR_TEXT:
    01243       case SCMFW_WIDGET_EYEBROWS_TEXT:
    01244       case SCMFW_WIDGET_EYECOLOUR_TEXT:
    01245       case SCMFW_WIDGET_GLASSES_TEXT:
    01246       case SCMFW_WIDGET_NOSE_TEXT:
    01247       case SCMFW_WIDGET_CHIN_TEXT:
    01248       case SCMFW_WIDGET_JACKET_TEXT:
    01249       case SCMFW_WIDGET_COLLAR_TEXT:
    01250         *size = GetStringBoundingBox(PART_TEXTS[widget - SCMFW_WIDGET_HAS_GLASSES_TEXT]);
    01251         size->width  += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
    01252         size->height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
    01253         break;
    01254
    01255       case SCMFW_WIDGET_HAS_MOUSTACHE_EARRING:
    01256       case SCMFW_WIDGET_HAS_GLASSES:
    01257         *size = this->yesno_dim;
    01258         break;
    01259
    01260       case SCMFW_WIDGET_EYECOLOUR:
    01261       case SCMFW_WIDGET_CHIN:
    01262       case SCMFW_WIDGET_EYEBROWS:
    01263       case SCMFW_WIDGET_LIPS_MOUSTACHE:
    01264       case SCMFW_WIDGET_NOSE:
    01265       case SCMFW_WIDGET_HAIR:
    01266       case SCMFW_WIDGET_JACKET:
    01267       case SCMFW_WIDGET_COLLAR:
    01268       case SCMFW_WIDGET_TIE_EARRING:
    01269       case SCMFW_WIDGET_GLASSES:
    01270         *size = this->number_dim;
    01271         break;
    01272     }
    01273   }
    01274
    01275   virtual void OnPaint()
    01276   {
    01277     /* lower the non-selected gender button */
    01278     this->SetWidgetsLoweredState(!this->is_female, SCMFW_WIDGET_MALE, SCMFW_WIDGET_MALE2, WIDGET_LIST_END);
    01279     this->SetWidgetsLoweredState( this->is_female, SCMFW_WIDGET_FEMALE, SCMFW_WIDGET_FEMALE2, WIDGET_LIST_END);
    01280
    01281     /* advanced company manager face selection window */
    01282
    01283     /* lower the non-selected ethnicity button */
    01284     this->SetWidgetLoweredState(SCMFW_WIDGET_ETHNICITY_EUR, !HasBit(this->ge, ETHNICITY_BLACK));
    01285     this->SetWidgetLoweredState(SCMFW_WIDGET_ETHNICITY_AFR,  HasBit(this->ge, ETHNICITY_BLACK));
    01286
    01287
    01288     /* Disable dynamically the widgets which CompanyManagerFaceVariable has less than 2 options
    01289      * (or in other words you haven't any choice).
    01290      * If the widgets depend on a HAS-variable and this is false the widgets will be disabled, too. */
    01291
    01292     /* Eye colour buttons */
    01293     this->SetWidgetsDisabledState(_cmf_info[CMFV_EYE_COLOUR].valid_values[this->ge] < 2,
    01294         SCMFW_WIDGET_EYECOLOUR, SCMFW_WIDGET_EYECOLOUR_L, SCMFW_WIDGET_EYECOLOUR_R, WIDGET_LIST_END);
    01295
    01296     /* Chin buttons */
    01297     this->SetWidgetsDisabledState(_cmf_info[CMFV_CHIN].valid_values[this->ge] < 2,
    01298         SCMFW_WIDGET_CHIN, SCMFW_WIDGET_CHIN_L, SCMFW_WIDGET_CHIN_R, WIDGET_LIST_END);
    01299
    01300     /* Eyebrows buttons */
    01301     this->SetWidgetsDisabledState(_cmf_info[CMFV_EYEBROWS].valid_values[this->ge] < 2,
    01302         SCMFW_WIDGET_EYEBROWS, SCMFW_WIDGET_EYEBROWS_L, SCMFW_WIDGET_EYEBROWS_R, WIDGET_LIST_END);
    01303
    01304     /* Lips or (if it a male face with a moustache) moustache buttons */
    01305     this->SetWidgetsDisabledState(_cmf_info[this->is_moust_male ? CMFV_MOUSTACHE : CMFV_LIPS].valid_values[this->ge] < 2,
    01306         SCMFW_WIDGET_LIPS_MOUSTACHE, SCMFW_WIDGET_LIPS_MOUSTACHE_L, SCMFW_WIDGET_LIPS_MOUSTACHE_R, WIDGET_LIST_END);
    01307
    01308     /* Nose buttons | male faces with moustache haven't any nose options */
    01309     this->SetWidgetsDisabledState(_cmf_info[CMFV_NOSE].valid_values[this->ge] < 2 || this->is_moust_male,
    01310         SCMFW_WIDGET_NOSE, SCMFW_WIDGET_NOSE_L, SCMFW_WIDGET_NOSE_R, WIDGET_LIST_END);
    01311
    01312     /* Hair buttons */
    01313     this->SetWidgetsDisabledState(_cmf_info[CMFV_HAIR].valid_values[this->ge] < 2,
    01314         SCMFW_WIDGET_HAIR, SCMFW_WIDGET_HAIR_L, SCMFW_WIDGET_HAIR_R, WIDGET_LIST_END);
    01315
    01316     /* Jacket buttons */
    01317     this->SetWidgetsDisabledState(_cmf_info[CMFV_JACKET].valid_values[this->ge] < 2,
    01318         SCMFW_WIDGET_JACKET, SCMFW_WIDGET_JACKET_L, SCMFW_WIDGET_JACKET_R, WIDGET_LIST_END);
    01319
    01320     /* Collar buttons */
    01321     this->SetWidgetsDisabledState(_cmf_info[CMFV_COLLAR].valid_values[this->ge] < 2,
    01322         SCMFW_WIDGET_COLLAR, SCMFW_WIDGET_COLLAR_L, SCMFW_WIDGET_COLLAR_R, WIDGET_LIST_END);
    01323
    01324     /* Tie/earring buttons | female faces without earring haven't any earring options */
    01325     this->SetWidgetsDisabledState(_cmf_info[CMFV_TIE_EARRING].valid_values[this->ge] < 2 ||
    01326           (this->is_female && GetCompanyManagerFaceBits(this->face, CMFV_HAS_TIE_EARRING, this->ge) == 0),
    01327         SCMFW_WIDGET_TIE_EARRING, SCMFW_WIDGET_TIE_EARRING_L, SCMFW_WIDGET_TIE_EARRING_R, WIDGET_LIST_END);
    01328
    01329     /* Glasses buttons | faces without glasses haven't any glasses options */
    01330     this->SetWidgetsDisabledState(_cmf_info[CMFV_GLASSES].valid_values[this->ge] < 2 || GetCompanyManagerFaceBits(this->face, CMFV_HAS_GLASSES, this->ge) == 0,
    01331         SCMFW_WIDGET_GLASSES, SCMFW_WIDGET_GLASSES_L, SCMFW_WIDGET_GLASSES_R, WIDGET_LIST_END);
    01332
    01333     this->DrawWidgets();
    01334   }
    01335
    01336   virtual void DrawWidget(const Rect &r, int widget) const
    01337   {
    01338     switch (widget) {
    01339       case SCMFW_WIDGET_HAS_MOUSTACHE_EARRING_TEXT:
    01340       case SCMFW_WIDGET_TIE_EARRING_TEXT: {
    01341         StringID str = PART_TEXTS_IS_FEMALE[(widget - SCMFW_WIDGET_HAS_MOUSTACHE_EARRING_TEXT) * 2 + this->is_female];
    01342         DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, str, TC_GOLD, SA_RIGHT);
    01343         break;
    01344       }
    01345
    01346       case SCMFW_WIDGET_LIPS_MOUSTACHE_TEXT:
    01347         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);
    01348         break;
    01349
    01350       case SCMFW_WIDGET_HAS_GLASSES_TEXT:
    01351       case SCMFW_WIDGET_HAIR_TEXT:
    01352       case SCMFW_WIDGET_EYEBROWS_TEXT:
    01353       case SCMFW_WIDGET_EYECOLOUR_TEXT:
    01354       case SCMFW_WIDGET_GLASSES_TEXT:
    01355       case SCMFW_WIDGET_NOSE_TEXT:
    01356       case SCMFW_WIDGET_CHIN_TEXT:
    01357       case SCMFW_WIDGET_JACKET_TEXT:
    01358       case SCMFW_WIDGET_COLLAR_TEXT:
    01359         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);
    01360         break;
    01361
    01362
    01363       case SCMFW_WIDGET_HAS_MOUSTACHE_EARRING:
    01364         if (this->is_female) { // Only for female faces
    01365           this->DrawFaceStringLabel(SCMFW_WIDGET_HAS_MOUSTACHE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_HAS_TIE_EARRING, this->ge), true);
    01366         } else { // Only for male faces
    01367           this->DrawFaceStringLabel(SCMFW_WIDGET_HAS_MOUSTACHE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_HAS_MOUSTACHE,   this->ge), true);
    01368         }
    01369         break;
    01370
    01371       case SCMFW_WIDGET_TIE_EARRING:
    01372         if (this->is_female) { // Only for female faces
    01373           this->DrawFaceStringLabel(SCMFW_WIDGET_TIE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_TIE_EARRING, this->ge), false);
    01374         } else { // Only for male faces
    01375           this->DrawFaceStringLabel(SCMFW_WIDGET_TIE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_TIE_EARRING, this->ge), false);
    01376         }
    01377         break;
    01378
    01379       case SCMFW_WIDGET_LIPS_MOUSTACHE:
    01380         if (this->is_moust_male) { // Only for male faces with moustache
    01381           this->DrawFaceStringLabel(SCMFW_WIDGET_LIPS_MOUSTACHE, GetCompanyManagerFaceBits(this->face, CMFV_MOUSTACHE, this->ge), false);
    01382         } else { // Only for female faces or male faces without moustache
    01383           this->DrawFaceStringLabel(SCMFW_WIDGET_LIPS_MOUSTACHE, GetCompanyManagerFaceBits(this->face, CMFV_LIPS,      this->ge), false);
    01384         }
    01385         break;
    01386
    01387       case SCMFW_WIDGET_HAS_GLASSES:
    01388         this->DrawFaceStringLabel(SCMFW_WIDGET_HAS_GLASSES, GetCompanyManagerFaceBits(this->face, CMFV_HAS_GLASSES, this->ge), true );
    01389         break;
    01390
    01391       case SCMFW_WIDGET_HAIR:
    01392         this->DrawFaceStringLabel(SCMFW_WIDGET_HAIR,        GetCompanyManagerFaceBits(this->face, CMFV_HAIR,        this->ge), false);
    01393         break;
    01394
    01395       case SCMFW_WIDGET_EYEBROWS:
    01396         this->DrawFaceStringLabel(SCMFW_WIDGET_EYEBROWS,    GetCompanyManagerFaceBits(this->face, CMFV_EYEBROWS,    this->ge), false);
    01397         break;
    01398
    01399       case SCMFW_WIDGET_EYECOLOUR:
    01400         this->DrawFaceStringLabel(SCMFW_WIDGET_EYECOLOUR,   GetCompanyManagerFaceBits(this->face, CMFV_EYE_COLOUR,  this->ge), false);
    01401         break;
    01402
    01403       case SCMFW_WIDGET_GLASSES:
    01404         this->DrawFaceStringLabel(SCMFW_WIDGET_GLASSES,     GetCompanyManagerFaceBits(this->face, CMFV_GLASSES,     this->ge), false);
    01405         break;
    01406
    01407       case SCMFW_WIDGET_NOSE:
    01408         this->DrawFaceStringLabel(SCMFW_WIDGET_NOSE,        GetCompanyManagerFaceBits(this->face, CMFV_NOSE,        this->ge), false);
    01409         break;
    01410
    01411       case SCMFW_WIDGET_CHIN:
    01412         this->DrawFaceStringLabel(SCMFW_WIDGET_CHIN,        GetCompanyManagerFaceBits(this->face, CMFV_CHIN,        this->ge), false);
    01413         break;
    01414
    01415       case SCMFW_WIDGET_JACKET:
    01416         this->DrawFaceStringLabel(SCMFW_WIDGET_JACKET,      GetCompanyManagerFaceBits(this->face, CMFV_JACKET,      this->ge), false);
    01417         break;
    01418
    01419       case SCMFW_WIDGET_COLLAR:
    01420         this->DrawFaceStringLabel(SCMFW_WIDGET_COLLAR,      GetCompanyManagerFaceBits(this->face, CMFV_COLLAR,      this->ge), false);
    01421         break;
    01422
    01423       case SCMFM_WIDGET_FACE:
    01424         DrawCompanyManagerFace(this->face, Company::Get((CompanyID)this->window_number)->colour, r.left, r.top);
    01425         break;
    01426     }
    01427   }
    01428
    01429   virtual void OnClick(Point pt, int widget, int click_count)
    01430   {
    01431     switch (widget) {
    01432       /* Toggle size, advanced/simple face selection */
    01433       case SCMFW_WIDGET_TOGGLE_LARGE_SMALL:
    01434       case SCMFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON:
    01435         this->advanced = !this->advanced;
    01436         this->SelectDisplayPlanes(this->advanced);
    01437         this->ReInit();
    01438         break;
    01439
    01440       /* OK button */
    01441       case SCMFW_WIDGET_ACCEPT:
    01442         DoCommandP(0, 0, this->face, CMD_SET_COMPANY_MANAGER_FACE);
    01443         /* FALL THROUGH */
    01444
    01445       /* Cancel button */
    01446       case SCMFW_WIDGET_CANCEL:
    01447         delete this;
    01448         break;
    01449
    01450       /* Load button */
    01451       case SCMFW_WIDGET_LOAD:
    01452         this->face = _company_manager_face;
    01453         ScaleAllCompanyManagerFaceBits(this->face);
    01454         ShowErrorMessage(STR_FACE_LOAD_DONE, INVALID_STRING_ID, WL_INFO);
    01455         this->UpdateData();
    01456         this->SetDirty();
    01457         break;
    01458
    01459       /* 'Company manager face number' button, view and/or set company manager face number */
    01460       case SCMFW_WIDGET_FACECODE:
    01461         SetDParam(0, this->face);
    01462         ShowQueryString(STR_JUST_INT, STR_FACE_FACECODE_CAPTION, 10 + 1, this, CS_NUMERAL, QSF_NONE);
    01463         break;
    01464
    01465       /* Save button */
    01466       case SCMFW_WIDGET_SAVE:
    01467         _company_manager_face = this->face;
    01468         ShowErrorMessage(STR_FACE_SAVE_DONE, INVALID_STRING_ID, WL_INFO);
    01469         break;
    01470
    01471       /* Toggle gender (male/female) button */
    01472       case SCMFW_WIDGET_MALE:
    01473       case SCMFW_WIDGET_FEMALE:
    01474       case SCMFW_WIDGET_MALE2:
    01475       case SCMFW_WIDGET_FEMALE2:
    01476         SetCompanyManagerFaceBits(this->face, CMFV_GENDER, this->ge, (widget == SCMFW_WIDGET_FEMALE || widget == SCMFW_WIDGET_FEMALE2));
    01477         ScaleAllCompanyManagerFaceBits(this->face);
    01478         this->UpdateData();
    01479         this->SetDirty();
    01480         break;
    01481
    01482       /* Randomize face button */
    01483       case SCMFW_WIDGET_RANDOM_NEW_FACE:
    01484         RandomCompanyManagerFaceBits(this->face, this->ge, this->advanced);
    01485         this->UpdateData();
    01486         this->SetDirty();
    01487         break;
    01488
    01489       /* Toggle ethnicity (european/african) button */
    01490       case SCMFW_WIDGET_ETHNICITY_EUR:
    01491       case SCMFW_WIDGET_ETHNICITY_AFR:
    01492         SetCompanyManagerFaceBits(this->face, CMFV_ETHNICITY, this->ge, widget - SCMFW_WIDGET_ETHNICITY_EUR);
    01493         ScaleAllCompanyManagerFaceBits(this->face);
    01494         this->UpdateData();
    01495         this->SetDirty();
    01496         break;
    01497
    01498       default:
    01499         /* Here all buttons from SCMFW_WIDGET_HAS_MOUSTACHE_EARRING to SCMFW_WIDGET_GLASSES_R are handled.
    01500          * First it checks which CompanyManagerFaceVariable is being changed, and then either
    01501          * a: invert the value for boolean variables, or
    01502          * b: it checks inside of IncreaseCompanyManagerFaceBits() if a left (_L) butten is pressed and then decrease else increase the variable */
    01503         if (widget >= SCMFW_WIDGET_HAS_MOUSTACHE_EARRING && widget <= SCMFW_WIDGET_GLASSES_R) {
    01504           CompanyManagerFaceVariable cmfv; // which CompanyManagerFaceVariable shall be edited
    01505
    01506           if (widget < SCMFW_WIDGET_EYECOLOUR_L) { // Bool buttons
    01507             switch (widget - SCMFW_WIDGET_HAS_MOUSTACHE_EARRING) {
    01508               default: NOT_REACHED();
    01509               case 0: cmfv = this->is_female ? CMFV_HAS_TIE_EARRING : CMFV_HAS_MOUSTACHE; break; // Has earring/moustache button
    01510               case 1: cmfv = CMFV_HAS_GLASSES; break; // Has glasses button
    01511             }
    01512             SetCompanyManagerFaceBits(this->face, cmfv, this->ge, !GetCompanyManagerFaceBits(this->face, cmfv, this->ge));
    01513             ScaleAllCompanyManagerFaceBits(this->face);
    01514           } else { // Value buttons
    01515             switch ((widget - SCMFW_WIDGET_EYECOLOUR_L) / 3) {
    01516               default: NOT_REACHED();
    01517               case 0: cmfv = CMFV_EYE_COLOUR; break;  // Eye colour buttons
    01518               case 1: cmfv = CMFV_CHIN; break;        // Chin buttons
    01519               case 2: cmfv = CMFV_EYEBROWS; break;    // Eyebrows buttons
    01520               case 3: cmfv = this->is_moust_male ? CMFV_MOUSTACHE : CMFV_LIPS; break; // Moustache or lips buttons
    01521               case 4: cmfv = CMFV_NOSE; break;        // Nose buttons
    01522               case 5: cmfv = CMFV_HAIR; break;        // Hair buttons
    01523               case 6: cmfv = CMFV_JACKET; break;      // Jacket buttons
    01524               case 7: cmfv = CMFV_COLLAR; break;      // Collar buttons
    01525               case 8: cmfv = CMFV_TIE_EARRING; break; // Tie/earring buttons
    01526               case 9: cmfv = CMFV_GLASSES; break;     // Glasses buttons
    01527             }
    01528             /* 0 == left (_L), 1 == middle or 2 == right (_R) - button click */
    01529             IncreaseCompanyManagerFaceBits(this->face, cmfv, this->ge, (((widget - SCMFW_WIDGET_EYECOLOUR_L) % 3) != 0) ? 1 : -1);
    01530           }
    01531           this->UpdateData();
    01532           this->SetDirty();
    01533         }
    01534         break;
    01535     }
    01536   }
    01537
    01538   virtual void OnQueryTextFinished(char *str)
    01539   {
    01540     if (str == NULL) return;
    01541     /* Set a new company manager face number */
    01542     if (!StrEmpty(str)) {
    01543       this->face = strtoul(str, NULL, 10);
    01544       ScaleAllCompanyManagerFaceBits(this->face);
    01545       ShowErrorMessage(STR_FACE_FACECODE_SET, INVALID_STRING_ID, WL_INFO);
    01546       this->UpdateData();
    01547       this->SetDirty();
    01548     } else {
    01549       ShowErrorMessage(STR_FACE_FACECODE_ERR, INVALID_STRING_ID, WL_INFO);
    01550     }
    01551   }
    01552 };
    01553
    01555 const StringID SelectCompanyManagerFaceWindow::PART_TEXTS_IS_FEMALE[] = {
    01556   STR_FACE_MOUSTACHE, STR_FACE_EARRING, // SCMFW_WIDGET_HAS_MOUSTACHE_EARRING_TEXT
    01557   STR_FACE_TIE,       STR_FACE_EARRING, // SCMFW_WIDGET_TIE_EARRING_TEXT
    01558 };
    01559
    01561 const StringID SelectCompanyManagerFaceWindow::PART_TEXTS[] = {
    01562   STR_FACE_GLASSES,   // SCMFW_WIDGET_HAS_GLASSES_TEXT
    01563   STR_FACE_HAIR,      // SCMFW_WIDGET_HAIR_TEXT
    01564   STR_FACE_EYEBROWS,  // SCMFW_WIDGET_EYEBROWS_TEXT
    01565   STR_FACE_EYECOLOUR, // SCMFW_WIDGET_EYECOLOUR_TEXT
    01566   STR_FACE_GLASSES,   // SCMFW_WIDGET_GLASSES_TEXT
    01567   STR_FACE_NOSE,      // SCMFW_WIDGET_NOSE_TEXT
    01568   STR_FACE_CHIN,      // SCMFW_WIDGET_CHIN_TEXT
    01569   STR_FACE_JACKET,    // SCMFW_WIDGET_JACKET_TEXT
    01570   STR_FACE_COLLAR,    // SCMFW_WIDGET_COLLAR_TEXT
    01571 };
    01572
    01574 static const WindowDesc _select_company_manager_face_desc(
    01575   WDP_AUTO, 0, 0,
    01576   WC_COMPANY_MANAGER_FACE, WC_NONE,
    01577   WDF_UNCLICK_BUTTONS | WDF_CONSTRUCTION,
    01578   _nested_select_company_manager_face_widgets, lengthof(_nested_select_company_manager_face_widgets)
    01579 );
    01580
    01589 static void DoSelectCompanyManagerFace(Window *parent)
    01590 {
    01591   if (!Company::IsValidID((CompanyID)parent->window_number)) return;
    01592
    01593   if (BringWindowToFrontById(WC_COMPANY_MANAGER_FACE, parent->window_number)) return;
    01594   new SelectCompanyManagerFaceWindow(&_select_company_manager_face_desc, parent);
    01595 }
    01596
    01597
    01599 enum CompanyWindowWidgets {
    01600   CW_WIDGET_CAPTION,
    01601
    01602   CW_WIDGET_FACE,
    01603   CW_WIDGET_FACE_TITLE,
    01604
    01605   CW_WIDGET_DESC_INAUGURATION,
    01606   CW_WIDGET_DESC_COLOUR_SCHEME,
    01607   CW_WIDGET_DESC_COLOUR_SCHEME_EXAMPLE,
    01608   CW_WIDGET_DESC_VEHICLE,
    01609   CW_WIDGET_DESC_VEHICLE_COUNTS,
    01610   CW_WIDGET_DESC_COMPANY_VALUE,
    01611   CW_WIDGET_DESC_OWNERS,
    01612
    01613   CW_WIDGET_SELECT_BUTTONS,
    01614   CW_WIDGET_NEW_FACE,
    01615   CW_WIDGET_COLOUR_SCHEME,
    01616   CW_WIDGET_PRESIDENT_NAME,
    01617   CW_WIDGET_COMPANY_NAME,
    01618   CW_WIDGET_BUY_SHARE,
    01619   CW_WIDGET_SELL_SHARE,
    01620
    01621   CW_WIDGET_SELECT_VIEW_BUILD_HQ,
    01622   CW_WIDGET_VIEW_HQ,
    01623   CW_WIDGET_BUILD_HQ,
    01624
    01625   CW_WIDGET_SELECT_RELOCATE,
    01626   CW_WIDGET_RELOCATE_HQ,
    01627
    01628   CW_WIDGET_PROFILE_LOAD,
    01629   CW_WIDGET_PROFILE_SAVE,
    01630
    01631   CW_WIDGET_HAS_PASSWORD,
    01632   CW_WIDGET_SELECT_MULTIPLAYER,
    01633   CW_WIDGET_COMPANY_PASSWORD,
    01634   CW_WIDGET_COMPANY_JOIN,
    01635 };
    01636
    01637 static const NWidgetPart _nested_company_widgets[] = {
    01638   NWidget(NWID_HORIZONTAL),
    01639     NWidget(WWT_CLOSEBOX, COLOUR_GREY),
    01640     NWidget(WWT_CAPTION, COLOUR_GREY, CW_WIDGET_CAPTION), SetDataTip(STR_COMPANY_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    01641     NWidget(WWT_SHADEBOX, COLOUR_GREY),
    01642     NWidget(WWT_STICKYBOX, COLOUR_GREY),
    01643   EndContainer(),
    01644   NWidget(WWT_PANEL, COLOUR_GREY),
    01645     NWidget(NWID_HORIZONTAL), SetPIP(4, 6, 4),
    01646       NWidget(NWID_VERTICAL), SetPIP(4, 2, 4),
    01647         NWidget(WWT_EMPTY, INVALID_COLOUR, CW_WIDGET_FACE), SetMinimalSize(92, 119), SetFill(1, 0),
    01648         NWidget(WWT_EMPTY, INVALID_COLOUR, CW_WIDGET_FACE_TITLE), SetFill(1, 1), SetMinimalTextLines(2, 0),
    01649       EndContainer(),
    01650       NWidget(NWID_VERTICAL),
    01651         NWidget(NWID_HORIZONTAL),
    01652           NWidget(NWID_VERTICAL), SetPIP(4, 5, 5),
    01653             NWidget(WWT_TEXT, COLOUR_GREY, CW_WIDGET_DESC_INAUGURATION), SetDataTip(STR_COMPANY_VIEW_INAUGURATED_TITLE, STR_NULL), SetFill(1, 0),
    01654             NWidget(NWID_HORIZONTAL), SetPIP(0, 5, 0),
    01655               NWidget(WWT_LABEL, COLOUR_GREY, CW_WIDGET_DESC_COLOUR_SCHEME), SetDataTip(STR_COMPANY_VIEW_COLOUR_SCHEME_TITLE, STR_NULL),
    01656               NWidget(WWT_EMPTY, INVALID_COLOUR, CW_WIDGET_DESC_COLOUR_SCHEME_EXAMPLE), SetMinimalSize(30, 0), SetFill(0, 1),
    01657               NWidget(NWID_SPACER), SetFill(1, 0),
    01658             EndContainer(),
    01659             NWidget(NWID_HORIZONTAL), SetPIP(0, 4, 0),
    01660               NWidget(NWID_VERTICAL),
    01661                 NWidget(WWT_TEXT, COLOUR_GREY, CW_WIDGET_DESC_VEHICLE), SetDataTip(STR_COMPANY_VIEW_VEHICLES_TITLE, STR_NULL),
    01662                 NWidget(NWID_SPACER), SetFill(0, 1),
    01663               EndContainer(),
    01664               NWidget(WWT_EMPTY, INVALID_COLOUR, CW_WIDGET_DESC_VEHICLE_COUNTS), SetMinimalTextLines(4, 0),
    01665               NWidget(NWID_SPACER), SetFill(1, 0),
    01666             EndContainer(),
    01667           EndContainer(),
    01668           NWidget(NWID_VERTICAL), SetPIP(4, 2, 4),
    01669             NWidget(NWID_SELECTION, INVALID_COLOUR, CW_WIDGET_SELECT_VIEW_BUILD_HQ),
    01670               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),
    01671               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),
    01672             EndContainer(),
    01673             NWidget(NWID_SELECTION, INVALID_COLOUR, CW_WIDGET_SELECT_RELOCATE),
    01674               NWidget(WWT_TEXTBTN, COLOUR_GREY, CW_WIDGET_RELOCATE_HQ), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_RELOCATE_HQ, STR_COMPANY_VIEW_RELOCATE_COMPANY_HEADQUARTERS),
    01675               NWidget(NWID_SPACER), SetMinimalSize(90, 0),
    01676             EndContainer(),
    01677             /* Company Profile buttons */
    01678             NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CW_WIDGET_PROFILE_LOAD), SetFill(1, 0), SetDataTip(STR_COMPANY_PROFILE_LOAD_BUTTON, STR_COMPANY_PROFILE_LOAD_TOOLTIP),
    01679             NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CW_WIDGET_PROFILE_SAVE), SetFill(1, 0), SetDataTip(STR_COMPANY_PROFILE_SAVE_BUTTON, STR_COMPANY_PROFILE_SAVE_TOOLTIP),
    01680             NWidget(NWID_SPACER), SetFill(0, 1),
    01681           EndContainer(),
    01682         EndContainer(),
    01683         NWidget(WWT_TEXT, COLOUR_GREY, CW_WIDGET_DESC_COMPANY_VALUE), SetDataTip(STR_COMPANY_VIEW_COMPANY_VALUE, STR_NULL), SetFill(1, 0),
    01684         NWidget(NWID_HORIZONTAL),
    01685           NWidget(NWID_VERTICAL), SetPIP(5, 5, 4),
    01686             NWidget(WWT_EMPTY, INVALID_COLOUR, CW_WIDGET_DESC_OWNERS), SetMinimalTextLines(3, 0),
    01687             NWidget(NWID_SPACER), SetFill(0, 1),
    01688           EndContainer(),
    01689           NWidget(NWID_VERTICAL), SetPIP(4, 2, 4),
    01690             NWidget(NWID_SPACER), SetMinimalSize(90, 0), SetFill(0, 1),
    01691             /* Multi player buttons. */
    01692             NWidget(NWID_HORIZONTAL),
    01693               NWidget(WWT_EMPTY, COLOUR_GREY, CW_WIDGET_HAS_PASSWORD),
    01694               NWidget(NWID_SELECTION, INVALID_COLOUR, CW_WIDGET_SELECT_MULTIPLAYER),
    01695                 NWidget(NWID_SPACER), SetFill(1, 0),
    01696                 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CW_WIDGET_COMPANY_PASSWORD), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_PASSWORD, STR_COMPANY_VIEW_PASSWORD_TOOLTIP),
    01697                 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CW_WIDGET_COMPANY_JOIN), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_JOIN, STR_COMPANY_VIEW_JOIN_TOOLTIP),
    01698               EndContainer(),
    01699             EndContainer(),
    01700           EndContainer(),
    01701         EndContainer(),
    01702       EndContainer(),
    01703     EndContainer(),
    01704   EndContainer(),
    01705   /* Button bars at the bottom. */
    01706   NWidget(NWID_SELECTION, INVALID_COLOUR, CW_WIDGET_SELECT_BUTTONS),
    01707     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
    01708       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),
    01709       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),
    01710       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),
    01711       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),
    01712     EndContainer(),
    01713     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
    01714       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),
    01715       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),
    01716     EndContainer(),
    01717   EndContainer(),
    01718 };
    01719
    01720 int GetAmountOwnedBy(const Company *c, Owner owner)
    01721 {
    01722   return (c->share_owners[0] == owner) +
    01723          (c->share_owners[1] == owner) +
    01724          (c->share_owners[2] == owner) +
    01725          (c->share_owners[3] == owner);
    01726 }
    01727
    01729 static const StringID _company_view_vehicle_count_strings[] = {
    01730   STR_COMPANY_VIEW_TRAINS, STR_COMPANY_VIEW_ROAD_VEHICLES, STR_COMPANY_VIEW_SHIPS, STR_COMPANY_VIEW_AIRCRAFT
    01731 };
    01732
    01736 struct CompanyWindow : Window
    01737 {
    01738   CompanyWindowWidgets query_widget;
    01739
    01741   enum CompanyWindowPlanes {
    01742     /* Display planes of the #CW_WIDGET_SELECT_MULTIPLAYER selection widget. */
    01743     CWP_MP_EMPTY = 0,
    01744     CWP_MP_C_PWD,
    01745     CWP_MP_C_JOIN,
    01746
    01747     /* Display planes of the #CW_WIDGET_SELECT_VIEW_BUILD_HQ selection widget. */
    01748     CWP_VB_VIEW = 0,
    01749     CWP_VB_BUILD,
    01750
    01751     /* Display planes of the #CW_WIDGET_SELECT_RELOCATE selection widget. */
    01752     CWP_RELOCATE_SHOW = 0,
    01753     CWP_RELOCATE_HIDE,
    01754
    01755     /* Display planes of the #CW_WIDGET_SELECT_BUTTONS selection widget. */
    01756     CWP_BUTTONS_LOCAL = 0,
    01757     CWP_BUTTONS_OTHER,
    01758   };
    01759
    01760   CompanyWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
    01761   {
    01762     this->InitNested(desc, window_number);
    01763     this->owner = (Owner)this->window_number;
    01764   }
    01765
    01766   virtual void OnPaint()
    01767   {
    01768     const Company *c = Company::Get((CompanyID)this->window_number);
    01769     bool local = this->window_number == _local_company;
    01770
    01771     if (!this->IsShaded()) {
    01772       /* Button bar selection. */
    01773       int plane = local ? CWP_BUTTONS_LOCAL : CWP_BUTTONS_OTHER;
    01774       NWidgetStacked *wi = this->GetWidget<NWidgetStacked>(CW_WIDGET_SELECT_BUTTONS);
    01775       if (plane != wi->shown_plane) {
    01776         wi->SetDisplayedPlane(plane);
    01777         this->SetDirty();
    01778         return;
    01779       }
    01780
    01781       /* Build HQ button handling. */
    01782       plane = (local && c->location_of_HQ == INVALID_TILE) ? CWP_VB_BUILD : CWP_VB_VIEW;
    01783       wi = this->GetWidget<NWidgetStacked>(CW_WIDGET_SELECT_VIEW_BUILD_HQ);
    01784       if (plane != wi->shown_plane) {
    01785         wi->SetDisplayedPlane(plane);
    01786         this->SetDirty();
    01787         return;
    01788       }
    01789
    01790       this->SetWidgetDisabledState(CW_WIDGET_VIEW_HQ, c->location_of_HQ == INVALID_TILE);
    01791
    01792       /* Enable/disable 'Relocate HQ' button. */
    01793       plane = (!local || c->location_of_HQ == INVALID_TILE) ? CWP_RELOCATE_HIDE : CWP_RELOCATE_SHOW;
    01794       wi = this->GetWidget<NWidgetStacked>(CW_WIDGET_SELECT_RELOCATE);
    01795       if (plane != wi->shown_plane) {
    01796         wi->SetDisplayedPlane(plane);
    01797         this->SetDirty();
    01798         return;
    01799       }
    01800
    01801       /* Multiplayer buttons. */
    01802       plane = ((!_networking) ? CWP_MP_EMPTY : (local ? CWP_MP_C_PWD : CWP_MP_C_JOIN));
    01803       wi = this->GetWidget<NWidgetStacked>(CW_WIDGET_SELECT_MULTIPLAYER);
    01804       if (plane != wi->shown_plane) {
    01805         wi->SetDisplayedPlane(plane);
    01806         this->SetDirty();
    01807         return;
    01808       }
    01809       this->SetWidgetDisabledState(CW_WIDGET_COMPANY_JOIN,   c->is_ai);
    01810     }
    01811
    01812     if (!local) {
    01813       /* Not the current player, so disable profile loading/saving */
    01814       this->SetWidgetDisabledState(CW_WIDGET_PROFILE_LOAD, true);
    01815       this->SetWidgetDisabledState(CW_WIDGET_PROFILE_SAVE, true);
    01816
    01817       if (_settings_game.economy.allow_shares) { // Shares are allowed
    01818         /* If all shares are owned by someone (none by nobody), disable buy button */
    01819         this->SetWidgetDisabledState(CW_WIDGET_BUY_SHARE, GetAmountOwnedBy(c, INVALID_OWNER) == 0 ||
    01820             /* Only 25% left to buy. If the company is human, disable buying it up.. TODO issues! */
    01821             (GetAmountOwnedBy(c, INVALID_OWNER) == 1 && !c->is_ai) ||
    01822             /* Spectators cannot do anything of course */
    01823             _local_company == COMPANY_SPECTATOR);
    01824
    01825         /* If the company doesn't own any shares, disable sell button */
    01826         this->SetWidgetDisabledState(CW_WIDGET_SELL_SHARE, (GetAmountOwnedBy(c, _local_company) == 0) ||
    01827             /* Spectators cannot do anything of course */
    01828             _local_company == COMPANY_SPECTATOR);
    01829       } else { // Shares are not allowed, disable buy/sell buttons
    01830         this->DisableWidget(CW_WIDGET_BUY_SHARE);
    01831         this->DisableWidget(CW_WIDGET_SELL_SHARE);
    01832       }
    01833     }
    01834
    01835     this->DrawWidgets();
    01836   }
    01837
    01838   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
    01839   {
    01840     switch (widget) {
    01841       case CW_WIDGET_DESC_COMPANY_VALUE:
    01842         SetDParam(0, INT64_MAX); // Arguably the maximum company value
    01843         size->width = GetStringBoundingBox(STR_COMPANY_VIEW_COMPANY_VALUE).width;
    01844         break;
    01845
    01846       case CW_WIDGET_DESC_VEHICLE_COUNTS:
    01847         SetDParam(0, 5000); // Maximum number of vehicles
    01848         for (uint i = 0; i < lengthof(_company_view_vehicle_count_strings); i++) {
    01849           size->width = max(size->width, GetStringBoundingBox(_company_view_vehicle_count_strings[i]).width);
    01850         }
    01851         break;
    01852
    01853       case CW_WIDGET_DESC_OWNERS: {
    01854         const Company *c2;
    01855
    01856         FOR_ALL_COMPANIES(c2) {
    01857           SetDParam(0, 25);
    01858           SetDParam(1, c2->index);
    01859
    01860           size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_SHARES_OWNED_BY).width);
    01861         }
    01862         break;
    01863       }
    01864
    01865 #ifdef ENABLE_NETWORK
    01866       case CW_WIDGET_HAS_PASSWORD:
    01867         *size = maxdim(*size, GetSpriteSize(SPR_LOCK));
    01868         break;
    01869 #endif /* ENABLE_NETWORK */
    01870     }
    01871   }
    01872
    01873   virtual void DrawWidget(const Rect &r, int widget) const
    01874   {
    01875     const Company *c = Company::Get((CompanyID)this->window_number);
    01876     switch (widget) {
    01877       case CW_WIDGET_FACE:
    01878         DrawCompanyManagerFace(c->face, c->colour, r.left, r.top);
    01879         break;
    01880
    01881       case CW_WIDGET_FACE_TITLE:
    01882         SetDParam(0, c->index);
    01883         DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE, TC_FROMSTRING, SA_CENTER);
    01884         break;
    01885
    01886       case CW_WIDGET_DESC_COLOUR_SCHEME_EXAMPLE:
    01887         DrawSprite(SPR_VEH_BUS_SW_VIEW, COMPANY_SPRITE_COLOUR(c->index), (r.left + r.right) / 2, r.top + FONT_HEIGHT_NORMAL / 10);
    01888         break;
    01889
    01890       case CW_WIDGET_DESC_VEHICLE_COUNTS: {
    01891         uint amounts[4];
    01892         CountCompanyVehicles((CompanyID)this->window_number, amounts);
    01893
    01894         int y = r.top;
    01895         if (amounts[0] + amounts[1] + amounts[2] + amounts[3] == 0) {
    01896           DrawString(r.left, r.right, y, STR_COMPANY_VIEW_VEHICLES_NONE);
    01897         } else {
    01898           assert_compile(lengthof(amounts) == lengthof(_company_view_vehicle_count_strings));
    01899
    01900           for (uint i = 0; i < lengthof(amounts); i++) {
    01901             if (amounts[i] != 0) {
    01902               SetDParam(0, amounts[i]);
    01903               DrawString(r.left, r.right, y, _company_view_vehicle_count_strings[i]);
    01904               y += FONT_HEIGHT_NORMAL;
    01905             }
    01906           }
    01907         }
    01908         break;
    01909       }
    01910
    01911       case CW_WIDGET_DESC_OWNERS: {
    01912         const Company *c2;
    01913         uint y = r.top;
    01914
    01915         FOR_ALL_COMPANIES(c2) {
    01916           uint amt = GetAmountOwnedBy(c, c2->index);
    01917           if (amt != 0) {
    01918             SetDParam(0, amt * 25);
    01919             SetDParam(1, c2->index);
    01920
    01921             DrawString(r.left, r.right, y, STR_COMPANY_VIEW_SHARES_OWNED_BY);
    01922             y += FONT_HEIGHT_NORMAL;
    01923           }
    01924         }
    01925         break;
    01926       }
    01927
    01928 #ifdef ENABLE_NETWORK
    01929       case CW_WIDGET_HAS_PASSWORD:
    01930         if (_networking && NetworkCompanyIsPassworded(c->index)) {
    01931           DrawSprite(SPR_LOCK, PAL_NONE, r.left, r.top);
    01932         }
    01933         break;
    01934 #endif /* ENABLE_NETWORK */
    01935     }
    01936   }
    01937
    01938   virtual void SetStringParameters(int widget) const
    01939   {
    01940     switch (widget) {
    01941       case CW_WIDGET_CAPTION:
    01942         SetDParam(0, (CompanyID)this->window_number);
    01943         SetDParam(1, (CompanyID)this->window_number);
    01944         break;
    01945
    01946       case CW_WIDGET_DESC_INAUGURATION:
    01947         SetDParam(0, Company::Get((CompanyID)this->window_number)->inaugurated_year);
    01948         break;
    01949
    01950       case CW_WIDGET_DESC_COMPANY_VALUE:
    01951         SetDParam(0, CalculateCompanyValue(Company::Get((CompanyID)this->window_number)));
    01952         break;
    01953     }
    01954   }
    01955
    01956   virtual void OnClick(Point pt, int widget, int click_count)
    01957   {
    01958     switch (widget) {
    01959       case CW_WIDGET_NEW_FACE: DoSelectCompanyManagerFace(this); break;
    01960
    01961       case CW_WIDGET_COLOUR_SCHEME:
    01962         if (BringWindowToFrontById(WC_COMPANY_COLOUR, this->window_number)) break;
    01963         new SelectCompanyLiveryWindow(&_select_company_livery_desc, (CompanyID)this->window_number);
    01964         break;
    01965
    01966       case CW_WIDGET_PRESIDENT_NAME:
    01967         this->query_widget = CW_WIDGET_PRESIDENT_NAME;
    01968         SetDParam(0, this->window_number);
    01969         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);
    01970         break;
    01971
    01972       case CW_WIDGET_COMPANY_NAME:
    01973         this->query_widget = CW_WIDGET_COMPANY_NAME;
    01974         SetDParam(0, this->window_number);
    01975         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);
    01976         break;
    01977
    01978       case CW_WIDGET_VIEW_HQ: {
    01979         TileIndex tile = Company::Get((CompanyID)this->window_number)->location_of_HQ;
    01980         if (_ctrl_pressed) {
    01981           ShowExtraViewPortWindow(tile);
    01982         } else {
    01983           ScrollMainWindowToTile(tile);
    01984         }
    01985         break;
    01986       }
    01987
    01988       case CW_WIDGET_BUILD_HQ:
    01989         if ((byte)this->window_number != _local_company) return;
    01990         SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, HT_RECT, this);
    01991         SetTileSelectSize(2, 2);
    01992         this->LowerWidget(CW_WIDGET_BUILD_HQ);
    01993         this->SetWidgetDirty(CW_WIDGET_BUILD_HQ);
    01994         break;
    01995
    01996       case CW_WIDGET_RELOCATE_HQ:
    01997         SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, HT_RECT, this);
    01998         SetTileSelectSize(2, 2);
    01999         this->LowerWidget(CW_WIDGET_RELOCATE_HQ);
    02000         this->SetWidgetDirty(CW_WIDGET_RELOCATE_HQ);
    02001         break;
    02002
    02003       case CW_WIDGET_PROFILE_LOAD:  // When load is clicked we want to perform most of the operations from above!
    02004       {
    02005         StringID       error_id;
    02006         CompanyProfile company_profile;
    02007
    02008         if ((byte)this->window_number != _local_company) return;
    02009
    02010         this->LowerWidget(CW_WIDGET_PROFILE_LOAD);
    02011         //this->SetWidgetDirty(CW_WIDGET_PROFILE_LOAD);
    02012
    02013         error_id = CompanyLoadProfile(company_profile);
    02014         if (error_id == STR_NULL) error_id = SetCompanyProfile(company_profile); // No error, so try setting the profile
    02015
    02016         /* If either CompanyProfileLoad or SetCompanyProfile have an error, they will be handled here */
    02017         if (error_id != STR_NULL) ShowErrorMessage(error_id, error_id, WL_INFO);
    02018
    02019         this->LowerWidget(CW_WIDGET_PROFILE_LOAD);
    02020         //this->SetWidgetDirty(CW_WIDGET_PROFILE_LOAD);
    02021         break;
    02022       }
    02023
    02024       case CW_WIDGET_PROFILE_SAVE:
    02025       {
    02026         StringID       error_id;
    02027         CompanyProfile company_profile;
    02028
    02029         if ((byte)this->window_number != _local_company) return;
    02030
    02031         this->LowerWidget(CW_WIDGET_PROFILE_SAVE);
    02032
    02033         company_profile = GetCompanyProfile(*_company_pool.Get(_local_company));
    02034         error_id = CompanySaveProfile(company_profile);
    02035
    02036         if (error_id != STR_NULL) ShowErrorMessage(error_id, error_id, WL_INFO);
    02037
    02038         this->LowerWidget(CW_WIDGET_PROFILE_SAVE);
    02039         break;
    02040       }
    02041
    02042       case CW_WIDGET_BUY_SHARE:
    02043         DoCommandP(0, this->window_number, 0, CMD_BUY_SHARE_IN_COMPANY | CMD_MSG(STR_ERROR_CAN_T_BUY_25_SHARE_IN_THIS));
    02044         break;
    02045
    02046       case CW_WIDGET_SELL_SHARE:
    02047         DoCommandP(0, this->window_number, 0, CMD_SELL_SHARE_IN_COMPANY | CMD_MSG(STR_ERROR_CAN_T_SELL_25_SHARE_IN));
    02048         break;
    02049
    02050 #ifdef ENABLE_NETWORK
    02051       case CW_WIDGET_COMPANY_PASSWORD:
    02052         if (this->window_number == _local_company) ShowNetworkCompanyPasswordWindow(this);
    02053         break;
    02054
    02055       case CW_WIDGET_COMPANY_JOIN: {
    02056         this->query_widget = CW_WIDGET_COMPANY_JOIN;
    02057         CompanyID company = (CompanyID)this->window_number;
    02058         if (_network_server) {
    02059           NetworkServerDoMove(CLIENT_ID_SERVER, company);
    02060           MarkWholeScreenDirty();
    02061         } else if (NetworkCompanyIsPassworded(company)) {
    02062           /* ask for the password */
    02063           ShowQueryString(STR_EMPTY, STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION, NETWORK_PASSWORD_LENGTH, this, CS_ALPHANUMERAL, QSF_NONE);
    02064         } else {
    02065           /* just send the join command */
    02066           NetworkClientRequestMove(company);
    02067         }
    02068         break;
    02069       }
    02070 #endif /* ENABLE_NETWORK */
    02071     }
    02072   }
    02073
    02074   virtual void OnHundredthTick()
    02075   {
    02076     /* redraw the window every now and then */
    02077     this->SetDirty();
    02078   }
    02079
    02080   virtual void OnPlaceObject(Point pt, TileIndex tile)
    02081   {
    02082     if (DoCommandP(tile, OBJECT_HQ, 0, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS))) {
    02083       ResetObjectToPlace();
    02084       this->RaiseButtons();
    02085     }
    02086   }
    02087
    02088   virtual void OnPlaceObjectAbort()
    02089   {
    02090     this->RaiseButtons();
    02091   }
    02092
    02093   virtual void OnQueryTextFinished(char *str)
    02094   {
    02095     if (str == NULL) return;
    02096
    02097     switch (this->query_widget) {
    02098       default: NOT_REACHED();
    02099
    02100       case CW_WIDGET_PRESIDENT_NAME:
    02101         DoCommandP(0, 0, 0, CMD_RENAME_PRESIDENT | CMD_MSG(STR_ERROR_CAN_T_CHANGE_PRESIDENT), NULL, str);
    02102         break;
    02103
    02104       case CW_WIDGET_COMPANY_NAME:
    02105         DoCommandP(0, 0, 0, CMD_RENAME_COMPANY | CMD_MSG(STR_ERROR_CAN_T_CHANGE_COMPANY_NAME), NULL, str);
    02106         break;
    02107
    02108 #ifdef ENABLE_NETWORK
    02109       case CW_WIDGET_COMPANY_JOIN:
    02110         NetworkClientRequestMove((CompanyID)this->window_number, str);
    02111         break;
    02112 #endif /* ENABLE_NETWORK */
    02113     }
    02114   }
    02115 };
    02116
    02117 static const WindowDesc _company_desc(
    02118   WDP_AUTO, 0, 0,
    02119   WC_COMPANY, WC_NONE,
    02120   WDF_UNCLICK_BUTTONS,
    02121   _nested_company_widgets, lengthof(_nested_company_widgets)
    02122 );
    02123
    02128 void ShowCompany(CompanyID company)
    02129 {
    02130   if (!Company::IsValidID(company)) return;
    02131
    02132   AllocateWindowDescFront<CompanyWindow>(&_company_desc, company);
    02133 }
    02134
    02136 enum BuyCompanyWidgets {
    02137   BCW_CAPTION,
    02138   BCW_FACE,
    02139   BCW_QUESTION,
    02140   BCW_NO,
    02141   BCW_YES,
    02142 };
    02143
    02144 struct BuyCompanyWindow : Window {
    02145   BuyCompanyWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
    02146   {
    02147     this->InitNested(desc, window_number);
    02148   }
    02149
    02150   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
    02151   {
    02152     switch (widget) {
    02153       case BCW_FACE:
    02154         *size = GetSpriteSize(SPR_GRADIENT);
    02155         break;
    02156
    02157       case BCW_QUESTION:
    02158         const Company *c = Company::Get((CompanyID)this->window_number);
    02159         SetDParam(0, c->index);
    02160         SetDParam(1, c->bankrupt_value);
    02161         size->height = GetStringHeight(STR_BUY_COMPANY_MESSAGE, size->width);
    02162         break;
    02163     }
    02164   }
    02165
    02166   virtual void SetStringParameters(int widget) const
    02167   {
    02168     switch (widget) {
    02169       case BCW_CAPTION:
    02170         SetDParam(0, STR_COMPANY_NAME);
    02171         SetDParam(1, Company::Get((CompanyID)this->window_number)->index);
    02172         break;
    02173     }
    02174   }
    02175
    02176   virtual void DrawWidget(const Rect &r, int widget) const
    02177   {
    02178     switch (widget) {
    02179       case BCW_FACE: {
    02180         const Company *c = Company::Get((CompanyID)this->window_number);
    02181         DrawCompanyManagerFace(c->face, c->colour, r.left, r.top);
    02182         break;
    02183       }
    02184
    02185       case BCW_QUESTION: {
    02186         const Company *c = Company::Get((CompanyID)this->window_number);
    02187         SetDParam(0, c->index);
    02188         SetDParam(1, c->bankrupt_value);
    02189         DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_BUY_COMPANY_MESSAGE, TC_FROMSTRING, SA_CENTER);
    02190         break;
    02191       }
    02192     }
    02193   }
    02194
    02195   virtual void OnClick(Point pt, int widget, int click_count)
    02196   {
    02197     switch (widget) {
    02198       case BCW_NO:
    02199         delete this;
    02200         break;
    02201
    02202       case BCW_YES:
    02203         DoCommandP(0, this->window_number, 0, CMD_BUY_COMPANY | CMD_MSG(STR_ERROR_CAN_T_BUY_COMPANY));
    02204         break;
    02205     }
    02206   }
    02207 };
    02208
    02209 static const NWidgetPart _nested_buy_company_widgets[] = {
    02210   NWidget(NWID_HORIZONTAL),
    02211     NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
    02212     NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE, BCW_CAPTION), SetDataTip(STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    02213   EndContainer(),
    02214   NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE),
    02215     NWidget(NWID_VERTICAL), SetPIP(8, 8, 8),
    02216       NWidget(NWID_HORIZONTAL), SetPIP(8, 10, 8),
    02217         NWidget(WWT_EMPTY, INVALID_COLOUR, BCW_FACE), SetFill(0, 1),
    02218         NWidget(WWT_EMPTY, INVALID_COLOUR, BCW_QUESTION), SetMinimalSize(240, 0), SetFill(1, 1),
    02219       EndContainer(),
    02220       NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(100, 10, 100),
    02221         NWidget(WWT_TEXTBTN, COLOUR_LIGHT_BLUE, BCW_NO), SetMinimalSize(60, 12), SetDataTip(STR_QUIT_NO, STR_NULL), SetFill(1, 0),
    02222         NWidget(WWT_TEXTBTN, COLOUR_LIGHT_BLUE, BCW_YES), SetMinimalSize(60, 12), SetDataTip(STR_QUIT_YES, STR_NULL), SetFill(1, 0),
    02223       EndContainer(),
    02224     EndContainer(),
    02225   EndContainer(),
    02226 };
    02227
    02228 static const WindowDesc _buy_company_desc(
    02229   WDP_AUTO, 0, 0,
    02230   WC_BUY_COMPANY, WC_NONE,
    02231   WDF_CONSTRUCTION,
    02232   _nested_buy_company_widgets, lengthof(_nested_buy_company_widgets)
    02233 );
    02234
    02239 void ShowBuyCompanyDialog(CompanyID company)
    02240 {
    02241   AllocateWindowDescFront<BuyCompanyWindow>(&_buy_company_desc, company);
    02242 }