# graph_gui.cpp

Go to the documentation of this file.

    00001 /* $Id: graph_gui.cpp 16059 2009-04-14 21:07:33Z rubidium $ */
    00002
    00005 #include "stdafx.h"
    00006 #include "openttd.h"
    00007 #include "gui.h"
    00008 #include "window_gui.h"
    00009 #include "company_base.h"
    00010 #include "company_gui.h"
    00011 #include "economy_func.h"
    00012 #include "cargotype.h"
    00013 #include "strings_func.h"
    00014 #include "window_func.h"
    00015 #include "date_func.h"
    00016 #include "gfx_func.h"
    00017 #include "sortlist_type.h"
    00018
    00019 #include "table/strings.h"
    00020
    00021 /* Bitmasks of company and cargo indices that shouldn't be drawn. */
    00022 static uint _legend_excluded_companies;
    00023 static uint _legend_excluded_cargo;
    00024
    00025 /* Apparently these don't play well with enums. */
    00026 static const OverflowSafeInt64 INVALID_DATAPOINT(INT64_MAX); // Value used for a datapoint that shouldn't be drawn.
    00027 static const uint INVALID_DATAPOINT_POS = UINT_MAX;  // Used to determine if the previous point was drawn.
    00028
    00029 /****************/
    00030 /* GRAPH LEGEND */
    00031 /****************/
    00032
    00033 struct GraphLegendWindow : Window {
    00034   GraphLegendWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
    00035   {
    00036     for (uint i = 3; i < this->widget_count; i++) {
    00037       if (!HasBit(_legend_excluded_companies, i - 3)) this->LowerWidget(i);
    00038     }
    00039
    00040     this->FindWindowPlacementAndResize(desc);
    00041   }
    00042
    00043   virtual void OnPaint()
    00044   {
    00045     for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
    00046       if (IsValidCompanyID(c)) continue;
    00047
    00048       SetBit(_legend_excluded_companies, c);
    00049       this->RaiseWidget(c + 3);
    00050     }
    00051
    00052     this->DrawWidgets();
    00053
    00054     const Company *c;
    00055     FOR_ALL_COMPANIES(c) {
    00056       DrawCompanyIcon(c->index, 4, 18 + c->index * 12);
    00057
    00058       SetDParam(0, c->index);
    00059       SetDParam(1, c->index);
    00060       DrawString(21, 17 + c->index * 12, STR_7021, HasBit(_legend_excluded_companies, c->index) ? TC_BLACK : TC_WHITE);
    00061     }
    00062   }
    00063
    00064   virtual void OnClick(Point pt, int widget)
    00065   {
    00066     if (!IsInsideMM(widget, 3, MAX_COMPANIES + 3)) return;
    00067
    00068     ToggleBit(_legend_excluded_companies, widget - 3);
    00069     this->ToggleWidgetLoweredState(widget);
    00070     this->SetDirty();
    00071     InvalidateWindow(WC_INCOME_GRAPH, 0);
    00072     InvalidateWindow(WC_OPERATING_PROFIT, 0);
    00073     InvalidateWindow(WC_DELIVERED_CARGO, 0);
    00074     InvalidateWindow(WC_PERFORMANCE_HISTORY, 0);
    00075     InvalidateWindow(WC_COMPANY_VALUE, 0);
    00076   }
    00077 };
    00078
    00079 static const Widget _graph_legend_widgets[] = {
    00080 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_GREY,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},
    00081 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_GREY,    11,   249,     0,    13, STR_704E_KEY_TO_COMPANY_GRAPHS, STR_018C_WINDOW_TITLE_DRAG_THIS},
    00082 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   249,    14,   195, 0x0,                            STR_NULL},
    00083 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,    16,    27, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00084 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,    28,    39, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00085 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,    40,    51, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00086 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,    52,    63, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00087 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,    64,    75, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00088 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,    76,    87, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00089 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,    88,    99, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00090 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,   100,   111, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00091 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,   112,   123, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00092 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,   124,   135, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00093 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,   136,   147, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00094 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,   148,   159, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00095 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,   160,   171, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00096 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,   172,   183, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00097 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,   184,   195, 0x0,                            STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    00098 {   WIDGETS_END},
    00099 };
    00100
    00101 static const WindowDesc _graph_legend_desc(
    00102   WDP_AUTO, WDP_AUTO, 250, 198, 250, 198,
    00103   WC_GRAPH_LEGEND, WC_NONE,
    00104   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
    00105   _graph_legend_widgets
    00106 );
    00107
    00108 static void ShowGraphLegend()
    00109 {
    00110   AllocateWindowDescFront<GraphLegendWindow>(&_graph_legend_desc, 0);
    00111 }
    00112
    00113 /******************/
    00114 /* BASE OF GRAPHS */
    00115 /*****************/
    00116
    00117 struct BaseGraphWindow : Window {
    00118 protected:
    00119   enum {
    00120     GRAPH_MAX_DATASETS = 32,
    00121     GRAPH_AXIS_LINE_COLOUR  = 215,
    00122
    00123     GRAPH_X_POSITION_BEGINNING  = 44,
    00124     GRAPH_X_POSITION_SEPARATION = 22,
    00125
    00126     GRAPH_NUM_LINES_Y = 9,
    00127     /* 9 is convenient as that means the distance between them is the gd_height of the graph / 8,
    00128      * which is the same
    00129      * as height >> 3. */
    00130   };
    00131
    00132   uint excluded_data;
    00133   byte num_dataset;
    00134   byte num_on_x_axis;
    00135   bool has_negative_values;
    00136   byte num_vert_lines;
    00137   static const TextColour graph_axis_label_colour = TC_BLACK;
    00138
    00139   /* The starting month and year that values are plotted against. If month is
    00140    * 0xFF, use x_values_start and x_values_increment below instead. */
    00141   byte month;
    00142   Year year;
    00143
    00144   /* These values are used if the graph is being plotted against values
    00145    * rather than the dates specified by month and year. */
    00146   uint16 x_values_start;
    00147   uint16 x_values_increment;
    00148
    00149   int gd_left, gd_top;
    00150   uint gd_height;
    00151   StringID format_str_y_axis;
    00152   byte colours[GRAPH_MAX_DATASETS];
    00153   OverflowSafeInt64 cost[GRAPH_MAX_DATASETS][24];
    00154
    00155   void DrawGraph() const
    00156   {
    00157     uint x, y;
    00158     OverflowSafeInt64 highest_value;
    00159     int x_axis_offset;
    00160
    00161     /* the colours and cost array of GraphDrawer must accomodate
    00162      * both values for cargo and companies. So if any are higher, quit */
    00163     assert(GRAPH_MAX_DATASETS >= (int)NUM_CARGO && GRAPH_MAX_DATASETS >= (int)MAX_COMPANIES);
    00164     assert(this->num_vert_lines > 0);
    00165
    00166     byte grid_colour = _colour_gradient[COLOUR_GREY][4];
    00167
    00168     /* The coordinates of the opposite edges of the graph. */
    00169     int bottom = this->gd_top + this->gd_height - 1;
    00170     int right  = this->gd_left + GRAPH_X_POSITION_BEGINNING + this->num_vert_lines * GRAPH_X_POSITION_SEPARATION - 1;
    00171
    00172     /* Draw the vertical grid lines. */
    00173
    00174     /* Don't draw the first line, as that's where the axis will be. */
    00175     x = this->gd_left + GRAPH_X_POSITION_BEGINNING + GRAPH_X_POSITION_SEPARATION;
    00176
    00177     for (int i = 0; i < this->num_vert_lines; i++) {
    00178       GfxFillRect(x, this->gd_top, x, bottom, grid_colour);
    00179       x += GRAPH_X_POSITION_SEPARATION;
    00180     }
    00181
    00182     /* Draw the horizontal grid lines. */
    00183     x = this->gd_left + GRAPH_X_POSITION_BEGINNING;
    00184     y = this->gd_height + this->gd_top;
    00185
    00186     for (int i = 0; i < GRAPH_NUM_LINES_Y; i++) {
    00187       GfxFillRect(x, y, right, y, grid_colour);
    00188       y -= (this->gd_height / (GRAPH_NUM_LINES_Y - 1));
    00189     }
    00190
    00191     /* Draw the y axis. */
    00192     GfxFillRect(x, this->gd_top, x, bottom, GRAPH_AXIS_LINE_COLOUR);
    00193
    00194     /* Find the distance from the gd_top of the graph to the x axis. */
    00195     x_axis_offset = this->gd_height;
    00196
    00197     /* The graph is currently symmetrical about the x axis. */
    00198     if (this->has_negative_values) x_axis_offset /= 2;
    00199
    00200     /* Draw the x axis. */
    00201     y = x_axis_offset + this->gd_top;
    00202     GfxFillRect(x, y, right, y, GRAPH_AXIS_LINE_COLOUR);
    00203
    00204     /* Find the largest value that will be drawn. */
    00205     if (this->num_on_x_axis == 0)
    00206       return;
    00207
    00208     assert(this->num_on_x_axis > 0);
    00209     assert(this->num_dataset > 0);
    00210
    00211     /* Start of with a value of twice the gd_height of the graph in pixels. It's a
    00212      * bit arbitrary, but it makes the cargo payment graph look a little nicer,
    00213      * and prevents division by zero when calculating where the datapoint
    00214      * should be drawn. */
    00215     highest_value = x_axis_offset * 2;
    00216
    00217     for (int i = 0; i < this->num_dataset; i++) {
    00218       if (!HasBit(this->excluded_data, i)) {
    00219         for (int j = 0; j < this->num_on_x_axis; j++) {
    00220           OverflowSafeInt64 datapoint = this->cost[i][j];
    00221
    00222           if (datapoint != INVALID_DATAPOINT) {
    00223             /* For now, if the graph has negative values the scaling is
    00224              * symmetrical about the x axis, so take the absolute value
    00225              * of each data point. */
    00226             highest_value = max(highest_value, abs(datapoint));
    00227           }
    00228         }
    00229       }
    00230     }
    00231
    00232     /* Round up highest_value so that it will divide cleanly into the number of
    00233      * axis labels used. */
    00234     int round_val = highest_value % (GRAPH_NUM_LINES_Y - 1);
    00235     if (round_val != 0) highest_value += (GRAPH_NUM_LINES_Y - 1 - round_val);
    00236
    00237     /* draw text strings on the y axis */
    00238     int64 y_label = highest_value;
    00239     int64 y_label_separation = highest_value / (GRAPH_NUM_LINES_Y - 1);
    00240
    00241     /* If there are negative values, the graph goes from highest_value to
    00242      * -highest_value, not highest_value to 0. */
    00243     if (this->has_negative_values) y_label_separation *= 2;
    00244
    00245     x = this->gd_left + GRAPH_X_POSITION_BEGINNING + 1;
    00246     y = this->gd_top - 3;
    00247
    00248     for (int i = 0; i < GRAPH_NUM_LINES_Y; i++) {
    00249       SetDParam(0, this->format_str_y_axis);
    00250       SetDParam(1, y_label);
    00251       DrawStringRightAligned(x, y, STR_0170, graph_axis_label_colour);
    00252
    00253       y_label -= y_label_separation;
    00254       y += (this->gd_height / (GRAPH_NUM_LINES_Y - 1));
    00255     }
    00256
    00257     /* draw strings on the x axis */
    00258     if (this->month != 0xFF) {
    00259       x = this->gd_left + GRAPH_X_POSITION_BEGINNING;
    00260       y = this->gd_top + this->gd_height + 1;
    00261       byte month = this->month;
    00262       Year year  = this->year;
    00263       for (int i = 0; i < this->num_on_x_axis; i++) {
    00264         SetDParam(0, month + STR_0162_JAN);
    00265         SetDParam(1, month + STR_0162_JAN + 2);
    00266         SetDParam(2, year);
    00267         DrawString(x, y, month == 0 ? STR_016F : STR_016E, graph_axis_label_colour);
    00268
    00269         month += 3;
    00270         if (month >= 12) {
    00271           month = 0;
    00272           year++;
    00273         }
    00274         x += GRAPH_X_POSITION_SEPARATION;
    00275       }
    00276     } else {
    00277       /* Draw the label under the data point rather than on the grid line. */
    00278       x = this->gd_left + GRAPH_X_POSITION_BEGINNING + (GRAPH_X_POSITION_SEPARATION / 2) + 1;
    00279       y = this->gd_top + this->gd_height + 1;
    00280       uint16 label = this->x_values_start;
    00281
    00282       for (int i = 0; i < this->num_on_x_axis; i++) {
    00283         SetDParam(0, label);
    00284         DrawStringCentered(x, y, STR_01CB, graph_axis_label_colour);
    00285
    00286         label += this->x_values_increment;
    00287         x += GRAPH_X_POSITION_SEPARATION;
    00288       }
    00289     }
    00290
    00291     /* draw lines and dots */
    00292     for (int i = 0; i < this->num_dataset; i++) {
    00293       if (!HasBit(this->excluded_data, i)) {
    00294         /* Centre the dot between the grid lines. */
    00295         x = this->gd_left + GRAPH_X_POSITION_BEGINNING + (GRAPH_X_POSITION_SEPARATION / 2);
    00296
    00297         byte colour  = this->colours[i];
    00298         uint prev_x = INVALID_DATAPOINT_POS;
    00299         uint prev_y = INVALID_DATAPOINT_POS;
    00300
    00301         for (int j = 0; j < this->num_on_x_axis; j++) {
    00302           OverflowSafeInt64 datapoint = this->cost[i][j];
    00303
    00304           if (datapoint != INVALID_DATAPOINT) {
    00305             /*
    00306              * Check whether we need to reduce the 'accuracy' of the
    00307              * datapoint value and the highest value to splut overflows.
    00308              * And when 'drawing' 'one million' or 'one million and one'
    00309              * there is no significant difference, so the least
    00310              * significant bits can just be removed.
    00311              *
    00312              * If there are more bits needed than would fit in a 32 bits
    00313              * integer, so at about 31 bits because of the sign bit, the
    00314              * least significant bits are removed.
    00315              */
    00316             int mult_range = FindLastBit(x_axis_offset) + FindLastBit(abs(datapoint));
    00317             int reduce_range = max(mult_range - 31, 0);
    00318
    00319             /* Handle negative values differently (don't shift sign) */
    00320             if (datapoint < 0) {
    00321               datapoint = -(abs(datapoint) >> reduce_range);
    00322             } else {
    00323               datapoint >>= reduce_range;
    00324             }
    00325
    00326             y = this->gd_top + x_axis_offset - (x_axis_offset * datapoint) / (highest_value >> reduce_range);
    00327
    00328             /* Draw the point. */
    00329             GfxFillRect(x - 1, y - 1, x + 1, y + 1, colour);
    00330
    00331             /* Draw the line connected to the previous point. */
    00332             if (prev_x != INVALID_DATAPOINT_POS) GfxDrawLine(prev_x, prev_y, x, y, colour);
    00333
    00334             prev_x = x;
    00335             prev_y = y;
    00336           } else {
    00337             prev_x = INVALID_DATAPOINT_POS;
    00338             prev_y = INVALID_DATAPOINT_POS;
    00339           }
    00340
    00341           x += GRAPH_X_POSITION_SEPARATION;
    00342         }
    00343       }
    00344     }
    00345   }
    00346
    00347
    00348   BaseGraphWindow(const WindowDesc *desc, WindowNumber window_number, int left,
    00349                   int top, int height, bool has_negative_values, StringID format_str_y_axis) :
    00350       Window(desc, window_number), has_negative_values(has_negative_values),
    00351       gd_left(left), gd_top(top), gd_height(height), format_str_y_axis(format_str_y_axis)
    00352   {
    00353     InvalidateWindow(WC_GRAPH_LEGEND, 0);
    00354   }
    00355
    00356 public:
    00357   virtual void OnPaint()
    00358   {
    00359     this->DrawWidgets();
    00360
    00361     uint excluded_companies = _legend_excluded_companies;
    00362
    00363     /* Exclude the companies which aren't valid */
    00364     for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
    00365       if (!IsValidCompanyID(c)) SetBit(excluded_companies, c);
    00366     }
    00367     this->excluded_data = excluded_companies;
    00368     this->num_vert_lines = 24;
    00369
    00370     byte nums = 0;
    00371     const Company *c;
    00372     FOR_ALL_COMPANIES(c) {
    00373       nums = max(nums, c->num_valid_stat_ent);
    00374     }
    00375     this->num_on_x_axis = min(nums, 24);
    00376
    00377     int mo = (_cur_month / 3 - nums) * 3;
    00378     int yr = _cur_year;
    00379     while (mo < 0) {
    00380       yr--;
    00381       mo += 12;
    00382     }
    00383
    00384     this->year = yr;
    00385     this->month = mo;
    00386
    00387     int numd = 0;
    00388     for (CompanyID k = COMPANY_FIRST; k < MAX_COMPANIES; k++) {
    00389       if (IsValidCompanyID(k)) {
    00390         c = GetCompany(k);
    00391         this->colours[numd] = _colour_gradient[c->colour][6];
    00392         for (int j = this->num_on_x_axis, i = 0; --j >= 0;) {
    00393           this->cost[numd][i] = (j >= c->num_valid_stat_ent) ? INVALID_DATAPOINT : GetGraphData(c, j);
    00394           i++;
    00395         }
    00396       }
    00397       numd++;
    00398     }
    00399
    00400     this->num_dataset = numd;
    00401
    00402     this->DrawGraph();
    00403   }
    00404
    00405   virtual OverflowSafeInt64 GetGraphData(const Company *c, int j)
    00406   {
    00407     return INVALID_DATAPOINT;
    00408   }
    00409
    00410   virtual void OnClick(Point pt, int widget)
    00411   {
    00412     /* Clicked on legend? */
    00413     if (widget == 2) ShowGraphLegend();
    00414   }
    00415 };
    00416
    00417 /********************/
    00418 /* OPERATING PROFIT */
    00419 /********************/
    00420
    00421 struct OperatingProfitGraphWindow : BaseGraphWindow {
    00422   OperatingProfitGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
    00423       BaseGraphWindow(desc, window_number, 2, 18, 136, true, STR_CURRCOMPACT)
    00424   {
    00425     this->FindWindowPlacementAndResize(desc);
    00426   }
    00427
    00428   virtual OverflowSafeInt64 GetGraphData(const Company *c, int j)
    00429   {
    00430     return c->old_economy[j].income + c->old_economy[j].expenses;
    00431   }
    00432 };
    00433
    00434 static const Widget _operating_profit_widgets[] = {
    00435 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_GREY,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},
    00436 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_GREY,    11,   525,     0,    13, STR_7025_OPERATING_PROFIT_GRAPH, STR_018C_WINDOW_TITLE_DRAG_THIS},
    00437 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   526,   575,     0,    13, STR_704C_KEY,                    STR_704D_SHOW_KEY_TO_GRAPHS},
    00438 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   575,    14,   173, 0x0,                             STR_NULL},
    00439 {   WIDGETS_END},
    00440 };
    00441
    00442 static const WindowDesc _operating_profit_desc(
    00443   WDP_AUTO, WDP_AUTO, 576, 174, 576, 174,
    00444   WC_OPERATING_PROFIT, WC_NONE,
    00445   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
    00446   _operating_profit_widgets
    00447 );
    00448
    00449
    00450 void ShowOperatingProfitGraph()
    00451 {
    00452   AllocateWindowDescFront<OperatingProfitGraphWindow>(&_operating_profit_desc, 0);
    00453 }
    00454
    00455
    00456 /****************/
    00457 /* INCOME GRAPH */
    00458 /****************/
    00459
    00460 struct IncomeGraphWindow : BaseGraphWindow {
    00461   IncomeGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
    00462       BaseGraphWindow(desc, window_number, 2, 18, 104, false, STR_CURRCOMPACT)
    00463   {
    00464     this->FindWindowPlacementAndResize(desc);
    00465   }
    00466
    00467   virtual OverflowSafeInt64 GetGraphData(const Company *c, int j)
    00468   {
    00469     return c->old_economy[j].income;
    00470   }
    00471 };
    00472
    00473 static const Widget _income_graph_widgets[] = {
    00474 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_GREY,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},
    00475 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_GREY,    11,   525,     0,    13, STR_7022_INCOME_GRAPH, STR_018C_WINDOW_TITLE_DRAG_THIS},
    00476 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   526,   575,     0,    13, STR_704C_KEY,          STR_704D_SHOW_KEY_TO_GRAPHS},
    00477 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   575,    14,   141, 0x0,                   STR_NULL},
    00478 {   WIDGETS_END},
    00479 };
    00480
    00481 static const WindowDesc _income_graph_desc(
    00482   WDP_AUTO, WDP_AUTO, 576, 142, 576, 142,
    00483   WC_INCOME_GRAPH, WC_NONE,
    00484   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
    00485   _income_graph_widgets
    00486 );
    00487
    00488 void ShowIncomeGraph()
    00489 {
    00490   AllocateWindowDescFront<IncomeGraphWindow>(&_income_graph_desc, 0);
    00491 }
    00492
    00493 /*******************/
    00494 /* DELIVERED CARGO */
    00495 /*******************/
    00496
    00497 struct DeliveredCargoGraphWindow : BaseGraphWindow {
    00498   DeliveredCargoGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
    00499       BaseGraphWindow(desc, window_number, 2, 18, 104, false, STR_7024)
    00500   {
    00501     this->FindWindowPlacementAndResize(desc);
    00502   }
    00503
    00504   virtual OverflowSafeInt64 GetGraphData(const Company *c, int j)
    00505   {
    00506     return c->old_economy[j].delivered_cargo;
    00507   }
    00508 };
    00509
    00510 static const Widget _delivered_cargo_graph_widgets[] = {
    00511 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_GREY,     0,    10,     0,    13, STR_00C5,                          STR_018B_CLOSE_WINDOW},
    00512 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_GREY,    11,   525,     0,    13, STR_7050_UNITS_OF_CARGO_DELIVERED, STR_018C_WINDOW_TITLE_DRAG_THIS},
    00513 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   526,   575,     0,    13, STR_704C_KEY,                      STR_704D_SHOW_KEY_TO_GRAPHS},
    00514 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   575,    14,   141, 0x0,                               STR_NULL},
    00515 {   WIDGETS_END},
    00516 };
    00517
    00518 static const WindowDesc _delivered_cargo_graph_desc(
    00519   WDP_AUTO, WDP_AUTO, 576, 142, 576, 142,
    00520   WC_DELIVERED_CARGO, WC_NONE,
    00521   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
    00522   _delivered_cargo_graph_widgets
    00523 );
    00524
    00525 void ShowDeliveredCargoGraph()
    00526 {
    00527   AllocateWindowDescFront<DeliveredCargoGraphWindow>(&_delivered_cargo_graph_desc, 0);
    00528 }
    00529
    00530 /***********************/
    00531 /* PERFORMANCE HISTORY */
    00532 /***********************/
    00533
    00534 struct PerformanceHistoryGraphWindow : BaseGraphWindow {
    00535   PerformanceHistoryGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
    00536       BaseGraphWindow(desc, window_number, 2, 18, 200, false, STR_7024)
    00537   {
    00538     this->FindWindowPlacementAndResize(desc);
    00539   }
    00540
    00541   virtual OverflowSafeInt64 GetGraphData(const Company *c, int j)
    00542   {
    00543     return c->old_economy[j].performance_history;
    00544   }
    00545
    00546   virtual void OnClick(Point pt, int widget)
    00547   {
    00548     if (widget == 3) ShowPerformanceRatingDetail();
    00549     this->BaseGraphWindow::OnClick(pt, widget);
    00550   }
    00551 };
    00552
    00553 static const Widget _performance_history_widgets[] = {
    00554 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_GREY,     0,    10,     0,    13, STR_00C5,                             STR_018B_CLOSE_WINDOW},
    00555 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_GREY,    11,   475,     0,    13, STR_7051_COMPANY_PERFORMANCE_RATINGS, STR_018C_WINDOW_TITLE_DRAG_THIS},
    00556 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   526,   575,     0,    13, STR_704C_KEY,                         STR_704D_SHOW_KEY_TO_GRAPHS},
    00557 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   476,   525,     0,    13, STR_PERFORMANCE_DETAIL_KEY,           STR_SHOW_DETAILED_PERFORMANCE_RATINGS},
    00558 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   575,    14,   237, 0x0,                                  STR_NULL},
    00559 {   WIDGETS_END},
    00560 };
    00561
    00562 static const WindowDesc _performance_history_desc(
    00563   WDP_AUTO, WDP_AUTO, 576, 238, 576, 238,
    00564   WC_PERFORMANCE_HISTORY, WC_NONE,
    00565   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
    00566   _performance_history_widgets
    00567 );
    00568
    00569 void ShowPerformanceHistoryGraph()
    00570 {
    00571   AllocateWindowDescFront<PerformanceHistoryGraphWindow>(&_performance_history_desc, 0);
    00572 }
    00573
    00574 /*****************/
    00575 /* COMPANY VALUE */
    00576 /*****************/
    00577
    00578 struct CompanyValueGraphWindow : BaseGraphWindow {
    00579   CompanyValueGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
    00580       BaseGraphWindow(desc, window_number, 2, 18, 200, false, STR_CURRCOMPACT)
    00581   {
    00582     this->FindWindowPlacementAndResize(desc);
    00583   }
    00584
    00585   virtual OverflowSafeInt64 GetGraphData(const Company *c, int j)
    00586   {
    00587     return c->old_economy[j].company_value;
    00588   }
    00589 };
    00590
    00591 static const Widget _company_value_graph_widgets[] = {
    00592 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_GREY,     0,    10,     0,    13, STR_00C5,                STR_018B_CLOSE_WINDOW},
    00593 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_GREY,    11,   525,     0,    13, STR_7052_COMPANY_VALUES, STR_018C_WINDOW_TITLE_DRAG_THIS},
    00594 { WWT_PUSHTXTBTN,   RESIZE_NONE,  COLOUR_GREY,   526,   575,     0,    13, STR_704C_KEY,            STR_704D_SHOW_KEY_TO_GRAPHS},
    00595 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   575,    14,   237, 0x0,                     STR_NULL},
    00596 {   WIDGETS_END},
    00597 };
    00598
    00599 static const WindowDesc _company_value_graph_desc(
    00600   WDP_AUTO, WDP_AUTO, 576, 238, 576, 238,
    00601   WC_COMPANY_VALUE, WC_NONE,
    00602   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
    00603   _company_value_graph_widgets
    00604 );
    00605
    00606 void ShowCompanyValueGraph()
    00607 {
    00608   AllocateWindowDescFront<CompanyValueGraphWindow>(&_company_value_graph_desc, 0);
    00609 }
    00610
    00611 /*****************/
    00612 /* PAYMENT RATES */
    00613 /*****************/
    00614
    00615 struct PaymentRatesGraphWindow : BaseGraphWindow {
    00616   PaymentRatesGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
    00617       BaseGraphWindow(desc, window_number, 2, 24, 200, false, STR_CURRCOMPACT)
    00618   {
    00619     uint num_active = 0;
    00620     for (CargoID c = 0; c < NUM_CARGO; c++) {
    00621       if (GetCargo(c)->IsValid()) num_active++;
    00622     }
    00623
    00624     /* Resize the window to fit the cargo types */
    00625     ResizeWindow(this, 0, max(num_active, 12U) * 8);
    00626
    00627     /* Add widgets for each cargo type */
    00628     this->widget_count += num_active;
    00629     this->widget = ReallocT(this->widget, this->widget_count + 1);
    00630     this->widget[this->widget_count].type = WWT_LAST;
    00631
    00632     /* Set the properties of each widget */
    00633     for (uint i = 0; i != num_active; i++) {
    00634       Widget *wi = &this->widget[3 + i];
    00635       wi->type     = WWT_PANEL;
    00636       wi->display_flags = RESIZE_NONE;
    00637       wi->colour   = COLOUR_ORANGE;
    00638       wi->left     = 493;
    00639       wi->right    = 562;
    00640       wi->top      = 24 + i * 8;
    00641       wi->bottom   = wi->top + 7;
    00642       wi->data     = 0;
    00643       wi->tooltips = STR_7064_TOGGLE_GRAPH_FOR_CARGO;
    00644
    00645       if (!HasBit(_legend_excluded_cargo, i)) this->LowerWidget(i + 3);
    00646     }
    00647
    00648     this->SetDirty();
    00649
    00650     this->gd_height = this->height - 38;
    00651     this->num_on_x_axis = 20;
    00652     this->num_vert_lines = 20;
    00653     this->month = 0xFF;
    00654     this->x_values_start     = 10;
    00655     this->x_values_increment = 10;
    00656
    00657     this->FindWindowPlacementAndResize(desc);
    00658   }
    00659
    00660   virtual void OnPaint()
    00661   {
    00662     this->DrawWidgets();
    00663
    00664     this->excluded_data = _legend_excluded_cargo;
    00665
    00666     int x = 495;
    00667     int y = 24;
    00668
    00669     uint i = 0;
    00670     for (CargoID c = 0; c < NUM_CARGO; c++) {
    00671       const CargoSpec *cs = GetCargo(c);
    00672       if (!cs->IsValid()) continue;
    00673
    00674       /* Only draw labels for widgets that exist. If the widget doesn't
    00675        * exist then the local company has used the climate cheat or
    00676        * changed the NewGRF configuration with this window open. */
    00677       if (i + 3 < this->widget_count) {
    00678         /* Since the buttons have no text, no images,
    00679          * both the text and the coloured box have to be manually painted.
    00680          * clk_dif will move one pixel down and one pixel to the right
    00681          * when the button is clicked */
    00682         byte clk_dif = this->IsWidgetLowered(i + 3) ? 1 : 0;
    00683
    00684         GfxFillRect(x + clk_dif, y + clk_dif, x + 8 + clk_dif, y + 5 + clk_dif, 0);
    00685         GfxFillRect(x + 1 + clk_dif, y + 1 + clk_dif, x + 7 + clk_dif, y + 4 + clk_dif, cs->legend_colour);
    00686         SetDParam(0, cs->name);
    00687         DrawString(x + 14 + clk_dif, y + clk_dif, STR_7065, TC_FROMSTRING);
    00688         y += 8;
    00689       }
    00690
    00691       this->colours[i] = cs->legend_colour;
    00692       for (uint j = 0; j != 20; j++) {
    00693         this->cost[i][j] = GetTransportedGoodsIncome(10, 20, j * 4 + 4, c);
    00694       }
    00695
    00696       i++;
    00697     }
    00698     this->num_dataset = i;
    00699
    00700     this->DrawGraph();
    00701
    00702     DrawString(2 + 46, 24 + this->gd_height + 7, STR_7062_DAYS_IN_TRANSIT, TC_FROMSTRING);
    00703     DrawString(2 + 84, 24 - 9, STR_7063_PAYMENT_FOR_DELIVERING, TC_FROMSTRING);
    00704   }
    00705
    00706   virtual void OnClick(Point pt, int widget)
    00707   {
    00708     if (widget >= 3) {
    00709       ToggleBit(_legend_excluded_cargo, widget - 3);
    00710       this->ToggleWidgetLoweredState(widget);
    00711       this->SetDirty();
    00712     }
    00713   }
    00714 };
    00715
    00716 static const Widget _cargo_payment_rates_widgets[] = {
    00717 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_GREY,     0,    10,     0,    13, STR_00C5,                     STR_018B_CLOSE_WINDOW},
    00718 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_GREY,    11,   567,     0,    13, STR_7061_CARGO_PAYMENT_RATES, STR_018C_WINDOW_TITLE_DRAG_THIS},
    00719 {      WWT_PANEL, RESIZE_BOTTOM,  COLOUR_GREY,     0,   567,    14,    45, 0x0,                          STR_NULL},
    00720 {   WIDGETS_END},
    00721 };
    00722
    00723 static const WindowDesc _cargo_payment_rates_desc(
    00724   WDP_AUTO, WDP_AUTO, 568, 46, 568, 46,
    00725   WC_PAYMENT_RATES, WC_NONE,
    00726   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
    00727   _cargo_payment_rates_widgets
    00728 );
    00729
    00730
    00731 void ShowCargoPaymentRates()
    00732 {
    00733   AllocateWindowDescFront<PaymentRatesGraphWindow>(&_cargo_payment_rates_desc, 0);
    00734 }
    00735
    00736 /************************/
    00737 /* COMPANY LEAGUE TABLE */
    00738 /************************/
    00739
    00740 static const StringID _performance_titles[] = {
    00741   STR_7066_ENGINEER,
    00742   STR_7066_ENGINEER,
    00743   STR_7067_TRAFFIC_MANAGER,
    00744   STR_7067_TRAFFIC_MANAGER,
    00745   STR_7068_TRANSPORT_COORDINATOR,
    00746   STR_7068_TRANSPORT_COORDINATOR,
    00747   STR_7069_ROUTE_SUPERVISOR,
    00748   STR_7069_ROUTE_SUPERVISOR,
    00749   STR_706A_DIRECTOR,
    00750   STR_706A_DIRECTOR,
    00751   STR_706B_CHIEF_EXECUTIVE,
    00752   STR_706B_CHIEF_EXECUTIVE,
    00753   STR_706C_CHAIRMAN,
    00754   STR_706C_CHAIRMAN,
    00755   STR_706D_PRESIDENT,
    00756   STR_706E_TYCOON,
    00757 };
    00758
    00759 static inline StringID GetPerformanceTitleFromValue(uint value)
    00760 {
    00761   return _performance_titles[minu(value, 1000) >> 6];
    00762 }
    00763
    00764 class CompanyLeagueWindow : public Window {
    00765 private:
    00766   GUIList<const Company*> companies;
    00767
    00771   void BuildCompanyList()
    00772   {
    00773     if (!this->companies.NeedRebuild()) return;
    00774
    00775     this->companies.Clear();
    00776
    00777     const Company *c;
    00778     FOR_ALL_COMPANIES(c) {
    00779       *this->companies.Append() = c;
    00780     }
    00781
    00782     this->companies.Compact();
    00783     this->companies.RebuildDone();
    00784   }
    00785
    00787   static int CDECL PerformanceSorter(const Company * const *c1, const Company * const *c2)
    00788   {
    00789     return (*c2)->old_economy[1].performance_history - (*c1)->old_economy[1].performance_history;
    00790   }
    00791
    00792 public:
    00793   CompanyLeagueWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
    00794   {
    00795     this->companies.ForceRebuild();
    00796     this->companies.NeedResort();
    00797
    00798     this->FindWindowPlacementAndResize(desc);
    00799   }
    00800
    00801   virtual void OnPaint()
    00802   {
    00803     this->BuildCompanyList();
    00804     this->companies.Sort(&PerformanceSorter);
    00805
    00806     this->DrawWidgets();
    00807
    00808     for (uint i = 0; i != this->companies.Length(); i++) {
    00809       const Company *c = this->companies[i];
    00810       SetDParam(0, i + STR_01AC_1ST);
    00811       SetDParam(1, c->index);
    00812       SetDParam(2, c->index);
    00813       SetDParam(3, GetPerformanceTitleFromValue(c->old_economy[1].performance_history));
    00814
    00815       DrawString(2, 15 + i * 10, i == 0 ? STR_7054 : STR_7055, TC_FROMSTRING);
    00816       DrawCompanyIcon(c->index, 27, 16 + i * 10);
    00817     }
    00818   }
    00819
    00820   virtual void OnTick()
    00821   {
    00822     if (this->companies.NeedResort()) {
    00823       this->SetDirty();
    00824     }
    00825   }
    00826
    00827   virtual void OnInvalidateData(int data)
    00828   {
    00829     if (data == 0) {
    00830       this->companies.ForceRebuild();
    00831     } else {
    00832       this->companies.ForceResort();
    00833     }
    00834   }
    00835 };
    00836
    00837
    00838 static const Widget _company_league_widgets[] = {
    00839 {   WWT_CLOSEBOX, RESIZE_NONE,  COLOUR_GREY,   0,  10,  0,  13, STR_00C5,                      STR_018B_CLOSE_WINDOW},
    00840 {    WWT_CAPTION, RESIZE_NONE,  COLOUR_GREY,  11, 387,  0,  13, STR_7053_COMPANY_LEAGUE_TABLE, STR_018C_WINDOW_TITLE_DRAG_THIS},
    00841 {  WWT_STICKYBOX, RESIZE_NONE,  COLOUR_GREY, 388, 399,  0,  13, STR_NULL,                      STR_STICKY_BUTTON},
    00842 {      WWT_PANEL, RESIZE_NONE,  COLOUR_GREY,   0, 399, 14, 166, 0x0,                           STR_NULL},
    00843 {   WIDGETS_END},
    00844 };
    00845
    00846 static const WindowDesc _company_league_desc(
    00847   WDP_AUTO, WDP_AUTO, 400, 167, 400, 167,
    00848   WC_COMPANY_LEAGUE, WC_NONE,
    00849   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
    00850   _company_league_widgets
    00851 );
    00852
    00853 void ShowCompanyLeagueTable()
    00854 {
    00855   AllocateWindowDescFront<CompanyLeagueWindow>(&_company_league_desc, 0);
    00856 }
    00857
    00858 /*****************************/
    00859 /* PERFORMANCE RATING DETAIL */
    00860 /*****************************/
    00861
    00862 struct PerformanceRatingDetailWindow : Window {
    00863 private:
    00864   enum PerformanteRatingWidgets {
    00865     PRW_COMPANY_FIRST = 13,
    00866     PRW_COMPANY_LAST  = PRW_COMPANY_FIRST + MAX_COMPANIES - 1,
    00867   };
    00868
    00869 public:
    00870   static CompanyID company;
    00871   int timeout;
    00872
    00873   PerformanceRatingDetailWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
    00874   {
    00875     /* Disable the companies who are not active */
    00876     for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
    00877       this->SetWidgetDisabledState(i + PRW_COMPANY_FIRST, !IsValidCompanyID(i));
    00878     }
    00879
    00880     this->UpdateCompanyStats();
    00881
    00882     if (company != INVALID_COMPANY) this->LowerWidget(company + PRW_COMPANY_FIRST);
    00883
    00884     this->FindWindowPlacementAndResize(desc);
    00885   }
    00886
    00887   void UpdateCompanyStats()
    00888   {
    00889     /* Update all company stats with the current data
    00890      * (this is because _score_info is not saved to a savegame) */
    00891     Company *c;
    00892     FOR_ALL_COMPANIES(c) {
    00893       UpdateCompanyRatingAndValue(c, false);
    00894     }
    00895
    00896     this->timeout = DAY_TICKS * 5;
    00897
    00898   }
    00899
    00900   virtual void OnPaint()
    00901   {
    00902     byte x;
    00903     uint16 y = 27;
    00904     int total_score = 0;
    00905     int colour_done, colour_notdone;
    00906
    00907     /* Draw standard stuff */
    00908     this->DrawWidgets();
    00909
    00910     /* Check if the currently selected company is still active. */
    00911     if (company == INVALID_COMPANY || !IsValidCompanyID(company)) {
    00912       if (company != INVALID_COMPANY) {
    00913         /* Raise and disable the widget for the previous selection. */
    00914         this->RaiseWidget(company + PRW_COMPANY_FIRST);
    00915         this->DisableWidget(company + PRW_COMPANY_FIRST);
    00916         this->SetDirty();
    00917
    00918         company = INVALID_COMPANY;
    00919       }
    00920
    00921       for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
    00922         if (IsValidCompanyID(i)) {
    00923           /* Lower the widget corresponding to this company. */
    00924           this->LowerWidget(i + PRW_COMPANY_FIRST);
    00925           this->SetDirty();
    00926
    00927           company = i;
    00928           break;
    00929         }
    00930       }
    00931     }
    00932
    00933     /* If there are no active companies, don't display anything else. */
    00934     if (company == INVALID_COMPANY) return;
    00935
    00936     /* Paint the company icons */
    00937     for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
    00938       if (!IsValidCompanyID(i)) {
    00939         /* Check if we have the company as an active company */
    00940         if (!this->IsWidgetDisabled(i + PRW_COMPANY_FIRST)) {
    00941           /* Bah, company gone :( */
    00942           this->DisableWidget(i + PRW_COMPANY_FIRST);
    00943
    00944           /* We need a repaint */
    00945           this->SetDirty();
    00946         }
    00947         continue;
    00948       }
    00949
    00950       /* Check if we have the company marked as inactive */
    00951       if (this->IsWidgetDisabled(i + PRW_COMPANY_FIRST)) {
    00952         /* New company! Yippie :p */
    00953         this->EnableWidget(i + PRW_COMPANY_FIRST);
    00954         /* We need a repaint */
    00955         this->SetDirty();
    00956       }
    00957
    00958       x = (i == company) ? 1 : 0;
    00959       DrawCompanyIcon(i, (i % 8) * 37 + 13 + x, (i < 8 ? 0 : 13) + 16 + x);
    00960     }
    00961
    00962     /* The colours used to show how the progress is going */
    00963     colour_done = _colour_gradient[COLOUR_GREEN][4];
    00964     colour_notdone = _colour_gradient[COLOUR_RED][4];
    00965
    00966     /* Draw all the score parts */
    00967     for (ScoreID i = SCORE_BEGIN; i < SCORE_END; i++) {
    00968       int val    = _score_part[company][i];
    00969       int needed = _score_info[i].needed;
    00970       int score  = _score_info[i].score;
    00971
    00972       y += 20;
    00973       /* SCORE_TOTAL has his own rulez ;) */
    00974       if (i == SCORE_TOTAL) {
    00975         needed = total_score;
    00976         score = SCORE_MAX;
    00977       } else {
    00978         total_score += score;
    00979       }
    00980
    00981       DrawString(7, y, STR_PERFORMANCE_DETAIL_VEHICLES + i, TC_FROMSTRING);
    00982
    00983       /* Draw the score */
    00984       SetDParam(0, score);
    00985       DrawStringRightAligned(107, y, STR_PERFORMANCE_DETAIL_INT, TC_FROMSTRING);
    00986
    00987       /* Calculate the %-bar */
    00988       x = Clamp(val, 0, needed) * 50 / needed;
    00989
    00990       /* SCORE_LOAN is inversed */
    00991       if (val < 0 && i == SCORE_LOAN) x = 0;
    00992
    00993       /* Draw the bar */
    00994       if (x !=  0) GfxFillRect(112,     y - 2, 112 + x,  y + 10, colour_done);
    00995       if (x != 50) GfxFillRect(112 + x, y - 2, 112 + 50, y + 10, colour_notdone);
    00996
    00997       /* Calculate the % */
    00998       x = Clamp(val, 0, needed) * 100 / needed;
    00999
    01000       /* SCORE_LOAN is inversed */
    01001       if (val < 0 && i == SCORE_LOAN) x = 0;
    01002
    01003       /* Draw it */
    01004       SetDParam(0, x);
    01005       DrawStringCentered(137, y, STR_PERFORMANCE_DETAIL_PERCENT, TC_FROMSTRING);
    01006
    01007       /* SCORE_LOAN is inversed */
    01008       if (i == SCORE_LOAN) val = needed - val;
    01009
    01010       /* Draw the amount we have against what is needed
    01011        * For some of them it is in currency format */
    01012       SetDParam(0, val);
    01013       SetDParam(1, needed);
    01014       switch (i) {
    01015         case SCORE_MIN_PROFIT:
    01016         case SCORE_MIN_INCOME:
    01017         case SCORE_MAX_INCOME:
    01018         case SCORE_MONEY:
    01019         case SCORE_LOAN:
    01020           DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY, TC_FROMSTRING);
    01021           break;
    01022         default:
    01023           DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_INT, TC_FROMSTRING);
    01024       }
    01025     }
    01026   }
    01027
    01028   virtual void OnClick(Point pt, int widget)
    01029   {
    01030     /* Check which button is clicked */
    01031     if (IsInsideMM(widget, PRW_COMPANY_FIRST, PRW_COMPANY_LAST + 1)) {
    01032       /* Is it no on disable? */
    01033       if (!this->IsWidgetDisabled(widget)) {
    01034         this->RaiseWidget(company + PRW_COMPANY_FIRST);
    01035         company = (CompanyID)(widget - PRW_COMPANY_FIRST);
    01036         this->LowerWidget(company + PRW_COMPANY_FIRST);
    01037         this->SetDirty();
    01038       }
    01039     }
    01040   }
    01041
    01042   virtual void OnTick()
    01043   {
    01044     if (_pause_game != 0) return;
    01045
    01046     /* Update the company score every 5 days */
    01047     if (--this->timeout == 0) {
    01048       this->UpdateCompanyStats();
    01049       this->SetDirty();
    01050     }
    01051   }
    01052 };
    01053
    01054 CompanyID PerformanceRatingDetailWindow::company = INVALID_COMPANY;
    01055
    01056
    01057 static const Widget _performance_rating_detail_widgets[] = {
    01058 {   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_GREY,     0,    10,     0,    13, STR_00C5,               STR_018B_CLOSE_WINDOW},
    01059 {    WWT_CAPTION,   RESIZE_NONE,  COLOUR_GREY,    11,   298,     0,    13, STR_PERFORMANCE_DETAIL, STR_018C_WINDOW_TITLE_DRAG_THIS},
    01060 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   298,    14,    40, 0x0,                    STR_NULL},
    01061
    01062 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   298,    41,    60, 0x0,                    STR_PERFORMANCE_DETAIL_VEHICLES_TIP},
    01063 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   298,    61,    80, 0x0,                    STR_PERFORMANCE_DETAIL_STATIONS_TIP},
    01064 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   298,    81,   100, 0x0,                    STR_PERFORMANCE_DETAIL_MIN_PROFIT_TIP},
    01065 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   298,   101,   120, 0x0,                    STR_PERFORMANCE_DETAIL_MIN_INCOME_TIP},
    01066 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   298,   121,   140, 0x0,                    STR_PERFORMANCE_DETAIL_MAX_INCOME_TIP},
    01067 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   298,   141,   160, 0x0,                    STR_PERFORMANCE_DETAIL_DELIVERED_TIP},
    01068 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   298,   161,   180, 0x0,                    STR_PERFORMANCE_DETAIL_CARGO_TIP},
    01069 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   298,   181,   200, 0x0,                    STR_PERFORMANCE_DETAIL_MONEY_TIP},
    01070 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   298,   201,   220, 0x0,                    STR_PERFORMANCE_DETAIL_LOAN_TIP},
    01071 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   298,   221,   240, 0x0,                    STR_PERFORMANCE_DETAIL_TOTAL_TIP},
    01072
    01073 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,    38,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    01074 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,    39,    75,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    01075 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,    76,   112,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    01076 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,   113,   149,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    01077 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,   150,   186,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    01078 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,   187,   223,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    01079 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,   224,   260,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    01080 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,   261,   297,    14,    26, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    01081 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,    38,    27,    39, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    01082 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,    39,    75,    27,    39, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    01083 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,    76,   112,    27,    39, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    01084 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,   113,   149,    27,    39, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    01085 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,   150,   186,    27,    39, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    01086 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,   187,   223,    27,    39, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    01087 {      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,   224,   260,    27,    39, 0x0,                    STR_704F_CLICK_HERE_TO_TOGGLE_COMPANY},
    01088 {   WIDGETS_END},
    01089 };
    01090
    01091 static const WindowDesc _performance_rating_detail_desc(
    01092   WDP_AUTO, WDP_AUTO, 299, 241, 299, 241,
    01093   WC_PERFORMANCE_DETAIL, WC_NONE,
    01094   WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
    01095   _performance_rating_detail_widgets
    01096 );
    01097
    01098 void ShowPerformanceRatingDetail()
    01099 {
    01100   AllocateWindowDescFront<PerformanceRatingDetailWindow>(&_performance_rating_detail_desc, 0);
    01101 }