src/company_gui.cpp
changeset 10208 72c00af5c95d
parent 10207 c291a21b304e
child 10209 a1e7417bf1b7
equal deleted inserted replaced
10207:c291a21b304e 10208:72c00af5c95d
       
     1 /* $Id$ */
       
     2 
       
     3 /** @file company_gui.cpp Company related GUIs. */
       
     4 
       
     5 #include "stdafx.h"
       
     6 #include "openttd.h"
       
     7 #include "gui.h"
       
     8 #include "window_gui.h"
       
     9 #include "textbuf_gui.h"
       
    10 #include "viewport_func.h"
       
    11 #include "gfx_func.h"
       
    12 #include "company_func.h"
       
    13 #include "company_base.h"
       
    14 #include "command_func.h"
       
    15 #include "network/network.h"
       
    16 #include "network/network_gui.h"
       
    17 #include "variables.h"
       
    18 #include "roadveh.h"
       
    19 #include "train.h"
       
    20 #include "aircraft.h"
       
    21 #include "newgrf.h"
       
    22 #include "company_manager_face.h"
       
    23 #include "strings_func.h"
       
    24 #include "functions.h"
       
    25 #include "window_func.h"
       
    26 #include "date_func.h"
       
    27 #include "string_func.h"
       
    28 #include "settings_type.h"
       
    29 #include "widgets/dropdown_func.h"
       
    30 #include "widgets/dropdown_type.h"
       
    31 #include "tilehighlight_func.h"
       
    32 
       
    33 #include "table/sprites.h"
       
    34 #include "table/strings.h"
       
    35 
       
    36 enum {
       
    37 	FIRST_GUI_CALL = INT_MAX,  ///< default value to specify thuis is the first call of the resizable gui
       
    38 };
       
    39 
       
    40 static void DoShowCompanyFinances(CompanyID company, bool show_small, bool show_stickied, int top = FIRST_GUI_CALL, int left = FIRST_GUI_CALL);
       
    41 static void DoSelectCompanyManagerFace(Window *parent, bool show_big, int top =  FIRST_GUI_CALL, int left = FIRST_GUI_CALL);
       
    42 
       
    43 static void DrawCompanyEconomyStats(const Company *c, bool small)
       
    44 {
       
    45 	int x, y, i, j, year;
       
    46 	const Money (*tbl)[EXPENSES_END];
       
    47 	Money sum, cost;
       
    48 	StringID str;
       
    49 
       
    50 	if (!small) { // normal sized economics window
       
    51 		/* draw categories */
       
    52 		DrawStringCenterUnderline(61, 15, STR_700F_EXPENDITURE_INCOME, TC_FROMSTRING);
       
    53 		for (i = 0; i != EXPENSES_END; i++)
       
    54 			DrawString(2, 27 + i * 10, STR_7011_CONSTRUCTION + i, TC_FROMSTRING);
       
    55 		DrawStringRightAligned(111, 27 + 10 * EXPENSES_END + 2, STR_7020_TOTAL, TC_FROMSTRING);
       
    56 
       
    57 		/* draw the price columns */
       
    58 		year = _cur_year - 2;
       
    59 		j = 3;
       
    60 		x = 215;
       
    61 		tbl = c->yearly_expenses + 2;
       
    62 		do {
       
    63 			if (year >= c->inaugurated_year) {
       
    64 				SetDParam(0, year);
       
    65 				DrawStringRightAlignedUnderline(x, 15, STR_7010, TC_FROMSTRING);
       
    66 				sum = 0;
       
    67 				for (i = 0; i != EXPENSES_END; i++) {
       
    68 					/* draw one row in the price column */
       
    69 					cost = (*tbl)[i];
       
    70 					if (cost != 0) {
       
    71 						sum += cost;
       
    72 
       
    73 						str = STR_701E;
       
    74 						if (cost < 0) { cost = -cost; str++; }
       
    75 						SetDParam(0, cost);
       
    76 						DrawStringRightAligned(x, 27 + i * 10, str, TC_FROMSTRING);
       
    77 					}
       
    78 				}
       
    79 
       
    80 				str = STR_701E;
       
    81 				if (sum < 0) { sum = -sum; str++; }
       
    82 				SetDParam(0, sum);
       
    83 				DrawStringRightAligned(x, 27 + EXPENSES_END * 10 + 2, str, TC_FROMSTRING);
       
    84 
       
    85 				GfxFillRect(x - 75, 27 + 10 * EXPENSES_END, x, 27 + 10 * EXPENSES_END, 215);
       
    86 				x += 95;
       
    87 			}
       
    88 			year++;
       
    89 			tbl--;
       
    90 		} while (--j != 0);
       
    91 
       
    92 		y = 27 + 10 * EXPENSES_END + 14;
       
    93 
       
    94 		/* draw max loan aligned to loan below (y += 10) */
       
    95 		SetDParam(0, _economy.max_loan);
       
    96 		DrawString(202, y + 10, STR_MAX_LOAN, TC_FROMSTRING);
       
    97 	} else {
       
    98 		y = 15;
       
    99 	}
       
   100 
       
   101 	DrawString(2, y, STR_7026_BANK_BALANCE, TC_FROMSTRING);
       
   102 	SetDParam(0, c->money);
       
   103 	DrawStringRightAligned(182, y, STR_7028, TC_FROMSTRING);
       
   104 
       
   105 	y += 10;
       
   106 
       
   107 	DrawString(2, y, STR_7027_LOAN, TC_FROMSTRING);
       
   108 	SetDParam(0, c->current_loan);
       
   109 	DrawStringRightAligned(182, y, STR_7028, TC_FROMSTRING);
       
   110 
       
   111 	y += 12;
       
   112 
       
   113 	GfxFillRect(182 - 75, y - 2, 182, y - 2, 215);
       
   114 
       
   115 	SetDParam(0, c->money - c->current_loan);
       
   116 	DrawStringRightAligned(182, y, STR_7028, TC_FROMSTRING);
       
   117 }
       
   118 
       
   119 enum CompanyFinancesWindowWidgets {
       
   120 	CFW_WIDGET_TOGGLE_SIZE   = 2,
       
   121 	CFW_WIDGET_INCREASE_LOAN = 6,
       
   122 	CFW_WIDGET_REPAY_LOAN    = 7,
       
   123 };
       
   124 
       
   125 static const Widget _company_finances_widgets[] = {
       
   126 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_GREY,     0,    10,     0,    13, STR_00C5,               STR_018B_CLOSE_WINDOW},
       
   127 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_GREY,    11,   379,     0,    13, STR_700E_FINANCES,      STR_018C_WINDOW_TITLE_DRAG_THIS},
       
   128 {     WWT_IMGBTN,   RESIZE_NONE,  COLOUR_GREY,   380,   394,     0,    13, SPR_LARGE_SMALL_WINDOW, STR_7075_TOGGLE_LARGE_SMALL_WINDOW},
       
   129 {  WWT_STICKYBOX,   RESIZE_NONE,  COLOUR_GREY,   395,   406,     0,    13, 0x0,                    STR_STICKY_BUTTON},
       
   130 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   406,    14, 39 + 10 * EXPENSES_END, 0x0,    STR_NULL},
       
   131 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   406, 40 + 10 * EXPENSES_END, 73 + 10 * EXPENSES_END, 0x0, STR_NULL},
       
   132 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     0,   202, 74 + 10 * EXPENSES_END, 85 + 10 * EXPENSES_END, STR_7029_BORROW,        STR_7035_INCREASE_SIZE_OF_LOAN},
       
   133 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   203,   406, 74 + 10 * EXPENSES_END, 85 + 10 * EXPENSES_END, STR_702A_REPAY,         STR_7036_REPAY_PART_OF_LOAN},
       
   134 {   WIDGETS_END},
       
   135 };
       
   136 
       
   137 static const Widget _company_finances_small_widgets[] = {
       
   138 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_GREY,     0,    10,     0,    13, STR_00C5,               STR_018B_CLOSE_WINDOW},
       
   139 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_GREY,    11,   253,     0,    13, STR_700E_FINANCES,      STR_018C_WINDOW_TITLE_DRAG_THIS},
       
   140 {     WWT_IMGBTN,   RESIZE_NONE,  COLOUR_GREY,   254,   267,     0,    13, SPR_LARGE_SMALL_WINDOW, STR_7075_TOGGLE_LARGE_SMALL_WINDOW},
       
   141 {  WWT_STICKYBOX,   RESIZE_NONE,  COLOUR_GREY,   268,   279,     0,    13, 0x0,                    STR_STICKY_BUTTON},
       
   142 {      WWT_EMPTY,   RESIZE_NONE,  COLOUR_GREY,     0,     0,     0,     0, 0x0,                    STR_NULL},
       
   143 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   279,    14,    47, STR_NULL,               STR_NULL},
       
   144 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     0,   139,    48,    59, STR_7029_BORROW,        STR_7035_INCREASE_SIZE_OF_LOAN},
       
   145 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   140,   279,    48,    59, STR_702A_REPAY,         STR_7036_REPAY_PART_OF_LOAN},
       
   146 {   WIDGETS_END},
       
   147 };
       
   148 
       
   149 struct CompanyFinancesWindow : Window {
       
   150 	bool small;
       
   151 
       
   152 	CompanyFinancesWindow(const WindowDesc *desc, CompanyID company, bool show_small,
       
   153 					bool show_stickied, int top, int left) :
       
   154 			Window(desc, company),
       
   155 			small(show_small)
       
   156 	{
       
   157 		this->caption_color = this->window_number;
       
   158 
       
   159 		if (show_stickied) this->flags4 |= WF_STICKY;
       
   160 
       
   161 		/* Check if repositioning from default is required */
       
   162 		if (top != FIRST_GUI_CALL && left != FIRST_GUI_CALL) {
       
   163 			this->top = top;
       
   164 			this->left = left;
       
   165 		}
       
   166 
       
   167 		this->FindWindowPlacementAndResize(desc);
       
   168 	}
       
   169 
       
   170 	virtual void OnPaint()
       
   171 	{
       
   172 		CompanyID company = (CompanyID)this->window_number;
       
   173 		const Company *c = GetCompany(company);
       
   174 
       
   175 		/* Recheck the size of the window as it might need to be resized due to the local company changing */
       
   176 		int new_height = ((company != _local_company) ? 0 : 12) + ((this->small != 0) ? 48 : 74 + 10 * EXPENSES_END);
       
   177 		if (this->height != new_height) {
       
   178 			/* Make window dirty before and after resizing */
       
   179 			this->SetDirty();
       
   180 			this->height = new_height;
       
   181 			this->SetDirty();
       
   182 
       
   183 			this->SetWidgetHiddenState(CFW_WIDGET_INCREASE_LOAN, company != _local_company);
       
   184 			this->SetWidgetHiddenState(CFW_WIDGET_REPAY_LOAN,    company != _local_company);
       
   185 		}
       
   186 
       
   187 		/* Borrow button only shows when there is any more money to loan */
       
   188 		this->SetWidgetDisabledState(CFW_WIDGET_INCREASE_LOAN, c->current_loan == _economy.max_loan);
       
   189 
       
   190 		/* Repay button only shows when there is any more money to repay */
       
   191 		this->SetWidgetDisabledState(CFW_WIDGET_REPAY_LOAN, company != _local_company || c->current_loan == 0);
       
   192 
       
   193 		SetDParam(0, c->index);
       
   194 		SetDParam(1, c->index);
       
   195 		SetDParam(2, LOAN_INTERVAL);
       
   196 		this->DrawWidgets();
       
   197 
       
   198 		DrawCompanyEconomyStats(c, this->small);
       
   199 	}
       
   200 
       
   201 	virtual void OnClick(Point pt, int widget)
       
   202 	{
       
   203 		switch (widget) {
       
   204 			case CFW_WIDGET_TOGGLE_SIZE: {/* toggle size */
       
   205 				bool new_mode = !this->small;
       
   206 				bool stickied = !!(this->flags4 & WF_STICKY);
       
   207 				int oldtop = this->top;   ///< current top position of the window before closing it
       
   208 				int oldleft = this->left; ///< current left position of the window before closing it
       
   209 				CompanyID company = (CompanyID)this->window_number;
       
   210 
       
   211 				delete this;
       
   212 				/* Open up the (toggled size) Finance window at the same position as the previous */
       
   213 				DoShowCompanyFinances(company, new_mode, stickied, oldtop, oldleft);
       
   214 			}
       
   215 			break;
       
   216 
       
   217 			case CFW_WIDGET_INCREASE_LOAN: /* increase loan */
       
   218 				DoCommandP(0, 0, _ctrl_pressed, NULL, CMD_INCREASE_LOAN | CMD_MSG(STR_702C_CAN_T_BORROW_ANY_MORE_MONEY));
       
   219 				break;
       
   220 
       
   221 			case CFW_WIDGET_REPAY_LOAN: /* repay loan */
       
   222 				DoCommandP(0, 0, _ctrl_pressed, NULL, CMD_DECREASE_LOAN | CMD_MSG(STR_702F_CAN_T_REPAY_LOAN));
       
   223 				break;
       
   224 		}
       
   225 	}
       
   226 };
       
   227 
       
   228 static const WindowDesc _company_finances_desc = {
       
   229 	WDP_AUTO, WDP_AUTO, 407, 86 + 10 * EXPENSES_END, 407, 86 + 10 * EXPENSES_END,
       
   230 	WC_FINANCES, WC_NONE,
       
   231 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
       
   232 	_company_finances_widgets,
       
   233 };
       
   234 
       
   235 static const WindowDesc _company_finances_small_desc = {
       
   236 	WDP_AUTO, WDP_AUTO, 280, 60, 280, 60,
       
   237 	WC_FINANCES, WC_NONE,
       
   238 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
       
   239 	_company_finances_small_widgets,
       
   240 };
       
   241 
       
   242 /**
       
   243  * Open the small/large finance window of the company
       
   244  *
       
   245  * @param company        the company who's finances are requested to be seen
       
   246  * @param show_small     show large or small version opf the window
       
   247  * @param show_stickied  previous "stickyness" of the window
       
   248  * @param top            previous top position of the window
       
   249  * @param left           previous left position of the window
       
   250  *
       
   251  * @pre is company a valid company
       
   252  */
       
   253 static void DoShowCompanyFinances(CompanyID company, bool show_small, bool show_stickied, int top, int left)
       
   254 {
       
   255 	if (!IsValidCompanyID(company)) return;
       
   256 
       
   257 	if (BringWindowToFrontById(WC_FINANCES, company)) return;
       
   258 	new CompanyFinancesWindow(show_small ? &_company_finances_small_desc : &_company_finances_desc, company, show_small, show_stickied, top, left);
       
   259 }
       
   260 
       
   261 void ShowCompanyFinances(CompanyID company)
       
   262 {
       
   263 	DoShowCompanyFinances(company, false, false);
       
   264 }
       
   265 
       
   266 /* List of colours for the livery window */
       
   267 static const StringID _colour_dropdown[] = {
       
   268 	STR_00D1_DARK_BLUE,
       
   269 	STR_00D2_PALE_GREEN,
       
   270 	STR_00D3_PINK,
       
   271 	STR_00D4_YELLOW,
       
   272 	STR_00D5_RED,
       
   273 	STR_00D6_LIGHT_BLUE,
       
   274 	STR_00D7_GREEN,
       
   275 	STR_00D8_DARK_GREEN,
       
   276 	STR_00D9_BLUE,
       
   277 	STR_00DA_CREAM,
       
   278 	STR_00DB_MAUVE,
       
   279 	STR_00DC_PURPLE,
       
   280 	STR_00DD_ORANGE,
       
   281 	STR_00DE_BROWN,
       
   282 	STR_00DF_GREY,
       
   283 	STR_00E0_WHITE,
       
   284 };
       
   285 
       
   286 /* Association of liveries to livery classes */
       
   287 static const LiveryClass _livery_class[LS_END] = {
       
   288 	LC_OTHER,
       
   289 	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,
       
   290 	LC_ROAD, LC_ROAD,
       
   291 	LC_SHIP, LC_SHIP,
       
   292 	LC_AIRCRAFT, LC_AIRCRAFT, LC_AIRCRAFT,
       
   293 	LC_ROAD, LC_ROAD,
       
   294 };
       
   295 
       
   296 class DropDownListColourItem : public DropDownListItem {
       
   297 public:
       
   298 	DropDownListColourItem(int result, bool masked) : DropDownListItem(result, masked) {}
       
   299 
       
   300 	virtual ~DropDownListColourItem() {}
       
   301 
       
   302 	StringID String() const
       
   303 	{
       
   304 		return _colour_dropdown[this->result];
       
   305 	}
       
   306 
       
   307 	uint Height(uint width) const
       
   308 	{
       
   309 		return 14;
       
   310 	}
       
   311 
       
   312 	bool Selectable() const
       
   313 	{
       
   314 		return true;
       
   315 	}
       
   316 
       
   317 	void Draw(int x, int y, uint width, uint height, bool sel, int bg_colour) const
       
   318 	{
       
   319 		DrawSprite(SPR_VEH_BUS_SIDE_VIEW, PALETTE_RECOLOR_START + this->result, x + 16, y + 7);
       
   320 		DrawStringTruncated(x + 32, y + 3, this->String(), sel ? TC_WHITE : TC_BLACK, width - 30);
       
   321 	}
       
   322 };
       
   323 
       
   324 struct SelectCompanyLiveryWindow : public Window {
       
   325 private:
       
   326 	uint32 sel;
       
   327 	LiveryClass livery_class;
       
   328 
       
   329 	enum SelectCompanyLiveryWindowWidgets {
       
   330 		SCLW_WIDGET_CLOSE,
       
   331 		SCLW_WIDGET_CAPTION,
       
   332 		SCLW_WIDGET_CLASS_GENERAL,
       
   333 		SCLW_WIDGET_CLASS_RAIL,
       
   334 		SCLW_WIDGET_CLASS_ROAD,
       
   335 		SCLW_WIDGET_CLASS_SHIP,
       
   336 		SCLW_WIDGET_CLASS_AIRCRAFT,
       
   337 		SCLW_WIDGET_SPACER_CLASS,
       
   338 		SCLW_WIDGET_SPACER_DROPDOWN,
       
   339 		SCLW_WIDGET_PRI_COL_DROPDOWN,
       
   340 		SCLW_WIDGET_SEC_COL_DROPDOWN,
       
   341 		SCLW_WIDGET_MATRIX,
       
   342 	};
       
   343 
       
   344 	void ShowColourDropDownMenu(uint32 widget)
       
   345 	{
       
   346 		uint32 used_colours = 0;
       
   347 		const Livery *livery;
       
   348 		LiveryScheme scheme;
       
   349 
       
   350 		/* Disallow other company colours for the primary colour */
       
   351 		if (HasBit(this->sel, LS_DEFAULT) && widget == SCLW_WIDGET_PRI_COL_DROPDOWN) {
       
   352 			const Company *c;
       
   353 			FOR_ALL_COMPANIES(c) {
       
   354 				if (c->index != _local_company) SetBit(used_colours, c->colour);
       
   355 			}
       
   356 		}
       
   357 
       
   358 		/* Get the first selected livery to use as the default dropdown item */
       
   359 		for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
       
   360 			if (HasBit(this->sel, scheme)) break;
       
   361 		}
       
   362 		if (scheme == LS_END) scheme = LS_DEFAULT;
       
   363 		livery = &GetCompany((CompanyID)this->window_number)->livery[scheme];
       
   364 
       
   365 		DropDownList *list = new DropDownList();
       
   366 		for (uint i = 0; i < lengthof(_colour_dropdown); i++) {
       
   367 			list->push_back(new DropDownListColourItem(i, HasBit(used_colours, i)));
       
   368 		}
       
   369 
       
   370 		ShowDropDownList(this, list, widget == SCLW_WIDGET_PRI_COL_DROPDOWN ? livery->colour1 : livery->colour2, widget);
       
   371 	}
       
   372 
       
   373 public:
       
   374 	SelectCompanyLiveryWindow(const WindowDesc *desc, CompanyID company) : Window(desc, company)
       
   375 	{
       
   376 		this->caption_color = company;
       
   377 		this->livery_class = LC_OTHER;
       
   378 		this->sel = 1;
       
   379 		this->LowerWidget(SCLW_WIDGET_CLASS_GENERAL);
       
   380 		this->OnInvalidateData(_loaded_newgrf_features.has_2CC);
       
   381 		this->FindWindowPlacementAndResize(desc);
       
   382 	}
       
   383 
       
   384 	virtual void OnPaint()
       
   385 	{
       
   386 		const Company *c = GetCompany((CompanyID)this->window_number);
       
   387 		LiveryScheme scheme = LS_DEFAULT;
       
   388 		int y = 51;
       
   389 
       
   390 		/* Disable dropdown controls if no scheme is selected */
       
   391 		this->SetWidgetDisabledState(SCLW_WIDGET_PRI_COL_DROPDOWN, this->sel == 0);
       
   392 		this->SetWidgetDisabledState(SCLW_WIDGET_SEC_COL_DROPDOWN, this->sel == 0);
       
   393 
       
   394 		if (this->sel != 0) {
       
   395 			for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
       
   396 				if (HasBit(this->sel, scheme)) break;
       
   397 			}
       
   398 			if (scheme == LS_END) scheme = LS_DEFAULT;
       
   399 		}
       
   400 
       
   401 		SetDParam(0, STR_00D1_DARK_BLUE + c->livery[scheme].colour1);
       
   402 		SetDParam(1, STR_00D1_DARK_BLUE + c->livery[scheme].colour2);
       
   403 
       
   404 		this->DrawWidgets();
       
   405 
       
   406 		for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
       
   407 			if (_livery_class[scheme] == this->livery_class) {
       
   408 				bool sel = HasBit(this->sel, scheme) != 0;
       
   409 
       
   410 				if (scheme != LS_DEFAULT) {
       
   411 					DrawSprite(c->livery[scheme].in_use ? SPR_BOX_CHECKED : SPR_BOX_EMPTY, PAL_NONE, 2, y);
       
   412 				}
       
   413 
       
   414 				DrawString(15, y, STR_LIVERY_DEFAULT + scheme, sel ? TC_WHITE : TC_BLACK);
       
   415 
       
   416 				DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOR(c->livery[scheme].colour1), 152, y);
       
   417 				DrawString(165, y, STR_00D1_DARK_BLUE + c->livery[scheme].colour1, sel ? TC_WHITE : TC_GOLD);
       
   418 
       
   419 				if (!this->IsWidgetHidden(SCLW_WIDGET_SEC_COL_DROPDOWN)) {
       
   420 					DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOR(c->livery[scheme].colour2), 277, y);
       
   421 					DrawString(290, y, STR_00D1_DARK_BLUE + c->livery[scheme].colour2, sel ? TC_WHITE : TC_GOLD);
       
   422 				}
       
   423 
       
   424 				y += 14;
       
   425 			}
       
   426 		}
       
   427 	}
       
   428 
       
   429 	virtual void OnClick(Point pt, int widget)
       
   430 	{
       
   431 		/* Number of liveries in each class, used to determine the height of the livery window */
       
   432 		static const byte livery_height[] = {
       
   433 			1,
       
   434 			13,
       
   435 			4,
       
   436 			2,
       
   437 			3,
       
   438 		};
       
   439 
       
   440 		switch (widget) {
       
   441 			/* Livery Class buttons */
       
   442 			case SCLW_WIDGET_CLASS_GENERAL:
       
   443 			case SCLW_WIDGET_CLASS_RAIL:
       
   444 			case SCLW_WIDGET_CLASS_ROAD:
       
   445 			case SCLW_WIDGET_CLASS_SHIP:
       
   446 			case SCLW_WIDGET_CLASS_AIRCRAFT: {
       
   447 				LiveryScheme scheme;
       
   448 
       
   449 				this->RaiseWidget(this->livery_class + SCLW_WIDGET_CLASS_GENERAL);
       
   450 				this->livery_class = (LiveryClass)(widget - SCLW_WIDGET_CLASS_GENERAL);
       
   451 				this->sel = 0;
       
   452 				this->LowerWidget(this->livery_class + SCLW_WIDGET_CLASS_GENERAL);
       
   453 
       
   454 				/* Select the first item in the list */
       
   455 				for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
       
   456 					if (_livery_class[scheme] == this->livery_class) {
       
   457 						this->sel = 1 << scheme;
       
   458 						break;
       
   459 					}
       
   460 				}
       
   461 				this->height = 49 + livery_height[this->livery_class] * 14;
       
   462 				this->widget[SCLW_WIDGET_MATRIX].bottom = this->height - 1;
       
   463 				this->widget[SCLW_WIDGET_MATRIX].data = livery_height[this->livery_class] << 8 | 1;
       
   464 				MarkWholeScreenDirty();
       
   465 				break;
       
   466 			}
       
   467 
       
   468 			case SCLW_WIDGET_PRI_COL_DROPDOWN: /* First colour dropdown */
       
   469 				ShowColourDropDownMenu(SCLW_WIDGET_PRI_COL_DROPDOWN);
       
   470 				break;
       
   471 
       
   472 			case SCLW_WIDGET_SEC_COL_DROPDOWN: /* Second colour dropdown */
       
   473 				ShowColourDropDownMenu(SCLW_WIDGET_SEC_COL_DROPDOWN);
       
   474 				break;
       
   475 
       
   476 			case SCLW_WIDGET_MATRIX: {
       
   477 				LiveryScheme scheme;
       
   478 				LiveryScheme j = (LiveryScheme)((pt.y - 48) / 14);
       
   479 
       
   480 				for (scheme = LS_BEGIN; scheme <= j; scheme++) {
       
   481 					if (_livery_class[scheme] != this->livery_class) j++;
       
   482 					if (scheme >= LS_END) return;
       
   483 				}
       
   484 				if (j >= LS_END) return;
       
   485 
       
   486 				/* If clicking on the left edge, toggle using the livery */
       
   487 				if (pt.x < 10) {
       
   488 					DoCommandP(0, j | (2 << 8), !GetCompany((CompanyID)this->window_number)->livery[j].in_use, NULL, CMD_SET_COMPANY_COLOR);
       
   489 				}
       
   490 
       
   491 				if (_ctrl_pressed) {
       
   492 					ToggleBit(this->sel, j);
       
   493 				} else {
       
   494 					this->sel = 1 << j;
       
   495 				}
       
   496 				this->SetDirty();
       
   497 				break;
       
   498 			}
       
   499 		}
       
   500 	}
       
   501 
       
   502 	virtual void OnDropdownSelect(int widget, int index)
       
   503 	{
       
   504 		for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
       
   505 			if (HasBit(this->sel, scheme)) {
       
   506 				DoCommandP(0, scheme | (widget == SCLW_WIDGET_PRI_COL_DROPDOWN ? 0 : 256), index, NULL, CMD_SET_COMPANY_COLOR);
       
   507 			}
       
   508 		}
       
   509 	}
       
   510 
       
   511 	virtual void OnInvalidateData(int data = 0)
       
   512 	{
       
   513 		static bool has2cc = true;
       
   514 
       
   515 		if (has2cc == !!data) return;
       
   516 
       
   517 		has2cc = !!data;
       
   518 
       
   519 		int r = this->widget[has2cc ? SCLW_WIDGET_SEC_COL_DROPDOWN : SCLW_WIDGET_PRI_COL_DROPDOWN].right;
       
   520 		this->SetWidgetHiddenState(SCLW_WIDGET_SEC_COL_DROPDOWN, !has2cc);
       
   521 		this->widget[SCLW_WIDGET_CAPTION].right = r;
       
   522 		this->widget[SCLW_WIDGET_SPACER_CLASS].right = r;
       
   523 		this->widget[SCLW_WIDGET_MATRIX].right = r;
       
   524 		this->width = r + 1;
       
   525 	}
       
   526 };
       
   527 
       
   528 static const Widget _select_company_livery_widgets[] = {
       
   529 { WWT_CLOSEBOX, RESIZE_NONE,  COLOUR_GREY,   0,  10,   0,  13, STR_00C5,                  STR_018B_CLOSE_WINDOW },
       
   530 {  WWT_CAPTION, RESIZE_NONE,  COLOUR_GREY,  11, 399,   0,  13, STR_7007_NEW_COLOR_SCHEME, STR_018C_WINDOW_TITLE_DRAG_THIS },
       
   531 {   WWT_IMGBTN, RESIZE_NONE,  COLOUR_GREY,   0,  21,  14,  35, SPR_IMG_COMPANY_GENERAL,   STR_LIVERY_GENERAL_TIP },
       
   532 {   WWT_IMGBTN, RESIZE_NONE,  COLOUR_GREY,  22,  43,  14,  35, SPR_IMG_TRAINLIST,         STR_LIVERY_TRAIN_TIP },
       
   533 {   WWT_IMGBTN, RESIZE_NONE,  COLOUR_GREY,  44,  65,  14,  35, SPR_IMG_TRUCKLIST,         STR_LIVERY_ROADVEH_TIP },
       
   534 {   WWT_IMGBTN, RESIZE_NONE,  COLOUR_GREY,  66,  87,  14,  35, SPR_IMG_SHIPLIST,          STR_LIVERY_SHIP_TIP },
       
   535 {   WWT_IMGBTN, RESIZE_NONE,  COLOUR_GREY,  88, 109,  14,  35, SPR_IMG_AIRPLANESLIST,     STR_LIVERY_AIRCRAFT_TIP },
       
   536 {    WWT_PANEL, RESIZE_NONE,  COLOUR_GREY, 110, 399,  14,  35, 0x0,                       STR_NULL },
       
   537 {    WWT_PANEL, RESIZE_NONE,  COLOUR_GREY,   0, 149,  36,  47, 0x0,                       STR_NULL },
       
   538 { WWT_DROPDOWN, RESIZE_NONE,  COLOUR_GREY, 150, 274,  36,  47, STR_02BD,                  STR_LIVERY_PRIMARY_TIP },
       
   539 { WWT_DROPDOWN, RESIZE_NONE,  COLOUR_GREY, 275, 399,  36,  47, STR_02E1,                  STR_LIVERY_SECONDARY_TIP },
       
   540 {   WWT_MATRIX, RESIZE_NONE,  COLOUR_GREY,   0, 399,  48,  48 + 1 * 14, (1 << 8) | 1,     STR_LIVERY_PANEL_TIP },
       
   541 { WIDGETS_END },
       
   542 };
       
   543 
       
   544 static const WindowDesc _select_company_livery_desc = {
       
   545 	WDP_AUTO, WDP_AUTO, 400, 49 + 1 * 14, 400, 49 + 1 * 14,
       
   546 	WC_COMPANY_COLOR, WC_NONE,
       
   547 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
       
   548 	_select_company_livery_widgets,
       
   549 };
       
   550 
       
   551 /**
       
   552  * Draws the face of a company manager's face.
       
   553  * @param cmf   the company manager's face
       
   554  * @param color the (background) color of the gradient
       
   555  * @param x     x-position to draw the face
       
   556  * @param y     y-position to draw the face
       
   557  */
       
   558 void DrawCompanyManagerFace(CompanyManagerFace cmf, int color, int x, int y)
       
   559 {
       
   560 	GenderEthnicity ge = (GenderEthnicity)GetCompanyManagerFaceBits(cmf, CMFV_GEN_ETHN, GE_WM);
       
   561 
       
   562 	bool has_moustache   = !HasBit(ge, GENDER_FEMALE) && GetCompanyManagerFaceBits(cmf, CMFV_HAS_MOUSTACHE,   ge) != 0;
       
   563 	bool has_tie_earring = !HasBit(ge, GENDER_FEMALE) || GetCompanyManagerFaceBits(cmf, CMFV_HAS_TIE_EARRING, ge) != 0;
       
   564 	bool has_glasses     = GetCompanyManagerFaceBits(cmf, CMFV_HAS_GLASSES, ge) != 0;
       
   565 	SpriteID pal;
       
   566 
       
   567 	/* Modify eye colour palette only if 2 or more valid values exist */
       
   568 	if (_cmf_info[CMFV_EYE_COLOUR].valid_values[ge] < 2) {
       
   569 		pal = PAL_NONE;
       
   570 	} else {
       
   571 		switch (GetCompanyManagerFaceBits(cmf, CMFV_EYE_COLOUR, ge)) {
       
   572 			default: NOT_REACHED();
       
   573 			case 0: pal = PALETTE_TO_BROWN; break;
       
   574 			case 1: pal = PALETTE_TO_BLUE;  break;
       
   575 			case 2: pal = PALETTE_TO_GREEN; break;
       
   576 		}
       
   577 	}
       
   578 
       
   579 	/* Draw the gradient (background) */
       
   580 	DrawSprite(SPR_GRADIENT, GENERAL_SPRITE_COLOR(color), x, y);
       
   581 
       
   582 	for (CompanyManagerFaceVariable cmfv = CMFV_CHEEKS; cmfv < CMFV_END; cmfv++) {
       
   583 		switch (cmfv) {
       
   584 			case CMFV_MOUSTACHE:   if (!has_moustache)   continue; break;
       
   585 			case CMFV_LIPS:        /* FALL THROUGH */
       
   586 			case CMFV_NOSE:        if (has_moustache)    continue; break;
       
   587 			case CMFV_TIE_EARRING: if (!has_tie_earring) continue; break;
       
   588 			case CMFV_GLASSES:     if (!has_glasses)     continue; break;
       
   589 			default: break;
       
   590 		}
       
   591 		DrawSprite(GetCompanyManagerFaceSprite(cmf, cmfv, ge), (cmfv == CMFV_EYEBROWS) ? pal : PAL_NONE, x, y);
       
   592 	}
       
   593 }
       
   594 
       
   595 /** Widget description for the normal/simple company manager face selection dialog */
       
   596 static const Widget _select_company_manager_face_widgets[] = {
       
   597 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_GREY,     0,    10,     0,    13, STR_00C5,                STR_018B_CLOSE_WINDOW},              // SCMFW_WIDGET_CLOSEBOX
       
   598 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_GREY,    11,   174,     0,    13, STR_7043_FACE_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS},    // SCMFW_WIDGET_CAPTION
       
   599 {     WWT_IMGBTN,   RESIZE_NONE,  COLOUR_GREY,   175,   189,     0,    13, SPR_LARGE_SMALL_WINDOW,  STR_FACE_ADVANCED_TIP},              // SCMFW_WIDGET_TOGGLE_LARGE_SMALL
       
   600 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   189,    14,   150, 0x0,                     STR_NULL},                           // SCMFW_WIDGET_SELECT_FACE
       
   601 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     0,    94,   151,   162, STR_012E_CANCEL,         STR_7047_CANCEL_NEW_FACE_SELECTION}, // SCMFW_WIDGET_CANCEL
       
   602 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    95,   189,   151,   162, STR_012F_OK,             STR_7048_ACCEPT_NEW_FACE_SELECTION}, // SCMFW_WIDGET_ACCEPT
       
   603 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_GREY,    95,   187,    75,    86, STR_7044_MALE,           STR_7049_SELECT_MALE_FACES},         // SCMFW_WIDGET_MALE
       
   604 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_GREY,    95,   187,    87,    98, STR_7045_FEMALE,         STR_704A_SELECT_FEMALE_FACES},       // SCMFW_WIDGET_FEMALE
       
   605 { 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
       
   606 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    95,   187,    16,    27, STR_FACE_ADVANCED,       STR_FACE_ADVANCED_TIP},              // SCMFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON
       
   607 {   WIDGETS_END},
       
   608 };
       
   609 
       
   610 /** Widget description for the advanced company manager face selection dialog */
       
   611 static const Widget _select_company_manager_face_adv_widgets[] = {
       
   612 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_GREY,     0,    10,     0,    13, STR_00C5,                STR_018B_CLOSE_WINDOW},              // SCMFW_WIDGET_CLOSEBOX
       
   613 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_GREY,    11,   204,     0,    13, STR_7043_FACE_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS},    // SCMFW_WIDGET_CAPTION
       
   614 {     WWT_IMGBTN,   RESIZE_NONE,  COLOUR_GREY,   205,   219,     0,    13, SPR_LARGE_SMALL_WINDOW,  STR_FACE_SIMPLE_TIP},                // SCMFW_WIDGET_TOGGLE_LARGE_SMALL
       
   615 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   219,    14,   207, 0x0,                     STR_NULL},                           // SCMFW_WIDGET_SELECT_FACE
       
   616 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     0,    94,   208,   219, STR_012E_CANCEL,         STR_7047_CANCEL_NEW_FACE_SELECTION}, // SCMFW_WIDGET_CANCEL
       
   617 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    95,   219,   208,   219, STR_012F_OK,             STR_7048_ACCEPT_NEW_FACE_SELECTION}, // SCMFW_WIDGET_ACCEPT
       
   618 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_GREY,    96,   156,    32,    43, STR_7044_MALE,           STR_7049_SELECT_MALE_FACES},         // SCMFW_WIDGET_MALE
       
   619 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_GREY,   157,   217,    32,    43, STR_7045_FEMALE,         STR_704A_SELECT_FEMALE_FACES},       // SCMFW_WIDGET_FEMALE
       
   620 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     2,    93,   137,   148, STR_RANDOM,              STR_704B_GENERATE_RANDOM_NEW_FACE},  // SCMFW_WIDGET_RANDOM_NEW_FACE
       
   621 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    95,   217,    16,    27, STR_FACE_SIMPLE,         STR_FACE_SIMPLE_TIP},                // SCMFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON
       
   622 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     2,    93,   158,   169, STR_FACE_LOAD,           STR_FACE_LOAD_TIP},                  // SCMFW_WIDGET_LOAD
       
   623 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     2,    93,   170,   181, STR_FACE_FACECODE,       STR_FACE_FACECODE_TIP},              // SCMFW_WIDGET_FACECODE
       
   624 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     2,    93,   182,   193, STR_FACE_SAVE,           STR_FACE_SAVE_TIP},                  // SCMFW_WIDGET_SAVE
       
   625 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_GREY,    96,   156,    46,    57, STR_FACE_EUROPEAN,       STR_FACE_SELECT_EUROPEAN},           // SCMFW_WIDGET_ETHNICITY_EUR
       
   626 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_GREY,   157,   217,    46,    57, STR_FACE_AFRICAN,        STR_FACE_SELECT_AFRICAN},            // SCMFW_WIDGET_ETHNICITY_AFR
       
   627 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   175,   217,    60,    71, STR_EMPTY,               STR_FACE_MOUSTACHE_EARRING_TIP},     // SCMFW_WIDGET_HAS_MOUSTACHE_EARRING
       
   628 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   175,   217,    72,    83, STR_EMPTY,               STR_FACE_GLASSES_TIP},               // SCMFW_WIDGET_HAS_GLASSES
       
   629 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,   110,   121, SPR_ARROW_LEFT,          STR_FACE_EYECOLOUR_TIP},             // SCMFW_WIDGET_EYECOLOUR_L
       
   630 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,   110,   121, STR_EMPTY,               STR_FACE_EYECOLOUR_TIP},             // SCMFW_WIDGET_EYECOLOUR
       
   631 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,   110,   121, SPR_ARROW_RIGHT,         STR_FACE_EYECOLOUR_TIP},             // SCMFW_WIDGET_EYECOLOUR_R
       
   632 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,   158,   169, SPR_ARROW_LEFT,          STR_FACE_CHIN_TIP},                  // SCMFW_WIDGET_CHIN_L
       
   633 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,   158,   169, STR_EMPTY,               STR_FACE_CHIN_TIP},                  // SCMFW_WIDGET_CHIN
       
   634 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,   158,   169, SPR_ARROW_RIGHT,         STR_FACE_CHIN_TIP},                  // SCMFW_WIDGET_CHIN_R
       
   635 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,    98,   109, SPR_ARROW_LEFT,          STR_FACE_EYEBROWS_TIP},              // SCMFW_WIDGET_EYEBROWS_L
       
   636 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,    98,   109, STR_EMPTY,               STR_FACE_EYEBROWS_TIP},              // SCMFW_WIDGET_EYEBROWS
       
   637 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,    98,   109, SPR_ARROW_RIGHT,         STR_FACE_EYEBROWS_TIP},              // SCMFW_WIDGET_EYEBROWS_R
       
   638 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,   146,   157, SPR_ARROW_LEFT,          STR_FACE_LIPS_MOUSTACHE_TIP},        // SCMFW_WIDGET_LIPS_MOUSTACHE_L
       
   639 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,   146,   157, STR_EMPTY,               STR_FACE_LIPS_MOUSTACHE_TIP},        // SCMFW_WIDGET_LIPS_MOUSTACHE
       
   640 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,   146,   157, SPR_ARROW_RIGHT,         STR_FACE_LIPS_MOUSTACHE_TIP},        // SCMFW_WIDGET_LIPS_MOUSTACHE_R
       
   641 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,   134,   145, SPR_ARROW_LEFT,          STR_FACE_NOSE_TIP},                  // SCMFW_WIDGET_NOSE_L
       
   642 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,   134,   145, STR_EMPTY,               STR_FACE_NOSE_TIP},                  // SCMFW_WIDGET_NOSE
       
   643 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,   134,   145, SPR_ARROW_RIGHT,         STR_FACE_NOSE_TIP},                  // SCMFW_WIDGET_NOSE_R
       
   644 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,    86,    97, SPR_ARROW_LEFT,          STR_FACE_HAIR_TIP},                  // SCMFW_WIDGET_HAIR_L
       
   645 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,    86,    97, STR_EMPTY,               STR_FACE_HAIR_TIP},                  // SCMFW_WIDGET_HAIR
       
   646 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,    86,    97, SPR_ARROW_RIGHT,         STR_FACE_HAIR_TIP},                  // SCMFW_WIDGET_HAIR_R
       
   647 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,   170,   181, SPR_ARROW_LEFT,          STR_FACE_JACKET_TIP},                // SCMFW_WIDGET_JACKET_L
       
   648 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,   170,   181, STR_EMPTY,               STR_FACE_JACKET_TIP},                // SCMFW_WIDGET_JACKET
       
   649 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,   170,   181, SPR_ARROW_RIGHT,         STR_FACE_JACKET_TIP},                // SCMFW_WIDGET_JACKET_R
       
   650 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,   182,   193, SPR_ARROW_LEFT,          STR_FACE_COLLAR_TIP},                // SCMFW_WIDGET_COLLAR_L
       
   651 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,   182,   193, STR_EMPTY,               STR_FACE_COLLAR_TIP},                // SCMFW_WIDGET_COLLAR
       
   652 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,   182,   193, SPR_ARROW_RIGHT,         STR_FACE_COLLAR_TIP},                // SCMFW_WIDGET_COLLAR_R
       
   653 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,   194,   205, SPR_ARROW_LEFT,          STR_FACE_TIE_EARRING_TIP},           // SCMFW_WIDGET_TIE_EARRING_L
       
   654 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,   194,   205, STR_EMPTY,               STR_FACE_TIE_EARRING_TIP},           // SCMFW_WIDGET_TIE_EARRING
       
   655 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,   194,   205, SPR_ARROW_RIGHT,         STR_FACE_TIE_EARRING_TIP},           // SCMFW_WIDGET_TIE_EARRING_R
       
   656 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    175,  183,   122,   133, SPR_ARROW_LEFT,          STR_FACE_GLASSES_TIP_2},             // SCMFW_WIDGET_GLASSES_L
       
   657 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    184,  208,   122,   133, STR_EMPTY,               STR_FACE_GLASSES_TIP_2},             // SCMFW_WIDGET_GLASSES
       
   658 { WWT_PUSHIMGBTN,   RESIZE_NONE,  COLOUR_GREY,    209,  217,   122,   133, SPR_ARROW_RIGHT,         STR_FACE_GLASSES_TIP_2},             // SCMFW_WIDGET_GLASSES_R
       
   659 {   WIDGETS_END},
       
   660 };
       
   661 
       
   662 class SelectCompanyManagerFaceWindow : public Window
       
   663 {
       
   664 	CompanyManagerFace face; ///< company manager face bits
       
   665 	bool advanced; ///< advanced company manager face selection window
       
   666 
       
   667 	GenderEthnicity ge;
       
   668 	bool is_female;
       
   669 	bool is_moust_male;
       
   670 
       
   671 	/**
       
   672 	 * Names of the widgets. Keep them in the same order as in the widget array.
       
   673 	 * Do not change the order of the widgets from SCMFW_WIDGET_HAS_MOUSTACHE_EARRING to SCMFW_WIDGET_GLASSES_R,
       
   674 	 * this order is needed for the WE_CLICK event of DrawFaceStringLabel().
       
   675 	 */
       
   676 	enum SelectCompanyManagerFaceWidgets {
       
   677 		SCMFW_WIDGET_CLOSEBOX = 0,
       
   678 		SCMFW_WIDGET_CAPTION,
       
   679 		SCMFW_WIDGET_TOGGLE_LARGE_SMALL,
       
   680 		SCMFW_WIDGET_SELECT_FACE,
       
   681 		SCMFW_WIDGET_CANCEL,
       
   682 		SCMFW_WIDGET_ACCEPT,
       
   683 		SCMFW_WIDGET_MALE,
       
   684 		SCMFW_WIDGET_FEMALE,
       
   685 		SCMFW_WIDGET_RANDOM_NEW_FACE,
       
   686 		SCMFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON,
       
   687 		/* from here is the advanced company manager face selection window */
       
   688 		SCMFW_WIDGET_LOAD,
       
   689 		SCMFW_WIDGET_FACECODE,
       
   690 		SCMFW_WIDGET_SAVE,
       
   691 		SCMFW_WIDGET_ETHNICITY_EUR,
       
   692 		SCMFW_WIDGET_ETHNICITY_AFR,
       
   693 		SCMFW_WIDGET_HAS_MOUSTACHE_EARRING,
       
   694 		SCMFW_WIDGET_HAS_GLASSES,
       
   695 		SCMFW_WIDGET_EYECOLOUR_L,
       
   696 		SCMFW_WIDGET_EYECOLOUR,
       
   697 		SCMFW_WIDGET_EYECOLOUR_R,
       
   698 		SCMFW_WIDGET_CHIN_L,
       
   699 		SCMFW_WIDGET_CHIN,
       
   700 		SCMFW_WIDGET_CHIN_R,
       
   701 		SCMFW_WIDGET_EYEBROWS_L,
       
   702 		SCMFW_WIDGET_EYEBROWS,
       
   703 		SCMFW_WIDGET_EYEBROWS_R,
       
   704 		SCMFW_WIDGET_LIPS_MOUSTACHE_L,
       
   705 		SCMFW_WIDGET_LIPS_MOUSTACHE,
       
   706 		SCMFW_WIDGET_LIPS_MOUSTACHE_R,
       
   707 		SCMFW_WIDGET_NOSE_L,
       
   708 		SCMFW_WIDGET_NOSE,
       
   709 		SCMFW_WIDGET_NOSE_R,
       
   710 		SCMFW_WIDGET_HAIR_L,
       
   711 		SCMFW_WIDGET_HAIR,
       
   712 		SCMFW_WIDGET_HAIR_R,
       
   713 		SCMFW_WIDGET_JACKET_L,
       
   714 		SCMFW_WIDGET_JACKET,
       
   715 		SCMFW_WIDGET_JACKET_R,
       
   716 		SCMFW_WIDGET_COLLAR_L,
       
   717 		SCMFW_WIDGET_COLLAR,
       
   718 		SCMFW_WIDGET_COLLAR_R,
       
   719 		SCMFW_WIDGET_TIE_EARRING_L,
       
   720 		SCMFW_WIDGET_TIE_EARRING,
       
   721 		SCMFW_WIDGET_TIE_EARRING_R,
       
   722 		SCMFW_WIDGET_GLASSES_L,
       
   723 		SCMFW_WIDGET_GLASSES,
       
   724 		SCMFW_WIDGET_GLASSES_R,
       
   725 	};
       
   726 	/**
       
   727 	 * Draw dynamic a label to the left of the button and a value in the button
       
   728 	 *
       
   729 	 * @param widget_index   index of this widget in the window
       
   730 	 * @param str            the label which will be draw
       
   731 	 * @param val            the value which will be draw
       
   732 	 * @param is_bool_widget is it a bool button
       
   733 	 */
       
   734 	void DrawFaceStringLabel(byte widget_index, StringID str, uint8 val, bool is_bool_widget)
       
   735 	{
       
   736 		/* Write the label in gold (0x2) to the left of the button. */
       
   737 		DrawStringRightAligned(this->widget[widget_index].left - (is_bool_widget ? 5 : 14), this->widget[widget_index].top + 1, str, TC_GOLD);
       
   738 
       
   739 		if (!this->IsWidgetDisabled(widget_index)) {
       
   740 			if (is_bool_widget) {
       
   741 				/* if it a bool button write yes or no */
       
   742 				str = (val != 0) ? STR_FACE_YES : STR_FACE_NO;
       
   743 			} else {
       
   744 				/* else write the value + 1 */
       
   745 				SetDParam(0, val + 1);
       
   746 				str = STR_JUST_INT;
       
   747 			}
       
   748 
       
   749 			/* Draw the value/bool in white (0xC). If the button clicked adds 1px to x and y text coordinates (IsWindowWidgetLowered()). */
       
   750 			DrawStringCentered(this->widget[widget_index].left + (this->widget[widget_index].right - this->widget[widget_index].left) / 2 +
       
   751 				this->IsWidgetLowered(widget_index), this->widget[widget_index].top + 1 + this->IsWidgetLowered(widget_index), str, TC_WHITE);
       
   752 		}
       
   753 	}
       
   754 
       
   755 	void UpdateData()
       
   756 	{
       
   757 		this->ge = (GenderEthnicity)GB(this->face, _cmf_info[CMFV_GEN_ETHN].offset, _cmf_info[CMFV_GEN_ETHN].length); // get the gender and ethnicity
       
   758 		this->is_female = HasBit(this->ge, GENDER_FEMALE); // get the gender: 0 == male and 1 == female
       
   759 		this->is_moust_male = !is_female && GetCompanyManagerFaceBits(this->face, CMFV_HAS_MOUSTACHE, this->ge) != 0; // is a male face with moustache
       
   760 	}
       
   761 
       
   762 public:
       
   763 	SelectCompanyManagerFaceWindow(const WindowDesc *desc, Window *parent, bool advanced, int top, int left) : Window(desc, parent->window_number)
       
   764 	{
       
   765 		this->parent = parent;
       
   766 		this->caption_color = this->window_number;
       
   767 		this->face = GetCompany((CompanyID)this->window_number)->face;
       
   768 		this->advanced = advanced;
       
   769 
       
   770 		this->UpdateData();
       
   771 
       
   772 		/* Check if repositioning from default is required */
       
   773 		if (top != FIRST_GUI_CALL && left != FIRST_GUI_CALL) {
       
   774 			this->top = top;
       
   775 			this->left = left;
       
   776 		}
       
   777 
       
   778 		this->FindWindowPlacementAndResize(desc);
       
   779 	}
       
   780 
       
   781 	virtual void OnPaint()
       
   782 	{
       
   783 		/* lower the non-selected gender button */
       
   784 		this->SetWidgetLoweredState(SCMFW_WIDGET_MALE,  !this->is_female);
       
   785 		this->SetWidgetLoweredState(SCMFW_WIDGET_FEMALE, this->is_female);
       
   786 
       
   787 		/* advanced company manager face selection window */
       
   788 		if (this->advanced) {
       
   789 			/* lower the non-selected ethnicity button */
       
   790 			this->SetWidgetLoweredState(SCMFW_WIDGET_ETHNICITY_EUR, !HasBit(this->ge, ETHNICITY_BLACK));
       
   791 			this->SetWidgetLoweredState(SCMFW_WIDGET_ETHNICITY_AFR,  HasBit(this->ge, ETHNICITY_BLACK));
       
   792 
       
   793 
       
   794 			/* Disable dynamically the widgets which CompanyManagerFaceVariable has less than 2 options
       
   795 			* (or in other words you haven't any choice).
       
   796 			* If the widgets depend on a HAS-variable and this is false the widgets will be disabled, too. */
       
   797 
       
   798 			/* Eye colour buttons */
       
   799 			this->SetWidgetsDisabledState(_cmf_info[CMFV_EYE_COLOUR].valid_values[this->ge] < 2,
       
   800 				SCMFW_WIDGET_EYECOLOUR, SCMFW_WIDGET_EYECOLOUR_L, SCMFW_WIDGET_EYECOLOUR_R, WIDGET_LIST_END);
       
   801 
       
   802 			/* Chin buttons */
       
   803 			this->SetWidgetsDisabledState(_cmf_info[CMFV_CHIN].valid_values[this->ge] < 2,
       
   804 				SCMFW_WIDGET_CHIN, SCMFW_WIDGET_CHIN_L, SCMFW_WIDGET_CHIN_R, WIDGET_LIST_END);
       
   805 
       
   806 			/* Eyebrows buttons */
       
   807 			this->SetWidgetsDisabledState(_cmf_info[CMFV_EYEBROWS].valid_values[this->ge] < 2,
       
   808 				SCMFW_WIDGET_EYEBROWS, SCMFW_WIDGET_EYEBROWS_L, SCMFW_WIDGET_EYEBROWS_R, WIDGET_LIST_END);
       
   809 
       
   810 			/* Lips or (if it a male face with a moustache) moustache buttons */
       
   811 			this->SetWidgetsDisabledState(_cmf_info[this->is_moust_male ? CMFV_MOUSTACHE : CMFV_LIPS].valid_values[this->ge] < 2,
       
   812 				SCMFW_WIDGET_LIPS_MOUSTACHE, SCMFW_WIDGET_LIPS_MOUSTACHE_L, SCMFW_WIDGET_LIPS_MOUSTACHE_R, WIDGET_LIST_END);
       
   813 
       
   814 			/* Nose buttons | male faces with moustache haven't any nose options */
       
   815 			this->SetWidgetsDisabledState(_cmf_info[CMFV_NOSE].valid_values[this->ge] < 2 || this->is_moust_male,
       
   816 				SCMFW_WIDGET_NOSE, SCMFW_WIDGET_NOSE_L, SCMFW_WIDGET_NOSE_R, WIDGET_LIST_END);
       
   817 
       
   818 			/* Hair buttons */
       
   819 			this->SetWidgetsDisabledState(_cmf_info[CMFV_HAIR].valid_values[this->ge] < 2,
       
   820 				SCMFW_WIDGET_HAIR, SCMFW_WIDGET_HAIR_L, SCMFW_WIDGET_HAIR_R, WIDGET_LIST_END);
       
   821 
       
   822 			/* Jacket buttons */
       
   823 			this->SetWidgetsDisabledState(_cmf_info[CMFV_JACKET].valid_values[this->ge] < 2,
       
   824 				SCMFW_WIDGET_JACKET, SCMFW_WIDGET_JACKET_L, SCMFW_WIDGET_JACKET_R, WIDGET_LIST_END);
       
   825 
       
   826 			/* Collar buttons */
       
   827 			this->SetWidgetsDisabledState(_cmf_info[CMFV_COLLAR].valid_values[this->ge] < 2,
       
   828 				SCMFW_WIDGET_COLLAR, SCMFW_WIDGET_COLLAR_L, SCMFW_WIDGET_COLLAR_R, WIDGET_LIST_END);
       
   829 
       
   830 			/* Tie/earring buttons | female faces without earring haven't any earring options */
       
   831 			this->SetWidgetsDisabledState(_cmf_info[CMFV_TIE_EARRING].valid_values[this->ge] < 2 ||
       
   832 					(this->is_female && GetCompanyManagerFaceBits(this->face, CMFV_HAS_TIE_EARRING, this->ge) == 0),
       
   833 				SCMFW_WIDGET_TIE_EARRING, SCMFW_WIDGET_TIE_EARRING_L, SCMFW_WIDGET_TIE_EARRING_R, WIDGET_LIST_END);
       
   834 
       
   835 			/* Glasses buttons | faces without glasses haven't any glasses options */
       
   836 			this->SetWidgetsDisabledState(_cmf_info[CMFV_GLASSES].valid_values[this->ge] < 2 || GetCompanyManagerFaceBits(this->face, CMFV_HAS_GLASSES, this->ge) == 0,
       
   837 				SCMFW_WIDGET_GLASSES, SCMFW_WIDGET_GLASSES_L, SCMFW_WIDGET_GLASSES_R, WIDGET_LIST_END);
       
   838 		}
       
   839 
       
   840 		this->DrawWidgets();
       
   841 
       
   842 		/* Draw dynamic button value and labels for the advanced company manager face selection window */
       
   843 		if (this->advanced) {
       
   844 			if (this->is_female) {
       
   845 				/* Only for female faces */
       
   846 				this->DrawFaceStringLabel(SCMFW_WIDGET_HAS_MOUSTACHE_EARRING, STR_FACE_EARRING,   GetCompanyManagerFaceBits(this->face, CMFV_HAS_TIE_EARRING, this->ge), true );
       
   847 				this->DrawFaceStringLabel(SCMFW_WIDGET_TIE_EARRING,           STR_FACE_EARRING,   GetCompanyManagerFaceBits(this->face, CMFV_TIE_EARRING,     this->ge), false);
       
   848 			} else {
       
   849 				/* Only for male faces */
       
   850 				this->DrawFaceStringLabel(SCMFW_WIDGET_HAS_MOUSTACHE_EARRING, STR_FACE_MOUSTACHE, GetCompanyManagerFaceBits(this->face, CMFV_HAS_MOUSTACHE,   this->ge), true );
       
   851 				this->DrawFaceStringLabel(SCMFW_WIDGET_TIE_EARRING,           STR_FACE_TIE,       GetCompanyManagerFaceBits(this->face, CMFV_TIE_EARRING,     this->ge), false);
       
   852 			}
       
   853 			if (this->is_moust_male) {
       
   854 				/* Only for male faces with moustache */
       
   855 				this->DrawFaceStringLabel(SCMFW_WIDGET_LIPS_MOUSTACHE,        STR_FACE_MOUSTACHE, GetCompanyManagerFaceBits(this->face, CMFV_MOUSTACHE,       this->ge), false);
       
   856 			} else {
       
   857 				/* Only for female faces or male faces without moustache */
       
   858 				this->DrawFaceStringLabel(SCMFW_WIDGET_LIPS_MOUSTACHE,        STR_FACE_LIPS,      GetCompanyManagerFaceBits(this->face, CMFV_LIPS,            this->ge), false);
       
   859 			}
       
   860 			/* For all faces */
       
   861 			this->DrawFaceStringLabel(SCMFW_WIDGET_HAS_GLASSES,           STR_FACE_GLASSES,     GetCompanyManagerFaceBits(this->face, CMFV_HAS_GLASSES,     this->ge), true );
       
   862 			this->DrawFaceStringLabel(SCMFW_WIDGET_HAIR,                  STR_FACE_HAIR,        GetCompanyManagerFaceBits(this->face, CMFV_HAIR,            this->ge), false);
       
   863 			this->DrawFaceStringLabel(SCMFW_WIDGET_EYEBROWS,              STR_FACE_EYEBROWS,    GetCompanyManagerFaceBits(this->face, CMFV_EYEBROWS,        this->ge), false);
       
   864 			this->DrawFaceStringLabel(SCMFW_WIDGET_EYECOLOUR,             STR_FACE_EYECOLOUR,   GetCompanyManagerFaceBits(this->face, CMFV_EYE_COLOUR,      this->ge), false);
       
   865 			this->DrawFaceStringLabel(SCMFW_WIDGET_GLASSES,               STR_FACE_GLASSES,     GetCompanyManagerFaceBits(this->face, CMFV_GLASSES,         this->ge), false);
       
   866 			this->DrawFaceStringLabel(SCMFW_WIDGET_NOSE,                  STR_FACE_NOSE,        GetCompanyManagerFaceBits(this->face, CMFV_NOSE,            this->ge), false);
       
   867 			this->DrawFaceStringLabel(SCMFW_WIDGET_CHIN,                  STR_FACE_CHIN,        GetCompanyManagerFaceBits(this->face, CMFV_CHIN,            this->ge), false);
       
   868 			this->DrawFaceStringLabel(SCMFW_WIDGET_JACKET,                STR_FACE_JACKET,      GetCompanyManagerFaceBits(this->face, CMFV_JACKET,          this->ge), false);
       
   869 			this->DrawFaceStringLabel(SCMFW_WIDGET_COLLAR,                STR_FACE_COLLAR,      GetCompanyManagerFaceBits(this->face, CMFV_COLLAR,          this->ge), false);
       
   870 		}
       
   871 
       
   872 		/* Draw the company manager face picture */
       
   873 		DrawCompanyManagerFace(this->face, GetCompany((CompanyID)this->window_number)->colour, 2, 16);
       
   874 	}
       
   875 
       
   876 	virtual void OnClick(Point pt, int widget)
       
   877 	{
       
   878 		switch (widget) {
       
   879 			/* Toggle size, advanced/simple face selection */
       
   880 			case SCMFW_WIDGET_TOGGLE_LARGE_SMALL:
       
   881 			case SCMFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON: {
       
   882 				DoCommandP(0, 0, this->face, NULL, CMD_SET_COMPANY_MANAGER_FACE);
       
   883 
       
   884 				/* Backup some data before deletion */
       
   885 				int oldtop = this->top;     ///< current top position of the window before closing it
       
   886 				int oldleft = this->left;   ///< current top position of the window before closing it
       
   887 				bool adv = !this->advanced;
       
   888 				Window *parent = this->parent;
       
   889 
       
   890 				delete this;
       
   891 
       
   892 				/* Open up the (toggled size) Face selection window at the same position as the previous */
       
   893 				DoSelectCompanyManagerFace(parent, adv, oldtop, oldleft);
       
   894 			} break;
       
   895 
       
   896 
       
   897 			/* OK button */
       
   898 			case SCMFW_WIDGET_ACCEPT:
       
   899 				DoCommandP(0, 0, this->face, NULL, CMD_SET_COMPANY_MANAGER_FACE);
       
   900 				/* Fall-Through */
       
   901 
       
   902 			/* Cancel button */
       
   903 			case SCMFW_WIDGET_CANCEL:
       
   904 				delete this;
       
   905 				break;
       
   906 
       
   907 			/* Load button */
       
   908 			case SCMFW_WIDGET_LOAD:
       
   909 				this->face = _company_manager_face;
       
   910 				ScaleAllCompanyManagerFaceBits(this->face);
       
   911 				ShowErrorMessage(INVALID_STRING_ID, STR_FACE_LOAD_DONE, 0, 0);
       
   912 				this->UpdateData();
       
   913 				this->SetDirty();
       
   914 				break;
       
   915 
       
   916 			/* 'Company manager face number' button, view and/or set company manager face number */
       
   917 			case SCMFW_WIDGET_FACECODE:
       
   918 				SetDParam(0, this->face);
       
   919 				ShowQueryString(STR_JUST_INT, STR_FACE_FACECODE_CAPTION, 10 + 1, 0, this, CS_NUMERAL, QSF_NONE);
       
   920 				break;
       
   921 
       
   922 			/* Save button */
       
   923 			case SCMFW_WIDGET_SAVE:
       
   924 				_company_manager_face = this->face;
       
   925 				ShowErrorMessage(INVALID_STRING_ID, STR_FACE_SAVE_DONE, 0, 0);
       
   926 				break;
       
   927 
       
   928 			/* Toggle gender (male/female) button */
       
   929 			case SCMFW_WIDGET_MALE:
       
   930 			case SCMFW_WIDGET_FEMALE:
       
   931 				SetCompanyManagerFaceBits(this->face, CMFV_GENDER, this->ge, widget - SCMFW_WIDGET_MALE);
       
   932 				ScaleAllCompanyManagerFaceBits(this->face);
       
   933 				this->UpdateData();
       
   934 				this->SetDirty();
       
   935 				break;
       
   936 
       
   937 			/* Randomize face button */
       
   938 			case SCMFW_WIDGET_RANDOM_NEW_FACE:
       
   939 				RandomCompanyManagerFaceBits(this->face, this->ge, this->advanced);
       
   940 				this->UpdateData();
       
   941 				this->SetDirty();
       
   942 				break;
       
   943 
       
   944 			/* Toggle ethnicity (european/african) button */
       
   945 			case SCMFW_WIDGET_ETHNICITY_EUR:
       
   946 			case SCMFW_WIDGET_ETHNICITY_AFR:
       
   947 				SetCompanyManagerFaceBits(this->face, CMFV_ETHNICITY, this->ge, widget - SCMFW_WIDGET_ETHNICITY_EUR);
       
   948 				ScaleAllCompanyManagerFaceBits(this->face);
       
   949 				this->UpdateData();
       
   950 				this->SetDirty();
       
   951 				break;
       
   952 
       
   953 			default:
       
   954 				/* For all buttons from SCMFW_WIDGET_HAS_MOUSTACHE_EARRING to SCMFW_WIDGET_GLASSES_R is the same function.
       
   955 				* Therefor is this combined function.
       
   956 				* First it checks which CompanyManagerFaceVariable will be change and then
       
   957 				* a: invert the value for boolean variables
       
   958 				* or b: it checks inside of IncreaseCompanyManagerFaceBits() if a left (_L) butten is pressed and then decrease else increase the variable */
       
   959 				if (this->advanced && widget >= SCMFW_WIDGET_HAS_MOUSTACHE_EARRING && widget <= SCMFW_WIDGET_GLASSES_R) {
       
   960 					CompanyManagerFaceVariable cmfv; // which CompanyManagerFaceVariable shall be edited
       
   961 
       
   962 					if (widget < SCMFW_WIDGET_EYECOLOUR_L) { // Bool buttons
       
   963 						switch (widget - SCMFW_WIDGET_HAS_MOUSTACHE_EARRING) {
       
   964 							default: NOT_REACHED();
       
   965 							case 0: cmfv = this->is_female ? CMFV_HAS_TIE_EARRING : CMFV_HAS_MOUSTACHE; break; // Has earring/moustache button
       
   966 							case 1: cmfv = CMFV_HAS_GLASSES; break; // Has glasses button
       
   967 						}
       
   968 						SetCompanyManagerFaceBits(this->face, cmfv, this->ge, !GetCompanyManagerFaceBits(this->face, cmfv, this->ge));
       
   969 						ScaleAllCompanyManagerFaceBits(this->face);
       
   970 					} else { // Value buttons
       
   971 						switch ((widget - SCMFW_WIDGET_EYECOLOUR_L) / 3) {
       
   972 							default: NOT_REACHED();
       
   973 							case 0: cmfv = CMFV_EYE_COLOUR; break;  // Eye colour buttons
       
   974 							case 1: cmfv = CMFV_CHIN; break;        // Chin buttons
       
   975 							case 2: cmfv = CMFV_EYEBROWS; break;    // Eyebrows buttons
       
   976 							case 3: cmfv = this->is_moust_male ? CMFV_MOUSTACHE : CMFV_LIPS; break; // Moustache or lips buttons
       
   977 							case 4: cmfv = CMFV_NOSE; break;        // Nose buttons
       
   978 							case 5: cmfv = CMFV_HAIR; break;        // Hair buttons
       
   979 							case 6: cmfv = CMFV_JACKET; break;      // Jacket buttons
       
   980 							case 7: cmfv = CMFV_COLLAR; break;      // Collar buttons
       
   981 							case 8: cmfv = CMFV_TIE_EARRING; break; // Tie/earring buttons
       
   982 							case 9: cmfv = CMFV_GLASSES; break;     // Glasses buttons
       
   983 						}
       
   984 						/* 0 == left (_L), 1 == middle or 2 == right (_R) - button click */
       
   985 						IncreaseCompanyManagerFaceBits(this->face, cmfv, this->ge, (((widget - SCMFW_WIDGET_EYECOLOUR_L) % 3) != 0) ? 1 : -1);
       
   986 					}
       
   987 					this->UpdateData();
       
   988 					this->SetDirty();
       
   989 				}
       
   990 				break;
       
   991 		}
       
   992 	}
       
   993 
       
   994 	virtual void OnQueryTextFinished(char *str)
       
   995 	{
       
   996 		if (str == NULL) return;
       
   997 		/* Set a new company manager face number */
       
   998 		if (!StrEmpty(str)) {
       
   999 			this->face = strtoul(str, NULL, 10);
       
  1000 			ScaleAllCompanyManagerFaceBits(this->face);
       
  1001 			ShowErrorMessage(INVALID_STRING_ID, STR_FACE_FACECODE_SET, 0, 0);
       
  1002 			this->UpdateData();
       
  1003 			this->SetDirty();
       
  1004 		} else {
       
  1005 			ShowErrorMessage(INVALID_STRING_ID, STR_FACE_FACECODE_ERR, 0, 0);
       
  1006 		}
       
  1007 	}
       
  1008 };
       
  1009 
       
  1010 /** normal/simple company manager face selection window description */
       
  1011 static const WindowDesc _select_company_manager_face_desc = {
       
  1012 	WDP_AUTO, WDP_AUTO, 190, 163, 190, 163,
       
  1013 	WC_COMPANY_MANAGER_FACE, WC_NONE,
       
  1014 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
       
  1015 	_select_company_manager_face_widgets,
       
  1016 };
       
  1017 
       
  1018 /** advanced company manager face selection window description */
       
  1019 static const WindowDesc _select_company_manager_face_adv_desc = {
       
  1020 	WDP_AUTO, WDP_AUTO, 220, 220, 220, 220,
       
  1021 	WC_COMPANY_MANAGER_FACE, WC_NONE,
       
  1022 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
       
  1023 	_select_company_manager_face_adv_widgets,
       
  1024 };
       
  1025 
       
  1026 /**
       
  1027  * Open the simple/advanced company manager face selection window
       
  1028  *
       
  1029  * @param parent the parent company window
       
  1030  * @param adv    simple or advanced face selection window
       
  1031  * @param top    previous top position of the window
       
  1032  * @param left   previous left position of the window
       
  1033  */
       
  1034 static void DoSelectCompanyManagerFace(Window *parent, bool adv, int top, int left)
       
  1035 {
       
  1036 	if (!IsValidCompanyID((CompanyID)parent->window_number)) return;
       
  1037 
       
  1038 	if (BringWindowToFrontById(WC_COMPANY_MANAGER_FACE, parent->window_number)) return;
       
  1039 	new SelectCompanyManagerFaceWindow(adv ? &_select_company_manager_face_adv_desc : &_select_company_manager_face_desc, parent, adv, top, left); // simple or advanced window
       
  1040 }
       
  1041 
       
  1042 
       
  1043 /* Names of the widgets. Keep them in the same order as in the widget array */
       
  1044 enum CompanyWindowWidgets {
       
  1045 	CW_WIDGET_CLOSEBOX = 0,
       
  1046 	CW_WIDGET_CAPTION,
       
  1047 	CW_WIDGET_FACE,
       
  1048 	CW_WIDGET_NEW_FACE,
       
  1049 	CW_WIDGET_COLOR_SCHEME,
       
  1050 	CW_WIDGET_PRESIDENT_NAME,
       
  1051 	CW_WIDGET_COMPANY_NAME,
       
  1052 	CW_WIDGET_BUILD_VIEW_HQ,
       
  1053 	CW_WIDGET_RELOCATE_HQ,
       
  1054 	CW_WIDGET_BUY_SHARE,
       
  1055 	CW_WIDGET_SELL_SHARE,
       
  1056 	CW_WIDGET_COMPANY_PASSWORD,
       
  1057 };
       
  1058 
       
  1059 static const Widget _company_widgets[] = {
       
  1060 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_GREY,     0,    10,     0,    13, STR_00C5,                          STR_018B_CLOSE_WINDOW},
       
  1061 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_GREY,    11,   359,     0,    13, STR_7001,                          STR_018C_WINDOW_TITLE_DRAG_THIS},
       
  1062 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   359,    14,   157, 0x0,                               STR_NULL},
       
  1063 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,     0,    89,   158,   169, STR_7004_NEW_FACE,                 STR_7030_SELECT_NEW_FACE_FOR_PRESIDENT},
       
  1064 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,    90,   179,   158,   169, STR_7005_COLOR_SCHEME,             STR_7031_CHANGE_THE_COMPANY_VEHICLE},
       
  1065 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   180,   269,   158,   169, STR_7009_PRESIDENT_NAME,           STR_7032_CHANGE_THE_PRESIDENT_S},
       
  1066 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   270,   359,   158,   169, STR_7008_COMPANY_NAME,             STR_7033_CHANGE_THE_COMPANY_NAME},
       
  1067 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_GREY,   266,   355,    18,    29, STR_7072_VIEW_HQ,                  STR_7070_BUILD_COMPANY_HEADQUARTERS},
       
  1068 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_GREY,   266,   355,    32,    43, STR_RELOCATE_HQ,                   STR_RELOCATE_COMPANY_HEADQUARTERS},
       
  1069 { 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},
       
  1070 { 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},
       
  1071 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   266,   355,   138,   149, STR_COMPANY_PASSWORD,              STR_COMPANY_PASSWORD_TOOLTIP},
       
  1072 {   WIDGETS_END},
       
  1073 };
       
  1074 
       
  1075 
       
  1076 /**
       
  1077  * Draws text "Vehicles:" and number of all vehicle types, or "(none)"
       
  1078  * @param company ID of company to print statistics of
       
  1079  */
       
  1080 static void DrawCompanyVehiclesAmount(CompanyID company)
       
  1081 {
       
  1082 	const int x = 110;
       
  1083 	int y = 63;
       
  1084 	const Vehicle *v;
       
  1085 	uint train = 0;
       
  1086 	uint road  = 0;
       
  1087 	uint air   = 0;
       
  1088 	uint ship  = 0;
       
  1089 
       
  1090 	DrawString(x, y, STR_7039_VEHICLES, TC_FROMSTRING);
       
  1091 
       
  1092 	FOR_ALL_VEHICLES(v) {
       
  1093 		if (v->owner == company) {
       
  1094 			switch (v->type) {
       
  1095 				case VEH_TRAIN:    if (IsFrontEngine(v)) train++; break;
       
  1096 				case VEH_ROAD:     if (IsRoadVehFront(v)) road++; break;
       
  1097 				case VEH_AIRCRAFT: if (IsNormalAircraft(v)) air++; break;
       
  1098 				case VEH_SHIP:     ship++; break;
       
  1099 				default: break;
       
  1100 			}
       
  1101 		}
       
  1102 	}
       
  1103 
       
  1104 	if (train + road + air + ship == 0) {
       
  1105 		DrawString(x + 70, y, STR_7042_NONE, TC_FROMSTRING);
       
  1106 	} else {
       
  1107 		if (train != 0) {
       
  1108 			SetDParam(0, train);
       
  1109 			DrawString(x + 70, y, STR_TRAINS, TC_FROMSTRING);
       
  1110 			y += 10;
       
  1111 		}
       
  1112 
       
  1113 		if (road != 0) {
       
  1114 			SetDParam(0, road);
       
  1115 			DrawString(x + 70, y, STR_ROAD_VEHICLES, TC_FROMSTRING);
       
  1116 			y += 10;
       
  1117 		}
       
  1118 
       
  1119 		if (air != 0) {
       
  1120 			SetDParam(0, air);
       
  1121 			DrawString(x + 70, y, STR_AIRCRAFT, TC_FROMSTRING);
       
  1122 			y += 10;
       
  1123 		}
       
  1124 
       
  1125 		if (ship != 0) {
       
  1126 			SetDParam(0, ship);
       
  1127 			DrawString(x + 70, y, STR_SHIPS, TC_FROMSTRING);
       
  1128 		}
       
  1129 	}
       
  1130 }
       
  1131 
       
  1132 int GetAmountOwnedBy(const Company *c, Owner owner)
       
  1133 {
       
  1134 	return (c->share_owners[0] == owner) +
       
  1135 				 (c->share_owners[1] == owner) +
       
  1136 				 (c->share_owners[2] == owner) +
       
  1137 				 (c->share_owners[3] == owner);
       
  1138 }
       
  1139 
       
  1140 /**
       
  1141  * Draws list of all companies with shares
       
  1142  * @param c pointer to the Company structure
       
  1143  */
       
  1144 static void DrawCompanyOwnerText(const Company *c)
       
  1145 {
       
  1146 	const Company *c2;
       
  1147 	uint num = 0;
       
  1148 	const byte height = GetCharacterHeight(FS_NORMAL);
       
  1149 
       
  1150 	FOR_ALL_COMPANIES(c2) {
       
  1151 		uint amt = GetAmountOwnedBy(c, c2->index);
       
  1152 		if (amt != 0) {
       
  1153 			SetDParam(0, amt * 25);
       
  1154 			SetDParam(1, c2->index);
       
  1155 
       
  1156 			DrawString(120, (num++) * height + 116, STR_707D_OWNED_BY, TC_FROMSTRING);
       
  1157 		}
       
  1158 	}
       
  1159 }
       
  1160 
       
  1161 /**
       
  1162  * Window with general information about a company
       
  1163  */
       
  1164 struct CompanyWindow : Window
       
  1165 {
       
  1166 	CompanyWindowWidgets query_widget;
       
  1167 
       
  1168 	CompanyWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
       
  1169 	{
       
  1170 		this->caption_color = this->window_number;
       
  1171 		this->FindWindowPlacementAndResize(desc);
       
  1172 	}
       
  1173 
       
  1174 	virtual void OnPaint()
       
  1175 	{
       
  1176 		const Company *c = GetCompany((CompanyID)this->window_number);
       
  1177 		bool local = this->window_number == _local_company;
       
  1178 
       
  1179 		this->SetWidgetHiddenState(CW_WIDGET_NEW_FACE,       !local);
       
  1180 		this->SetWidgetHiddenState(CW_WIDGET_COLOR_SCHEME,   !local);
       
  1181 		this->SetWidgetHiddenState(CW_WIDGET_PRESIDENT_NAME, !local);
       
  1182 		this->SetWidgetHiddenState(CW_WIDGET_COMPANY_NAME,   !local);
       
  1183 		this->widget[CW_WIDGET_BUILD_VIEW_HQ].data = (local && c->location_of_HQ == 0) ? STR_706F_BUILD_HQ : STR_7072_VIEW_HQ;
       
  1184 		if (local && c->location_of_HQ != 0) this->widget[CW_WIDGET_BUILD_VIEW_HQ].type = WWT_PUSHTXTBTN; //HQ is already built.
       
  1185 		this->SetWidgetDisabledState(CW_WIDGET_BUILD_VIEW_HQ, !local && c->location_of_HQ == 0);
       
  1186 		this->SetWidgetHiddenState(CW_WIDGET_RELOCATE_HQ,      !local || c->location_of_HQ == 0);
       
  1187 		this->SetWidgetHiddenState(CW_WIDGET_BUY_SHARE,        local);
       
  1188 		this->SetWidgetHiddenState(CW_WIDGET_SELL_SHARE,       local);
       
  1189 		this->SetWidgetHiddenState(CW_WIDGET_COMPANY_PASSWORD, !local || !_networking);
       
  1190 
       
  1191 		if (!local) {
       
  1192 			if (_settings_game.economy.allow_shares) { // Shares are allowed
       
  1193 				/* If all shares are owned by someone (none by nobody), disable buy button */
       
  1194 				this->SetWidgetDisabledState(CW_WIDGET_BUY_SHARE, GetAmountOwnedBy(c, INVALID_OWNER) == 0 ||
       
  1195 						/* Only 25% left to buy. If the company is human, disable buying it up.. TODO issues! */
       
  1196 						(GetAmountOwnedBy(c, INVALID_OWNER) == 1 && !c->is_ai) ||
       
  1197 						/* Spectators cannot do anything of course */
       
  1198 						_local_company == COMPANY_SPECTATOR);
       
  1199 
       
  1200 				/* If the company doesn't own any shares, disable sell button */
       
  1201 				this->SetWidgetDisabledState(CW_WIDGET_SELL_SHARE, (GetAmountOwnedBy(c, _local_company) == 0) ||
       
  1202 						/* Spectators cannot do anything of course */
       
  1203 						_local_company == COMPANY_SPECTATOR);
       
  1204 			} else { // Shares are not allowed, disable buy/sell buttons
       
  1205 				this->DisableWidget(CW_WIDGET_BUY_SHARE);
       
  1206 				this->DisableWidget(CW_WIDGET_SELL_SHARE);
       
  1207 			}
       
  1208 		}
       
  1209 
       
  1210 		SetDParam(0, c->index);
       
  1211 		SetDParam(1, c->index);
       
  1212 
       
  1213 		this->DrawWidgets();
       
  1214 
       
  1215 		/* Company manager's face */
       
  1216 		DrawCompanyManagerFace(c->face, c->colour, 2, 16);
       
  1217 
       
  1218 		/* "xxx (Manager)" */
       
  1219 		SetDParam(0, c->index);
       
  1220 		DrawStringMultiCenter(48, 141, STR_7037_PRESIDENT, MAX_LENGTH_PRESIDENT_NAME_PIXELS);
       
  1221 
       
  1222 		/* "Inaugurated:" */
       
  1223 		SetDParam(0, c->inaugurated_year);
       
  1224 		DrawString(110, 23, STR_7038_INAUGURATED, TC_FROMSTRING);
       
  1225 
       
  1226 		/* "Colour scheme:" */
       
  1227 		DrawString(110, 43, STR_7006_COLOR_SCHEME, TC_FROMSTRING);
       
  1228 		/* Draw company-colour bus */
       
  1229 		DrawSprite(SPR_VEH_BUS_SW_VIEW, COMPANY_SPRITE_COLOR(c->index), 215, 44);
       
  1230 
       
  1231 		/* "Vehicles:" */
       
  1232 		DrawCompanyVehiclesAmount((CompanyID)this->window_number);
       
  1233 
       
  1234 		/* "Company value:" */
       
  1235 		SetDParam(0, CalculateCompanyValue(c));
       
  1236 		DrawString(110, 106, STR_7076_COMPANY_VALUE, TC_FROMSTRING);
       
  1237 
       
  1238 		/* Shares list */
       
  1239 		DrawCompanyOwnerText(c);
       
  1240 	}
       
  1241 
       
  1242 	virtual void OnClick(Point pt, int widget)
       
  1243 	{
       
  1244 		switch (widget) {
       
  1245 			case CW_WIDGET_NEW_FACE: DoSelectCompanyManagerFace(this, false); break;
       
  1246 
       
  1247 			case CW_WIDGET_COLOR_SCHEME:
       
  1248 				if (BringWindowToFrontById(WC_COMPANY_COLOR, this->window_number)) break;
       
  1249 				new SelectCompanyLiveryWindow(&_select_company_livery_desc, (CompanyID)this->window_number);
       
  1250 				break;
       
  1251 
       
  1252 			case CW_WIDGET_PRESIDENT_NAME:
       
  1253 				this->query_widget = CW_WIDGET_PRESIDENT_NAME;
       
  1254 				SetDParam(0, this->window_number);
       
  1255 				ShowQueryString(STR_PLAYER_NAME, STR_700B_PRESIDENT_S_NAME, MAX_LENGTH_PRESIDENT_NAME_BYTES, MAX_LENGTH_PRESIDENT_NAME_PIXELS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT);
       
  1256 				break;
       
  1257 
       
  1258 			case CW_WIDGET_COMPANY_NAME:
       
  1259 				this->query_widget = CW_WIDGET_COMPANY_NAME;
       
  1260 				SetDParam(0, this->window_number);
       
  1261 				ShowQueryString(STR_COMPANY_NAME, STR_700A_COMPANY_NAME, MAX_LENGTH_COMPANY_NAME_BYTES, MAX_LENGTH_COMPANY_NAME_PIXELS, this, CS_ALPHANUMERAL, QSF_ENABLE_DEFAULT);
       
  1262 				break;
       
  1263 
       
  1264 			case CW_WIDGET_BUILD_VIEW_HQ: {
       
  1265 				TileIndex tile = GetCompany((CompanyID)this->window_number)->location_of_HQ;
       
  1266 				if (tile == 0) {
       
  1267 					if ((byte)this->window_number != _local_company) return;
       
  1268 					SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, VHM_RECT, this);
       
  1269 					SetTileSelectSize(2, 2);
       
  1270 					this->LowerWidget(CW_WIDGET_BUILD_VIEW_HQ);
       
  1271 					this->InvalidateWidget(CW_WIDGET_BUILD_VIEW_HQ);
       
  1272 				} else {
       
  1273 					if (_ctrl_pressed) {
       
  1274 						ShowExtraViewPortWindow(tile);
       
  1275 					} else {
       
  1276 						ScrollMainWindowToTile(tile);
       
  1277 					}
       
  1278 				}
       
  1279 				break;
       
  1280 			}
       
  1281 
       
  1282 			case CW_WIDGET_RELOCATE_HQ:
       
  1283 				SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, VHM_RECT, this);
       
  1284 				SetTileSelectSize(2, 2);
       
  1285 				this->LowerWidget(CW_WIDGET_RELOCATE_HQ);
       
  1286 				this->InvalidateWidget(CW_WIDGET_RELOCATE_HQ);
       
  1287 				break;
       
  1288 
       
  1289 			case CW_WIDGET_BUY_SHARE:
       
  1290 				DoCommandP(0, this->window_number, 0, NULL, CMD_BUY_SHARE_IN_COMPANY | CMD_MSG(STR_707B_CAN_T_BUY_25_SHARE_IN_THIS));
       
  1291 				break;
       
  1292 
       
  1293 			case CW_WIDGET_SELL_SHARE:
       
  1294 				DoCommandP(0, this->window_number, 0, NULL, CMD_SELL_SHARE_IN_COMPANY | CMD_MSG(STR_707C_CAN_T_SELL_25_SHARE_IN));
       
  1295 				break;
       
  1296 
       
  1297 #ifdef ENABLE_NETWORK
       
  1298 			case CW_WIDGET_COMPANY_PASSWORD:
       
  1299 				if (this->window_number == _local_company) ShowNetworkCompanyPasswordWindow(this);
       
  1300 				break;
       
  1301 #endif /* ENABLE_NETWORK */
       
  1302 		}
       
  1303 	}
       
  1304 
       
  1305 	virtual void OnHundredthTick()
       
  1306 	{
       
  1307 		/* redraw the window every now and then */
       
  1308 		this->SetDirty();
       
  1309 	}
       
  1310 
       
  1311 	virtual void OnPlaceObject(Point pt, TileIndex tile)
       
  1312 	{
       
  1313 		if (DoCommandP(tile, 0, 0, NULL, CMD_BUILD_COMPANY_HQ | CMD_NO_WATER | CMD_MSG(STR_7071_CAN_T_BUILD_COMPANY_HEADQUARTERS)))
       
  1314 			ResetObjectToPlace();
       
  1315 			this->widget[CW_WIDGET_BUILD_VIEW_HQ].type = WWT_PUSHTXTBTN; // this button can now behave as a normal push button
       
  1316 			this->RaiseButtons();
       
  1317 	}
       
  1318 
       
  1319 	virtual void OnPlaceObjectAbort()
       
  1320 	{
       
  1321 		this->RaiseButtons();
       
  1322 	}
       
  1323 
       
  1324 	virtual void OnQueryTextFinished(char *str)
       
  1325 	{
       
  1326 		if (str == NULL) return;
       
  1327 
       
  1328 		_cmd_text = str;
       
  1329 		switch (this->query_widget) {
       
  1330 			default: NOT_REACHED();
       
  1331 
       
  1332 			case CW_WIDGET_PRESIDENT_NAME:
       
  1333 				DoCommandP(0, 0, 0, NULL, CMD_RENAME_PRESIDENT | CMD_MSG(STR_700D_CAN_T_CHANGE_PRESIDENT));
       
  1334 				break;
       
  1335 
       
  1336 			case CW_WIDGET_COMPANY_NAME:
       
  1337 				DoCommandP(0, 0, 0, NULL, CMD_RENAME_COMPANY | CMD_MSG(STR_700C_CAN_T_CHANGE_COMPANY_NAME));
       
  1338 				break;
       
  1339 		}
       
  1340 	}
       
  1341 };
       
  1342 
       
  1343 static const WindowDesc _company_desc = {
       
  1344 	WDP_AUTO, WDP_AUTO, 360, 170, 360, 170,
       
  1345 	WC_COMPANY, WC_NONE,
       
  1346 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
       
  1347 	_company_widgets,
       
  1348 };
       
  1349 
       
  1350 void ShowCompany(CompanyID company)
       
  1351 {
       
  1352 	if (!IsValidCompanyID(company)) return;
       
  1353 
       
  1354 	AllocateWindowDescFront<CompanyWindow>(&_company_desc, company);
       
  1355 }
       
  1356 
       
  1357 
       
  1358 
       
  1359 struct BuyCompanyWindow : Window {
       
  1360 	BuyCompanyWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
       
  1361 	{
       
  1362 		this->FindWindowPlacementAndResize(desc);
       
  1363 	}
       
  1364 
       
  1365 	virtual void OnPaint()
       
  1366 	{
       
  1367 		Company *c = GetCompany((CompanyID)this->window_number);
       
  1368 		SetDParam(0, STR_COMPANY_NAME);
       
  1369 		SetDParam(1, c->index);
       
  1370 		this->DrawWidgets();
       
  1371 
       
  1372 		DrawCompanyManagerFace(c->face, c->colour, 2, 16);
       
  1373 
       
  1374 		SetDParam(0, c->index);
       
  1375 		SetDParam(1, c->bankrupt_value);
       
  1376 		DrawStringMultiCenter(214, 65, STR_705B_WE_ARE_LOOKING_FOR_A_TRANSPORT, 238);
       
  1377 	}
       
  1378 
       
  1379 	virtual void OnClick(Point pt, int widget)
       
  1380 	{
       
  1381 		switch (widget) {
       
  1382 			case 3:
       
  1383 				delete this;
       
  1384 				break;
       
  1385 
       
  1386 			case 4:
       
  1387 				DoCommandP(0, this->window_number, 0, NULL, CMD_BUY_COMPANY | CMD_MSG(STR_7060_CAN_T_BUY_COMPANY));
       
  1388 				break;
       
  1389 		}
       
  1390 	}
       
  1391 };
       
  1392 
       
  1393 static const Widget _buy_company_widgets[] = {
       
  1394 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_LIGHT_BLUE,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},
       
  1395 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_LIGHT_BLUE,    11,   333,     0,    13, STR_00B3_MESSAGE_FROM, STR_018C_WINDOW_TITLE_DRAG_THIS},
       
  1396 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_LIGHT_BLUE,     0,   333,    14,   136, 0x0,                   STR_NULL},
       
  1397 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_LIGHT_BLUE,   148,   207,   117,   128, STR_00C9_NO,           STR_NULL},
       
  1398 {    WWT_TEXTBTN,   RESIZE_NONE,  COLOUR_LIGHT_BLUE,   218,   277,   117,   128, STR_00C8_YES,          STR_NULL},
       
  1399 {   WIDGETS_END},
       
  1400 };
       
  1401 
       
  1402 static const WindowDesc _buy_company_desc = {
       
  1403 	153, 171, 334, 137, 334, 137,
       
  1404 	WC_BUY_COMPANY, WC_NONE,
       
  1405 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
       
  1406 	_buy_company_widgets,
       
  1407 };
       
  1408 
       
  1409 
       
  1410 void ShowBuyCompanyDialog(CompanyID company)
       
  1411 {
       
  1412 	AllocateWindowDescFront<BuyCompanyWindow>(&_buy_company_desc, company);
       
  1413 }
       
  1414 
       
  1415 /********** HIGHSCORE and ENDGAME windows */
       
  1416 
       
  1417 extern StringID EndGameGetPerformanceTitleFromValue(uint value);
       
  1418 
       
  1419 
       
  1420 struct EndGameHighScoreBaseWindow : Window
       
  1421 {
       
  1422 	uint32 background_img;
       
  1423 	int8 rank;
       
  1424 
       
  1425 	EndGameHighScoreBaseWindow(const WindowDesc *desc) : Window(desc)
       
  1426 	{
       
  1427 	}
       
  1428 
       
  1429 	/* Always draw a maximized window and within there the centered background */
       
  1430 	void SetupHighScoreEndWindow(uint *x, uint *y)
       
  1431 	{
       
  1432 		/* resize window to "full-screen" */
       
  1433 		this->width = _screen.width;
       
  1434 		this->height = _screen.height;
       
  1435 		this->widget[0].right = this->width - 1;
       
  1436 		this->widget[0].bottom = this->height - 1;
       
  1437 
       
  1438 		this->DrawWidgets();
       
  1439 
       
  1440 		/* Center Highscore/Endscreen background */
       
  1441 		*x = max(0, (_screen.width  / 2) - (640 / 2));
       
  1442 		*y = max(0, (_screen.height / 2) - (480 / 2));
       
  1443 		for (uint i = 0; i < 10; i++) { // the image is split into 10 50px high parts
       
  1444 			DrawSprite(this->background_img + i, PAL_NONE, *x, *y + (i * 50));
       
  1445 		}
       
  1446 	}
       
  1447 
       
  1448 	virtual void OnClick(Point pt, int widget)
       
  1449 	{
       
  1450 		delete this;
       
  1451 	}
       
  1452 };
       
  1453 
       
  1454 /** End game window shown at the end of the game */
       
  1455 struct EndGameWindow : EndGameHighScoreBaseWindow {
       
  1456 	EndGameWindow(const WindowDesc *desc) : EndGameHighScoreBaseWindow(desc)
       
  1457 	{
       
  1458 		/* Pause in single-player to have a look at the highscore at your own leisure */
       
  1459 		if (!_networking) DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
       
  1460 
       
  1461 		this->background_img = SPR_TYCOON_IMG1_BEGIN;
       
  1462 
       
  1463 		if (_local_company != COMPANY_SPECTATOR) {
       
  1464 			const Company *c = GetCompany(_local_company);
       
  1465 			if (c->old_economy[0].performance_history == SCORE_MAX) {
       
  1466 				this->background_img = SPR_TYCOON_IMG2_BEGIN;
       
  1467 			}
       
  1468 		}
       
  1469 
       
  1470 		/* In a network game show the endscores of the custom difficulty 'network' which is the last one
       
  1471 		 * as well as generate a TOP5 of that game, and not an all-time top5. */
       
  1472 		if (_networking) {
       
  1473 			this->window_number = lengthof(_highscore_table) - 1;
       
  1474 			this->rank = SaveHighScoreValueNetwork();
       
  1475 		} else {
       
  1476 			/* in single player _local company is always valid */
       
  1477 			const Company *c = GetCompany(_local_company);
       
  1478 			this->window_number = _settings_game.difficulty.diff_level;
       
  1479 			this->rank = SaveHighScoreValue(c);
       
  1480 		}
       
  1481 
       
  1482 		MarkWholeScreenDirty();
       
  1483 	}
       
  1484 
       
  1485 	~EndGameWindow()
       
  1486 	{
       
  1487 		if (!_networking) DoCommandP(0, 0, 0, NULL, CMD_PAUSE); // unpause
       
  1488 		ShowHighscoreTable(this->window_number, this->rank);
       
  1489 	}
       
  1490 
       
  1491 	virtual void OnPaint()
       
  1492 	{
       
  1493 		const Company *c;
       
  1494 		uint x, y;
       
  1495 
       
  1496 		this->SetupHighScoreEndWindow(&x, &y);
       
  1497 
       
  1498 		if (!IsValidCompanyID(_local_company)) return;
       
  1499 
       
  1500 		c = GetCompany(_local_company);
       
  1501 		/* We need to get performance from last year because the image is shown
       
  1502 		 * at the start of the new year when these things have already been copied */
       
  1503 		if (this->background_img == SPR_TYCOON_IMG2_BEGIN) { // Tycoon of the century \o/
       
  1504 			SetDParam(0, c->index);
       
  1505 			SetDParam(1, c->index);
       
  1506 			SetDParam(2, EndGameGetPerformanceTitleFromValue(c->old_economy[0].performance_history));
       
  1507 			DrawStringMultiCenter(x + (640 / 2), y + 107, STR_021C_OF_ACHIEVES_STATUS, 640);
       
  1508 		} else {
       
  1509 			SetDParam(0, c->index);
       
  1510 			SetDParam(1, EndGameGetPerformanceTitleFromValue(c->old_economy[0].performance_history));
       
  1511 			DrawStringMultiCenter(x + (640 / 2), y + 157, STR_021B_ACHIEVES_STATUS, 640);
       
  1512 		}
       
  1513 	}
       
  1514 };
       
  1515 
       
  1516 struct HighScoreWindow : EndGameHighScoreBaseWindow
       
  1517 {
       
  1518 	HighScoreWindow(const WindowDesc *desc, int difficulty, int8 ranking) : EndGameHighScoreBaseWindow(desc)
       
  1519 	{
       
  1520 		/* pause game to show the chart */
       
  1521 		if (!_networking) DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
       
  1522 
       
  1523 		/* Close all always on-top windows to get a clean screen */
       
  1524 		if (_game_mode != GM_MENU) HideVitalWindows();
       
  1525 
       
  1526 		MarkWholeScreenDirty();
       
  1527 		this->window_number = difficulty; // show highscore chart for difficulty...
       
  1528 		this->background_img = SPR_HIGHSCORE_CHART_BEGIN; // which background to show
       
  1529 		this->rank = ranking;
       
  1530 	}
       
  1531 
       
  1532 	~HighScoreWindow()
       
  1533 	{
       
  1534 		if (_game_mode != GM_MENU) ShowVitalWindows();
       
  1535 
       
  1536 		if (!_networking) DoCommandP(0, 0, 0, NULL, CMD_PAUSE); // unpause
       
  1537 	}
       
  1538 
       
  1539 	virtual void OnPaint()
       
  1540 	{
       
  1541 		const HighScore *hs = _highscore_table[this->window_number];
       
  1542 		uint x, y;
       
  1543 
       
  1544 		this->SetupHighScoreEndWindow(&x, &y);
       
  1545 
       
  1546 		SetDParam(0, _settings_client.gui.ending_year);
       
  1547 		SetDParam(1, this->window_number + STR_6801_EASY);
       
  1548 		DrawStringMultiCenter(x + (640 / 2), y + 62, !_networking ? STR_0211_TOP_COMPANIES_WHO_REACHED : STR_TOP_COMPANIES_NETWORK_GAME, 500);
       
  1549 
       
  1550 		/* Draw Highscore peepz */
       
  1551 		for (uint8 i = 0; i < lengthof(_highscore_table[0]); i++) {
       
  1552 			SetDParam(0, i + 1);
       
  1553 			DrawString(x + 40, y + 140 + (i * 55), STR_0212, TC_BLACK);
       
  1554 
       
  1555 			if (hs[i].company[0] != '\0') {
       
  1556 				TextColour colour = (this->rank == i) ? TC_RED : TC_BLACK; // draw new highscore in red
       
  1557 
       
  1558 				DoDrawString(hs[i].company, x + 71, y + 140 + (i * 55), colour);
       
  1559 				SetDParam(0, hs[i].title);
       
  1560 				SetDParam(1, hs[i].score);
       
  1561 				DrawString(x + 71, y + 160 + (i * 55), STR_HIGHSCORE_STATS, colour);
       
  1562 			}
       
  1563 		}
       
  1564 	}
       
  1565 };
       
  1566 
       
  1567 static const Widget _highscore_widgets[] = {
       
  1568 {      WWT_PANEL, RESIZE_NONE,  COLOUR_END, 0, 640, 0, 480, 0x0, STR_NULL},
       
  1569 {   WIDGETS_END},
       
  1570 };
       
  1571 
       
  1572 static const WindowDesc _highscore_desc = {
       
  1573 	0, 0, 641, 481, 641, 481,
       
  1574 	WC_HIGHSCORE, WC_NONE,
       
  1575 	0,
       
  1576 	_highscore_widgets,
       
  1577 };
       
  1578 
       
  1579 static const WindowDesc _endgame_desc = {
       
  1580 	0, 0, 641, 481, 641, 481,
       
  1581 	WC_ENDSCREEN, WC_NONE,
       
  1582 	0,
       
  1583 	_highscore_widgets,
       
  1584 };
       
  1585 
       
  1586 /** Show the highscore table for a given difficulty. When called from
       
  1587  * endgame ranking is set to the top5 element that was newly added
       
  1588  * and is thus highlighted */
       
  1589 void ShowHighscoreTable(int difficulty, int8 ranking)
       
  1590 {
       
  1591 	DeleteWindowByClass(WC_HIGHSCORE);
       
  1592 	new HighScoreWindow(&_highscore_desc, difficulty, ranking);
       
  1593 }
       
  1594 
       
  1595 /** Show the endgame victory screen in 2050. Update the new highscore
       
  1596  * if it was high enough */
       
  1597 void ShowEndGameChart()
       
  1598 {
       
  1599 	/* Dedicated server doesn't need the highscore window */
       
  1600 	if (_network_dedicated) return;
       
  1601 
       
  1602 	HideVitalWindows();
       
  1603 	DeleteWindowByClass(WC_ENDSCREEN);
       
  1604 	new EndGameWindow(&_endgame_desc);
       
  1605 }