src/graph_gui.cpp
branchcustombridgeheads
changeset 5649 55c8267c933f
parent 5643 3778051e8095
child 5650 aefc131bf5ce
equal deleted inserted replaced
5648:1608018c5ff2 5649:55c8267c933f
       
     1 /* $Id$ */
       
     2 
       
     3 #include "stdafx.h"
       
     4 #include "openttd.h"
       
     5 #include "table/strings.h"
       
     6 #include "table/sprites.h"
       
     7 #include "functions.h"
       
     8 #include "window.h"
       
     9 #include "gui.h"
       
    10 #include "gfx.h"
       
    11 #include "player.h"
       
    12 #include "economy.h"
       
    13 #include "signs.h"
       
    14 #include "strings.h"
       
    15 #include "debug.h"
       
    16 #include "variables.h"
       
    17 #include "date.h"
       
    18 
       
    19 const byte _cargo_colours[NUM_CARGO] = {152, 32, 15, 174, 208, 194, 191, 84, 184, 10, 202, 48};
       
    20 
       
    21 static uint _legend_excludebits;
       
    22 static uint _legend_cargobits;
       
    23 
       
    24 /************************/
       
    25 /* GENERIC GRAPH DRAWER */
       
    26 /************************/
       
    27 
       
    28 enum {GRAPH_NUM = 16};
       
    29 
       
    30 typedef struct GraphDrawer {
       
    31 	uint sel; // bitmask of the players *excluded* (e.g. 11111111 means that no players are shown)
       
    32 	byte num_dataset;
       
    33 	byte num_on_x_axis;
       
    34 	byte month;
       
    35 	Year year;
       
    36 	bool include_neg;
       
    37 	byte num_vert_lines;
       
    38 	uint16 unk61A;
       
    39 	uint16 unk61C;
       
    40 	int left, top;
       
    41 	uint height;
       
    42 	StringID format_str_y_axis;
       
    43 	byte color_3, color_2, bg_line_color;
       
    44 	byte colors[GRAPH_NUM];
       
    45 	uint64 cost[GRAPH_NUM][24]; // last 2 years
       
    46 } GraphDrawer;
       
    47 
       
    48 #define INVALID_VALUE 0x80000000
       
    49 
       
    50 static void DrawGraph(const GraphDrawer *gw)
       
    51 {
       
    52 
       
    53 	int i,j,k;
       
    54 	uint x,y,old_x,old_y;
       
    55 	int color;
       
    56 	int right, bottom;
       
    57 	int num_x, num_dataset;
       
    58 	const uint64 *row_ptr, *col_ptr;
       
    59 	int64 mx;
       
    60 	int adj_height;
       
    61 	uint64 y_scaling, tmp;
       
    62 	int64 value;
       
    63 	int64 cur_val;
       
    64 	uint sel;
       
    65 
       
    66 	/* the colors and cost array of GraphDrawer must accomodate
       
    67 	 * both values for cargo and players. So if any are higher, quit */
       
    68 	assert(GRAPH_NUM >= NUM_CARGO && GRAPH_NUM >= MAX_PLAYERS);
       
    69 
       
    70 	color = _colour_gradient[gw->bg_line_color][4];
       
    71 
       
    72 	/* draw the vertical lines */
       
    73 	i = gw->num_vert_lines; assert(i > 0);
       
    74 	x = gw->left + 66;
       
    75 	bottom = gw->top + gw->height - 1;
       
    76 	do {
       
    77 		GfxFillRect(x, gw->top, x, bottom, color);
       
    78 		x += 22;
       
    79 	} while (--i);
       
    80 
       
    81 	/* draw the horizontal lines */
       
    82 	i = 9;
       
    83 	x = gw->left + 44;
       
    84 	y = gw->height + gw->top;
       
    85 	right = gw->left + 44 + gw->num_vert_lines*22-1;
       
    86 
       
    87 	do {
       
    88 		GfxFillRect(x, y, right, y, color);
       
    89 		y -= gw->height >> 3;
       
    90 	} while (--i);
       
    91 
       
    92 	/* draw vertical edge line */
       
    93 	GfxFillRect(x, gw->top, x, bottom, gw->color_2);
       
    94 
       
    95 	adj_height = gw->height;
       
    96 	if (gw->include_neg) adj_height >>= 1;
       
    97 
       
    98 	/* draw horiz edge line */
       
    99 	y = adj_height + gw->top;
       
   100 	GfxFillRect(x, y, right, y, gw->color_2);
       
   101 
       
   102 	/* find the max element */
       
   103 	if (gw->num_on_x_axis == 0)
       
   104 		return;
       
   105 
       
   106 	num_dataset = gw->num_dataset;
       
   107 	assert(num_dataset > 0);
       
   108 
       
   109 	row_ptr = gw->cost[0];
       
   110 	mx = 0;
       
   111 		/* bit selection for the showing of various players, base max element
       
   112 		 * on to-be shown player-information. This way the graph can scale */
       
   113 	sel = gw->sel;
       
   114 	do {
       
   115 		if (!(sel&1)) {
       
   116 			num_x = gw->num_on_x_axis;
       
   117 			assert(num_x > 0);
       
   118 			col_ptr = row_ptr;
       
   119 			do {
       
   120 				if (*col_ptr != INVALID_VALUE) {
       
   121 					mx = max64(mx, myabs64(*col_ptr));
       
   122 				}
       
   123 			} while (col_ptr++, --num_x);
       
   124 		}
       
   125 	} while (sel>>=1, row_ptr+=24, --num_dataset);
       
   126 
       
   127 	/* setup scaling */
       
   128 	y_scaling = INVALID_VALUE;
       
   129 	value = adj_height * 2;
       
   130 
       
   131 	if (mx > value) {
       
   132 		mx = (mx + 7) & ~7;
       
   133 		y_scaling = (((uint64) (value>>1) << 32) / mx);
       
   134 		value = mx;
       
   135 	}
       
   136 
       
   137 	/* draw text strings on the y axis */
       
   138 	tmp = value;
       
   139 	if (gw->include_neg) tmp >>= 1;
       
   140 	x = gw->left + 45;
       
   141 	y = gw->top - 3;
       
   142 	i = 9;
       
   143 	do {
       
   144 		SetDParam(0, gw->format_str_y_axis);
       
   145 		SetDParam64(1, (int64)tmp);
       
   146 		tmp -= (value >> 3);
       
   147 		DrawStringRightAligned(x, y, STR_0170, gw->color_3);
       
   148 		y += gw->height >> 3;
       
   149 	} while (--i);
       
   150 
       
   151 	/* draw strings on the x axis */
       
   152 	if (gw->month != 0xFF) {
       
   153 		x = gw->left + 44;
       
   154 		y = gw->top + gw->height + 1;
       
   155 		j = gw->month;
       
   156 		k = gw->year;
       
   157 		i = gw->num_on_x_axis;assert(i>0);
       
   158 		do {
       
   159 			SetDParam(2, k);
       
   160 			SetDParam(0, j + STR_0162_JAN);
       
   161 			SetDParam(1, j + STR_0162_JAN + 2);
       
   162 			DrawString(x, y, j == 0 ? STR_016F : STR_016E, gw->color_3);
       
   163 
       
   164 			j += 3;
       
   165 			if (j >= 12) {
       
   166 				j = 0;
       
   167 				k++;
       
   168 			}
       
   169 			x += 22;
       
   170 		} while (--i);
       
   171 	} else {
       
   172 		x = gw->left + 52;
       
   173 		y = gw->top + gw->height + 1;
       
   174 		j = gw->unk61A;
       
   175 		i = gw->num_on_x_axis;assert(i>0);
       
   176 		do {
       
   177 			SetDParam(0, j);
       
   178 			DrawString(x, y, STR_01CB, gw->color_3);
       
   179 			j += gw->unk61C;
       
   180 			x += 22;
       
   181 		} while (--i);
       
   182 	}
       
   183 
       
   184 	/* draw lines and dots */
       
   185 	i = 0;
       
   186 	row_ptr = gw->cost[0];
       
   187 	sel = gw->sel; // show only selected lines. GraphDrawer qw->sel set in Graph-Legend (_legend_excludebits)
       
   188 	do {
       
   189 		if (!(sel & 1)) {
       
   190 			x = gw->left + 55;
       
   191 			j = gw->num_on_x_axis;assert(j>0);
       
   192 			col_ptr = row_ptr;
       
   193 			color = gw->colors[i];
       
   194 			old_y = old_x = INVALID_VALUE;
       
   195 			do {
       
   196 				cur_val = *col_ptr++;
       
   197 				if (cur_val != INVALID_VALUE) {
       
   198 					y = adj_height - BIGMULSS64(cur_val, y_scaling >> 1, 31) + gw->top;
       
   199 
       
   200 					GfxFillRect(x-1, y-1, x+1, y+1, color);
       
   201 					if (old_x != INVALID_VALUE)
       
   202 						GfxDrawLine(old_x, old_y, x, y, color);
       
   203 
       
   204 					old_x = x;
       
   205 					old_y = y;
       
   206 				} else {
       
   207 					old_x = INVALID_VALUE;
       
   208 				}
       
   209 			} while (x+=22,--j);
       
   210 		}
       
   211 	} while (sel>>=1,row_ptr+=24, ++i < gw->num_dataset);
       
   212 }
       
   213 
       
   214 /****************/
       
   215 /* GRAPH LEGEND */
       
   216 /****************/
       
   217 
       
   218 void DrawPlayerIcon(PlayerID p, int x, int y)
       
   219 {
       
   220 	DrawSprite(SPRITE_PALETTE(PLAYER_SPRITE_COLOR(p) + 0x2EB), x, y);
       
   221 }
       
   222 
       
   223 static void GraphLegendWndProc(Window *w, WindowEvent *e)
       
   224 {
       
   225 	const Player* p;
       
   226 
       
   227 	switch (e->event) {
       
   228 	case WE_CREATE: {
       
   229 		uint i;
       
   230 		for (i = 3; i < w->widget_count; i++) {
       
   231 			if (!HASBIT(_legend_excludebits, i - 3)) LowerWindowWidget(w, i);
       
   232 		}
       
   233 		break;
       
   234 	}
       
   235 
       
   236 	case WE_PAINT:
       
   237 		FOR_ALL_PLAYERS(p) {
       
   238 			if (!p->is_active) {
       
   239 				SETBIT(_legend_excludebits, p->index);
       
   240 				RaiseWindowWidget(w, p->index + 3);
       
   241 			}
       
   242 		}
       
   243 		DrawWindowWidgets(w);
       
   244 
       
   245 		FOR_ALL_PLAYERS(p) {
       
   246 			if (!p->is_active) continue;
       
   247 
       
   248 			DrawPlayerIcon(p->index, 4, 18+p->index*12);
       
   249 
       
   250 			SetDParam(0, p->name_1);
       
   251 			SetDParam(1, p->name_2);
       
   252 			SetDParam(2, GetPlayerNameString(p->index, 3));
       
   253 			DrawString(21,17+p->index*12,STR_7021,HASBIT(_legend_excludebits, p->index) ? 0x10 : 0xC);
       
   254 		}
       
   255 		break;
       
   256 
       
   257 	case WE_CLICK:
       
   258 		if (IS_INT_INSIDE(e->we.click.widget, 3, 11)) {
       
   259 			_legend_excludebits ^= (1 << (e->we.click.widget - 3));
       
   260 			ToggleWidgetLoweredState(w, e->we.click.widget);
       
   261 			SetWindowDirty(w);
       
   262 			InvalidateWindow(WC_INCOME_GRAPH, 0);
       
   263 			InvalidateWindow(WC_OPERATING_PROFIT, 0);
       
   264 			InvalidateWindow(WC_DELIVERED_CARGO, 0);
       
   265 			InvalidateWindow(WC_PERFORMANCE_HISTORY, 0);
       
   266 			InvalidateWindow(WC_COMPANY_VALUE, 0);
       
   267 		}
       
   268 		break;
       
   269 	}
       
   270 }
       
   271 
       
   272 static const Widget _graph_legend_widgets[] = {
       
   273 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},
       
   274 {    WWT_CAPTION,   RESIZE_NONE,    14,    11,   249,     0,    13, STR_704E_KEY_TO_COMPANY_GRAPHS, STR_018C_WINDOW_TITLE_DRAG_THIS},
       
   275 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   249,    14,   113, 0x0,                            STR_NULL},
       
   276 {      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    16,    27, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
       
   277 {      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    28,    39, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
       
   278 {      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    40,    51, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
       
   279 {      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    52,    63, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
       
   280 {      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    64,    75, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
       
   281 {      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    76,    87, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
       
   282 {      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,    88,    99, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
       
   283 {      WWT_PANEL,   RESIZE_NONE,    14,     2,   247,   100,   111, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
       
   284 {   WIDGETS_END},
       
   285 };
       
   286 
       
   287 static const WindowDesc _graph_legend_desc = {
       
   288 	WDP_AUTO, WDP_AUTO, 250, 114,
       
   289 	WC_GRAPH_LEGEND,0,
       
   290 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
       
   291 	_graph_legend_widgets,
       
   292 	GraphLegendWndProc
       
   293 };
       
   294 
       
   295 static void ShowGraphLegend(void)
       
   296 {
       
   297 	AllocateWindowDescFront(&_graph_legend_desc, 0);
       
   298 }
       
   299 
       
   300 /********************/
       
   301 /* OPERATING PROFIT */
       
   302 /********************/
       
   303 
       
   304 static void SetupGraphDrawerForPlayers(GraphDrawer *gd)
       
   305 {
       
   306 	const Player* p;
       
   307 	uint excludebits = _legend_excludebits;
       
   308 	int nums;
       
   309 	int mo,yr;
       
   310 
       
   311 	// Exclude the players which aren't valid
       
   312 	FOR_ALL_PLAYERS(p) {
       
   313 		if (!p->is_active) SETBIT(excludebits,p->index);
       
   314 	}
       
   315 	gd->sel = excludebits;
       
   316 	gd->num_vert_lines = 24;
       
   317 
       
   318 	nums = 0;
       
   319 	FOR_ALL_PLAYERS(p) {
       
   320 		if (p->is_active) nums = max(nums,p->num_valid_stat_ent);
       
   321 	}
       
   322 	gd->num_on_x_axis = min(nums,24);
       
   323 
       
   324 	mo = (_cur_month/3-nums)*3;
       
   325 	yr = _cur_year;
       
   326 	while (mo < 0) {
       
   327 		yr--;
       
   328 		mo += 12;
       
   329 	}
       
   330 
       
   331 	gd->year = yr;
       
   332 	gd->month = mo;
       
   333 }
       
   334 
       
   335 static void OperatingProfitWndProc(Window *w, WindowEvent *e)
       
   336 {
       
   337 	switch (e->event) {
       
   338 	case WE_PAINT: {
       
   339 		GraphDrawer gd;
       
   340 		const Player* p;
       
   341 		int i,j;
       
   342 		int numd;
       
   343 
       
   344 		DrawWindowWidgets(w);
       
   345 
       
   346 		gd.left = 2;
       
   347 		gd.top = 18;
       
   348 		gd.height = 136;
       
   349 		gd.include_neg = true;
       
   350 		gd.format_str_y_axis = STR_CURRCOMPACT;
       
   351 		gd.color_3 = 0x10;
       
   352 		gd.color_2 = 0xD7;
       
   353 		gd.bg_line_color = 0xE;
       
   354 
       
   355 		SetupGraphDrawerForPlayers(&gd);
       
   356 
       
   357 		numd = 0;
       
   358 		FOR_ALL_PLAYERS(p) {
       
   359 			if (p->is_active) {
       
   360 				gd.colors[numd] = _colour_gradient[p->player_color][6];
       
   361 				for (j = gd.num_on_x_axis, i = 0; --j >= 0;) {
       
   362 					gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_VALUE : (uint64)(p->old_economy[j].income + p->old_economy[j].expenses);
       
   363 					i++;
       
   364 				}
       
   365 			}
       
   366 			numd++;
       
   367 		}
       
   368 
       
   369 		gd.num_dataset = numd;
       
   370 
       
   371 		DrawGraph(&gd);
       
   372 	}	break;
       
   373 	case WE_CLICK:
       
   374 		if (e->we.click.widget == 2) /* Clicked on Legend */
       
   375 			ShowGraphLegend();
       
   376 		break;
       
   377 	}
       
   378 }
       
   379 
       
   380 static const Widget _operating_profit_widgets[] = {
       
   381 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},
       
   382 {    WWT_CAPTION,   RESIZE_NONE,    14,    11,   525,     0,    13, STR_7025_OPERATING_PROFIT_GRAPH, STR_018C_WINDOW_TITLE_DRAG_THIS},
       
   383 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   526,   575,     0,    13, STR_704C_KEY,                    STR_704D_SHOW_KEY_TO_GRAPHS},
       
   384 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   575,    14,   173, 0x0,                             STR_NULL},
       
   385 {   WIDGETS_END},
       
   386 };
       
   387 
       
   388 static const WindowDesc _operating_profit_desc = {
       
   389 	WDP_AUTO, WDP_AUTO, 576, 174,
       
   390 	WC_OPERATING_PROFIT,0,
       
   391 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
       
   392 	_operating_profit_widgets,
       
   393 	OperatingProfitWndProc
       
   394 };
       
   395 
       
   396 
       
   397 void ShowOperatingProfitGraph(void)
       
   398 {
       
   399 	if (AllocateWindowDescFront(&_operating_profit_desc, 0)) {
       
   400 		InvalidateWindow(WC_GRAPH_LEGEND, 0);
       
   401 	}
       
   402 }
       
   403 
       
   404 
       
   405 /****************/
       
   406 /* INCOME GRAPH */
       
   407 /****************/
       
   408 
       
   409 static void IncomeGraphWndProc(Window *w, WindowEvent *e)
       
   410 {
       
   411 	switch (e->event) {
       
   412 	case WE_PAINT: {
       
   413 		GraphDrawer gd;
       
   414 		const Player* p;
       
   415 		int i,j;
       
   416 		int numd;
       
   417 
       
   418 		DrawWindowWidgets(w);
       
   419 
       
   420 		gd.left = 2;
       
   421 		gd.top = 18;
       
   422 		gd.height = 104;
       
   423 		gd.include_neg = false;
       
   424 		gd.format_str_y_axis = STR_CURRCOMPACT;
       
   425 		gd.color_3 = 0x10;
       
   426 		gd.color_2 = 0xD7;
       
   427 		gd.bg_line_color = 0xE;
       
   428 		SetupGraphDrawerForPlayers(&gd);
       
   429 
       
   430 		numd = 0;
       
   431 		FOR_ALL_PLAYERS(p) {
       
   432 			if (p->is_active) {
       
   433 				gd.colors[numd] = _colour_gradient[p->player_color][6];
       
   434 				for (j = gd.num_on_x_axis, i = 0; --j >= 0;) {
       
   435 					gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_VALUE : (uint64)p->old_economy[j].income;
       
   436 					i++;
       
   437 				}
       
   438 			}
       
   439 			numd++;
       
   440 		}
       
   441 
       
   442 		gd.num_dataset = numd;
       
   443 
       
   444 		DrawGraph(&gd);
       
   445 		break;
       
   446 	}
       
   447 
       
   448 	case WE_CLICK:
       
   449 		if (e->we.click.widget == 2)
       
   450 			ShowGraphLegend();
       
   451 		break;
       
   452 	}
       
   453 }
       
   454 
       
   455 static const Widget _income_graph_widgets[] = {
       
   456 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},
       
   457 {    WWT_CAPTION,   RESIZE_NONE,    14,    11,   525,     0,    13, STR_7022_INCOME_GRAPH, STR_018C_WINDOW_TITLE_DRAG_THIS},
       
   458 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   526,   575,     0,    13, STR_704C_KEY,          STR_704D_SHOW_KEY_TO_GRAPHS},
       
   459 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   575,    14,   141, 0x0,                   STR_NULL},
       
   460 {   WIDGETS_END},
       
   461 };
       
   462 
       
   463 static const WindowDesc _income_graph_desc = {
       
   464 	WDP_AUTO, WDP_AUTO, 576, 142,
       
   465 	WC_INCOME_GRAPH,0,
       
   466 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
       
   467 	_income_graph_widgets,
       
   468 	IncomeGraphWndProc
       
   469 };
       
   470 
       
   471 void ShowIncomeGraph(void)
       
   472 {
       
   473 	if (AllocateWindowDescFront(&_income_graph_desc, 0)) {
       
   474 		InvalidateWindow(WC_GRAPH_LEGEND, 0);
       
   475 	}
       
   476 }
       
   477 
       
   478 /*******************/
       
   479 /* DELIVERED CARGO */
       
   480 /*******************/
       
   481 
       
   482 static void DeliveredCargoGraphWndProc(Window *w, WindowEvent *e)
       
   483 {
       
   484 	switch (e->event) {
       
   485 	case WE_PAINT: {
       
   486 		GraphDrawer gd;
       
   487 		const Player* p;
       
   488 		int i,j;
       
   489 		int numd;
       
   490 
       
   491 		DrawWindowWidgets(w);
       
   492 
       
   493 		gd.left = 2;
       
   494 		gd.top = 18;
       
   495 		gd.height = 104;
       
   496 		gd.include_neg = false;
       
   497 		gd.format_str_y_axis = STR_7024;
       
   498 		gd.color_3 = 0x10;
       
   499 		gd.color_2 = 0xD7;
       
   500 		gd.bg_line_color = 0xE;
       
   501 		SetupGraphDrawerForPlayers(&gd);
       
   502 
       
   503 		numd = 0;
       
   504 		FOR_ALL_PLAYERS(p) {
       
   505 			if (p->is_active) {
       
   506 				gd.colors[numd] = _colour_gradient[p->player_color][6];
       
   507 				for (j = gd.num_on_x_axis, i = 0; --j >= 0;) {
       
   508 					gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_VALUE : (uint64)p->old_economy[j].delivered_cargo;
       
   509 					i++;
       
   510 				}
       
   511 			}
       
   512 			numd++;
       
   513 		}
       
   514 
       
   515 		gd.num_dataset = numd;
       
   516 
       
   517 		DrawGraph(&gd);
       
   518 		break;
       
   519 	}
       
   520 
       
   521 	case WE_CLICK:
       
   522 		if (e->we.click.widget == 2)
       
   523 			ShowGraphLegend();
       
   524 		break;
       
   525 	}
       
   526 }
       
   527 
       
   528 static const Widget _delivered_cargo_graph_widgets[] = {
       
   529 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                          STR_018B_CLOSE_WINDOW},
       
   530 {    WWT_CAPTION,   RESIZE_NONE,    14,    11,   525,     0,    13, STR_7050_UNITS_OF_CARGO_DELIVERED, STR_018C_WINDOW_TITLE_DRAG_THIS},
       
   531 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   526,   575,     0,    13, STR_704C_KEY,                      STR_704D_SHOW_KEY_TO_GRAPHS},
       
   532 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   575,    14,   141, 0x0,                               STR_NULL},
       
   533 {   WIDGETS_END},
       
   534 };
       
   535 
       
   536 static const WindowDesc _delivered_cargo_graph_desc = {
       
   537 	WDP_AUTO, WDP_AUTO, 576, 142,
       
   538 	WC_DELIVERED_CARGO,0,
       
   539 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
       
   540 	_delivered_cargo_graph_widgets,
       
   541 	DeliveredCargoGraphWndProc
       
   542 };
       
   543 
       
   544 void ShowDeliveredCargoGraph(void)
       
   545 {
       
   546 	if (AllocateWindowDescFront(&_delivered_cargo_graph_desc, 0)) {
       
   547 		InvalidateWindow(WC_GRAPH_LEGEND, 0);
       
   548 	}
       
   549 }
       
   550 
       
   551 /***********************/
       
   552 /* PERFORMANCE HISTORY */
       
   553 /***********************/
       
   554 
       
   555 static void PerformanceHistoryWndProc(Window *w, WindowEvent *e)
       
   556 {
       
   557 	switch (e->event) {
       
   558 	case WE_PAINT: {
       
   559 		GraphDrawer gd;
       
   560 		const Player* p;
       
   561 		int i,j;
       
   562 		int numd;
       
   563 
       
   564 		DrawWindowWidgets(w);
       
   565 
       
   566 		gd.left = 2;
       
   567 		gd.top = 18;
       
   568 		gd.height = 200;
       
   569 		gd.include_neg = false;
       
   570 		gd.format_str_y_axis = STR_7024;
       
   571 		gd.color_3 = 0x10;
       
   572 		gd.color_2 = 0xD7;
       
   573 		gd.bg_line_color = 0xE;
       
   574 		SetupGraphDrawerForPlayers(&gd);
       
   575 
       
   576 		numd = 0;
       
   577 		FOR_ALL_PLAYERS(p) {
       
   578 			if (p->is_active) {
       
   579 				gd.colors[numd] = _colour_gradient[p->player_color][6];
       
   580 				for (j = gd.num_on_x_axis, i = 0; --j >= 0;) {
       
   581 					gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_VALUE : (uint64)p->old_economy[j].performance_history;
       
   582 					i++;
       
   583 				}
       
   584 			}
       
   585 			numd++;
       
   586 		}
       
   587 
       
   588 		gd.num_dataset = numd;
       
   589 
       
   590 		DrawGraph(&gd);
       
   591 		break;
       
   592 	}
       
   593 
       
   594 	case WE_CLICK:
       
   595 		if (e->we.click.widget == 2)
       
   596 			ShowGraphLegend();
       
   597 		if (e->we.click.widget == 3)
       
   598 			ShowPerformanceRatingDetail();
       
   599 		break;
       
   600 	}
       
   601 }
       
   602 
       
   603 static const Widget _performance_history_widgets[] = {
       
   604 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                             STR_018B_CLOSE_WINDOW},
       
   605 {    WWT_CAPTION,   RESIZE_NONE,    14,    11,   475,     0,    13, STR_7051_COMPANY_PERFORMANCE_RATINGS, STR_018C_WINDOW_TITLE_DRAG_THIS},
       
   606 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   526,   575,     0,    13, STR_704C_KEY,                         STR_704D_SHOW_KEY_TO_GRAPHS},
       
   607 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   476,   525,     0,    13, STR_PERFORMANCE_DETAIL_KEY,           STR_704D_SHOW_KEY_TO_GRAPHS},
       
   608 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   575,    14,   237, 0x0,                                  STR_NULL},
       
   609 {   WIDGETS_END},
       
   610 };
       
   611 
       
   612 static const WindowDesc _performance_history_desc = {
       
   613 	WDP_AUTO, WDP_AUTO, 576, 238,
       
   614 	WC_PERFORMANCE_HISTORY,0,
       
   615 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
       
   616 	_performance_history_widgets,
       
   617 	PerformanceHistoryWndProc
       
   618 };
       
   619 
       
   620 void ShowPerformanceHistoryGraph(void)
       
   621 {
       
   622 	if (AllocateWindowDescFront(&_performance_history_desc, 0)) {
       
   623 		InvalidateWindow(WC_GRAPH_LEGEND, 0);
       
   624 	}
       
   625 }
       
   626 
       
   627 /*****************/
       
   628 /* COMPANY VALUE */
       
   629 /*****************/
       
   630 
       
   631 static void CompanyValueGraphWndProc(Window *w, WindowEvent *e)
       
   632 {
       
   633 	switch (e->event) {
       
   634 	case WE_PAINT: {
       
   635 		GraphDrawer gd;
       
   636 		const Player* p;
       
   637 		int i,j;
       
   638 		int numd;
       
   639 
       
   640 		DrawWindowWidgets(w);
       
   641 
       
   642 		gd.left = 2;
       
   643 		gd.top = 18;
       
   644 		gd.height = 200;
       
   645 		gd.include_neg = false;
       
   646 		gd.format_str_y_axis = STR_CURRCOMPACT;
       
   647 		gd.color_3 = 0x10;
       
   648 		gd.color_2 = 0xD7;
       
   649 		gd.bg_line_color = 0xE;
       
   650 		SetupGraphDrawerForPlayers(&gd);
       
   651 
       
   652 		numd = 0;
       
   653 		FOR_ALL_PLAYERS(p) {
       
   654 			if (p->is_active) {
       
   655 				gd.colors[numd] = _colour_gradient[p->player_color][6];
       
   656 				for (j = gd.num_on_x_axis, i = 0; --j >= 0;) {
       
   657 					gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_VALUE : (uint64)p->old_economy[j].company_value;
       
   658 					i++;
       
   659 				}
       
   660 			}
       
   661 			numd++;
       
   662 		}
       
   663 
       
   664 		gd.num_dataset = numd;
       
   665 
       
   666 		DrawGraph(&gd);
       
   667 		break;
       
   668 	}
       
   669 
       
   670 	case WE_CLICK:
       
   671 		if (e->we.click.widget == 2)
       
   672 			ShowGraphLegend();
       
   673 		break;
       
   674 	}
       
   675 }
       
   676 
       
   677 static const Widget _company_value_graph_widgets[] = {
       
   678 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                STR_018B_CLOSE_WINDOW},
       
   679 {    WWT_CAPTION,   RESIZE_NONE,    14,    11,   525,     0,    13, STR_7052_COMPANY_VALUES, STR_018C_WINDOW_TITLE_DRAG_THIS},
       
   680 { WWT_PUSHTXTBTN,   RESIZE_NONE,    14,   526,   575,     0,    13, STR_704C_KEY,            STR_704D_SHOW_KEY_TO_GRAPHS},
       
   681 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   575,    14,   237, 0x0,                     STR_NULL},
       
   682 {   WIDGETS_END},
       
   683 };
       
   684 
       
   685 static const WindowDesc _company_value_graph_desc = {
       
   686 	WDP_AUTO, WDP_AUTO, 576, 238,
       
   687 	WC_COMPANY_VALUE,0,
       
   688 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
       
   689 	_company_value_graph_widgets,
       
   690 	CompanyValueGraphWndProc
       
   691 };
       
   692 
       
   693 void ShowCompanyValueGraph(void)
       
   694 {
       
   695 	if (AllocateWindowDescFront(&_company_value_graph_desc, 0)) {
       
   696 		InvalidateWindow(WC_GRAPH_LEGEND, 0);
       
   697 	}
       
   698 }
       
   699 
       
   700 /*****************/
       
   701 /* PAYMENT RATES */
       
   702 /*****************/
       
   703 
       
   704 static void CargoPaymentRatesWndProc(Window *w, WindowEvent *e)
       
   705 {
       
   706 	switch (e->event) {
       
   707 	case WE_CREATE: {
       
   708 		uint i;
       
   709 		for (i = 3; i < w->widget_count; i++) {
       
   710 			if (!HASBIT(_legend_cargobits, i - 3)) LowerWindowWidget(w, i);
       
   711 		}
       
   712 		break;
       
   713 	}
       
   714 
       
   715 	case WE_PAINT: {
       
   716 		int j, x, y;
       
   717 		CargoID i;
       
   718 		GraphDrawer gd;
       
   719 
       
   720 		DrawWindowWidgets(w);
       
   721 
       
   722 		x = 495;
       
   723 		y = 24;
       
   724 
       
   725 		gd.sel = _legend_cargobits;
       
   726 		gd.left = 2;
       
   727 		gd.top = 24;
       
   728 		gd.height = 104;
       
   729 		gd.include_neg = false;
       
   730 		gd.format_str_y_axis = STR_CURRCOMPACT;
       
   731 		gd.color_3 = 16;
       
   732 		gd.color_2 = 215;
       
   733 		gd.bg_line_color = 14;
       
   734 		gd.num_dataset = NUM_CARGO;
       
   735 		gd.num_on_x_axis = 20;
       
   736 		gd.num_vert_lines = 20;
       
   737 		gd.month = 0xFF;
       
   738 		gd.unk61A = 10;
       
   739 		gd.unk61C = 10;
       
   740 
       
   741 		for (i = 0; i != NUM_CARGO; i++) {
       
   742 			/* Since the buttons have no text, no images,
       
   743 			 * both the text and the colored box have to be manually painted.
       
   744 			 * clk_dif will move one pixel down and one pixel to the right
       
   745 			 * when the button is clicked */
       
   746 			byte clk_dif = IsWindowWidgetLowered(w, i + 3) ? 1 : 0;
       
   747 
       
   748 			GfxFillRect(x + clk_dif, y + clk_dif, x + 8 + clk_dif, y + 5 + clk_dif, 0);
       
   749 			GfxFillRect(x + 1 + clk_dif, y + 1 + clk_dif, x + 7 + clk_dif, y + 4 + clk_dif, _cargo_colours[i]);
       
   750 			SetDParam(0, _cargoc.names_s[i]);
       
   751 			DrawString(x + 14 + clk_dif, y + clk_dif, STR_7065, 0);
       
   752 			y += 8;
       
   753 			gd.colors[i] = _cargo_colours[i];
       
   754 			for (j = 0; j != 20; j++) {
       
   755 				gd.cost[i][j] = (uint64)GetTransportedGoodsIncome(10, 20, j * 6 + 6, i);
       
   756 			}
       
   757 		}
       
   758 
       
   759 		DrawGraph(&gd);
       
   760 
       
   761 		DrawString(2 + 46, 24 + gd.height + 7, STR_7062_DAYS_IN_TRANSIT, 0);
       
   762 		DrawString(2 + 84, 24 - 9, STR_7063_PAYMENT_FOR_DELIVERING, 0);
       
   763 	} break;
       
   764 
       
   765 	case WE_CLICK: {
       
   766 		switch (e->we.click.widget) {
       
   767 		case 3: case 4: case 5: case 6:
       
   768 		case 7: case 8: case 9: case 10:
       
   769 		case 11: case 12: case 13: case 14:
       
   770 			TOGGLEBIT(_legend_cargobits, e->we.click.widget - 3);
       
   771 			ToggleWidgetLoweredState(w, e->we.click.widget);
       
   772 			SetWindowDirty(w);
       
   773 			break;
       
   774 		}
       
   775 	} break;
       
   776 	}
       
   777 }
       
   778 
       
   779 static const Widget _cargo_payment_rates_widgets[] = {
       
   780 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                     STR_018B_CLOSE_WINDOW},
       
   781 {    WWT_CAPTION,   RESIZE_NONE,    14,    11,   567,     0,    13, STR_7061_CARGO_PAYMENT_RATES, STR_018C_WINDOW_TITLE_DRAG_THIS},
       
   782 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   567,    14,   141, 0x0,                          STR_NULL},
       
   783 {      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    24,    31, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
       
   784 {      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    32,    39, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
       
   785 {      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    40,    47, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
       
   786 {      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    48,    55, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
       
   787 {      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    56,    63, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
       
   788 {      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    64,    71, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
       
   789 {      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    72,    79, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
       
   790 {      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    80,    87, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
       
   791 {      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    88,    95, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
       
   792 {      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,    96,   103, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
       
   793 {      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,   104,   111, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
       
   794 {      WWT_PANEL,   RESIZE_NONE,    12,   493,   562,   112,   119, 0x0,                          STR_7064_TOGGLE_GRAPH_FOR_CARGO},
       
   795 {   WIDGETS_END},
       
   796 };
       
   797 
       
   798 static const WindowDesc _cargo_payment_rates_desc = {
       
   799 	WDP_AUTO, WDP_AUTO, 568, 142,
       
   800 	WC_PAYMENT_RATES,0,
       
   801 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
       
   802 	_cargo_payment_rates_widgets,
       
   803 	CargoPaymentRatesWndProc
       
   804 };
       
   805 
       
   806 
       
   807 void ShowCargoPaymentRates(void)
       
   808 {
       
   809 	AllocateWindowDescFront(&_cargo_payment_rates_desc, 0);
       
   810 }
       
   811 
       
   812 /************************/
       
   813 /* COMPANY LEAGUE TABLE */
       
   814 /************************/
       
   815 
       
   816 static const StringID _performance_titles[] = {
       
   817 	STR_7066_ENGINEER,
       
   818 	STR_7066_ENGINEER,
       
   819 	STR_7067_TRAFFIC_MANAGER,
       
   820 	STR_7067_TRAFFIC_MANAGER,
       
   821 	STR_7068_TRANSPORT_COORDINATOR,
       
   822 	STR_7068_TRANSPORT_COORDINATOR,
       
   823 	STR_7069_ROUTE_SUPERVISOR,
       
   824 	STR_7069_ROUTE_SUPERVISOR,
       
   825 	STR_706A_DIRECTOR,
       
   826 	STR_706A_DIRECTOR,
       
   827 	STR_706B_CHIEF_EXECUTIVE,
       
   828 	STR_706B_CHIEF_EXECUTIVE,
       
   829 	STR_706C_CHAIRMAN,
       
   830 	STR_706C_CHAIRMAN,
       
   831 	STR_706D_PRESIDENT,
       
   832 	STR_706E_TYCOON,
       
   833 };
       
   834 
       
   835 static inline StringID GetPerformanceTitleFromValue(uint value)
       
   836 {
       
   837 	return _performance_titles[minu(value, 1000) >> 6];
       
   838 }
       
   839 
       
   840 static int CDECL PerfHistComp(const void* elem1, const void* elem2)
       
   841 {
       
   842 	const Player* p1 = *(const Player* const*)elem1;
       
   843 	const Player* p2 = *(const Player* const*)elem2;
       
   844 
       
   845 	return p2->old_economy[1].performance_history - p1->old_economy[1].performance_history;
       
   846 }
       
   847 
       
   848 static void CompanyLeagueWndProc(Window *w, WindowEvent *e)
       
   849 {
       
   850 	switch (e->event) {
       
   851 		case WE_PAINT: {
       
   852 			const Player* plist[MAX_PLAYERS];
       
   853 			const Player* p;
       
   854 			uint pl_num;
       
   855 			uint i;
       
   856 
       
   857 			DrawWindowWidgets(w);
       
   858 
       
   859 			pl_num = 0;
       
   860 			FOR_ALL_PLAYERS(p) if (p->is_active) plist[pl_num++] = p;
       
   861 
       
   862 			qsort((void*)plist, pl_num, sizeof(*plist), PerfHistComp);
       
   863 
       
   864 			for (i = 0; i != pl_num; i++) {
       
   865 				p = plist[i];
       
   866 				SetDParam(0, i + STR_01AC_1ST);
       
   867 				SetDParam(1, p->name_1);
       
   868 				SetDParam(2, p->name_2);
       
   869 				SetDParam(3, GetPlayerNameString(p->index, 4));
       
   870 				SetDParam(5, GetPerformanceTitleFromValue(p->old_economy[1].performance_history));
       
   871 
       
   872 				DrawString(2, 15 + i * 10, i == 0 ? STR_7054 : STR_7055, 0);
       
   873 				DrawPlayerIcon(p->index, 27, 16 + i * 10);
       
   874 			}
       
   875 
       
   876 			break;
       
   877 		}
       
   878 	}
       
   879 }
       
   880 
       
   881 
       
   882 static const Widget _company_league_widgets[] = {
       
   883 {   WWT_CLOSEBOX, RESIZE_NONE, 14,   0,  10,  0, 13, STR_00C5,                      STR_018B_CLOSE_WINDOW},
       
   884 {    WWT_CAPTION, RESIZE_NONE, 14,  11, 387,  0, 13, STR_7053_COMPANY_LEAGUE_TABLE, STR_018C_WINDOW_TITLE_DRAG_THIS},
       
   885 {  WWT_STICKYBOX, RESIZE_NONE, 14, 388, 399,  0, 13, STR_NULL,                      STR_STICKY_BUTTON},
       
   886 {      WWT_PANEL, RESIZE_NONE, 14,   0, 399, 14, 96, 0x0,                           STR_NULL},
       
   887 {   WIDGETS_END},
       
   888 };
       
   889 
       
   890 static const WindowDesc _company_league_desc = {
       
   891 	WDP_AUTO, WDP_AUTO, 400, 97,
       
   892 	WC_COMPANY_LEAGUE,0,
       
   893 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
       
   894 	_company_league_widgets,
       
   895 	CompanyLeagueWndProc
       
   896 };
       
   897 
       
   898 void ShowCompanyLeagueTable(void)
       
   899 {
       
   900 	AllocateWindowDescFront(&_company_league_desc,0);
       
   901 }
       
   902 
       
   903 /*****************************/
       
   904 /* PERFORMANCE RATING DETAIL */
       
   905 /*****************************/
       
   906 
       
   907 static void PerformanceRatingDetailWndProc(Window *w, WindowEvent *e)
       
   908 {
       
   909 	static PlayerID _performance_rating_detail_player = 0;
       
   910 
       
   911 	switch (e->event) {
       
   912 		case WE_PAINT: {
       
   913 			int i;
       
   914 			byte x;
       
   915 			uint16 y = 14;
       
   916 			int total_score = 0;
       
   917 			int color_done, color_notdone;
       
   918 
       
   919 			// Draw standard stuff
       
   920 			DrawWindowWidgets(w);
       
   921 
       
   922 			// Paint the player icons
       
   923 			for (i = 0; i < MAX_PLAYERS; i++) {
       
   924 				if (!GetPlayer(i)->is_active) {
       
   925 					// Check if we have the player as an active player
       
   926 					if (!IsWindowWidgetDisabled(w, i + 13)) {
       
   927 						// Bah, player gone :(
       
   928 						DisableWindowWidget(w, i + 13);
       
   929 						// Is this player selected? If so, select first player (always save? :s)
       
   930 						if (IsWindowWidgetLowered(w, i + 13)) {
       
   931 							RaiseWindowWidget(w, i + 13);
       
   932 							LowerWindowWidget(w, 13);
       
   933 							_performance_rating_detail_player = 0;
       
   934 						}
       
   935 						// We need a repaint
       
   936 						SetWindowDirty(w);
       
   937 					}
       
   938 				continue;
       
   939 				}
       
   940 
       
   941 				// Check if we have the player marked as inactive
       
   942 				if (IsWindowWidgetDisabled(w, i + 13)) {
       
   943 					// New player! Yippie :p
       
   944 					EnableWindowWidget(w, i + 13);
       
   945 					// We need a repaint
       
   946 					SetWindowDirty(w);
       
   947 				}
       
   948 
       
   949 				x = (i == _performance_rating_detail_player) ? 1 : 0;
       
   950 				DrawPlayerIcon(i, i * 37 + 13 + x, 16 + x);
       
   951 			}
       
   952 
       
   953 			// The colors used to show how the progress is going
       
   954 			color_done = _colour_gradient[COLOUR_GREEN][4];
       
   955 			color_notdone = _colour_gradient[COLOUR_RED][4];
       
   956 
       
   957 			// Draw all the score parts
       
   958 			for (i = 0; i < NUM_SCORE; i++) {
       
   959 				int val    = _score_part[_performance_rating_detail_player][i];
       
   960 				int needed = _score_info[i].needed;
       
   961 				int score  = _score_info[i].score;
       
   962 
       
   963 				y += 20;
       
   964 				// SCORE_TOTAL has his own rulez ;)
       
   965 				if (i == SCORE_TOTAL) {
       
   966 					needed = total_score;
       
   967 					score = SCORE_MAX;
       
   968 				} else {
       
   969 					total_score += score;
       
   970 				}
       
   971 
       
   972 				DrawString(7, y, STR_PERFORMANCE_DETAIL_VEHICLES + i, 0);
       
   973 
       
   974 				// Draw the score
       
   975 				SetDParam(0, score);
       
   976 				DrawStringRightAligned(107, y, SET_PERFORMANCE_DETAIL_INT, 0);
       
   977 
       
   978 				// Calculate the %-bar
       
   979 				if (val > needed) {
       
   980 					x = 50;
       
   981 				} else if (val == 0) {
       
   982 					x = 0;
       
   983 				} else {
       
   984 					x = val * 50 / needed;
       
   985 				}
       
   986 
       
   987 				// SCORE_LOAN is inversed
       
   988 				if (val < 0 && i == SCORE_LOAN) x = 0;
       
   989 
       
   990 				// Draw the bar
       
   991 				if (x !=  0) GfxFillRect(112,     y - 2, 112 + x,  y + 10, color_done);
       
   992 				if (x != 50) GfxFillRect(112 + x, y - 2, 112 + 50, y + 10, color_notdone);
       
   993 
       
   994 				// Calculate the %
       
   995 				x = (val <= needed) ? val * 100 / needed : 100;
       
   996 
       
   997 				// SCORE_LOAN is inversed
       
   998 				if (val < 0 && i == SCORE_LOAN) x = 0;
       
   999 
       
  1000 				// Draw it
       
  1001 				SetDParam(0, x);
       
  1002 				DrawStringCentered(137, y, STR_PERFORMANCE_DETAIL_PERCENT, 0);
       
  1003 
       
  1004 				// SCORE_LOAN is inversed
       
  1005 				if (i == SCORE_LOAN) val = needed - val;
       
  1006 
       
  1007 				// Draw the amount we have against what is needed
       
  1008 				//  For some of them it is in currency format
       
  1009 				SetDParam(0, val);
       
  1010 				SetDParam(1, needed);
       
  1011 				switch (i) {
       
  1012 					case SCORE_MIN_PROFIT:
       
  1013 					case SCORE_MIN_INCOME:
       
  1014 					case SCORE_MAX_INCOME:
       
  1015 					case SCORE_MONEY:
       
  1016 					case SCORE_LOAN:
       
  1017 						DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY, 0);
       
  1018 						break;
       
  1019 					default:
       
  1020 						DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_INT, 0);
       
  1021 				}
       
  1022 			}
       
  1023 
       
  1024 			break;
       
  1025 		}
       
  1026 
       
  1027 		case WE_CLICK:
       
  1028 			// Check which button is clicked
       
  1029 			if (IS_INT_INSIDE(e->we.click.widget, 13, 21)) {
       
  1030 				// Is it no on disable?
       
  1031 				if (!IsWindowWidgetDisabled(w, e->we.click.widget)) {
       
  1032 					RaiseWindowWidget(w, _performance_rating_detail_player + 13);
       
  1033 					_performance_rating_detail_player = e->we.click.widget - 13;
       
  1034 					LowerWindowWidget(w, _performance_rating_detail_player + 13);
       
  1035 					SetWindowDirty(w);
       
  1036 				}
       
  1037 			}
       
  1038 			break;
       
  1039 
       
  1040 		case WE_CREATE: {
       
  1041 			int i;
       
  1042 			Player *p2;
       
  1043 
       
  1044 			/* Disable the players who are not active */
       
  1045 			for (i = 0; i < MAX_PLAYERS; i++) {
       
  1046 				SetWindowWidgetDisabledState(w, i + 13, !GetPlayer(i)->is_active);
       
  1047 			}
       
  1048 			/* Update all player stats with the current data
       
  1049 			 * (this is because _score_info is not saved to a savegame) */
       
  1050 			FOR_ALL_PLAYERS(p2) {
       
  1051 				if (p2->is_active) UpdateCompanyRatingAndValue(p2, false);
       
  1052 			}
       
  1053 
       
  1054 			w->custom[0] = DAY_TICKS;
       
  1055 			w->custom[1] = 5;
       
  1056 
       
  1057 			_performance_rating_detail_player = 0;
       
  1058 			LowerWindowWidget(w, _performance_rating_detail_player + 13);
       
  1059 			SetWindowDirty(w);
       
  1060 
       
  1061 			break;
       
  1062 		}
       
  1063 
       
  1064 		case WE_TICK: {
       
  1065 			// Update the player score every 5 days
       
  1066 			if (--w->custom[0] == 0) {
       
  1067 				w->custom[0] = DAY_TICKS;
       
  1068 				if (--w->custom[1] == 0) {
       
  1069 					Player *p2;
       
  1070 
       
  1071 					w->custom[1] = 5;
       
  1072 					FOR_ALL_PLAYERS(p2) {
       
  1073 						// Skip if player is not active
       
  1074 						if (p2->is_active) UpdateCompanyRatingAndValue(p2, false);
       
  1075 					}
       
  1076 					SetWindowDirty(w);
       
  1077 				}
       
  1078 			}
       
  1079 
       
  1080 			break;
       
  1081 		}
       
  1082 	}
       
  1083 }
       
  1084 
       
  1085 static const Widget _performance_rating_detail_widgets[] = {
       
  1086 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,               STR_018B_CLOSE_WINDOW},
       
  1087 {    WWT_CAPTION,   RESIZE_NONE,    14,    11,   298,     0,    13, STR_PERFORMANCE_DETAIL, STR_018C_WINDOW_TITLE_DRAG_THIS},
       
  1088 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,    14,    27, 0x0,                    STR_NULL},
       
  1089 
       
  1090 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,    28,    47, 0x0,                    STR_PERFORMANCE_DETAIL_VEHICLES_TIP},
       
  1091 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,    48,    67, 0x0,                    STR_PERFORMANCE_DETAIL_STATIONS_TIP},
       
  1092 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,    68,    87, 0x0,                    STR_PERFORMANCE_DETAIL_MIN_PROFIT_TIP},
       
  1093 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,    88,   107, 0x0,                    STR_PERFORMANCE_DETAIL_MIN_INCOME_TIP},
       
  1094 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,   108,   127, 0x0,                    STR_PERFORMANCE_DETAIL_MAX_INCOME_TIP},
       
  1095 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,   128,   147, 0x0,                    STR_PERFORMANCE_DETAIL_DELIVERED_TIP},
       
  1096 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,   148,   167, 0x0,                    STR_PERFORMANCE_DETAIL_CARGO_TIP},
       
  1097 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,   168,   187, 0x0,                    STR_PERFORMANCE_DETAIL_MONEY_TIP},
       
  1098 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,   188,   207, 0x0,                    STR_PERFORMANCE_DETAIL_LOAN_TIP},
       
  1099 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   298,   208,   227, 0x0,                    STR_PERFORMANCE_DETAIL_TOTAL_TIP},
       
  1100 
       
  1101 {      WWT_PANEL,   RESIZE_NONE,    14,     2,    38,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
       
  1102 {      WWT_PANEL,   RESIZE_NONE,    14,    39,    75,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
       
  1103 {      WWT_PANEL,   RESIZE_NONE,    14,    76,   112,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
       
  1104 {      WWT_PANEL,   RESIZE_NONE,    14,   113,   149,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
       
  1105 {      WWT_PANEL,   RESIZE_NONE,    14,   150,   186,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
       
  1106 {      WWT_PANEL,   RESIZE_NONE,    14,   187,   223,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
       
  1107 {      WWT_PANEL,   RESIZE_NONE,    14,   224,   260,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
       
  1108 {      WWT_PANEL,   RESIZE_NONE,    14,   261,   297,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
       
  1109 {   WIDGETS_END},
       
  1110 };
       
  1111 
       
  1112 static const WindowDesc _performance_rating_detail_desc = {
       
  1113 	WDP_AUTO, WDP_AUTO, 299, 228,
       
  1114 	WC_PERFORMANCE_DETAIL,0,
       
  1115 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
       
  1116 	_performance_rating_detail_widgets,
       
  1117 	PerformanceRatingDetailWndProc
       
  1118 };
       
  1119 
       
  1120 void ShowPerformanceRatingDetail(void)
       
  1121 {
       
  1122 	AllocateWindowDescFront(&_performance_rating_detail_desc, 0);
       
  1123 }
       
  1124 
       
  1125 
       
  1126 static const Sign **_sign_sort;
       
  1127 static uint _num_sign_sort;
       
  1128 
       
  1129 static char _bufcache[64];
       
  1130 static const Sign *_last_sign;
       
  1131 
       
  1132 static int CDECL SignNameSorter(const void *a, const void *b)
       
  1133 {
       
  1134 	const Sign *sign0 = *(const Sign**)a;
       
  1135 	const Sign *sign1 = *(const Sign**)b;
       
  1136 	char buf1[64];
       
  1137 
       
  1138 	GetString(buf1, sign0->str, lastof(buf1));
       
  1139 
       
  1140 	if (sign1 != _last_sign) {
       
  1141 		_last_sign = sign1;
       
  1142 		GetString(_bufcache, sign1->str, lastof(_bufcache));
       
  1143 	}
       
  1144 
       
  1145 	return strcmp(buf1, _bufcache); // sort by name
       
  1146 }
       
  1147 
       
  1148 static void GlobalSortSignList(void)
       
  1149 {
       
  1150 	const Sign *si;
       
  1151 	uint n = 0;
       
  1152 
       
  1153 	/* Create array for sorting */
       
  1154 	_sign_sort = realloc((void *)_sign_sort, (GetMaxSignIndex() + 1)* sizeof(_sign_sort[0]));
       
  1155 	if (_sign_sort == NULL) error("Could not allocate memory for the sign-sorting-list");
       
  1156 
       
  1157 	FOR_ALL_SIGNS(si) _sign_sort[n++] = si;
       
  1158 	_num_sign_sort = n;
       
  1159 
       
  1160 	qsort((void*)_sign_sort, n, sizeof(_sign_sort[0]), SignNameSorter);
       
  1161 
       
  1162 	_sign_sort_dirty = false;
       
  1163 
       
  1164 	DEBUG(misc, 3, "Resorting global signs list");
       
  1165 }
       
  1166 
       
  1167 static void SignListWndProc(Window *w, WindowEvent *e)
       
  1168 {
       
  1169 	switch (e->event) {
       
  1170 	case WE_PAINT: {
       
  1171 		int y = 16; // offset from top of widget
       
  1172 
       
  1173 		if (_sign_sort_dirty)
       
  1174 			GlobalSortSignList();
       
  1175 
       
  1176 		SetVScrollCount(w, _num_sign_sort);
       
  1177 
       
  1178 		SetDParam(0, w->vscroll.count);
       
  1179 		DrawWindowWidgets(w);
       
  1180 
       
  1181 		/* No signs? */
       
  1182 		if (w->vscroll.count == 0) {
       
  1183 			DrawString(2, y, STR_304A_NONE, 0);
       
  1184 			return;
       
  1185 		}
       
  1186 
       
  1187 		{
       
  1188 			uint16 i;
       
  1189 
       
  1190 			/* Start drawing the signs */
       
  1191 			for (i = w->vscroll.pos; i < w->vscroll.cap + w->vscroll.pos && i < w->vscroll.count; i++) {
       
  1192 				const Sign *si = _sign_sort[i];
       
  1193 
       
  1194 				if (si->owner != OWNER_NONE)
       
  1195 					DrawPlayerIcon(si->owner, 4, y + 1);
       
  1196 
       
  1197 				DrawString(22, y, si->str, 8);
       
  1198 				y += 10;
       
  1199 			}
       
  1200 		}
       
  1201 	} break;
       
  1202 
       
  1203 	case WE_CLICK: {
       
  1204 		switch (e->we.click.widget) {
       
  1205 		case 3: {
       
  1206 			uint32 id_v = (e->we.click.pt.y - 15) / 10;
       
  1207 			const Sign *si;
       
  1208 
       
  1209 			if (id_v >= w->vscroll.cap)
       
  1210 				return;
       
  1211 
       
  1212 			id_v += w->vscroll.pos;
       
  1213 
       
  1214 			if (id_v >= w->vscroll.count)
       
  1215 				return;
       
  1216 
       
  1217 			si = _sign_sort[id_v];
       
  1218 			ScrollMainWindowToTile(TileVirtXY(si->x, si->y));
       
  1219 		} break;
       
  1220 		}
       
  1221 	} break;
       
  1222 
       
  1223 	case WE_RESIZE:
       
  1224 		w->vscroll.cap += e->we.sizing.diff.y / 10;
       
  1225 		break;
       
  1226 	}
       
  1227 }
       
  1228 
       
  1229 static const Widget _sign_list_widget[] = {
       
  1230 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},
       
  1231 {    WWT_CAPTION,  RESIZE_RIGHT,    14,    11,   345,     0,    13, STR_SIGN_LIST_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
       
  1232 {  WWT_STICKYBOX,     RESIZE_LR,    14,   346,   357,     0,    13, 0x0,                   STR_STICKY_BUTTON},
       
  1233 {      WWT_PANEL,     RESIZE_RB,    14,     0,   345,    14,   137, 0x0,                   STR_NULL},
       
  1234 {  WWT_SCROLLBAR,    RESIZE_LRB,    14,   346,   357,    14,   125, 0x0,                   STR_0190_SCROLL_BAR_SCROLLS_LIST},
       
  1235 {  WWT_RESIZEBOX,   RESIZE_LRTB,    14,   346,   357,   126,   137, 0x0,                   STR_RESIZE_BUTTON},
       
  1236 {   WIDGETS_END},
       
  1237 };
       
  1238 
       
  1239 static const WindowDesc _sign_list_desc = {
       
  1240 	WDP_AUTO, WDP_AUTO, 358, 138,
       
  1241 	WC_SIGN_LIST,0,
       
  1242 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON | WDF_RESIZABLE,
       
  1243 	_sign_list_widget,
       
  1244 	SignListWndProc
       
  1245 };
       
  1246 
       
  1247 
       
  1248 void ShowSignList(void)
       
  1249 {
       
  1250 	Window *w;
       
  1251 
       
  1252 	w = AllocateWindowDescFront(&_sign_list_desc, 0);
       
  1253 	if (w != NULL) {
       
  1254 		w->vscroll.cap = 12;
       
  1255 		w->resize.step_height = 10;
       
  1256 		w->resize.height = w->height - 10 * 7; // minimum if 5 in the list
       
  1257 	}
       
  1258 }