00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "openttd.h"
00014 #include "graph_gui.h"
00015 #include "window_gui.h"
00016 #include "company_base.h"
00017 #include "company_gui.h"
00018 #include "economy_func.h"
00019 #include "cargotype.h"
00020 #include "strings_func.h"
00021 #include "window_func.h"
00022 #include "date_func.h"
00023 #include "gfx_func.h"
00024 #include "sortlist_type.h"
00025 #include "core/geometry_func.hpp"
00026
00027 #include "table/strings.h"
00028 #include "table/sprites.h"
00029
00030
00031 static uint _legend_excluded_companies;
00032 static uint _legend_excluded_cargo;
00033
00034
00035 static const OverflowSafeInt64 INVALID_DATAPOINT(INT64_MAX);
00036 static const uint INVALID_DATAPOINT_POS = UINT_MAX;
00037
00038
00039
00040
00041
00043 enum GraphLegendWidgetNumbers {
00044 GLW_BACKGROUND,
00045
00046 GLW_FIRST_COMPANY,
00047 GLW_LAST_COMPANY = GLW_FIRST_COMPANY + MAX_COMPANIES - 1,
00048 };
00049
00050 struct GraphLegendWindow : Window {
00051 GraphLegendWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
00052 {
00053 this->InitNested(desc, window_number);
00054
00055 for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
00056 if (!HasBit(_legend_excluded_companies, c)) this->LowerWidget(c + GLW_FIRST_COMPANY);
00057
00058 this->OnInvalidateData(c);
00059 }
00060 }
00061
00062 virtual void OnPaint()
00063 {
00064 this->DrawWidgets();
00065 }
00066
00067 virtual void DrawWidget(const Rect &r, int widget) const
00068 {
00069 if (!IsInsideMM(widget, GLW_FIRST_COMPANY, MAX_COMPANIES + GLW_FIRST_COMPANY)) return;
00070
00071 CompanyID cid = (CompanyID)(widget - GLW_FIRST_COMPANY);
00072
00073 if (!Company::IsValidID(cid)) return;
00074
00075 bool rtl = _dynlang.text_dir == TD_RTL;
00076
00077 DrawCompanyIcon(cid, rtl ? r.right - 16 : r.left + 2, r.top + 2 + (FONT_HEIGHT_NORMAL - 10) / 2);
00078
00079 SetDParam(0, cid);
00080 SetDParam(1, cid);
00081 DrawString(r.left + (rtl ? WD_FRAMERECT_LEFT : 19), r.right - (rtl ? 19 : WD_FRAMERECT_RIGHT), r.top + WD_FRAMERECT_TOP, STR_COMPANY_NAME_COMPANY_NUM, HasBit(_legend_excluded_companies, cid) ? TC_BLACK : TC_WHITE);
00082 }
00083
00084 virtual void OnClick(Point pt, int widget, int click_count)
00085 {
00086 if (!IsInsideMM(widget, GLW_FIRST_COMPANY, MAX_COMPANIES + GLW_FIRST_COMPANY)) return;
00087
00088 ToggleBit(_legend_excluded_companies, widget - GLW_FIRST_COMPANY);
00089 this->ToggleWidgetLoweredState(widget);
00090 this->SetDirty();
00091 SetWindowDirty(WC_INCOME_GRAPH, 0);
00092 SetWindowDirty(WC_OPERATING_PROFIT, 0);
00093 SetWindowDirty(WC_DELIVERED_CARGO, 0);
00094 SetWindowDirty(WC_PERFORMANCE_HISTORY, 0);
00095 SetWindowDirty(WC_COMPANY_VALUE, 0);
00096 }
00097
00098 virtual void OnInvalidateData(int data)
00099 {
00100 if (Company::IsValidID(data)) return;
00101
00102 SetBit(_legend_excluded_companies, data);
00103 this->RaiseWidget(data + GLW_FIRST_COMPANY);
00104 }
00105 };
00106
00113 static NWidgetBase *MakeNWidgetCompanyLines(int *biggest_index)
00114 {
00115 NWidgetVertical *vert = new NWidgetVertical();
00116
00117 for (int widnum = GLW_FIRST_COMPANY; widnum <= GLW_LAST_COMPANY; widnum++) {
00118 NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, widnum);
00119 panel->SetMinimalSize(246, FONT_HEIGHT_NORMAL + WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM);
00120 panel->SetFill(1, 0);
00121 panel->SetDataTip(0x0, STR_GRAPH_KEY_COMPANY_SELECTION_TOOLTIP);
00122 vert->Add(panel);
00123 }
00124 *biggest_index = GLW_LAST_COMPANY;
00125 return vert;
00126 }
00127
00128 static const NWidgetPart _nested_graph_legend_widgets[] = {
00129 NWidget(NWID_HORIZONTAL),
00130 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00131 NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_GRAPH_KEY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00132 NWidget(WWT_SHADEBOX, COLOUR_GREY),
00133 NWidget(WWT_STICKYBOX, COLOUR_GREY),
00134 EndContainer(),
00135 NWidget(WWT_PANEL, COLOUR_GREY, GLW_BACKGROUND),
00136 NWidget(NWID_SPACER), SetMinimalSize(0, 2),
00137 NWidget(NWID_HORIZONTAL),
00138 NWidget(NWID_SPACER), SetMinimalSize(2, 0),
00139 NWidgetFunction(MakeNWidgetCompanyLines),
00140 NWidget(NWID_SPACER), SetMinimalSize(2, 0),
00141 EndContainer(),
00142 EndContainer(),
00143 };
00144
00145 static const WindowDesc _graph_legend_desc(
00146 WDP_AUTO, 0, 0,
00147 WC_GRAPH_LEGEND, WC_NONE,
00148 0,
00149 _nested_graph_legend_widgets, lengthof(_nested_graph_legend_widgets)
00150 );
00151
00152 static void ShowGraphLegend()
00153 {
00154 AllocateWindowDescFront<GraphLegendWindow>(&_graph_legend_desc, 0);
00155 }
00156
00157
00158
00159
00160
00162 enum CompanyValueWidgets {
00163 BGW_KEY_BUTTON,
00164 BGW_BACKGROUND,
00165 };
00166
00167 struct BaseGraphWindow : Window {
00168 protected:
00169 enum {
00170 GRAPH_MAX_DATASETS = 32,
00171 GRAPH_AXIS_LINE_COLOUR = 215,
00172 GRAPH_NUM_MONTHS = 24,
00173
00174 GRAPH_NUM_LINES_Y = 9,
00175
00176
00177
00178 };
00179
00180 uint excluded_data;
00181 byte num_dataset;
00182 byte num_on_x_axis;
00183 bool has_negative_values;
00184 byte num_vert_lines;
00185 static const TextColour graph_axis_label_colour = TC_BLACK;
00186
00187
00188
00189 byte month;
00190 Year year;
00191
00192
00193
00194 uint16 x_values_start;
00195 uint16 x_values_increment;
00196
00197 int graph_widget;
00198 StringID format_str_y_axis;
00199 byte colours[GRAPH_MAX_DATASETS];
00200 OverflowSafeInt64 cost[GRAPH_MAX_DATASETS][GRAPH_NUM_MONTHS];
00201
00202 int64 GetHighestValue(int initial_highest_value) const
00203 {
00204 OverflowSafeInt64 highest_value = initial_highest_value;
00205
00206 for (int i = 0; i < this->num_dataset; i++) {
00207 if (!HasBit(this->excluded_data, i)) {
00208 for (int j = 0; j < this->num_on_x_axis; j++) {
00209 OverflowSafeInt64 datapoint = this->cost[i][j];
00210
00211 if (datapoint != INVALID_DATAPOINT) {
00212
00213
00214
00215 highest_value = max(highest_value, abs(datapoint));
00216 }
00217 }
00218 }
00219 }
00220
00221
00222
00223 int round_val = highest_value % (GRAPH_NUM_LINES_Y - 1);
00224 if (round_val != 0) highest_value += (GRAPH_NUM_LINES_Y - 1 - round_val);
00225
00226 return highest_value;
00227 }
00228
00229 uint GetYLabelWidth(int64 highest_value) const
00230 {
00231
00232 int64 y_label = highest_value;
00233 int64 y_label_separation = highest_value / (GRAPH_NUM_LINES_Y - 1);
00234
00235
00236
00237 if (this->has_negative_values) y_label_separation *= 2;
00238
00239 uint max_width = 0;
00240
00241 for (int i = 0; i < GRAPH_NUM_LINES_Y; i++) {
00242 SetDParam(0, this->format_str_y_axis);
00243 SetDParam(1, y_label);
00244 Dimension d = GetStringBoundingBox(STR_GRAPH_Y_LABEL);
00245 if (d.width > max_width) max_width = d.width;
00246
00247 y_label -= y_label_separation;
00248 }
00249
00250 return max_width;
00251 }
00252
00257 void DrawGraph(Rect r) const
00258 {
00259 uint x, y;
00260 OverflowSafeInt64 highest_value;
00261 int x_axis_offset;
00262
00263
00264
00265 assert_compile(GRAPH_MAX_DATASETS >= (int)NUM_CARGO && GRAPH_MAX_DATASETS >= (int)MAX_COMPANIES);
00266 assert(this->num_vert_lines > 0);
00267
00268 byte grid_colour = _colour_gradient[COLOUR_GREY][4];
00269
00270
00271
00272 r.top += 5 + GetCharacterHeight(FS_SMALL) / 2;
00273 r.bottom -= (this->month == 0xFF ? 1 : 3) * GetCharacterHeight(FS_SMALL) + 4;
00274 r.left += 9;
00275 r.right -= 5;
00276
00277
00278
00279
00280
00281 highest_value = r.bottom - r.top + 1;
00282 if (!this->has_negative_values) highest_value *= 2;
00283 highest_value = GetHighestValue(highest_value);
00284
00285
00286 int label_width = GetYLabelWidth(highest_value);
00287
00288 r.left += label_width;
00289
00290 int x_sep = (r.right - r.left) / this->num_vert_lines;
00291 int y_sep = (r.bottom - r.top) / (GRAPH_NUM_LINES_Y - 1);
00292
00293
00294
00295 r.right = r.left + x_sep * this->num_vert_lines;
00296 r.bottom = r.top + y_sep * (GRAPH_NUM_LINES_Y - 1);
00297
00298
00299 x_axis_offset = r.bottom - r.top;
00300 if (this->has_negative_values) x_axis_offset /= 2;
00301
00302
00303
00304
00305 x = r.left + x_sep;
00306
00307 for (int i = 0; i < this->num_vert_lines; i++) {
00308 GfxFillRect(x, r.top, x, r.bottom, grid_colour);
00309 x += x_sep;
00310 }
00311
00312
00313 y = r.bottom;
00314
00315 for (int i = 0; i < GRAPH_NUM_LINES_Y; i++) {
00316 GfxFillRect(r.left - 3, y, r.left - 1, y, GRAPH_AXIS_LINE_COLOUR);
00317 GfxFillRect(r.left, y, r.right, y, grid_colour);
00318 y -= y_sep;
00319 }
00320
00321
00322 GfxFillRect(r.left, r.top, r.left, r.bottom, GRAPH_AXIS_LINE_COLOUR);
00323
00324
00325 y = x_axis_offset + r.top;
00326 GfxFillRect(r.left, y, r.right, y, GRAPH_AXIS_LINE_COLOUR);
00327
00328
00329 if (this->num_on_x_axis == 0)
00330 return;
00331
00332 assert(this->num_on_x_axis > 0);
00333 assert(this->num_dataset > 0);
00334
00335
00336 int64 y_label = highest_value;
00337 int64 y_label_separation = highest_value / (GRAPH_NUM_LINES_Y - 1);
00338
00339
00340
00341 if (this->has_negative_values) y_label_separation *= 2;
00342
00343 y = r.top - GetCharacterHeight(FS_SMALL) / 2;
00344
00345 for (int i = 0; i < GRAPH_NUM_LINES_Y; i++) {
00346 SetDParam(0, this->format_str_y_axis);
00347 SetDParam(1, y_label);
00348 DrawString(r.left - label_width - 4, r.left - 4, y, STR_GRAPH_Y_LABEL, graph_axis_label_colour, SA_RIGHT);
00349
00350 y_label -= y_label_separation;
00351 y += y_sep;
00352 }
00353
00354
00355 if (this->month != 0xFF) {
00356 x = r.left;
00357 y = r.bottom + 2;
00358 byte month = this->month;
00359 Year year = this->year;
00360 for (int i = 0; i < this->num_on_x_axis; i++) {
00361 SetDParam(0, month + STR_MONTH_ABBREV_JAN);
00362 SetDParam(1, month + STR_MONTH_ABBREV_JAN + 2);
00363 SetDParam(2, year);
00364 DrawStringMultiLine(x, x + x_sep, y, this->height, month == 0 ? STR_GRAPH_X_LABEL_MONTH_YEAR : STR_GRAPH_X_LABEL_MONTH, graph_axis_label_colour);
00365
00366 month += 3;
00367 if (month >= 12) {
00368 month = 0;
00369 year++;
00370 }
00371 x += x_sep;
00372 }
00373 } else {
00374
00375 x = r.left;
00376 y = r.bottom + 2;
00377 uint16 label = this->x_values_start;
00378
00379 for (int i = 0; i < this->num_on_x_axis; i++) {
00380 SetDParam(0, label);
00381 DrawString(x + 1, x + x_sep - 1, y, STR_GRAPH_Y_LABEL_NUMBER, graph_axis_label_colour, SA_CENTER);
00382
00383 label += this->x_values_increment;
00384 x += x_sep;
00385 }
00386 }
00387
00388
00389 for (int i = 0; i < this->num_dataset; i++) {
00390 if (!HasBit(this->excluded_data, i)) {
00391
00392 x = r.left + (x_sep / 2);
00393
00394 byte colour = this->colours[i];
00395 uint prev_x = INVALID_DATAPOINT_POS;
00396 uint prev_y = INVALID_DATAPOINT_POS;
00397
00398 for (int j = 0; j < this->num_on_x_axis; j++) {
00399 OverflowSafeInt64 datapoint = this->cost[i][j];
00400
00401 if (datapoint != INVALID_DATAPOINT) {
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413 int mult_range = FindLastBit(x_axis_offset) + FindLastBit(abs(datapoint));
00414 int reduce_range = max(mult_range - 31, 0);
00415
00416
00417 if (datapoint < 0) {
00418 datapoint = -(abs(datapoint) >> reduce_range);
00419 } else {
00420 datapoint >>= reduce_range;
00421 }
00422
00423 y = r.top + x_axis_offset - (x_axis_offset * datapoint) / (highest_value >> reduce_range);
00424
00425
00426 GfxFillRect(x - 1, y - 1, x + 1, y + 1, colour);
00427
00428
00429 if (prev_x != INVALID_DATAPOINT_POS) GfxDrawLine(prev_x, prev_y, x, y, colour);
00430
00431 prev_x = x;
00432 prev_y = y;
00433 } else {
00434 prev_x = INVALID_DATAPOINT_POS;
00435 prev_y = INVALID_DATAPOINT_POS;
00436 }
00437
00438 x += x_sep;
00439 }
00440 }
00441 }
00442 }
00443
00444
00445 BaseGraphWindow(int widget, bool has_negative_values, StringID format_str_y_axis) :
00446 Window(), has_negative_values(has_negative_values),
00447 format_str_y_axis(format_str_y_axis)
00448 {
00449 SetWindowDirty(WC_GRAPH_LEGEND, 0);
00450 this->num_vert_lines = 24;
00451 this->graph_widget = widget;
00452 }
00453
00454 void InitializeWindow(const WindowDesc *desc, WindowNumber number)
00455 {
00456
00457 this->UpdateStatistics(true);
00458
00459 this->InitNested(desc, number);
00460 }
00461
00462 public:
00463 virtual void OnPaint()
00464 {
00465 this->DrawWidgets();
00466 }
00467
00468 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00469 {
00470 if (widget != this->graph_widget) return;
00471
00472 uint x_label_width = 0;
00473
00474 if (this->month != 0xFF) {
00475 byte month = this->month;
00476 Year year = this->year;
00477 for (int i = 0; i < this->num_on_x_axis; i++) {
00478 SetDParam(0, month + STR_MONTH_ABBREV_JAN);
00479 SetDParam(1, month + STR_MONTH_ABBREV_JAN + 2);
00480 SetDParam(2, year);
00481 x_label_width = max(x_label_width, GetStringBoundingBox(month == 0 ? STR_GRAPH_X_LABEL_MONTH_YEAR : STR_GRAPH_X_LABEL_MONTH).width);
00482
00483 month += 3;
00484 if (month >= 12) {
00485 month = 0;
00486 year++;
00487 }
00488 }
00489 } else {
00490
00491 SetDParam(0, this->x_values_start + this->num_on_x_axis * this->x_values_increment);
00492 x_label_width = GetStringBoundingBox(STR_GRAPH_Y_LABEL_NUMBER).width;
00493 }
00494
00495 SetDParam(0, this->format_str_y_axis);
00496 SetDParam(1, INT64_MAX);
00497 uint y_label_width = GetStringBoundingBox(STR_GRAPH_Y_LABEL).width;
00498
00499 size->width = max<uint>(size->width, 5 + y_label_width + this->num_on_x_axis * (x_label_width + 5) + 9);
00500 size->height = max<uint>(size->height, 5 + (1 + GRAPH_NUM_LINES_Y * 2 + (this->month != 0xFF ? 3 : 1)) * FONT_HEIGHT_SMALL + 4);
00501 size->height = max<uint>(size->height, size->width / 3);
00502 }
00503
00504 virtual void DrawWidget(const Rect &r, int widget) const
00505 {
00506 if (widget != this->graph_widget) return;
00507
00508 DrawGraph(r);
00509 }
00510
00511 virtual OverflowSafeInt64 GetGraphData(const Company *c, int j)
00512 {
00513 return INVALID_DATAPOINT;
00514 }
00515
00516 virtual void OnClick(Point pt, int widget, int click_count)
00517 {
00518
00519 if (widget == BGW_KEY_BUTTON) ShowGraphLegend();
00520 }
00521
00522 virtual void OnTick()
00523 {
00524 this->UpdateStatistics(false);
00525 }
00526
00531 void UpdateStatistics(bool initialize)
00532 {
00533 uint excluded_companies = _legend_excluded_companies;
00534
00535
00536 for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
00537 if (!Company::IsValidID(c)) SetBit(excluded_companies, c);
00538 }
00539
00540 byte nums = 0;
00541 const Company *c;
00542 FOR_ALL_COMPANIES(c) {
00543 nums = min(this->num_vert_lines, max(nums, c->num_valid_stat_ent));
00544 }
00545
00546 int mo = (_cur_month / 3 - nums) * 3;
00547 int yr = _cur_year;
00548 while (mo < 0) {
00549 yr--;
00550 mo += 12;
00551 }
00552
00553 if (!initialize && this->excluded_data == excluded_companies && this->num_on_x_axis == nums &&
00554 this->year == yr && this->month == mo) {
00555
00556 return;
00557 }
00558
00559 this->excluded_data = excluded_companies;
00560 this->num_on_x_axis = nums;
00561 this->year = yr;
00562 this->month = mo;
00563
00564 int numd = 0;
00565 for (CompanyID k = COMPANY_FIRST; k < MAX_COMPANIES; k++) {
00566 c = Company::GetIfValid(k);
00567 if (c != NULL) {
00568 this->colours[numd] = _colour_gradient[c->colour][6];
00569 for (int j = this->num_on_x_axis, i = 0; --j >= 0;) {
00570 this->cost[numd][i] = (j >= c->num_valid_stat_ent) ? INVALID_DATAPOINT : GetGraphData(c, j);
00571 i++;
00572 }
00573 }
00574 numd++;
00575 }
00576
00577 this->num_dataset = numd;
00578 }
00579 };
00580
00581
00582
00583
00584
00585
00586 struct OperatingProfitGraphWindow : BaseGraphWindow {
00587 OperatingProfitGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
00588 BaseGraphWindow(BGW_BACKGROUND, true, STR_JUST_CURRCOMPACT)
00589 {
00590 this->InitializeWindow(desc, window_number);
00591 }
00592
00593 virtual OverflowSafeInt64 GetGraphData(const Company *c, int j)
00594 {
00595 return c->old_economy[j].income + c->old_economy[j].expenses;
00596 }
00597 };
00598
00599 static const NWidgetPart _nested_operating_profit_widgets[] = {
00600 NWidget(NWID_HORIZONTAL),
00601 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00602 NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_GRAPH_OPERATING_PROFIT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00603 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, BGW_KEY_BUTTON), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP),
00604 NWidget(WWT_SHADEBOX, COLOUR_GREY),
00605 NWidget(WWT_STICKYBOX, COLOUR_GREY),
00606 EndContainer(),
00607 NWidget(WWT_PANEL, COLOUR_GREY, BGW_BACKGROUND), SetMinimalSize(576, 160), EndContainer(),
00608 };
00609
00610 static const WindowDesc _operating_profit_desc(
00611 WDP_AUTO, 0, 0,
00612 WC_OPERATING_PROFIT, WC_NONE,
00613 WDF_UNCLICK_BUTTONS,
00614 _nested_operating_profit_widgets, lengthof(_nested_operating_profit_widgets)
00615 );
00616
00617
00618 void ShowOperatingProfitGraph()
00619 {
00620 AllocateWindowDescFront<OperatingProfitGraphWindow>(&_operating_profit_desc, 0);
00621 }
00622
00623
00624
00625
00626
00627
00628 struct IncomeGraphWindow : BaseGraphWindow {
00629 IncomeGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
00630 BaseGraphWindow(BGW_BACKGROUND, false, STR_JUST_CURRCOMPACT)
00631 {
00632 this->InitializeWindow(desc, window_number);
00633 }
00634
00635 virtual OverflowSafeInt64 GetGraphData(const Company *c, int j)
00636 {
00637 return c->old_economy[j].income;
00638 }
00639 };
00640
00641 static const NWidgetPart _nested_income_graph_widgets[] = {
00642 NWidget(NWID_HORIZONTAL),
00643 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00644 NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_GRAPH_INCOME_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00645 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, BGW_KEY_BUTTON), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP),
00646 NWidget(WWT_SHADEBOX, COLOUR_GREY),
00647 NWidget(WWT_STICKYBOX, COLOUR_GREY),
00648 EndContainer(),
00649 NWidget(WWT_PANEL, COLOUR_GREY, BGW_BACKGROUND), SetMinimalSize(576, 128), EndContainer(),
00650 };
00651
00652
00653 static const WindowDesc _income_graph_desc(
00654 WDP_AUTO, 0, 0,
00655 WC_INCOME_GRAPH, WC_NONE,
00656 WDF_UNCLICK_BUTTONS,
00657 _nested_income_graph_widgets, lengthof(_nested_income_graph_widgets)
00658 );
00659
00660 void ShowIncomeGraph()
00661 {
00662 AllocateWindowDescFront<IncomeGraphWindow>(&_income_graph_desc, 0);
00663 }
00664
00665
00666
00667
00668
00669 struct DeliveredCargoGraphWindow : BaseGraphWindow {
00670 DeliveredCargoGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
00671 BaseGraphWindow(BGW_BACKGROUND, false, STR_JUST_COMMA)
00672 {
00673 this->InitializeWindow(desc, window_number);
00674 }
00675
00676 virtual OverflowSafeInt64 GetGraphData(const Company *c, int j)
00677 {
00678 return c->old_economy[j].delivered_cargo;
00679 }
00680 };
00681
00682 static const NWidgetPart _nested_delivered_cargo_graph_widgets[] = {
00683 NWidget(NWID_HORIZONTAL),
00684 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00685 NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_GRAPH_CARGO_DELIVERED_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00686 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, BGW_KEY_BUTTON), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP),
00687 NWidget(WWT_SHADEBOX, COLOUR_GREY),
00688 NWidget(WWT_STICKYBOX, COLOUR_GREY),
00689 EndContainer(),
00690 NWidget(WWT_PANEL, COLOUR_GREY, BGW_BACKGROUND), SetMinimalSize(576, 128), EndContainer(),
00691 };
00692
00693 static const WindowDesc _delivered_cargo_graph_desc(
00694 WDP_AUTO, 0, 0,
00695 WC_DELIVERED_CARGO, WC_NONE,
00696 WDF_UNCLICK_BUTTONS,
00697 _nested_delivered_cargo_graph_widgets, lengthof(_nested_delivered_cargo_graph_widgets)
00698 );
00699
00700 void ShowDeliveredCargoGraph()
00701 {
00702 AllocateWindowDescFront<DeliveredCargoGraphWindow>(&_delivered_cargo_graph_desc, 0);
00703 }
00704
00705
00706
00707
00708
00710 enum PerformanceHistoryGraphWidgets {
00711 PHW_KEY,
00712 PHW_DETAILED_PERFORMANCE,
00713 PHW_BACKGROUND,
00714 };
00715
00716 struct PerformanceHistoryGraphWindow : BaseGraphWindow {
00717 PerformanceHistoryGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
00718 BaseGraphWindow(PHW_BACKGROUND, false, STR_JUST_COMMA)
00719 {
00720 this->InitializeWindow(desc, window_number);
00721 }
00722
00723 virtual OverflowSafeInt64 GetGraphData(const Company *c, int j)
00724 {
00725 return c->old_economy[j].performance_history;
00726 }
00727
00728 virtual void OnClick(Point pt, int widget, int click_count)
00729 {
00730 if (widget == PHW_DETAILED_PERFORMANCE) ShowPerformanceRatingDetail();
00731 this->BaseGraphWindow::OnClick(pt, widget, click_count);
00732 }
00733 };
00734
00735 static const NWidgetPart _nested_performance_history_widgets[] = {
00736 NWidget(NWID_HORIZONTAL),
00737 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00738 NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_GRAPH_COMPANY_PERFORMANCE_RATINGS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00739 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, PHW_DETAILED_PERFORMANCE), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_PERFORMANCE_DETAIL_KEY, STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP),
00740 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, PHW_KEY), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP),
00741 NWidget(WWT_SHADEBOX, COLOUR_GREY),
00742 NWidget(WWT_STICKYBOX, COLOUR_GREY),
00743 EndContainer(),
00744 NWidget(WWT_PANEL, COLOUR_GREY, PHW_BACKGROUND), SetMinimalSize(576, 224), EndContainer(),
00745 };
00746
00747 static const WindowDesc _performance_history_desc(
00748 WDP_AUTO, 0, 0,
00749 WC_PERFORMANCE_HISTORY, WC_NONE,
00750 WDF_UNCLICK_BUTTONS,
00751 _nested_performance_history_widgets, lengthof(_nested_performance_history_widgets)
00752 );
00753
00754 void ShowPerformanceHistoryGraph()
00755 {
00756 AllocateWindowDescFront<PerformanceHistoryGraphWindow>(&_performance_history_desc, 0);
00757 }
00758
00759
00760
00761
00762
00763 struct CompanyValueGraphWindow : BaseGraphWindow {
00764 CompanyValueGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
00765 BaseGraphWindow(BGW_BACKGROUND, false, STR_JUST_CURRCOMPACT)
00766 {
00767 this->InitializeWindow(desc, window_number);
00768 }
00769
00770 virtual OverflowSafeInt64 GetGraphData(const Company *c, int j)
00771 {
00772 return c->old_economy[j].company_value;
00773 }
00774 };
00775
00776 static const NWidgetPart _nested_company_value_graph_widgets[] = {
00777 NWidget(NWID_HORIZONTAL),
00778 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00779 NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_GRAPH_COMPANY_VALUES_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00780 NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, BGW_KEY_BUTTON), SetMinimalSize(50, 0), SetMinimalTextLines(1, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 2), SetDataTip(STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP),
00781 NWidget(WWT_SHADEBOX, COLOUR_GREY),
00782 NWidget(WWT_STICKYBOX, COLOUR_GREY),
00783 EndContainer(),
00784 NWidget(WWT_PANEL, COLOUR_GREY, BGW_BACKGROUND), SetMinimalSize(576, 224), EndContainer(),
00785 };
00786
00787 static const WindowDesc _company_value_graph_desc(
00788 WDP_AUTO, 0, 0,
00789 WC_COMPANY_VALUE, WC_NONE,
00790 WDF_UNCLICK_BUTTONS,
00791 _nested_company_value_graph_widgets, lengthof(_nested_company_value_graph_widgets)
00792 );
00793
00794 void ShowCompanyValueGraph()
00795 {
00796 AllocateWindowDescFront<CompanyValueGraphWindow>(&_company_value_graph_desc, 0);
00797 }
00798
00799
00800
00801
00802
00804 enum CargoPaymentRatesWidgets {
00805 CPW_BACKGROUND,
00806 CPW_HEADER,
00807 CPW_GRAPH,
00808 CPW_FOOTER,
00809 CPW_CARGO_FIRST,
00810 };
00811
00812 struct PaymentRatesGraphWindow : BaseGraphWindow {
00813 PaymentRatesGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
00814 BaseGraphWindow(CPW_GRAPH, false, STR_JUST_CURRCOMPACT)
00815 {
00816 this->num_on_x_axis = 20;
00817 this->num_vert_lines = 20;
00818 this->month = 0xFF;
00819 this->x_values_start = 10;
00820 this->x_values_increment = 10;
00821
00822
00823 this->OnHundredthTick();
00824
00825 this->InitNested(desc, window_number);
00826
00827 int i = 0;
00828 const CargoSpec *cs;
00829 FOR_ALL_CARGOSPECS(cs) {
00830 this->SetWidgetLoweredState(CPW_CARGO_FIRST + cs->Index(), !HasBit(_legend_excluded_cargo, i));
00831 i++;
00832 }
00833 }
00834
00835 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00836 {
00837 if (widget < CPW_CARGO_FIRST) {
00838 BaseGraphWindow::UpdateWidgetSize(widget, size, padding, fill, resize);
00839 return;
00840 }
00841
00842 const CargoSpec *cs = CargoSpec::Get(widget - CPW_CARGO_FIRST);
00843 SetDParam(0, cs->name);
00844 Dimension d = GetStringBoundingBox(STR_GRAPH_CARGO_PAYMENT_CARGO);
00845 d.width += 14;
00846 d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT;
00847 d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM;
00848 *size = maxdim(d, *size);
00849 }
00850
00851 virtual void DrawWidget(const Rect &r, int widget) const
00852 {
00853 if (widget < CPW_CARGO_FIRST) {
00854 BaseGraphWindow::DrawWidget(r, widget);
00855 return;
00856 }
00857
00858 const CargoSpec *cs = CargoSpec::Get(widget - CPW_CARGO_FIRST);
00859 bool rtl = _dynlang.text_dir == TD_RTL;
00860
00861
00862
00863
00864
00865 byte clk_dif = this->IsWidgetLowered(widget) ? 1 : 0;
00866 int x = r.left + WD_FRAMERECT_LEFT;
00867 int y = r.top;
00868
00869 int rect_x = clk_dif + (rtl ? r.right - 12 : r.left + WD_FRAMERECT_LEFT);
00870
00871 GfxFillRect(rect_x, y + clk_dif, rect_x + 8, y + 5 + clk_dif, 0);
00872 GfxFillRect(rect_x + 1, y + 1 + clk_dif, rect_x + 7, y + 4 + clk_dif, cs->legend_colour);
00873 SetDParam(0, cs->name);
00874 DrawString(rtl ? r.left : x + 14 + clk_dif, (rtl ? r.right - 14 + clk_dif : r.right), y + clk_dif, STR_GRAPH_CARGO_PAYMENT_CARGO);
00875 }
00876
00877 virtual void OnClick(Point pt, int widget, int click_count)
00878 {
00879 if (widget >= CPW_CARGO_FIRST) {
00880 int i = 0;
00881 const CargoSpec *cs;
00882 FOR_ALL_CARGOSPECS(cs) {
00883 if (cs->Index() + CPW_CARGO_FIRST == widget) break;
00884 i++;
00885 }
00886
00887 ToggleBit(_legend_excluded_cargo, i);
00888 this->ToggleWidgetLoweredState(widget);
00889 this->excluded_data = _legend_excluded_cargo;
00890 this->SetDirty();
00891 }
00892 }
00893
00894 virtual void OnTick()
00895 {
00896
00897 }
00898
00899 virtual void OnHundredthTick()
00900 {
00901 this->excluded_data = _legend_excluded_cargo;
00902
00903 int i = 0;
00904 const CargoSpec *cs;
00905 FOR_ALL_CARGOSPECS(cs) {
00906 this->colours[i] = cs->legend_colour;
00907 for (uint j = 0; j != 20; j++) {
00908 this->cost[i][j] = GetTransportedGoodsIncome(10, 20, j * 4 + 4, cs->Index());
00909 }
00910
00911 i++;
00912 }
00913 this->num_dataset = i;
00914 }
00915 };
00916
00918 static NWidgetBase *MakeCargoButtons(int *biggest_index)
00919 {
00920 NWidgetVertical *ver = new NWidgetVertical;
00921
00922 const CargoSpec *cs;
00923 FOR_ALL_CARGOSPECS(cs) {
00924 *biggest_index = CPW_CARGO_FIRST + cs->Index();
00925 NWidgetBackground *leaf = new NWidgetBackground(WWT_PANEL, COLOUR_ORANGE, *biggest_index, NULL);
00926 leaf->tool_tip = STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO;
00927 leaf->SetFill(1, 0);
00928 leaf->SetLowered(true);
00929 ver->Add(leaf);
00930 }
00931 return ver;
00932 }
00933
00934
00935 static const NWidgetPart _nested_cargo_payment_rates_widgets[] = {
00936 NWidget(NWID_HORIZONTAL),
00937 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
00938 NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_GRAPH_CARGO_PAYMENT_RATES_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00939 NWidget(WWT_SHADEBOX, COLOUR_GREY),
00940 NWidget(WWT_STICKYBOX, COLOUR_GREY),
00941 EndContainer(),
00942 NWidget(WWT_PANEL, COLOUR_GREY, CPW_BACKGROUND), SetMinimalSize(568, 128), SetResize(0, 1),
00943 NWidget(NWID_VERTICAL),
00944 NWidget(NWID_HORIZONTAL),
00945 NWidget(NWID_SPACER), SetFill(1, 0),
00946 NWidget(WWT_TEXT, COLOUR_GREY, CPW_HEADER), SetMinimalSize(0, 6), SetPadding(2, 0, 2, 0), SetDataTip(STR_GRAPH_CARGO_PAYMENT_RATES_TITLE, STR_NULL),
00947 NWidget(NWID_SPACER), SetFill(1, 0),
00948 EndContainer(),
00949 NWidget(NWID_HORIZONTAL),
00950 NWidget(WWT_EMPTY, COLOUR_GREY, CPW_GRAPH), SetMinimalSize(495, 0), SetFill(1, 1),
00951 NWidget(NWID_VERTICAL),
00952 NWidget(NWID_SPACER), SetMinimalSize(0, 24), SetFill(0, 0),
00953 NWidgetFunction(MakeCargoButtons),
00954 NWidget(NWID_SPACER), SetMinimalSize(0, 24), SetFill(0, 1),
00955 EndContainer(),
00956 NWidget(NWID_SPACER), SetMinimalSize(5, 0), SetFill(0, 1),
00957 EndContainer(),
00958 NWidget(NWID_HORIZONTAL),
00959 NWidget(NWID_SPACER), SetFill(1, 0),
00960 NWidget(WWT_TEXT, COLOUR_GREY, CPW_FOOTER), SetMinimalSize(0, 6), SetPadding(2, 0, 2, 0), SetDataTip(STR_GRAPH_CARGO_PAYMENT_RATES_X_LABEL, STR_NULL),
00961 NWidget(NWID_SPACER), SetFill(1, 0),
00962 EndContainer(),
00963 EndContainer(),
00964 EndContainer(),
00965 };
00966
00967 static const WindowDesc _cargo_payment_rates_desc(
00968 WDP_AUTO, 0, 0,
00969 WC_PAYMENT_RATES, WC_NONE,
00970 0,
00971 _nested_cargo_payment_rates_widgets, lengthof(_nested_cargo_payment_rates_widgets)
00972 );
00973
00974
00975 void ShowCargoPaymentRates()
00976 {
00977 AllocateWindowDescFront<PaymentRatesGraphWindow>(&_cargo_payment_rates_desc, 0);
00978 }
00979
00980
00981
00982
00983
00985 enum CompanyLeagueWidgets {
00986 CLW_BACKGROUND,
00987 };
00988
00989 static const StringID _performance_titles[] = {
00990 STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ENGINEER,
00991 STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ENGINEER,
00992 STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRAFFIC_MANAGER,
00993 STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRAFFIC_MANAGER,
00994 STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRANSPORT_COORDINATOR,
00995 STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TRANSPORT_COORDINATOR,
00996 STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ROUTE_SUPERVISOR,
00997 STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_ROUTE_SUPERVISOR,
00998 STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_DIRECTOR,
00999 STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_DIRECTOR,
01000 STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHIEF_EXECUTIVE,
01001 STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHIEF_EXECUTIVE,
01002 STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHAIRMAN,
01003 STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_CHAIRMAN,
01004 STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_PRESIDENT,
01005 STR_COMPANY_LEAGUE_PERFORMANCE_TITLE_TYCOON,
01006 };
01007
01008 static inline StringID GetPerformanceTitleFromValue(uint value)
01009 {
01010 return _performance_titles[minu(value, 1000) >> 6];
01011 }
01012
01013 class CompanyLeagueWindow : public Window {
01014 private:
01015 GUIList<const Company*> companies;
01016 uint ordinal_width;
01017 uint text_width;
01018
01022 void BuildCompanyList()
01023 {
01024 if (!this->companies.NeedRebuild()) return;
01025
01026 this->companies.Clear();
01027
01028 const Company *c;
01029 FOR_ALL_COMPANIES(c) {
01030 *this->companies.Append() = c;
01031 }
01032
01033 this->companies.Compact();
01034 this->companies.RebuildDone();
01035 }
01036
01038 static int CDECL PerformanceSorter(const Company * const *c1, const Company * const *c2)
01039 {
01040 return (*c2)->old_economy[1].performance_history - (*c1)->old_economy[1].performance_history;
01041 }
01042
01043 public:
01044 CompanyLeagueWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
01045 {
01046 this->InitNested(desc, window_number);
01047 this->companies.ForceRebuild();
01048 this->companies.NeedResort();
01049 }
01050
01051 virtual void OnPaint()
01052 {
01053 this->BuildCompanyList();
01054 this->companies.Sort(&PerformanceSorter);
01055
01056 this->DrawWidgets();
01057 }
01058
01059 virtual void DrawWidget(const Rect &r, int widget) const
01060 {
01061 if (widget != CLW_BACKGROUND) return;
01062
01063 uint y = r.top + WD_FRAMERECT_TOP;
01064 int icon_y_offset = 1 + (FONT_HEIGHT_NORMAL - 10) / 2;
01065
01066 bool rtl = _dynlang.text_dir == TD_RTL;
01067 uint ordinal_left = rtl ? r.right - WD_FRAMERECT_LEFT - this->ordinal_width : r.left + WD_FRAMERECT_LEFT;
01068 uint ordinal_right = rtl ? r.right - WD_FRAMERECT_LEFT : r.left + WD_FRAMERECT_LEFT + this->ordinal_width;
01069 uint icon_left = r.left + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT + (rtl ? this->text_width : this->ordinal_width);
01070 uint text_left = rtl ? r.left + WD_FRAMERECT_LEFT : r.right - WD_FRAMERECT_LEFT - this->text_width;
01071 uint text_right = rtl ? r.left + WD_FRAMERECT_LEFT + this->text_width : r.right - WD_FRAMERECT_LEFT;
01072
01073 for (uint i = 0; i != this->companies.Length(); i++) {
01074 const Company *c = this->companies[i];
01075 DrawString(ordinal_left, ordinal_right, y, i + STR_ORDINAL_NUMBER_1ST, i == 0 ? TC_WHITE : TC_YELLOW);
01076
01077 DrawCompanyIcon(c->index, icon_left, y + icon_y_offset);
01078
01079 SetDParam(0, c->index);
01080 SetDParam(1, c->index);
01081 SetDParam(2, GetPerformanceTitleFromValue(c->old_economy[1].performance_history));
01082 DrawString(text_left, text_right, y, STR_COMPANY_LEAGUE_COMPANY_NAME);
01083 y += FONT_HEIGHT_NORMAL;
01084 }
01085 }
01086
01087 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
01088 {
01089 if (widget != CLW_BACKGROUND) return;
01090
01091 this->ordinal_width = 0;
01092 for (uint i = 0; i < MAX_COMPANIES; i++) {
01093 this->ordinal_width = max(this->ordinal_width, GetStringBoundingBox(STR_ORDINAL_NUMBER_1ST + i).width);
01094 }
01095 this->ordinal_width += 5;
01096
01097 uint widest_width = 0;
01098 uint widest_title = 0;
01099 for (uint i = 0; i < lengthof(_performance_titles); i++) {
01100 uint width = GetStringBoundingBox(_performance_titles[i]).width;
01101 if (width > widest_width) {
01102 widest_title = i;
01103 widest_width = width;
01104 }
01105 }
01106
01107 const Company *c;
01108 FOR_ALL_COMPANIES(c) {
01109 SetDParam(0, c->index);
01110 SetDParam(1, c->index);
01111 SetDParam(2, _performance_titles[widest_title]);
01112 widest_width = max(widest_width, GetStringBoundingBox(STR_COMPANY_LEAGUE_COMPANY_NAME).width);
01113 }
01114
01115 this->text_width = widest_width + 30;
01116
01117 size->width = WD_FRAMERECT_LEFT + this->ordinal_width + WD_FRAMERECT_RIGHT + 16 + WD_FRAMERECT_LEFT + this->text_width + WD_FRAMERECT_RIGHT;
01118 }
01119
01120
01121 virtual void OnTick()
01122 {
01123 if (this->companies.NeedResort()) {
01124 this->SetDirty();
01125 }
01126 }
01127
01128 virtual void OnInvalidateData(int data)
01129 {
01130 if (data == 0) {
01131 this->companies.ForceRebuild();
01132 } else {
01133 this->companies.ForceResort();
01134 }
01135 }
01136 };
01137
01138 static const NWidgetPart _nested_company_league_widgets[] = {
01139 NWidget(NWID_HORIZONTAL),
01140 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
01141 NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_COMPANY_LEAGUE_TABLE_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01142 NWidget(WWT_SHADEBOX, COLOUR_GREY),
01143 NWidget(WWT_STICKYBOX, COLOUR_GREY),
01144 EndContainer(),
01145 NWidget(WWT_PANEL, COLOUR_GREY, CLW_BACKGROUND), SetMinimalSize(400, 0), SetMinimalTextLines(15, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM),
01146 };
01147
01148 static const WindowDesc _company_league_desc(
01149 WDP_AUTO, 0, 0,
01150 WC_COMPANY_LEAGUE, WC_NONE,
01151 0,
01152 _nested_company_league_widgets, lengthof(_nested_company_league_widgets)
01153 );
01154
01155 void ShowCompanyLeagueTable()
01156 {
01157 AllocateWindowDescFront<CompanyLeagueWindow>(&_company_league_desc, 0);
01158 }
01159
01160
01161
01162
01163
01165 enum PerformanceRatingDetailsWidgets {
01166 PRW_SCORE_FIRST,
01167 PRW_SCORE_LAST = PRW_SCORE_FIRST + (SCORE_END - SCORE_BEGIN) - 1,
01168
01169 PRW_COMPANY_FIRST,
01170 PRW_COMPANY_LAST = PRW_COMPANY_FIRST + MAX_COMPANIES - 1,
01171 };
01172
01173 struct PerformanceRatingDetailWindow : Window {
01174 static CompanyID company;
01175 int timeout;
01176
01177 PerformanceRatingDetailWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
01178 {
01179 this->UpdateCompanyStats();
01180
01181 this->InitNested(desc, window_number);
01182 this->OnInvalidateData(INVALID_COMPANY);
01183 }
01184
01185 void UpdateCompanyStats()
01186 {
01187
01188
01189 Company *c;
01190 FOR_ALL_COMPANIES(c) {
01191 UpdateCompanyRatingAndValue(c, false);
01192 }
01193
01194 this->timeout = DAY_TICKS * 5;
01195 }
01196
01197 uint score_info_left;
01198 uint score_info_right;
01199 uint bar_left;
01200 uint bar_right;
01201 uint bar_width;
01202 uint bar_height;
01203 uint score_detail_left;
01204 uint score_detail_right;
01205
01206 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
01207 {
01208 switch (widget) {
01209 case PRW_SCORE_FIRST:
01210 this->bar_height = FONT_HEIGHT_NORMAL + 4;
01211 size->height = this->bar_height + 2 * WD_MATRIX_TOP;
01212
01213 uint score_info_width = 0;
01214 for (uint i = SCORE_BEGIN; i < SCORE_END; i++) {
01215 score_info_width = max(score_info_width, GetStringBoundingBox(STR_PERFORMANCE_DETAIL_VEHICLES + i).width);
01216 }
01217 SetDParam(0, 1000);
01218 score_info_width += GetStringBoundingBox(STR_BLACK_COMMA).width + WD_FRAMERECT_LEFT;
01219
01220 SetDParam(0, 100);
01221 this->bar_width = GetStringBoundingBox(STR_PERFORMANCE_DETAIL_PERCENT).width + 20;
01222
01223
01224
01225
01226 uint max = 999999999;
01227 SetDParam(0, max);
01228 SetDParam(1, max);
01229 uint score_detail_width = GetStringBoundingBox(STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY).width;
01230
01231 size->width = 7 + score_info_width + 5 + this->bar_width + 5 + score_detail_width + 7;
01232 uint left = 7;
01233 uint right = size->width - 7;
01234
01235 bool rtl = _dynlang.text_dir == TD_RTL;
01236 this->score_info_left = rtl ? right - score_info_width : left;
01237 this->score_info_right = rtl ? right : left + score_info_width;
01238
01239 this->score_detail_left = rtl ? left : right - score_detail_width;
01240 this->score_detail_right = rtl ? left + score_detail_width : right;
01241
01242 this->bar_left = left + (rtl ? score_detail_width : score_info_width) + 5;
01243 this->bar_right = this->bar_left + this->bar_width;
01244 break;
01245 }
01246 }
01247
01248 virtual void OnPaint()
01249 {
01250
01251 this->DrawWidgets();
01252 }
01253
01254 virtual void DrawWidget(const Rect &r, int widget) const
01255 {
01256
01257 if (this->company == INVALID_COMPANY) return;
01258
01259 if (IsInsideMM(widget, PRW_COMPANY_FIRST, PRW_COMPANY_LAST + 1)) {
01260 if (this->IsWidgetDisabled(widget)) return;
01261 CompanyID cid = (CompanyID)(widget - PRW_COMPANY_FIRST);
01262 int offset = (cid == this->company) ? 1 : 0;
01263 Dimension sprite_size = GetSpriteSize(SPR_COMPANY_ICON);
01264 DrawCompanyIcon(cid, (r.left + r.right - sprite_size.width) / 2 + offset, (r.top + r.bottom - sprite_size.height) / 2 + offset);
01265 return;
01266 }
01267
01268 if (!IsInsideMM(widget, PRW_SCORE_FIRST, PRW_SCORE_LAST + 1)) return;
01269
01270 ScoreID score_type = (ScoreID)(widget - PRW_SCORE_FIRST);
01271
01272
01273 int colour_done = _colour_gradient[COLOUR_GREEN][4];
01274 int colour_notdone = _colour_gradient[COLOUR_RED][4];
01275
01276
01277 int val = _score_part[company][score_type];
01278 int needed = _score_info[score_type].needed;
01279 int score = _score_info[score_type].score;
01280
01281
01282 if (score_type == SCORE_TOTAL) {
01283 for (ScoreID i = SCORE_BEGIN; i < SCORE_END; i++) score += _score_info[i].score;
01284 needed = SCORE_MAX;
01285 }
01286
01287 uint bar_top = r.top + WD_MATRIX_TOP;
01288 uint text_top = bar_top + 2;
01289
01290 DrawString(this->score_info_left, this->score_info_right, text_top, STR_PERFORMANCE_DETAIL_VEHICLES + score_type);
01291
01292
01293 SetDParam(0, score);
01294 DrawString(this->score_info_left, this->score_info_right, text_top, STR_BLACK_COMMA, TC_FROMSTRING, SA_RIGHT);
01295
01296
01297 uint x = Clamp(val, 0, needed) * this->bar_width / needed;
01298 bool rtl = _dynlang.text_dir == TD_RTL;
01299 if (rtl) {
01300 x = this->bar_right - x;
01301 } else {
01302 x = this->bar_left + x;
01303 }
01304
01305
01306 if (x != this->bar_left) GfxFillRect(this->bar_left, bar_top, x, bar_top + this->bar_height, rtl ? colour_notdone : colour_done);
01307 if (x != this->bar_right) GfxFillRect(x, bar_top, this->bar_right, bar_top + this->bar_height, rtl ? colour_done : colour_notdone);
01308
01309
01310 SetDParam(0, Clamp(val, 0, needed) * 100 / needed);
01311 DrawString(this->bar_left, this->bar_right, text_top, STR_PERFORMANCE_DETAIL_PERCENT, TC_FROMSTRING, SA_CENTER);
01312
01313
01314 if (score_type == SCORE_LOAN) val = needed - val;
01315
01316
01317
01318 SetDParam(0, val);
01319 SetDParam(1, needed);
01320 switch (score_type) {
01321 case SCORE_MIN_PROFIT:
01322 case SCORE_MIN_INCOME:
01323 case SCORE_MAX_INCOME:
01324 case SCORE_MONEY:
01325 case SCORE_LOAN:
01326 DrawString(this->score_detail_left, this->score_detail_right, text_top, STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY);
01327 break;
01328 default:
01329 DrawString(this->score_detail_left, this->score_detail_right, text_top, STR_PERFORMANCE_DETAIL_AMOUNT_INT);
01330 }
01331 }
01332
01333 virtual void OnClick(Point pt, int widget, int click_count)
01334 {
01335
01336 if (IsInsideMM(widget, PRW_COMPANY_FIRST, PRW_COMPANY_LAST + 1)) {
01337
01338 if (!this->IsWidgetDisabled(widget)) {
01339 this->RaiseWidget(this->company + PRW_COMPANY_FIRST);
01340 this->company = (CompanyID)(widget - PRW_COMPANY_FIRST);
01341 this->LowerWidget(this->company + PRW_COMPANY_FIRST);
01342 this->SetDirty();
01343 }
01344 }
01345 }
01346
01347 virtual void OnTick()
01348 {
01349 if (_pause_mode != PM_UNPAUSED) return;
01350
01351
01352 if (--this->timeout == 0) {
01353 this->UpdateCompanyStats();
01354 this->SetDirty();
01355 }
01356 }
01357
01362 virtual void OnInvalidateData(int data)
01363 {
01364
01365 for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) {
01366 this->SetWidgetDisabledState(i + PRW_COMPANY_FIRST, !Company::IsValidID(i));
01367 }
01368
01369
01370 if (this->company != INVALID_COMPANY && !Company::IsValidID(this->company)) {
01371
01372 this->RaiseWidget(this->company + PRW_COMPANY_FIRST);
01373 this->company = INVALID_COMPANY;
01374 }
01375
01376 if (this->company == INVALID_COMPANY) {
01377 const Company *c;
01378 FOR_ALL_COMPANIES(c) {
01379 this->company = c->index;
01380 break;
01381 }
01382 }
01383
01384
01385 this->LowerWidget(this->company + PRW_COMPANY_FIRST);
01386 }
01387 };
01388
01389 CompanyID PerformanceRatingDetailWindow::company = INVALID_COMPANY;
01390
01396 static NWidgetBase *MakePerformanceDetailPanels(int *biggest_index)
01397 {
01398 const StringID performance_tips[] = {
01399 STR_PERFORMANCE_DETAIL_VEHICLES_TOOLTIP,
01400 STR_PERFORMANCE_DETAIL_STATIONS_TOOLTIP,
01401 STR_PERFORMANCE_DETAIL_MIN_PROFIT_TOOLTIP,
01402 STR_PERFORMANCE_DETAIL_MIN_INCOME_TOOLTIP,
01403 STR_PERFORMANCE_DETAIL_MAX_INCOME_TOOLTIP,
01404 STR_PERFORMANCE_DETAIL_DELIVERED_TOOLTIP,
01405 STR_PERFORMANCE_DETAIL_CARGO_TOOLTIP,
01406 STR_PERFORMANCE_DETAIL_MONEY_TOOLTIP,
01407 STR_PERFORMANCE_DETAIL_LOAN_TOOLTIP,
01408 STR_PERFORMANCE_DETAIL_TOTAL_TOOLTIP,
01409 };
01410
01411 assert_compile(lengthof(performance_tips) == SCORE_END - SCORE_BEGIN);
01412
01413 NWidgetVertical *vert = new NWidgetVertical(NC_EQUALSIZE);
01414 for (int widnum = PRW_SCORE_FIRST; widnum <= PRW_SCORE_LAST; widnum++) {
01415 NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, widnum);
01416 panel->SetFill(1, 1);
01417 panel->SetDataTip(0x0, performance_tips[widnum - PRW_SCORE_FIRST]);
01418 vert->Add(panel);
01419 }
01420 *biggest_index = PRW_SCORE_LAST;
01421 return vert;
01422 }
01423
01430 static NWidgetBase *MakeCompanyButtonRows(int *biggest_index)
01431 {
01432 static const int MAX_LENGTH = 8;
01433 NWidgetVertical *vert = NULL;
01434 NWidgetHorizontal *hor = NULL;
01435 int hor_length = 0;
01436
01437 Dimension sprite_size = GetSpriteSize(SPR_COMPANY_ICON);
01438 sprite_size.width += WD_MATRIX_LEFT + WD_MATRIX_RIGHT;
01439 sprite_size.height += WD_MATRIX_TOP + WD_MATRIX_BOTTOM + 1;
01440
01441 for (int widnum = PRW_COMPANY_FIRST; widnum <= PRW_COMPANY_LAST; widnum++) {
01442
01443 if (hor_length == MAX_LENGTH) {
01444 if (vert == NULL) vert = new NWidgetVertical();
01445 vert->Add(hor);
01446 hor = NULL;
01447 hor_length = 0;
01448 }
01449 if (hor == NULL) {
01450 hor = new NWidgetHorizontal();
01451 hor_length = 0;
01452 }
01453
01454 NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, widnum);
01455 panel->SetMinimalSize(sprite_size.width, sprite_size.height);
01456 panel->SetFill(1, 0);
01457 panel->SetDataTip(0x0, STR_GRAPH_KEY_COMPANY_SELECTION_TOOLTIP);
01458 hor->Add(panel);
01459 hor_length++;
01460 }
01461 *biggest_index = PRW_COMPANY_LAST;
01462 if (vert == NULL) return hor;
01463
01464 if (hor_length > 0 && hor_length < MAX_LENGTH) {
01465
01466 NWidgetSpacer *spc = new NWidgetSpacer(0, 0);
01467 spc->SetMinimalSize(sprite_size.width, sprite_size.height);
01468 spc->SetFill(1, 0);
01469 hor->Add(spc);
01470 }
01471 if (hor != NULL) vert->Add(hor);
01472 return vert;
01473 }
01474
01475 static const NWidgetPart _nested_performance_rating_detail_widgets[] = {
01476 NWidget(NWID_HORIZONTAL),
01477 NWidget(WWT_CLOSEBOX, COLOUR_GREY),
01478 NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_PERFORMANCE_DETAIL, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01479 NWidget(WWT_SHADEBOX, COLOUR_GREY),
01480 NWidget(WWT_STICKYBOX, COLOUR_GREY),
01481 EndContainer(),
01482 NWidget(WWT_PANEL, COLOUR_GREY),
01483 NWidgetFunction(MakeCompanyButtonRows), SetPadding(0, 1, 1, 2),
01484 EndContainer(),
01485 NWidgetFunction(MakePerformanceDetailPanels),
01486 };
01487
01488 static const WindowDesc _performance_rating_detail_desc(
01489 WDP_AUTO, 0, 0,
01490 WC_PERFORMANCE_DETAIL, WC_NONE,
01491 0,
01492 _nested_performance_rating_detail_widgets, lengthof(_nested_performance_rating_detail_widgets)
01493 );
01494
01495 void ShowPerformanceRatingDetail()
01496 {
01497 AllocateWindowDescFront<PerformanceRatingDetailWindow>(&_performance_rating_detail_desc, 0);
01498 }