# company_gui.cpp

Go to the documentation of this file.

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