~ubuntu-branches/debian/squeeze/openttd/squeeze

« back to all changes in this revision

Viewing changes to src/graph_gui.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jordi Mallach, Matthijs Kooijman, Jordi Mallach
  • Date: 2009-04-15 18:22:10 UTC
  • mfrom: (1.1.6 upstream) (2.1.3 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090415182210-22ktb8kdbp2tf3bm
[ Matthijs Kooijman ]
* New upstream release.
* Remove Debian specific desktop file, upstream provides one now. 
* Add debian/watch file.

[ Jordi Mallach ]
* Bump Standards-Version to 3.8.1, with no changes required.
* Move to debhelper compat 7. Bump Build-Depends accordingly.
* Use dh_prep.
* Add "set -e" to config script.
* Remove a few extra doc files that get installed by upstream Makefile.
* Add more complete copyright information.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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 $ */
2
2
 
3
 
/** @file graph_gui.cpp */
 
3
/** @file graph_gui.cpp GUI that shows performance graphs. */
4
4
 
5
5
#include "stdafx.h"
6
6
#include "openttd.h"
7
7
#include "gui.h"
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"
19
18
 
20
19
#include "table/strings.h"
21
 
#include "table/sprites.h"
22
20
 
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;
26
24
 
27
 
/************************/
28
 
/* GENERIC GRAPH DRAWER */
29
 
/************************/
30
 
 
31
 
enum {
32
 
        GRAPH_MAX_DATASETS = 32,
33
 
        GRAPH_AXIS_LABEL_COLOUR = TC_BLACK,
34
 
        GRAPH_AXIS_LINE_COLOUR  = 215,
35
 
 
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
38
 
 
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,
41
 
         * which is the same
42
 
         * as height >> 3. */
43
 
};
44
 
 
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.
48
28
 
49
 
struct GraphDrawer {
 
29
/****************/
 
30
/* GRAPH LEGEND */
 
31
/****************/
 
32
 
 
33
struct GraphLegendWindow : Window {
 
34
        GraphLegendWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
 
35
        {
 
36
                for (uint i = 3; i < this->widget_count; i++) {
 
37
                        if (!HasBit(_legend_excluded_companies, i - 3)) this->LowerWidget(i);
 
38
                }
 
39
 
 
40
                this->FindWindowPlacementAndResize(desc);
 
41
        }
 
42
 
 
43
        virtual void OnPaint()
 
44
        {
 
45
                for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
 
46
                        if (IsValidCompanyID(c)) continue;
 
47
 
 
48
                        SetBit(_legend_excluded_companies, c);
 
49
                        this->RaiseWidget(c + 3);
 
50
                }
 
51
 
 
52
                this->DrawWidgets();
 
53
 
 
54
                const Company *c;
 
55
                FOR_ALL_COMPANIES(c) {
 
56
                        DrawCompanyIcon(c->index, 4, 18 + c->index * 12);
 
57
 
 
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);
 
61
                }
 
62
        }
 
63
 
 
64
        virtual void OnClick(Point pt, int widget)
 
65
        {
 
66
                if (!IsInsideMM(widget, 3, MAX_COMPANIES + 3)) return;
 
67
 
 
68
                ToggleBit(_legend_excluded_companies, widget - 3);
 
69
                this->ToggleWidgetLoweredState(widget);
 
70
                this->SetDirty();
 
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);
 
76
        }
 
77
};
 
78
 
 
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},
 
98
{   WIDGETS_END},
 
99
};
 
100
 
 
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
 
106
);
 
107
 
 
108
static void ShowGraphLegend()
 
109
{
 
110
        AllocateWindowDescFront<GraphLegendWindow>(&_graph_legend_desc, 0);
 
111
}
 
112
 
 
113
/******************/
 
114
/* BASE OF GRAPHS */
 
115
/*****************/
 
116
 
 
117
struct BaseGraphWindow : Window {
 
118
protected:
 
119
        enum {
 
120
                GRAPH_MAX_DATASETS = 32,
 
121
                GRAPH_AXIS_LINE_COLOUR  = 215,
 
122
 
 
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
 
125
 
 
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,
 
128
                 * which is the same
 
129
                 * as height >> 3. */
 
130
        };
 
131
 
50
132
        uint excluded_data; ///< bitmask of the datasets that shouldn't be displayed.
51
133
        byte num_dataset;
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.
55
138
 
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;
65
148
 
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
71
 
};
72
 
 
73
 
static void DrawGraph(const GraphDrawer *gw)
74
 
{
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.
78
 
 
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);
83
 
 
84
 
        byte grid_colour = _colour_gradient[14][4];
85
 
 
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;
89
 
 
90
 
        /* Draw the vertical grid lines. */
91
 
 
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;
94
 
 
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;
98
 
        }
99
 
 
100
 
        /* Draw the horizontal grid lines. */
101
 
        x = gw->left + GRAPH_X_POSITION_BEGINNING;
102
 
        y = gw->height + gw->top;
103
 
 
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));
107
 
        }
108
 
 
109
 
        /* Draw the y axis. */
110
 
        GfxFillRect(x, gw->top, x, bottom, GRAPH_AXIS_LINE_COLOUR);
111
 
 
112
 
        /* Find the distance from the top of the graph to the x axis. */
113
 
        x_axis_offset = gw->height;
114
 
 
115
 
        /* The graph is currently symmetrical about the x axis. */
116
 
        if (gw->has_negative_values) x_axis_offset /= 2;
117
 
 
118
 
        /* Draw the x axis. */
119
 
        y = x_axis_offset + gw->top;
120
 
        GfxFillRect(x, y, right, y, GRAPH_AXIS_LINE_COLOUR);
121
 
 
122
 
        /* Find the largest value that will be drawn. */
123
 
        if (gw->num_on_x_axis == 0)
124
 
                return;
125
 
 
126
 
        assert(gw->num_on_x_axis > 0);
127
 
        assert(gw->num_dataset > 0);
128
 
 
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;
134
 
 
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];
139
 
 
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));
145
 
                                }
146
 
                        }
147
 
                }
148
 
        }
149
 
 
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);
154
 
 
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);
158
 
 
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;
162
 
 
163
 
        x = gw->left + GRAPH_X_POSITION_BEGINNING + 1;
164
 
        y = gw->top - 3;
165
 
 
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);
170
 
 
171
 
                y_label -= y_label_separation;
172
 
                y += (gw->height / (GRAPH_NUM_LINES_Y - 1));
173
 
        }
174
 
 
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);
184
 
                        SetDParam(2, year);
185
 
                        DrawString(x, y, month == 0 ? STR_016F : STR_016E, GRAPH_AXIS_LABEL_COLOUR);
186
 
 
187
 
                        month += 3;
188
 
                        if (month >= 12) {
189
 
                                month = 0;
190
 
                                year++;
191
 
                        }
192
 
                        x += GRAPH_X_POSITION_SEPARATION;
193
 
                }
