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