# company_gui.cpp

Go to the documentation of this file.

    00001 /* $Id: company_gui.cpp 16830 2009-07-14 20:38:45Z 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();
    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     int r = this->widget[_loaded_newgrf_features.has_2CC ? SCLW_WIDGET_SEC_COL_DROPDOWN : SCLW_WIDGET_PRI_COL_DROPDOWN].right;
    00599     this->SetWidgetHiddenState(SCLW_WIDGET_SEC_COL_DROPDOWN, !_loaded_newgrf_features.has_2CC);
    00600     this->widget[SCLW_WIDGET_CAPTION].right = r;
    00601     this->widget[SCLW_WIDGET_SPACER_CLASS].right = r;
    00602     this->widget[SCLW_WIDGET_MATRIX].right = r;
    00603     this->width = r + 1;
    00604   }
    00605 };
    00606
    00607 static const Widget _select_company_livery_widgets[] = {
    00608 { WWT_CLOSEBOX, RESIZE_NONE,  COLOUR_GREY,   0,  10,   0,  13, STR_00C5,                   STR_018B_CLOSE_WINDOW },
    00609 {  WWT_CAPTION, RESIZE_NONE,  COLOUR_GREY,  11, 399,   0,  13, STR_7007_NEW_COLOUR_SCHEME, STR_018C_WINDOW_TITLE_DRAG_THIS },
    00610 {   WWT_IMGBTN, RESIZE_NONE,  COLOUR_GREY,   0,  21,  14,  35, SPR_IMG_COMPANY_GENERAL,    STR_LIVERY_GENERAL_TIP },
    00611 {   WWT_IMGBTN, RESIZE_NONE,  COLOUR_GREY,  22,  43,  14,  35, SPR_IMG_TRAINLIST,          STR_LIVERY_TRAIN_TIP },
    00612 {   WWT_IMGBTN, RESIZE_NONE,  COLOUR_GREY,  44,  65,  14,  35, SPR_IMG_TRUCKLIST,          STR_LIVERY_ROADVEH_TIP },
    00613 {   WWT_IMGBTN, RESIZE_NONE,  COLOUR_GREY,  66,  87,  14,  35, SPR_IMG_SHIPLIST,           STR_LIVERY_SHIP_TIP },
    00614 {   WWT_IMGBTN, RESIZE_NONE,  COLOUR_GREY,  88, 109,  14,  35, SPR_IMG_AIRPLANESLIST,      STR_LIVERY_AIRCRAFT_TIP },
    00615 {    WWT_PANEL, RESIZE_NONE,  COLOUR_GREY, 110, 399,  14,  35, 0x0,                        STR_NULL },
    00616 {    WWT_PANEL, RESIZE_NONE,  COLOUR_GREY,   0, 149,  36,  47, 0x0,                        STR_NULL },
    00617 { WWT_DROPDOWN, RESIZE_NONE,  COLOUR_GREY, 150, 274,  36,  47, STR_02BD,                   STR_LIVERY_PRIMARY_TIP },
    00618 { WWT_DROPDOWN, RESIZE_NONE,  COLOUR_GREY, 275, 399,  36,  47, STR_02E1,                   STR_LIVERY_SECONDARY_TIP },
    00619 {   WWT_MATRIX, RESIZE_NONE,  COLOUR_GREY,   0, 399,  48,  48 + 1 * 14, (1 << 8) | 1,      STR_LIVERY_PANEL_TIP },
    00620 { WIDGETS_END },
    00621 };
    00622
    00623 static const WindowDesc _select_company_livery_desc(
    00624   WDP_AUTO, WDP_AUTO, 400, 49 + 1 * 14, 400, 49 + 1 * 14,
    00625   WC_COMPANY_COLOUR, WC_NONE,
    00626   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
    00627   _select_company_livery_widgets
    00628 );
    00629
    00637 void DrawCompanyManagerFace(CompanyManagerFace cmf, int colour, int x, int y)
    00638 {
    00639   GenderEthnicity ge = (GenderEthnicity)GetCompanyManagerFaceBits(cmf, CMFV_GEN_ETHN, GE_WM);
    00640
    00641   bool has_moustache   = !HasBit(ge, GENDER_FEMALE) && GetCompanyManagerFaceBits(cmf, CMFV_HAS_MOUSTACHE,   ge) != 0;
    00642   bool has_tie_earring = !HasBit(ge, GENDER_FEMALE) || GetCompanyManagerFaceBits(cmf, CMFV_HAS_TIE_EARRING, ge) != 0;
    00643   bool has_glasses     = GetCompanyManagerFaceBits(cmf, CMFV_HAS_GLASSES, ge) != 0;
    00644   SpriteID pal;
    00645
    00646   /* Modify eye colour palette only if 2 or more valid values exist */
    00647   if (_cmf_info[CMFV_EYE_COLOUR].valid_values[ge] < 2) {
    00648     pal = PAL_NONE;
    00649   } else {
    00650     switch (GetCompanyManagerFaceBits(cmf, CMFV_EYE_COLOUR, ge)) {
    00651       default: NOT_REACHED();
    00652       case 0: pal = PALETTE_TO_BROWN; break;
    00653       case 1: pal = PALETTE_TO_BLUE;  break;
    00654       case 2: pal = PALETTE_TO_GREEN; break;
    00655     }
    00656   }
    00657
    00658   /* Draw the gradient (background) */
    00659   DrawSprite(SPR_GRADIENT, GENERAL_SPRITE_COLOUR(colour), x, y);
    00660
    00661   for (CompanyManagerFaceVariable cmfv = CMFV_CHEEKS; cmfv < CMFV_END; cmfv++) {
    00662     switch (cmfv) {
    00663       case CMFV_MOUSTACHE:   if (!has_moustache)   continue; break;
    00664       case CMFV_LIPS:        // FALL THROUGH
    00665       case CMFV_NOSE:        if (has_moustache)    continue; break;
    00666       case CMFV_TIE_EARRING: if (!has_tie_earring) continue; break;
    00667       case CMFV_GLASSES:     if (!has_glasses)     continue; break;
    00668       default: break;
    00669     }
    00670     DrawSprite(GetCompanyManagerFaceSprite(cmf, cmfv, ge), (cmfv == CMFV_EYEBROWS) ? pal : PAL_NONE, x, y);
    00671   }
    00672 }
    00673
    00675 static const Widget _select_company_manager_face_widgets[] = {
    00676 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_GREY,     0,    10,     0,    13, STR_00C5,                STR_018B_CLOSE_WINDOW},              // SCMFW_WIDGET_CLOSEBOX
    00677 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_GREY,    11,   174,     0,    13, STR_7043_FACE_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS},    // SCMFW_WIDGET_CAPTION
    00678 {     WWT_IMGBTN,   RESIZE_NONE,  COLOUR_GREY,   175,   189,     0,    13, SPR_LARGE_SMALL_WINDOW,  STR_FACE_ADVANCED_TIP},              // SCMFW_WIDGET_TOGGLE_LARGE_SMALL
    00679 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   189,    14,   150, 0x0,                     STR_NULL},                           // SCMFW_WIDGET_SELECT_FACE
    00680 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     0,    94,   151,   162, STR_012E_CANCEL,         STR_7047_CANCEL_NEW_FACE_SELECTION}, // SCMFW_WIDGET_CANCEL
    00681 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    95,   189,   151,   162, STR_012F_OK,             STR_7048_ACCEPT_NEW_FACE_SELECTION}, // SCMFW_WIDGET_ACCEPT
    00682 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_GREY,    95,   187,    75,    86, STR_7044_MALE,           STR_7049_SELECT_MALE_FACES},         // SCMFW_WIDGET_MALE
    00683 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_GREY,    95,   187,    87,    98, STR_7045_FEMALE,         STR_704A_SELECT_FEMALE_FACES},       // SCMFW_WIDGET_FEMALE
    00684 { 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
    00685 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    95,   187,    16,    27, STR_FACE_ADVANCED,       STR_FACE_ADVANCED_TIP},              // SCMFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON
    00686 {   WIDGETS_END},
    00687 };
    00688
    00690 static const Widget _select_company_manager_face_adv_widgets[] = {
    00691 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_GREY,     0,    10,     0,    13, STR_00C5,                STR_018B_CLOSE_WINDOW},              // SCMFW_WIDGET_CLOSEBOX
    00692 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_GREY,    11,   204,     0,    13, STR_7043_FACE_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS},    // SCMFW_WIDGET_CAPTION
    00693 {     WWT_IMGBTN,   RESIZE_NONE,  COLOUR_GREY,   205,   219,     0,    13, SPR_LARGE_SMALL_WINDOW,  STR_FACE_SIMPLE_TIP},                // SCMFW_WIDGET_TOGGLE_LARGE_SMALL
    00694 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   219,    14,   207, 0x0,                     STR_NULL},                           // SCMFW_WIDGET_SELECT_FACE
    00695 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     0,    94,   208,   219, STR_012E_CANCEL,         STR_7047_CANCEL_NEW_FACE_SELECTION}, // SCMFW_WIDGET_CANCEL
    00696 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    95,   219,   208,   219, STR_012F_OK,             STR_7048_ACCEPT_NEW_FACE_SELECTION}, // SCMFW_WIDGET_ACCEPT
    00697 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_GREY,    96,   156,    32,    43, STR_7044_MALE,           STR_7049_SELECT_MALE_FACES},         // SCMFW_WIDGET_MALE
    00698 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_GREY,   157,   217,    32,    43, STR_7045_FEMALE,         STR_704A_SELECT_FEMALE_FACES},       // SCMFW_WIDGET_FEMALE
    00699 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     2,    93,   137,   148, STR_RANDOM,              STR_704B_GENERATE_RANDOM_NEW_FACE},  // SCMFW_WIDGET_RANDOM_NEW_FACE
    00700 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    95,   217,    16,    27, STR_FACE_SIMPLE,         STR_FACE_SIMPLE_TIP},                // SCMFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON
    00701 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     2,    93,   158,   169, STR_FACE_LOAD,           STR_FACE_LOAD_TIP},                  // SCMFW_WIDGET_LOAD
    00702 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     2,    93,   170,   181, STR_FACE_FACECODE,       STR_FACE_FACECODE_TIP},              // SCMFW_WIDGET_FACECODE
    00703 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     2,    93,   182,   193, STR_FACE_SAVE,           STR_FACE_SAVE_TIP},                  // SCMFW_WIDGET_SAVE
    00704 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_GREY,    96,   156,    46,    57, STR_FACE_EUROPEAN,       STR_FACE_SELECT_EUROPEAN},           // SCMFW_WIDGET_ETHNICITY_EUR
    00705 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_GREY,   157,   217,    46,    57, STR_FACE_AFRICAN,        STR_FACE_SELECT_AFRICAN},            // SCMFW_WIDGET_ETHNICITY_AFR
    00706 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   175,   217,    60,    71, STR_EMPTY,               STR_FACE_MOUSTACHE_EARRING_TIP},     // SCMFW_WIDGET_HAS_MOUSTACHE_EARRING
    00707 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   175,   217,    72,    83, STR_EMPTY,               STR_FACE_GLASSES_TIP},               // SCMFW_WIDGET_HAS_GLASSES
    00708 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,   110,   121, SPR_ARROW_LEFT,          STR_FACE_EYECOLOUR_TIP},             // SCMFW_WIDGET_EYECOLOUR_L
    00709 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,   110,   121, STR_EMPTY,               STR_FACE_EYECOLOUR_TIP},             // SCMFW_WIDGET_EYECOLOUR
    00710 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,   110,   121, SPR_ARROW_RIGHT,         STR_FACE_EYECOLOUR_TIP},             // SCMFW_WIDGET_EYECOLOUR_R
    00711 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,   158,   169, SPR_ARROW_LEFT,          STR_FACE_CHIN_TIP},                  // SCMFW_WIDGET_CHIN_L
    00712 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,   158,   169, STR_EMPTY,               STR_FACE_CHIN_TIP},                  // SCMFW_WIDGET_CHIN
    00713 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,   158,   169, SPR_ARROW_RIGHT,         STR_FACE_CHIN_TIP},                  // SCMFW_WIDGET_CHIN_R
    00714 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,    98,   109, SPR_ARROW_LEFT,          STR_FACE_EYEBROWS_TIP},              // SCMFW_WIDGET_EYEBROWS_L
    00715 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,    98,   109, STR_EMPTY,               STR_FACE_EYEBROWS_TIP},              // SCMFW_WIDGET_EYEBROWS
    00716 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,    98,   109, SPR_ARROW_RIGHT,         STR_FACE_EYEBROWS_TIP},              // SCMFW_WIDGET_EYEBROWS_R
    00717 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,   146,   157, SPR_ARROW_LEFT,          STR_FACE_LIPS_MOUSTACHE_TIP},        // SCMFW_WIDGET_LIPS_MOUSTACHE_L
    00718 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,   146,   157, STR_EMPTY,               STR_FACE_LIPS_MOUSTACHE_TIP},        // SCMFW_WIDGET_LIPS_MOUSTACHE
    00719 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,   146,   157, SPR_ARROW_RIGHT,         STR_FACE_LIPS_MOUSTACHE_TIP},        // SCMFW_WIDGET_LIPS_MOUSTACHE_R
    00720 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,   134,   145, SPR_ARROW_LEFT,          STR_FACE_NOSE_TIP},                  // SCMFW_WIDGET_NOSE_L
    00721 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,   134,   145, STR_EMPTY,               STR_FACE_NOSE_TIP},                  // SCMFW_WIDGET_NOSE
    00722 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,   134,   145, SPR_ARROW_RIGHT,         STR_FACE_NOSE_TIP},                  // SCMFW_WIDGET_NOSE_R
    00723 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,    86,    97, SPR_ARROW_LEFT,          STR_FACE_HAIR_TIP},                  // SCMFW_WIDGET_HAIR_L
    00724 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,    86,    97, STR_EMPTY,               STR_FACE_HAIR_TIP},                  // SCMFW_WIDGET_HAIR
    00725 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,    86,    97, SPR_ARROW_RIGHT,         STR_FACE_HAIR_TIP},                  // SCMFW_WIDGET_HAIR_R
    00726 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,   170,   181, SPR_ARROW_LEFT,          STR_FACE_JACKET_TIP},                // SCMFW_WIDGET_JACKET_L
    00727 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,   170,   181, STR_EMPTY,               STR_FACE_JACKET_TIP},                // SCMFW_WIDGET_JACKET
    00728 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,   170,   181, SPR_ARROW_RIGHT,         STR_FACE_JACKET_TIP},                // SCMFW_WIDGET_JACKET_R
    00729 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,   182,   193, SPR_ARROW_LEFT,          STR_FACE_COLLAR_TIP},                // SCMFW_WIDGET_COLLAR_L
    00730 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,   182,   193, STR_EMPTY,               STR_FACE_COLLAR_TIP},                // SCMFW_WIDGET_COLLAR
    00731 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,   182,   193, SPR_ARROW_RIGHT,         STR_FACE_COLLAR_TIP},                // SCMFW_WIDGET_COLLAR_R
    00732 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,   194,   205, SPR_ARROW_LEFT,          STR_FACE_TIE_EARRING_TIP},           // SCMFW_WIDGET_TIE_EARRING_L
    00733 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,   194,   205, STR_EMPTY,               STR_FACE_TIE_EARRING_TIP},           // SCMFW_WIDGET_TIE_EARRING
    00734 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,   194,   205, SPR_ARROW_RIGHT,         STR_FACE_TIE_EARRING_TIP},           // SCMFW_WIDGET_TIE_EARRING_R
    00735 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,   122,   133, SPR_ARROW_LEFT,          STR_FACE_GLASSES_TIP_2},             // SCMFW_WIDGET_GLASSES_L
    00736 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,   122,   133, STR_EMPTY,               STR_FACE_GLASSES_TIP_2},             // SCMFW_WIDGET_GLASSES
    00737 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,   122,   133, SPR_ARROW_RIGHT,         STR_FACE_GLASSES_TIP_2},             // SCMFW_WIDGET_GLASSES_R
    00738 {   WIDGETS_END},
    00739 };
    00740
    00741 class SelectCompanyManagerFaceWindow : public Window
    00742 {
    00743   CompanyManagerFace face;
    00744   bool advanced;
    00745
    00746   GenderEthnicity ge;
    00747   bool is_female;
    00748   bool is_moust_male;
    00749
    00755   enum SelectCompanyManagerFaceWidgets {
    00756     SCMFW_WIDGET_CLOSEBOX = 0,
    00757     SCMFW_WIDGET_CAPTION,
    00758     SCMFW_WIDGET_TOGGLE_LARGE_SMALL,
    00759     SCMFW_WIDGET_SELECT_FACE,
    00760     SCMFW_WIDGET_CANCEL,
    00761     SCMFW_WIDGET_ACCEPT,
    00762     SCMFW_WIDGET_MALE,
    00763     SCMFW_WIDGET_FEMALE,
    00764     SCMFW_WIDGET_RANDOM_NEW_FACE,
    00765     SCMFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON,
    00766     /* from here is the advanced company manager face selection window */
    00767     SCMFW_WIDGET_LOAD,
    00768     SCMFW_WIDGET_FACECODE,
    00769     SCMFW_WIDGET_SAVE,
    00770     SCMFW_WIDGET_ETHNICITY_EUR,
    00771     SCMFW_WIDGET_ETHNICITY_AFR,
    00772     SCMFW_WIDGET_HAS_MOUSTACHE_EARRING,
    00773     SCMFW_WIDGET_HAS_GLASSES,
    00774     SCMFW_WIDGET_EYECOLOUR_L,
    00775     SCMFW_WIDGET_EYECOLOUR,
    00776     SCMFW_WIDGET_EYECOLOUR_R,
    00777     SCMFW_WIDGET_CHIN_L,
    00778     SCMFW_WIDGET_CHIN,
    00779     SCMFW_WIDGET_CHIN_R,
    00780     SCMFW_WIDGET_EYEBROWS_L,
    00781     SCMFW_WIDGET_EYEBROWS,
    00782     SCMFW_WIDGET_EYEBROWS_R,
    00783     SCMFW_WIDGET_LIPS_MOUSTACHE_L,
    00784     SCMFW_WIDGET_LIPS_MOUSTACHE,
    00785     SCMFW_WIDGET_LIPS_MOUSTACHE_R,
    00786     SCMFW_WIDGET_NOSE_L,
    00787     SCMFW_WIDGET_NOSE,
    00788     SCMFW_WIDGET_NOSE_R,
    00789     SCMFW_WIDGET_HAIR_L,
    00790     SCMFW_WIDGET_HAIR,
    00791     SCMFW_WIDGET_HAIR_R,
    00792     SCMFW_WIDGET_JACKET_L,
    00793     SCMFW_WIDGET_JACKET,
    00794     SCMFW_WIDGET_JACKET_R,
    00795     SCMFW_WIDGET_COLLAR_L,
    00796     SCMFW_WIDGET_COLLAR,
    00797     SCMFW_WIDGET_COLLAR_R,
    00798     SCMFW_WIDGET_TIE_EARRING_L,
    00799     SCMFW_WIDGET_TIE_EARRING,
    00800     SCMFW_WIDGET_TIE_EARRING_R,
    00801     SCMFW_WIDGET_GLASSES_L,
    00802     SCMFW_WIDGET_GLASSES,
    00803     SCMFW_WIDGET_GLASSES_R,
    00804   };
    00813   void DrawFaceStringLabel(byte widget_index, StringID str, uint8 val, bool is_bool_widget)
    00814   {
    00815     /* Write the label in gold (0x2) to the left of the button. */
    00816     DrawStringRightAligned(this->widget[widget_index].left - (is_bool_widget ? 5 : 14), this->widget[widget_index].top + 1, str, TC_GOLD);
    00817
    00818     if (!this->IsWidgetDisabled(widget_index)) {
    00819       if (is_bool_widget) {
    00820         /* if it a bool button write yes or no */
    00821         str = (val != 0) ? STR_FACE_YES : STR_FACE_NO;
    00822       } else {
    00823         /* else write the value + 1 */
    00824         SetDParam(0, val + 1);
    00825         str = STR_JUST_INT;
    00826       }
    00827
    00828       /* Draw the value/bool in white (0xC). If the button clicked adds 1px to x and y text coordinates (IsWindowWidgetLowered()). */
    00829       DrawStringCentered(this->widget[widget_index].left + (this->widget[widget_index].right - this->widget[widget_index].left) / 2 +
    00830         this->IsWidgetLowered(widget_index), this->widget[widget_index].top + 1 + this->IsWidgetLowered(widget_index), str, TC_WHITE);
    00831     }
    00832   }
    00833
    00834   void UpdateData()
    00835   {
    00836     this->ge = (GenderEthnicity)GB(this->face, _cmf_info[CMFV_GEN_ETHN].offset, _cmf_info[CMFV_GEN_ETHN].length); // get the gender and ethnicity
    00837     this->is_female = HasBit(this->ge, GENDER_FEMALE); // get the gender: 0 == male and 1 == female
    00838     this->is_moust_male = !is_female && GetCompanyManagerFaceBits(this->face, CMFV_HAS_MOUSTACHE, this->ge) != 0; // is a male face with moustache
    00839   }
    00840
    00841 public:
    00842   SelectCompanyManagerFaceWindow(const WindowDesc *desc, Window *parent, bool advanced, int top, int left) : Window(desc, parent->window_number)
    00843   {
    00844     this->parent = parent;
    00845     this->owner = (Owner)this->window_number;
    00846     this->face = GetCompany((CompanyID)this->window_number)->face;
    00847     this->advanced = advanced;
    00848
    00849     this->UpdateData();
    00850
    00851     /* Check if repositioning from default is required */
    00852     if (top != FIRST_GUI_CALL && left != FIRST_GUI_CALL) {
    00853       this->top = top;
    00854       this->left = left;
    00855     }
    00856
    00857     this->FindWindowPlacementAndResize(desc);
    00858   }
    00859
    00860   virtual void OnPaint()
    00861   {
    00862     /* lower the non-selected gender button */
    00863     this->SetWidgetLoweredState(SCMFW_WIDGET_MALE,  !this->is_female);
    00864     this->SetWidgetLoweredState(SCMFW_WIDGET_FEMALE, this->is_female);
    00865
    00866     /* advanced company manager face selection window */
    00867     if (this->advanced) {
    00868       /* lower the non-selected ethnicity button */
    00869       this->SetWidgetLoweredState(SCMFW_WIDGET_ETHNICITY_EUR, !HasBit(this->ge, ETHNICITY_BLACK));
    00870       this->SetWidgetLoweredState(SCMFW_WIDGET_ETHNICITY_AFR,  HasBit(this->ge, ETHNICITY_BLACK));
    00871
    00872
    00873       /* Disable dynamically the widgets which CompanyManagerFaceVariable has less than 2 options
    00874        * (or in other words you haven't any choice).
    00875        * If the widgets depend on a HAS-variable and this is false the widgets will be disabled, too. */
    00876
    00877       /* Eye colour buttons */
    00878       this->SetWidgetsDisabledState(_cmf_info[CMFV_EYE_COLOUR].valid_values[this->ge] < 2,
    00879         SCMFW_WIDGET_EYECOLOUR, SCMFW_WIDGET_EYECOLOUR_L, SCMFW_WIDGET_EYECOLOUR_R, WIDGET_LIST_END);
    00880
    00881       /* Chin buttons */
    00882       this->SetWidgetsDisabledState(_cmf_info[CMFV_CHIN].valid_values[this->ge] < 2,
    00883         SCMFW_WIDGET_CHIN, SCMFW_WIDGET_CHIN_L, SCMFW_WIDGET_CHIN_R, WIDGET_LIST_END);
    00884
    00885       /* Eyebrows buttons */
    00886       this->SetWidgetsDisabledState(_cmf_info[CMFV_EYEBROWS].valid_values[this->ge] < 2,
    00887         SCMFW_WIDGET_EYEBROWS, SCMFW_WIDGET_EYEBROWS_L, SCMFW_WIDGET_EYEBROWS_R, WIDGET_LIST_END);
    00888
    00889       /* Lips or (if it a male face with a moustache) moustache buttons */
    00890       this->SetWidgetsDisabledState(_cmf_info[this->is_moust_male ? CMFV_MOUSTACHE : CMFV_LIPS].valid_values[this->ge] < 2,
    00891         SCMFW_WIDGET_LIPS_MOUSTACHE, SCMFW_WIDGET_LIPS_MOUSTACHE_L, SCMFW_WIDGET_LIPS_MOUSTACHE_R, WIDGET_LIST_END);
    00892
    00893       /* Nose buttons | male faces with moustache haven't any nose options */
    00894       this->SetWidgetsDisabledState(_cmf_info[CMFV_NOSE].valid_values[this->ge] < 2 || this->is_moust_male,
    00895         SCMFW_WIDGET_NOSE, SCMFW_WIDGET_NOSE_L, SCMFW_WIDGET_NOSE_R, WIDGET_LIST_END);
    00896
    00897       /* Hair buttons */
    00898       this->SetWidgetsDisabledState(_cmf_info[CMFV_HAIR].valid_values[this->ge] < 2,
    00899         SCMFW_WIDGET_HAIR, SCMFW_WIDGET_HAIR_L, SCMFW_WIDGET_HAIR_R, WIDGET_LIST_END);
    00900
    00901       /* Jacket buttons */
    00902       this->SetWidgetsDisabledState(_cmf_info[CMFV_JACKET].valid_values[this->ge] < 2,
    00903         SCMFW_WIDGET_JACKET, SCMFW_WIDGET_JACKET_L, SCMFW_WIDGET_JACKET_R, WIDGET_LIST_END);
    00904
    00905       /* Collar buttons */
    00906       this->SetWidgetsDisabledState(_cmf_info[CMFV_COLLAR].valid_values[this->ge] < 2,
    00907         SCMFW_WIDGET_COLLAR, SCMFW_WIDGET_COLLAR_L, SCMFW_WIDGET_COLLAR_R, WIDGET_LIST_END);
    00908
    00909       /* Tie/earring buttons | female faces without earring haven't any earring options */
    00910       this->SetWidgetsDisabledState(_cmf_info[CMFV_TIE_EARRING].valid_values[this->ge] < 2 ||
    00911           (this->is_female && GetCompanyManagerFaceBits(this->face, CMFV_HAS_TIE_EARRING, this->ge) == 0),
    00912         SCMFW_WIDGET_TIE_EARRING, SCMFW_WIDGET_TIE_EARRING_L, SCMFW_WIDGET_TIE_EARRING_R, WIDGET_LIST_END);
    00913
    00914       /* Glasses buttons | faces without glasses haven't any glasses options */
    00915       this->SetWidgetsDisabledState(_cmf_info[CMFV_GLASSES].valid_values[this->ge] < 2 || GetCompanyManagerFaceBits(this->face, CMFV_HAS_GLASSES, this->ge) == 0,
    00916         SCMFW_WIDGET_GLASSES, SCMFW_WIDGET_GLASSES_L, SCMFW_WIDGET_GLASSES_R, WIDGET_LIST_END);
    00917     }
    00918
    00919     this->DrawWidgets();
    00920
    00921     /* Draw dynamic button value and labels for the advanced company manager face selection window */
    00922     if (this->advanced) {
    00923       if (this->is_female) {
    00924         /* Only for female faces */
    00925         this->DrawFaceStringLabel(SCMFW_WIDGET_HAS_MOUSTACHE_EARRING, STR_FACE_EARRING,   GetCompanyManagerFaceBits(this->face, CMFV_HAS_TIE_EARRING, this->ge), true );
    00926         this->DrawFaceStringLabel(SCMFW_WIDGET_TIE_EARRING,           STR_FACE_EARRING,   GetCompanyManagerFaceBits(this->face, CMFV_TIE_EARRING,     this->ge), false);
    00927       } else {
    00928         /* Only for male faces */
    00929         this->DrawFaceStringLabel(SCMFW_WIDGET_HAS_MOUSTACHE_EARRING, STR_FACE_MOUSTACHE, GetCompanyManagerFaceBits(this->face, CMFV_HAS_MOUSTACHE,   this->ge), true );
    00930         this->DrawFaceStringLabel(SCMFW_WIDGET_TIE_EARRING,           STR_FACE_TIE,       GetCompanyManagerFaceBits(this->face, CMFV_TIE_EARRING,     this->ge), false);
    00931       }
    00932       if (this->is_moust_male) {
    00933         /* Only for male faces with moustache */
    00934         this->DrawFaceStringLabel(SCMFW_WIDGET_LIPS_MOUSTACHE,        STR_FACE_MOUSTACHE, GetCompanyManagerFaceBits(this->face, CMFV_MOUSTACHE,       this->ge), false);
    00935       } else {
    00936         /* Only for female faces or male faces without moustache */
    00937         this->DrawFaceStringLabel(SCMFW_WIDGET_LIPS_MOUSTACHE,        STR_FACE_LIPS,      GetCompanyManagerFaceBits(this->face, CMFV_LIPS,            this->ge), false);
    00938       }
    00939       /* For all faces */
    00940       this->DrawFaceStringLabel(SCMFW_WIDGET_HAS_GLASSES,           STR_FACE_GLASSES,     GetCompanyManagerFaceBits(this->face, CMFV_HAS_GLASSES,     this->ge), true );
    00941       this->DrawFaceStringLabel(SCMFW_WIDGET_HAIR,                  STR_FACE_HAIR,        GetCompanyManagerFaceBits(this->face, CMFV_HAIR,            this->ge), false);
    00942       this->DrawFaceStringLabel(SCMFW_WIDGET_EYEBROWS,              STR_FACE_EYEBROWS,    GetCompanyManagerFaceBits(this->face, CMFV_EYEBROWS,        this->ge), false);
    00943       this->DrawFaceStringLabel(SCMFW_WIDGET_EYECOLOUR,             STR_FACE_EYECOLOUR,   GetCompanyManagerFaceBits(this->face, CMFV_EYE_COLOUR,      this->ge), false);
    00944       this->DrawFaceStringLabel(SCMFW_WIDGET_GLASSES,               STR_FACE_GLASSES,     GetCompanyManagerFaceBits(this->face, CMFV_GLASSES,         this->ge), false);
    00945       this->DrawFaceStringLabel(SCMFW_WIDGET_NOSE,                  STR_FACE_NOSE,        GetCompanyManagerFaceBits(this->face, CMFV_NOSE,            this->ge), false);
    00946       this->DrawFaceStringLabel(SCMFW_WIDGET_CHIN,                  STR_FACE_CHIN,        GetCompanyManagerFaceBits(this->face, CMFV_CHIN,            this->ge), false);
    00947       this->DrawFaceStringLabel(SCMFW_WIDGET_JACKET,                STR_FACE_JACKET,      GetCompanyManagerFaceBits(this->face, CMFV_JACKET,          this->ge), false);
    00948       this->DrawFaceStringLabel(SCMFW_WIDGET_COLLAR,                STR_FACE_COLLAR,      GetCompanyManagerFaceBits(this->face, CMFV_COLLAR,          this->ge), false);
    00949     }
    00950
    00951     /* Draw the company manager face picture */
    00952     DrawCompanyManagerFace(this->face, GetCompany((CompanyID)this->window_number)->colour, 2, 16);
    00953   }
    00954
    00955   virtual void OnClick(Point pt, int widget)
    00956   {
    00957     switch (widget) {
    00958       /* Toggle size, advanced/simple face selection */
    00959       case SCMFW_WIDGET_TOGGLE_LARGE_SMALL:
    00960       case SCMFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON: {
    00961         DoCommandP(0, 0, this->face, CMD_SET_COMPANY_MANAGER_FACE);
    00962
    00963         /* Backup some data before deletion */
    00964         int oldtop = this->top;
    00965         int oldleft = this->left;
    00966         bool adv = !this->advanced;
    00967         Window *parent = this->parent;
    00968
    00969         delete this;
    00970
    00971         /* Open up the (toggled size) Face selection window at the same position as the previous */
    00972         DoSelectCompanyManagerFace(parent, adv, oldtop, oldleft);
    00973       } break;
    00974
    00975
    00976       /* OK button */
    00977       case SCMFW_WIDGET_ACCEPT:
    00978         DoCommandP(0, 0, this->face, CMD_SET_COMPANY_MANAGER_FACE);
    00979         /* Fall-Through */
    00980
    00981       /* Cancel button */
    00982       case SCMFW_WIDGET_CANCEL:
    00983         delete this;
    00984         break;
    00985
    00986       /* Load button */
    00987       case SCMFW_WIDGET_LOAD:
    00988         this->face = _company_manager_face;
    00989         ScaleAllCompanyManagerFaceBits(this->face);
    00990         ShowErrorMessage(INVALID_STRING_ID, STR_FACE_LOAD_DONE, 0, 0);
    00991         this->UpdateData();
    00992         this->SetDirty();
    00993         break;
    00994
    00995       /* 'Company manager face number' button, view and/or set company manager face number */
    00996       case SCMFW_WIDGET_FACECODE:
    00997         SetDParam(0, this->face);
    00998         ShowQueryString(STR_JUST_INT, STR_FACE_FACECODE_CAPTION, 10 + 1, 0, this, CS_NUMERAL, QSF_NONE);
    00999         break;
    01000
    01001       /* Save button */
    01002       case SCMFW_WIDGET_SAVE:
    01003         _company_manager_face = this->face;
    01004         ShowErrorMessage(INVALID_STRING_ID, STR_FACE_SAVE_DONE, 0, 0);
    01005         break;
    01006
    01007       /* Toggle gender (male/female) button */
    01008       case SCMFW_WIDGET_MALE:
    01009       case SCMFW_WIDGET_FEMALE:
    01010         SetCompanyManagerFaceBits(this->face, CMFV_GENDER, this->ge, widget - SCMFW_WIDGET_MALE);
    01011         ScaleAllCompanyManagerFaceBits(this->face);
    01012         this->UpdateData();
    01013         this->SetDirty();
    01014         break;
    01015
    01016       /* Randomize face button */
    01017       case SCMFW_WIDGET_RANDOM_NEW_FACE:
    01018         RandomCompanyManagerFaceBits(this->face, this->ge, this->advanced);
    01019         this->UpdateData();
    01020         this->SetDirty();
    01021         break;
    01022
    01023       /* Toggle ethnicity (european/african) button */
    01024       case SCMFW_WIDGET_ETHNICITY_EUR:
    01025       case SCMFW_WIDGET_ETHNICITY_AFR:
    01026         SetCompanyManagerFaceBits(this->face, CMFV_ETHNICITY, this->ge, widget - SCMFW_WIDGET_ETHNICITY_EUR);
    01027         ScaleAllCompanyManagerFaceBits(this->face);
    01028         this->UpdateData();
    01029         this->SetDirty();
    01030         break;
    01031
    01032       default:
    01033         /* For all buttons from SCMFW_WIDGET_HAS_MOUSTACHE_EARRING to SCMFW_WIDGET_GLASSES_R is the same function.
    01034          * Therefor is this combined function.
    01035          * First it checks which CompanyManagerFaceVariable will be change and then
    01036          * a: invert the value for boolean variables
    01037          * or b: it checks inside of IncreaseCompanyManagerFaceBits() if a left (_L) butten is pressed and then decrease else increase the variable */
    01038         if (this->advanced && widget >= SCMFW_WIDGET_HAS_MOUSTACHE_EARRING && widget <= SCMFW_WIDGET_GLASSES_R) {
    01039           CompanyManagerFaceVariable cmfv; // which CompanyManagerFaceVariable shall be edited
    01040
    01041           if (widget < SCMFW_WIDGET_EYECOLOUR_L) { // Bool buttons
    01042             switch (widget - SCMFW_WIDGET_HAS_MOUSTACHE_EARRING) {
    01043               default: NOT_REACHED();
    01044               case 0: cmfv = this->is_female ? CMFV_HAS_TIE_EARRING : CMFV_HAS_MOUSTACHE; break; // Has earring/moustache button
    01045               case 1: cmfv = CMFV_HAS_GLASSES; break; // Has glasses button
    01046             }
    01047             SetCompanyManagerFaceBits(this->face, cmfv, this->ge, !GetCompanyManagerFaceBits(this->face, cmfv, this->ge));
    01048             ScaleAllCompanyManagerFaceBits(this->face);
    01049           } else { // Value buttons
    01050             switch ((widget - SCMFW_WIDGET_EYECOLOUR_L) / 3) {
    01051               default: NOT_REACHED();
    01052               case 0: cmfv = CMFV_EYE_COLOUR; break;  // Eye colour buttons
    01053               case 1: cmfv = CMFV_CHIN; break;        // Chin buttons
    01054               case 2: cmfv = CMFV_EYEBROWS; break;    // Eyebrows buttons
    01055               case 3: cmfv = this->is_moust_male ? CMFV_MOUSTACHE : CMFV_LIPS; break; // Moustache or lips buttons
    01056               case 4: cmfv = CMFV_NOSE; break;        // Nose buttons
    01057               case 5: cmfv = CMFV_HAIR; break;        // Hair buttons
    01058               case 6: cmfv = CMFV_JACKET; break;      // Jacket buttons
    01059               case 7: cmfv = CMFV_COLLAR; break;      // Collar buttons
    01060               case 8: cmfv = CMFV_TIE_EARRING; break; // Tie/earring buttons
    01061               case 9: cmfv = CMFV_GLASSES; break;     // Glasses buttons
    01062             }
    01063             /* 0 == left (_L), 1 == middle or 2 == right (_R) - button click */
    01064             IncreaseCompanyManagerFaceBits(this->face, cmfv, this->ge, (((widget - SCMFW_WIDGET_EYECOLOUR_L) % 3) != 0) ? 1 : -1);
    01065           }
    01066           this->UpdateData();
    01067           this->SetDirty();
    01068         }
    01069         break;
    01070     }
    01071   }
    01072
    01073   virtual void OnQueryTextFinished(char *str)
    01074   {
    01075     if (str == NULL) return;
    01076     /* Set a new company manager face number */
    01077     if (!StrEmpty(str)) {
    01078       this->face = strtoul(str, NULL, 10);
    01079       ScaleAllCompanyManagerFaceBits(this->face);
    01080       ShowErrorMessage(INVALID_STRING_ID, STR_FACE_FACECODE_SET, 0, 0);
    01081       this->UpdateData();
    01082       this->SetDirty();
    01083     } else {
    01084       ShowErrorMessage(INVALID_STRING_ID, STR_FACE_FACECODE_ERR, 0, 0);
    01085     }
    01086   }
    01087 };
    01088
    01090 static const WindowDesc _select_company_manager_face_desc(
    01091   WDP_AUTO, WDP_AUTO, 190, 163, 190, 163,
    01092   WC_COMPANY_MANAGER_FACE, WC_NONE,
    01093   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_CONSTRUCTION,
    01094   _select_company_manager_face_widgets
    01095 );
    01096
    01098 static const WindowDesc _select_company_manager_face_adv_desc(
    01099   WDP_AUTO, WDP_AUTO, 220, 220, 220, 220,
    01100   WC_COMPANY_MANAGER_FACE, WC_NONE,
    01101   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_CONSTRUCTION,
    01102   _select_company_manager_face_adv_widgets
    01103 );
    01104
    01113 static void DoSelectCompanyManagerFace(Window *parent, bool adv, int top, int left)
    01114 {
    01115   if (!IsValidCompanyID((CompanyID)parent->window_number)) return;
    01116
    01117   if (BringWindowToFrontById(WC_COMPANY_MANAGER_FACE, parent->window_number)) return;
    01118   new SelectCompanyManagerFaceWindow(adv ? &_select_company_manager_face_adv_desc : &_select_company_manager_face_desc, parent, adv, top, left); // simple or advanced window
    01119 }
    01120
    01121
    01122 /* Names of the widgets. Keep them in the same order as in the widget array */
    01123 enum CompanyWindowWidgets {
    01124   CW_WIDGET_CLOSEBOX = 0,
    01125   CW_WIDGET_CAPTION,
    01126   CW_WIDGET_FACE,
    01127   CW_WIDGET_NEW_FACE,
    01128   CW_WIDGET_COLOUR_SCHEME,
    01129   CW_WIDGET_PRESIDENT_NAME,
    01130   CW_WIDGET_COMPANY_NAME,
    01131   CW_WIDGET_BUILD_VIEW_HQ,
    01132   CW_WIDGET_RELOCATE_HQ,
    01133   CW_WIDGET_BUY_SHARE,
    01134   CW_WIDGET_SELL_SHARE,
    01135   CW_WIDGET_COMPANY_PASSWORD,
    01136   CW_WIDGET_COMPANY_JOIN,
    01137 };
    01138
    01139 static const Widget _company_widgets[] = {
    01140 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_GREY,     0,    10,     0,    13, STR_00C5,                          STR_018B_CLOSE_WINDOW},
    01141 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_GREY,    11,   359,     0,    13, STR_7001,                          STR_018C_WINDOW_TITLE_DRAG_THIS},
    01142 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   359,    14,   157, 0x0,                               STR_NULL},
    01143 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     0,    89,   158,   169, STR_7004_NEW_FACE,                 STR_7030_SELECT_NEW_FACE_FOR_PRESIDENT},
    01144 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    90,   179,   158,   169, STR_7005_COLOUR_SCHEME,            STR_7031_CHANGE_THE_COMPANY_VEHICLE},
    01145 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   180,   269,   158,   169, STR_7009_PRESIDENT_NAME,           STR_7032_CHANGE_THE_PRESIDENT_S},
    01146 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   270,   359,   158,   169, STR_7008_COMPANY_NAME,             STR_7033_CHANGE_THE_COMPANY_NAME},
    01147 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_GREY,   266,   355,    18,    29, STR_7072_VIEW_HQ,                  STR_7070_BUILD_COMPANY_HEADQUARTERS},
    01148 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_GREY,   266,   355,    32,    43, STR_RELOCATE_HQ,                   STR_RELOCATE_COMPANY_HEADQUARTERS},
    01149 { 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},
    01150 { 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},
    01151 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   266,   355,   138,   149, STR_COMPANY_PASSWORD,              STR_COMPANY_PASSWORD_TOOLTIP},
    01152 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   266,   355,   138,   149, STR_COMPANY_JOIN,                  STR_COMPANY_JOIN_TIP},
    01153 {   WIDGETS_END},
    01154 };
    01155
    01156
    01161 static void DrawCompanyVehiclesAmount(CompanyID company)
    01162 {
    01163   const int x = 110;
    01164   int y = 63;
    01165   const Vehicle *v;
    01166   uint train = 0;
    01167   uint road  = 0;
    01168   uint air   = 0;
    01169   uint ship  = 0;
    01170
    01171   DrawString(x, y, STR_7039_VEHICLES, TC_FROMSTRING);
    01172
    01173   FOR_ALL_VEHICLES(v) {
    01174     if (v->owner == company) {
    01175       switch (v->type) {
    01176         case VEH_TRAIN:    if (IsFrontEngine(v)) train++; break;
    01177         case VEH_ROAD:     if (IsRoadVehFront(v)) road++; break;
    01178         case VEH_AIRCRAFT: if (IsNormalAircraft(v)) air++; break;
    01179         case VEH_SHIP:     ship++; break;
    01180         default: break;
    01181       }
    01182     }
    01183   }
    01184
    01185   if (train + road + air + ship == 0) {
    01186     DrawString(x + 70, y, STR_7042_NONE, TC_FROMSTRING);
    01187   } else {
    01188     if (train != 0) {
    01189       SetDParam(0, train);
    01190       DrawString(x + 70, y, STR_TRAINS, TC_FROMSTRING);
    01191       y += 10;
    01192     }
    01193
    01194     if (road != 0) {
    01195       SetDParam(0, road);
    01196       DrawString(x + 70, y, STR_ROAD_VEHICLES, TC_FROMSTRING);
    01197       y += 10;
    01198     }
    01199
    01200     if (air != 0) {
    01201       SetDParam(0, air);
    01202       DrawString(x + 70, y, STR_AIRCRAFT, TC_FROMSTRING);
    01203       y += 10;
    01204     }
    01205
    01206     if (ship != 0) {
    01207       SetDParam(0, ship);
    01208       DrawString(x + 70, y, STR_SHIPS, TC_FROMSTRING);
    01209     }
    01210   }
    01211 }
    01212
    01213 int GetAmountOwnedBy(const Company *c, Owner owner)
    01214 {
    01215   return (c->share_owners[0] == owner) +
    01216          (c->share_owners[1] == owner) +
    01217          (c->share_owners[2] == owner) +
    01218          (c->share_owners[3] == owner);
    01219 }
    01220
    01225 static void DrawCompanyOwnerText(const Company *c)
    01226 {
    01227   const Company *c2;
    01228   uint num = 0;
    01229   const byte height = GetCharacterHeight(FS_NORMAL);
    01230
    01231   FOR_ALL_COMPANIES(c2) {
    01232     uint amt = GetAmountOwnedBy(c, c2->index);
    01233     if (amt != 0) {
    01234       SetDParam(0, amt * 25);
    01235       SetDParam(1, c2->index);
    01236
    01237       DrawString(120, (num++) * height + 116, STR_707D_OWNED_BY, TC_FROMSTRING);
    01238     }
    01239   }
    01240 }
    01241
    01245 struct CompanyWindow : Window
    01246 {
    01247   CompanyWindowWidgets query_widget;
    01248
    01249   CompanyWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
    01250   {
    01251     this->owner = (Owner)this->window_number;
    01252     this->FindWindowPlacementAndResize(desc);
    01253   }
    01254
    01255   virtual void OnPaint()
    01256   {
    01257     const Company *c = GetCompany((CompanyID)this->window_number);
    01258     bool local = this->window_number == _local_company;
    01259
    01260     this->SetWidgetHiddenState(CW_WIDGET_NEW_FACE,       !local);
    01261     this->SetWidgetHiddenState(CW_WIDGET_COLOUR_SCHEME,   !local);
    01262     this->SetWidgetHiddenState(CW_WIDGET_PRESIDENT_NAME, !local);
    01263     this->SetWidgetHiddenState(CW_WIDGET_COMPANY_NAME,   !local);
    01264     this->widget[CW_WIDGET_BUILD_VIEW_HQ].data = (local && c->location_of_HQ == INVALID_TILE) ? STR_706F_BUILD_HQ : STR_7072_VIEW_HQ;
    01265     if (local && c->location_of_HQ != INVALID_TILE) this->widget[CW_WIDGET_BUILD_VIEW_HQ].type = WWT_PUSHTXTBTN; // HQ is already built.
    01266     this->SetWidgetDisabledState(CW_WIDGET_BUILD_VIEW_HQ, !local && c->location_of_HQ == INVALID_TILE);
    01267     this->SetWidgetHiddenState(CW_WIDGET_RELOCATE_HQ,      !local || c->location_of_HQ == INVALID_TILE);
    01268     this->SetWidgetHiddenState(CW_WIDGET_BUY_SHARE,        local);
    01269     this->SetWidgetHiddenState(CW_WIDGET_SELL_SHARE,       local);
    01270     this->SetWidgetHiddenState(CW_WIDGET_COMPANY_PASSWORD, !local || !_networking);
    01271     this->SetWidgetHiddenState(CW_WIDGET_COMPANY_JOIN,     local || !_networking);
    01272     this->SetWidgetDisabledState(CW_WIDGET_COMPANY_JOIN,   !IsHumanCompany(c->index));
    01273
    01274     if (!local) {
    01275       if (_settings_game.economy.allow_shares) { // Shares are allowed
    01276         /* If all shares are owned by someone (none by nobody), disable buy button */
    01277         this->SetWidgetDisabledState(CW_WIDGET_BUY_SHARE, GetAmountOwnedBy(c, INVALID_OWNER) == 0 ||
    01278             /* Only 25% left to buy. If the company is human, disable buying it up.. TODO issues! */
    01279             (GetAmountOwnedBy(c, INVALID_OWNER) == 1 && !c->is_ai) ||
    01280             /* Spectators cannot do anything of course */
    01281             _local_company == COMPANY_SPECTATOR);
    01282
    01283         /* If the company doesn't own any shares, disable sell button */
    01284         this->SetWidgetDisabledState(CW_WIDGET_SELL_SHARE, (GetAmountOwnedBy(c, _local_company) == 0) ||
    01285             /* Spectators cannot do anything of course */
    01286             _local_company == COMPANY_SPECTATOR);
    01287       } else { // Shares are not allowed, disable buy/sell buttons
    01288         this->DisableWidget(CW_WIDGET_BUY_SHARE);
    01289         this->DisableWidget(CW_WIDGET_SELL_SHARE);
    01290       }
    01291     }
    01292
    01293     SetDParam(0, c->index);
    01294     SetDParam(1, c->index);
    01295
    01296     this->DrawWidgets();
    01297
    01298 #ifdef ENABLE_NETWORK
    01299     if (_networking && NetworkCompanyIsPassworded(c->index)) {
    01300       DrawSprite(SPR_LOCK, PAL_NONE, this->widget[CW_WIDGET_COMPANY_JOIN].left - 10, this->widget[CW_WIDGET_COMPANY_JOIN].top + 2);
    01301     }
    01302 #endif /* ENABLE_NETWORK */
    01303
    01304     /* Company manager's face */
    01305     DrawCompanyManagerFace(c->face, c->colour, 2, 16);
    01306
    01307     /* "xxx (Manager)" */
    01308     SetDParam(0, c->index);
    01309     DrawStringMultiCenter(48, 141, STR_7037_PRESIDENT, MAX_LENGTH_PRESIDENT_NAME_PIXELS);
    01310
    01311     /* "Inaugurated:" */
    01312     SetDParam(0, c->inaugurated_year);
    01313     DrawString(110, 23, STR_7038_INAUGURATED, TC_FROMSTRING);
    01314
    01315     /* "Colour scheme:" */
    01316     DrawString(110, 43, STR_7006_COLOUR_SCHEME, TC_FROMSTRING);
    01317     /* Draw company-colour bus */
    01318     DrawSprite(SPR_VEH_BUS_SW_VIEW, COMPANY_SPRITE_COLOUR(c->index), 215, 44);
    01319
    01320     /* "Vehicles:" */
    01321     DrawCompanyVehiclesAmount((CompanyID)this->window_number);
    01322
    01323     /* "Company value:" */
    01324     SetDParam(0, CalculateCompanyValue(c));
    01325     DrawString(110, 106, STR_7076_COMPANY_VALUE, TC_FROMSTRING);
    01326
    01327     /* Shares list */
    01328     DrawCompanyOwnerText(c);
    01329   }
    01330
    01331   virtual void OnClick(Point pt, int widget)
    01332   {
    01333     switch (widget) {
    01334       case CW_WIDGET_NEW_FACE: DoSelectCompanyManagerFace(this, false); break;
    01335
    01336       case CW_WIDGET_COLOUR_SCHEME:
    01337         if (BringWindowToFrontById(WC_COMPANY_COLOUR, this->window_number)) break;
    01338         new SelectCompanyLiveryWindow(&_select_company_livery_desc, (CompanyID)this->window_number);
    01339         break;
    01340
    01341       case CW_WIDGET_PRESIDENT_NAME:
    01342         this->query_widget = CW_WIDGET_PRESIDENT_NAME;
    01343         SetDParam(0, this->window_number);
    01344         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);
    01345         break;
    01346
    01347       case CW_WIDGET_COMPANY_NAME:
    01348         this->query_widget = CW_WIDGET_COMPANY_NAME;
    01349         SetDParam(0, this->window_number);
    01350         ShowQueryString(STR_COMPANY_NAME, STR_700A_COMPANY_NAME, MAX_LENGTH_COMPANY_NAME_BYTES, MAX_LENGTH_COMPANY_NAME_PIXELS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT);
    01351         break;
    01352
    01353       case CW_WIDGET_BUILD_VIEW_HQ: {
    01354         TileIndex tile = GetCompany((CompanyID)this->window_number)->location_of_HQ;
    01355         if (tile == INVALID_TILE) {
    01356           if ((byte)this->window_number != _local_company) return;
    01357           SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, VHM_RECT, this);
    01358           SetTileSelectSize(2, 2);
    01359           this->LowerWidget(CW_WIDGET_BUILD_VIEW_HQ);
    01360           this->InvalidateWidget(CW_WIDGET_BUILD_VIEW_HQ);
    01361         } else {
    01362           if (_ctrl_pressed) {
    01363             ShowExtraViewPortWindow(tile);
    01364           } else {
    01365             ScrollMainWindowToTile(tile);
    01366           }
    01367         }
    01368         break;
    01369       }
    01370
    01371       case CW_WIDGET_RELOCATE_HQ:
    01372         SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, VHM_RECT, this);
    01373         SetTileSelectSize(2, 2);
    01374         this->LowerWidget(CW_WIDGET_RELOCATE_HQ);
    01375         this->InvalidateWidget(CW_WIDGET_RELOCATE_HQ);
    01376         break;
    01377
    01378       case CW_WIDGET_BUY_SHARE:
    01379         DoCommandP(0, this->window_number, 0, CMD_BUY_SHARE_IN_COMPANY | CMD_MSG(STR_707B_CAN_T_BUY_25_SHARE_IN_THIS));
    01380         break;
    01381
    01382       case CW_WIDGET_SELL_SHARE:
    01383         DoCommandP(0, this->window_number, 0, CMD_SELL_SHARE_IN_COMPANY | CMD_MSG(STR_707C_CAN_T_SELL_25_SHARE_IN));
    01384         break;
    01385
    01386 #ifdef ENABLE_NETWORK
    01387       case CW_WIDGET_COMPANY_PASSWORD:
    01388         if (this->window_number == _local_company) ShowNetworkCompanyPasswordWindow(this);
    01389         break;
    01390
    01391       case CW_WIDGET_COMPANY_JOIN: {
    01392         this->query_widget = CW_WIDGET_COMPANY_JOIN;
    01393         CompanyID company = (CompanyID)this->window_number;
    01394         if (_network_server) {
    01395           NetworkServerDoMove(CLIENT_ID_SERVER, company);
    01396           MarkWholeScreenDirty();
    01397         } else if (NetworkCompanyIsPassworded(company)) {
    01398           /* ask for the password */
    01399           ShowQueryString(STR_EMPTY, STR_NETWORK_NEED_COMPANY_PASSWORD_CAPTION, 20, 180, this, CS_ALPHANUMERAL, QSF_NONE);
    01400         } else {
    01401           /* just send the join command */
    01402           NetworkClientRequestMove(company);
    01403         }
    01404         break;
    01405       }
    01406 #endif /* ENABLE_NETWORK */
    01407     }
    01408   }
    01409
    01410   virtual void OnHundredthTick()
    01411   {
    01412     /* redraw the window every now and then */
    01413     this->SetDirty();
    01414   }
    01415
    01416   virtual void OnPlaceObject(Point pt, TileIndex tile)
    01417   {
    01418     if (DoCommandP(tile, 0, 0, CMD_BUILD_COMPANY_HQ | CMD_MSG(STR_7071_CAN_T_BUILD_COMPANY_HEADQUARTERS)))
    01419       ResetObjectToPlace();
    01420       this->widget[CW_WIDGET_BUILD_VIEW_HQ].type = WWT_PUSHTXTBTN; // this button can now behave as a normal push button
    01421       this->RaiseButtons();
    01422   }
    01423
    01424   virtual void OnPlaceObjectAbort()
    01425   {
    01426     this->RaiseButtons();
    01427   }
    01428
    01429   virtual void OnQueryTextFinished(char *str)
    01430   {
    01431     if (str == NULL) return;
    01432
    01433     switch (this->query_widget) {
    01434       default: NOT_REACHED();
    01435
    01436       case CW_WIDGET_PRESIDENT_NAME:
    01437         DoCommandP(0, 0, 0, CMD_RENAME_PRESIDENT | CMD_MSG(STR_700D_CAN_T_CHANGE_PRESIDENT), NULL, str);
    01438         break;
    01439
    01440       case CW_WIDGET_COMPANY_NAME:
    01441         DoCommandP(0, 0, 0, CMD_RENAME_COMPANY | CMD_MSG(STR_700C_CAN_T_CHANGE_COMPANY_NAME), NULL, str);
    01442         break;
    01443
    01444 #ifdef ENABLE_NETWORK
    01445       case CW_WIDGET_COMPANY_JOIN:
    01446         NetworkClientRequestMove((CompanyID)this->window_number, str);
    01447         break;
    01448 #endif /* ENABLE_NETWORK */
    01449     }
    01450   }
    01451 };
    01452
    01453 static const WindowDesc _company_desc(
    01454   WDP_AUTO, WDP_AUTO, 360, 170, 360, 170,
    01455   WC_COMPANY, WC_NONE,
    01456   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
    01457   _company_widgets
    01458 );
    01459
    01460 void ShowCompany(CompanyID company)
    01461 {
    01462   if (!IsValidCompanyID(company)) return;
    01463
    01464   AllocateWindowDescFront<CompanyWindow>(&_company_desc, company);
    01465 }
    01466
    01467
    01468
    01469 struct BuyCompanyWindow : Window {
    01470   BuyCompanyWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
    01471   {
    01472     this->FindWindowPlacementAndResize(desc);
    01473   }
    01474
    01475   virtual void OnPaint()
    01476   {
    01477     Company *c = GetCompany((CompanyID)this->window_number);
    01478     SetDParam(0, STR_COMPANY_NAME);
    01479     SetDParam(1, c->index);
    01480     this->DrawWidgets();
    01481
    01482     DrawCompanyManagerFace(c->face, c->colour, 2, 16);
    01483
    01484     SetDParam(0, c->index);
    01485     SetDParam(1, c->bankrupt_value);
    01486     DrawStringMultiCenter(214, 65, STR_705B_WE_ARE_LOOKING_FOR_A_TRANSPORT, 238);
    01487   }
    01488
    01489   virtual void OnClick(Point pt, int widget)
    01490   {
    01491     switch (widget) {
    01492       case 3:
    01493         delete this;
    01494         break;
    01495
    01496       case 4:
    01497         DoCommandP(0, this->window_number, 0, CMD_BUY_COMPANY | CMD_MSG(STR_7060_CAN_T_BUY_COMPANY));
    01498         break;
    01499     }
    01500   }
    01501 };
    01502
    01503 static const Widget _buy_company_widgets[] = {
    01504 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_LIGHT_BLUE,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},
    01505 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_LIGHT_BLUE,    11,   333,     0,    13, STR_00B3_MESSAGE_FROM, STR_018C_WINDOW_TITLE_DRAG_THIS},
    01506 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_LIGHT_BLUE,     0,   333,    14,   136, 0x0,                   STR_NULL},
    01507 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_LIGHT_BLUE,   148,   207,   117,   128, STR_00C9_NO,           STR_NULL},
    01508 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_LIGHT_BLUE,   218,   277,   117,   128, STR_00C8_YES,          STR_NULL},
    01509 {   WIDGETS_END},
    01510 };
    01511
    01512 static const WindowDesc _buy_company_desc(
    01513   153, 171, 334, 137, 334, 137,
    01514   WC_BUY_COMPANY, WC_NONE,
    01515   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_CONSTRUCTION,
    01516   _buy_company_widgets
    01517 );
    01518
    01519
    01520 void ShowBuyCompanyDialog(CompanyID company)
    01521 {
    01522   AllocateWindowDescFront<BuyCompanyWindow>(&_buy_company_desc, company);
    01523 }