194
 
        } else {
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;
199
 
 
200
 
                for (int i = 0; i < gw->num_on_x_axis; i++) {
201
 
                        SetDParam(0, label);
202
 
                        DrawStringCentered(x, y, STR_01CB, GRAPH_AXIS_LABEL_COLOUR);
203
 
 
204
 
                        label += gw->x_values_increment;
205
 
                        x += GRAPH_X_POSITION_SEPARATION;
206
 
                }
207
 
        }
208
 
 
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);
214
 
 
215
 
                        byte color  = gw->colors[i];
216
 
                        uint prev_x = INVALID_DATAPOINT_POS;
217
 
                        uint prev_y = INVALID_DATAPOINT_POS;
218
 
 
219
 
                        for (int j = 0; j < gw->num_on_x_axis; j++) {
220
 
                                OverflowSafeInt64 datapoint = gw->cost[i][j];
221
 
 
222
 
                                if (datapoint != INVALID_DATAPOINT) {
223
 
                                        /*
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.
229
 
                                         *
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.
233
 
                                         */
234
 
                                        int mult_range = FindLastBit(x_axis_offset) + FindLastBit(abs(datapoint));
235
 
                                        int reduce_range = max(mult_range - 31, 0);
236
 
 
237
 
                                        /* Handle negative values differently (don't shift sign) */
238
 
                                        if (datapoint < 0) {
239
 
                                                datapoint = -(abs(datapoint) >> reduce_range);
 
154
 
 
155
        void DrawGraph() const
 
156
        {
 
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.
 
160
 
 
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);
 
165
 
 
166
                byte grid_colour = _colour_gradient[COLOUR_GREY][4];
 
167
 
 
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;
 
171
 
 
172
                /* Draw the vertical grid lines. */
 
173
 
 
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;
 
176
 
 
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;
 
180
                }
 
181
 
 
182
                /* Draw the horizontal grid lines. */
 
183
                x = this->gd_left + GRAPH_X_POSITION_BEGINNING;
 
184
                y = this->gd_height + this->gd_top;
 
185
 
 
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));
 
189
                }
 
190
 
 
191
                /* Draw the y axis. */
 
192
                GfxFillRect(x, this->gd_top, x, bottom, GRAPH_AXIS_LINE_COLOUR);
 
193
 
 
194
                /* Find the distance from the gd_top of the graph to the x axis. */
 
195
                x_axis_offset = this->gd_height;
 
196
 
 
197
                /* The graph is currently symmetrical about the x axis. */
 
198
                if (this->has_negative_values) x_axis_offset /= 2;
 
199
 
 
200
                /* Draw the x axis. */
 
201
                y = x_axis_offset + this->gd_top;
 
202
                GfxFillRect(x, y, right, y, GRAPH_AXIS_LINE_COLOUR);
 
203
 
 
204
                /* Find the largest value that will be drawn. */
 
205
                if (this->num_on_x_axis == 0)
 
206
                        return;
 
207
 
 
208
                assert(this->num_on_x_axis > 0);
 
209
                assert(this->num_dataset > 0);
 
210
 
 
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;
 
216
 
 
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];
 
221
 
 
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));
 
227
                                        }
 
228
                                }
 
229
                        }
 
230
                }
 
231
 
 
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);
 
236
 
 
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);
 
240
 
 
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;
 
244
 
 
245
                x = this->gd_left + GRAPH_X_POSITION_BEGINNING + 1;
 
246
                y = this->gd_top - 3;
 
247
 
 
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);
 
252
 
 
253
                        y_label -= y_label_separation;
 
254
                        y += (this->gd_height / (GRAPH_NUM_LINES_Y - 1));
 
255
                }
 
256
 
 
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);
 
266
                                SetDParam(2, year);
 
267
                                DrawString(x, y, month == 0 ? STR_016F : STR_016E, graph_axis_label_colour);
 
268
 
 
269
                                month += 3;
 
270
                                if (month >= 12) {
 
271
                                        month = 0;
 
272
                                        year++;
 
273
                                }
 
274
                                x += GRAPH_X_POSITION_SEPARATION;
 
275
                        }
 
276
                } else {
 
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;
 
281
 
 
282
                        for (int i = 0; i < this->num_on_x_axis; i++) {
 
283
                                SetDParam(0, label);
 
284
                                DrawStringCentered(x, y, STR_01CB, graph_axis_label_colour);
 
285
 
 
286
                                label += this->x_values_increment;
 
287
                                x += GRAPH_X_POSITION_SEPARATION;
 
288
                        }
 
289
                }
 
290
 
 
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);
 
296
 
 
297
                                byte colour  = this->colours[i];
 
298
                                uint prev_x = INVALID_DATAPOINT_POS;
 
299
                                uint prev_y = INVALID_DATAPOINT_POS;
 
300
 
 
301
                                for (int j = 0; j < this->num_on_x_axis; j++) {
 
302
                                        OverflowSafeInt64 datapoint = this->cost[i][j];
 
303
 
 
304
                                        if (datapoint != INVALID_DATAPOINT) {
 
305
                                                /*
 
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.
 
311
                                                 *
 
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.
 
315
                                                 */
 
316
                                                int mult_range = FindLastBit(x_axis_offset) + FindLastBit(abs(datapoint));
 
317
                                                int reduce_range = max(mult_range - 31, 0);
 
318
 
 
319
                                                /* Handle negative values differently (don't shift sign) */
 
320
                                                if (datapoint < 0) {
 
321
                                                        datapoint = -(abs(datapoint) >> reduce_range);
 
322
                                                } else {
 
323
                                                        datapoint >>= reduce_range;
 
324
                                                }
 
325
 
 
326
                                                y = this->gd_top + x_axis_offset - (x_axis_offset * datapoint) / (highest_value >> reduce_range);
 
327
 
 
328
                                                /* Draw the point. */
 
329
                                                GfxFillRect(x - 1, y - 1, x + 1, y + 1, colour);
 
330
 
 
331
                                                /* Draw the line connected to the previous point. */
 
332
                                                if (prev_x != INVALID_DATAPOINT_POS) GfxDrawLine(prev_x, prev_y, x, y, colour);
 
333
 
 
334
                                                prev_x = x;
 
335
                                                prev_y = y;
240
336
                                        } else {
241
 
                                                datapoint >>= reduce_range;
 
337
                                                prev_x = INVALID_DATAPOINT_POS;
 
338
                                                prev_y = INVALID_DATAPOINT_POS;
242
339
                                        }
243
340
 
244
 
                                        y = gw->top + x_axis_offset - (x_axis_offset * datapoint) / (highest_value >> reduce_range);
245
 
 
246
 
                                        /* Draw the point. */
247
 
                                        GfxFillRect(x - 1, y - 1, x + 1, y + 1, color);
248
 
 
249
 
                                        /* Draw the line connected to the previous point. */
250
 
                                        if (prev_x != INVALID_DATAPOINT_POS) GfxDrawLine(prev_x, prev_y, x, y, color);
251
 
 
252
 
                                        prev_x = x;
253
 
                                        prev_y = y;
254
 
                                } else {
255
 
                                        prev_x = INVALID_DATAPOINT_POS;
256
 
                                        prev_y = INVALID_DATAPOINT_POS;
257
 
                                }
