company_gui.cpp

Go to the documentation of this file.
00001 /* $Id$ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "stdafx.h"
00013 #include "gui.h"
00014 #include "window_gui.h"
00015 #include "textbuf_gui.h"
00016 #include "viewport_func.h"
00017 #include "company_func.h"
00018 #include "command_func.h"
00019 #include "network/network.h"
00020 #include "network/network_gui.h"
00021 #include "network/network_func.h"
00022 #include "vehicle_func.h"
00023 #include "newgrf.h"
00024 #include "company_manager_face.h"
00025 #include "strings_func.h"
00026 #include "date_func.h"
00027 #include "widgets/dropdown_type.h"
00028 #include "tilehighlight_func.h"
00029 #include "sprite.h"
00030 #include "company_base.h"
00031 #include "core/geometry_func.hpp"
00032 #include "economy_func.h"
00033 #include "object_type.h"
00034 #include "rail.h"
00035 #include "engine_base.h"
00036 #include "window_func.h"
00037 #include "road_func.h"
00038 #include "water.h"
00039 #include "station_func.h"
00040 
00041 #include "table/strings.h"
00042 
00044 static const uint EXP_LINESPACE  = 2;      
00045 static const uint EXP_BLOCKSPACE = 10;     
00046 
00047 static void DoSelectCompanyManagerFace(Window *parent);
00048 static void ShowCompanyInfrastructure(CompanyID company);
00049 
00051 static ExpensesType _expenses_list_1[] = {
00052   EXPENSES_CONSTRUCTION,
00053   EXPENSES_NEW_VEHICLES,
00054   EXPENSES_TRAIN_RUN,
00055   EXPENSES_ROADVEH_RUN,
00056   EXPENSES_AIRCRAFT_RUN,
00057   EXPENSES_SHIP_RUN,
00058   EXPENSES_PROPERTY,
00059   EXPENSES_TRAIN_INC,
00060   EXPENSES_ROADVEH_INC,
00061   EXPENSES_AIRCRAFT_INC,
00062   EXPENSES_SHIP_INC,
00063   EXPENSES_LOAN_INT,
00064   EXPENSES_SHARING_INC,
00065   EXPENSES_SHARING_COST,
00066   EXPENSES_OTHER,
00067 };
00068 
00070 static ExpensesType _expenses_list_2[] = {
00071   EXPENSES_TRAIN_INC,
00072   EXPENSES_ROADVEH_INC,
00073   EXPENSES_AIRCRAFT_INC,
00074   EXPENSES_SHIP_INC,
00075   EXPENSES_SHARING_INC,
00076   INVALID_EXPENSES,
00077   EXPENSES_TRAIN_RUN,
00078   EXPENSES_ROADVEH_RUN,
00079   EXPENSES_AIRCRAFT_RUN,
00080   EXPENSES_SHIP_RUN,
00081   EXPENSES_PROPERTY,
00082   EXPENSES_LOAN_INT,
00083   EXPENSES_SHARING_COST,
00084   INVALID_EXPENSES,
00085   EXPENSES_CONSTRUCTION,
00086   EXPENSES_NEW_VEHICLES,
00087   EXPENSES_OTHER,
00088   INVALID_EXPENSES,
00089 };
00090 
00092 struct ExpensesList {
00093   const ExpensesType *et;   
00094   const uint length;        
00095   const uint num_subtotals; 
00096 
00097   ExpensesList(ExpensesType *et, int length, int num_subtotals) : et(et), length(length), num_subtotals(num_subtotals)
00098   {
00099   }
00100 
00101   uint GetHeight() const
00102   {
00103     /* heading + line + texts of expenses + sub-totals + total line + total text */
00104     return FONT_HEIGHT_NORMAL + EXP_LINESPACE + this->length * FONT_HEIGHT_NORMAL + num_subtotals * (EXP_BLOCKSPACE + EXP_LINESPACE) + EXP_LINESPACE + FONT_HEIGHT_NORMAL;
00105   }
00106 
00108   uint GetCategoriesWidth() const
00109   {
00110     uint width = 0;
00111     bool invalid_expenses_measured = false; // Measure 'Total' width only once.
00112     for (uint i = 0; i < this->length; i++) {
00113       ExpensesType et = this->et[i];
00114       if (et == INVALID_EXPENSES) {
00115         if (!invalid_expenses_measured) {
00116           width = max(width, GetStringBoundingBox(STR_FINANCES_TOTAL_CAPTION).width);
00117           invalid_expenses_measured = true;
00118         }
00119       } else {
00120         width = max(width, GetStringBoundingBox(STR_FINANCES_SECTION_CONSTRUCTION + et).width);
00121       }
00122     }
00123     return width;
00124   }
00125 };
00126 
00127 static const ExpensesList _expenses_list_types[] = {
00128   ExpensesList(_expenses_list_1, lengthof(_expenses_list_1), 0),
00129   ExpensesList(_expenses_list_2, lengthof(_expenses_list_2), 3),
00130 };
00131 
00133 enum CompanyFinancesWindowWidgets {
00134   CFW_CAPTION,       
00135   CFW_TOGGLE_SIZE,   
00136   CFW_SEL_PANEL,     
00137   CFW_EXPS_CATEGORY, 
00138   CFW_EXPS_PRICE1,   
00139   CFW_EXPS_PRICE2,   
00140   CFW_EXPS_PRICE3,   
00141   CFW_TOTAL_PANEL,   
00142   CFW_SEL_MAXLOAN,   
00143   CFW_BALANCE_VALUE, 
00144   CFW_LOAN_VALUE,    
00145   CFW_LOAN_LINE,     
00146   CFW_TOTAL_VALUE,   
00147   CFW_MAXLOAN_GAP,   
00148   CFW_MAXLOAN_VALUE, 
00149   CFW_SEL_BUTTONS,   
00150   CFW_INCREASE_LOAN, 
00151   CFW_REPAY_LOAN,    
00152   CFW_INFRASTRUCTURE,
00153 };
00154 
00160 static void DrawCategories(const Rect &r)
00161 {
00162   int y = r.top;
00163 
00164   DrawString(r.left, r.right, y, STR_FINANCES_EXPENDITURE_INCOME_TITLE, TC_FROMSTRING, SA_HOR_CENTER, true);
00165   y += FONT_HEIGHT_NORMAL + EXP_LINESPACE;
00166 
00167   int type = _settings_client.gui.expenses_layout;
00168   for (uint i = 0; i < _expenses_list_types[type].length; i++) {
00169     const ExpensesType et = _expenses_list_types[type].et[i];
00170     if (et == INVALID_EXPENSES) {
00171       y += EXP_LINESPACE;
00172       DrawString(r.left, r.right, y, STR_FINANCES_TOTAL_CAPTION, TC_FROMSTRING, SA_RIGHT);
00173       y += FONT_HEIGHT_NORMAL + EXP_BLOCKSPACE;
00174     } else {
00175       DrawString(r.left, r.right, y, STR_FINANCES_SECTION_CONSTRUCTION + et);
00176       y += FONT_HEIGHT_NORMAL;
00177     }
00178   }
00179 
00180   DrawString(r.left, r.right, y + EXP_LINESPACE, STR_FINANCES_TOTAL_CAPTION, TC_FROMSTRING, SA_RIGHT);
00181 }
00182 
00190 static void DrawPrice(Money amount, int left, int right, int top)
00191 {
00192   StringID str = STR_FINANCES_NEGATIVE_INCOME;
00193   if (amount < 0) {
00194     amount = -amount;
00195     str++;
00196   }
00197   SetDParam(0, amount);
00198   DrawString(left, right, top, str, TC_FROMSTRING, SA_RIGHT);
00199 }
00200 
00208 static void DrawYearColumn(const Rect &r, int year, const Money (*tbl)[EXPENSES_END])
00209 {
00210   int y = r.top;
00211 
00212   SetDParam(0, year);
00213   DrawString(r.left, r.right, y, STR_FINANCES_YEAR, TC_FROMSTRING, SA_RIGHT, true);
00214   y += FONT_HEIGHT_NORMAL + EXP_LINESPACE;
00215 
00216   Money sum = 0;
00217   Money subtotal = 0;
00218   int type = _settings_client.gui.expenses_layout;
00219   for (uint i = 0; i < _expenses_list_types[type].length; i++) {
00220     const ExpensesType et = _expenses_list_types[type].et[i];
00221     if (et == INVALID_EXPENSES) {
00222       Money cost = subtotal;
00223       subtotal = 0;
00224       GfxFillRect(r.left, y, r.right, y, PC_BLACK);
00225       y += EXP_LINESPACE;
00226       DrawPrice(cost, r.left, r.right, y);
00227       y += FONT_HEIGHT_NORMAL + EXP_BLOCKSPACE;
00228     } else {
00229       Money cost = (*tbl)[et];
00230       subtotal += cost;
00231       sum += cost;
00232       if (cost != 0) DrawPrice(cost, r.left, r.right, y);
00233       y += FONT_HEIGHT_NORMAL;
00234     }
00235   }
00236 
00237   GfxFillRect(r.left, y, r.right, y, PC_BLACK);
00238   y += EXP_LINESPACE;
00239   DrawPrice(sum, r.left, r.right, y);
00240 }
00241 
00242 static const NWidgetPart _nested_company_finances_widgets[] = {
00243   NWidget(NWID_HORIZONTAL),
00244     NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00245     NWidget(WWT_CAPTION, COLOUR_GREY, CFW_CAPTION), SetDataTip(STR_FINANCES_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00246     NWidget(WWT_IMGBTN, COLOUR_GREY, CFW_TOGGLE_SIZE), SetDataTip(SPR_LARGE_SMALL_WINDOW, STR_TOOLTIP_TOGGLE_LARGE_SMALL_WINDOW),
00247     NWidget(WWT_SHADEBOX, COLOUR_GREY),
00248     NWidget(WWT_STICKYBOX, COLOUR_GREY),
00249   EndContainer(),
00250   NWidget(NWID_SELECTION, INVALID_COLOUR, CFW_SEL_PANEL),
00251     NWidget(WWT_PANEL, COLOUR_GREY),
00252       NWidget(NWID_HORIZONTAL), SetPadding(WD_FRAMERECT_TOP, WD_FRAMERECT_RIGHT, WD_FRAMERECT_BOTTOM, WD_FRAMERECT_LEFT), SetPIP(0, 9, 0),
00253         NWidget(WWT_EMPTY, COLOUR_GREY, CFW_EXPS_CATEGORY), SetMinimalSize(120, 0), SetFill(0, 0),
00254         NWidget(WWT_EMPTY, COLOUR_GREY, CFW_EXPS_PRICE1), SetMinimalSize(86, 0), SetFill(0, 0),
00255         NWidget(WWT_EMPTY, COLOUR_GREY, CFW_EXPS_PRICE2), SetMinimalSize(86, 0), SetFill(0, 0),
00256         NWidget(WWT_EMPTY, COLOUR_GREY, CFW_EXPS_PRICE3), SetMinimalSize(86, 0), SetFill(0, 0),
00257       EndContainer(),
00258     EndContainer(),
00259   EndContainer(),
00260   NWidget(WWT_PANEL, COLOUR_GREY),
00261     NWidget(NWID_HORIZONTAL), SetPadding(WD_FRAMERECT_TOP, WD_FRAMERECT_RIGHT, WD_FRAMERECT_BOTTOM, WD_FRAMERECT_LEFT),
00262       NWidget(NWID_VERTICAL), // Vertical column with 'bank balance', 'loan'
00263         NWidget(WWT_TEXT, COLOUR_GREY), SetDataTip(STR_FINANCES_BANK_BALANCE_TITLE, STR_NULL), SetFill(1, 0),
00264         NWidget(WWT_TEXT, COLOUR_GREY), SetDataTip(STR_FINANCES_LOAN_TITLE, STR_NULL), SetFill(1, 0),
00265         NWidget(NWID_SPACER), SetFill(0, 1),
00266       EndContainer(),
00267       NWidget(NWID_SPACER), SetFill(0, 0), SetMinimalSize(30, 0),
00268       NWidget(NWID_VERTICAL), // Vertical column with bank balance amount, loan amount, and total.
00269         NWidget(WWT_TEXT, COLOUR_GREY, CFW_BALANCE_VALUE), SetDataTip(STR_NULL, STR_NULL),
00270         NWidget(WWT_TEXT, COLOUR_GREY, CFW_LOAN_VALUE), SetDataTip(STR_NULL, STR_NULL),
00271         NWidget(WWT_EMPTY, COLOUR_GREY, CFW_LOAN_LINE), SetMinimalSize(0, 2), SetFill(1, 0),
00272         NWidget(WWT_TEXT, COLOUR_GREY, CFW_TOTAL_VALUE), SetDataTip(STR_NULL, STR_NULL),
00273       EndContainer(),
00274       NWidget(NWID_SELECTION, INVALID_COLOUR, CFW_SEL_MAXLOAN),
00275         NWidget(NWID_HORIZONTAL),
00276           NWidget(NWID_SPACER), SetFill(0, 1), SetMinimalSize(25, 0),
00277           NWidget(NWID_VERTICAL), // Max loan information
00278             NWidget(WWT_EMPTY, COLOUR_GREY, CFW_MAXLOAN_GAP), SetFill(0, 0),
00279             NWidget(WWT_TEXT, COLOUR_GREY, CFW_MAXLOAN_VALUE), SetDataTip(STR_FINANCES_MAX_LOAN, STR_NULL),
00280             NWidget(NWID_SPACER), SetFill(0, 1),
00281           EndContainer(),
00282         EndContainer(),
00283       EndContainer(),
00284       NWidget(NWID_SPACER), SetFill(1, 1),
00285     EndContainer(),
00286   EndContainer(),
00287   NWidget(NWID_SELECTION, INVALID_COLOUR, CFW_SEL_BUTTONS),
00288     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
00289       NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CFW_INCREASE_LOAN), SetFill(1, 0), SetDataTip(STR_FINANCES_BORROW_BUTTON, STR_FINANCES_BORROW_TOOLTIP),
00290       NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CFW_REPAY_LOAN), SetFill(1, 0), SetDataTip(STR_FINANCES_REPAY_BUTTON, STR_FINANCES_REPAY_TOOLTIP),
00291       NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CFW_INFRASTRUCTURE), SetFill(1, 0), SetDataTip(STR_FINANCES_INFRASTRUCTURE_BUTTON, STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP),
00292     EndContainer(),
00293   EndContainer(),
00294 };
00295 
00300 struct CompanyFinancesWindow : Window {
00301   static Money max_money; 
00302   bool small;             
00303 
00304   CompanyFinancesWindow(const WindowDesc *desc, CompanyID company) : Window()
00305   {
00306     this->small = false;
00307     this->CreateNestedTree(desc);
00308     this->SetupWidgets();
00309     this->FinishInitNested(desc, company);
00310 
00311     this->owner = (Owner)this->window_number;
00312   }
00313 
00314   virtual void SetStringParameters(int widget) const
00315   {
00316     switch (widget) {
00317       case CFW_CAPTION:
00318         SetDParam(0, (CompanyID)this->window_number);
00319         SetDParam(1, (CompanyID)this->window_number);
00320         break;
00321 
00322       case CFW_MAXLOAN_VALUE:
00323         SetDParam(0, _economy.max_loan);
00324         break;
00325 
00326       case CFW_INCREASE_LOAN:
00327       case CFW_REPAY_LOAN:
00328         SetDParam(0, LOAN_INTERVAL);
00329         break;
00330     }
00331   }
00332 
00333   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00334   {
00335     int type = _settings_client.gui.expenses_layout;
00336     switch (widget) {
00337       case CFW_EXPS_CATEGORY:
00338         size->width  = _expenses_list_types[type].GetCategoriesWidth();
00339         size->height = _expenses_list_types[type].GetHeight();
00340         break;
00341 
00342       case CFW_EXPS_PRICE1:
00343       case CFW_EXPS_PRICE2:
00344       case CFW_EXPS_PRICE3:
00345         size->height = _expenses_list_types[type].GetHeight();
00346         /* FALL THROUGH */
00347       case CFW_BALANCE_VALUE:
00348       case CFW_LOAN_VALUE:
00349       case CFW_TOTAL_VALUE:
00350         SetDParam(0, CompanyFinancesWindow::max_money);
00351         size->width = max(GetStringBoundingBox(STR_FINANCES_NEGATIVE_INCOME).width, GetStringBoundingBox(STR_FINANCES_POSITIVE_INCOME).width) + padding.width;
00352         break;
00353 
00354       case CFW_MAXLOAN_GAP:
00355         size->height = FONT_HEIGHT_NORMAL;
00356         break;
00357     }
00358   }
00359 
00360   virtual void DrawWidget(const Rect &r, int widget) const
00361   {
00362     switch (widget) {
00363       case CFW_EXPS_CATEGORY:
00364         DrawCategories(r);
00365         break;
00366 
00367       case CFW_EXPS_PRICE1:
00368       case CFW_EXPS_PRICE2:
00369       case CFW_EXPS_PRICE3: {
00370         const Company *c = Company::Get((CompanyID)this->window_number);
00371         int age = min(_cur_year - c->inaugurated_year, 2);
00372         int wid_offset = widget - CFW_EXPS_PRICE1;
00373         if (wid_offset <= age) {
00374           DrawYearColumn(r, _cur_year - (age - wid_offset), c->yearly_expenses + (age - wid_offset));
00375         }
00376         break;
00377       }
00378 
00379       case CFW_BALANCE_VALUE: {
00380         const Company *c = Company::Get((CompanyID)this->window_number);
00381         SetDParam(0, c->money);
00382         DrawString(r.left, r.right, r.top, STR_FINANCES_TOTAL_CURRENCY, TC_FROMSTRING, SA_RIGHT);
00383         break;
00384       }
00385 
00386       case CFW_LOAN_VALUE: {
00387         const Company *c = Company::Get((CompanyID)this->window_number);
00388         SetDParam(0, c->current_loan);
00389         DrawString(r.left, r.right, r.top, STR_FINANCES_TOTAL_CURRENCY, TC_FROMSTRING, SA_RIGHT);
00390         break;
00391       }
00392 
00393       case CFW_TOTAL_VALUE: {
00394         const Company *c = Company::Get((CompanyID)this->window_number);
00395         SetDParam(0, c->money - c->current_loan);
00396         DrawString(r.left, r.right, r.top, STR_FINANCES_TOTAL_CURRENCY, TC_FROMSTRING, SA_RIGHT);
00397         break;
00398       }
00399 
00400       case CFW_LOAN_LINE:
00401         GfxFillRect(r.left, r.top, r.right, r.top, PC_BLACK);
00402         break;
00403     }
00404   }
00405 
00410   void SetupWidgets()
00411   {
00412     int plane = this->small ? SZSP_NONE : 0;
00413     this->GetWidget<NWidgetStacked>(CFW_SEL_PANEL)->SetDisplayedPlane(plane);
00414     this->GetWidget<NWidgetStacked>(CFW_SEL_MAXLOAN)->SetDisplayedPlane(plane);
00415 
00416     CompanyID company = (CompanyID)this->window_number;
00417     plane = (company != _local_company) ? SZSP_NONE : 0;
00418     this->GetWidget<NWidgetStacked>(CFW_SEL_BUTTONS)->SetDisplayedPlane(plane);
00419   }
00420 
00421   virtual void OnPaint()
00422   {
00423     if (!this->IsShaded()) {
00424       if (!this->small) {
00425         /* Check that the expenses panel height matches the height needed for the layout. */
00426         int type = _settings_client.gui.expenses_layout;
00427         if (_expenses_list_types[type].GetHeight() != this->GetWidget<NWidgetBase>(CFW_EXPS_CATEGORY)->current_y) {
00428           this->SetupWidgets();
00429           this->ReInit();
00430           return;
00431         }
00432       }
00433 
00434       /* Check that the loan buttons are shown only when the user owns the company. */
00435       CompanyID company = (CompanyID)this->window_number;
00436       int req_plane = (company != _local_company) ? SZSP_NONE : 0;
00437       if (req_plane != this->GetWidget<NWidgetStacked>(CFW_SEL_BUTTONS)->shown_plane) {
00438         this->SetupWidgets();
00439         this->ReInit();
00440         return;
00441       }
00442 
00443       const Company *c = Company::Get(company);
00444       this->SetWidgetDisabledState(CFW_INCREASE_LOAN, c->current_loan == _economy.max_loan); // Borrow button only shows when there is any more money to loan.
00445       this->SetWidgetDisabledState(CFW_REPAY_LOAN, company != _local_company || c->current_loan == 0); // Repay button only shows when there is any more money to repay.
00446     }
00447 
00448     this->DrawWidgets();
00449   }
00450 
00451   virtual void OnClick(Point pt, int widget, int click_count)
00452   {
00453     switch (widget) {
00454       case CFW_TOGGLE_SIZE: // toggle size
00455         this->small = !this->small;
00456         this->SetupWidgets();
00457         if (this->IsShaded()) {
00458           /* Finances window is not resizable, so size hints given during unshading have no effect
00459            * on the changed appearance of the window. */
00460           this->SetShaded(false);
00461         } else {
00462           this->ReInit();
00463         }
00464         break;
00465 
00466       case CFW_INCREASE_LOAN: // increase loan
00467         DoCommandP(0, 0, _ctrl_pressed, CMD_INCREASE_LOAN | CMD_MSG(STR_ERROR_CAN_T_BORROW_ANY_MORE_MONEY));
00468         break;
00469 
00470       case CFW_REPAY_LOAN: // repay loan
00471         DoCommandP(0, 0, _ctrl_pressed, CMD_DECREASE_LOAN | CMD_MSG(STR_ERROR_CAN_T_REPAY_LOAN));
00472         break;
00473 
00474       case CFW_INFRASTRUCTURE: // show infrastructure details
00475         ShowCompanyInfrastructure((CompanyID)this->window_number);
00476         break;
00477     }
00478   }
00479 
00480   virtual void OnHundredthTick()
00481   {
00482     const Company *c = Company::Get((CompanyID)this->window_number);
00483     if (c->money > CompanyFinancesWindow::max_money) {
00484       CompanyFinancesWindow::max_money = max(c->money * 2, CompanyFinancesWindow::max_money * 4);
00485       this->SetupWidgets();
00486       this->ReInit();
00487     }
00488   }
00489 };
00490 
00492 Money CompanyFinancesWindow::max_money = INT32_MAX;
00493 
00494 static const WindowDesc _company_finances_desc(
00495   WDP_AUTO, 0, 0,
00496   WC_FINANCES, WC_NONE,
00497   WDF_UNCLICK_BUTTONS,
00498   _nested_company_finances_widgets, lengthof(_nested_company_finances_widgets)
00499 );
00500 
00506 void ShowCompanyFinances(CompanyID company)
00507 {
00508   if (!Company::IsValidID(company)) return;
00509   if (BringWindowToFrontById(WC_FINANCES, company)) return;
00510 
00511   new CompanyFinancesWindow(&_company_finances_desc, company);
00512 }
00513 
00514 /* List of colours for the livery window */
00515 static const StringID _colour_dropdown[] = {
00516   STR_COLOUR_DARK_BLUE,
00517   STR_COLOUR_PALE_GREEN,
00518   STR_COLOUR_PINK,
00519   STR_COLOUR_YELLOW,
00520   STR_COLOUR_RED,
00521   STR_COLOUR_LIGHT_BLUE,
00522   STR_COLOUR_GREEN,
00523   STR_COLOUR_DARK_GREEN,
00524   STR_COLOUR_BLUE,
00525   STR_COLOUR_CREAM,
00526   STR_COLOUR_MAUVE,
00527   STR_COLOUR_PURPLE,
00528   STR_COLOUR_ORANGE,
00529   STR_COLOUR_BROWN,
00530   STR_COLOUR_GREY,
00531   STR_COLOUR_WHITE,
00532 };
00533 
00534 /* Association of liveries to livery classes */
00535 static const LiveryClass _livery_class[LS_END] = {
00536   LC_OTHER,
00537   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,
00538   LC_ROAD, LC_ROAD,
00539   LC_SHIP, LC_SHIP,
00540   LC_AIRCRAFT, LC_AIRCRAFT, LC_AIRCRAFT,
00541   LC_ROAD, LC_ROAD,
00542 };
00543 
00544 class DropDownListColourItem : public DropDownListItem {
00545 public:
00546   DropDownListColourItem(int result, bool masked) : DropDownListItem(result, masked) {}
00547 
00548   virtual ~DropDownListColourItem() {}
00549 
00550   StringID String() const
00551   {
00552     return _colour_dropdown[this->result];
00553   }
00554 
00555   uint Height(uint width) const
00556   {
00557     return max(FONT_HEIGHT_NORMAL, (byte)14);
00558   }
00559 
00560   bool Selectable() const
00561   {
00562     return true;
00563   }
00564 
00565   void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const
00566   {
00567     bool rtl = _current_text_dir == TD_RTL;
00568     DrawSprite(SPR_VEH_BUS_SIDE_VIEW, PALETTE_RECOLOUR_START + this->result, rtl ? right - 16 : left + 16, top + 7);
00569     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);
00570   }
00571 };
00572 
00574 enum SelectCompanyLiveryWindowWidgets {
00575   SCLW_WIDGET_CAPTION,
00576   SCLW_WIDGET_CLASS_GENERAL,
00577   SCLW_WIDGET_CLASS_RAIL,
00578   SCLW_WIDGET_CLASS_ROAD,
00579   SCLW_WIDGET_CLASS_SHIP,
00580   SCLW_WIDGET_CLASS_AIRCRAFT,
00581   SCLW_WIDGET_SPACER_DROPDOWN,
00582   SCLW_WIDGET_PRI_COL_DROPDOWN,
00583   SCLW_WIDGET_SEC_COL_DROPDOWN,
00584   SCLW_WIDGET_MATRIX,
00585 };
00586 
00588 struct SelectCompanyLiveryWindow : public Window {
00589 private:
00590   static const uint TEXT_INDENT = 15; 
00591   uint32 sel;
00592   LiveryClass livery_class;
00593 
00594   void ShowColourDropDownMenu(uint32 widget)
00595   {
00596     uint32 used_colours = 0;
00597     const Livery *livery;
00598     LiveryScheme scheme;
00599 
00600     /* Disallow other company colours for the primary colour */
00601     if (HasBit(this->sel, LS_DEFAULT) && widget == SCLW_WIDGET_PRI_COL_DROPDOWN) {
00602       const Company *c;
00603       FOR_ALL_COMPANIES(c) {
00604         if (c->index != _local_company) SetBit(used_colours, c->colour);
00605       }
00606     }
00607 
00608     /* Get the first selected livery to use as the default dropdown item */
00609     for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
00610       if (HasBit(this->sel, scheme)) break;
00611     }
00612     if (scheme == LS_END) scheme = LS_DEFAULT;
00613     livery = &Company::Get((CompanyID)this->window_number)->livery[scheme];
00614 
00615     DropDownList *list = new DropDownList();
00616     for (uint i = 0; i < lengthof(_colour_dropdown); i++) {
00617       list->push_back(new DropDownListColourItem(i, HasBit(used_colours, i)));
00618     }
00619 
00620     ShowDropDownList(this, list, widget == SCLW_WIDGET_PRI_COL_DROPDOWN ? livery->colour1 : livery->colour2, widget);
00621   }
00622 
00623 public:
00624   SelectCompanyLiveryWindow(const WindowDesc *desc, CompanyID company) : Window()
00625   {
00626     this->livery_class = LC_OTHER;
00627     this->sel = 1;
00628     this->InitNested(desc, company);
00629     this->owner = company;
00630     this->LowerWidget(SCLW_WIDGET_CLASS_GENERAL);
00631     this->InvalidateData(1);
00632   }
00633 
00634   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00635   {
00636     switch (widget) {
00637       case SCLW_WIDGET_SPACER_DROPDOWN: {
00638         /* The matrix widget below needs enough room to print all the schemes. */
00639         Dimension d = {0, 0};
00640         for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
00641           d = maxdim(d, GetStringBoundingBox(STR_LIVERY_DEFAULT + scheme));
00642         }
00643         size->width = max(size->width, TEXT_INDENT + d.width + WD_FRAMERECT_RIGHT);
00644         break;
00645       }
00646 
00647       case SCLW_WIDGET_MATRIX: {
00648         uint livery_height = 0;
00649         for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
00650           if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
00651             livery_height++;
00652           }
00653         }
00654         size->height = livery_height * (4 + FONT_HEIGHT_NORMAL);
00655         this->GetWidget<NWidgetCore>(SCLW_WIDGET_MATRIX)->widget_data = (livery_height << MAT_ROW_START) | (1 << MAT_COL_START);
00656         break;
00657       }
00658 
00659       case SCLW_WIDGET_SEC_COL_DROPDOWN:
00660         if (!_loaded_newgrf_features.has_2CC) {
00661           size->width = 0;
00662           break;
00663         }
00664         /* FALL THROUGH */
00665       case SCLW_WIDGET_PRI_COL_DROPDOWN: {
00666         for (const StringID *id = _colour_dropdown; id != endof(_colour_dropdown); id++) {
00667           size->width = max(size->width, GetStringBoundingBox(*id).width + 34);
00668         }
00669         break;
00670       }
00671     }
00672   }
00673 
00674   virtual void OnPaint()
00675   {
00676     /* Disable dropdown controls if no scheme is selected */
00677     this->SetWidgetDisabledState(SCLW_WIDGET_PRI_COL_DROPDOWN, this->sel == 0);
00678     this->SetWidgetDisabledState(SCLW_WIDGET_SEC_COL_DROPDOWN, this->sel == 0);
00679 
00680     this->DrawWidgets();
00681   }
00682 
00683   virtual void SetStringParameters(int widget) const
00684   {
00685     switch (widget) {
00686       case SCLW_WIDGET_PRI_COL_DROPDOWN:
00687       case SCLW_WIDGET_SEC_COL_DROPDOWN: {
00688         const Company *c = Company::Get((CompanyID)this->window_number);
00689         LiveryScheme scheme = LS_DEFAULT;
00690 
00691         if (this->sel != 0) {
00692           for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
00693             if (HasBit(this->sel, scheme)) break;
00694           }
00695           if (scheme == LS_END) scheme = LS_DEFAULT;
00696         }
00697         SetDParam(0, STR_COLOUR_DARK_BLUE + ((widget == SCLW_WIDGET_PRI_COL_DROPDOWN) ? c->livery[scheme].colour1 : c->livery[scheme].colour2));
00698         break;
00699       }
00700     }
00701   }
00702 
00703   virtual void DrawWidget(const Rect &r, int widget) const
00704   {
00705     if (widget != SCLW_WIDGET_MATRIX) return;
00706 
00707     bool rtl = _current_text_dir == TD_RTL;
00708 
00709     /* Horizontal coordinates of scheme name column. */
00710     const NWidgetBase *nwi = this->GetWidget<NWidgetBase>(SCLW_WIDGET_SPACER_DROPDOWN);
00711     int sch_left = nwi->pos_x;
00712     int sch_right = sch_left + nwi->current_x - 1;
00713     /* Horizontal coordinates of first dropdown. */
00714     nwi = this->GetWidget<NWidgetBase>(SCLW_WIDGET_PRI_COL_DROPDOWN);
00715     int pri_left = nwi->pos_x;
00716     int pri_right = pri_left + nwi->current_x - 1;
00717     /* Horizontal coordinates of second dropdown. */
00718     nwi = this->GetWidget<NWidgetBase>(SCLW_WIDGET_SEC_COL_DROPDOWN);
00719     int sec_left = nwi->pos_x;
00720     int sec_right = sec_left + nwi->current_x - 1;
00721 
00722     int text_left  = (rtl ? (uint)WD_FRAMERECT_LEFT : TEXT_INDENT);
00723     int text_right = (rtl ? TEXT_INDENT : (uint)WD_FRAMERECT_RIGHT);
00724 
00725     int y = r.top + 3;
00726     const Company *c = Company::Get((CompanyID)this->window_number);
00727     for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
00728       if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
00729         bool sel = HasBit(this->sel, scheme) != 0;
00730 
00731         /* Optional check box + scheme name. */
00732         if (scheme != LS_DEFAULT) {
00733           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);
00734         }
00735         DrawString(sch_left + text_left, sch_right - text_right, y, STR_LIVERY_DEFAULT + scheme, sel ? TC_WHITE : TC_BLACK);
00736 
00737         /* Text below the first dropdown. */
00738         DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOUR(c->livery[scheme].colour1), (rtl ? pri_right - TEXT_INDENT + WD_FRAMERECT_RIGHT : pri_left) + WD_FRAMERECT_LEFT, y);
00739         DrawString(pri_left + text_left, pri_right - text_right, y, STR_COLOUR_DARK_BLUE + c->livery[scheme].colour1, sel ? TC_WHITE : TC_GOLD);
00740 
00741         /* Text below the second dropdown. */
00742         if (sec_right > sec_left) { // Second dropdown has non-zero size.
00743           DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOUR(c->livery[scheme].colour2), (rtl ? sec_right - TEXT_INDENT + WD_FRAMERECT_RIGHT : sec_left) + WD_FRAMERECT_LEFT, y);
00744           DrawString(sec_left + text_left, sec_right - text_right, y, STR_COLOUR_DARK_BLUE + c->livery[scheme].colour2, sel ? TC_WHITE : TC_GOLD);
00745         }
00746 
00747         y += 4 + FONT_HEIGHT_NORMAL;
00748       }
00749     }
00750   }
00751 
00752   virtual void OnClick(Point pt, int widget, int click_count)
00753   {
00754     switch (widget) {
00755       /* Livery Class buttons */
00756       case SCLW_WIDGET_CLASS_GENERAL:
00757       case SCLW_WIDGET_CLASS_RAIL:
00758       case SCLW_WIDGET_CLASS_ROAD:
00759       case SCLW_WIDGET_CLASS_SHIP:
00760       case SCLW_WIDGET_CLASS_AIRCRAFT:
00761         this->RaiseWidget(this->livery_class + SCLW_WIDGET_CLASS_GENERAL);
00762         this->livery_class = (LiveryClass)(widget - SCLW_WIDGET_CLASS_GENERAL);
00763         this->LowerWidget(this->livery_class + SCLW_WIDGET_CLASS_GENERAL);
00764 
00765         /* Select the first item in the list */
00766         this->sel = 0;
00767         for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
00768           if (_livery_class[scheme] == this->livery_class && HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
00769             this->sel = 1 << scheme;
00770             break;
00771           }
00772         }
00773 
00774         this->ReInit();
00775         break;
00776 
00777       case SCLW_WIDGET_PRI_COL_DROPDOWN: // First colour dropdown
00778         ShowColourDropDownMenu(SCLW_WIDGET_PRI_COL_DROPDOWN);
00779         break;
00780 
00781       case SCLW_WIDGET_SEC_COL_DROPDOWN: // Second colour dropdown
00782         ShowColourDropDownMenu(SCLW_WIDGET_SEC_COL_DROPDOWN);
00783         break;
00784 
00785       case SCLW_WIDGET_MATRIX: {
00786         const NWidgetBase *wid = this->GetWidget<NWidgetBase>(SCLW_WIDGET_MATRIX);
00787         LiveryScheme j = (LiveryScheme)((pt.y - wid->pos_y) / (4 + FONT_HEIGHT_NORMAL));
00788 
00789         for (LiveryScheme scheme = LS_BEGIN; scheme <= j; scheme++) {
00790           if (_livery_class[scheme] != this->livery_class || !HasBit(_loaded_newgrf_features.used_liveries, scheme)) j++;
00791           if (scheme >= LS_END) return;
00792         }
00793         if (j >= LS_END) return;
00794 
00795         /* If clicking on the left edge, toggle using the livery */
00796         if (_current_text_dir == TD_RTL ? pt.x - wid->pos_x > wid->current_x - TEXT_INDENT : pt.x - wid->pos_x < TEXT_INDENT) {
00797           DoCommandP(0, j | (2 << 8), !Company::Get((CompanyID)this->window_number)->livery[j].in_use, CMD_SET_COMPANY_COLOUR);
00798         }
00799 
00800         if (_ctrl_pressed) {
00801           ToggleBit(this->sel, j);
00802         } else {
00803           this->sel = 1 << j;
00804         }
00805         this->SetDirty();
00806         break;
00807       }
00808     }
00809   }
00810 
00811   virtual void OnDropdownSelect(int widget, int index)
00812   {
00813     for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
00814       if (HasBit(this->sel, scheme)) {
00815         DoCommandP(0, scheme | (widget == SCLW_WIDGET_PRI_COL_DROPDOWN ? 0 : 256), index, CMD_SET_COMPANY_COLOUR);
00816       }
00817     }
00818   }
00819 
00825   virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
00826   {
00827     if (!gui_scope) return;
00828     this->SetWidgetsDisabledState(true, SCLW_WIDGET_CLASS_RAIL, SCLW_WIDGET_CLASS_ROAD, SCLW_WIDGET_CLASS_SHIP, SCLW_WIDGET_CLASS_AIRCRAFT, WIDGET_LIST_END);
00829 
00830     bool current_class_valid = this->livery_class == LC_OTHER;
00831     if (_settings_client.gui.liveries == LIT_ALL || (_settings_client.gui.liveries == LIT_COMPANY && this->window_number == _local_company)) {
00832       for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
00833         if (HasBit(_loaded_newgrf_features.used_liveries, scheme)) {
00834           if (_livery_class[scheme] == this->livery_class) current_class_valid = true;
00835           this->EnableWidget(SCLW_WIDGET_CLASS_GENERAL + _livery_class[scheme]);
00836         } else {
00837           ClrBit(this->sel, scheme);
00838         }
00839       }
00840     }
00841 
00842     if (!current_class_valid) {
00843       Point pt = {0, 0};
00844       this->OnClick(pt, SCLW_WIDGET_CLASS_GENERAL, 1);
00845     } else if (data == 0) {
00846       this->ReInit();
00847     }
00848   }
00849 };
00850 
00851 static const NWidgetPart _nested_select_company_livery_widgets [] = {
00852   NWidget(NWID_HORIZONTAL),
00853     NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00854     NWidget(WWT_CAPTION, COLOUR_GREY, SCLW_WIDGET_CAPTION), SetDataTip(STR_LIVERY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00855   EndContainer(),
00856   NWidget(NWID_HORIZONTAL),
00857     NWidget(WWT_IMGBTN, COLOUR_GREY, SCLW_WIDGET_CLASS_GENERAL), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_COMPANY_GENERAL, STR_LIVERY_GENERAL_TOOLTIP),
00858     NWidget(WWT_IMGBTN, COLOUR_GREY, SCLW_WIDGET_CLASS_RAIL), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_TRAINLIST, STR_LIVERY_TRAIN_TOOLTIP),
00859     NWidget(WWT_IMGBTN, COLOUR_GREY, SCLW_WIDGET_CLASS_ROAD), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_TRUCKLIST, STR_LIVERY_ROAD_VEHICLE_TOOLTIP),
00860     NWidget(WWT_IMGBTN, COLOUR_GREY, SCLW_WIDGET_CLASS_SHIP), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_SHIPLIST, STR_LIVERY_SHIP_TOOLTIP),
00861     NWidget(WWT_IMGBTN, COLOUR_GREY, SCLW_WIDGET_CLASS_AIRCRAFT), SetMinimalSize(22, 22), SetFill(0, 1), SetDataTip(SPR_IMG_AIRPLANESLIST, STR_LIVERY_AIRCRAFT_TOOLTIP),
00862     NWidget(WWT_PANEL, COLOUR_GREY), SetMinimalSize(90, 22), SetFill(1, 1), EndContainer(),
00863   EndContainer(),
00864   NWidget(NWID_HORIZONTAL),
00865     NWidget(WWT_PANEL, COLOUR_GREY, SCLW_WIDGET_SPACER_DROPDOWN), SetMinimalSize(150, 12), SetFill(1, 1), EndContainer(),
00866     NWidget(WWT_DROPDOWN, COLOUR_GREY, SCLW_WIDGET_PRI_COL_DROPDOWN), SetMinimalSize(125, 12), SetFill(0, 1), SetDataTip(STR_BLACK_STRING, STR_LIVERY_PRIMARY_TOOLTIP),
00867     NWidget(WWT_DROPDOWN, COLOUR_GREY, SCLW_WIDGET_SEC_COL_DROPDOWN), SetMinimalSize(125, 12), SetFill(0, 1),
00868         SetDataTip(STR_BLACK_STRING, STR_LIVERY_SECONDARY_TOOLTIP),
00869   EndContainer(),
00870   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),
00871 };
00872 
00873 static const WindowDesc _select_company_livery_desc(
00874   WDP_AUTO, 0, 0,
00875   WC_COMPANY_COLOUR, WC_NONE,
00876   0,
00877   _nested_select_company_livery_widgets, lengthof(_nested_select_company_livery_widgets)
00878 );
00879 
00887 void DrawCompanyManagerFace(CompanyManagerFace cmf, int colour, int x, int y)
00888 {
00889   GenderEthnicity ge = (GenderEthnicity)GetCompanyManagerFaceBits(cmf, CMFV_GEN_ETHN, GE_WM);
00890 
00891   bool has_moustache   = !HasBit(ge, GENDER_FEMALE) && GetCompanyManagerFaceBits(cmf, CMFV_HAS_MOUSTACHE,   ge) != 0;
00892   bool has_tie_earring = !HasBit(ge, GENDER_FEMALE) || GetCompanyManagerFaceBits(cmf, CMFV_HAS_TIE_EARRING, ge) != 0;
00893   bool has_glasses     = GetCompanyManagerFaceBits(cmf, CMFV_HAS_GLASSES, ge) != 0;
00894   PaletteID pal;
00895 
00896   /* Modify eye colour palette only if 2 or more valid values exist */
00897   if (_cmf_info[CMFV_EYE_COLOUR].valid_values[ge] < 2) {
00898     pal = PAL_NONE;
00899   } else {
00900     switch (GetCompanyManagerFaceBits(cmf, CMFV_EYE_COLOUR, ge)) {
00901       default: NOT_REACHED();
00902       case 0: pal = PALETTE_TO_BROWN; break;
00903       case 1: pal = PALETTE_TO_BLUE;  break;
00904       case 2: pal = PALETTE_TO_GREEN; break;
00905     }
00906   }
00907 
00908   /* Draw the gradient (background) */
00909   DrawSprite(SPR_GRADIENT, GENERAL_SPRITE_COLOUR(colour), x, y);
00910 
00911   for (CompanyManagerFaceVariable cmfv = CMFV_CHEEKS; cmfv < CMFV_END; cmfv++) {
00912     switch (cmfv) {
00913       case CMFV_MOUSTACHE:   if (!has_moustache)   continue; break;
00914       case CMFV_LIPS:        // FALL THROUGH
00915       case CMFV_NOSE:        if (has_moustache)    continue; break;
00916       case CMFV_TIE_EARRING: if (!has_tie_earring) continue; break;
00917       case CMFV_GLASSES:     if (!has_glasses)     continue; break;
00918       default: break;
00919     }
00920     DrawSprite(GetCompanyManagerFaceSprite(cmf, cmfv, ge), (cmfv == CMFV_EYEBROWS) ? pal : PAL_NONE, x, y);
00921   }
00922 }
00923 
00929 enum SelectCompanyManagerFaceWidgets {
00930   SCMFW_WIDGET_CAPTION,
00931   SCMFW_WIDGET_TOGGLE_LARGE_SMALL,
00932   SCMFW_WIDGET_SELECT_FACE,
00933   SCMFW_WIDGET_CANCEL,
00934   SCMFW_WIDGET_ACCEPT,
00935   SCMFW_WIDGET_MALE,           
00936   SCMFW_WIDGET_FEMALE,         
00937   SCMFW_WIDGET_MALE2,          
00938   SCMFW_WIDGET_FEMALE2,        
00939   SCMFW_WIDGET_SEL_LOADSAVE,   
00940   SCMFW_WIDGET_SEL_MALEFEMALE, 
00941   SCMFW_WIDGET_SEL_PARTS,      
00942   SCMFW_WIDGET_RANDOM_NEW_FACE,
00943   SCMFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON,
00944   SCMFM_WIDGET_FACE,
00945   SCMFW_WIDGET_LOAD,
00946   SCMFW_WIDGET_FACECODE,
00947   SCMFW_WIDGET_SAVE,
00948   SCMFW_WIDGET_HAS_MOUSTACHE_EARRING_TEXT,
00949   SCMFW_WIDGET_TIE_EARRING_TEXT,
00950   SCMFW_WIDGET_LIPS_MOUSTACHE_TEXT,
00951   SCMFW_WIDGET_HAS_GLASSES_TEXT,
00952   SCMFW_WIDGET_HAIR_TEXT,
00953   SCMFW_WIDGET_EYEBROWS_TEXT,
00954   SCMFW_WIDGET_EYECOLOUR_TEXT,
00955   SCMFW_WIDGET_GLASSES_TEXT,
00956   SCMFW_WIDGET_NOSE_TEXT,
00957   SCMFW_WIDGET_CHIN_TEXT,
00958   SCMFW_WIDGET_JACKET_TEXT,
00959   SCMFW_WIDGET_COLLAR_TEXT,
00960   SCMFW_WIDGET_ETHNICITY_EUR,
00961   SCMFW_WIDGET_ETHNICITY_AFR,
00962   SCMFW_WIDGET_HAS_MOUSTACHE_EARRING,
00963   SCMFW_WIDGET_HAS_GLASSES,
00964   SCMFW_WIDGET_EYECOLOUR_L,
00965   SCMFW_WIDGET_EYECOLOUR,
00966   SCMFW_WIDGET_EYECOLOUR_R,
00967   SCMFW_WIDGET_CHIN_L,
00968   SCMFW_WIDGET_CHIN,
00969   SCMFW_WIDGET_CHIN_R,
00970   SCMFW_WIDGET_EYEBROWS_L,
00971   SCMFW_WIDGET_EYEBROWS,
00972   SCMFW_WIDGET_EYEBROWS_R,
00973   SCMFW_WIDGET_LIPS_MOUSTACHE_L,
00974   SCMFW_WIDGET_LIPS_MOUSTACHE,
00975   SCMFW_WIDGET_LIPS_MOUSTACHE_R,
00976   SCMFW_WIDGET_NOSE_L,
00977   SCMFW_WIDGET_NOSE,
00978   SCMFW_WIDGET_NOSE_R,
00979   SCMFW_WIDGET_HAIR_L,
00980   SCMFW_WIDGET_HAIR,
00981   SCMFW_WIDGET_HAIR_R,
00982   SCMFW_WIDGET_JACKET_L,
00983   SCMFW_WIDGET_JACKET,
00984   SCMFW_WIDGET_JACKET_R,
00985   SCMFW_WIDGET_COLLAR_L,
00986   SCMFW_WIDGET_COLLAR,
00987   SCMFW_WIDGET_COLLAR_R,
00988   SCMFW_WIDGET_TIE_EARRING_L,
00989   SCMFW_WIDGET_TIE_EARRING,
00990   SCMFW_WIDGET_TIE_EARRING_R,
00991   SCMFW_WIDGET_GLASSES_L,
00992   SCMFW_WIDGET_GLASSES,
00993   SCMFW_WIDGET_GLASSES_R,
00994 };
00995 
00997 static const NWidgetPart _nested_select_company_manager_face_widgets[] = {
00998   NWidget(NWID_HORIZONTAL),
00999     NWidget(WWT_CLOSEBOX, COLOUR_GREY),
01000     NWidget(WWT_CAPTION, COLOUR_GREY, SCMFW_WIDGET_CAPTION), SetDataTip(STR_FACE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01001     NWidget(WWT_IMGBTN, COLOUR_GREY, SCMFW_WIDGET_TOGGLE_LARGE_SMALL), SetDataTip(SPR_LARGE_SMALL_WINDOW, STR_FACE_ADVANCED_TOOLTIP),
01002   EndContainer(),
01003   NWidget(WWT_PANEL, COLOUR_GREY, SCMFW_WIDGET_SELECT_FACE),
01004     NWidget(NWID_SPACER), SetMinimalSize(0, 2),
01005     NWidget(NWID_HORIZONTAL), SetPIP(2, 2, 2),
01006       NWidget(NWID_VERTICAL),
01007         NWidget(NWID_HORIZONTAL),
01008           NWidget(NWID_SPACER), SetFill(1, 0),
01009           NWidget(WWT_EMPTY, COLOUR_GREY, SCMFM_WIDGET_FACE), SetMinimalSize(92, 119),
01010           NWidget(NWID_SPACER), SetFill(1, 0),
01011         EndContainer(),
01012         NWidget(NWID_SPACER), SetMinimalSize(0, 2),
01013         NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_RANDOM_NEW_FACE), SetFill(1, 0), SetDataTip(STR_FACE_NEW_FACE_BUTTON, STR_FACE_NEW_FACE_TOOLTIP),
01014         NWidget(NWID_SELECTION, INVALID_COLOUR, SCMFW_WIDGET_SEL_LOADSAVE), // Load/number/save buttons under the portrait in the advanced view.
01015           NWidget(NWID_VERTICAL),
01016             NWidget(NWID_SPACER), SetMinimalSize(0, 5), SetFill(0, 1),
01017             NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_LOAD), SetFill(1, 0), SetDataTip(STR_FACE_LOAD, STR_FACE_LOAD_TOOLTIP),
01018             NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_FACECODE), SetFill(1, 0), SetDataTip(STR_FACE_FACECODE, STR_FACE_FACECODE_TOOLTIP),
01019             NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_SAVE), SetFill(1, 0), SetDataTip(STR_FACE_SAVE, STR_FACE_SAVE_TOOLTIP),
01020             NWidget(NWID_SPACER), SetMinimalSize(0, 5), SetFill(0, 1),
01021           EndContainer(),
01022         EndContainer(),
01023       EndContainer(),
01024       NWidget(NWID_VERTICAL),
01025         NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON), SetFill(1, 0), SetDataTip(STR_FACE_ADVANCED, STR_FACE_ADVANCED_TOOLTIP),
01026         NWidget(NWID_SPACER), SetMinimalSize(0, 2),
01027         NWidget(NWID_SELECTION, INVALID_COLOUR, SCMFW_WIDGET_SEL_MALEFEMALE), // Simple male/female face setting.
01028           NWidget(NWID_VERTICAL),
01029             NWidget(NWID_SPACER), SetFill(0, 1),
01030             NWidget(WWT_TEXTBTN, COLOUR_GREY, SCMFW_WIDGET_MALE), SetFill(1, 0), SetDataTip(STR_FACE_MALE_BUTTON, STR_FACE_MALE_TOOLTIP),
01031             NWidget(WWT_TEXTBTN, COLOUR_GREY, SCMFW_WIDGET_FEMALE), SetFill(1, 0), SetDataTip(STR_FACE_FEMALE_BUTTON, STR_FACE_FEMALE_TOOLTIP),
01032             NWidget(NWID_SPACER), SetFill(0, 1),
01033           EndContainer(),
01034         EndContainer(),
01035         NWidget(NWID_SELECTION, INVALID_COLOUR, SCMFW_WIDGET_SEL_PARTS), // Advanced face parts setting.
01036           NWidget(NWID_VERTICAL),
01037             NWidget(NWID_SPACER), SetMinimalSize(0, 2),
01038             NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01039               NWidget(WWT_TEXTBTN, COLOUR_GREY, SCMFW_WIDGET_MALE2), SetFill(1, 0), SetDataTip(STR_FACE_MALE_BUTTON, STR_FACE_MALE_TOOLTIP),
01040               NWidget(WWT_TEXTBTN, COLOUR_GREY, SCMFW_WIDGET_FEMALE2), SetFill(1, 0), SetDataTip(STR_FACE_FEMALE_BUTTON, STR_FACE_FEMALE_TOOLTIP),
01041             EndContainer(),
01042             NWidget(NWID_SPACER), SetMinimalSize(0, 2),
01043             NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01044               NWidget(WWT_TEXTBTN, COLOUR_GREY, SCMFW_WIDGET_ETHNICITY_EUR), SetFill(1, 0), SetDataTip(STR_FACE_EUROPEAN, STR_FACE_SELECT_EUROPEAN),
01045               NWidget(WWT_TEXTBTN, COLOUR_GREY, SCMFW_WIDGET_ETHNICITY_AFR), SetFill(1, 0), SetDataTip(STR_FACE_AFRICAN, STR_FACE_SELECT_AFRICAN),
01046             EndContainer(),
01047             NWidget(NWID_SPACER), SetMinimalSize(0, 4),
01048             NWidget(NWID_HORIZONTAL),
01049               NWidget(WWT_EMPTY, INVALID_COLOUR, SCMFW_WIDGET_HAS_MOUSTACHE_EARRING_TEXT), SetFill(1, 0),
01050               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_HAS_MOUSTACHE_EARRING), SetDataTip(STR_EMPTY, STR_FACE_MOUSTACHE_EARRING_TOOLTIP),
01051             EndContainer(),
01052             NWidget(NWID_HORIZONTAL),
01053               NWidget(WWT_EMPTY, INVALID_COLOUR, SCMFW_WIDGET_HAS_GLASSES_TEXT), SetFill(1, 0),
01054               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_HAS_GLASSES), SetDataTip(STR_EMPTY, STR_FACE_GLASSES_TOOLTIP),
01055             EndContainer(),
01056             NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetFill(1, 0),
01057             NWidget(NWID_HORIZONTAL),
01058               NWidget(WWT_EMPTY, INVALID_COLOUR, SCMFW_WIDGET_HAIR_TEXT), SetFill(1, 0),
01059               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_HAIR_L), SetDataTip(AWV_DECREASE, STR_FACE_HAIR_TOOLTIP),
01060               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_HAIR), SetDataTip(STR_EMPTY, STR_FACE_HAIR_TOOLTIP),
01061               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_HAIR_R), SetDataTip(AWV_INCREASE, STR_FACE_HAIR_TOOLTIP),
01062             EndContainer(),
01063             NWidget(NWID_HORIZONTAL),
01064               NWidget(WWT_EMPTY, INVALID_COLOUR, SCMFW_WIDGET_EYEBROWS_TEXT), SetFill(1, 0),
01065               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_EYEBROWS_L), SetDataTip(AWV_DECREASE, STR_FACE_EYEBROWS_TOOLTIP),
01066               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_EYEBROWS), SetDataTip(STR_EMPTY, STR_FACE_EYEBROWS_TOOLTIP),
01067               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_EYEBROWS_R), SetDataTip(AWV_INCREASE, STR_FACE_EYEBROWS_TOOLTIP),
01068             EndContainer(),
01069             NWidget(NWID_HORIZONTAL),
01070               NWidget(WWT_EMPTY, INVALID_COLOUR, SCMFW_WIDGET_EYECOLOUR_TEXT), SetFill(1, 0),
01071               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_EYECOLOUR_L), SetDataTip(AWV_DECREASE, STR_FACE_EYECOLOUR_TOOLTIP),
01072               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_EYECOLOUR), SetDataTip(STR_EMPTY, STR_FACE_EYECOLOUR_TOOLTIP),
01073               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_EYECOLOUR_R), SetDataTip(AWV_INCREASE, STR_FACE_EYECOLOUR_TOOLTIP),
01074             EndContainer(),
01075             NWidget(NWID_HORIZONTAL),
01076               NWidget(WWT_EMPTY, INVALID_COLOUR, SCMFW_WIDGET_GLASSES_TEXT), SetFill(1, 0),
01077               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_GLASSES_L), SetDataTip(AWV_DECREASE, STR_FACE_GLASSES_TOOLTIP_2),
01078               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_GLASSES), SetDataTip(STR_EMPTY, STR_FACE_GLASSES_TOOLTIP_2),
01079               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_GLASSES_R), SetDataTip(AWV_INCREASE, STR_FACE_GLASSES_TOOLTIP_2),
01080             EndContainer(),
01081             NWidget(NWID_HORIZONTAL),
01082               NWidget(WWT_EMPTY, INVALID_COLOUR, SCMFW_WIDGET_NOSE_TEXT), SetFill(1, 0),
01083               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_NOSE_L), SetDataTip(AWV_DECREASE, STR_FACE_NOSE_TOOLTIP),
01084               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_NOSE), SetDataTip(STR_EMPTY, STR_FACE_NOSE_TOOLTIP),
01085               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_NOSE_R), SetDataTip(AWV_INCREASE, STR_FACE_NOSE_TOOLTIP),
01086             EndContainer(),
01087             NWidget(NWID_HORIZONTAL),
01088               NWidget(WWT_EMPTY, INVALID_COLOUR, SCMFW_WIDGET_LIPS_MOUSTACHE_TEXT), SetFill(1, 0),
01089               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_LIPS_MOUSTACHE_L), SetDataTip(AWV_DECREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP),
01090               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_LIPS_MOUSTACHE), SetDataTip(STR_EMPTY, STR_FACE_LIPS_MOUSTACHE_TOOLTIP),
01091               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_LIPS_MOUSTACHE_R), SetDataTip(AWV_INCREASE, STR_FACE_LIPS_MOUSTACHE_TOOLTIP),
01092             EndContainer(),
01093             NWidget(NWID_HORIZONTAL),
01094               NWidget(WWT_EMPTY, INVALID_COLOUR, SCMFW_WIDGET_CHIN_TEXT), SetFill(1, 0),
01095               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_CHIN_L), SetDataTip(AWV_DECREASE, STR_FACE_CHIN_TOOLTIP),
01096               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_CHIN), SetDataTip(STR_EMPTY, STR_FACE_CHIN_TOOLTIP),
01097               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_CHIN_R), SetDataTip(AWV_INCREASE, STR_FACE_CHIN_TOOLTIP),
01098             EndContainer(),
01099             NWidget(NWID_HORIZONTAL),
01100               NWidget(WWT_EMPTY, INVALID_COLOUR, SCMFW_WIDGET_JACKET_TEXT), SetFill(1, 0),
01101               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_JACKET_L), SetDataTip(AWV_DECREASE, STR_FACE_JACKET_TOOLTIP),
01102               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_JACKET), SetDataTip(STR_EMPTY, STR_FACE_JACKET_TOOLTIP),
01103               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_JACKET_R), SetDataTip(AWV_INCREASE, STR_FACE_JACKET_TOOLTIP),
01104             EndContainer(),
01105             NWidget(NWID_HORIZONTAL),
01106               NWidget(WWT_EMPTY, INVALID_COLOUR, SCMFW_WIDGET_COLLAR_TEXT), SetFill(1, 0),
01107               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_COLLAR_L), SetDataTip(AWV_DECREASE, STR_FACE_COLLAR_TOOLTIP),
01108               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_COLLAR), SetDataTip(STR_EMPTY, STR_FACE_COLLAR_TOOLTIP),
01109               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_COLLAR_R), SetDataTip(AWV_INCREASE, STR_FACE_COLLAR_TOOLTIP),
01110             EndContainer(),
01111             NWidget(NWID_HORIZONTAL),
01112               NWidget(WWT_EMPTY, INVALID_COLOUR, SCMFW_WIDGET_TIE_EARRING_TEXT), SetFill(1, 0),
01113               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_TIE_EARRING_L), SetDataTip(AWV_DECREASE, STR_FACE_TIE_EARRING_TOOLTIP),
01114               NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_TIE_EARRING), SetDataTip(STR_EMPTY, STR_FACE_TIE_EARRING_TOOLTIP),
01115               NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, SCMFW_WIDGET_TIE_EARRING_R), SetDataTip(AWV_INCREASE, STR_FACE_TIE_EARRING_TOOLTIP),
01116             EndContainer(),
01117             NWidget(NWID_SPACER), SetFill(0, 1),
01118           EndContainer(),
01119         EndContainer(),
01120       EndContainer(),
01121     EndContainer(),
01122     NWidget(NWID_SPACER), SetMinimalSize(0, 2),
01123   EndContainer(),
01124   NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01125     NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_CANCEL), SetFill(1, 0), SetDataTip(STR_BUTTON_CANCEL, STR_FACE_CANCEL_TOOLTIP),
01126     NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, SCMFW_WIDGET_ACCEPT), SetFill(1, 0), SetDataTip(STR_BUTTON_OK, STR_FACE_OK_TOOLTIP),
01127   EndContainer(),
01128 };
01129 
01131 class SelectCompanyManagerFaceWindow : public Window
01132 {
01133   CompanyManagerFace face; 
01134   bool advanced; 
01135 
01136   GenderEthnicity ge; 
01137   bool is_female;     
01138   bool is_moust_male; 
01139 
01140   Dimension yesno_dim;  
01141   Dimension number_dim; 
01142 
01143   static const StringID PART_TEXTS_IS_FEMALE[]; 
01144   static const StringID PART_TEXTS[];           
01145 
01153   void DrawFaceStringLabel(byte widget_index, uint8 val, bool is_bool_widget) const
01154   {
01155     StringID str;
01156     const NWidgetCore *nwi_widget = this->GetWidget<NWidgetCore>(widget_index);
01157     if (!nwi_widget->IsDisabled()) {
01158       if (is_bool_widget) {
01159         /* if it a bool button write yes or no */
01160         str = (val != 0) ? STR_FACE_YES : STR_FACE_NO;
01161       } else {
01162         /* else write the value + 1 */
01163         SetDParam(0, val + 1);
01164         str = STR_JUST_INT;
01165       }
01166 
01167       /* Draw the value/bool in white (0xC). If the button clicked adds 1px to x and y text coordinates (IsWindowWidgetLowered()). */
01168       DrawString(nwi_widget->pos_x + nwi_widget->IsLowered(), nwi_widget->pos_x + nwi_widget->current_x - 1 - nwi_widget->IsLowered(),
01169           nwi_widget->pos_y + 1 + nwi_widget->IsLowered(), str, TC_WHITE, SA_HOR_CENTER);
01170     }
01171   }
01172 
01173   void UpdateData()
01174   {
01175     this->ge = (GenderEthnicity)GB(this->face, _cmf_info[CMFV_GEN_ETHN].offset, _cmf_info[CMFV_GEN_ETHN].length); // get the gender and ethnicity
01176     this->is_female = HasBit(this->ge, GENDER_FEMALE); // get the gender: 0 == male and 1 == female
01177     this->is_moust_male = !is_female && GetCompanyManagerFaceBits(this->face, CMFV_HAS_MOUSTACHE, this->ge) != 0; // is a male face with moustache
01178   }
01179 
01180 public:
01181   SelectCompanyManagerFaceWindow(const WindowDesc *desc, Window *parent) : Window()
01182   {
01183     this->advanced = false;
01184     this->CreateNestedTree(desc);
01185     this->SelectDisplayPlanes(this->advanced);
01186     this->FinishInitNested(desc, parent->window_number);
01187     this->parent = parent;
01188     this->owner = (Owner)this->window_number;
01189     this->face = Company::Get((CompanyID)this->window_number)->face;
01190 
01191     this->UpdateData();
01192   }
01193 
01198   void SelectDisplayPlanes(bool advanced)
01199   {
01200     this->GetWidget<NWidgetStacked>(SCMFW_WIDGET_SEL_LOADSAVE)->SetDisplayedPlane(advanced ? 0 : SZSP_NONE);
01201     this->GetWidget<NWidgetStacked>(SCMFW_WIDGET_SEL_PARTS)->SetDisplayedPlane(advanced ? 0 : SZSP_NONE);
01202     this->GetWidget<NWidgetStacked>(SCMFW_WIDGET_SEL_MALEFEMALE)->SetDisplayedPlane(advanced ? SZSP_NONE : 0);
01203     this->GetWidget<NWidgetCore>(SCMFW_WIDGET_RANDOM_NEW_FACE)->widget_data = advanced ? STR_MAPGEN_RANDOM : STR_FACE_NEW_FACE_BUTTON;
01204 
01205     NWidgetCore *wi = this->GetWidget<NWidgetCore>(SCMFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON);
01206     if (advanced) {
01207       wi->SetDataTip(STR_FACE_SIMPLE, STR_FACE_SIMPLE_TOOLTIP);
01208     } else {
01209       wi->SetDataTip(STR_FACE_ADVANCED, STR_FACE_ADVANCED_TOOLTIP);
01210     }
01211   }
01212 
01213   virtual void OnInit()
01214   {
01215     /* Size of the boolean yes/no button. */
01216     Dimension yesno_dim = maxdim(GetStringBoundingBox(STR_FACE_YES), GetStringBoundingBox(STR_FACE_NO));
01217     yesno_dim.width  += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
01218     yesno_dim.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
01219     /* Size of the number button + arrows. */
01220     Dimension number_dim = {0, 0};
01221     for (int val = 1; val <= 12; val++) {
01222       SetDParam(0, val);
01223       number_dim = maxdim(number_dim, GetStringBoundingBox(STR_JUST_INT));
01224     }
01225     uint arrows_width = GetSpriteSize(SPR_ARROW_LEFT).width + GetSpriteSize(SPR_ARROW_RIGHT).width + 2 * (WD_IMGBTN_LEFT + WD_IMGBTN_RIGHT);
01226     number_dim.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT + arrows_width;
01227     number_dim.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
01228     /* Compute width of both buttons. */
01229     yesno_dim.width = max(yesno_dim.width, number_dim.width);
01230     number_dim.width = yesno_dim.width - arrows_width;
01231 
01232     this->yesno_dim = yesno_dim;
01233     this->number_dim = number_dim;
01234   }
01235 
01236   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
01237   {
01238     switch (widget) {
01239       case SCMFW_WIDGET_HAS_MOUSTACHE_EARRING_TEXT:
01240       case SCMFW_WIDGET_TIE_EARRING_TEXT: {
01241         int offset = (widget - SCMFW_WIDGET_HAS_MOUSTACHE_EARRING_TEXT) * 2;
01242         *size = maxdim(GetStringBoundingBox(PART_TEXTS_IS_FEMALE[offset]), GetStringBoundingBox(PART_TEXTS_IS_FEMALE[offset + 1]));
01243         size->width  += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
01244         size->height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
01245         break;
01246       }
01247 
01248       case SCMFW_WIDGET_LIPS_MOUSTACHE_TEXT:
01249         *size = maxdim(GetStringBoundingBox(STR_FACE_LIPS), GetStringBoundingBox(STR_FACE_MOUSTACHE));
01250         size->width  += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
01251         size->height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
01252         break;
01253 
01254       case SCMFW_WIDGET_HAS_GLASSES_TEXT:
01255       case SCMFW_WIDGET_HAIR_TEXT:
01256       case SCMFW_WIDGET_EYEBROWS_TEXT:
01257       case SCMFW_WIDGET_EYECOLOUR_TEXT:
01258       case SCMFW_WIDGET_GLASSES_TEXT:
01259       case SCMFW_WIDGET_NOSE_TEXT:
01260       case SCMFW_WIDGET_CHIN_TEXT:
01261       case SCMFW_WIDGET_JACKET_TEXT:
01262       case SCMFW_WIDGET_COLLAR_TEXT:
01263         *size = GetStringBoundingBox(PART_TEXTS[widget - SCMFW_WIDGET_HAS_GLASSES_TEXT]);
01264         size->width  += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
01265         size->height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
01266         break;
01267 
01268       case SCMFW_WIDGET_HAS_MOUSTACHE_EARRING:
01269       case SCMFW_WIDGET_HAS_GLASSES:
01270         *size = this->yesno_dim;
01271         break;
01272 
01273       case SCMFW_WIDGET_EYECOLOUR:
01274       case SCMFW_WIDGET_CHIN:
01275       case SCMFW_WIDGET_EYEBROWS:
01276       case SCMFW_WIDGET_LIPS_MOUSTACHE:
01277       case SCMFW_WIDGET_NOSE:
01278       case SCMFW_WIDGET_HAIR:
01279       case SCMFW_WIDGET_JACKET:
01280       case SCMFW_WIDGET_COLLAR:
01281       case SCMFW_WIDGET_TIE_EARRING:
01282       case SCMFW_WIDGET_GLASSES:
01283         *size = this->number_dim;
01284         break;
01285     }
01286   }
01287 
01288   virtual void OnPaint()
01289   {
01290     /* lower the non-selected gender button */
01291     this->SetWidgetsLoweredState(!this->is_female, SCMFW_WIDGET_MALE, SCMFW_WIDGET_MALE2, WIDGET_LIST_END);
01292     this->SetWidgetsLoweredState( this->is_female, SCMFW_WIDGET_FEMALE, SCMFW_WIDGET_FEMALE2, WIDGET_LIST_END);
01293 
01294     /* advanced company manager face selection window */
01295 
01296     /* lower the non-selected ethnicity button */
01297     this->SetWidgetLoweredState(SCMFW_WIDGET_ETHNICITY_EUR, !HasBit(this->ge, ETHNICITY_BLACK));
01298     this->SetWidgetLoweredState(SCMFW_WIDGET_ETHNICITY_AFR,  HasBit(this->ge, ETHNICITY_BLACK));
01299 
01300 
01301     /* Disable dynamically the widgets which CompanyManagerFaceVariable has less than 2 options
01302      * (or in other words you haven't any choice).
01303      * If the widgets depend on a HAS-variable and this is false the widgets will be disabled, too. */
01304 
01305     /* Eye colour buttons */
01306     this->SetWidgetsDisabledState(_cmf_info[CMFV_EYE_COLOUR].valid_values[this->ge] < 2,
01307         SCMFW_WIDGET_EYECOLOUR, SCMFW_WIDGET_EYECOLOUR_L, SCMFW_WIDGET_EYECOLOUR_R, WIDGET_LIST_END);
01308 
01309     /* Chin buttons */
01310     this->SetWidgetsDisabledState(_cmf_info[CMFV_CHIN].valid_values[this->ge] < 2,
01311         SCMFW_WIDGET_CHIN, SCMFW_WIDGET_CHIN_L, SCMFW_WIDGET_CHIN_R, WIDGET_LIST_END);
01312 
01313     /* Eyebrows buttons */
01314     this->SetWidgetsDisabledState(_cmf_info[CMFV_EYEBROWS].valid_values[this->ge] < 2,
01315         SCMFW_WIDGET_EYEBROWS, SCMFW_WIDGET_EYEBROWS_L, SCMFW_WIDGET_EYEBROWS_R, WIDGET_LIST_END);
01316 
01317     /* Lips or (if it a male face with a moustache) moustache buttons */
01318     this->SetWidgetsDisabledState(_cmf_info[this->is_moust_male ? CMFV_MOUSTACHE : CMFV_LIPS].valid_values[this->ge] < 2,
01319         SCMFW_WIDGET_LIPS_MOUSTACHE, SCMFW_WIDGET_LIPS_MOUSTACHE_L, SCMFW_WIDGET_LIPS_MOUSTACHE_R, WIDGET_LIST_END);
01320 
01321     /* Nose buttons | male faces with moustache haven't any nose options */
01322     this->SetWidgetsDisabledState(_cmf_info[CMFV_NOSE].valid_values[this->ge] < 2 || this->is_moust_male,
01323         SCMFW_WIDGET_NOSE, SCMFW_WIDGET_NOSE_L, SCMFW_WIDGET_NOSE_R, WIDGET_LIST_END);
01324 
01325     /* Hair buttons */
01326     this->SetWidgetsDisabledState(_cmf_info[CMFV_HAIR].valid_values[this->ge] < 2,
01327         SCMFW_WIDGET_HAIR, SCMFW_WIDGET_HAIR_L, SCMFW_WIDGET_HAIR_R, WIDGET_LIST_END);
01328 
01329     /* Jacket buttons */
01330     this->SetWidgetsDisabledState(_cmf_info[CMFV_JACKET].valid_values[this->ge] < 2,
01331         SCMFW_WIDGET_JACKET, SCMFW_WIDGET_JACKET_L, SCMFW_WIDGET_JACKET_R, WIDGET_LIST_END);
01332 
01333     /* Collar buttons */
01334     this->SetWidgetsDisabledState(_cmf_info[CMFV_COLLAR].valid_values[this->ge] < 2,
01335         SCMFW_WIDGET_COLLAR, SCMFW_WIDGET_COLLAR_L, SCMFW_WIDGET_COLLAR_R, WIDGET_LIST_END);
01336 
01337     /* Tie/earring buttons | female faces without earring haven't any earring options */
01338     this->SetWidgetsDisabledState(_cmf_info[CMFV_TIE_EARRING].valid_values[this->ge] < 2 ||
01339           (this->is_female && GetCompanyManagerFaceBits(this->face, CMFV_HAS_TIE_EARRING, this->ge) == 0),
01340         SCMFW_WIDGET_TIE_EARRING, SCMFW_WIDGET_TIE_EARRING_L, SCMFW_WIDGET_TIE_EARRING_R, WIDGET_LIST_END);
01341 
01342     /* Glasses buttons | faces without glasses haven't any glasses options */
01343     this->SetWidgetsDisabledState(_cmf_info[CMFV_GLASSES].valid_values[this->ge] < 2 || GetCompanyManagerFaceBits(this->face, CMFV_HAS_GLASSES, this->ge) == 0,
01344         SCMFW_WIDGET_GLASSES, SCMFW_WIDGET_GLASSES_L, SCMFW_WIDGET_GLASSES_R, WIDGET_LIST_END);
01345 
01346     this->DrawWidgets();
01347   }
01348 
01349   virtual void DrawWidget(const Rect &r, int widget) const
01350   {
01351     switch (widget) {
01352       case SCMFW_WIDGET_HAS_MOUSTACHE_EARRING_TEXT:
01353       case SCMFW_WIDGET_TIE_EARRING_TEXT: {
01354         StringID str = PART_TEXTS_IS_FEMALE[(widget - SCMFW_WIDGET_HAS_MOUSTACHE_EARRING_TEXT) * 2 + this->is_female];
01355         DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_FRAMERECT_TOP, str, TC_GOLD, SA_RIGHT);
01356         break;
01357       }
01358 
01359       case SCMFW_WIDGET_LIPS_MOUSTACHE_TEXT:
01360         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);
01361         break;
01362 
01363       case SCMFW_WIDGET_HAS_GLASSES_TEXT:
01364       case SCMFW_WIDGET_HAIR_TEXT:
01365       case SCMFW_WIDGET_EYEBROWS_TEXT:
01366       case SCMFW_WIDGET_EYECOLOUR_TEXT:
01367       case SCMFW_WIDGET_GLASSES_TEXT:
01368       case SCMFW_WIDGET_NOSE_TEXT:
01369       case SCMFW_WIDGET_CHIN_TEXT:
01370       case SCMFW_WIDGET_JACKET_TEXT:
01371       case SCMFW_WIDGET_COLLAR_TEXT:
01372         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);
01373         break;
01374 
01375 
01376       case SCMFW_WIDGET_HAS_MOUSTACHE_EARRING:
01377         if (this->is_female) { // Only for female faces
01378           this->DrawFaceStringLabel(SCMFW_WIDGET_HAS_MOUSTACHE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_HAS_TIE_EARRING, this->ge), true);
01379         } else { // Only for male faces
01380           this->DrawFaceStringLabel(SCMFW_WIDGET_HAS_MOUSTACHE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_HAS_MOUSTACHE,   this->ge), true);
01381         }
01382         break;
01383 
01384       case SCMFW_WIDGET_TIE_EARRING:
01385         if (this->is_female) { // Only for female faces
01386           this->DrawFaceStringLabel(SCMFW_WIDGET_TIE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_TIE_EARRING, this->ge), false);
01387         } else { // Only for male faces
01388           this->DrawFaceStringLabel(SCMFW_WIDGET_TIE_EARRING, GetCompanyManagerFaceBits(this->face, CMFV_TIE_EARRING, this->ge), false);
01389         }
01390         break;
01391 
01392       case SCMFW_WIDGET_LIPS_MOUSTACHE:
01393         if (this->is_moust_male) { // Only for male faces with moustache
01394           this->DrawFaceStringLabel(SCMFW_WIDGET_LIPS_MOUSTACHE, GetCompanyManagerFaceBits(this->face, CMFV_MOUSTACHE, this->ge), false);
01395         } else { // Only for female faces or male faces without moustache
01396           this->DrawFaceStringLabel(SCMFW_WIDGET_LIPS_MOUSTACHE, GetCompanyManagerFaceBits(this->face, CMFV_LIPS,      this->ge), false);
01397         }
01398         break;
01399 
01400       case SCMFW_WIDGET_HAS_GLASSES:
01401         this->DrawFaceStringLabel(SCMFW_WIDGET_HAS_GLASSES, GetCompanyManagerFaceBits(this->face, CMFV_HAS_GLASSES, this->ge), true );
01402         break;
01403 
01404       case SCMFW_WIDGET_HAIR:
01405         this->DrawFaceStringLabel(SCMFW_WIDGET_HAIR,        GetCompanyManagerFaceBits(this->face, CMFV_HAIR,        this->ge), false);
01406         break;
01407 
01408       case SCMFW_WIDGET_EYEBROWS:
01409         this->DrawFaceStringLabel(SCMFW_WIDGET_EYEBROWS,    GetCompanyManagerFaceBits(this->face, CMFV_EYEBROWS,    this->ge), false);
01410         break;
01411 
01412       case SCMFW_WIDGET_EYECOLOUR:
01413         this->DrawFaceStringLabel(SCMFW_WIDGET_EYECOLOUR,   GetCompanyManagerFaceBits(this->face, CMFV_EYE_COLOUR,  this->ge), false);
01414         break;
01415 
01416       case SCMFW_WIDGET_GLASSES:
01417         this->DrawFaceStringLabel(SCMFW_WIDGET_GLASSES,     GetCompanyManagerFaceBits(this->face, CMFV_GLASSES,     this->ge), false);
01418         break;
01419 
01420       case SCMFW_WIDGET_NOSE:
01421         this->DrawFaceStringLabel(SCMFW_WIDGET_NOSE,        GetCompanyManagerFaceBits(this->face, CMFV_NOSE,        this->ge), false);
01422         break;
01423 
01424       case SCMFW_WIDGET_CHIN:
01425         this->DrawFaceStringLabel(SCMFW_WIDGET_CHIN,        GetCompanyManagerFaceBits(this->face, CMFV_CHIN,        this->ge), false);
01426         break;
01427 
01428       case SCMFW_WIDGET_JACKET:
01429         this->DrawFaceStringLabel(SCMFW_WIDGET_JACKET,      GetCompanyManagerFaceBits(this->face, CMFV_JACKET,      this->ge), false);
01430         break;
01431 
01432       case SCMFW_WIDGET_COLLAR:
01433         this->DrawFaceStringLabel(SCMFW_WIDGET_COLLAR,      GetCompanyManagerFaceBits(this->face, CMFV_COLLAR,      this->ge), false);
01434         break;
01435 
01436       case SCMFM_WIDGET_FACE:
01437         DrawCompanyManagerFace(this->face, Company::Get((CompanyID)this->window_number)->colour, r.left, r.top);
01438         break;
01439     }
01440   }
01441 
01442   virtual void OnClick(Point pt, int widget, int click_count)
01443   {
01444     switch (widget) {
01445       /* Toggle size, advanced/simple face selection */
01446       case SCMFW_WIDGET_TOGGLE_LARGE_SMALL:
01447       case SCMFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON:
01448         this->advanced = !this->advanced;
01449         this->SelectDisplayPlanes(this->advanced);
01450         this->ReInit();
01451         break;
01452 
01453       /* OK button */
01454       case SCMFW_WIDGET_ACCEPT:
01455         DoCommandP(0, 0, this->face, CMD_SET_COMPANY_MANAGER_FACE);
01456         /* FALL THROUGH */
01457 
01458       /* Cancel button */
01459       case SCMFW_WIDGET_CANCEL:
01460         delete this;
01461         break;
01462 
01463       /* Load button */
01464       case SCMFW_WIDGET_LOAD:
01465         this->face = _company_manager_face;
01466         ScaleAllCompanyManagerFaceBits(this->face);
01467         ShowErrorMessage(STR_FACE_LOAD_DONE, INVALID_STRING_ID, WL_INFO);
01468         this->UpdateData();
01469         this->SetDirty();
01470         break;
01471 
01472       /* 'Company manager face number' button, view and/or set company manager face number */
01473       case SCMFW_WIDGET_FACECODE:
01474         SetDParam(0, this->face);
01475         ShowQueryString(STR_JUST_INT, STR_FACE_FACECODE_CAPTION, 10 + 1, this, CS_NUMERAL, QSF_NONE);
01476         break;
01477 
01478       /* Save button */
01479       case SCMFW_WIDGET_SAVE:
01480         _company_manager_face = this->face;
01481         ShowErrorMessage(STR_FACE_SAVE_DONE, INVALID_STRING_ID, WL_INFO);
01482         break;
01483 
01484       /* Toggle gender (male/female) button */
01485       case SCMFW_WIDGET_MALE:
01486       case SCMFW_WIDGET_FEMALE:
01487       case SCMFW_WIDGET_MALE2:
01488       case SCMFW_WIDGET_FEMALE2:
01489         SetCompanyManagerFaceBits(this->face, CMFV_GENDER, this->ge, (widget == SCMFW_WIDGET_FEMALE || widget == SCMFW_WIDGET_FEMALE2));
01490         ScaleAllCompanyManagerFaceBits(this->face);
01491         this->UpdateData();
01492         this->SetDirty();
01493         break;
01494 
01495       /* Randomize face button */
01496       case SCMFW_WIDGET_RANDOM_NEW_FACE:
01497         RandomCompanyManagerFaceBits(this->face, this->ge, this->advanced);
01498         this->UpdateData();
01499         this->SetDirty();
01500         break;
01501 
01502       /* Toggle ethnicity (european/african) button */
01503       case SCMFW_WIDGET_ETHNICITY_EUR:
01504       case SCMFW_WIDGET_ETHNICITY_AFR:
01505         SetCompanyManagerFaceBits(this->face, CMFV_ETHNICITY, this->ge, widget - SCMFW_WIDGET_ETHNICITY_EUR);
01506         ScaleAllCompanyManagerFaceBits(this->face);
01507         this->UpdateData();
01508         this->SetDirty();
01509         break;
01510 
01511       default:
01512         /* Here all buttons from SCMFW_WIDGET_HAS_MOUSTACHE_EARRING to SCMFW_WIDGET_GLASSES_R are handled.
01513          * First it checks which CompanyManagerFaceVariable is being changed, and then either
01514          * a: invert the value for boolean variables, or
01515          * b: it checks inside of IncreaseCompanyManagerFaceBits() if a left (_L) butten is pressed and then decrease else increase the variable */
01516         if (widget >= SCMFW_WIDGET_HAS_MOUSTACHE_EARRING && widget <= SCMFW_WIDGET_GLASSES_R) {
01517           CompanyManagerFaceVariable cmfv; // which CompanyManagerFaceVariable shall be edited
01518 
01519           if (widget < SCMFW_WIDGET_EYECOLOUR_L) { // Bool buttons
01520             switch (widget - SCMFW_WIDGET_HAS_MOUSTACHE_EARRING) {
01521               default: NOT_REACHED();
01522               case 0: cmfv = this->is_female ? CMFV_HAS_TIE_EARRING : CMFV_HAS_MOUSTACHE; break; // Has earring/moustache button
01523               case 1: cmfv = CMFV_HAS_GLASSES; break; // Has glasses button
01524             }
01525             SetCompanyManagerFaceBits(this->face, cmfv, this->ge, !GetCompanyManagerFaceBits(this->face, cmfv, this->ge));
01526             ScaleAllCompanyManagerFaceBits(this->face);
01527           } else { // Value buttons
01528             switch ((widget - SCMFW_WIDGET_EYECOLOUR_L) / 3) {
01529               default: NOT_REACHED();
01530               case 0: cmfv = CMFV_EYE_COLOUR; break;  // Eye colour buttons
01531               case 1: cmfv = CMFV_CHIN; break;        // Chin buttons
01532               case 2: cmfv = CMFV_EYEBROWS; break;    // Eyebrows buttons
01533               case 3: cmfv = this->is_moust_male ? CMFV_MOUSTACHE : CMFV_LIPS; break; // Moustache or lips buttons
01534               case 4: cmfv = CMFV_NOSE; break;        // Nose buttons
01535               case 5: cmfv = CMFV_HAIR; break;        // Hair buttons
01536               case 6: cmfv = CMFV_JACKET; break;      // Jacket buttons
01537               case 7: cmfv = CMFV_COLLAR; break;      // Collar buttons
01538               case 8: cmfv = CMFV_TIE_EARRING; break; // Tie/earring buttons
01539               case 9: cmfv = CMFV_GLASSES; break;     // Glasses buttons
01540             }
01541             /* 0 == left (_L), 1 == middle or 2 == right (_R) - button click */
01542             IncreaseCompanyManagerFaceBits(this->face, cmfv, this->ge, (((widget - SCMFW_WIDGET_EYECOLOUR_L) % 3) != 0) ? 1 : -1);
01543           }
01544           this->UpdateData();
01545           this->SetDirty();
01546         }
01547         break;
01548     }
01549   }
01550 
01551   virtual void OnQueryTextFinished(char *str)
01552   {
01553     if (str == NULL) return;
01554     /* Set a new company manager face number */
01555     if (!StrEmpty(str)) {
01556       this->face = strtoul(str, NULL, 10);
01557       ScaleAllCompanyManagerFaceBits(this->face);
01558       ShowErrorMessage(STR_FACE_FACECODE_SET, INVALID_STRING_ID, WL_INFO);
01559       this->UpdateData();
01560       this->SetDirty();
01561     } else {
01562       ShowErrorMessage(STR_FACE_FACECODE_ERR, INVALID_STRING_ID, WL_INFO);
01563     }
01564   }
01565 };
01566 
01568 const StringID SelectCompanyManagerFaceWindow::PART_TEXTS_IS_FEMALE[] = {
01569   STR_FACE_MOUSTACHE, STR_FACE_EARRING, // SCMFW_WIDGET_HAS_MOUSTACHE_EARRING_TEXT
01570   STR_FACE_TIE,       STR_FACE_EARRING, // SCMFW_WIDGET_TIE_EARRING_TEXT
01571 };
01572 
01574 const StringID SelectCompanyManagerFaceWindow::PART_TEXTS[] = {
01575   STR_FACE_GLASSES,   // SCMFW_WIDGET_HAS_GLASSES_TEXT
01576   STR_FACE_HAIR,      // SCMFW_WIDGET_HAIR_TEXT
01577   STR_FACE_EYEBROWS,  // SCMFW_WIDGET_EYEBROWS_TEXT
01578   STR_FACE_EYECOLOUR, // SCMFW_WIDGET_EYECOLOUR_TEXT
01579   STR_FACE_GLASSES,   // SCMFW_WIDGET_GLASSES_TEXT
01580   STR_FACE_NOSE,      // SCMFW_WIDGET_NOSE_TEXT
01581   STR_FACE_CHIN,      // SCMFW_WIDGET_CHIN_TEXT
01582   STR_FACE_JACKET,    // SCMFW_WIDGET_JACKET_TEXT
01583   STR_FACE_COLLAR,    // SCMFW_WIDGET_COLLAR_TEXT
01584 };
01585 
01587 static const WindowDesc _select_company_manager_face_desc(
01588   WDP_AUTO, 0, 0,
01589   WC_COMPANY_MANAGER_FACE, WC_NONE,
01590   WDF_UNCLICK_BUTTONS | WDF_CONSTRUCTION,
01591   _nested_select_company_manager_face_widgets, lengthof(_nested_select_company_manager_face_widgets)
01592 );
01593 
01602 static void DoSelectCompanyManagerFace(Window *parent)
01603 {
01604   if (!Company::IsValidID((CompanyID)parent->window_number)) return;
01605 
01606   if (BringWindowToFrontById(WC_COMPANY_MANAGER_FACE, parent->window_number)) return;
01607   new SelectCompanyManagerFaceWindow(&_select_company_manager_face_desc, parent);
01608 }
01609 
01611 enum CompanyInfrastructureWindowWidgets {
01612   CIW_WIDGET_CAPTION,
01613   CIW_WIDGET_RAIL_DESC,
01614   CIW_WIDGET_RAIL_COUNT,
01615   CIW_WIDGET_ROAD_DESC,
01616   CIW_WIDGET_ROAD_COUNT,
01617   CIW_WIDGET_WATER_DESC,
01618   CIW_WIDGET_WATER_COUNT,
01619   CIW_WIDGET_STATION_DESC,
01620   CIW_WIDGET_STATION_COUNT,
01621   CIW_WIDGET_TOTAL_DESC,
01622   CIW_WIDGET_TOTAL,
01623 };
01624 
01625 static const NWidgetPart _nested_company_infrastructure_widgets[] = {
01626   NWidget(NWID_HORIZONTAL),
01627     NWidget(WWT_CLOSEBOX, COLOUR_GREY),
01628     NWidget(WWT_CAPTION, COLOUR_GREY, CIW_WIDGET_CAPTION), SetDataTip(STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01629     NWidget(WWT_SHADEBOX, COLOUR_GREY),
01630     NWidget(WWT_STICKYBOX, COLOUR_GREY),
01631   EndContainer(),
01632   NWidget(WWT_PANEL, COLOUR_GREY),
01633     NWidget(NWID_VERTICAL), SetPIP(WD_FRAMERECT_TOP, 4, WD_FRAMETEXT_BOTTOM),
01634       NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
01635         NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_RAIL_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0),
01636         NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_RAIL_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1),
01637       EndContainer(),
01638       NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
01639         NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_ROAD_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0),
01640         NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_ROAD_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1),
01641       EndContainer(),
01642       NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
01643         NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_WATER_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0),
01644         NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_WATER_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1),
01645       EndContainer(),
01646       NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
01647         NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_STATION_DESC), SetMinimalTextLines(3, 0), SetFill(1, 0),
01648         NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_STATION_COUNT), SetMinimalTextLines(3, 0), SetFill(0, 1),
01649       EndContainer(),
01650       NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
01651         NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_TOTAL_DESC), SetFill(1, 0),
01652         NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_TOTAL), SetFill(0, 1),
01653       EndContainer(),
01654     EndContainer(),
01655   EndContainer(),
01656 };
01657 
01661 struct CompanyInfrastructureWindow : Window
01662 {
01663   RailTypes railtypes; 
01664   RoadTypes roadtypes; 
01665 
01666   uint total_width; 
01667 
01668   CompanyInfrastructureWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
01669   {
01670     this->UpdateRailRoadTypes();
01671 
01672     this->InitNested(desc, window_number);
01673     this->owner = (Owner)this->window_number;
01674   }
01675 
01676   void UpdateRailRoadTypes()
01677   {
01678     this->railtypes = RAILTYPES_NONE;
01679     this->roadtypes = ROADTYPES_ROAD; // Road is always available.
01680 
01681     /* Find the used railtypes. */
01682     Engine *e;
01683     FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) {
01684       if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue;
01685 
01686       this->railtypes |= GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes;
01687     }
01688 
01689     /* Get the date introduced railtypes as well. */
01690     this->railtypes = AddDateIntroducedRailTypes(this->railtypes, MAX_DAY);
01691 
01692     /* Tram is only visible when there will be a tram. */
01693     FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) {
01694       if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue;
01695       if (!HasBit(e->info.misc_flags, EF_ROAD_TRAM)) continue;
01696 
01697       this->roadtypes |= ROADTYPES_TRAM;
01698       break;
01699     }
01700   }
01701 
01703   Money GetTotalMaintenanceCost() const
01704   {
01705     const Company *c = Company::Get((CompanyID)this->window_number);
01706     Money total;
01707 
01708     for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
01709       if (HasBit(this->railtypes, rt)) total += RailMaintenanceCost(rt, c->rail_infrastructure[rt]);
01710     }
01711     total += SignalMaintenanceCost(c->signal_infrastructure);
01712 
01713     if (HasBit(this->roadtypes, ROADTYPE_ROAD)) total += RoadMaintenanceCost(ROADTYPE_ROAD, c->road_infrastructure[ROADTYPE_ROAD]);
01714     if (HasBit(this->roadtypes, ROADTYPE_TRAM)) total += RoadMaintenanceCost(ROADTYPE_TRAM, c->road_infrastructure[ROADTYPE_TRAM]);
01715 
01716     total += CanalMaintenanceCost(c->water_infrastructure);
01717     total += StationMaintenanceCost(c->station_infrastructure);
01718     total += AirportMaintenanceCost(c->index);
01719 
01720     return total;
01721   }
01722 
01723   virtual void SetStringParameters(int widget) const
01724   {
01725     switch (widget) {
01726       case CIW_WIDGET_CAPTION:
01727         SetDParam(0, (CompanyID)this->window_number);
01728         break;
01729     }
01730   }
01731 
01732   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
01733   {
01734     const Company *c = Company::Get((CompanyID)this->window_number);
01735 
01736     switch (widget) {
01737       case CIW_WIDGET_RAIL_DESC: {
01738         uint lines = 1;
01739 
01740         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT).width);
01741 
01742         for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) {
01743           if (HasBit(this->railtypes, rt)) {
01744             lines++;
01745             SetDParam(0, GetRailTypeInfo(rt)->strings.toolbar_caption);
01746             size->width = max(size->width, GetStringBoundingBox(STR_WHITE_STRING).width + WD_FRAMERECT_LEFT);
01747           }
01748         }
01749         if (this->railtypes != RAILTYPES_NONE) {
01750           lines++;
01751           size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS).width + WD_FRAMERECT_LEFT);
01752         }
01753 
01754         size->height = max(size->height, lines * FONT_HEIGHT_NORMAL);
01755         break;
01756       }
01757 
01758       case CIW_WIDGET_ROAD_DESC: {
01759         uint lines = 1;
01760 
01761         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT).width);
01762 
01763         if (HasBit(this->roadtypes, ROADTYPE_ROAD)) {
01764           lines++;
01765           size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD).width + WD_FRAMERECT_LEFT);
01766         }
01767         if (HasBit(this->roadtypes, ROADTYPE_TRAM)) {
01768           lines++;
01769           size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY).width + WD_FRAMERECT_LEFT);
01770         }
01771 
01772         size->height = max(size->height, lines * FONT_HEIGHT_NORMAL);
01773         break;
01774       }
01775 
01776       case CIW_WIDGET_WATER_DESC:
01777         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT).width);
01778         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS).width + WD_FRAMERECT_LEFT);
01779         break;
01780 
01781       case CIW_WIDGET_STATION_DESC:
01782         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT).width);
01783         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS).width + WD_FRAMERECT_LEFT);
01784         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS).width + WD_FRAMERECT_LEFT);
01785         break;
01786 
01787       case CIW_WIDGET_RAIL_COUNT:
01788       case CIW_WIDGET_ROAD_COUNT:
01789       case CIW_WIDGET_WATER_COUNT:
01790       case CIW_WIDGET_STATION_COUNT:
01791       case CIW_WIDGET_TOTAL: {
01792         /* Find the maximum count that is displayed. */
01793         uint32 max_val = 1000;
01794         Money max_cost = 10000;
01795         for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) {
01796           max_val = max(max_val, c->rail_infrastructure[rt]);
01797           max_cost = max(max_cost, RailMaintenanceCost(rt, c->rail_infrastructure[rt]));
01798         }
01799         max_val = max(max_val, c->signal_infrastructure);
01800         max_cost = max(max_cost, SignalMaintenanceCost(c->signal_infrastructure));
01801         for (RoadType rt = ROADTYPE_BEGIN; rt < ROADTYPE_END; rt++) {
01802           max_val = max(max_val, c->road_infrastructure[rt]);
01803           max_cost = max(max_cost, RoadMaintenanceCost(rt, c->road_infrastructure[rt]));
01804         }
01805         max_val = max(max_val, c->water_infrastructure);
01806         max_cost = max(max_cost, CanalMaintenanceCost(c->water_infrastructure));
01807         max_val = max(max_val, c->station_infrastructure);
01808         max_cost = max(max_cost, StationMaintenanceCost(c->station_infrastructure));
01809         max_val = max(max_val, c->airport_infrastructure);
01810         max_cost = max(max_cost, AirportMaintenanceCost(c->index));
01811 
01812         SetDParam(0, max_val);
01813         SetDParam(1, max_cost * 12); // Convert to per year
01814         size->width = max(size->width, GetStringBoundingBox(_settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA).width + 20); // Reserve some wiggle room.
01815 
01816         if (_settings_game.economy.infrastructure_maintenance) {
01817           SetDParam(0, this->GetTotalMaintenanceCost() * 12); // Convert to per year
01818           this->total_width = GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL).width + 20;
01819           size->width = max(size->width, this->total_width);
01820         }
01821 
01822         /* Set height of the total line. */
01823         if (widget == CIW_WIDGET_TOTAL) {
01824           size->height = _settings_game.economy.infrastructure_maintenance ? max(size->height, EXP_LINESPACE + FONT_HEIGHT_NORMAL) : 0;
01825         }
01826         break;
01827       }
01828     }
01829   }
01830 
01831   virtual void DrawWidget(const Rect &r, int widget) const
01832   {
01833     const Company *c = Company::Get((CompanyID)this->window_number);
01834     int y = r.top;
01835 
01836     int offs_left = _current_text_dir == TD_LTR ? WD_FRAMERECT_LEFT : 0;
01837     int offs_right = _current_text_dir == TD_LTR ? 0 : WD_FRAMERECT_LEFT;
01838 
01839     switch (widget) {
01840       case CIW_WIDGET_RAIL_DESC:
01841         DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT);
01842 
01843         if (this->railtypes != RAILTYPES_NONE) {
01844           /* Draw name of each valid railtype. */
01845           for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
01846             if (HasBit(this->railtypes, rt)) {
01847               SetDParam(0, GetRailTypeInfo(rt)->strings.toolbar_caption);
01848               DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_WHITE_STRING);
01849             }
01850           }
01851           DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS);
01852         } else {
01853           /* No valid railtype. */
01854           DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE);
01855         }
01856 
01857         break;
01858 
01859       case CIW_WIDGET_RAIL_COUNT:
01860         /* Draw infrastructure count for each valid railtype. */
01861         for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
01862           if (HasBit(this->railtypes, rt)) {
01863             SetDParam(0, c->rail_infrastructure[rt]);
01864             SetDParam(1, RailMaintenanceCost(rt, c->rail_infrastructure[rt]) * 12); // Convert to per year
01865             DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA);
01866           }
01867         }
01868         if (this->railtypes != RAILTYPES_NONE) {
01869           SetDParam(0, c->signal_infrastructure);
01870           SetDParam(1, SignalMaintenanceCost(c->signal_infrastructure) * 12); // Convert to per year
01871           DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA);
01872         }
01873         break;
01874 
01875       case CIW_WIDGET_ROAD_DESC:
01876         DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT);
01877 
01878         if (this->roadtypes != ROADTYPES_NONE) {
01879           if (HasBit(this->roadtypes, ROADTYPE_ROAD)) DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD);
01880           if (HasBit(this->roadtypes, ROADTYPE_TRAM)) DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY);
01881         } else {
01882           /* No valid roadtypes. */
01883           DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE);
01884         }
01885 
01886         break;
01887 
01888       case CIW_WIDGET_ROAD_COUNT:
01889         if (HasBit(this->roadtypes, ROADTYPE_ROAD)) {
01890           SetDParam(0, c->road_infrastructure[ROADTYPE_ROAD]);
01891           SetDParam(1, RoadMaintenanceCost(ROADTYPE_ROAD, c->road_infrastructure[ROADTYPE_ROAD]) * 12); // Convert to per year
01892           DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA);
01893         }
01894         if (HasBit(this->roadtypes, ROADTYPE_TRAM)) {
01895           SetDParam(0, c->road_infrastructure[ROADTYPE_TRAM]);
01896           SetDParam(1, RoadMaintenanceCost(ROADTYPE_TRAM, c->road_infrastructure[ROADTYPE_TRAM]) * 12); // Convert to per year
01897           DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA);
01898         }
01899         break;
01900 
01901       case CIW_WIDGET_WATER_DESC:
01902         DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT);
01903         DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS);
01904         break;
01905 
01906       case CIW_WIDGET_WATER_COUNT:
01907         SetDParam(0, c->water_infrastructure);
01908         SetDParam(1, CanalMaintenanceCost(c->water_infrastructure) * 12); // Convert to per year
01909         DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA);
01910         break;
01911 
01912       case CIW_WIDGET_TOTAL:
01913         if (_settings_game.economy.infrastructure_maintenance) {
01914           GfxFillRect(r.left, y, r.left + this->total_width, y, PC_WHITE);
01915           y += EXP_LINESPACE;
01916           SetDParam(0, this->GetTotalMaintenanceCost() * 12); // Convert to per year
01917           DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_TOTAL);
01918         }
01919         break;
01920 
01921       case CIW_WIDGET_STATION_DESC:
01922         DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT);
01923         DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS);
01924         DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS);
01925         break;
01926 
01927       case CIW_WIDGET_STATION_COUNT:
01928         SetDParam(0, c->station_infrastructure);
01929         SetDParam(1, StationMaintenanceCost(c->station_infrastructure) * 12); // Convert to per year
01930         DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA);
01931         SetDParam(0, c->airport_infrastructure);
01932         SetDParam(1, AirportMaintenanceCost(c->index) * 12); // Convert to per year
01933         DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, _settings_game.economy.infrastructure_maintenance ? STR_COMPANY_INFRASTRUCTURE_VIEW_COST : STR_WHITE_COMMA);
01934         break;
01935     }
01936   }
01937 
01943   virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
01944   {
01945     if (!gui_scope) return;
01946 
01947     this->UpdateRailRoadTypes();
01948     this->ReInit();
01949   }
01950 };
01951 
01952 static const WindowDesc _company_infrastructure_desc(
01953   WDP_AUTO, 0, 0,
01954   WC_COMPANY_INFRASTRUCTURE, WC_NONE,
01955   WDF_UNCLICK_BUTTONS,
01956   _nested_company_infrastructure_widgets, lengthof(_nested_company_infrastructure_widgets)
01957 );
01958 
01963 static void ShowCompanyInfrastructure(CompanyID company)
01964 {
01965   if (!Company::IsValidID(company)) return;
01966   AllocateWindowDescFront<CompanyInfrastructureWindow>(&_company_infrastructure_desc, company);
01967 }
01968 
01970 enum CompanyWindowWidgets {
01971   CW_WIDGET_CAPTION,
01972 
01973   CW_WIDGET_FACE,
01974   CW_WIDGET_FACE_TITLE,
01975 
01976   CW_WIDGET_DESC_INAUGURATION,
01977   CW_WIDGET_DESC_COLOUR_SCHEME,
01978   CW_WIDGET_DESC_COLOUR_SCHEME_EXAMPLE,
01979   CW_WIDGET_DESC_VEHICLE,
01980   CW_WIDGET_DESC_VEHICLE_COUNTS,
01981   CW_WIDGET_DESC_COMPANY_VALUE,
01982   CW_WIDGET_DESC_INFRASTRUCTURE,
01983   CW_WIDGET_DESC_INFRASTRUCTURE_COUNTS,
01984   CW_WIDGET_DESC_OWNERS,
01985 
01986   CW_WIDGET_SELECT_BUTTONS,     
01987   CW_WIDGET_NEW_FACE,
01988   CW_WIDGET_COLOUR_SCHEME,
01989   CW_WIDGET_PRESIDENT_NAME,
01990   CW_WIDGET_COMPANY_NAME,
01991   CW_WIDGET_BUY_SHARE,
01992   CW_WIDGET_SELL_SHARE,
01993 
01994   CW_WIDGET_SELECT_VIEW_BUILD_HQ,
01995   CW_WIDGET_VIEW_HQ,
01996   CW_WIDGET_BUILD_HQ,
01997 
01998   CW_WIDGET_SELECT_RELOCATE,    
01999   CW_WIDGET_RELOCATE_HQ,
02000 
02001   CW_WIDGET_PROFILE_LOAD,       
02002   CW_WIDGET_PROFILE_SAVE,       
02003 
02004   CW_WIDGET_VIEW_INFRASTRUCTURE,
02005 
02006   CW_WIDGET_HAS_PASSWORD,       
02007   CW_WIDGET_SELECT_MULTIPLAYER, 
02008   CW_WIDGET_COMPANY_PASSWORD,
02009   CW_WIDGET_COMPANY_JOIN,
02010 };
02011 
02012 static const NWidgetPart _nested_company_widgets[] = {
02013   NWidget(NWID_HORIZONTAL),
02014     NWidget(WWT_CLOSEBOX, COLOUR_GREY),
02015     NWidget(WWT_CAPTION, COLOUR_GREY, CW_WIDGET_CAPTION), SetDataTip(STR_COMPANY_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
02016     NWidget(WWT_SHADEBOX, COLOUR_GREY),
02017     NWidget(WWT_STICKYBOX, COLOUR_GREY),
02018   EndContainer(),
02019   NWidget(WWT_PANEL, COLOUR_GREY),
02020     NWidget(NWID_HORIZONTAL), SetPIP(4, 6, 4),
02021       NWidget(NWID_VERTICAL), SetPIP(4, 2, 4),
02022         NWidget(WWT_EMPTY, INVALID_COLOUR, CW_WIDGET_FACE), SetMinimalSize(92, 119), SetFill(1, 0),
02023         NWidget(WWT_EMPTY, INVALID_COLOUR, CW_WIDGET_FACE_TITLE), SetFill(1, 1), SetMinimalTextLines(2, 0),
02024       EndContainer(),
02025       NWidget(NWID_VERTICAL),
02026         NWidget(NWID_HORIZONTAL),
02027           NWidget(NWID_VERTICAL), SetPIP(4, 5, 5),
02028             NWidget(WWT_TEXT, COLOUR_GREY, CW_WIDGET_DESC_INAUGURATION), SetDataTip(STR_COMPANY_VIEW_INAUGURATED_TITLE, STR_NULL), SetFill(1, 0),
02029             NWidget(NWID_HORIZONTAL), SetPIP(0, 5, 0),
02030               NWidget(WWT_LABEL, COLOUR_GREY, CW_WIDGET_DESC_COLOUR_SCHEME), SetDataTip(STR_COMPANY_VIEW_COLOUR_SCHEME_TITLE, STR_NULL),
02031               NWidget(WWT_EMPTY, INVALID_COLOUR, CW_WIDGET_DESC_COLOUR_SCHEME_EXAMPLE), SetMinimalSize(30, 0), SetFill(0, 1),
02032               NWidget(NWID_SPACER), SetFill(1, 0),
02033             EndContainer(),
02034             NWidget(NWID_HORIZONTAL), SetPIP(0, 4, 0),
02035               NWidget(NWID_VERTICAL),
02036                 NWidget(WWT_TEXT, COLOUR_GREY, CW_WIDGET_DESC_VEHICLE), SetDataTip(STR_COMPANY_VIEW_VEHICLES_TITLE, STR_NULL),
02037                 NWidget(NWID_SPACER), SetFill(0, 1),
02038               EndContainer(),
02039               NWidget(WWT_EMPTY, INVALID_COLOUR, CW_WIDGET_DESC_VEHICLE_COUNTS), SetMinimalTextLines(4, 0),
02040               NWidget(NWID_SPACER), SetFill(1, 0),
02041             EndContainer(),
02042           EndContainer(),
02043           NWidget(NWID_VERTICAL), SetPIP(4, 2, 4),
02044             NWidget(NWID_SELECTION, INVALID_COLOUR, CW_WIDGET_SELECT_VIEW_BUILD_HQ),
02045               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),
02046               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),
02047             EndContainer(),
02048             NWidget(NWID_SELECTION, INVALID_COLOUR, CW_WIDGET_SELECT_RELOCATE),
02049               NWidget(WWT_TEXTBTN, COLOUR_GREY, CW_WIDGET_RELOCATE_HQ), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_RELOCATE_HQ, STR_COMPANY_VIEW_RELOCATE_COMPANY_HEADQUARTERS),
02050               NWidget(NWID_SPACER), SetMinimalSize(90, 0),
02051             EndContainer(),
02052             /* Company Profile buttons */
02053             NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CW_WIDGET_PROFILE_LOAD), SetFill(1, 0), SetDataTip(STR_COMPANY_PROFILE_LOAD_BUTTON, STR_COMPANY_PROFILE_LOAD_TOOLTIP),
02054             NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CW_WIDGET_PROFILE_SAVE), SetFill(1, 0), SetDataTip(STR_COMPANY_PROFILE_SAVE_BUTTON, STR_COMPANY_PROFILE_SAVE_TOOLTIP),
02055             NWidget(NWID_SPACER), SetFill(0, 1),
02056           EndContainer(),
02057         EndContainer(),
02058         NWidget(WWT_TEXT, COLOUR_GREY, CW_WIDGET_DESC_COMPANY_VALUE), SetDataTip(STR_COMPANY_VIEW_COMPANY_VALUE, STR_NULL), SetFill(1, 0),
02059           NWidget(NWID_VERTICAL), SetPIP(4, 2, 4),
02060             NWidget(NWID_HORIZONTAL), SetPIP(0, 4, 0),
02061               NWidget(NWID_VERTICAL),
02062                 NWidget(WWT_TEXT, COLOUR_GREY, CW_WIDGET_DESC_INFRASTRUCTURE), SetDataTip(STR_COMPANY_VIEW_INFRASTRUCTURE, STR_NULL),
02063                 NWidget(NWID_SPACER), SetFill(0, 1),
02064               EndContainer(),
02065               NWidget(WWT_EMPTY, INVALID_COLOUR, CW_WIDGET_DESC_INFRASTRUCTURE_COUNTS), SetMinimalTextLines(5, 0), SetFill(1, 0),
02066               NWidget(NWID_VERTICAL),
02067                 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CW_WIDGET_VIEW_INFRASTRUCTURE), SetDataTip(STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON, STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP),
02068                 NWidget(NWID_SPACER), SetFill(0, 1), SetMinimalSize(90, 0),
02069               EndContainer(),
02070             EndContainer(),
02071           EndContainer(),
02072         NWidget(NWID_HORIZONTAL),
02073           NWidget(NWID_VERTICAL), SetPIP(5, 5, 4),
02074             NWidget(WWT_EMPTY, INVALID_COLOUR, CW_WIDGET_DESC_OWNERS), SetMinimalTextLines(3, 0),
02075             NWidget(NWID_SPACER), SetFill(0, 1),
02076           EndContainer(),
02077           NWidget(NWID_VERTICAL), SetPIP(4, 2, 4),
02078             NWidget(NWID_SPACER), SetMinimalSize(90, 0), SetFill(0, 1),
02079             /* Multi player buttons. */
02080             NWidget(NWID_HORIZONTAL),
02081               NWidget(WWT_EMPTY, COLOUR_GREY, CW_WIDGET_HAS_PASSWORD),
02082               NWidget(NWID_SELECTION, INVALID_COLOUR, CW_WIDGET_SELECT_MULTIPLAYER),
02083                 NWidget(NWID_SPACER), SetFill(1, 0),
02084                 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CW_WIDGET_COMPANY_PASSWORD), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_PASSWORD, STR_COMPANY_VIEW_PASSWORD_TOOLTIP),
02085                 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CW_WIDGET_COMPANY_JOIN), SetFill(1, 0), SetDataTip(STR_COMPANY_VIEW_JOIN, STR_COMPANY_VIEW_JOIN_TOOLTIP),
02086               EndContainer(),
02087             EndContainer(),
02088           EndContainer(),
02089         EndContainer(),
02090       EndContainer(),
02091     EndContainer(),
02092   EndContainer(),
02093   /* Button bars at the bottom. */
02094   NWidget(NWID_SELECTION, INVALID_COLOUR, CW_WIDGET_SELECT_BUTTONS),
02095     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
02096       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),
02097       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),
02098       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),
02099       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),
02100     EndContainer(),
02101     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
02102       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),
02103       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),
02104     EndContainer(),
02105   EndContainer(),
02106 };
02107 
02108 int GetAmountOwnedBy(const Company *c, Owner owner)
02109 {
02110   return (c->share_owners[0] == owner) +
02111          (c->share_owners[1] == owner) +
02112          (c->share_owners[2] == owner) +
02113          (c->share_owners[3] == owner);
02114 }
02115 
02117 static const StringID _company_view_vehicle_count_strings[] = {
02118   STR_COMPANY_VIEW_TRAINS, STR_COMPANY_VIEW_ROAD_VEHICLES, STR_COMPANY_VIEW_SHIPS, STR_COMPANY_VIEW_AIRCRAFT
02119 };
02120 
02124 struct CompanyWindow : Window
02125 {
02126   CompanyWindowWidgets query_widget;
02127 
02129   enum CompanyWindowPlanes {
02130     /* Display planes of the #CW_WIDGET_SELECT_MULTIPLAYER selection widget. */
02131     CWP_MP_EMPTY = 0, 
02132     CWP_MP_C_PWD,     
02133     CWP_MP_C_JOIN,    
02134 
02135     /* Display planes of the #CW_WIDGET_SELECT_VIEW_BUILD_HQ selection widget. */
02136     CWP_VB_VIEW = 0,  
02137     CWP_VB_BUILD,     
02138 
02139     /* Display planes of the #CW_WIDGET_SELECT_RELOCATE selection widget. */
02140     CWP_RELOCATE_SHOW = 0, 
02141     CWP_RELOCATE_HIDE,     
02142 
02143     /* Display planes of the #CW_WIDGET_SELECT_BUTTONS selection widget. */
02144     CWP_BUTTONS_LOCAL = 0, 
02145     CWP_BUTTONS_OTHER,     
02146   };
02147 
02148   CompanyWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
02149   {
02150     this->InitNested(desc, window_number);
02151     this->owner = (Owner)this->window_number;
02152   }
02153 
02154   virtual void OnPaint()
02155   {
02156     const Company *c = Company::Get((CompanyID)this->window_number);
02157     bool local = this->window_number == _local_company;
02158 
02159     if (!this->IsShaded()) {
02160       /* Button bar selection. */
02161       int plane = local ? CWP_BUTTONS_LOCAL : CWP_BUTTONS_OTHER;
02162       NWidgetStacked *wi = this->GetWidget<NWidgetStacked>(CW_WIDGET_SELECT_BUTTONS);
02163       if (plane != wi->shown_plane) {
02164         wi->SetDisplayedPlane(plane);
02165         this->SetDirty();
02166         return;
02167       }
02168 
02169       /* Build HQ button handling. */
02170       plane = (local && c->location_of_HQ == INVALID_TILE) ? CWP_VB_BUILD : CWP_VB_VIEW;
02171       wi = this->GetWidget<NWidgetStacked>(CW_WIDGET_SELECT_VIEW_BUILD_HQ);
02172       if (plane != wi->shown_plane) {
02173         wi->SetDisplayedPlane(plane);
02174         this->SetDirty();
02175         return;
02176       }
02177 
02178       this->SetWidgetDisabledState(CW_WIDGET_VIEW_HQ, c->location_of_HQ == INVALID_TILE);
02179 
02180       /* Enable/disable 'Relocate HQ' button. */
02181       plane = (!local || c->location_of_HQ == INVALID_TILE) ? CWP_RELOCATE_HIDE : CWP_RELOCATE_SHOW;
02182       wi = this->GetWidget<NWidgetStacked>(CW_WIDGET_SELECT_RELOCATE);
02183       if (plane != wi->shown_plane) {
02184         wi->SetDisplayedPlane(plane);
02185         this->SetDirty();
02186         return;
02187       }
02188 
02189       /* Multiplayer buttons. */
02190       plane = ((!_networking) ? CWP_MP_EMPTY : (local ? CWP_MP_C_PWD : CWP_MP_C_JOIN));
02191       wi = this->GetWidget<NWidgetStacked>(CW_WIDGET_SELECT_MULTIPLAYER);
02192       if (plane != wi->shown_plane) {
02193         wi->SetDisplayedPlane(plane);
02194         this->SetDirty();
02195         return;
02196       }
02197       this->SetWidgetDisabledState(CW_WIDGET_COMPANY_JOIN,   c->is_ai);
02198     }
02199 
02200     if (!local) {
02201       /* Not the current player, so disable profile loading/saving */
02202       this->SetWidgetDisabledState(CW_WIDGET_PROFILE_LOAD, true);
02203       this->SetWidgetDisabledState(CW_WIDGET_PROFILE_SAVE, true);
02204 
02205       if (_settings_game.economy.allow_shares) { // Shares are allowed
02206         /* If all shares are owned by someone (none by nobody), disable buy button */
02207         this->SetWidgetDisabledState(CW_WIDGET_BUY_SHARE, GetAmountOwnedBy(c, INVALID_OWNER) == 0 ||
02208             /* Only 25% left to buy. If the company is human, disable buying it up.. TODO issues! */
02209             (GetAmountOwnedBy(c, INVALID_OWNER) == 1 && !c->is_ai) ||
02210             /* Spectators cannot do anything of course */
02211             _local_company == COMPANY_SPECTATOR);
02212 
02213         /* If the company doesn't own any shares, disable sell button */
02214         this->SetWidgetDisabledState(CW_WIDGET_SELL_SHARE, (GetAmountOwnedBy(c, _local_company) == 0) ||
02215             /* Spectators cannot do anything of course */
02216             _local_company == COMPANY_SPECTATOR);
02217       } else { // Shares are not allowed, disable buy/sell buttons
02218         this->DisableWidget(CW_WIDGET_BUY_SHARE);
02219         this->DisableWidget(CW_WIDGET_SELL_SHARE);
02220       }
02221     }
02222 
02223     this->DrawWidgets();
02224   }
02225 
02226   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
02227   {
02228     switch (widget) {
02229       case CW_WIDGET_DESC_COMPANY_VALUE:
02230         SetDParam(0, INT64_MAX); // Arguably the maximum company value
02231         size->width = GetStringBoundingBox(STR_COMPANY_VIEW_COMPANY_VALUE).width;
02232         break;
02233 
02234       case CW_WIDGET_DESC_VEHICLE_COUNTS:
02235         SetDParam(0, 5000); // Maximum number of vehicles
02236         for (uint i = 0; i < lengthof(_company_view_vehicle_count_strings); i++) {
02237           size->width = max(size->width, GetStringBoundingBox(_company_view_vehicle_count_strings[i]).width);
02238         }
02239         break;
02240 
02241       case CW_WIDGET_DESC_INFRASTRUCTURE_COUNTS:
02242         SetDParam(0, UINT_MAX);
02243         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL).width);
02244         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD).width);
02245         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_WATER).width);
02246         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_STATION).width);
02247         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT).width);
02248         size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_NONE).width);
02249         break;
02250 
02251       case CW_WIDGET_DESC_OWNERS: {
02252         const Company *c2;
02253 
02254         FOR_ALL_COMPANIES(c2) {
02255           SetDParam(0, 25);
02256           SetDParam(1, c2->index);
02257 
02258           size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_SHARES_OWNED_BY).width);
02259         }
02260         break;
02261       }
02262 
02263 #ifdef ENABLE_NETWORK
02264       case CW_WIDGET_HAS_PASSWORD:
02265         *size = maxdim(*size, GetSpriteSize(SPR_LOCK));
02266         break;
02267 #endif /* ENABLE_NETWORK */
02268     }
02269   }
02270 
02271   virtual void DrawWidget(const Rect &r, int widget) const
02272   {
02273     const Company *c = Company::Get((CompanyID)this->window_number);
02274     switch (widget) {
02275       case CW_WIDGET_FACE:
02276         DrawCompanyManagerFace(c->face, c->colour, r.left, r.top);
02277         break;
02278 
02279       case CW_WIDGET_FACE_TITLE:
02280         SetDParam(0, c->index);
02281         DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_COMPANY_VIEW_PRESIDENT_MANAGER_TITLE, TC_FROMSTRING, SA_HOR_CENTER);
02282         break;
02283 
02284       case CW_WIDGET_DESC_COLOUR_SCHEME_EXAMPLE:
02285         DrawSprite(SPR_VEH_BUS_SW_VIEW, COMPANY_SPRITE_COLOUR(c->index), (r.left + r.right) / 2, r.top + FONT_HEIGHT_NORMAL / 10);
02286         break;
02287 
02288       case CW_WIDGET_DESC_VEHICLE_COUNTS: {
02289         uint amounts[4];
02290         CountCompanyVehicles((CompanyID)this->window_number, amounts);
02291 
02292         int y = r.top;
02293         if (amounts[0] + amounts[1] + amounts[2] + amounts[3] == 0) {
02294           DrawString(r.left, r.right, y, STR_COMPANY_VIEW_VEHICLES_NONE);
02295         } else {
02296           assert_compile(lengthof(amounts) == lengthof(_company_view_vehicle_count_strings));
02297 
02298           for (uint i = 0; i < lengthof(amounts); i++) {
02299             if (amounts[i] != 0) {
02300               SetDParam(0, amounts[i]);
02301               DrawString(r.left, r.right, y, _company_view_vehicle_count_strings[i]);
02302               y += FONT_HEIGHT_NORMAL;
02303             }
02304           }
02305         }
02306         break;
02307       }
02308 
02309       case CW_WIDGET_DESC_INFRASTRUCTURE_COUNTS: {
02310         uint y = r.top;
02311 
02312         /* Collect rail and road counts. */
02313         uint rail_pices = c->signal_infrastructure;
02314         uint road_pieces = 0;
02315         for (uint i = 0; i < lengthof(c->rail_infrastructure); i++) rail_pices += c->rail_infrastructure[i];
02316         for (uint i = 0; i < lengthof(c->road_infrastructure); i++) road_pieces += c->road_infrastructure[i];
02317 
02318         if (rail_pices == 0 && road_pieces == 0 && c->water_infrastructure == 0 && c->station_infrastructure == 0 && c->airport_infrastructure == 0) {
02319           DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE);
02320         } else {
02321           if (rail_pices != 0) {
02322             SetDParam(0, rail_pices);
02323             DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL);
02324             y += FONT_HEIGHT_NORMAL;
02325           }
02326           if (road_pieces != 0) {
02327             SetDParam(0, road_pieces);
02328             DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD);
02329             y += FONT_HEIGHT_NORMAL;
02330           }
02331           if (c->water_infrastructure != 0) {
02332             SetDParam(0, c->water_infrastructure);
02333             DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_WATER);
02334             y += FONT_HEIGHT_NORMAL;
02335           }
02336           if (c->station_infrastructure != 0) {
02337             SetDParam(0, c->station_infrastructure);
02338             DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_STATION);
02339             y += FONT_HEIGHT_NORMAL;
02340           }
02341           if (c->airport_infrastructure != 0) {
02342             SetDParam(0, c->airport_infrastructure);
02343             DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT);
02344           }
02345         }
02346 
02347         break;
02348       }
02349 
02350       case CW_WIDGET_DESC_OWNERS: {
02351         const Company *c2;
02352         uint y = r.top;
02353 
02354         FOR_ALL_COMPANIES(c2) {
02355           uint amt = GetAmountOwnedBy(c, c2->index);
02356           if (amt != 0) {
02357             SetDParam(0, amt * 25);
02358             SetDParam(1, c2->index);
02359 
02360             DrawString(r.left, r.right, y, STR_COMPANY_VIEW_SHARES_OWNED_BY);
02361             y += FONT_HEIGHT_NORMAL;
02362           }
02363         }
02364         break;
02365       }
02366 
02367 #ifdef ENABLE_NETWORK
02368       case CW_WIDGET_HAS_PASSWORD:
02369         if (_networking && NetworkCompanyIsPassworded(c->index)) {
02370           DrawSprite(SPR_LOCK, PAL_NONE, r.left, r.top);
02371         }
02372         break;
02373 #endif /* ENABLE_NETWORK */
02374     }
02375   }
02376 
02377   virtual void SetStringParameters(int widget) const
02378   {
02379     switch (widget) {
02380       case CW_WIDGET_CAPTION:
02381         SetDParam(0, (CompanyID)this->window_number);
02382         SetDParam(1, (CompanyID)this->window_number);
02383         break;
02384 
02385       case CW_WIDGET_DESC_INAUGURATION:
02386         SetDParam(0, Company::Get((CompanyID)this->window_number)->inaugurated_year);
02387         break;
02388 
02389       case CW_WIDGET_DESC_COMPANY_VALUE:
02390         SetDParam(0, CalculateCompanyValue(Company::Get((CompanyID)this->window_number)));
02391         break;
02392     }
02393   }
02394 
02395   virtual void OnClick(Point pt, int widget, int click_count)
02396   {
02397     switch (widget) {
02398       case CW_WIDGET_NEW_FACE: DoSelectCompanyManagerFace(this); break;
02399 
02400       case CW_WIDGET_COLOUR_SCHEME:
02401         if (BringWindowToFrontById(WC_COMPANY_COLOUR, this->window_number)) break;
02402         new SelectCompanyLiveryWindow(&_select_company_livery_desc, (CompanyID)this->window_number);
02403         break;
02404 
02405       case CW_WIDGET_PRESIDENT_NAME:
02406         this->query_widget = CW_WIDGET_PRESIDENT_NAME;
02407         SetDParam(0, this->window_number);
02408         ShowQueryString(STR_PRESIDENT_NAME, STR_COMPANY_VIEW_PRESIDENT_S_NAME_QUERY_CAPTION, MAX_LENGTH_PRESIDENT_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS);
02409         break;
02410 
02411       case CW_WIDGET_COMPANY_NAME:
02412         this->query_widget = CW_WIDGET_COMPANY_NAME;
02413         SetDParam(0, this->window_number);
02414         ShowQueryString(STR_COMPANY_NAME, STR_COMPANY_VIEW_COMPANY_NAME_QUERY_CAPTION, MAX_LENGTH_COMPANY_NAME_CHARS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT | QSF_LEN_IN_CHARS);
02415         break;
02416 
02417       case CW_WIDGET_VIEW_HQ: {
02418         TileIndex tile = Company::Get((CompanyID)this->window_number)->location_of_HQ;
02419         if (_ctrl_pressed) {
02420           ShowExtraViewPortWindow(tile);
02421         } else {
02422           ScrollMainWindowToTile(tile);
02423         }
02424         break;
02425       }
02426 
02427       case CW_WIDGET_BUILD_HQ:
02428         if ((byte)this->window_number != _local_company) return;
02429         SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, HT_RECT, this);
02430         SetTileSelectSize(2, 2);
02431         this->LowerWidget(CW_WIDGET_BUILD_HQ);
02432         this->SetWidgetDirty(CW_WIDGET_BUILD_HQ);
02433         break;
02434 
02435       case CW_WIDGET_RELOCATE_HQ:
02436         SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, HT_RECT, this);
02437         SetTileSelectSize(2, 2);
02438         this->LowerWidget(CW_WIDGET_RELOCATE_HQ);
02439         this->SetWidgetDirty(CW_WIDGET_RELOCATE_HQ);
02440         break;
02441 
02442       case CW_WIDGET_PROFILE_LOAD:  // When load is clicked we want to perform most of the operations from above!
02443       {
02444         StringID       error_id;
02445         CompanyProfile company_profile;
02446 
02447         if ((byte)this->window_number != _local_company) return;
02448 
02449         this->LowerWidget(CW_WIDGET_PROFILE_LOAD);
02450         //this->SetWidgetDirty(CW_WIDGET_PROFILE_LOAD);
02451 
02452         error_id = CompanyLoadProfile(company_profile);
02453         if (error_id == STR_NULL) error_id = SetCompanyProfile(company_profile); // No error, so try setting the profile
02454         
02455         /* If either CompanyProfileLoad or SetCompanyProfile have an error, they will be handled here */
02456         if (error_id != STR_NULL) ShowErrorMessage(error_id, error_id, WL_INFO); 
02457 
02458         this->LowerWidget(CW_WIDGET_PROFILE_LOAD);
02459         //this->SetWidgetDirty(CW_WIDGET_PROFILE_LOAD);
02460         break;
02461       }
02462 
02463       case CW_WIDGET_PROFILE_SAVE: 
02464       {
02465         StringID       error_id;
02466         CompanyProfile company_profile;
02467 
02468         if ((byte)this->window_number != _local_company) return;
02469 
02470         this->LowerWidget(CW_WIDGET_PROFILE_SAVE);
02471 
02472         company_profile = GetCompanyProfile(*_company_pool.Get(_local_company));
02473         error_id = CompanySaveProfile(company_profile);
02474 
02475         if (error_id != STR_NULL) ShowErrorMessage(error_id, error_id, WL_INFO);  
02476 
02477         this->LowerWidget(CW_WIDGET_PROFILE_SAVE);
02478         break;
02479       }
02480 
02481       case CW_WIDGET_VIEW_INFRASTRUCTURE:
02482         ShowCompanyInfrastructure((CompanyID)this->window_number);
02483         break;
02484 
02485       case CW_WIDGET_BUY_SHARE:
02486         DoCommandP(0, this->window_number, 0, CMD_BUY_SHARE_IN_COMPANY | CMD_MSG(STR_ERROR_CAN_T_BUY_25_SHARE_IN_THIS));
02487         break;
02488 
02489       case CW_WIDGET_SELL_SHARE:
02490         DoCommandP(0, this->window_number, 0, CMD_SELL_SHARE_IN_COMPANY | CMD_MSG(STR_ERROR_CAN_T_SELL_25_SHARE_IN));
02491         break;
02492 
02493 #ifdef ENABLE_NETWORK
02494       case CW_WIDGET_COMPANY_PASSWORD:
02495         if (this->window_number == _local_company) ShowNetworkCompanyPasswordWindow(this);
02496         break;
02497 
02498       case CW_WIDGET_COMPANY_JOIN: {
02499         this->query_widget = CW_WIDGET_COMPANY_JOIN;
02500         CompanyID company = (CompanyID)this->window_number;
02501         if (_network_server) {
02502           NetworkServerDoMove(CLIENT_ID_SERVER, company);
02503           MarkWholeScreenDirty();
02504         } else if (NetworkCompanyIsPassworded(company)) {
02505           /* ask for the password */
02506           ShowQueryString(STR_EMPTY, STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION, NETWORK_PASSWORD_LENGTH, this, CS_ALPHANUMERAL, QSF_NONE);
02507         } else {
02508           /* just send the join command */
02509           NetworkClientRequestMove(company);
02510         }
02511         break;
02512       }
02513 #endif /* ENABLE_NETWORK */
02514     }
02515   }
02516 
02517   virtual void OnHundredthTick()
02518   {
02519     /* redraw the window every now and then */
02520     this->SetDirty();
02521   }
02522 
02523   virtual void OnPlaceObject(Point pt, TileIndex tile)
02524   {
02525     if (DoCommandP(tile, OBJECT_HQ, 0, CMD_BUILD_OBJECT | CMD_MSG(STR_ERROR_CAN_T_BUILD_COMPANY_HEADQUARTERS))) {
02526       ResetObjectToPlace();
02527       this->RaiseButtons();
02528     }
02529   }
02530 
02531   virtual void OnPlaceObjectAbort()
02532   {
02533     this->RaiseButtons();
02534   }
02535 
02536   virtual void OnQueryTextFinished(char *str)
02537   {
02538     if (str == NULL) return;
02539 
02540     switch (this->query_widget) {
02541       default: NOT_REACHED();
02542 
02543       case CW_WIDGET_PRESIDENT_NAME:
02544         DoCommandP(0, 0, 0, CMD_RENAME_PRESIDENT | CMD_MSG(STR_ERROR_CAN_T_CHANGE_PRESIDENT), NULL, str);
02545         break;
02546 
02547       case CW_WIDGET_COMPANY_NAME:
02548         DoCommandP(0, 0, 0, CMD_RENAME_COMPANY | CMD_MSG(STR_ERROR_CAN_T_CHANGE_COMPANY_NAME), NULL, str);
02549         break;
02550 
02551 #ifdef ENABLE_NETWORK
02552       case CW_WIDGET_COMPANY_JOIN:
02553         NetworkClientRequestMove((CompanyID)this->window_number, str);
02554         break;
02555 #endif /* ENABLE_NETWORK */
02556     }
02557   }
02558 };
02559 
02560 static const WindowDesc _company_desc(
02561   WDP_AUTO, 0, 0,
02562   WC_COMPANY, WC_NONE,
02563   WDF_UNCLICK_BUTTONS,
02564   _nested_company_widgets, lengthof(_nested_company_widgets)
02565 );
02566 
02571 void ShowCompany(CompanyID company)
02572 {
02573   if (!Company::IsValidID(company)) return;
02574 
02575   AllocateWindowDescFront<CompanyWindow>(&_company_desc, company);
02576 }
02577 
02582 void DirtyCompanyInfrastructureWindows(CompanyID company)
02583 {
02584   SetWindowDirty(WC_COMPANY, company);
02585   SetWindowDirty(WC_COMPANY_INFRASTRUCTURE, company);
02586 }
02587 
02589 enum BuyCompanyWidgets {
02590   BCW_CAPTION,
02591   BCW_FACE,
02592   BCW_QUESTION,
02593   BCW_NO,
02594   BCW_YES,
02595 };
02596 
02597 struct BuyCompanyWindow : Window {
02598   BuyCompanyWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
02599   {
02600     this->InitNested(desc, window_number);
02601   }
02602 
02603   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
02604   {
02605     switch (widget) {
02606       case BCW_FACE:
02607         *size = GetSpriteSize(SPR_GRADIENT);
02608         break;
02609 
02610       case BCW_QUESTION:
02611         const Company *c = Company::Get((CompanyID)this->window_number);
02612         SetDParam(0, c->index);
02613         SetDParam(1, c->bankrupt_value);
02614         size->height = GetStringHeight(STR_BUY_COMPANY_MESSAGE, size->width);
02615         break;
02616     }
02617   }
02618 
02619   virtual void SetStringParameters(int widget) const
02620   {
02621     switch (widget) {
02622       case BCW_CAPTION:
02623         SetDParam(0, STR_COMPANY_NAME);
02624         SetDParam(1, Company::Get((CompanyID)this->window_number)->index);
02625         break;
02626     }
02627   }
02628 
02629   virtual void DrawWidget(const Rect &r, int widget) const
02630   {
02631     switch (widget) {
02632       case BCW_FACE: {
02633         const Company *c = Company::Get((CompanyID)this->window_number);
02634         DrawCompanyManagerFace(c->face, c->colour, r.left, r.top);
02635         break;
02636       }
02637 
02638       case BCW_QUESTION: {
02639         const Company *c = Company::Get((CompanyID)this->window_number);
02640         SetDParam(0, c->index);
02641         SetDParam(1, c->bankrupt_value);
02642         DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_BUY_COMPANY_MESSAGE, TC_FROMSTRING, SA_CENTER);
02643         break;
02644       }
02645     }
02646   }
02647 
02648   virtual void OnClick(Point pt, int widget, int click_count)
02649   {
02650     switch (widget) {
02651       case BCW_NO:
02652         delete this;
02653         break;
02654 
02655       case BCW_YES:
02656         DoCommandP(0, this->window_number, 0, CMD_BUY_COMPANY | CMD_MSG(STR_ERROR_CAN_T_BUY_COMPANY));
02657         break;
02658     }
02659   }
02660 };
02661 
02662 static const NWidgetPart _nested_buy_company_widgets[] = {
02663   NWidget(NWID_HORIZONTAL),
02664     NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE),
02665     NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE, BCW_CAPTION), SetDataTip(STR_ERROR_MESSAGE_CAPTION_OTHER_COMPANY, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
02666   EndContainer(),
02667   NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE),
02668     NWidget(NWID_VERTICAL), SetPIP(8, 8, 8),
02669       NWidget(NWID_HORIZONTAL), SetPIP(8, 10, 8),
02670         NWidget(WWT_EMPTY, INVALID_COLOUR, BCW_FACE), SetFill(0, 1),
02671         NWidget(WWT_EMPTY, INVALID_COLOUR, BCW_QUESTION), SetMinimalSize(240, 0), SetFill(1, 1),
02672       EndContainer(),
02673       NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(100, 10, 100),
02674         NWidget(WWT_TEXTBTN, COLOUR_LIGHT_BLUE, BCW_NO), SetMinimalSize(60, 12), SetDataTip(STR_QUIT_NO, STR_NULL), SetFill(1, 0),
02675         NWidget(WWT_TEXTBTN, COLOUR_LIGHT_BLUE, BCW_YES), SetMinimalSize(60, 12), SetDataTip(STR_QUIT_YES, STR_NULL), SetFill(1, 0),
02676       EndContainer(),
02677     EndContainer(),
02678   EndContainer(),
02679 };
02680 
02681 static const WindowDesc _buy_company_desc(
02682   WDP_AUTO, 0, 0,
02683   WC_BUY_COMPANY, WC_NONE,
02684   WDF_CONSTRUCTION,
02685   _nested_buy_company_widgets, lengthof(_nested_buy_company_widgets)
02686 );
02687 
02692 void ShowBuyCompanyDialog(CompanyID company)
02693 {
02694   AllocateWindowDescFront<BuyCompanyWindow>(&_buy_company_desc, company);
02695 }