# company_gui.cpp

Go to the documentation of this file.

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