258
 
 
259
 
                                x += GRAPH_X_POSITION_SEPARATION;
260
 
                        }
261
 
                }
262
 
        }
263
 
}
264
 
 
265
 
/****************/
266
 
/* GRAPH LEGEND */
267
 
/****************/
268
 
 
269
 
static void GraphLegendWndProc(Window *w, WindowEvent *e)
270
 
{
271
 
        switch (e->event) {
272
 
                case WE_CREATE:
273
 
                        for (uint i = 3; i < w->widget_count; i++) {
274
 
                                if (!HasBit(_legend_excluded_players, i - 3)) w->LowerWidget(i);
275
 
                        }
276
 
                        break;
277
 
 
278
 
                case WE_PAINT: {
279
 
                        const Player *p;
280
 
 
281
 
                        FOR_ALL_PLAYERS(p) {
282
 
                                if (p->is_active) continue;
283
 
 
284
 
                                SetBit(_legend_excluded_players, p->index);
285
 
                                w->RaiseWidget(p->index + 3);
286
 
                        }
287
 
 
288
 
                        DrawWindowWidgets(w);
289
 
 
290
 
                        FOR_ALL_PLAYERS(p) {
291
 
                                if (!p->is_active) continue;
292
 
 
293
 
                                DrawPlayerIcon(p->index, 4, 18 + p->index * 12);
294
 
 
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);
298
 
                        }
299
 
                        break;
300
 
                }
301
 
 
302
 
                case WE_CLICK:
303
 
                        if (!IsInsideMM(e->we.click.widget, 3, 11)) return;
304
 
 
305
 
                        ToggleBit(_legend_excluded_players, e->we.click.widget - 3);
306
 
                        w->ToggleWidgetLoweredState(e->we.click.widget);
307
 
                        SetWindowDirty(w);
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);
313
 
                        break;
314
 
        }
315
 
}
316
 
 
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},
329
 
{   WIDGETS_END},
330
 
};
331
 
 
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,
337
 
        GraphLegendWndProc
338
 
};
339
 
 
340
 
static void ShowGraphLegend()
341
 
{
342
 
        AllocateWindowDescFront(&_graph_legend_desc, 0);
343
 
}
 
341
                                        x += GRAPH_X_POSITION_SEPARATION;
 
342
                                }
 
343
                        }
 
344
                }
 
345
        }
 
346
 
 
347
 
 
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)
 
352
        {
 
353
                InvalidateWindow(WC_GRAPH_LEGEND, 0);
 
354
        }
 
355
 
 
356
public:
 
357
        virtual void OnPaint()
 
358
        {
 
359
                this->DrawWidgets();
 
360
 
 
361
                uint excluded_companies = _legend_excluded_companies;
 
362
 
 
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);
 
366
                }
 
367
                this->excluded_data = excluded_companies;
 
368
                this->num_vert_lines = 24;
 
369
 
 
370
                byte nums = 0;
 
371
                const Company *c;
 
372
                FOR_ALL_COMPANIES(c) {
 
373
                        nums = max(nums, c->num_valid_stat_ent);
 
374
                }
 
375
                this->num_on_x_axis = min(nums, 24);
 
376
 
 
377
                int mo = (_cur_month / 3 - nums) * 3;
 
378
                int yr = _cur_year;
 
379
                while (mo < 0) {
 
380
                        yr--;
 
381
                        mo += 12;
 
382
                }
 
383
 
 
384
                this->year = yr;
 
385
                this->month = mo;
 
386
 
 
387
                int numd = 0;
 
388
                for (CompanyID k = COMPANY_FIRST; k < MAX_COMPANIES; k++) {
 
389
                        if (IsValidCompanyID(k)) {
 
390
                                c = GetCompany(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);
 
394
                                        i++;
 
395
                                }
 
396
                        }
 
397
                        numd++;
 
398
                }
 
399
 
 
400
                this->num_dataset = numd;
 
401
 
 
402
                this->DrawGraph();
 
403
        }
 
404
 
 
405
        virtual OverflowSafeInt64 GetGraphData(const Company *c, int j)
 
406
        {
 
407
                return INVALID_DATAPOINT;
 
408
        }
 
409
 
 
410
        virtual void OnClick(Point pt, int widget)
 
411
        {
 
412
                /* Clicked on legend? */
 
413
                if (widget == 2) ShowGraphLegend();
 
414
        }
 
415
};
344
416
 
345
417
/********************/
346
418
/* OPERATING PROFIT */
347
419
/********************/
348
420
 
349
 
static void SetupGraphDrawerForPlayers(GraphDrawer *gd)
350
 
{
351
 
        const Player* p;
352
 
        uint excluded_players = _legend_excluded_players;
353
 
        byte nums;
354
 
        int mo, yr;
355
 
 
356
 
        /* Exclude the players which aren't valid */
357
 
        FOR_ALL_PLAYERS(p) {
358
 
                if (!p->is_active) SetBit(excluded_players, p->index);
359
 
        }
360
 
        gd->excluded_data = excluded_players;
361
 
        gd->num_vert_lines = 24;
362
 
 
363
 
        nums = 0;
364
 
        FOR_ALL_PLAYERS(p) {
365
 
                if (p->is_active) nums = max(nums, p->num_valid_stat_ent);
366
 
        }
367
 
        gd->num_on_x_axis = min(nums, 24);
368
 
 
369
 
        mo = (_cur_month / 3 - nums) * 3;
370
 
        yr = _cur_year;
371
 
        while (mo < 0) {
372
 
                yr--;
373
 
                mo += 12;
374
 
        }
375
 
 
376
 
        gd->year = yr;
377
 
        gd->month = mo;
378
 
}
379
 
 
380
 
static void OperatingProfitWndProc(Window *w, WindowEvent *e)
381
 
{
382
 
        switch (e->event) {
383
 
                case WE_PAINT: {
384
 
                        GraphDrawer gd;
385
 
                        const Player* p;
386
 
 
387
 
                        DrawWindowWidgets(w);
388
 
 
389
 
                        gd.left = 2;
390
 
                        gd.top = 18;
391
 
                        gd.height = 136;
392
 
                        gd.has_negative_values = true;
393
 
                        gd.format_str_y_axis = STR_CURRCOMPACT;
394
 
 
395
 
                        SetupGraphDrawerForPlayers(&gd);
396
 
 
397
 
                        int numd = 0;
398
 
                        FOR_ALL_PLAYERS(p) {
399
 
                                if (p->is_active) {
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);
403
 
                                                i++;
404
 
                                        }
405
 
                                }
406
 
                                numd++;
407
 
                        }
408
 
 
409
 
                        gd.num_dataset = numd;
410
 
 
411
 
                        DrawGraph(&gd);
412
 
                        break;
413
 
                }
