# company_gui.cpp

Go to the documentation of this file.

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