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