414
 
 
415
 
                case WE_CLICK:
416
 
                        /* Clicked on legend? */
417
 
                        if (e->we.click.widget == 2) ShowGraphLegend();
418
 
                        break;
419
 
        }
420
 
}
 
421
struct OperatingProfitGraphWindow : BaseGraphWindow {
 
422
        OperatingProfitGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
 
423
                        BaseGraphWindow(desc, window_number, 2, 18, 136, true, STR_CURRCOMPACT)
 
424
        {
 
425
                this->FindWindowPlacementAndResize(desc);
 
426
        }
 
427
 
 
428
        virtual OverflowSafeInt64 GetGraphData(const Company *c, int j)
 
429
        {
 
430
                return c->old_economy[j].income + c->old_economy[j].expenses;
 
431
        }
 
432
};
421
433
 
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},
427
439
{   WIDGETS_END},
428
440
};
429
441
 
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
436
 
};
 
446
        _operating_profit_widgets
 
447
);
437
448
 
438
449
 
439
450
void ShowOperatingProfitGraph()
440
451
{
441
 
        if (AllocateWindowDescFront(&_operating_profit_desc, 0)) {
442
 
                InvalidateWindow(WC_GRAPH_LEGEND, 0);
443
 
        }
 
452
        AllocateWindowDescFront<OperatingProfitGraphWindow>(&_operating_profit_desc, 0);
444
453
}
445
454
 
446
455
 
448
457
/* INCOME GRAPH */
449
458
/****************/
450
459
 
451
 
static void IncomeGraphWndProc(Window *w, WindowEvent *e)
452
 
{
453
 
        switch (e->event) {
454
 
                case WE_PAINT: {
455
 
                        GraphDrawer gd;
456
 
                        const Player* p;
457
 
 
458
 
                        DrawWindowWidgets(w);
459
 
 
460
 
                        gd.left = 2;
461
 
                        gd.top = 18;
462
 
                        gd.height = 104;
463
 
                        gd.has_negative_values = false;
464
 
                        gd.format_str_y_axis = STR_CURRCOMPACT;
465
 
                        SetupGraphDrawerForPlayers(&gd);
466
 
 
467
 
                        int numd = 0;
468
 
                        FOR_ALL_PLAYERS(p) {
469
 
                                if (p->is_active) {
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;
473
 
                                                i++;
474
 
                                        }
475
 
                                }
476
 
                                numd++;
477
 
                        }
478
 
 
479
 
                        gd.num_dataset = numd;
480
 
 
481
 
                        DrawGraph(&gd);
482
 
                        break;
483
 
                }
484
 
 
485
 
                case WE_CLICK:
486
 
                        if (e->we.click.widget == 2) ShowGraphLegend();
487
 
                        break;
488
 
        }
489
 
}
 
460
struct IncomeGraphWindow : BaseGraphWindow {
 
461
        IncomeGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
 
462
                        BaseGraphWindow(desc, window_number, 2, 18, 104, false, STR_CURRCOMPACT)
 
463
        {
 
464
                this->FindWindowPlacementAndResize(desc);
 
465
        }
 
466
 
 
467
        virtual OverflowSafeInt64 GetGraphData(const Company *c, int j)
 
468
        {
 
469
                return c->old_economy[j].income;
 
470
        }
 
471
};
490
472
 
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},
496
478
{   WIDGETS_END},
497
479
};
498
480
 
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,
504
 
        IncomeGraphWndProc
505
 
};
 
485
        _income_graph_widgets
 
486
);
506
487
 
507
488
void ShowIncomeGraph()
508
489
{
509
 
        if (AllocateWindowDescFront(&_income_graph_desc, 0)) {
510
 
                InvalidateWindow(WC_GRAPH_LEGEND, 0);
511
 
        }
 
490
        AllocateWindowDescFront<IncomeGraphWindow>(&_income_graph_desc, 0);
512
491
}
513
492
 
514
493
/*******************/
515
494
/* DELIVERED CARGO */
516
495
/*******************/
517
496
 
518
 
static void DeliveredCargoGraphWndProc(Window *w, WindowEvent *e)
519
 
{
520
 
        switch (e->event) {
521
 
                case WE_PAINT: {
522
 
                        GraphDrawer gd;
523
 
                        const Player* p;
524
 
 
525
 
                        DrawWindowWidgets(w);
526
 
 
527
 
                        gd.left = 2;
528
 
                        gd.top = 18;
529
 
                        gd.height = 104;
530
 
                        gd.has_negative_values = false;
531
 
                        gd.format_str_y_axis = STR_7024;
532
 
                        SetupGraphDrawerForPlayers(&gd);
533
 
 
534
 
                        int numd = 0;
535
 
                        FOR_ALL_PLAYERS(p) {
536
 
                                if (p->is_active) {
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;
540
 
                                                i++;
541
 
                                        }
542
 
                                }
543
 
                                numd++;
544
 
                        }
545
 
 
546
 
                        gd.num_dataset = numd;
547
 
 
548
 
                        DrawGraph(&gd);
549
 
                        break;
550
 
                }
551
 
 
552
 
                case WE_CLICK:
553
 
                        if (e->we.click.widget == 2) ShowGraphLegend();
554
 
                        break;
555
 
        }
556
 
}
 
497
struct DeliveredCargoGraphWindow : BaseGraphWindow {
 
498
        DeliveredCargoGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
 
499
                        BaseGraphWindow(desc, window_number, 2, 18, 104, false, STR_7024)
 
500
        {
 
501
                this->FindWindowPlacementAndResize(desc);
 
502
        }
 
503
 
 
504
        virtual OverflowSafeInt64 GetGraphData(const Company *c, int j)
 
505
        {
 
506
                return c->old_economy[j].delivered_cargo;
 
507
        }
 
508
};
557
509
 
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},
563
515
{   WIDGETS_END},
564
516
};
565
517
 
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
572
 
};
 
522
        _delivered_cargo_graph_widgets
 
523
);
573
524
 
574
525
void ShowDeliveredCargoGraph()
575
526
{
576
 
        if (AllocateWindowDescFront(&_delivered_cargo_graph_desc, 0)) {
577
 
                InvalidateWindow(WC_GRAPH_LEGEND, 0);
578
 
        }
 
527
        AllocateWindowDescFront<DeliveredCargoGraphWindow>(&_delivered_cargo_graph_desc, 0);
579
528
}
580
529
 
581
530
/***********************/
582
531
/* PERFORMANCE HISTORY */
583
532
/***********************/
584
533
 
585
 
static void PerformanceHistoryWndProc(Window *w, WindowEvent *e)
586
 
