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