1
/* $Id: graph_gui.cpp 14269 2008-09-07 22:14:48Z rubidium $ */
1
/* $Id: graph_gui.cpp 15723 2009-03-15 15:12:06Z rubidium $ */
3
/** @file graph_gui.cpp */
3
/** @file graph_gui.cpp GUI that shows performance graphs. */
8
8
#include "window_gui.h"
9
#include "player_base.h"
10
#include "player_gui.h"
9
#include "company_base.h"
10
#include "company_gui.h"
11
11
#include "economy_func.h"
12
#include "variables.h"
13
12
#include "cargotype.h"
14
13
#include "strings_func.h"
15
#include "core/alloc_func.hpp"
16
14
#include "window_func.h"
17
15
#include "date_func.h"
18
16
#include "gfx_func.h"
17
#include "sortlist_type.h"
20
19
#include "table/strings.h"
21
#include "table/sprites.h"
23
/* Bitmasks of player and cargo indices that shouldn't be drawn. */
24
static uint _legend_excluded_players;
21
/* Bitmasks of company and cargo indices that shouldn't be drawn. */
22
static uint _legend_excluded_companies;
25
23
static uint _legend_excluded_cargo;
27
/************************/
28
/* GENERIC GRAPH DRAWER */
29
/************************/
32
GRAPH_MAX_DATASETS = 32,
33
GRAPH_AXIS_LABEL_COLOUR = TC_BLACK,
34
GRAPH_AXIS_LINE_COLOUR = 215,
36
GRAPH_X_POSITION_BEGINNING = 44, ///< Start the graph 44 pixels from gw->left
37
GRAPH_X_POSITION_SEPARATION = 22, ///< There are 22 pixels between each X value
39
GRAPH_NUM_LINES_Y = 9, ///< How many horizontal lines to draw.
40
/* 9 is convenient as that means the distance between them is the height of the graph / 8,
45
25
/* Apparently these don't play well with enums. */
46
26
static const OverflowSafeInt64 INVALID_DATAPOINT(INT64_MAX); // Value used for a datapoint that shouldn't be drawn.
47
27
static const uint INVALID_DATAPOINT_POS = UINT_MAX; // Used to determine if the previous point was drawn.
33
struct GraphLegendWindow : Window {
34
GraphLegendWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
36
for (uint i = 3; i < this->widget_count; i++) {
37
if (!HasBit(_legend_excluded_companies, i - 3)) this->LowerWidget(i);
40
this->FindWindowPlacementAndResize(desc);
43
virtual void OnPaint()
45
for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
46
if (IsValidCompanyID(c)) continue;
48
SetBit(_legend_excluded_companies, c);
49
this->RaiseWidget(c + 3);
55
FOR_ALL_COMPANIES(c) {
56
DrawCompanyIcon(c->index, 4, 18 + c->index * 12);
58
SetDParam(0, c->index);
59
SetDParam(1, c->index);
60
DrawString(21, 17 + c->index * 12, STR_7021, HasBit(_legend_excluded_companies, c->index) ? TC_BLACK : TC_WHITE);
64
virtual void OnClick(Point pt, int widget)
66
if (!IsInsideMM(widget, 3, MAX_COMPANIES + 3)) return;
68
ToggleBit(_legend_excluded_companies, widget - 3);
69
this->ToggleWidgetLoweredState(widget);
71
InvalidateWindow(WC_INCOME_GRAPH, 0);
72
InvalidateWindow(WC_OPERATING_PROFIT, 0);
73
InvalidateWindow(WC_DELIVERED_CARGO, 0);
74
InvalidateWindow(WC_PERFORMANCE_HISTORY, 0);
75
InvalidateWindow(WC_COMPANY_VALUE, 0);
79
static const Widget _graph_legend_widgets[] = {
80
{ WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
81
{ WWT_CAPTION, RESIZE_NONE, COLOUR_GREY, 11, 249, 0, 13, STR_704E_KEY_TO_COMPANY_GRAPHS, STR_018C_WINDOW_TITLE_DRAG_THIS},
82
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 249, 14, 195, 0x0, STR_NULL},
83
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 2, 247, 16, 27, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
84
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 2, 247, 28, 39, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
85
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 2, 247, 40, 51, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
86
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 2, 247, 52, 63, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
87
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 2, 247, 64, 75, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
88
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 2, 247, 76, 87, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
89
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 2, 247, 88, 99, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
90
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 2, 247, 100, 111, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
91
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 2, 247, 112, 123, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
92
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 2, 247, 124, 135, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
93
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 2, 247, 136, 147, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
94
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 2, 247, 148, 159, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
95
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 2, 247, 160, 171, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
96
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 2, 247, 172, 183, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
97
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 2, 247, 184, 195, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
101
static const WindowDesc _graph_legend_desc(
102
WDP_AUTO, WDP_AUTO, 250, 198, 250, 198,
103
WC_GRAPH_LEGEND, WC_NONE,
104
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
105
_graph_legend_widgets
108
static void ShowGraphLegend()
110
AllocateWindowDescFront<GraphLegendWindow>(&_graph_legend_desc, 0);
117
struct BaseGraphWindow : Window {
120
GRAPH_MAX_DATASETS = 32,
121
GRAPH_AXIS_LINE_COLOUR = 215,
123
GRAPH_X_POSITION_BEGINNING = 44, ///< Start the graph 44 pixels from gd_left
124
GRAPH_X_POSITION_SEPARATION = 22, ///< There are 22 pixels between each X value
126
GRAPH_NUM_LINES_Y = 9, ///< How many horizontal lines to draw.
127
/* 9 is convenient as that means the distance between them is the gd_height of the graph / 8,
50
132
uint excluded_data; ///< bitmask of the datasets that shouldn't be displayed.
52
134
byte num_on_x_axis;
53
135
bool has_negative_values;
54
136
byte num_vert_lines;
137
static const TextColour graph_axis_label_colour = TC_BLACK; ///< colour of the graph axis label.
56
139
/* The starting month and year that values are plotted against. If month is
57
140
* 0xFF, use x_values_start and x_values_increment below instead. */
63
146
uint16 x_values_start;
64
147
uint16 x_values_increment;
66
int left, top; ///< Where to start drawing the graph, in pixels.
67
uint height; ///< The height of the graph in pixels.
149
int gd_left, gd_top; ///< Where to start drawing the graph, in pixels.
150
uint gd_height; ///< The height of the graph in pixels.
68
151
StringID format_str_y_axis;
69
byte colors[GRAPH_MAX_DATASETS];
152
byte colours[GRAPH_MAX_DATASETS];
70
153
OverflowSafeInt64 cost[GRAPH_MAX_DATASETS][24]; ///< last 2 years
73
static void DrawGraph(const GraphDrawer *gw)
75
uint x, y; ///< Reused whenever x and y coordinates are needed.
76
OverflowSafeInt64 highest_value; ///< Highest value to be drawn.
77
int x_axis_offset; ///< Distance from the top of the graph to the x axis.
79
/* the colors and cost array of GraphDrawer must accomodate
80
* both values for cargo and players. So if any are higher, quit */
81
assert(GRAPH_MAX_DATASETS >= (int)NUM_CARGO && GRAPH_MAX_DATASETS >= (int)MAX_PLAYERS);
82
assert(gw->num_vert_lines > 0);
84
byte grid_colour = _colour_gradient[14][4];
86
/* The coordinates of the opposite edges of the graph. */
87
int bottom = gw->top + gw->height - 1;
88
int right = gw->left + GRAPH_X_POSITION_BEGINNING + gw->num_vert_lines * GRAPH_X_POSITION_SEPARATION - 1;
90
/* Draw the vertical grid lines. */
92
/* Don't draw the first line, as that's where the axis will be. */
93
x = gw->left + GRAPH_X_POSITION_BEGINNING + GRAPH_X_POSITION_SEPARATION;
95
for (int i = 0; i < gw->num_vert_lines; i++) {
96
GfxFillRect(x, gw->top, x, bottom, grid_colour);
97
x += GRAPH_X_POSITION_SEPARATION;
100
/* Draw the horizontal grid lines. */
101
x = gw->left + GRAPH_X_POSITION_BEGINNING;
102
y = gw->height + gw->top;
104
for (int i = 0; i < GRAPH_NUM_LINES_Y; i++) {
105
GfxFillRect(x, y, right, y, grid_colour);
106
y -= (gw->height / (GRAPH_NUM_LINES_Y - 1));
109
/* Draw the y axis. */
110
GfxFillRect(x, gw->top, x, bottom, GRAPH_AXIS_LINE_COLOUR);
112
/* Find the distance from the top of the graph to the x axis. */
113
x_axis_offset = gw->height;
115
/* The graph is currently symmetrical about the x axis. */
116
if (gw->has_negative_values) x_axis_offset /= 2;
118
/* Draw the x axis. */
119
y = x_axis_offset + gw->top;
120
GfxFillRect(x, y, right, y, GRAPH_AXIS_LINE_COLOUR);
122
/* Find the largest value that will be drawn. */
123
if (gw->num_on_x_axis == 0)
126
assert(gw->num_on_x_axis > 0);
127
assert(gw->num_dataset > 0);
129
/* Start of with a value of twice the height of the graph in pixels. It's a
130
* bit arbitrary, but it makes the cargo payment graph look a little nicer,
131
* and prevents division by zero when calculating where the datapoint
132
* should be drawn. */
133
highest_value = x_axis_offset * 2;
135
for (int i = 0; i < gw->num_dataset; i++) {
136
if (!HasBit(gw->excluded_data, i)) {
137
for (int j = 0; j < gw->num_on_x_axis; j++) {
138
OverflowSafeInt64 datapoint = gw->cost[i][j];
140
if (datapoint != INVALID_DATAPOINT) {
141
/* For now, if the graph has negative values the scaling is
142
* symmetrical about the x axis, so take the absolute value
143
* of each data point. */
144
highest_value = max(highest_value, abs(datapoint));
150
/* Round up highest_value so that it will divide cleanly into the number of
151
* axis labels used. */
152
int round_val = highest_value % (GRAPH_NUM_LINES_Y - 1);
153
if (round_val != 0) highest_value += (GRAPH_NUM_LINES_Y - 1 - round_val);
155
/* draw text strings on the y axis */
156
int64 y_label = highest_value;
157
int64 y_label_separation = highest_value / (GRAPH_NUM_LINES_Y - 1);
159
/* If there are negative values, the graph goes from highest_value to
160
* -highest_value, not highest_value to 0. */
161
if (gw->has_negative_values) y_label_separation *= 2;
163
x = gw->left + GRAPH_X_POSITION_BEGINNING + 1;
166
for (int i = 0; i < GRAPH_NUM_LINES_Y; i++) {
167
SetDParam(0, gw->format_str_y_axis);
168
SetDParam(1, y_label);
169
DrawStringRightAligned(x, y, STR_0170, GRAPH_AXIS_LABEL_COLOUR);
171
y_label -= y_label_separation;
172
y += (gw->height / (GRAPH_NUM_LINES_Y - 1));
175
/* draw strings on the x axis */
176
if (gw->month != 0xFF) {
177
x = gw->left + GRAPH_X_POSITION_BEGINNING;
178
y = gw->top + gw->height + 1;
179
byte month = gw->month;
180
Year year = gw->year;
181
for (int i = 0; i < gw->num_on_x_axis; i++) {
182
SetDParam(0, month + STR_0162_JAN);
183
SetDParam(1, month + STR_0162_JAN + 2);
185
DrawString(x, y, month == 0 ? STR_016F : STR_016E, GRAPH_AXIS_LABEL_COLOUR);
192
x += GRAPH_X_POSITION_SEPARATION;
195
/* Draw the label under the data point rather than on the grid line. */
196
x = gw->left + GRAPH_X_POSITION_BEGINNING + (GRAPH_X_POSITION_SEPARATION / 2) + 1;
197
y = gw->top + gw->height + 1;
198
uint16 label = gw->x_values_start;
200
for (int i = 0; i < gw->num_on_x_axis; i++) {
202
DrawStringCentered(x, y, STR_01CB, GRAPH_AXIS_LABEL_COLOUR);
204
label += gw->x_values_increment;
205
x += GRAPH_X_POSITION_SEPARATION;
209
/* draw lines and dots */
210
for (int i = 0; i < gw->num_dataset; i++) {
211
if (!HasBit(gw->excluded_data, i)) {
212
/* Centre the dot between the grid lines. */
213
x = gw->left + GRAPH_X_POSITION_BEGINNING + (GRAPH_X_POSITION_SEPARATION / 2);
215
byte color = gw->colors[i];
216
uint prev_x = INVALID_DATAPOINT_POS;
217
uint prev_y = INVALID_DATAPOINT_POS;
219
for (int j = 0; j < gw->num_on_x_axis; j++) {
220
OverflowSafeInt64 datapoint = gw->cost[i][j];
222
if (datapoint != INVALID_DATAPOINT) {
224
* Check whether we need to reduce the 'accuracy' of the
225
* datapoint value and the highest value to splut overflows.
226
* And when 'drawing' 'one million' or 'one million and one'
227
* there is no significant difference, so the least
228
* significant bits can just be removed.
230
* If there are more bits needed than would fit in a 32 bits
231
* integer, so at about 31 bits because of the sign bit, the
232
* least significant bits are removed.
234
int mult_range = FindLastBit(x_axis_offset) + FindLastBit(abs(datapoint));
235
int reduce_range = max(mult_range - 31, 0);
237
/* Handle negative values differently (don't shift sign) */
239
datapoint = -(abs(datapoint) >> reduce_range);
155
void DrawGraph() const
157
uint x, y; ///< Reused whenever x and y coordinates are needed.
158
OverflowSafeInt64 highest_value; ///< Highest value to be drawn.
159
int x_axis_offset; ///< Distance from the top of the graph to the x axis.
161
/* the colours and cost array of GraphDrawer must accomodate
162
* both values for cargo and companies. So if any are higher, quit */
163
assert(GRAPH_MAX_DATASETS >= (int)NUM_CARGO && GRAPH_MAX_DATASETS >= (int)MAX_COMPANIES);
164
assert(this->num_vert_lines > 0);
166
byte grid_colour = _colour_gradient[COLOUR_GREY][4];
168
/* The coordinates of the opposite edges of the graph. */
169
int bottom = this->gd_top + this->gd_height - 1;
170
int right = this->gd_left + GRAPH_X_POSITION_BEGINNING + this->num_vert_lines * GRAPH_X_POSITION_SEPARATION - 1;
172
/* Draw the vertical grid lines. */
174
/* Don't draw the first line, as that's where the axis will be. */
175
x = this->gd_left + GRAPH_X_POSITION_BEGINNING + GRAPH_X_POSITION_SEPARATION;
177
for (int i = 0; i < this->num_vert_lines; i++) {
178
GfxFillRect(x, this->gd_top, x, bottom, grid_colour);
179
x += GRAPH_X_POSITION_SEPARATION;
182
/* Draw the horizontal grid lines. */
183
x = this->gd_left + GRAPH_X_POSITION_BEGINNING;
184
y = this->gd_height + this->gd_top;
186
for (int i = 0; i < GRAPH_NUM_LINES_Y; i++) {
187
GfxFillRect(x, y, right, y, grid_colour);
188
y -= (this->gd_height / (GRAPH_NUM_LINES_Y - 1));
191
/* Draw the y axis. */
192
GfxFillRect(x, this->gd_top, x, bottom, GRAPH_AXIS_LINE_COLOUR);
194
/* Find the distance from the gd_top of the graph to the x axis. */
195
x_axis_offset = this->gd_height;
197
/* The graph is currently symmetrical about the x axis. */
198
if (this->has_negative_values) x_axis_offset /= 2;
200
/* Draw the x axis. */
201
y = x_axis_offset + this->gd_top;
202
GfxFillRect(x, y, right, y, GRAPH_AXIS_LINE_COLOUR);
204
/* Find the largest value that will be drawn. */
205
if (this->num_on_x_axis == 0)
208
assert(this->num_on_x_axis > 0);
209
assert(this->num_dataset > 0);
211
/* Start of with a value of twice the gd_height of the graph in pixels. It's a
212
* bit arbitrary, but it makes the cargo payment graph look a little nicer,
213
* and prevents division by zero when calculating where the datapoint
214
* should be drawn. */
215
highest_value = x_axis_offset * 2;
217
for (int i = 0; i < this->num_dataset; i++) {
218
if (!HasBit(this->excluded_data, i)) {
219
for (int j = 0; j < this->num_on_x_axis; j++) {
220
OverflowSafeInt64 datapoint = this->cost[i][j];
222
if (datapoint != INVALID_DATAPOINT) {
223
/* For now, if the graph has negative values the scaling is
224
* symmetrical about the x axis, so take the absolute value
225
* of each data point. */
226
highest_value = max(highest_value, abs(datapoint));
232
/* Round up highest_value so that it will divide cleanly into the number of
233
* axis labels used. */
234
int round_val = highest_value % (GRAPH_NUM_LINES_Y - 1);
235
if (round_val != 0) highest_value += (GRAPH_NUM_LINES_Y - 1 - round_val);
237
/* draw text strings on the y axis */
238
int64 y_label = highest_value;
239
int64 y_label_separation = highest_value / (GRAPH_NUM_LINES_Y - 1);
241
/* If there are negative values, the graph goes from highest_value to
242
* -highest_value, not highest_value to 0. */
243
if (this->has_negative_values) y_label_separation *= 2;
245
x = this->gd_left + GRAPH_X_POSITION_BEGINNING + 1;
246
y = this->gd_top - 3;
248
for (int i = 0; i < GRAPH_NUM_LINES_Y; i++) {
249
SetDParam(0, this->format_str_y_axis);
250
SetDParam(1, y_label);
251
DrawStringRightAligned(x, y, STR_0170, graph_axis_label_colour);
253
y_label -= y_label_separation;
254
y += (this->gd_height / (GRAPH_NUM_LINES_Y - 1));
257
/* draw strings on the x axis */
258
if (this->month != 0xFF) {
259
x = this->gd_left + GRAPH_X_POSITION_BEGINNING;
260
y = this->gd_top + this->gd_height + 1;
261
byte month = this->month;
262
Year year = this->year;
263
for (int i = 0; i < this->num_on_x_axis; i++) {
264
SetDParam(0, month + STR_0162_JAN);
265
SetDParam(1, month + STR_0162_JAN + 2);
267
DrawString(x, y, month == 0 ? STR_016F : STR_016E, graph_axis_label_colour);
274
x += GRAPH_X_POSITION_SEPARATION;
277
/* Draw the label under the data point rather than on the grid line. */
278
x = this->gd_left + GRAPH_X_POSITION_BEGINNING + (GRAPH_X_POSITION_SEPARATION / 2) + 1;
279
y = this->gd_top + this->gd_height + 1;
280
uint16 label = this->x_values_start;
282
for (int i = 0; i < this->num_on_x_axis; i++) {
284
DrawStringCentered(x, y, STR_01CB, graph_axis_label_colour);
286
label += this->x_values_increment;
287
x += GRAPH_X_POSITION_SEPARATION;
291
/* draw lines and dots */
292
for (int i = 0; i < this->num_dataset; i++) {
293
if (!HasBit(this->excluded_data, i)) {
294
/* Centre the dot between the grid lines. */
295
x = this->gd_left + GRAPH_X_POSITION_BEGINNING + (GRAPH_X_POSITION_SEPARATION / 2);
297
byte colour = this->colours[i];
298
uint prev_x = INVALID_DATAPOINT_POS;
299
uint prev_y = INVALID_DATAPOINT_POS;
301
for (int j = 0; j < this->num_on_x_axis; j++) {
302
OverflowSafeInt64 datapoint = this->cost[i][j];
304
if (datapoint != INVALID_DATAPOINT) {
306
* Check whether we need to reduce the 'accuracy' of the
307
* datapoint value and the highest value to splut overflows.
308
* And when 'drawing' 'one million' or 'one million and one'
309
* there is no significant difference, so the least
310
* significant bits can just be removed.
312
* If there are more bits needed than would fit in a 32 bits
313
* integer, so at about 31 bits because of the sign bit, the
314
* least significant bits are removed.
316
int mult_range = FindLastBit(x_axis_offset) + FindLastBit(abs(datapoint));
317
int reduce_range = max(mult_range - 31, 0);
319
/* Handle negative values differently (don't shift sign) */
321
datapoint = -(abs(datapoint) >> reduce_range);
323
datapoint >>= reduce_range;
326
y = this->gd_top + x_axis_offset - (x_axis_offset * datapoint) / (highest_value >> reduce_range);
328
/* Draw the point. */
329
GfxFillRect(x - 1, y - 1, x + 1, y + 1, colour);
331
/* Draw the line connected to the previous point. */
332
if (prev_x != INVALID_DATAPOINT_POS) GfxDrawLine(prev_x, prev_y, x, y, colour);
241
datapoint >>= reduce_range;
337
prev_x = INVALID_DATAPOINT_POS;
338
prev_y = INVALID_DATAPOINT_POS;
244
y = gw->top + x_axis_offset - (x_axis_offset * datapoint) / (highest_value >> reduce_range);
246
/* Draw the point. */
247
GfxFillRect(x - 1, y - 1, x + 1, y + 1, color);
249
/* Draw the line connected to the previous point. */
250
if (prev_x != INVALID_DATAPOINT_POS) GfxDrawLine(prev_x, prev_y, x, y, color);
255
prev_x = INVALID_DATAPOINT_POS;
256
prev_y = INVALID_DATAPOINT_POS;
259
x += GRAPH_X_POSITION_SEPARATION;
269
static void GraphLegendWndProc(Window *w, WindowEvent *e)
273
for (uint i = 3; i < w->widget_count; i++) {
274
if (!HasBit(_legend_excluded_players, i - 3)) w->LowerWidget(i);
282
if (p->is_active) continue;
284
SetBit(_legend_excluded_players, p->index);
285
w->RaiseWidget(p->index + 3);
288
DrawWindowWidgets(w);
291
if (!p->is_active) continue;
293
DrawPlayerIcon(p->index, 4, 18 + p->index * 12);
295
SetDParam(0, p->index);
296
SetDParam(1, p->index);
297
DrawString(21, 17 + p->index * 12, STR_7021, HasBit(_legend_excluded_players, p->index) ? TC_BLACK : TC_WHITE);
303
if (!IsInsideMM(e->we.click.widget, 3, 11)) return;
305
ToggleBit(_legend_excluded_players, e->we.click.widget - 3);
306
w->ToggleWidgetLoweredState(e->we.click.widget);
308
InvalidateWindow(WC_INCOME_GRAPH, 0);
309
InvalidateWindow(WC_OPERATING_PROFIT, 0);
310
InvalidateWindow(WC_DELIVERED_CARGO, 0);
311
InvalidateWindow(WC_PERFORMANCE_HISTORY, 0);
312
InvalidateWindow(WC_COMPANY_VALUE, 0);
317
static const Widget _graph_legend_widgets[] = {
318
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
319
{ WWT_CAPTION, RESIZE_NONE, 14, 11, 249, 0, 13, STR_704E_KEY_TO_COMPANY_GRAPHS, STR_018C_WINDOW_TITLE_DRAG_THIS},
320
{ WWT_PANEL, RESIZE_NONE, 14, 0, 249, 14, 113, 0x0, STR_NULL},
321
{ WWT_PANEL, RESIZE_NONE, 14, 2, 247, 16, 27, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
322
{ WWT_PANEL, RESIZE_NONE, 14, 2, 247, 28, 39, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
323
{ WWT_PANEL, RESIZE_NONE, 14, 2, 247, 40, 51, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
324
{ WWT_PANEL, RESIZE_NONE, 14, 2, 247, 52, 63, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
325
{ WWT_PANEL, RESIZE_NONE, 14, 2, 247, 64, 75, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
326
{ WWT_PANEL, RESIZE_NONE, 14, 2, 247, 76, 87, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
327
{ WWT_PANEL, RESIZE_NONE, 14, 2, 247, 88, 99, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
328
{ WWT_PANEL, RESIZE_NONE, 14, 2, 247, 100, 111, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
332
static const WindowDesc _graph_legend_desc = {
333
WDP_AUTO, WDP_AUTO, 250, 114, 250, 114,
334
WC_GRAPH_LEGEND, WC_NONE,
335
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
336
_graph_legend_widgets,
340
static void ShowGraphLegend()
342
AllocateWindowDescFront(&_graph_legend_desc, 0);
341
x += GRAPH_X_POSITION_SEPARATION;
348
BaseGraphWindow(const WindowDesc *desc, WindowNumber window_number, int left,
349
int top, int height, bool has_negative_values, StringID format_str_y_axis) :
350
Window(desc, window_number), has_negative_values(has_negative_values),
351
gd_left(left), gd_top(top), gd_height(height), format_str_y_axis(format_str_y_axis)
353
InvalidateWindow(WC_GRAPH_LEGEND, 0);
357
virtual void OnPaint()
361
uint excluded_companies = _legend_excluded_companies;
363
/* Exclude the companies which aren't valid */
364
for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
365
if (!IsValidCompanyID(c)) SetBit(excluded_companies, c);
367
this->excluded_data = excluded_companies;
368
this->num_vert_lines = 24;
372
FOR_ALL_COMPANIES(c) {
373
nums = max(nums, c->num_valid_stat_ent);
375
this->num_on_x_axis = min(nums, 24);
377
int mo = (_cur_month / 3 - nums) * 3;
388
for (CompanyID k = COMPANY_FIRST; k < MAX_COMPANIES; k++) {
389
if (IsValidCompanyID(k)) {
391
this->colours[numd] = _colour_gradient[c->colour][6];
392
for (int j = this->num_on_x_axis, i = 0; --j >= 0;) {
393
this->cost[numd][i] = (j >= c->num_valid_stat_ent) ? INVALID_DATAPOINT : GetGraphData(c, j);
400
this->num_dataset = numd;
405
virtual OverflowSafeInt64 GetGraphData(const Company *c, int j)
407
return INVALID_DATAPOINT;
410
virtual void OnClick(Point pt, int widget)
412
/* Clicked on legend? */
413
if (widget == 2) ShowGraphLegend();
345
417
/********************/
346
418
/* OPERATING PROFIT */
347
419
/********************/
349
static void SetupGraphDrawerForPlayers(GraphDrawer *gd)
352
uint excluded_players = _legend_excluded_players;
356
/* Exclude the players which aren't valid */
358
if (!p->is_active) SetBit(excluded_players, p->index);
360
gd->excluded_data = excluded_players;
361
gd->num_vert_lines = 24;
365
if (p->is_active) nums = max(nums, p->num_valid_stat_ent);
367
gd->num_on_x_axis = min(nums, 24);
369
mo = (_cur_month / 3 - nums) * 3;
380
static void OperatingProfitWndProc(Window *w, WindowEvent *e)
387
DrawWindowWidgets(w);
392
gd.has_negative_values = true;
393
gd.format_str_y_axis = STR_CURRCOMPACT;
395
SetupGraphDrawerForPlayers(&gd);
400
gd.colors[numd] = _colour_gradient[p->player_color][6];
401
for (int j = gd.num_on_x_axis, i = 0; --j >= 0;) {
402
gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_DATAPOINT : (p->old_economy[j].income + p->old_economy[j].expenses);
409
gd.num_dataset = numd;
416
/* Clicked on legend? */
417
if (e->we.click.widget == 2) ShowGraphLegend();
421
struct OperatingProfitGraphWindow : BaseGraphWindow {
422
OperatingProfitGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
423
BaseGraphWindow(desc, window_number, 2, 18, 136, true, STR_CURRCOMPACT)
425
this->FindWindowPlacementAndResize(desc);
428
virtual OverflowSafeInt64 GetGraphData(const Company *c, int j)
430
return c->old_economy[j].income + c->old_economy[j].expenses;
422
434
static const Widget _operating_profit_widgets[] = {
423
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
424
{ WWT_CAPTION, RESIZE_NONE, 14, 11, 525, 0, 13, STR_7025_OPERATING_PROFIT_GRAPH, STR_018C_WINDOW_TITLE_DRAG_THIS},
425
{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
426
{ WWT_PANEL, RESIZE_NONE, 14, 0, 575, 14, 173, 0x0, STR_NULL},
435
{ WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
436
{ WWT_CAPTION, RESIZE_NONE, COLOUR_GREY, 11, 525, 0, 13, STR_7025_OPERATING_PROFIT_GRAPH, STR_018C_WINDOW_TITLE_DRAG_THIS},
437
{ WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_GREY, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
438
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 575, 14, 173, 0x0, STR_NULL},
430
static const WindowDesc _operating_profit_desc = {
442
static const WindowDesc _operating_profit_desc(
431
443
WDP_AUTO, WDP_AUTO, 576, 174, 576, 174,
432
444
WC_OPERATING_PROFIT, WC_NONE,
433
445
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
434
_operating_profit_widgets,
435
OperatingProfitWndProc
446
_operating_profit_widgets
439
450
void ShowOperatingProfitGraph()
441
if (AllocateWindowDescFront(&_operating_profit_desc, 0)) {
442
InvalidateWindow(WC_GRAPH_LEGEND, 0);
452
AllocateWindowDescFront<OperatingProfitGraphWindow>(&_operating_profit_desc, 0);
448
457
/* INCOME GRAPH */
449
458
/****************/
451
static void IncomeGraphWndProc(Window *w, WindowEvent *e)
458
DrawWindowWidgets(w);
463
gd.has_negative_values = false;
464
gd.format_str_y_axis = STR_CURRCOMPACT;
465
SetupGraphDrawerForPlayers(&gd);
470
gd.colors[numd] = _colour_gradient[p->player_color][6];
471
for (int j = gd.num_on_x_axis, i = 0; --j >= 0;) {
472
gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_DATAPOINT : p->old_economy[j].income;
479
gd.num_dataset = numd;
486
if (e->we.click.widget == 2) ShowGraphLegend();
460
struct IncomeGraphWindow : BaseGraphWindow {
461
IncomeGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
462
BaseGraphWindow(desc, window_number, 2, 18, 104, false, STR_CURRCOMPACT)
464
this->FindWindowPlacementAndResize(desc);
467
virtual OverflowSafeInt64 GetGraphData(const Company *c, int j)
469
return c->old_economy[j].income;
491
473
static const Widget _income_graph_widgets[] = {
492
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
493
{ WWT_CAPTION, RESIZE_NONE, 14, 11, 525, 0, 13, STR_7022_INCOME_GRAPH, STR_018C_WINDOW_TITLE_DRAG_THIS},
494
{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
495
{ WWT_PANEL, RESIZE_NONE, 14, 0, 575, 14, 141, 0x0, STR_NULL},
474
{ WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
475
{ WWT_CAPTION, RESIZE_NONE, COLOUR_GREY, 11, 525, 0, 13, STR_7022_INCOME_GRAPH, STR_018C_WINDOW_TITLE_DRAG_THIS},
476
{ WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_GREY, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
477
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 575, 14, 141, 0x0, STR_NULL},
499
static const WindowDesc _income_graph_desc = {
481
static const WindowDesc _income_graph_desc(
500
482
WDP_AUTO, WDP_AUTO, 576, 142, 576, 142,
501
483
WC_INCOME_GRAPH, WC_NONE,
502
484
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
503
_income_graph_widgets,
485
_income_graph_widgets
507
488
void ShowIncomeGraph()
509
if (AllocateWindowDescFront(&_income_graph_desc, 0)) {
510
InvalidateWindow(WC_GRAPH_LEGEND, 0);
490
AllocateWindowDescFront<IncomeGraphWindow>(&_income_graph_desc, 0);
514
493
/*******************/
515
494
/* DELIVERED CARGO */
516
495
/*******************/
518
static void DeliveredCargoGraphWndProc(Window *w, WindowEvent *e)
525
DrawWindowWidgets(w);
530
gd.has_negative_values = false;
531
gd.format_str_y_axis = STR_7024;
532
SetupGraphDrawerForPlayers(&gd);
537
gd.colors[numd] = _colour_gradient[p->player_color][6];
538
for (int j = gd.num_on_x_axis, i = 0; --j >= 0;) {
539
gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_DATAPOINT : (OverflowSafeInt64)p->old_economy[j].delivered_cargo;
546
gd.num_dataset = numd;
553
if (e->we.click.widget == 2) ShowGraphLegend();
497
struct DeliveredCargoGraphWindow : BaseGraphWindow {
498
DeliveredCargoGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
499
BaseGraphWindow(desc, window_number, 2, 18, 104, false, STR_7024)
501
this->FindWindowPlacementAndResize(desc);
504
virtual OverflowSafeInt64 GetGraphData(const Company *c, int j)
506
return c->old_economy[j].delivered_cargo;
558
510
static const Widget _delivered_cargo_graph_widgets[] = {
559
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
560
{ WWT_CAPTION, RESIZE_NONE, 14, 11, 525, 0, 13, STR_7050_UNITS_OF_CARGO_DELIVERED, STR_018C_WINDOW_TITLE_DRAG_THIS},
561
{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
562
{ WWT_PANEL, RESIZE_NONE, 14, 0, 575, 14, 141, 0x0, STR_NULL},
511
{ WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
512
{ WWT_CAPTION, RESIZE_NONE, COLOUR_GREY, 11, 525, 0, 13, STR_7050_UNITS_OF_CARGO_DELIVERED, STR_018C_WINDOW_TITLE_DRAG_THIS},
513
{ WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_GREY, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
514
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 575, 14, 141, 0x0, STR_NULL},
566
static const WindowDesc _delivered_cargo_graph_desc = {
518
static const WindowDesc _delivered_cargo_graph_desc(
567
519
WDP_AUTO, WDP_AUTO, 576, 142, 576, 142,
568
520
WC_DELIVERED_CARGO, WC_NONE,
569
521
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
570
_delivered_cargo_graph_widgets,
571
DeliveredCargoGraphWndProc
522
_delivered_cargo_graph_widgets
574
525
void ShowDeliveredCargoGraph()
576
if (AllocateWindowDescFront(&_delivered_cargo_graph_desc, 0)) {
577
InvalidateWindow(WC_GRAPH_LEGEND, 0);
527
AllocateWindowDescFront<DeliveredCargoGraphWindow>(&_delivered_cargo_graph_desc, 0);
581
530
/***********************/
582
531
/* PERFORMANCE HISTORY */
583
532
/***********************/
585
static void PerformanceHistoryWndProc(Window *w, WindowEvent *e)
592
DrawWindowWidgets(w);
597
gd.has_negative_values = false;
598
gd.format_str_y_axis = STR_7024;
599
SetupGraphDrawerForPlayers(&gd);
604
gd.colors[numd] = _colour_gradient[p->player_color][6];
605
for (int j = gd.num_on_x_axis, i = 0; --j >= 0;) {
606
gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_DATAPOINT : (OverflowSafeInt64)p->old_economy[j].performance_history;
613
gd.num_dataset = numd;
620
if (e->we.click.widget == 2) ShowGraphLegend();
621
if (e->we.click.widget == 3) ShowPerformanceRatingDetail();
534
struct PerformanceHistoryGraphWindow : BaseGraphWindow {
535
PerformanceHistoryGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
536
BaseGraphWindow(desc, window_number, 2, 18, 200, false, STR_7024)
538
this->FindWindowPlacementAndResize(desc);
541
virtual OverflowSafeInt64 GetGraphData(const Company *c, int j)
543
return c->old_economy[j].performance_history;
546
virtual void OnClick(Point pt, int widget)
548
if (widget == 3) ShowPerformanceRatingDetail();
549
this->BaseGraphWindow::OnClick(pt, widget);
626
553
static const Widget _performance_history_widgets[] = {
627
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
628
{ WWT_CAPTION, RESIZE_NONE, 14, 11, 475, 0, 13, STR_7051_COMPANY_PERFORMANCE_RATINGS, STR_018C_WINDOW_TITLE_DRAG_THIS},
629
{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
630
{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 476, 525, 0, 13, STR_PERFORMANCE_DETAIL_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
631
{ WWT_PANEL, RESIZE_NONE, 14, 0, 575, 14, 237, 0x0, STR_NULL},
554
{ WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
555
{ WWT_CAPTION, RESIZE_NONE, COLOUR_GREY, 11, 475, 0, 13, STR_7051_COMPANY_PERFORMANCE_RATINGS, STR_018C_WINDOW_TITLE_DRAG_THIS},
556
{ WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_GREY, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
557
{ WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_GREY, 476, 525, 0, 13, STR_PERFORMANCE_DETAIL_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
558
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 575, 14, 237, 0x0, STR_NULL},
635
static const WindowDesc _performance_history_desc = {
562
static const WindowDesc _performance_history_desc(
636
563
WDP_AUTO, WDP_AUTO, 576, 238, 576, 238,
637
564
WC_PERFORMANCE_HISTORY, WC_NONE,
638
565
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
639
_performance_history_widgets,
640
PerformanceHistoryWndProc
566
_performance_history_widgets
643
569
void ShowPerformanceHistoryGraph()
645
if (AllocateWindowDescFront(&_performance_history_desc, 0)) {
646
InvalidateWindow(WC_GRAPH_LEGEND, 0);
571
AllocateWindowDescFront<PerformanceHistoryGraphWindow>(&_performance_history_desc, 0);
650
574
/*****************/
651
575
/* COMPANY VALUE */
652
576
/*****************/
654
static void CompanyValueGraphWndProc(Window *w, WindowEvent *e)
661
DrawWindowWidgets(w);
666
gd.has_negative_values = false;
667
gd.format_str_y_axis = STR_CURRCOMPACT;
668
SetupGraphDrawerForPlayers(&gd);
673
gd.colors[numd] = _colour_gradient[p->player_color][6];
674
for (int j = gd.num_on_x_axis, i = 0; --j >= 0;) {
675
gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_DATAPOINT : p->old_economy[j].company_value;
682
gd.num_dataset = numd;
689
if (e->we.click.widget == 2) ShowGraphLegend();
578
struct CompanyValueGraphWindow : BaseGraphWindow {
579
CompanyValueGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
580
BaseGraphWindow(desc, window_number, 2, 18, 200, false, STR_CURRCOMPACT)
582
this->FindWindowPlacementAndResize(desc);
585
virtual OverflowSafeInt64 GetGraphData(const Company *c, int j)
587
return c->old_economy[j].company_value;
694
591
static const Widget _company_value_graph_widgets[] = {
695
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
696
{ WWT_CAPTION, RESIZE_NONE, 14, 11, 525, 0, 13, STR_7052_COMPANY_VALUES, STR_018C_WINDOW_TITLE_DRAG_THIS},
697
{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
698
{ WWT_PANEL, RESIZE_NONE, 14, 0, 575, 14, 237, 0x0, STR_NULL},
592
{ WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
593
{ WWT_CAPTION, RESIZE_NONE, COLOUR_GREY, 11, 525, 0, 13, STR_7052_COMPANY_VALUES, STR_018C_WINDOW_TITLE_DRAG_THIS},
594
{ WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_GREY, 526, 575, 0, 13, STR_704C_KEY, STR_704D_SHOW_KEY_TO_GRAPHS},
595
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 575, 14, 237, 0x0, STR_NULL},
702
static const WindowDesc _company_value_graph_desc = {
599
static const WindowDesc _company_value_graph_desc(
703
600
WDP_AUTO, WDP_AUTO, 576, 238, 576, 238,
704
601
WC_COMPANY_VALUE, WC_NONE,
705
602
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
706
_company_value_graph_widgets,
707
CompanyValueGraphWndProc
603
_company_value_graph_widgets
710
606
void ShowCompanyValueGraph()
712
if (AllocateWindowDescFront(&_company_value_graph_desc, 0)) {
713
InvalidateWindow(WC_GRAPH_LEGEND, 0);
608
AllocateWindowDescFront<CompanyValueGraphWindow>(&_company_value_graph_desc, 0);
717
611
/*****************/
718
612
/* PAYMENT RATES */
719
613
/*****************/
721
static void CargoPaymentRatesWndProc(Window *w, WindowEvent *e)
727
DrawWindowWidgets(w);
732
gd.excluded_data = _legend_excluded_cargo;
735
gd.height = w->height - 38;
736
gd.has_negative_values = false;
737
gd.format_str_y_axis = STR_CURRCOMPACT;
738
gd.num_on_x_axis = 20;
739
gd.num_vert_lines = 20;
741
gd.x_values_start = 10;
742
gd.x_values_increment = 10;
745
for (CargoID c = 0; c < NUM_CARGO; c++) {
746
const CargoSpec *cs = GetCargo(c);
747
if (!cs->IsValid()) continue;
749
/* Only draw labels for widgets that exist. If the widget doesn't
750
* exist then the local player has used the climate cheat or
751
* changed the NewGRF configuration with this window open. */
752
if (i + 3 < w->widget_count) {
753
/* Since the buttons have no text, no images,
754
* both the text and the colored box have to be manually painted.
755
* clk_dif will move one pixel down and one pixel to the right
756
* when the button is clicked */
757
byte clk_dif = w->IsWidgetLowered(i + 3) ? 1 : 0;
759
GfxFillRect(x + clk_dif, y + clk_dif, x + 8 + clk_dif, y + 5 + clk_dif, 0);
760
GfxFillRect(x + 1 + clk_dif, y + 1 + clk_dif, x + 7 + clk_dif, y + 4 + clk_dif, cs->legend_colour);
761
SetDParam(0, cs->name);
762
DrawString(x + 14 + clk_dif, y + clk_dif, STR_7065, TC_FROMSTRING);
766
gd.colors[i] = cs->legend_colour;
767
for (uint j = 0; j != 20; j++) {
768
gd.cost[i][j] = GetTransportedGoodsIncome(10, 20, j * 4 + 4, c);
777
DrawString(2 + 46, 24 + gd.height + 7, STR_7062_DAYS_IN_TRANSIT, TC_FROMSTRING);
778
DrawString(2 + 84, 24 - 9, STR_7063_PAYMENT_FOR_DELIVERING, TC_FROMSTRING);
783
if (e->we.click.widget >= 3) {
784
ToggleBit(_legend_excluded_cargo, e->we.click.widget - 3);
785
w->ToggleWidgetLoweredState(e->we.click.widget);
615
struct PaymentRatesGraphWindow : BaseGraphWindow {
616
PaymentRatesGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
617
BaseGraphWindow(desc, window_number, 2, 24, 200, false, STR_CURRCOMPACT)
620
for (CargoID c = 0; c < NUM_CARGO; c++) {
621
if (GetCargo(c)->IsValid()) num_active++;
624
/* Resize the window to fit the cargo types */
625
ResizeWindow(this, 0, max(num_active, 12U) * 8);
627
/* Add widgets for each cargo type */
628
this->widget_count += num_active;
629
this->widget = ReallocT(this->widget, this->widget_count + 1);
630
this->widget[this->widget_count].type = WWT_LAST;
632
/* Set the properties of each widget */
633
for (uint i = 0; i != num_active; i++) {
634
Widget *wi = &this->widget[3 + i];
635
wi->type = WWT_PANEL;
636
wi->display_flags = RESIZE_NONE;
637
wi->colour = COLOUR_ORANGE;
640
wi->top = 24 + i * 8;
641
wi->bottom = wi->top + 7;
643
wi->tooltips = STR_7064_TOGGLE_GRAPH_FOR_CARGO;
645
if (!HasBit(_legend_excluded_cargo, i)) this->LowerWidget(i + 3);
650
this->gd_height = this->height - 38;
651
this->num_on_x_axis = 20;
652
this->num_vert_lines = 20;
654
this->x_values_start = 10;
655
this->x_values_increment = 10;
657
this->FindWindowPlacementAndResize(desc);
660
virtual void OnPaint()
664
this->excluded_data = _legend_excluded_cargo;
670
for (CargoID c = 0; c < NUM_CARGO; c++) {
671
const CargoSpec *cs = GetCargo(c);
672
if (!cs->IsValid()) continue;
674
/* Only draw labels for widgets that exist. If the widget doesn't
675
* exist then the local company has used the climate cheat or
676
* changed the NewGRF configuration with this window open. */
677
if (i + 3 < this->widget_count) {
678
/* Since the buttons have no text, no images,
679
* both the text and the coloured box have to be manually painted.
680
* clk_dif will move one pixel down and one pixel to the right
681
* when the button is clicked */
682
byte clk_dif = this->IsWidgetLowered(i + 3) ? 1 : 0;
684
GfxFillRect(x + clk_dif, y + clk_dif, x + 8 + clk_dif, y + 5 + clk_dif, 0);
685
GfxFillRect(x + 1 + clk_dif, y + 1 + clk_dif, x + 7 + clk_dif, y + 4 + clk_dif, cs->legend_colour);
686
SetDParam(0, cs->name);
687
DrawString(x + 14 + clk_dif, y + clk_dif, STR_7065, TC_FROMSTRING);
691
this->colours[i] = cs->legend_colour;
692
for (uint j = 0; j != 20; j++) {
693
this->cost[i][j] = GetTransportedGoodsIncome(10, 20, j * 4 + 4, c);
698
this->num_dataset = i;
702
DrawString(2 + 46, 24 + this->gd_height + 7, STR_7062_DAYS_IN_TRANSIT, TC_FROMSTRING);
703
DrawString(2 + 84, 24 - 9, STR_7063_PAYMENT_FOR_DELIVERING, TC_FROMSTRING);
706
virtual void OnClick(Point pt, int widget)
709
ToggleBit(_legend_excluded_cargo, widget - 3);
710
this->ToggleWidgetLoweredState(widget);
792
716
static const Widget _cargo_payment_rates_widgets[] = {
793
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
794
{ WWT_CAPTION, RESIZE_NONE, 14, 11, 567, 0, 13, STR_7061_CARGO_PAYMENT_RATES, STR_018C_WINDOW_TITLE_DRAG_THIS},
795
{ WWT_PANEL, RESIZE_BOTTOM, 14, 0, 567, 14, 45, 0x0, STR_NULL},
717
{ WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
718
{ WWT_CAPTION, RESIZE_NONE, COLOUR_GREY, 11, 567, 0, 13, STR_7061_CARGO_PAYMENT_RATES, STR_018C_WINDOW_TITLE_DRAG_THIS},
719
{ WWT_PANEL, RESIZE_BOTTOM, COLOUR_GREY, 0, 567, 14, 45, 0x0, STR_NULL},
799
static const WindowDesc _cargo_payment_rates_desc = {
723
static const WindowDesc _cargo_payment_rates_desc(
800
724
WDP_AUTO, WDP_AUTO, 568, 46, 568, 46,
801
725
WC_PAYMENT_RATES, WC_NONE,
802
726
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
803
_cargo_payment_rates_widgets,
804
CargoPaymentRatesWndProc
727
_cargo_payment_rates_widgets
808
731
void ShowCargoPaymentRates()
810
Window *w = AllocateWindowDescFront(&_cargo_payment_rates_desc, 0);
811
if (w == NULL) return;
813
/* Count the number of active cargo types */
815
for (CargoID c = 0; c < NUM_CARGO; c++) {
816
if (GetCargo(c)->IsValid()) num_active++;
819
/* Resize the window to fit the cargo types */
820
ResizeWindow(w, 0, max(num_active, 12U) * 8);
822
/* Add widgets for each cargo type */
823
w->widget_count += num_active;
824
w->widget = ReallocT(w->widget, w->widget_count + 1);
825
w->widget[w->widget_count].type = WWT_LAST;
827
/* Set the properties of each widget */
828
for (uint i = 0; i != num_active; i++) {
829
Widget *wi = &w->widget[3 + i];
830
wi->type = WWT_PANEL;
831
wi->display_flags = RESIZE_NONE;
835
wi->top = 24 + i * 8;
836
wi->bottom = wi->top + 7;
838
wi->tooltips = STR_7064_TOGGLE_GRAPH_FOR_CARGO;
840
if (!HasBit(_legend_excluded_cargo, i)) w->LowerWidget(i + 3);
733
AllocateWindowDescFront<PaymentRatesGraphWindow>(&_cargo_payment_rates_desc, 0);
846
736
/************************/
871
761
return _performance_titles[minu(value, 1000) >> 6];
874
static int CDECL PerfHistComp(const void* elem1, const void* elem2)
876
const Player* p1 = *(const Player* const*)elem1;
877
const Player* p2 = *(const Player* const*)elem2;
879
return p2->old_economy[1].performance_history - p1->old_economy[1].performance_history;
882
static void CompanyLeagueWndProc(Window *w, WindowEvent *e)
886
const Player* plist[MAX_PLAYERS];
889
DrawWindowWidgets(w);
892
FOR_ALL_PLAYERS(p) if (p->is_active) plist[pl_num++] = p;
894
qsort((void*)plist, pl_num, sizeof(*plist), PerfHistComp);
896
for (uint i = 0; i != pl_num; i++) {
898
SetDParam(0, i + STR_01AC_1ST);
899
SetDParam(1, p->index);
900
SetDParam(2, p->index);
901
SetDParam(3, GetPerformanceTitleFromValue(p->old_economy[1].performance_history));
903
DrawString(2, 15 + i * 10, i == 0 ? STR_7054 : STR_7055, TC_FROMSTRING);
904
DrawPlayerIcon(p->index, 27, 16 + i * 10);
764
class CompanyLeagueWindow : public Window {
766
GUIList<const Company*> companies;
769
* (Re)Build the company league list
771
void BuildCompanyList()
773
if (!this->companies.NeedRebuild()) return;
775
this->companies.Clear();
778
FOR_ALL_COMPANIES(c) {
779
*this->companies.Append() = c;
782
this->companies.Compact();
783
this->companies.RebuildDone();
786
/** Sort the company league by performance history */
787
static int CDECL PerformanceSorter(const Company * const *c1, const Company * const *c2)
789
return (*c2)->old_economy[1].performance_history - (*c1)->old_economy[1].performance_history;
793
CompanyLeagueWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
795
this->companies.ForceRebuild();
796
this->companies.NeedResort();
798
this->FindWindowPlacementAndResize(desc);
801
virtual void OnPaint()
803
this->BuildCompanyList();
804
this->companies.Sort(&PerformanceSorter);
808
for (uint i = 0; i != this->companies.Length(); i++) {
809
const Company *c = this->companies[i];
810
SetDParam(0, i + STR_01AC_1ST);
811
SetDParam(1, c->index);
812
SetDParam(2, c->index);
813
SetDParam(3, GetPerformanceTitleFromValue(c->old_economy[1].performance_history));
815
DrawString(2, 15 + i * 10, i == 0 ? STR_7054 : STR_7055, TC_FROMSTRING);
816
DrawCompanyIcon(c->index, 27, 16 + i * 10);
820
virtual void OnTick()
822
if (this->companies.NeedResort()) {
827
virtual void OnInvalidateData(int data)
830
this->companies.ForceRebuild();
832
this->companies.ForceResort();
913
838
static const Widget _company_league_widgets[] = {
914
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
915
{ WWT_CAPTION, RESIZE_NONE, 14, 11, 387, 0, 13, STR_7053_COMPANY_LEAGUE_TABLE, STR_018C_WINDOW_TITLE_DRAG_THIS},
916
{ WWT_STICKYBOX, RESIZE_NONE, 14, 388, 399, 0, 13, STR_NULL, STR_STICKY_BUTTON},
917
{ WWT_PANEL, RESIZE_NONE, 14, 0, 399, 14, 96, 0x0, STR_NULL},
839
{ WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
840
{ WWT_CAPTION, RESIZE_NONE, COLOUR_GREY, 11, 387, 0, 13, STR_7053_COMPANY_LEAGUE_TABLE, STR_018C_WINDOW_TITLE_DRAG_THIS},
841
{ WWT_STICKYBOX, RESIZE_NONE, COLOUR_GREY, 388, 399, 0, 13, STR_NULL, STR_STICKY_BUTTON},
842
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 399, 14, 166, 0x0, STR_NULL},
921
static const WindowDesc _company_league_desc = {
922
WDP_AUTO, WDP_AUTO, 400, 97, 400, 97,
846
static const WindowDesc _company_league_desc(
847
WDP_AUTO, WDP_AUTO, 400, 167, 400, 167,
923
848
WC_COMPANY_LEAGUE, WC_NONE,
924
849
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
925
_company_league_widgets,
850
_company_league_widgets
929
853
void ShowCompanyLeagueTable()
931
AllocateWindowDescFront(&_company_league_desc, 0);
855
AllocateWindowDescFront<CompanyLeagueWindow>(&_company_league_desc, 0);
934
858
/*****************************/
935
859
/* PERFORMANCE RATING DETAIL */
936
860
/*****************************/
938
static void PerformanceRatingDetailWndProc(Window *w, WindowEvent *e)
940
static PlayerID _performance_rating_detail_player = INVALID_PLAYER;
947
int color_done, color_notdone;
949
/* Draw standard stuff */
950
DrawWindowWidgets(w);
952
/* Check if the currently selected player is still active. */
953
if (_performance_rating_detail_player == INVALID_PLAYER || !GetPlayer(_performance_rating_detail_player)->is_active) {
954
if (_performance_rating_detail_player != INVALID_PLAYER) {
955
/* Raise and disable the widget for the previous selection. */
956
w->RaiseWidget(_performance_rating_detail_player + 13);
957
w->DisableWidget(_performance_rating_detail_player + 13);
960
_performance_rating_detail_player = INVALID_PLAYER;
963
for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
964
if (GetPlayer(i)->is_active) {
965
/* Lower the widget corresponding to this player. */
966
w->LowerWidget(i + 13);
969
_performance_rating_detail_player = i;
975
/* If there are no active players, don't display anything else. */
976
if (_performance_rating_detail_player == INVALID_PLAYER) break;
978
/* Paint the player icons */
979
for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
980
if (!GetPlayer(i)->is_active) {
981
/* Check if we have the player as an active player */
982
if (!w->IsWidgetDisabled(i + 13)) {
983
/* Bah, player gone :( */
984
w->DisableWidget(i + 13);
986
/* We need a repaint */
992
/* Check if we have the player marked as inactive */
993
if (w->IsWidgetDisabled(i + 13)) {
994
/* New player! Yippie :p */
995
w->EnableWidget(i + 13);
862
struct PerformanceRatingDetailWindow : Window {
864
enum PerformanteRatingWidgets {
865
PRW_COMPANY_FIRST = 13,
866
PRW_COMPANY_LAST = PRW_COMPANY_FIRST + MAX_COMPANIES - 1,
870
static CompanyID company;
873
PerformanceRatingDetailWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
875
/* Disable the companies who are not active */
876
for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
877
this->SetWidgetDisabledState(i + PRW_COMPANY_FIRST, !IsValidCompanyID(i));
880
this->UpdateCompanyStats();
882
if (company != INVALID_COMPANY) this->LowerWidget(company + PRW_COMPANY_FIRST);
884
this->FindWindowPlacementAndResize(desc);
887
void UpdateCompanyStats()
889
/* Update all company stats with the current data
890
* (this is because _score_info is not saved to a savegame) */
892
FOR_ALL_COMPANIES(c) {
893
UpdateCompanyRatingAndValue(c, false);
896
this->timeout = DAY_TICKS * 5;
900
virtual void OnPaint()
905
int colour_done, colour_notdone;
907
/* Draw standard stuff */
910
/* Check if the currently selected company is still active. */
911
if (company == INVALID_COMPANY || !IsValidCompanyID(company)) {
912
if (company != INVALID_COMPANY) {
913
/* Raise and disable the widget for the previous selection. */
914
this->RaiseWidget(company + PRW_COMPANY_FIRST);
915
this->DisableWidget(company + PRW_COMPANY_FIRST);
918
company = INVALID_COMPANY;
921
for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
922
if (IsValidCompanyID(i)) {
923
/* Lower the widget corresponding to this company. */
924
this->LowerWidget(i + PRW_COMPANY_FIRST);
933
/* If there are no active companies, don't display anything else. */
934
if (company == INVALID_COMPANY) return;
936
/* Paint the company icons */
937
for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
938
if (!IsValidCompanyID(i)) {
939
/* Check if we have the company as an active company */
940
if (!this->IsWidgetDisabled(i + PRW_COMPANY_FIRST)) {
941
/* Bah, company gone :( */
942
this->DisableWidget(i + PRW_COMPANY_FIRST);
996
944
/* We need a repaint */
1000
x = (i == _performance_rating_detail_player) ? 1 : 0;
1001
DrawPlayerIcon(i, i * 37 + 13 + x, 16 + x);
1004
/* The colors used to show how the progress is going */
1005
color_done = _colour_gradient[COLOUR_GREEN][4];
1006
color_notdone = _colour_gradient[COLOUR_RED][4];
1008
/* Draw all the score parts */
1009
for (ScoreID i = SCORE_BEGIN; i < SCORE_END; i++) {
1010
int val = _score_part[_performance_rating_detail_player][i];
1011
int needed = _score_info[i].needed;
1012
int score = _score_info[i].score;
1015
/* SCORE_TOTAL has his own rulez ;) */
1016
if (i == SCORE_TOTAL) {
1017
needed = total_score;
1020
total_score += score;
1023
DrawString(7, y, STR_PERFORMANCE_DETAIL_VEHICLES + i, TC_FROMSTRING);
1025
/* Draw the score */
1026
SetDParam(0, score);
1027
DrawStringRightAligned(107, y, SET_PERFORMANCE_DETAIL_INT, TC_FROMSTRING);
1029
/* Calculate the %-bar */
1030
x = Clamp(val, 0, needed) * 50 / needed;
1032
/* SCORE_LOAN is inversed */
1033
if (val < 0 && i == SCORE_LOAN) x = 0;
1036
if (x != 0) GfxFillRect(112, y - 2, 112 + x, y + 10, color_done);
1037
if (x != 50) GfxFillRect(112 + x, y - 2, 112 + 50, y + 10, color_notdone);
1039
/* Calculate the % */
1040
x = Clamp(val, 0, needed) * 100 / needed;
1042
/* SCORE_LOAN is inversed */
1043
if (val < 0 && i == SCORE_LOAN) x = 0;
1047
DrawStringCentered(137, y, STR_PERFORMANCE_DETAIL_PERCENT, TC_FROMSTRING);
1049
/* SCORE_LOAN is inversed */
1050
if (i == SCORE_LOAN) val = needed - val;
1052
/* Draw the amount we have against what is needed
1053
* For some of them it is in currency format */
1055
SetDParam(1, needed);
1057
case SCORE_MIN_PROFIT:
1058
case SCORE_MIN_INCOME:
1059
case SCORE_MAX_INCOME:
1062
DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY, TC_FROMSTRING);
1065
DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_INT, TC_FROMSTRING);
1073
/* Check which button is clicked */
1074
if (IsInsideMM(e->we.click.widget, 13, 21)) {
1075
/* Is it no on disable? */
1076
if (!w->IsWidgetDisabled(e->we.click.widget)) {
1077
w->RaiseWidget(_performance_rating_detail_player + 13);
1078
_performance_rating_detail_player = (PlayerID)(e->we.click.widget - 13);
1079
w->LowerWidget(_performance_rating_detail_player + 13);
1088
/* Disable the players who are not active */
1089
for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
1090
w->SetWidgetDisabledState(i + 13, !GetPlayer(i)->is_active);
1092
/* Update all player stats with the current data
1093
* (this is because _score_info is not saved to a savegame) */
1094
FOR_ALL_PLAYERS(p2) {
1095
if (p2->is_active) UpdateCompanyRatingAndValue(p2, false);
1098
w->custom[0] = DAY_TICKS;
1101
if (_performance_rating_detail_player != INVALID_PLAYER) w->LowerWidget(_performance_rating_detail_player + 13);
1108
if (_pause_game != 0) break;
1110
/* Update the player score every 5 days */
1111
if (--w->custom[0] == 0) {
1112
w->custom[0] = DAY_TICKS;
1113
if (--w->custom[1] == 0) {
1117
FOR_ALL_PLAYERS(p2) {
1118
/* Skip if player is not active */
1119
if (p2->is_active) UpdateCompanyRatingAndValue(p2, false);
950
/* Check if we have the company marked as inactive */
951
if (this->IsWidgetDisabled(i + PRW_COMPANY_FIRST)) {
952
/* New company! Yippie :p */
953
this->EnableWidget(i + PRW_COMPANY_FIRST);
954
/* We need a repaint */
958
x = (i == company) ? 1 : 0;
959
DrawCompanyIcon(i, (i % 8) * 37 + 13 + x, (i < 8 ? 0 : 13) + 16 + x);
962
/* The colours used to show how the progress is going */
963
colour_done = _colour_gradient[COLOUR_GREEN][4];
964
colour_notdone = _colour_gradient[COLOUR_RED][4];
966
/* Draw all the score parts */
967
for (ScoreID i = SCORE_BEGIN; i < SCORE_END; i++) {
968
int val = _score_part[company][i];
969
int needed = _score_info[i].needed;
970
int score = _score_info[i].score;
973
/* SCORE_TOTAL has his own rulez ;) */
974
if (i == SCORE_TOTAL) {
975
needed = total_score;
978
total_score += score;
981
DrawString(7, y, STR_PERFORMANCE_DETAIL_VEHICLES + i, TC_FROMSTRING);
985
DrawStringRightAligned(107, y, STR_PERFORMANCE_DETAIL_INT, TC_FROMSTRING);
987
/* Calculate the %-bar */
988
x = Clamp(val, 0, needed) * 50 / needed;
990
/* SCORE_LOAN is inversed */
991
if (val < 0 && i == SCORE_LOAN) x = 0;
994
if (x != 0) GfxFillRect(112, y - 2, 112 + x, y + 10, colour_done);
995
if (x != 50) GfxFillRect(112 + x, y - 2, 112 + 50, y + 10, colour_notdone);
997
/* Calculate the % */
998
x = Clamp(val, 0, needed) * 100 / needed;
1000
/* SCORE_LOAN is inversed */
1001
if (val < 0 && i == SCORE_LOAN) x = 0;
1005
DrawStringCentered(137, y, STR_PERFORMANCE_DETAIL_PERCENT, TC_FROMSTRING);
1007
/* SCORE_LOAN is inversed */
1008
if (i == SCORE_LOAN) val = needed - val;
1010
/* Draw the amount we have against what is needed
1011
* For some of them it is in currency format */
1013
SetDParam(1, needed);
1015
case SCORE_MIN_PROFIT:
1016
case SCORE_MIN_INCOME:
1017
case SCORE_MAX_INCOME:
1020
DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY, TC_FROMSTRING);
1023
DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_INT, TC_FROMSTRING);
1028
virtual void OnClick(Point pt, int widget)
1030
/* Check which button is clicked */
1031
if (IsInsideMM(widget, PRW_COMPANY_FIRST, PRW_COMPANY_LAST + 1)) {
1032
/* Is it no on disable? */
1033
if (!this->IsWidgetDisabled(widget)) {
1034
this->RaiseWidget(company + PRW_COMPANY_FIRST);
1035
company = (CompanyID)(widget - PRW_COMPANY_FIRST);
1036
this->LowerWidget(company + PRW_COMPANY_FIRST);
1042
virtual void OnTick()
1044
if (_pause_game != 0) return;
1046
/* Update the company score every 5 days */
1047
if (--this->timeout == 0) {
1048
this->UpdateCompanyStats();
1054
CompanyID PerformanceRatingDetailWindow::company = INVALID_COMPANY;
1129
1057
static const Widget _performance_rating_detail_widgets[] = {
1130
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
1131
{ WWT_CAPTION, RESIZE_NONE, 14, 11, 298, 0, 13, STR_PERFORMANCE_DETAIL, STR_018C_WINDOW_TITLE_DRAG_THIS},
1132
{ WWT_PANEL, RESIZE_NONE, 14, 0, 298, 14, 27, 0x0, STR_NULL},
1134
{ WWT_PANEL, RESIZE_NONE, 14, 0, 298, 28, 47, 0x0, STR_PERFORMANCE_DETAIL_VEHICLES_TIP},
1135
{ WWT_PANEL, RESIZE_NONE, 14, 0, 298, 48, 67, 0x0, STR_PERFORMANCE_DETAIL_STATIONS_TIP},
1136
{ WWT_PANEL, RESIZE_NONE, 14, 0, 298, 68, 87, 0x0, STR_PERFORMANCE_DETAIL_MIN_PROFIT_TIP},
1137
{ WWT_PANEL, RESIZE_NONE, 14, 0, 298, 88, 107, 0x0, STR_PERFORMANCE_DETAIL_MIN_INCOME_TIP},
1138
{ WWT_PANEL, RESIZE_NONE, 14, 0, 298, 108, 127, 0x0, STR_PERFORMANCE_DETAIL_MAX_INCOME_TIP},
1139
{ WWT_PANEL, RESIZE_NONE, 14, 0, 298, 128, 147, 0x0, STR_PERFORMANCE_DETAIL_DELIVERED_TIP},
1140
{ WWT_PANEL, RESIZE_NONE, 14, 0, 298, 148, 167, 0x0, STR_PERFORMANCE_DETAIL_CARGO_TIP},
1141
{ WWT_PANEL, RESIZE_NONE, 14, 0, 298, 168, 187, 0x0, STR_PERFORMANCE_DETAIL_MONEY_TIP},
1142
{ WWT_PANEL, RESIZE_NONE, 14, 0, 298, 188, 207, 0x0, STR_PERFORMANCE_DETAIL_LOAN_TIP},
1143
{ WWT_PANEL, RESIZE_NONE, 14, 0, 298, 208, 227, 0x0, STR_PERFORMANCE_DETAIL_TOTAL_TIP},
1145
{ WWT_PANEL, RESIZE_NONE, 14, 2, 38, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1146
{ WWT_PANEL, RESIZE_NONE, 14, 39, 75, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1147
{ WWT_PANEL, RESIZE_NONE, 14, 76, 112, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1148
{ WWT_PANEL, RESIZE_NONE, 14, 113, 149, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1149
{ WWT_PANEL, RESIZE_NONE, 14, 150, 186, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1150
{ WWT_PANEL, RESIZE_NONE, 14, 187, 223, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1151
{ WWT_PANEL, RESIZE_NONE, 14, 224, 260, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1152
{ WWT_PANEL, RESIZE_NONE, 14, 261, 297, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1058
{ WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
1059
{ WWT_CAPTION, RESIZE_NONE, COLOUR_GREY, 11, 298, 0, 13, STR_PERFORMANCE_DETAIL, STR_018C_WINDOW_TITLE_DRAG_THIS},
1060
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 298, 14, 40, 0x0, STR_NULL},
1062
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 298, 41, 60, 0x0, STR_PERFORMANCE_DETAIL_VEHICLES_TIP},
1063
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 298, 61, 80, 0x0, STR_PERFORMANCE_DETAIL_STATIONS_TIP},
1064
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 298, 81, 100, 0x0, STR_PERFORMANCE_DETAIL_MIN_PROFIT_TIP},
1065
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 298, 101, 120, 0x0, STR_PERFORMANCE_DETAIL_MIN_INCOME_TIP},
1066
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 298, 121, 140, 0x0, STR_PERFORMANCE_DETAIL_MAX_INCOME_TIP},
1067
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 298, 141, 160, 0x0, STR_PERFORMANCE_DETAIL_DELIVERED_TIP},
1068
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 298, 161, 180, 0x0, STR_PERFORMANCE_DETAIL_CARGO_TIP},
1069
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 298, 181, 200, 0x0, STR_PERFORMANCE_DETAIL_MONEY_TIP},
1070
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 298, 201, 220, 0x0, STR_PERFORMANCE_DETAIL_LOAN_TIP},
1071
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 298, 221, 240, 0x0, STR_PERFORMANCE_DETAIL_TOTAL_TIP},
1073
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 2, 38, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1074
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 39, 75, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1075
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 76, 112, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1076
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 113, 149, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1077
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 150, 186, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1078
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 187, 223, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1079
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 224, 260, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1080
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 261, 297, 14, 26, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1081
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 2, 38, 27, 39, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1082
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 39, 75, 27, 39, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1083
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 76, 112, 27, 39, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1084
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 113, 149, 27, 39, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1085
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 150, 186, 27, 39, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1086
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 187, 223, 27, 39, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1087
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 224, 260, 27, 39, 0x0, STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
1153
1088
{ WIDGETS_END},
1156
static const WindowDesc _performance_rating_detail_desc = {
1157
WDP_AUTO, WDP_AUTO, 299, 228, 299, 228,
1091
static const WindowDesc _performance_rating_detail_desc(
1092
WDP_AUTO, WDP_AUTO, 299, 241, 299, 241,
1158
1093
WC_PERFORMANCE_DETAIL, WC_NONE,
1159
1094
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
1160
_performance_rating_detail_widgets,
1161
PerformanceRatingDetailWndProc
1095
_performance_rating_detail_widgets
1164
1098
void ShowPerformanceRatingDetail()
1166
AllocateWindowDescFront(&_performance_rating_detail_desc, 0);
1100
AllocateWindowDescFront<PerformanceRatingDetailWindow>(&_performance_rating_detail_desc, 0);