{
587
 
        switch (e->event) {
588
 
                case WE_PAINT: {
589
 
                        GraphDrawer gd;
590
 
                        const Player* p;
591
 
 
592
 
                        DrawWindowWidgets(w);
593
 
 
594
 
                        gd.left = 2;
595
 
                        gd.top = 18;
596
 
                        gd.height = 200;
597
 
                        gd.has_negative_values = false;
598
 
                        gd.format_str_y_axis = STR_7024;
599
 
                        SetupGraphDrawerForPlayers(&gd);
600
 
 
601
 
                        int numd = 0;
602
 
                        FOR_ALL_PLAYERS(p) {
603
 
                                if (p->is_active) {
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;
607
 
                                                i++;
608
 
                                        }
609
 
                                }
610
 
                                numd++;
611
 
                        }
612
 
 
613
 
                        gd.num_dataset = numd;
614
 
 
615
 
                        DrawGraph(&gd);
616
 
                        break;
617
 
                }
618
 
 
619
 
                case WE_CLICK:
620
 
                        if (e->we.click.widget == 2) ShowGraphLegend();
621
 
                        if (e->we.click.widget == 3) ShowPerformanceRatingDetail();
622
 
                        break;
623
 
        }
624
 
}
 
534
struct PerformanceHistoryGraphWindow : BaseGraphWindow {
 
535
        PerformanceHistoryGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
 
536
                        BaseGraphWindow(desc, window_number, 2, 18, 200, false, STR_7024)
 
537
        {
 
538
                this->FindWindowPlacementAndResize(desc);
 
539
        }
 
540
 
 
541
        virtual OverflowSafeInt64 GetGraphData(const Company *c, int j)
 
542
        {
 
543
                return c->old_economy[j].performance_history;
 
544
        }
 
545
 
 
546
        virtual void OnClick(Point pt, int widget)
 
547
        {
 
548
                if (widget == 3) ShowPerformanceRatingDetail();
 
549
                this->BaseGraphWindow::OnClick(pt, widget);
 
550
        }
 
551
};
625
552
 
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},
632
559
{   WIDGETS_END},
633
560
};
634
561
 
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
641
 
};
 
566
        _performance_history_widgets
 
567
);
642
568
 
643
569
void ShowPerformanceHistoryGraph()
644
570
{
645
 
        if (AllocateWindowDescFront(&_performance_history_desc, 0)) {
646
 
                InvalidateWindow(WC_GRAPH_LEGEND, 0);
647
 
        }
 
571
        AllocateWindowDescFront<PerformanceHistoryGraphWindow>(&_performance_history_desc, 0);
648
572
}
649
573
 
650
574
/*****************/
651
575
/* COMPANY VALUE */
652
576
/*****************/
653
577
 
654
 
static void CompanyValueGraphWndProc(Window *w, WindowEvent *e)
655
 
{
656
 
        switch (e->event) {
657
 
                case WE_PAINT: {
658
 
                        GraphDrawer gd;
659
 
                        const Player* p;
660
 
 
661
 
                        DrawWindowWidgets(w);
662
 
 
663
 
                        gd.left = 2;
664
 
                        gd.top = 18;
665
 
                        gd.height = 200;
666
 
                        gd.has_negative_values = false;
667
 
                        gd.format_str_y_axis = STR_CURRCOMPACT;
668
 
                        SetupGraphDrawerForPlayers(&gd);
669
 
 
670
 
                        int numd = 0;
671
 
                        FOR_ALL_PLAYERS(p) {
672
 
                                if (p->is_active) {
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;
676
 
                                                i++;
677
 
                                        }
678
 
                                }
679
 
                                numd++;
680
 
                        }
681
 
 
682
 
                        gd.num_dataset = numd;
683
 
 
684
 
                        DrawGraph(&gd);
685
 
                        break;
686
 
                }
687
 
 
688
 
                case WE_CLICK:
689
 
                        if (e->we.click.widget == 2) ShowGraphLegend();
690
 
                        break;
691
 
        }
692
 
}
 
578
struct CompanyValueGraphWindow : BaseGraphWindow {
 
579
        CompanyValueGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
 
580
                        BaseGraphWindow(desc, window_number, 2, 18, 200, false, STR_CURRCOMPACT)
 
581
        {
 
582
                this->FindWindowPlacementAndResize(desc);
 
583
        }
 
584
 
 
585
        virtual OverflowSafeInt64 GetGraphData(const Company *c, int j)
 
586
        {
 
587
                return c->old_economy[j].company_value;
 
588
        }
 
589
};
693
590
 
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},
699
596
{   WIDGETS_END},
700
597
};
701
598
 
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
708
 
};
 
603
        _company_value_graph_widgets
 
604
);
709
605
 
710
606
void ShowCompanyValueGraph()
711
607
{
712
 
        if (AllocateWindowDescFront(&_company_value_graph_desc, 0)) {
713
 
                InvalidateWindow(WC_GRAPH_LEGEND, 0);
714
 
        }
 
608
        AllocateWindowDescFront<CompanyValueGraphWindow>(&_company_value_graph_desc, 0);
715
609
}
716
610
 
717
611
/*****************/
718
612
/* PAYMENT RATES */
719
613
/*****************/
720
614
 
721
 
static void CargoPaymentRatesWndProc(Window *w, WindowEvent *e)
722
 
{
723
 
        switch (e->event) {
724
 
                case WE_PAINT: {
725
 
                        GraphDrawer gd;
726
 
 
727
 
                        DrawWindowWidgets(w);
728
 
 
729
 
                        int x = 495;
730
 
                        int y = 24;
731
 
 
732
 
                        gd.excluded_data = _legend_excluded_cargo;
733
 
                        gd.left = 2;
734
 
                        gd.top = 24;
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;
740
 
                        gd.month = 0xFF;
741
 
                        gd.x_values_start     = 10;
742
 
                        gd.x_values_increment = 10;
743
 
 
744
 
                        uint i = 0;
745
 
                        for (CargoID c = 0; c < NUM_CARGO; c++) {
746
 
                                const CargoSpec *cs = GetCargo(c);
747
 
                                if (!cs->IsValid()) continue;
748
 
 
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;
758
 
 
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);
763
 
                                        y += 8;
764
 
                                }
765
 
 
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);
769
 
                                }
770
 
 
771
 
                                i++;
772
 
                        }
773
 
                        gd.num_dataset = i;
774
 
 
775
 
                        DrawGraph(&gd);
776
 
 
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);
779
 
                        break;
780
 
                }
781
 
 
782
 
                case WE_CLICK:
783
 
                        if (e->we.click.widget >= 3) {
784
 
                                ToggleBit(_legend_excluded_cargo, e->we.click.widget - 3);
785
 
                                w->ToggleWidgetLoweredState(e->we.click.widget);
786
 
                                SetWindowDirty(w);
787
 
                        }
788
 
                        break;
789
 
        }
790
 
}
 
