# company_gui.cpp

Go to the documentation of this file.

    00001 /* $Id: company_gui.cpp 15903 2009-03-30 23:15:05Z rubidium $ */
    00002
    00005 #include "stdafx.h"
    00006 #include "gui.h"
    00007 #include "window_gui.h"
    00008 #include "textbuf_gui.h"
    00009 #include "viewport_func.h"
    00010 #include "gfx_func.h"
    00011 #include "company_func.h"
    00012 #include "command_func.h"
    00013 #include "network/network.h"
    00014 #include "network/network_gui.h"
    00015 #include "network/network_func.h"
    00016 #include "roadveh.h"
    00017 #include "train.h"
    00018 #include "aircraft.h"
    00019 #include "newgrf.h"
    00020 #include "company_manager_face.h"
    00021 #include "strings_func.h"
    00022 #include "date_func.h"
    00023 #include "string_func.h"
    00024 #include "widgets/dropdown_type.h"
    00025 #include "tilehighlight_func.h"
    00026 #include "settings_type.h"
    00027
    00028 #include "table/strings.h"
    00029
    00030 enum {
    00031   FIRST_GUI_CALL = INT_MAX,
    00032 };
    00033
    00034 static void DoShowCompanyFinances(CompanyID company, bool show_small, bool show_stickied, int top = FIRST_GUI_CALL, int left = FIRST_GUI_CALL);
    00035 static void DoSelectCompanyManagerFace(Window *parent, bool show_big, int top =  FIRST_GUI_CALL, int left = FIRST_GUI_CALL);
    00036
    00038 static ExpensesType _expenses_list_1[] = {
    00039   EXPENSES_CONSTRUCTION,
    00040   EXPENSES_NEW_VEHICLES,
    00041   EXPENSES_TRAIN_RUN,
    00042   EXPENSES_ROADVEH_RUN,
    00043   EXPENSES_AIRCRAFT_RUN,
    00044   EXPENSES_SHIP_RUN,
    00045   EXPENSES_PROPERTY,
    00046   EXPENSES_TRAIN_INC,
    00047   EXPENSES_ROADVEH_INC,
    00048   EXPENSES_AIRCRAFT_INC,
    00049   EXPENSES_SHIP_INC,
    00050   EXPENSES_LOAN_INT,
    00051   EXPENSES_OTHER,
    00052 };
    00053
    00055 static ExpensesType _expenses_list_2[] = {
    00056   EXPENSES_TRAIN_INC,
    00057   EXPENSES_ROADVEH_INC,
    00058   EXPENSES_AIRCRAFT_INC,
    00059   EXPENSES_SHIP_INC,
    00060   INVALID_EXPENSES,
    00061   EXPENSES_TRAIN_RUN,
    00062   EXPENSES_ROADVEH_RUN,
    00063   EXPENSES_AIRCRAFT_RUN,
    00064   EXPENSES_SHIP_RUN,
    00065   EXPENSES_PROPERTY,
    00066   EXPENSES_LOAN_INT,
    00067   INVALID_EXPENSES,
    00068   EXPENSES_CONSTRUCTION,
    00069   EXPENSES_NEW_VEHICLES,
    00070   EXPENSES_OTHER,
    00071   INVALID_EXPENSES,
    00072 };
    00073
    00075 struct ExpensesList {
    00076   const ExpensesType *et;
    00077   const int length;
    00078   const int height;
    00079 };
    00080
    00081 static const ExpensesList _expenses_list_types[] = {
    00082   { _expenses_list_1, lengthof(_expenses_list_1), lengthof(_expenses_list_1) * 10 },
    00083   { _expenses_list_2, lengthof(_expenses_list_2), lengthof(_expenses_list_2) * 10 + 3 * 12 },
    00084 };
    00085
    00086 static void DrawCompanyEconomyStats(const Company *c, bool small)
    00087 {
    00088   int type = _settings_client.gui.expenses_layout;
    00089   int x, y, i, j, year;
    00090   const Money (*tbl)[EXPENSES_END];
    00091   StringID str;
    00092
    00093   if (!small) { // normal sized economics window
    00094     /* draw categories */
    00095     DrawStringCenterUnderline(61, 15, STR_700F_EXPENDITURE_INCOME, TC_FROMSTRING);
    00096
    00097     y = 27;
    00098     for (i = 0; i < _expenses_list_types[type].length; i++) {
    00099       ExpensesType et = _expenses_list_types[type].et[i];
    00100       if (et == INVALID_EXPENSES) {
    00101         y += 2;
    00102         DrawStringRightAligned(111, y, STR_7020_TOTAL, TC_FROMSTRING);
    00103         y += 20;
    00104       } else {
    00105         DrawString(2, y, STR_7011_CONSTRUCTION + et, TC_FROMSTRING);
    00106         y += 10;
    00107       }
    00108     }
    00109
    00110     DrawStringRightAligned(111, y + 2, STR_7020_TOTAL, TC_FROMSTRING);
    00111
    00112     /* draw the price columns */
    00113     year = _cur_year - 2;
    00114     j = 3;
    00115     x = 215;
    00116     tbl = c->yearly_expenses + 2;
    00117
    00118     do {
    00119       if (year >= c->inaugurated_year) {
    00120         SetDParam(0, year);
    00121         DrawStringRightAlignedUnderline(x, 15, STR_7010, TC_FROMSTRING);
    00122
    00123         Money sum = 0;
    00124         Money subtotal = 0;
    00125
    00126         int y = 27;
    00127
    00128         for (int i = 0; i < _expenses_list_types[type].length; i++) {
    00129           ExpensesType et = _expenses_list_types[type].et[i];
    00130           Money cost;
    00131
    00132           if (et == INVALID_EXPENSES) {
    00133             GfxFillRect(x - 75, y, x, y, 215);
    00134             cost = subtotal;
    00135             subtotal = 0;
    00136             y += 2;
    00137           } else {
    00138             cost = (*tbl)[et];
    00139             subtotal += cost;
    00140             sum += cost;
    00141           }
    00142
    00143           if (cost != 0 || et == INVALID_EXPENSES) {
    00144             str = STR_701E;
    00145             if (cost < 0) { cost = -cost; str++; }
    00146             SetDParam(0, cost);
    00147             DrawStringRightAligned(x, y, str, TC_FROMSTRING);
    00148           }
    00149           y += (et == INVALID_EXPENSES) ? 20 : 10;
    00150         }
    00151
    00152         str = STR_701E;
    00153         if (sum < 0) { sum = -sum; str++; }
    00154         SetDParam(0, sum);
    00155         DrawStringRightAligned(x, y + 2, str, TC_FROMSTRING);
    00156
    00157         GfxFillRect(x - 75, y, x, y, 215);
    00158         x += 95;
    00159       }
    00160       year++;
    00161       tbl--;
    00162     } while (--j != 0);
    00163
    00164     y += 14;
    00165
    00166     /* draw max loan aligned to loan below (y += 10) */
    00167     SetDParam(0, _economy.max_loan);
    00168     DrawString(202, y + 10, STR_MAX_LOAN, TC_FROMSTRING);
    00169   } else {
    00170     y = 15;
    00171   }
    00172
    00173   DrawString(2, y, STR_7026_BANK_BALANCE, TC_FROMSTRING);
    00174   SetDParam(0, c->money);
    00175   DrawStringRightAligned(182, y, STR_7028, TC_FROMSTRING);
    00176
    00177   y += 10;
    00178
    00179   DrawString(2, y, STR_7027_LOAN, TC_FROMSTRING);
    00180   SetDParam(0, c->current_loan);
    00181   DrawStringRightAligned(182, y, STR_7028, TC_FROMSTRING);
    00182
    00183   y += 12;
    00184
    00185   GfxFillRect(182 - 75, y - 2, 182, y - 2, 215);
    00186
    00187   SetDParam(0, c->money - c->current_loan);
    00188   DrawStringRightAligned(182, y, STR_7028, TC_FROMSTRING);
    00189 }
    00190
    00191 enum CompanyFinancesWindowWidgets {
    00192   CFW_WIDGET_TOGGLE_SIZE   = 2,
    00193   CFW_WIDGET_EXPS_PANEL    = 4,
    00194   CFW_WIDGET_TOTAL_PANEL   = 5,
    00195   CFW_WIDGET_INCREASE_LOAN = 6,
    00196   CFW_WIDGET_REPAY_LOAN    = 7,
    00197 };
    00198
    00199 static const Widget _company_finances_widgets[] = {
    00200 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_GREY,     0,    10,       0,      13, STR_00C5,               STR_018B_CLOSE_WINDOW},
    00201 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_GREY,    11,   379,       0,      13, STR_700E_FINANCES,      STR_018C_WINDOW_TITLE_DRAG_THIS},
    00202 {     WWT_IMGBTN,   RESIZE_NONE,  COLOUR_GREY,   380,   394,       0,      13, SPR_LARGE_SMALL_WINDOW, STR_7075_TOGGLE_LARGE_SMALL_WINDOW},
    00203 {  WWT_STICKYBOX,   RESIZE_NONE,  COLOUR_GREY,   395,   406,       0,      13, 0x0,                    STR_STICKY_BUTTON},
    00204 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   406,      14, 13 + 10, 0x0,    STR_NULL},
    00205 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   406, 14 + 10, 47 + 10, 0x0, STR_NULL},
    00206 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     0,   202, 48 + 10, 59 + 10, STR_7029_BORROW,        STR_7035_INCREASE_SIZE_OF_LOAN},
    00207 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   203,   406, 48 + 10, 59 + 10, STR_702A_REPAY,         STR_7036_REPAY_PART_OF_LOAN},
    00208 {   WIDGETS_END},
    00209 };
    00210
    00211 static const Widget _company_finances_small_widgets[] = {
    00212 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_GREY,     0,    10,     0,    13, STR_00C5,               STR_018B_CLOSE_WINDOW},
    00213 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_GREY,    11,   253,     0,    13, STR_700E_FINANCES,      STR_018C_WINDOW_TITLE_DRAG_THIS},
    00214 {     WWT_IMGBTN,   RESIZE_NONE,  COLOUR_GREY,   254,   267,     0,    13, SPR_LARGE_SMALL_WINDOW, STR_7075_TOGGLE_LARGE_SMALL_WINDOW},
    00215 {  WWT_STICKYBOX,   RESIZE_NONE,  COLOUR_GREY,   268,   279,     0,    13, 0x0,                    STR_STICKY_BUTTON},
    00216 {      WWT_EMPTY,   RESIZE_NONE,  COLOUR_GREY,     0,     0,     0,     0, 0x0,                    STR_NULL},
    00217 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   279,    14,    47, STR_NULL,               STR_NULL},
    00218 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     0,   139,    48,    59, STR_7029_BORROW,        STR_7035_INCREASE_SIZE_OF_LOAN},
    00219 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   140,   279,    48,    59, STR_702A_REPAY,         STR_7036_REPAY_PART_OF_LOAN},
    00220 {   WIDGETS_END},
    00221 };
    00222
    00223 struct CompanyFinancesWindow : Window {
    00224   bool small;
    00225
    00226   CompanyFinancesWindow(const WindowDesc *desc, CompanyID company, bool show_small,
    00227           bool show_stickied, int top, int left) :
    00228       Window(desc, company),
    00229       small(show_small)
    00230   {
    00231     this->owner = (Owner)this->window_number;
    00232
    00233     if (show_stickied) this->flags4 |= WF_STICKY;
    00234
    00235     /* Check if repositioning from default is required */
    00236     if (top != FIRST_GUI_CALL && left != FIRST_GUI_CALL) {
    00237       this->top = top;
    00238       this->left = left;
    00239     }
    00240
    00241     this->FindWindowPlacementAndResize(desc);
    00242   }
    00243
    00244   virtual void OnPaint()
    00245   {
    00246     CompanyID company = (CompanyID)this->window_number;
    00247     const Company *c = GetCompany(company);
    00248
    00249     if (!small) {
    00250       int type = _settings_client.gui.expenses_layout;
    00251       int height = this->widget[CFW_WIDGET_EXPS_PANEL].bottom - this->widget[CFW_WIDGET_EXPS_PANEL].top + 1;
    00252       if (_expenses_list_types[type].height + 26 != height) {
    00253         this->SetDirty();
    00254         ResizeWindowForWidget(this, CFW_WIDGET_EXPS_PANEL, 0, _expenses_list_types[type].height - height + 26);
    00255         this->SetDirty();
    00256         return;
    00257       }
    00258     }
    00259
    00260     /* Recheck the size of the window as it might need to be resized due to the local company changing */
    00261     int new_height = this->widget[(company == _local_company) ? CFW_WIDGET_INCREASE_LOAN : CFW_WIDGET_TOTAL_PANEL].bottom + 1;
    00262     if (this->height != new_height) {
    00263       /* Make window dirty before and after resizing */
    00264       this->SetDirty();
    00265       this->height = new_height;
    00266       this->SetDirty();
    00267
    00268       this->SetWidgetHiddenState(CFW_WIDGET_INCREASE_LOAN, company != _local_company);
    00269       this->SetWidgetHiddenState(CFW_WIDGET_REPAY_LOAN,    company != _local_company);
    00270     }
    00271
    00272     /* Borrow button only shows when there is any more money to loan */
    00273     this->SetWidgetDisabledState(CFW_WIDGET_INCREASE_LOAN, c->current_loan == _economy.max_loan);
    00274
    00275     /* Repay button only shows when there is any more money to repay */
    00276     this->SetWidgetDisabledState(CFW_WIDGET_REPAY_LOAN, company != _local_company || c->current_loan == 0);
    00277
    00278     SetDParam(0, c->index);
    00279     SetDParam(1, c->index);
    00280     SetDParam(2, LOAN_INTERVAL);
    00281     this->DrawWidgets();
    00282
    00283     DrawCompanyEconomyStats(c, this->small);
    00284   }
    00285
    00286   virtual void OnClick(Point pt, int widget)
    00287   {
    00288     switch (widget) {
    00289       case CFW_WIDGET_TOGGLE_SIZE: {// toggle size
    00290         bool new_mode = !this->small;
    00291         bool stickied = !!(this->flags4 & WF_STICKY);
    00292         int oldtop = this->top;
    00293         int oldleft = this->left;
    00294         CompanyID company = (CompanyID)this->window_number;
    00295
    00296         delete this;
    00297         /* Open up the (toggled size) Finance window at the same position as the previous */
    00298         DoShowCompanyFinances(company, new_mode, stickied, oldtop, oldleft);
    00299       }
    00300       break;
    00301
    00302       case CFW_WIDGET_INCREASE_LOAN: // increase loan
    00303         DoCommandP(0, 0, _ctrl_pressed, CMD_INCREASE_LOAN | CMD_MSG(STR_702C_CAN_T_BORROW_ANY_MORE_MONEY));
    00304         break;
    00305
    00306       case CFW_WIDGET_REPAY_LOAN: // repay loan
    00307         DoCommandP(0, 0, _ctrl_pressed, CMD_DECREASE_LOAN | CMD_MSG(STR_702F_CAN_T_REPAY_LOAN));
    00308         break;
    00309     }
    00310   }
    00311 };
    00312
    00313 static const WindowDesc _company_finances_desc(
    00314   WDP_AUTO, WDP_AUTO, 407, 60 + 10, 407, 60 + 10,
    00315   WC_FINANCES, WC_NONE,
    00316   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
    00317   _company_finances_widgets
    00318 );
    00319
    00320 static const WindowDesc _company_finances_small_desc(
    00321   WDP_AUTO, WDP_AUTO, 280, 60, 280, 60,
    00322   WC_FINANCES, WC_NONE,
    00323   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
    00324   _company_finances_small_widgets
    00325 );
    00326
    00338 static void DoShowCompanyFinances(CompanyID company, bool show_small, bool show_stickied, int top, int left)
    00339 {
    00340   if (!IsValidCompanyID(company)) return;
    00341
    00342   if (BringWindowToFrontById(WC_FINANCES, company)) return;
    00343   new CompanyFinancesWindow(show_small ? &_company_finances_small_desc : &_company_finances_desc, company, show_small, show_stickied, top, left);
    00344 }
    00345
    00346 void ShowCompanyFinances(CompanyID company)
    00347 {
    00348   DoShowCompanyFinances(company, false, false);
    00349 }
    00350
    00351 /* List of colours for the livery window */
    00352 static const StringID _colour_dropdown[] = {
    00353   STR_00D1_DARK_BLUE,
    00354   STR_00D2_PALE_GREEN,
    00355   STR_00D3_PINK,
    00356   STR_00D4_YELLOW,
    00357   STR_00D5_RED,
    00358   STR_00D6_LIGHT_BLUE,
    00359   STR_00D7_GREEN,
    00360   STR_00D8_DARK_GREEN,
    00361   STR_00D9_BLUE,
    00362   STR_00DA_CREAM,
    00363   STR_00DB_MAUVE,
    00364   STR_00DC_PURPLE,
    00365   STR_00DD_ORANGE,
    00366   STR_00DE_BROWN,
    00367   STR_00DF_GREY,
    00368   STR_00E0_WHITE,
    00369 };
    00370
    00371 /* Association of liveries to livery classes */
    00372 static const LiveryClass _livery_class[LS_END] = {
    00373   LC_OTHER,
    00374   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,
    00375   LC_ROAD, LC_ROAD,
    00376   LC_SHIP, LC_SHIP,
    00377   LC_AIRCRAFT, LC_AIRCRAFT, LC_AIRCRAFT,
    00378   LC_ROAD, LC_ROAD,
    00379 };
    00380
    00381 class DropDownListColourItem : public DropDownListItem {
    00382 public:
    00383   DropDownListColourItem(int result, bool masked) : DropDownListItem(result, masked) {}
    00384
    00385   virtual ~DropDownListColourItem() {}
    00386
    00387   StringID String() const
    00388   {
    00389     return _colour_dropdown[this->result];
    00390   }
    00391
    00392   uint Height(uint width) const
    00393   {
    00394     return 14;
    00395   }
    00396
    00397   bool Selectable() const
    00398   {
    00399     return true;
    00400   }
    00401
    00402   void Draw(int x, int y, uint width, uint height, bool sel, int bg_colour) const
    00403   {
    00404     DrawSprite(SPR_VEH_BUS_SIDE_VIEW, PALETTE_RECOLOUR_START + this->result, x + 16, y + 7);
    00405     DrawStringTruncated(x + 32, y + 3, this->String(), sel ? TC_WHITE : TC_BLACK, width - 30);
    00406   }
    00407 };
    00408
    00409 struct SelectCompanyLiveryWindow : public Window {
    00410 private:
    00411   uint32 sel;
    00412   LiveryClass livery_class;
    00413
    00414   enum SelectCompanyLiveryWindowWidgets {
    00415     SCLW_WIDGET_CLOSE,
    00416     SCLW_WIDGET_CAPTION,
    00417     SCLW_WIDGET_CLASS_GENERAL,
    00418     SCLW_WIDGET_CLASS_RAIL,
    00419     SCLW_WIDGET_CLASS_ROAD,
    00420     SCLW_WIDGET_CLASS_SHIP,
    00421     SCLW_WIDGET_CLASS_AIRCRAFT,
    00422     SCLW_WIDGET_SPACER_CLASS,
    00423     SCLW_WIDGET_SPACER_DROPDOWN,
    00424     SCLW_WIDGET_PRI_COL_DROPDOWN,
    00425     SCLW_WIDGET_SEC_COL_DROPDOWN,
    00426     SCLW_WIDGET_MATRIX,
    00427   };
    00428
    00429   void ShowColourDropDownMenu(uint32 widget)
    00430   {
    00431     uint32 used_colours = 0;
    00432     const Livery *livery;
    00433     LiveryScheme scheme;
    00434
    00435     /* Disallow other company colours for the primary colour */
    00436     if (HasBit(this->sel, LS_DEFAULT) && widget == SCLW_WIDGET_PRI_COL_DROPDOWN) {
    00437       const Company *c;
    00438       FOR_ALL_COMPANIES(c) {
    00439         if (c->index != _local_company) SetBit(used_colours, c->colour);
    00440       }
    00441     }
    00442
    00443     /* Get the first selected livery to use as the default dropdown item */
    00444     for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
    00445       if (HasBit(this->sel, scheme)) break;
    00446     }
    00447     if (scheme == LS_END) scheme = LS_DEFAULT;
    00448     livery = &GetCompany((CompanyID)this->window_number)->livery[scheme];
    00449
    00450     DropDownList *list = new DropDownList();
    00451     for (uint i = 0; i < lengthof(_colour_dropdown); i++) {
    00452       list->push_back(new DropDownListColourItem(i, HasBit(used_colours, i)));
    00453     }
    00454
    00455     ShowDropDownList(this, list, widget == SCLW_WIDGET_PRI_COL_DROPDOWN ? livery->colour1 : livery->colour2, widget);
    00456   }
    00457
    00458 public:
    00459   SelectCompanyLiveryWindow(const WindowDesc *desc, CompanyID company) : Window(desc, company)
    00460   {
    00461     this->owner = company;
    00462     this->livery_class = LC_OTHER;
    00463     this->sel = 1;
    00464     this->LowerWidget(SCLW_WIDGET_CLASS_GENERAL);
    00465     this->OnInvalidateData(_loaded_newgrf_features.has_2CC);
    00466     this->FindWindowPlacementAndResize(desc);
    00467   }
    00468
    00469   virtual void OnPaint()
    00470   {
    00471     const Company *c = GetCompany((CompanyID)this->window_number);
    00472     LiveryScheme scheme = LS_DEFAULT;
    00473     int y = 51;
    00474
    00475     /* Disable dropdown controls if no scheme is selected */
    00476     this->SetWidgetDisabledState(SCLW_WIDGET_PRI_COL_DROPDOWN, this->sel == 0);
    00477     this->SetWidgetDisabledState(SCLW_WIDGET_SEC_COL_DROPDOWN, this->sel == 0);
    00478
    00479     if (this->sel != 0) {
    00480       for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
    00481         if (HasBit(this->sel, scheme)) break;
    00482       }
    00483       if (scheme == LS_END) scheme = LS_DEFAULT;
    00484     }
    00485
    00486     SetDParam(0, STR_00D1_DARK_BLUE + c->livery[scheme].colour1);
    00487     SetDParam(1, STR_00D1_DARK_BLUE + c->livery[scheme].colour2);
    00488
    00489     this->DrawWidgets();
    00490
    00491     for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
    00492       if (_livery_class[scheme] == this->livery_class) {
    00493         bool sel = HasBit(this->sel, scheme) != 0;
    00494
    00495         if (scheme != LS_DEFAULT) {
    00496           DrawSprite(c->livery[scheme].in_use ? SPR_BOX_CHECKED : SPR_BOX_EMPTY, PAL_NONE, 2, y);
    00497         }
    00498
    00499         DrawString(15, y, STR_LIVERY_DEFAULT + scheme, sel ? TC_WHITE : TC_BLACK);
    00500
    00501         DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOUR(c->livery[scheme].colour1), 152, y);
    00502         DrawString(165, y, STR_00D1_DARK_BLUE + c->livery[scheme].colour1, sel ? TC_WHITE : TC_GOLD);
    00503
    00504         if (!this->IsWidgetHidden(SCLW_WIDGET_SEC_COL_DROPDOWN)) {
    00505           DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOUR(c->livery[scheme].colour2), 277, y);
    00506           DrawString(290, y, STR_00D1_DARK_BLUE + c->livery[scheme].colour2, sel ? TC_WHITE : TC_GOLD);
    00507         }
    00508
    00509         y += 14;
    00510       }
    00511     }
    00512   }
    00513
    00514   virtual void OnClick(Point pt, int widget)
    00515   {
    00516     /* Number of liveries in each class, used to determine the height of the livery window */
    00517     static const byte livery_height[] = {
    00518       1,
    00519       13,
    00520       4,
    00521       2,
    00522       3,
    00523     };
    00524
    00525     switch (widget) {
    00526       /* Livery Class buttons */
    00527       case SCLW_WIDGET_CLASS_GENERAL:
    00528       case SCLW_WIDGET_CLASS_RAIL:
    00529       case SCLW_WIDGET_CLASS_ROAD:
    00530       case SCLW_WIDGET_CLASS_SHIP:
    00531       case SCLW_WIDGET_CLASS_AIRCRAFT: {
    00532         LiveryScheme scheme;
    00533
    00534         this->RaiseWidget(this->livery_class + SCLW_WIDGET_CLASS_GENERAL);
    00535         this->livery_class = (LiveryClass)(widget - SCLW_WIDGET_CLASS_GENERAL);
    00536         this->sel = 0;
    00537         this->LowerWidget(this->livery_class + SCLW_WIDGET_CLASS_GENERAL);
    00538
    00539         /* Select the first item in the list */
    00540         for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
    00541           if (_livery_class[scheme] == this->livery_class) {
    00542             this->sel = 1 << scheme;
    00543             break;
    00544           }
    00545         }
    00546         this->height = 49 + livery_height[this->livery_class] * 14;
    00547         this->widget[SCLW_WIDGET_MATRIX].bottom = this->height - 1;
    00548         this->widget[SCLW_WIDGET_MATRIX].data = livery_height[this->livery_class] << 8 | 1;
    00549         MarkWholeScreenDirty();
    00550         break;
    00551       }
    00552
    00553       case SCLW_WIDGET_PRI_COL_DROPDOWN: // First colour dropdown
    00554         ShowColourDropDownMenu(SCLW_WIDGET_PRI_COL_DROPDOWN);
    00555         break;
    00556
    00557       case SCLW_WIDGET_SEC_COL_DROPDOWN: // Second colour dropdown
    00558         ShowColourDropDownMenu(SCLW_WIDGET_SEC_COL_DROPDOWN);
    00559         break;
    00560
    00561       case SCLW_WIDGET_MATRIX: {
    00562         LiveryScheme scheme;
    00563         LiveryScheme j = (LiveryScheme)((pt.y - 48) / 14);
    00564
    00565         for (scheme = LS_BEGIN; scheme <= j; scheme++) {
    00566           if (_livery_class[scheme] != this->livery_class) j++;
    00567           if (scheme >= LS_END) return;
    00568         }
    00569         if (j >= LS_END) return;
    00570
    00571         /* If clicking on the left edge, toggle using the livery */
    00572         if (pt.x < 10) {
    00573           DoCommandP(0, j | (2 << 8), !GetCompany((CompanyID)this->window_number)->livery[j].in_use, CMD_SET_COMPANY_COLOUR);
    00574         }
    00575
    00576         if (_ctrl_pressed) {
    00577           ToggleBit(this->sel, j);
    00578         } else {
    00579           this->sel = 1 << j;
    00580         }
    00581         this->SetDirty();
    00582         break;
    00583       }
    00584     }
    00585   }
    00586
    00587   virtual void OnDropdownSelect(int widget, int index)
    00588   {
    00589     for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
    00590       if (HasBit(this->sel, scheme)) {
    00591         DoCommandP(0, scheme | (widget == SCLW_WIDGET_PRI_COL_DROPDOWN ? 0 : 256), index, CMD_SET_COMPANY_COLOUR);
    00592       }
    00593     }
    00594   }
    00595
    00596   virtual void OnInvalidateData(int data = 0)
    00597   {
    00598     static bool has2cc = true;
    00599
    00600     if (has2cc == !!data) return;
    00601
    00602     has2cc = !!data;
    00603
    00604     int r = this->widget[has2cc ? SCLW_WIDGET_SEC_COL_DROPDOWN : SCLW_WIDGET_PRI_COL_DROPDOWN].right;
    00605     this->SetWidgetHiddenState(SCLW_WIDGET_SEC_COL_DROPDOWN, !has2cc);
    00606     this->widget[SCLW_WIDGET_CAPTION].right = r;
    00607     this->widget[SCLW_WIDGET_SPACER_CLASS].right = r;
    00608     this->widget[SCLW_WIDGET_MATRIX].right = r;
    00609     this->width = r + 1;
    00610   }
    00611 };
    00612
    00613 static const Widget _select_company_livery_widgets[] = {
    00614 { WWT_CLOSEBOX, RESIZE_NONE,  COLOUR_GREY,   0,  10,   0,  13, STR_00C5,                   STR_018B_CLOSE_WINDOW },
    00615 {  WWT_CAPTION, RESIZE_NONE,  COLOUR_GREY,  11, 399,   0,  13, STR_7007_NEW_COLOUR_SCHEME, STR_018C_WINDOW_TITLE_DRAG_THIS },
    00616 {   WWT_IMGBTN, RESIZE_NONE,  COLOUR_GREY,   0,  21,  14,  35, SPR_IMG_COMPANY_GENERAL,    STR_LIVERY_GENERAL_TIP },
    00617 {   WWT_IMGBTN, RESIZE_NONE,  COLOUR_GREY,  22,  43,  14,  35, SPR_IMG_TRAINLIST,          STR_LIVERY_TRAIN_TIP },
    00618 {   WWT_IMGBTN, RESIZE_NONE,  COLOUR_GREY,  44,  65,  14,  35, SPR_IMG_TRUCKLIST,          STR_LIVERY_ROADVEH_TIP },
    00619 {   WWT_IMGBTN, RESIZE_NONE,  COLOUR_GREY,  66,  87,  14,  35, SPR_IMG_SHIPLIST,           STR_LIVERY_SHIP_TIP },
    00620 {   WWT_IMGBTN, RESIZE_NONE,  COLOUR_GREY,  88, 109,  14,  35, SPR_IMG_AIRPLANESLIST,      STR_LIVERY_AIRCRAFT_TIP },
    00621 {    WWT_PANEL, RESIZE_NONE,  COLOUR_GREY, 110, 399,  14,  35, 0x0,                        STR_NULL },
    00622 {    WWT_PANEL, RESIZE_NONE,  COLOUR_GREY,   0, 149,  36,  47, 0x0,                        STR_NULL },
    00623 { WWT_DROPDOWN, RESIZE_NONE,  COLOUR_GREY, 150, 274,  36,  47, STR_02BD,                   STR_LIVERY_PRIMARY_TIP },
    00624 { WWT_DROPDOWN, RESIZE_NONE,  COLOUR_GREY, 275, 399,  36,  47, STR_02E1,                   STR_LIVERY_SECONDARY_TIP },
    00625 {   WWT_MATRIX, RESIZE_NONE,  COLOUR_GREY,   0, 399,  48,  48 + 1 * 14, (1 << 8) | 1,      STR_LIVERY_PANEL_TIP },
    00626 { WIDGETS_END },
    00627 };
    00628
    00629 static const WindowDesc _select_company_livery_desc(
    00630   WDP_AUTO, WDP_AUTO, 400, 49 + 1 * 14, 400, 49 + 1 * 14,
    00631   WC_COMPANY_COLOUR, WC_NONE,
    00632   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
    00633   _select_company_livery_widgets
    00634 );
    00635
    00643 void DrawCompanyManagerFace(CompanyManagerFace cmf, int colour, int x, int y)
    00644 {
    00645   GenderEthnicity ge = (GenderEthnicity)GetCompanyManagerFaceBits(cmf, CMFV_GEN_ETHN, GE_WM);
    00646
    00647   bool has_moustache   = !HasBit(ge, GENDER_FEMALE) && GetCompanyManagerFaceBits(cmf, CMFV_HAS_MOUSTACHE,   ge) != 0;
    00648   bool has_tie_earring = !HasBit(ge, GENDER_FEMALE) || GetCompanyManagerFaceBits(cmf, CMFV_HAS_TIE_EARRING, ge) != 0;
    00649   bool has_glasses     = GetCompanyManagerFaceBits(cmf, CMFV_HAS_GLASSES, ge) != 0;
    00650   SpriteID pal;
    00651
    00652   /* Modify eye colour palette only if 2 or more valid values exist */
    00653   if (_cmf_info[CMFV_EYE_COLOUR].valid_values[ge] < 2) {
    00654     pal = PAL_NONE;
    00655   } else {
    00656     switch (GetCompanyManagerFaceBits(cmf, CMFV_EYE_COLOUR, ge)) {
    00657       default: NOT_REACHED();
    00658       case 0: pal = PALETTE_TO_BROWN; break;
    00659       case 1: pal = PALETTE_TO_BLUE;  break;
    00660       case 2: pal = PALETTE_TO_GREEN; break;
    00661     }
    00662   }
    00663
    00664   /* Draw the gradient (background) */
    00665   DrawSprite(SPR_GRADIENT, GENERAL_SPRITE_COLOUR(colour), x, y);
    00666
    00667   for (CompanyManagerFaceVariable cmfv = CMFV_CHEEKS; cmfv < CMFV_END; cmfv++) {
    00668     switch (cmfv) {
    00669       case CMFV_MOUSTACHE:   if (!has_moustache)   continue; break;
    00670       case CMFV_LIPS:        // FALL THROUGH
    00671       case CMFV_NOSE:        if (has_moustache)    continue; break;
    00672       case CMFV_TIE_EARRING: if (!has_tie_earring) continue; break;
    00673       case CMFV_GLASSES:     if (!has_glasses)     continue; break;
    00674       default: break;
    00675     }
    00676     DrawSprite(GetCompanyManagerFaceSprite(cmf, cmfv, ge), (cmfv == CMFV_EYEBROWS) ? pal : PAL_NONE, x, y);
    00677   }
    00678 }
    00679
    00681 static const Widget _select_company_manager_face_widgets[] = {
    00682 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_GREY,     0,    10,     0,    13, STR_00C5,                STR_018B_CLOSE_WINDOW},              // SCMFW_WIDGET_CLOSEBOX
    00683 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_GREY,    11,   174,     0,    13, STR_7043_FACE_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS},    // SCMFW_WIDGET_CAPTION
    00684 {     WWT_IMGBTN,   RESIZE_NONE,  COLOUR_GREY,   175,   189,     0,    13, SPR_LARGE_SMALL_WINDOW,  STR_FACE_ADVANCED_TIP},              // SCMFW_WIDGET_TOGGLE_LARGE_SMALL
    00685 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   189,    14,   150, 0x0,                     STR_NULL},                           // SCMFW_WIDGET_SELECT_FACE
    00686 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     0,    94,   151,   162, STR_012E_CANCEL,         STR_7047_CANCEL_NEW_FACE_SELECTION}, // SCMFW_WIDGET_CANCEL
    00687 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    95,   189,   151,   162, STR_012F_OK,             STR_7048_ACCEPT_NEW_FACE_SELECTION}, // SCMFW_WIDGET_ACCEPT
    00688 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_GREY,    95,   187,    75,    86, STR_7044_MALE,           STR_7049_SELECT_MALE_FACES},         // SCMFW_WIDGET_MALE
    00689 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_GREY,    95,   187,    87,    98, STR_7045_FEMALE,         STR_704A_SELECT_FEMALE_FACES},       // SCMFW_WIDGET_FEMALE
    00690 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     2,    93,   137,   148, STR_7046_NEW_FACE,       STR_704B_GENERATE_RANDOM_NEW_FACE},  // SCMFW_WIDGET_RANDOM_NEW_FACE
    00691 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    95,   187,    16,    27, STR_FACE_ADVANCED,       STR_FACE_ADVANCED_TIP},              // SCMFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON
    00692 {   WIDGETS_END},
    00693 };
    00694
    00696 static const Widget _select_company_manager_face_adv_widgets[] = {
    00697 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_GREY,     0,    10,     0,    13, STR_00C5,                STR_018B_CLOSE_WINDOW},              // SCMFW_WIDGET_CLOSEBOX
    00698 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_GREY,    11,   204,     0,    13, STR_7043_FACE_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS},    // SCMFW_WIDGET_CAPTION
    00699 {     WWT_IMGBTN,   RESIZE_NONE,  COLOUR_GREY,   205,   219,     0,    13, SPR_LARGE_SMALL_WINDOW,  STR_FACE_SIMPLE_TIP},                // SCMFW_WIDGET_TOGGLE_LARGE_SMALL
    00700 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   219,    14,   207, 0x0,                     STR_NULL},                           // SCMFW_WIDGET_SELECT_FACE
    00701 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     0,    94,   208,   219, STR_012E_CANCEL,         STR_7047_CANCEL_NEW_FACE_SELECTION}, // SCMFW_WIDGET_CANCEL
    00702 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    95,   219,   208,   219, STR_012F_OK,             STR_7048_ACCEPT_NEW_FACE_SELECTION}, // SCMFW_WIDGET_ACCEPT
    00703 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_GREY,    96,   156,    32,    43, STR_7044_MALE,           STR_7049_SELECT_MALE_FACES},         // SCMFW_WIDGET_MALE
    00704 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_GREY,   157,   217,    32,    43, STR_7045_FEMALE,         STR_704A_SELECT_FEMALE_FACES},       // SCMFW_WIDGET_FEMALE
    00705 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     2,    93,   137,   148, STR_RANDOM,              STR_704B_GENERATE_RANDOM_NEW_FACE},  // SCMFW_WIDGET_RANDOM_NEW_FACE
    00706 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    95,   217,    16,    27, STR_FACE_SIMPLE,         STR_FACE_SIMPLE_TIP},                // SCMFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON
    00707 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     2,    93,   158,   169, STR_FACE_LOAD,           STR_FACE_LOAD_TIP},                  // SCMFW_WIDGET_LOAD
    00708 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     2,    93,   170,   181, STR_FACE_FACECODE,       STR_FACE_FACECODE_TIP},              // SCMFW_WIDGET_FACECODE
    00709 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     2,    93,   182,   193, STR_FACE_SAVE,           STR_FACE_SAVE_TIP},                  // SCMFW_WIDGET_SAVE
    00710 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_GREY,    96,   156,    46,    57, STR_FACE_EUROPEAN,       STR_FACE_SELECT_EUROPEAN},           // SCMFW_WIDGET_ETHNICITY_EUR
    00711 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_GREY,   157,   217,    46,    57, STR_FACE_AFRICAN,        STR_FACE_SELECT_AFRICAN},            // SCMFW_WIDGET_ETHNICITY_AFR
    00712 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   175,   217,    60,    71, STR_EMPTY,               STR_FACE_MOUSTACHE_EARRING_TIP},     // SCMFW_WIDGET_HAS_MOUSTACHE_EARRING
    00713 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   175,   217,    72,    83, STR_EMPTY,               STR_FACE_GLASSES_TIP},               // SCMFW_WIDGET_HAS_GLASSES
    00714 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,   110,   121, SPR_ARROW_LEFT,          STR_FACE_EYECOLOUR_TIP},             // SCMFW_WIDGET_EYECOLOUR_L
    00715 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,   110,   121, STR_EMPTY,               STR_FACE_EYECOLOUR_TIP},             // SCMFW_WIDGET_EYECOLOUR
    00716 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,   110,   121, SPR_ARROW_RIGHT,         STR_FACE_EYECOLOUR_TIP},             // SCMFW_WIDGET_EYECOLOUR_R
    00717 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,   158,   169, SPR_ARROW_LEFT,          STR_FACE_CHIN_TIP},                  // SCMFW_WIDGET_CHIN_L
    00718 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,   158,   169, STR_EMPTY,               STR_FACE_CHIN_TIP},                  // SCMFW_WIDGET_CHIN
    00719 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,   158,   169, SPR_ARROW_RIGHT,         STR_FACE_CHIN_TIP},                  // SCMFW_WIDGET_CHIN_R
    00720 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,    98,   109, SPR_ARROW_LEFT,          STR_FACE_EYEBROWS_TIP},              // SCMFW_WIDGET_EYEBROWS_L
    00721 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,    98,   109, STR_EMPTY,               STR_FACE_EYEBROWS_TIP},              // SCMFW_WIDGET_EYEBROWS
    00722 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,    98,   109, SPR_ARROW_RIGHT,         STR_FACE_EYEBROWS_TIP},              // SCMFW_WIDGET_EYEBROWS_R
    00723 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,   146,   157, SPR_ARROW_LEFT,          STR_FACE_LIPS_MOUSTACHE_TIP},        // SCMFW_WIDGET_LIPS_MOUSTACHE_L
    00724 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,   146,   157, STR_EMPTY,               STR_FACE_LIPS_MOUSTACHE_TIP},        // SCMFW_WIDGET_LIPS_MOUSTACHE
    00725 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,   146,   157, SPR_ARROW_RIGHT,         STR_FACE_LIPS_MOUSTACHE_TIP},        // SCMFW_WIDGET_LIPS_MOUSTACHE_R
    00726 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,   134,   145, SPR_ARROW_LEFT,          STR_FACE_NOSE_TIP},                  // SCMFW_WIDGET_NOSE_L
    00727 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,   134,   145, STR_EMPTY,               STR_FACE_NOSE_TIP},                  // SCMFW_WIDGET_NOSE
    00728 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,   134,   145, SPR_ARROW_RIGHT,         STR_FACE_NOSE_TIP},                  // SCMFW_WIDGET_NOSE_R
    00729 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,    86,    97, SPR_ARROW_LEFT,          STR_FACE_HAIR_TIP},                  // SCMFW_WIDGET_HAIR_L
    00730 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,    86,    97, STR_EMPTY,               STR_FACE_HAIR_TIP},                  // SCMFW_WIDGET_HAIR
    00731 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,    86,    97, SPR_ARROW_RIGHT,         STR_FACE_HAIR_TIP},                  // SCMFW_WIDGET_HAIR_R
    00732 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,   170,   181, SPR_ARROW_LEFT,          STR_FACE_JACKET_TIP},                // SCMFW_WIDGET_JACKET_L
    00733 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,   170,   181, STR_EMPTY,               STR_FACE_JACKET_TIP},                // SCMFW_WIDGET_JACKET
    00734 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,   170,   181, SPR_ARROW_RIGHT,         STR_FACE_JACKET_TIP},                // SCMFW_WIDGET_JACKET_R
    00735 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,   182,   193, SPR_ARROW_LEFT,          STR_FACE_COLLAR_TIP},                // SCMFW_WIDGET_COLLAR_L
    00736 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,   182,   193, STR_EMPTY,               STR_FACE_COLLAR_TIP},                // SCMFW_WIDGET_COLLAR
    00737 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,   182,   193, SPR_ARROW_RIGHT,         STR_FACE_COLLAR_TIP},                // SCMFW_WIDGET_COLLAR_R
    00738 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,   194,   205, SPR_ARROW_LEFT,          STR_FACE_TIE_EARRING_TIP},           // SCMFW_WIDGET_TIE_EARRING_L
    00739 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,   194,   205, STR_EMPTY,               STR_FACE_TIE_EARRING_TIP},           // SCMFW_WIDGET_TIE_EARRING
    00740 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,   194,   205, SPR_ARROW_RIGHT,         STR_FACE_TIE_EARRING_TIP},           // SCMFW_WIDGET_TIE_EARRING_R
    00741 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,   122,   133, SPR_ARROW_LEFT,          STR_FACE_GLASSES_TIP_2},             // SCMFW_WIDGET_GLASSES_L
    00742 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,   122,   133, STR_EMPTY,               STR_FACE_GLASSES_TIP_2},             // SCMFW_WIDGET_GLASSES
    00743 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,   122,   133, SPR_ARROW_RIGHT,         STR_FACE_GLASSES_TIP_2},             // SCMFW_WIDGET_GLASSES_R
    00744 {   WIDGETS_END},
    00745 };
    00746
    00747 class SelectCompanyManagerFaceWindow : public Window
    00748 {
    00749   CompanyManagerFace face;
    00750   bool advanced;
    00751
    00752   GenderEthnicity ge;
    00753   bool is_female;
    00754   bool is_moust_male;
    00755
    00761   enum SelectCompanyManagerFaceWidgets {
    00762     SCMFW_WIDGET_CLOSEBOX = 0,
    00763     SCMFW_WIDGET_CAPTION,
    00764     SCMFW_WIDGET_TOGGLE_LARGE_SMALL,
    00765     SCMFW_WIDGET_SELECT_FACE,
    00766     SCMFW_WIDGET_CANCEL,
    00767     SCMFW_WIDGET_ACCEPT,
    00768     SCMFW_WIDGET_MALE,
    00769     SCMFW_WIDGET_FEMALE,
    00770     SCMFW_WIDGET_RANDOM_NEW_FACE,
    00771     SCMFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON,
    00772     /* from here is the advanced company manager face selection window */
    00773     SCMFW_WIDGET_LOAD,
    00774     SCMFW_WIDGET_FACECODE,
    00775     SCMFW_WIDGET_SAVE,
    00776     SCMFW_WIDGET_ETHNICITY_EUR,
    00777     SCMFW_WIDGET_ETHNICITY_AFR,
    00778     SCMFW_WIDGET_HAS_MOUSTACHE_EARRING,
    00779     SCMFW_WIDGET_HAS_GLASSES,
    00780     SCMFW_WIDGET_EYECOLOUR_L,
    00781     SCMFW_WIDGET_EYECOLOUR,
    00782     SCMFW_WIDGET_EYECOLOUR_R,
    00783     SCMFW_WIDGET_CHIN_L,
    00784     SCMFW_WIDGET_CHIN,
    00785     SCMFW_WIDGET_CHIN_R,
    00786     SCMFW_WIDGET_EYEBROWS_L,
    00787     SCMFW_WIDGET_EYEBROWS,
    00788     SCMFW_WIDGET_EYEBROWS_R,
    00789     SCMFW_WIDGET_LIPS_MOUSTACHE_L,
    00790     SCMFW_WIDGET_LIPS_MOUSTACHE,
    00791     SCMFW_WIDGET_LIPS_MOUSTACHE_R,
    00792     SCMFW_WIDGET_NOSE_L,
    00793     SCMFW_WIDGET_NOSE,
    00794     SCMFW_WIDGET_NOSE_R,
    00795     SCMFW_WIDGET_HAIR_L,
    00796     SCMFW_WIDGET_HAIR,
    00797     SCMFW_WIDGET_HAIR_R,
    00798     SCMFW_WIDGET_JACKET_L,
    00799     SCMFW_WIDGET_JACKET,
    00800     SCMFW_WIDGET_JACKET_R,
    00801     SCMFW_WIDGET_COLLAR_L,
    00802     SCMFW_WIDGET_COLLAR,
    00803     SCMFW_WIDGET_COLLAR_R,
    00804     SCMFW_WIDGET_TIE_EARRING_L,
    00805     SCMFW_WIDGET_TIE_EARRING,
    00806     SCMFW_WIDGET_TIE_EARRING_R,
    00807     SCMFW_WIDGET_GLASSES_L,
    00808     SCMFW_WIDGET_GLASSES,
    00809     SCMFW_WIDGET_GLASSES_R,
    00810   };
    00819   void DrawFaceStringLabel(byte widget_index, StringID str, uint8 val, bool is_bool_widget)
    00820   {
    00821     /* Write the label in gold (0x2) to the left of the button. */
    00822     DrawStringRightAligned(this->widget[widget_index].left - (is_bool_widget ? 5 : 14), this->widget[widget_index].top + 1, str, TC_GOLD);
    00823
    00824     if (!this->IsWidgetDisabled(widget_index)) {
    00825       if (is_bool_widget) {
    00826         /* if it a bool button write yes or no */
    00827         str = (val != 0) ? STR_FACE_YES : STR_FACE_NO;
    00828       } else {
    00829         /* else write the value + 1 */
    00830         SetDParam(0, val + 1);
    00831         str = STR_JUST_INT;
    00832       }
    00833
    00834       /* Draw the value/bool in white (0xC). If the button clicked adds 1px to x and y text coordinates (IsWindowWidgetLowered()). */
    00835       DrawStringCentered(this->widget[widget_index].left + (this->widget[widget_index].right - this->widget[widget_index].left) / 2 +
    00836         this->IsWidgetLowered(widget_index), this->widget[widget_index].top + 1 + this->IsWidgetLowered(widget_index), str, TC_WHITE);
    00837     }
    00838   }
    00839
    00840   void UpdateData()
    00841   {
    00842     this->ge = (GenderEthnicity)GB(this->face, _cmf_info[CMFV_GEN_ETHN].offset, _cmf_info[CMFV_GEN_ETHN].length); // get the gender and ethnicity
    00843     this->is_female = HasBit(this->ge, GENDER_FEMALE); // get the gender: 0 == male and 1 == female
    00844     this->is_moust_male = !is_female && GetCompanyManagerFaceBits(this->face, CMFV_HAS_MOUSTACHE, this->ge) != 0; // is a male face with moustache
    00845   }
    00846
    00847 public:
    00848   SelectCompanyManagerFaceWindow(const WindowDesc *desc, Window *parent, bool advanced, int top, int left) : Window(desc, parent->window_number)
    00849   {
    00850     this->parent = parent;
    00851     this->owner = (Owner)this->window_number;
    00852     this->face = GetCompany((CompanyID)this->window_number)->face;
    00853     this->advanced = advanced;
    00854
    00855     this->UpdateData();
    00856
    00857     /* Check if repositioning from default is required */
    00858     if (top != FIRST_GUI_CALL && left != FIRST_GUI_CALL) {
    00859       this->top = top;
    00860       this->left = left;
    00861     }
    00862
    00863     this->FindWindowPlacementAndResize(desc);
    00864   }
    00865
    00866   virtual void OnPaint()
    00867   {
    00868     /* lower the non-selected gender button */
    00869     this->SetWidgetLoweredState(SCMFW_WIDGET_MALE,  !this->is_female);
    00870     this->SetWidgetLoweredState(SCMFW_WIDGET_FEMALE, this->is_female);
    00871
    00872     /* advanced company manager face selection window */
    00873     if (this->advanced) {
    00874       /* lower the non-selected ethnicity button */
    00875       this->SetWidgetLoweredState(SCMFW_WIDGET_ETHNICITY_EUR, !HasBit(this->ge, ETHNICITY_BLACK));
    00876       this->SetWidgetLoweredState(SCMFW_WIDGET_ETHNICITY_AFR,  HasBit(this->ge, ETHNICITY_BLACK));
    00877
    00878
    00879       /* Disable dynamically the widgets which CompanyManagerFaceVariable has less than 2 options
    00880        * (or in other words you haven't any choice).
    00881        * If the widgets depend on a HAS-variable and this is false the widgets will be disabled, too. */
    00882
    00883       /* Eye colour buttons */
    00884       this->SetWidgetsDisabledState(_cmf_info[CMFV_EYE_COLOUR].valid_values[this->ge] < 2,
    00885         SCMFW_WIDGET_EYECOLOUR, SCMFW_WIDGET_EYECOLOUR_L, SCMFW_WIDGET_EYECOLOUR_R, WIDGET_LIST_END);
    00886
    00887       /* Chin buttons */
    00888       this->SetWidgetsDisabledState(_cmf_info[CMFV_CHIN].valid_values[this->ge] < 2,
    00889         SCMFW_WIDGET_CHIN, SCMFW_WIDGET_CHIN_L, SCMFW_WIDGET_CHIN_R, WIDGET_LIST_END);
    00890
    00891       /* Eyebrows buttons */
    00892       this->SetWidgetsDisabledState(_cmf_info[CMFV_EYEBROWS].valid_values[this->ge] < 2,
    00893         SCMFW_WIDGET_EYEBROWS, SCMFW_WIDGET_EYEBROWS_L, SCMFW_WIDGET_EYEBROWS_R, WIDGET_LIST_END);
    00894
    00895       /* Lips or (if it a male face with a moustache) moustache buttons */
    00896       this->SetWidgetsDisabledState(_cmf_info[this->is_moust_male ? CMFV_MOUSTACHE : CMFV_LIPS].valid_values[this->ge] < 2,
    00897         SCMFW_WIDGET_LIPS_MOUSTACHE, SCMFW_WIDGET_LIPS_MOUSTACHE_L, SCMFW_WIDGET_LIPS_MOUSTACHE_R, WIDGET_LIST_END);
    00898
    00899       /* Nose buttons | male faces with moustache haven't any nose options */
    00900       this->SetWidgetsDisabledState(_cmf_info[CMFV_NOSE].valid_values[this->ge] < 2 || this->is_moust_male,
    00901         SCMFW_WIDGET_NOSE, SCMFW_WIDGET_NOSE_L, SCMFW_WIDGET_NOSE_R, WIDGET_LIST_END);
    00902
    00903       /* Hair buttons */
    00904       this->SetWidgetsDisabledState(_cmf_info[CMFV_HAIR].valid_values[this->ge] < 2,
    00905         SCMFW_WIDGET_HAIR, SCMFW_WIDGET_HAIR_L, SCMFW_WIDGET_HAIR_R, WIDGET_LIST_END);
    00906
    00907       /* Jacket buttons */
    00908       this->SetWidgetsDisabledState(_cmf_info[CMFV_JACKET].valid_values[this->ge] < 2,
    00909         SCMFW_WIDGET_JACKET, SCMFW_WIDGET_JACKET_L, SCMFW_WIDGET_JACKET_R, WIDGET_LIST_END);
    00910
    00911       /* Collar buttons */
    00912       this->SetWidgetsDisabledState(_cmf_info[CMFV_COLLAR].valid_values[this->ge] < 2,
    00913         SCMFW_WIDGET_COLLAR, SCMFW_WIDGET_COLLAR_L, SCMFW_WIDGET_COLLAR_R, WIDGET_LIST_END);
    00914
    00915       /* Tie/earring buttons | female faces without earring haven't any earring options */
    00916       this->SetWidgetsDisabledState(_cmf_info[CMFV_TIE_EARRING].valid_values[this->ge] < 2 ||
    00917           (this->is_female && GetCompanyManagerFaceBits(this->face, CMFV_HAS_TIE_EARRING, this->ge) == 0),
    00918         SCMFW_WIDGET_TIE_EARRING, SCMFW_WIDGET_TIE_EARRING_L, SCMFW_WIDGET_TIE_EARRING_R, WIDGET_LIST_END);
    00919
    00920       /* Glasses buttons | faces without glasses haven't any glasses options */
    00921       this->SetWidgetsDisabledState(_cmf_info[CMFV_GLASSES].valid_values[this->ge] < 2 || GetCompanyManagerFaceBits(this->face, CMFV_HAS_GLASSES, this->ge) == 0,
    00922         SCMFW_WIDGET_GLASSES, SCMFW_WIDGET_GLASSES_L, SCMFW_WIDGET_GLASSES_R, WIDGET_LIST_END);
    00923     }
    00924
    00925     this->DrawWidgets();
    00926
    00927     /* Draw dynamic button value and labels for the advanced company manager face selection window */
    00928     if (this->advanced) {
    00929       if (this->is_female) {
    00930         /* Only for female faces */
    00931         this->DrawFaceStringLabel(SCMFW_WIDGET_HAS_MOUSTACHE_EARRING, STR_FACE_EARRING,   GetCompanyManagerFaceBits(this->face, CMFV_HAS_TIE_EARRING, this->ge), true );
    00932         this->DrawFaceStringLabel(SCMFW_WIDGET_TIE_EARRING,           STR_FACE_EARRING,   GetCompanyManagerFaceBits(this->face, CMFV_TIE_EARRING,     this->ge), false);
    00933       } else {
    00934         /* Only for male faces */
    00935         this->DrawFaceStringLabel(SCMFW_WIDGET_HAS_MOUSTACHE_EARRING, STR_FACE_MOUSTACHE, GetCompanyManagerFaceBits(this->face, CMFV_HAS_MOUSTACHE,   this->ge), true );
    00936         this->DrawFaceStringLabel(SCMFW_WIDGET_TIE_EARRING,           STR_FACE_TIE,       GetCompanyManagerFaceBits(this->face, CMFV_TIE_EARRING,     this->ge), false);
    00937       }
    00938       if (this->is_moust_male) {
    00939         /* Only for male faces with moustache */
    00940         this->DrawFaceStringLabel(SCMFW_WIDGET_LIPS_MOUSTACHE,        STR_FACE_MOUSTACHE, GetCompanyManagerFaceBits(this->face, CMFV_MOUSTACHE,       this->ge), false);
    00941       } else {
    00942         /* Only for female faces or male faces without moustache */
    00943         this->DrawFaceStringLabel(SCMFW_WIDGET_LIPS_MOUSTACHE,        STR_FACE_LIPS,      GetCompanyManagerFaceBits(this->face, CMFV_LIPS,            this->ge), false);
    00944       }
    00945       /* For all faces */
    00946       this->DrawFaceStringLabel(SCMFW_WIDGET_HAS_GLASSES,           STR_FACE_GLASSES,     GetCompanyManagerFaceBits(this->face, CMFV_HAS_GLASSES,     this->ge), true );
    00947       this->DrawFaceStringLabel(SCMFW_WIDGET_HAIR,                  STR_FACE_HAIR,        GetCompanyManagerFaceBits(this->face, CMFV_HAIR,            this->ge), false);
    00948       this->DrawFaceStringLabel(SCMFW_WIDGET_EYEBROWS,              STR_FACE_EYEBROWS,    GetCompanyManagerFaceBits(this->face, CMFV_EYEBROWS,        this->ge), false);
    00949       this->DrawFaceStringLabel(SCMFW_WIDGET_EYECOLOUR,             STR_FACE_EYECOLOUR,   GetCompanyManagerFaceBits(this->face, CMFV_EYE_COLOUR,      this->ge), false);
    00950       this->DrawFaceStringLabel(SCMFW_WIDGET_GLASSES,               STR_FACE_GLASSES,     GetCompanyManagerFaceBits(this->face, CMFV_GLASSES,         this->ge), false);
    00951       this->DrawFaceStringLabel(SCMFW_WIDGET_NOSE,                  STR_FACE_NOSE,        GetCompanyManagerFaceBits(this->face, CMFV_NOSE,            this->ge), false);
    00952       this->DrawFaceStringLabel(SCMFW_WIDGET_CHIN,                  STR_FACE_CHIN,        GetCompanyManagerFaceBits(this->face, CMFV_CHIN,            this->ge), false);
    00953       this->DrawFaceStringLabel(SCMFW_WIDGET_JACKET,                STR_FACE_JACKET,      GetCompanyManagerFaceBits(this->face, CMFV_JACKET,          this->ge), false);
    00954       this->DrawFaceStringLabel(SCMFW_WIDGET_COLLAR,                STR_FACE_COLLAR,      GetCompanyManagerFaceBits(this->face, CMFV_COLLAR,          this->ge), false);
    00955     }
    00956
    00957     /* Draw the company manager face picture */
    00958     DrawCompanyManagerFace(this->face, GetCompany((CompanyID)this->window_number)->colour, 2, 16);
    00959   }
    00960
    00961   virtual void OnClick(Point pt, int widget)
    00962   {
    00963     switch (widget) {
    00964       /* Toggle size, advanced/simple face selection */
    00965       case SCMFW_WIDGET_TOGGLE_LARGE_SMALL:
    00966       case SCMFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON: {
    00967         DoCommandP(0, 0, this->face, CMD_SET_COMPANY_MANAGER_FACE);
    00968
    00969         /* Backup some data before deletion */
    00970         int oldtop = this->top;
    00971         int oldleft = this->left;
    00972         bool adv = !this->advanced;
    00973         Window *parent = this->parent;
    00974
    00975         delete this;
    00976
    00977         /* Open up the (toggled size) Face selection window at the same position as the previous */
    00978         DoSelectCompanyManagerFace(parent, adv, oldtop, oldleft);
    00979       } break;
    00980
    00981
    00982       /* OK button */
    00983       case SCMFW_WIDGET_ACCEPT:
    00984         DoCommandP(0, 0, this->face, CMD_SET_COMPANY_MANAGER_FACE);
    00985         /* Fall-Through */
    00986
    00987       /* Cancel button */
    00988       case SCMFW_WIDGET_CANCEL:
    00989         delete this;
    00990         break;
    00991
    00992       /* Load button */
    00993       case SCMFW_WIDGET_LOAD:
    00994         this->face = _company_manager_face;
    00995         ScaleAllCompanyManagerFaceBits(this->face);
    00996         ShowErrorMessage(INVALID_STRING_ID, STR_FACE_LOAD_DONE, 0, 0);
    00997         this->UpdateData();
    00998         this->SetDirty();
    00999         break;
    01000
    01001       /* 'Company manager face number' button, view and/or set company manager face number */
    01002       case SCMFW_WIDGET_FACECODE:
    01003         SetDParam(0, this->face);
    01004         ShowQueryString(STR_JUST_INT, STR_FACE_FACECODE_CAPTION, 10 + 1, 0, this, CS_NUMERAL, QSF_NONE);
    01005         break;
    01006
    01007       /* Save button */
    01008       case SCMFW_WIDGET_SAVE:
    01009         _company_manager_face = this->face;
    01010         ShowErrorMessage(INVALID_STRING_ID, STR_FACE_SAVE_DONE, 0, 0);
    01011         break;
    01012
    01013       /* Toggle gender (male/female) button */
    01014       case SCMFW_WIDGET_MALE:
    01015       case SCMFW_WIDGET_FEMALE:
    01016         SetCompanyManagerFaceBits(this->face, CMFV_GENDER, this->ge, widget - SCMFW_WIDGET_MALE);
    01017         ScaleAllCompanyManagerFaceBits(this->face);
    01018         this->UpdateData();
    01019         this->SetDirty();
    01020         break;
    01021
    01022       /* Randomize face button */
    01023       case SCMFW_WIDGET_RANDOM_NEW_FACE:
    01024         RandomCompanyManagerFaceBits(this->face, this->ge, this->advanced);
    01025         this->UpdateData();
    01026         this->SetDirty();
    01027         break;
    01028
    01029       /* Toggle ethnicity (european/african) button */
    01030       case SCMFW_WIDGET_ETHNICITY_EUR:
    01031       case SCMFW_WIDGET_ETHNICITY_AFR:
    01032         SetCompanyManagerFaceBits(this->face, CMFV_ETHNICITY, this->ge, widget - SCMFW_WIDGET_ETHNICITY_EUR);
    01033         ScaleAllCompanyManagerFaceBits(this->face);
    01034         this->UpdateData();
    01035         this->SetDirty();
    01036         break;
    01037
    01038       default:
    01039         /* For all buttons from SCMFW_WIDGET_HAS_MOUSTACHE_EARRING to SCMFW_WIDGET_GLASSES_R is the same function.
    01040          * Therefor is this combined function.
    01041          * First it checks which CompanyManagerFaceVariable will be change and then
    01042          * a: invert the value for boolean variables
    01043          * or b: it checks inside of IncreaseCompanyManagerFaceBits() if a left (_L) butten is pressed and then decrease else increase the variable */
    01044         if (this->advanced && widget >= SCMFW_WIDGET_HAS_MOUSTACHE_EARRING && widget <= SCMFW_WIDGET_GLASSES_R) {
    01045           CompanyManagerFaceVariable cmfv; // which CompanyManagerFaceVariable shall be edited
    01046
    01047           if (widget < SCMFW_WIDGET_EYECOLOUR_L) { // Bool buttons
    01048             switch (widget - SCMFW_WIDGET_HAS_MOUSTACHE_EARRING) {
    01049               default: NOT_REACHED();
    01050               case 0: cmfv = this->is_female ? CMFV_HAS_TIE_EARRING : CMFV_HAS_MOUSTACHE; break; // Has earring/moustache button
    01051               case 1: cmfv = CMFV_HAS_GLASSES; break; // Has glasses button
    01052             }
    01053             SetCompanyManagerFaceBits(this->face, cmfv, this->ge, !GetCompanyManagerFaceBits(this->face, cmfv, this->ge));
    01054             ScaleAllCompanyManagerFaceBits(this->face);
    01055           } else { // Value buttons
    01056             switch ((widget - SCMFW_WIDGET_EYECOLOUR_L) / 3) {
    01057               default: NOT_REACHED();
    01058               case 0: cmfv = CMFV_EYE_COLOUR; break;  // Eye colour buttons
    01059               case 1: cmfv = CMFV_CHIN; break;        // Chin buttons
    01060               case 2: cmfv = CMFV_EYEBROWS; break;    // Eyebrows buttons
    01061               case 3: cmfv = this->is_moust_male ? CMFV_MOUSTACHE : CMFV_LIPS; break; // Moustache or lips buttons
    01062               case 4: cmfv = CMFV_NOSE; break;        // Nose buttons
    01063               case 5: cmfv = CMFV_HAIR; break;        // Hair buttons
    01064               case 6: cmfv = CMFV_JACKET; break;      // Jacket buttons
    01065               case 7: cmfv = CMFV_COLLAR; break;      // Collar buttons
    01066               case 8: cmfv = CMFV_TIE_EARRING; break; // Tie/earring buttons
    01067               case 9: cmfv = CMFV_GLASSES; break;     // Glasses buttons
    01068             }
    01069             /* 0 == left (_L), 1 == middle or 2 == right (_R) - button click */
    01070             IncreaseCompanyManagerFaceBits(this->face, cmfv, this->ge, (((widget - SCMFW_WIDGET_EYECOLOUR_L) % 3) != 0) ? 1 : -1);
    01071           }
    01072           this->UpdateData();
    01073           this->SetDirty();
    01074         }
    01075         break;
    01076     }
    01077   }
    01078
    01079   virtual void OnQueryTextFinished(char *str)
    01080   {
    01081     if (str == NULL) return;
    01082     /* Set a new company manager face number */
    01083     if (!StrEmpty(str)) {
    01084       this->face = strtoul(str, NULL, 10);
    01085       ScaleAllCompanyManagerFaceBits(this->face);
    01086       ShowErrorMessage(INVALID_STRING_ID, STR_FACE_FACECODE_SET, 0, 0);
    01087       this->UpdateData();
    01088       this->SetDirty();
    01089     } else {
    01090       ShowErrorMessage(INVALID_STRING_ID, STR_FACE_FACECODE_ERR, 0, 0);
    01091     }
    01092   }
    01093 };
    01094
    01096 static const WindowDesc _select_company_manager_face_desc(
    01097   WDP_AUTO, WDP_AUTO, 190, 163, 190, 163,
    01098   WC_COMPANY_MANAGER_FACE, WC_NONE,
    01099   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_CONSTRUCTION,
    01100   _select_company_manager_face_widgets
    01101 );
    01102
    01104 static const WindowDesc _select_company_manager_face_adv_desc(
    01105   WDP_AUTO, WDP_AUTO, 220, 220, 220, 220,
    01106   WC_COMPANY_MANAGER_FACE, WC_NONE,
    01107   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_CONSTRUCTION,
    01108   _select_company_manager_face_adv_widgets
    01109 );
    01110
    01119 static void DoSelectCompanyManagerFace(Window *parent, bool adv, int top, int left)
    01120 {
    01121   if (!IsValidCompanyID((CompanyID)parent->window_number)) return;
    01122
    01123   if (BringWindowToFrontById(WC_COMPANY_MANAGER_FACE, parent->window_number)) return;
    01124   new SelectCompanyManagerFaceWindow(adv ? &_select_company_manager_face_adv_desc : &_select_company_manager_face_desc, parent, adv, top, left); // simple or advanced window
    01125 }
    01126
    01127
    01128 /* Names of the widgets. Keep them in the same order as in the widget array */
    01129 enum CompanyWindowWidgets {
    01130   CW_WIDGET_CLOSEBOX = 0,
    01131   CW_WIDGET_CAPTION,
    01132   CW_WIDGET_FACE,
    01133   CW_WIDGET_NEW_FACE,
    01134   CW_WIDGET_COLOUR_SCHEME,
    01135   CW_WIDGET_PRESIDENT_NAME,
    01136   CW_WIDGET_COMPANY_NAME,
    01137   CW_WIDGET_BUILD_VIEW_HQ,
    01138   CW_WIDGET_RELOCATE_HQ,
    01139   CW_WIDGET_BUY_SHARE,
    01140   CW_WIDGET_SELL_SHARE,
    01141   CW_WIDGET_COMPANY_PASSWORD,
    01142   CW_WIDGET_COMPANY_JOIN,
    01143 };
    01144
    01145 static const Widget _company_widgets[] = {
    01146 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_GREY,     0,    10,     0,    13, STR_00C5,                          STR_018B_CLOSE_WINDOW},
    01147 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_GREY,    11,   359,     0,    13, STR_7001,                          STR_018C_WINDOW_TITLE_DRAG_THIS},
    01148 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   359,    14,   157, 0x0,                               STR_NULL},
    01149 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     0,    89,   158,   169, STR_7004_NEW_FACE,                 STR_7030_SELECT_NEW_FACE_FOR_PRESIDENT},
    01150 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    90,   179,   158,   169, STR_7005_COLOUR_SCHEME,            STR_7031_CHANGE_THE_COMPANY_VEHICLE},
    01151 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   180,   269,   158,   169, STR_7009_PRESIDENT_NAME,           STR_7032_CHANGE_THE_PRESIDENT_S},
    01152 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   270,   359,   158,   169, STR_7008_COMPANY_NAME,             STR_7033_CHANGE_THE_COMPANY_NAME},
    01153 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_GREY,   266,   355,    18,    29, STR_7072_VIEW_HQ,                  STR_7070_BUILD_COMPANY_HEADQUARTERS},
    01154 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_GREY,   266,   355,    32,    43, STR_RELOCATE_HQ,                   STR_RELOCATE_COMPANY_HEADQUARTERS},
    01155 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     0,   179,   158,   169, STR_7077_BUY_25_SHARE_IN_COMPANY,  STR_7079_BUY_25_SHARE_IN_THIS_COMPANY},
    01156 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   180,   359,   158,   169, STR_7078_SELL_25_SHARE_IN_COMPANY, STR_707A_SELL_25_SHARE_IN_THIS_COMPANY},
    01157 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   266,   355,   138,   149, STR_COMPANY_PASSWORD,              STR_COMPANY_PASSWORD_TOOLTIP},
    01158 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   266,   355,   138,   149, STR_COMPANY_JOIN,                  STR_COMPANY_JOIN_TIP},
    01159 {   WIDGETS_END},
    01160 };
    01161
    01162
    01167 static void DrawCompanyVehiclesAmount(CompanyID company)
    01168 {
    01169   const int x = 110;
    01170   int y = 63;
    01171   const Vehicle *v;
    01172   uint train = 0;
    01173   uint road  = 0;
    01174   uint air   = 0;
    01175   uint ship  = 0;
    01176
    01177   DrawString(x, y, STR_7039_VEHICLES, TC_FROMSTRING);
    01178
    01179   FOR_ALL_VEHICLES(v) {
    01180     if (v->owner == company) {
    01181       switch (v->type) {
    01182         case VEH_TRAIN:    if (IsFrontEngine(v)) train++; break;
    01183         case VEH_ROAD:     if (IsRoadVehFront(v)) road++; break;
    01184         case VEH_AIRCRAFT: if (IsNormalAircraft(v)) air++; break;
    01185         case VEH_SHIP:     ship++; break;
    01186         default: break;
    01187       }
    01188     }
    01189   }
    01190
    01191   if (train + road + air + ship == 0) {
    01192     DrawString(x + 70, y, STR_7042_NONE, TC_FROMSTRING);
    01193   } else {
    01194     if (train != 0) {
    01195       SetDParam(0, train);
    01196       DrawString(x + 70, y, STR_TRAINS, TC_FROMSTRING);
    01197       y += 10;
    01198     }
    01199
    01200     if (road != 0) {
    01201       SetDParam(0, road);
    01202       DrawString(x + 70, y, STR_ROAD_VEHICLES, TC_FROMSTRING);
    01203       y += 10;
    01204     }
    01205
    01206     if (air != 0) {
    01207       SetDParam(0, air);
    01208       DrawString(x + 70, y, STR_AIRCRAFT, TC_FROMSTRING);
    01209       y += 10;
    01210     }
    01211
    01212     if (ship != 0) {
    01213       SetDParam(0, ship);
    01214       DrawString(x + 70, y, STR_SHIPS, TC_FROMSTRING);
    01215     }
    01216   }
    01217 }
    01218
    01219 int GetAmountOwnedBy(const Company *c, Owner owner)
    01220 {
    01221   return (c->share_owners[0] == owner) +
    01222          (c->share_owners[1] == owner) +
    01223          (c->share_owners[2] == owner) +
    01224          (c->share_owners[3] == owner);
    01225 }
    01226
    01231 static void DrawCompanyOwnerText(const Company *c)
    01232 {
    01233   const Company *c2;
    01234   uint num = 0;
    01235   const byte height = GetCharacterHeight(FS_NORMAL);
    01236
    01237   FOR_ALL_COMPANIES(c2) {
    01238     uint amt = GetAmountOwnedBy(c, c2->index);
    01239     if (amt != 0) {
    01240       SetDParam(0, amt * 25);
    01241       SetDParam(1, c2->index);
    01242
    01243       DrawString(120, (num++) * height + 116, STR_707D_OWNED_BY, TC_FROMSTRING);
    01244     }
    01245   }
    01246 }
    01247
    01251 struct CompanyWindow : Window
    01252 {
    01253   CompanyWindowWidgets query_widget;
    01254
    01255   CompanyWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
    01256   {
    01257     this->owner = (Owner)this->window_number;
    01258     this->FindWindowPlacementAndResize(desc);
    01259   }
    01260
    01261   virtual void OnPaint()
    01262   {
    01263     const Company *c = GetCompany((CompanyID)this->window_number);
    01264     bool local = this->window_number == _local_company;
    01265
    01266     this->SetWidgetHiddenState(CW_WIDGET_NEW_FACE,       !local);
    01267     this->SetWidgetHiddenState(CW_WIDGET_COLOUR_SCHEME,   !local);
    01268     this->SetWidgetHiddenState(CW_WIDGET_PRESIDENT_NAME, !local);
    01269     this->SetWidgetHiddenState(CW_WIDGET_COMPANY_NAME,   !local);
    01270     this->widget[CW_WIDGET_BUILD_VIEW_HQ].data = (local && c->location_of_HQ == INVALID_TILE) ? STR_706F_BUILD_HQ : STR_7072_VIEW_HQ;
    01271     if (local && c->location_of_HQ != INVALID_TILE) this->widget[CW_WIDGET_BUILD_VIEW_HQ].type = WWT_PUSHTXTBTN; // HQ is already built.
    01272     this->SetWidgetDisabledState(CW_WIDGET_BUILD_VIEW_HQ, !local && c->location_of_HQ == INVALID_TILE);
    01273     this->SetWidgetHiddenState(CW_WIDGET_RELOCATE_HQ,      !local || c->location_of_HQ == INVALID_TILE);
    01274     this->SetWidgetHiddenState(CW_WIDGET_BUY_SHARE,        local);
    01275     this->SetWidgetHiddenState(CW_WIDGET_SELL_SHARE,       local);
    01276     this->SetWidgetHiddenState(CW_WIDGET_COMPANY_PASSWORD, !local || !_networking);
    01277     this->SetWidgetHiddenState(CW_WIDGET_COMPANY_JOIN,     local || !_networking);
    01278     this->SetWidgetDisabledState(CW_WIDGET_COMPANY_JOIN,   !IsHumanCompany(c->index));
    01279
    01280     if (!local) {
    01281       if (_settings_game.economy.allow_shares) { // Shares are allowed
    01282         /* If all shares are owned by someone (none by nobody), disable buy button */
    01283         this->SetWidgetDisabledState(CW_WIDGET_BUY_SHARE, GetAmountOwnedBy(c, INVALID_OWNER) == 0 ||
    01284             /* Only 25% left to buy. If the company is human, disable buying it up.. TODO issues! */
    01285             (GetAmountOwnedBy(c, INVALID_OWNER) == 1 && !c->is_ai) ||
    01286             /* Spectators cannot do anything of course */
    01287             _local_company == COMPANY_SPECTATOR);
    01288
    01289         /* If the company doesn't own any shares, disable sell button */
    01290         this->SetWidgetDisabledState(CW_WIDGET_SELL_SHARE, (GetAmountOwnedBy(c, _local_company) == 0) ||
    01291             /* Spectators cannot do anything of course */
    01292             _local_company == COMPANY_SPECTATOR);
    01293       } else { // Shares are not allowed, disable buy/sell buttons
    01294         this->DisableWidget(CW_WIDGET_BUY_SHARE);
    01295         this->DisableWidget(CW_WIDGET_SELL_SHARE);
    01296       }
    01297     }
    01298
    01299     SetDParam(0, c->index);
    01300     SetDParam(1, c->index);
    01301
    01302     this->DrawWidgets();
    01303
    01304 #ifdef ENABLE_NETWORK
    01305     if (_networking && NetworkCompanyIsPassworded(c->index)) {
    01306       DrawSprite(SPR_LOCK, PAL_NONE, this->widget[CW_WIDGET_COMPANY_JOIN].left - 10, this->widget[CW_WIDGET_COMPANY_JOIN].top + 2);
    01307     }
    01308 #endif /* ENABLE_NETWORK */
    01309
    01310     /* Company manager's face */
    01311     DrawCompanyManagerFace(c->face, c->colour, 2, 16);
    01312
    01313     /* "xxx (Manager)" */
    01314     SetDParam(0, c->index);
    01315     DrawStringMultiCenter(48, 141, STR_7037_PRESIDENT, MAX_LENGTH_PRESIDENT_NAME_PIXELS);
    01316
    01317     /* "Inaugurated:" */
    01318     SetDParam(0, c->inaugurated_year);
    01319     DrawString(110, 23, STR_7038_INAUGURATED, TC_FROMSTRING);
    01320
    01321     /* "Colour scheme:" */
    01322     DrawString(110, 43, STR_7006_COLOUR_SCHEME, TC_FROMSTRING);
    01323     /* Draw company-colour bus */
    01324     DrawSprite(SPR_VEH_BUS_SW_VIEW, COMPANY_SPRITE_COLOUR(c->index), 215, 44);
    01325
    01326     /* "Vehicles:" */
    01327     DrawCompanyVehiclesAmount((CompanyID)this->window_number);
    01328
    01329     /* "Company value:" */
    01330     SetDParam(0, CalculateCompanyValue(c));
    01331     DrawString(110, 106, STR_7076_COMPANY_VALUE, TC_FROMSTRING);
    01332
    01333     /* Shares list */
    01334     DrawCompanyOwnerText(c);
    01335   }
    01336
    01337   virtual void OnClick(Point pt, int widget)
    01338   {
    01339     switch (widget) {
    01340       case CW_WIDGET_NEW_FACE: DoSelectCompanyManagerFace(this, false); break;
    01341
    01342       case CW_WIDGET_COLOUR_SCHEME:
    01343         if (BringWindowToFrontById(WC_COMPANY_COLOUR, this->window_number)) break;
    01344         new SelectCompanyLiveryWindow(&_select_company_livery_desc, (CompanyID)this->window_number);
    01345         break;
    01346
    01347       case CW_WIDGET_PRESIDENT_NAME:
    01348         this->query_widget = CW_WIDGET_PRESIDENT_NAME;
    01349         SetDParam(0, this->window_number);
    01350         ShowQueryString(STR_PRESIDENT_NAME, STR_700B_PRESIDENT_S_NAME, MAX_LENGTH_PRESIDENT_NAME_BYTES, MAX_LENGTH_PRESIDENT_NAME_PIXELS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT);
    01351         break;
    01352
    01353       case CW_WIDGET_COMPANY_NAME:
    01354         this->query_widget = CW_WIDGET_COMPANY_NAME;
    01355         SetDParam(0, this->window_number);
    01356         ShowQueryString(STR_COMPANY_NAME, STR_700A_COMPANY_NAME, MAX_LENGTH_COMPANY_NAME_BYTES, MAX_LENGTH_COMPANY_NAME_PIXELS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT);
    01357         break;
    01358
    01359       case CW_WIDGET_BUILD_VIEW_HQ: {
    01360         TileIndex tile = GetCompany((CompanyID)this->window_number)->location_of_HQ;
    01361         if (tile == INVALID_TILE) {
    01362           if ((byte)this->window_number != _local_company) return;
    01363           SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, VHM_RECT, this);
    01364           SetTileSelectSize(2, 2);
    01365           this->LowerWidget(CW_WIDGET_BUILD_VIEW_HQ);
    01366           this->InvalidateWidget(CW_WIDGET_BUILD_VIEW_HQ);
    01367         } else {
    01368           if (_ctrl_pressed) {
    01369             ShowExtraViewPortWindow(tile);
    01370           } else {
    01371             ScrollMainWindowToTile(tile);
    01372           }
    01373         }
    01374         break;
    01375       }
    01376
    01377       case CW_WIDGET_RELOCATE_HQ:
    01378         SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, VHM_RECT, this);
    01379         SetTileSelectSize(2, 2);
    01380         this->LowerWidget(CW_WIDGET_RELOCATE_HQ);
    01381         this->InvalidateWidget(CW_WIDGET_RELOCATE_HQ);
    01382         break;
    01383
    01384       case CW_WIDGET_BUY_SHARE:
    01385         DoCommandP(0, this->window_number, 0, CMD_BUY_SHARE_IN_COMPANY | CMD_MSG(STR_707B_CAN_T_BUY_25_SHARE_IN_THIS));
    01386         break;
    01387
    01388       case CW_WIDGET_SELL_SHARE:
    01389         DoCommandP(0, this->window_number, 0, CMD_SELL_SHARE_IN_COMPANY | CMD_MSG(STR_707C_CAN_T_SELL_25_SHARE_IN));
    01390         break;
    01391
    01392 #ifdef ENABLE_NETWORK
    01393       case CW_WIDGET_COMPANY_PASSWORD:
    01394         if (this->window_number == _local_company) ShowNetworkCompanyPasswordWindow(this);
    01395         break;
    01396
    01397       case CW_WIDGET_COMPANY_JOIN: {
    01398         this->query_widget = CW_WIDGET_COMPANY_JOIN;
    01399         CompanyID company = (CompanyID)this->window_number;
    01400         if (_network_server) {
    01401           NetworkServerDoMove(CLIENT_ID_SERVER, company);
    01402           MarkWholeScreenDirty();
    01403         } else if (NetworkCompanyIsPassworded(company)) {
    01404           /* ask for the password */
    01405           ShowQueryString(STR_EMPTY, STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION, 20, 180, this, CS_ALPHANUMERAL, QSF_NONE);
    01406         } else {
    01407           /* just send the join command */
    01408           NetworkClientRequestMove(company);
    01409         }
    01410         break;
    01411       }
    01412 #endif /* ENABLE_NETWORK */
    01413     }
    01414   }
    01415
    01416   virtual void OnHundredthTick()
    01417   {
    01418     /* redraw the window every now and then */
    01419     this->SetDirty();
    01420   }
    01421
    01422   virtual void OnPlaceObject(Point pt, TileIndex tile)
    01423   {
    01424     if (DoCommandP(tile, 0, 0, CMD_BUILD_COMPANY_HQ | CMD_MSG(STR_7071_CAN_T_BUILD_COMPANY_HEADQUARTERS)))
    01425       ResetObjectToPlace();
    01426       this->widget[CW_WIDGET_BUILD_VIEW_HQ].type = WWT_PUSHTXTBTN; // this button can now behave as a normal push button
    01427       this->RaiseButtons();
    01428   }
    01429
    01430   virtual void OnPlaceObjectAbort()
    01431   {
    01432     this->RaiseButtons();
    01433   }
    01434
    01435   virtual void OnQueryTextFinished(char *str)
    01436   {
    01437     if (str == NULL) return;
    01438
    01439     switch (this->query_widget) {
    01440       default: NOT_REACHED();
    01441
    01442       case CW_WIDGET_PRESIDENT_NAME:
    01443         DoCommandP(0, 0, 0, CMD_RENAME_PRESIDENT | CMD_MSG(STR_700D_CAN_T_CHANGE_PRESIDENT), NULL, str);
    01444         break;
    01445
    01446       case CW_WIDGET_COMPANY_NAME:
    01447         DoCommandP(0, 0, 0, CMD_RENAME_COMPANY | CMD_MSG(STR_700C_CAN_T_CHANGE_COMPANY_NAME), NULL, str);
    01448         break;
    01449
    01450 #ifdef ENABLE_NETWORK
    01451       case CW_WIDGET_COMPANY_JOIN:
    01452         NetworkClientRequestMove((CompanyID)this->window_number, str);
    01453         break;
    01454 #endif /* ENABLE_NETWORK */
    01455     }
    01456   }
    01457 };
    01458
    01459 static const WindowDesc _company_desc(
    01460   WDP_AUTO, WDP_AUTO, 360, 170, 360, 170,
    01461   WC_COMPANY, WC_NONE,
    01462   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
    01463   _company_widgets
    01464 );
    01465
    01466 void ShowCompany(CompanyID company)
    01467 {
    01468   if (!IsValidCompanyID(company)) return;
    01469
    01470   AllocateWindowDescFront<CompanyWindow>(&_company_desc, company);
    01471 }
    01472
    01473
    01474
    01475 struct BuyCompanyWindow : Window {
    01476   BuyCompanyWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
    01477   {
    01478     this->FindWindowPlacementAndResize(desc);
    01479   }
    01480
    01481   virtual void OnPaint()
    01482   {
    01483     Company *c = GetCompany((CompanyID)this->window_number);
    01484     SetDParam(0, STR_COMPANY_NAME);
    01485     SetDParam(1, c->index);
    01486     this->DrawWidgets();
    01487
    01488     DrawCompanyManagerFace(c->face, c->colour, 2, 16);
    01489
    01490     SetDParam(0, c->index);
    01491     SetDParam(1, c->bankrupt_value);
    01492     DrawStringMultiCenter(214, 65, STR_705B_WE_ARE_LOOKING_FOR_A_TRANSPORT, 238);
    01493   }
    01494
    01495   virtual void OnClick(Point pt, int widget)
    01496   {
    01497     switch (widget) {
    01498       case 3:
    01499         delete this;
    01500         break;
    01501
    01502       case 4:
    01503         DoCommandP(0, this->window_number, 0, CMD_BUY_COMPANY | CMD_MSG(STR_7060_CAN_T_BUY_COMPANY));
    01504         break;
    01505     }
    01506   }
    01507 };
    01508
    01509 static const Widget _buy_company_widgets[] = {
    01510 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_LIGHT_BLUE,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},
    01511 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_LIGHT_BLUE,    11,   333,     0,    13, STR_00B3_MESSAGE_FROM, STR_018C_WINDOW_TITLE_DRAG_THIS},
    01512 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_LIGHT_BLUE,     0,   333,    14,   136, 0x0,                   STR_NULL},
    01513 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_LIGHT_BLUE,   148,   207,   117,   128, STR_00C9_NO,           STR_NULL},
    01514 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_LIGHT_BLUE,   218,   277,   117,   128, STR_00C8_YES,          STR_NULL},
    01515 {   WIDGETS_END},
    01516 };
    01517
    01518 static const WindowDesc _buy_company_desc(
    01519   153, 171, 334, 137, 334, 137,
    01520   WC_BUY_COMPANY, WC_NONE,
    01521   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_CONSTRUCTION,
    01522   _buy_company_widgets
    01523 );
    01524
    01525
    01526 void ShowBuyCompanyDialog(CompanyID company)
    01527 {
    01528   AllocateWindowDescFront<BuyCompanyWindow>(&_buy_company_desc, company);
    01529 }