# company_gui.cpp

Go to the documentation of this file.

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