615
struct PaymentRatesGraphWindow : BaseGraphWindow {
 
616
        PaymentRatesGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
 
617
                        BaseGraphWindow(desc, window_number, 2, 24, 200, false, STR_CURRCOMPACT)
 
618
        {
 
619
                uint num_active = 0;
 
620
                for (CargoID c = 0; c < NUM_CARGO; c++) {
 
621
                        if (GetCargo(c)->IsValid()) num_active++;
 
622
                }
 
623
 
 
624
                /* Resize the window to fit the cargo types */
 
625
                ResizeWindow(this, 0, max(num_active, 12U) * 8);
 
626
 
 
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;
 
631
 
 
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;
 
638
                        wi->left     = 493;
 
639
                        wi->right    = 562;
 
640
                        wi->top      = 24 + i * 8;
 
641
                        wi->bottom   = wi->top + 7;
 
642
                        wi->data     = 0;
 
643
                        wi->tooltips = STR_7064_TOGGLE_GRAPH_FOR_CARGO;
 
644
 
 
645
                        if (!HasBit(_legend_excluded_cargo, i)) this->LowerWidget(i + 3);
 
646
                }
 
647
 
 
648
                this->SetDirty();
 
649
 
 
650
                this->gd_height = this->height - 38;
 
651
                this->num_on_x_axis = 20;
 
652
                this->num_vert_lines = 20;
 
653
                this->month = 0xFF;
 
654
                this->x_values_start     = 10;
 
655
                this->x_values_increment = 10;
 
656
 
 
657
                this->FindWindowPlacementAndResize(desc);
 
658
        }
 
659
 
 
660
        virtual void OnPaint()
 
661
        {
 
662
                this->DrawWidgets();
 
663
 
 
664
                this->excluded_data = _legend_excluded_cargo;
 
665
 
 
666
                int x = 495;
 
667
                int y = 24;
 
668
 
 
669
                uint i = 0;
 
670
                for (CargoID c = 0; c < NUM_CARGO; c++) {
 
671
                        const CargoSpec *cs = GetCargo(c);
 
672
                        if (!cs->IsValid()) continue;
 
673
 
 
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;
 
683
 
 
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);
 
688
                                y += 8;
 
689
                        }
 
690
 
 
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);
 
694
                        }
 
695
 
 
696
                        i++;
 
697
                }
 
698
                this->num_dataset = i;
 
699
 
 
700
                this->DrawGraph();
 
701
 
 
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);
 
704
        }
 
705
 
 
706
        virtual void OnClick(Point pt, int widget)
 
707
        {
 
708
                if (widget >= 3) {
 
709
                        ToggleBit(_legend_excluded_cargo, widget - 3);
 
710
                        this->ToggleWidgetLoweredState(widget);
 
711
                        this->SetDirty();
 
712
                }
 
713
        }
 
714
};
791
715
 
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},
796
720
{   WIDGETS_END},
797
721
};
798
722
 
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
805
 
};
 
727
        _cargo_payment_rates_widgets
 
728
);
806
729
 
807
730
 
808
731
void ShowCargoPaymentRates()
809
732
{
810
 
        Window *w = AllocateWindowDescFront(&_cargo_payment_rates_desc, 0);
811
 
        if (w == NULL) return;
812
 
 
813
 
        /* Count the number of active cargo types */
814
 
        uint num_active = 0;
815
 
        for (CargoID c = 0; c < NUM_CARGO; c++) {
816
 
                if (GetCargo(c)->IsValid()) num_active++;
817
 
        }
818
 
 
819
 
        /* Resize the window to fit the cargo types */
820
 
        ResizeWindow(w, 0, max(num_active, 12U) * 8);
821
 
 
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;
826
 
 
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;
832
 
                wi->color    = 12;
833
 
                wi->left     = 493;
834
 
                wi->right    = 562;
835
 
                wi->top      = 24 + i * 8;
836
 
                wi->bottom   = wi->top + 7;
837
 
                wi->data     = 0;
838
 
                wi->tooltips = STR_7064_TOGGLE_GRAPH_FOR_CARGO;
839
 
 
840
 
                if (!HasBit(_legend_excluded_cargo, i)) w->LowerWidget(i + 3);
841
 
        }
842
 
 
843
 
        SetWindowDirty(w);
 
733
        AllocateWindowDescFront<PaymentRatesGraphWindow>(&_cargo_payment_rates_desc, 0);
844
734
}
845
735
 
846
736
/************************/
871
761
        return _performance_titles[minu(value, 1000) >> 6];
872
762
}
873
763
 
874
 
static int CDECL PerfHistComp(const void* elem1, const void* elem2)
875
 
{
876
 
        const Player* p1 = *(const Player* const*)elem1;
877
 
        const Player* p2 = *(const Player* const*)elem2;
878
 
 
879
 
        return p2->old_economy[1].performance_history - p1->old_economy[1].performance_history;
880
 
}
881
 
 
882
 
static void CompanyLeagueWndProc(Window *w, WindowEvent *e)
883
 
{
884
 
        switch (e->event) {
885
 
                case WE_PAINT: {
886
 
                        const Player* plist[MAX_PLAYERS];
887
 
                        const Player* p;
888
 
 
889
 
                        DrawWindowWidgets(w);
890
 
 
891
 
                        uint pl_num = 0;
892
 
                        FOR_ALL_PLAYERS(p) if (p->is_active) plist[pl_num++] = p;
893
 
 
894
 
                        qsort((void*)plist, pl_num, sizeof(*plist), PerfHistComp);
895
 
 
896
 
                        for (uint i = 0; i != pl_num; i++) {
897
 
                                p = plist[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));
902
 
 
903
 
                                DrawString(2, 15 + i * 10, i == 0 ? STR_7054 : STR_7055, TC_FROMSTRING);
904
 
                                DrawPlayerIcon(p->index, 27, 16 + i * 10);
905
 
                        }
906
 
 
907
 
                        break;
908
 
                }
909
 
        }
910
 
}
 
764
class CompanyLeagueWindow : public Window {
 
765
private:
 
766
        GUIList<const Company*> companies;
 
767
 
 
768
        /**
 
769
         * (Re)Build the company league list
 
770
         */
 
771
        void BuildCompanyList()
 
772
        {
 
773
                if (!this->companies.NeedRebuild()) return;
 
774
 
 
775
                this->companies.Clear();
 
776
 
 
777
                const Company *c;
 
778
                FOR_ALL_COMPANIES(c) {
 
779
                        *this->companies.Append() = c;
 
780
                }
 
781
 
 
782
                this->companies.Compact();
 
783
                this->companies.RebuildDone();
 
784
        }
 
785
 
 
786
        /** Sort the company league by performance history */
 
787
        static int CDECL PerformanceSorter(const Company * const *c1, const Company * const *c2)
 
788
        {
 
789
                return (*c2)->old_economy[1].performance_history - (*c1)->old_economy[1].performance_history;
 
790
        }
 
791
 
 
792
public:
 
793
        CompanyLeagueWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
 
794
        {
 
795
                this->companies.ForceRebuild();
 
796
                this->companies.NeedResort();
 
797
 
 
798
                this->FindWindowPlacementAndResize(desc);
 
799
        }
 
800
 
 
801
        virtual void OnPaint()
 
802
        {
 
803
                this->BuildCompanyList();
 
804
                this->companies.Sort(&PerformanceSorter);
 
805
 
 
806
                this->DrawWidgets();
 
807
 
 
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));
 
814
 
 
815
                        DrawString(2, 15 + i * 10, i == 0 ? STR_7054 : STR_7055, TC_FROMSTRING);
 
816
                        DrawCompanyIcon(c->index, 27, 16 + i * 10);
 
817
                }
 
818
        }
 
819
 
 
820
        virtual void OnTick()
 
821
        {
 
822
                if (this->companies.NeedResort()) {
 
823
                        this->SetDirty();
 
824
                }
 
825
        }
 
826
 
 
827
        virtual void OnInvalidateData(int data)
 
828
        {
 
829
                if (data == 0) {
 
830
                        this->companies.ForceRebuild();
 
831
                } else {
 
832
                        this->companies.ForceResort();
 
833
                }
 
834
        }
 
835
};
911
836
 
912
837
 
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},
918
843
{   WIDGETS_END},
919
844
};
920
845
 
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,
926
 
        CompanyLeagueWndProc
927
 
};
 
850
        _company_league_widgets
 
851
);
928
852
 
929
853
void ShowCompanyLeagueTable()
930
854
{
931
 
        AllocateWindowDescFront(&_company_league_desc, 0);
 
855
        AllocateWindowDescFront<CompanyLeagueWindow>(&_company_league_desc, 0);
932
856
}
933
857
 
934
858
/*****************************/
935
859
/* PERFORMANCE RATING DETAIL */
936
860
/*****************************/
937
861
 
938
 
static void PerformanceRatingDetailWndProc(Window *w, WindowEvent *e)
939
 
{
940
 
        static PlayerID _performance_rating_detail_player = INVALID_PLAYER;
941
 
 
942
 
        switch (e->event) {
943
 
                case WE_PAINT: {
944
 
                        byte x;
945
 
                        uint16 y = 14;
946
 
                        int total_score = 0;
947
 
                        int color_done, color_notdone;
948
 
 
949
 
                        /* Draw standard stuff */
950
 
                        DrawWindowWidgets(w);
951
 
 
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);
958
 
                                        SetWindowDirty(w);
959
 
 
960
 
                                        _performance_rating_detail_player = INVALID_PLAYER;
961
 
                                }
962
 
 
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);
967
 
                                                SetWindowDirty(w);
968
 
 
969
 
                                                _performance_rating_detail_player = i;
970
 
                                                break;
971
 
                                        }
972
 
                                }
973
 
                        }
974
 
 
975
 
                        /* If there are no active players, don't display anything else. */
976
 
                        if (_performance_rating_detail_player == INVALID_PLAYER) break;
977
 
 
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);
985
 
 
986
 
                                                /* We need a repaint */
987
 
                                                SetWindowDirty(w);
988
 
                                        }
989
 
                                        continue;
990
 
                                }
991
 
 
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 {
 
863
private:
 
864
        enum PerformanteRatingWidgets {
 
865
                PRW_COMPANY_FIRST = 13,
 
866
                PRW_COMPANY_LAST  = PRW_COMPANY_FIRST + MAX_COMPANIES - 1,
 
867
        };
 
868
 
 
869
public:
 
870
        static CompanyID company;
 
871
        int timeout;
 
872
 
 
873
        PerformanceRatingDetailWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
 
874
        {
 
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));
 
878
                }
 
879
 
 
880
                this->UpdateCompanyStats();
 
881
 
 
882
                if (company != INVALID_COMPANY) this->LowerWidget(company + PRW_COMPANY_FIRST);
 
883
 
 
884
                this->FindWindowPlacementAndResize(desc);
 
885
        }
 
886
 
 
887
        void UpdateCompanyStats()
 
888
        {
 
889
                /* Update all company stats with the current data
 
890
                 * (this is because _score_info is not saved to a savegame) */
 
891
                Company *c;
 
892
                FOR_ALL_COMPANIES(c) {
 
893
                        UpdateCompanyRatingAndValue(c, false);
 
894
                }
 
895
 
 
896
                this->timeout = DAY_TICKS * 5;
 
897
 
 
898
        }
 
899
 
 
900
        virtual void OnPaint()
 
901
        {
 
902
                byte x;
 
903
                uint16 y = 27;
 
904
                int total_score = 0;
 
905
                int colour_done, colour_notdone;
 
906
 
 
907
                /* Draw standard stuff */
 
908
                this->DrawWidgets();
 
909
 
 
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);
 
916
                                this->SetDirty();
 
917
 
 
918
                                company = INVALID_COMPANY;
 
919
                        }
 
920
 
 
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);
 
925
                                        this->SetDirty();
 
926
 
 
927
                                        company = i;
 
928
                                        break;
 
929
                                }
 
930
                        }
 
931
                }
 
932
 
 
933
                /* If there are no active companies, don't display anything else. */
 
934
                if (company == INVALID_COMPANY) return;
 
935
 
 
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);
 
943
 
996
944
                                        /* We need a repaint */
997
 
                                        SetWindowDirty(w);
998
 
                                }
999
 
 
1000
 
                                x = (i == _performance_rating_detail_player) ? 1 : 0;
1001
 
                                DrawPlayerIcon(i, i * 37 + 13 + x, 16 + x);
1002
 
                        }
1003
 
 
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];
1007
 
 
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;
1013
 
 
1014
 
                                y += 20;
1015
 
                                /* SCORE_TOTAL has his own rulez ;) */
1016
 
                                if (i == SCORE_TOTAL) {
1017
 
                                        needed = total_score;
1018
 
                                        score = SCORE_MAX;
1019
 
                                } else {
1020
 
                                        total_score += score;
1021
 
                                }
1022
 
 
1023
 
                                DrawString(7, y, STR_PERFORMANCE_DETAIL_VEHICLES + i, TC_FROMSTRING);
1024
 
 
1025
 
                                /* Draw the score */
1026
 
                                SetDParam(0, score);
1027
 
                                DrawStringRightAligned(107, y, SET_PERFORMANCE_DETAIL_INT, TC_FROMSTRING);
1028
 
 
1029
 
                                /* Calculate the %-bar */
1030
 
                                x = Clamp(val, 0, needed) * 50 / needed;
1031
 
 
1032
 
                                /* SCORE_LOAN is inversed */
1033
 
                                if (val < 0 && i == SCORE_LOAN) x = 0;
1034
 
 
1035
 
                                /* Draw the bar */
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);
1038
 
 
1039
 
                                /* Calculate the % */
1040
 
                                x = Clamp(val, 0, needed) * 100 / needed;
1041
 
 
1042
 
                                /* SCORE_LOAN is inversed */
1043
 
                                if (val < 0 && i == SCORE_LOAN) x = 0;
1044
 
 
1045
 
                                /* Draw it */
1046
 
                                SetDParam(0, x);
1047
 
                                DrawStringCentered(137, y, STR_PERFORMANCE_DETAIL_PERCENT, TC_FROMSTRING);
1048
 
 
1049
 
                                /* SCORE_LOAN is inversed */
1050
 
                                if (i == SCORE_LOAN) val = needed - val;
1051
 
 
1052
 
                                /* Draw the amount we have against what is needed
1053
 
                                 * For some of them it is in currency format */
1054
 
                                SetDParam(0, val);
1055
 
                                SetDParam(1, needed);
1056
 
                                switch (i) {
1057
 
                                        case SCORE_MIN_PROFIT:
1058
 
                                        case SCORE_MIN_INCOME:
1059
 
                                        case SCORE_MAX_INCOME:
1060
 
                                        case SCORE_MONEY:
1061
 
                                        case SCORE_LOAN:
1062
 
                                                DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY, TC_FROMSTRING);
1063
 
                                                break;
1064
 
                                        default:
1065
 
                                                DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_INT, TC_FROMSTRING);
1066
 
                                }
1067
 
                        }
1068
 
 
1069
 
                        break;
1070
 
                }
1071
 
 
1072
 
                case WE_CLICK:
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);
1080
 
                                        SetWindowDirty(w);
1081
 
                                }
1082
 
                        }
1083
 
                        break;
1084
 
 
1085
 
                case WE_CREATE: {
1086
 
                        Player *p2;
1087
 
 
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);
1091
 
                        }
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);
1096
 
                        }
1097
 
 
1098
 
                        w->custom[0] = DAY_TICKS;
1099
 
                        w->custom[1] = 5;
1100
 
 
1101
 
                        if (_performance_rating_detail_player != INVALID_PLAYER) w->LowerWidget(_performance_rating_detail_player + 13);
1102
 
                        SetWindowDirty(w);
1103
 
 
1104
 
                        break;
1105
 
                }
1106
 
 
1107
 
                case WE_TICK:
1108
 
                        if (_pause_game != 0) break;
1109
 
 
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) {
1114
 
                                        Player *p2;
1115
 
 
1116
 
                                        w->custom[1] = 5;
1117
 
                                        FOR_ALL_PLAYERS(p2) {
1118
 
                                                /* Skip if player is not active */
1119
 
                                                if (p2->is_active) UpdateCompanyRatingAndValue(p2, false);
1120
 
                                        }
1121
 
                                        SetWindowDirty(w);
1122
 
                                }
1123
 
                        }
1124
 
 
1125
 
                        break;
1126
 
        }
1127
 
}
 
945
                                        this->SetDirty();
 
946
                                }
 
947
                                continue;
 
948
                        }
 
949
 
 
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 */
 
955
                                this->SetDirty();
 
956
                        }
 
957
 
 
958
                        x = (i == company) ? 1 : 0;
 
959
                        DrawCompanyIcon(i, (i % 8) * 37 + 13 + x, (i < 8 ? 0 : 13) + 16 + x);
 
960
                }
 
961
 
 
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];
 
965
 
 
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;
 
971
 
 
972
                        y += 20;
 
973
                        /* SCORE_TOTAL has his own rulez ;) */
 
974
                        if (i == SCORE_TOTAL) {
 
975
                                needed = total_score;
 
976
                                score = SCORE_MAX;
 
977
                        } else {
 
978
                                total_score += score;
 
979
                        }
 
980
 
 
981
                        DrawString(7, y, STR_PERFORMANCE_DETAIL_VEHICLES + i, TC_FROMSTRING);
 
982
 
 
983
                        /* Draw the score */
 
984
                        SetDParam(0, score);
 
985
                        DrawStringRightAligned(107, y, STR_PERFORMANCE_DETAIL_INT, TC_FROMSTRING);
 
986
 
 
987
                        /* Calculate the %-bar */
 
988
                        x = Clamp(val, 0, needed) * 50 / needed;
 
989
 
 
990
                        /* SCORE_LOAN is inversed */
 
991
                        if (val < 0 && i == SCORE_LOAN) x = 0;
 
992
 
 
993
                        /* Draw the bar */
 
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);
 
996
 
 
997
                        /* Calculate the % */
 
998
                        x = Clamp(val, 0, needed) * 100 / needed;
 
999
 
 
1000
                        /* SCORE_LOAN is inversed */
 
1001
                        if (val < 0 && i == SCORE_LOAN) x = 0;
 
1002
 
 
1003
                        /* Draw it */
 
1004
                        SetDParam(0, x);
 
1005
                        DrawStringCentered(137, y, STR_PERFORMANCE_DETAIL_PERCENT, TC_FROMSTRING);
 
1006
 
 
1007
                        /* SCORE_LOAN is inversed */
 
1008
                        if (i == SCORE_LOAN) val = needed - val;
 
1009
 
 
1010
                        /* Draw the amount we have against what is needed
 
1011
                         * For some of them it is in currency format */
 
1012
                        SetDParam(0, val);
 
1013
                        SetDParam(1, needed);
 
1014
                        switch (i) {
 
1015
                                case SCORE_MIN_PROFIT:
 
1016
                                case SCORE_MIN_INCOME:
 
1017
                                case SCORE_MAX_INCOME:
 
1018
                                case SCORE_MONEY:
 
1019
                                case SCORE_LOAN:
 
1020
                                        DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY, TC_FROMSTRING);
 
1021
                                        break;
 
1022
                                default:
 
1023
                                        DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_INT, TC_FROMSTRING);
 
1024
                        }
 
1025
                }
 
1026
        }
 
1027
 
 
1028
        virtual void OnClick(Point pt, int widget)
 
1029
        {
 
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);
 
1037
                                this->SetDirty();
 
1038
                        }
 
1039
                }
 
1040
        }
 
1041
 
 
1042
        virtual void OnTick()
 
1043
        {
 
1044
                if (_pause_game != 0) return;
 
1045
 
 
1046
                /* Update the company score every 5 days */
 
1047
                if (--this->timeout == 0) {
 
1048
                        this->UpdateCompanyStats();
 
1049
                        this->SetDirty();
 
1050
                }
 
1051
        }
 
1052
};
 
1053
 
 
1054
CompanyID PerformanceRatingDetailWindow::company = INVALID_COMPANY;
 
1055
 
1128
1056
 
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},
1133
 
 
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},
1144
 
 
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},
 
1061
 
 
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},
 
1072
 
 
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},
1154
1089
};
1155
1090
 
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
1162
 
};
 
1095
        _performance_rating_detail_widgets
 
1096
);
1163
1097
 
1164
1098
void ShowPerformanceRatingDetail()
1165
1099
{
1166
 
        AllocateWindowDescFront(&_performance_rating_detail_desc, 0);
 
1100
        AllocateWindowDescFront<PerformanceRatingDetailWindow>(&_performance_rating_detail_desc, 0);
1167
1101
}