@@ -305,485 +305,499 @@ protected:
y = r.bottom + 2;
byte month = this->month;
Year year = this->year;
for (int i = 0; i < this->num_on_x_axis; i++) {
SetDParam(0, month + STR_MONTH_ABBREV_JAN);
SetDParam(1, month + STR_MONTH_ABBREV_JAN + 2);
SetDParam(2, year);
DrawStringMultiLine(x, x + GRAPH_X_POSITION_SEPARATION, y, this->height, month == 0 ? STR_GRAPH_X_LABEL_MONTH_YEAR : STR_GRAPH_X_LABEL_MONTH, graph_axis_label_colour);
month += 3;
if (month >= 12) {
month = 0;
year++;
}
x += GRAPH_X_POSITION_SEPARATION;
} else {
/* Draw the label under the data point rather than on the grid line. */
x = r.left + GRAPH_X_POSITION_BEGINNING;
uint16 label = this->x_values_start;
SetDParam(0, label);
DrawString(x + 1, x + GRAPH_X_POSITION_SEPARATION - 1, y, STR_GRAPH_Y_LABEL_NUMBER, graph_axis_label_colour, SA_CENTER);
label += this->x_values_increment;
/* draw lines and dots */
for (int i = 0; i < this->num_dataset; i++) {
if (!HasBit(this->excluded_data, i)) {
/* Centre the dot between the grid lines. */
x = r.left + GRAPH_X_POSITION_BEGINNING + (GRAPH_X_POSITION_SEPARATION / 2);
byte colour = this->colours[i];
uint prev_x = INVALID_DATAPOINT_POS;
uint prev_y = INVALID_DATAPOINT_POS;
for (int j = 0; j < this->num_on_x_axis; j++) {
OverflowSafeInt64 datapoint = this->cost[i][j];
if (datapoint != INVALID_DATAPOINT) {
/*
* Check whether we need to reduce the 'accuracy' of the
* datapoint value and the highest value to splut overflows.
* And when 'drawing' 'one million' or 'one million and one'
* there is no significant difference, so the least
* significant bits can just be removed.
*
* If there are more bits needed than would fit in a 32 bits
* integer, so at about 31 bits because of the sign bit, the
* least significant bits are removed.
*/
int mult_range = FindLastBit(x_axis_offset) + FindLastBit(abs(datapoint));
int reduce_range = max(mult_range - 31, 0);
/* Handle negative values differently (don't shift sign) */
if (datapoint < 0) {
datapoint = -(abs(datapoint) >> reduce_range);
datapoint >>= reduce_range;
y = r.top + x_axis_offset - (x_axis_offset * datapoint) / (highest_value >> reduce_range);
/* Draw the point. */
GfxFillRect(x - 1, y - 1, x + 1, y + 1, colour);
/* Draw the line connected to the previous point. */
if (prev_x != INVALID_DATAPOINT_POS) GfxDrawLine(prev_x, prev_y, x, y, colour);
prev_x = x;
prev_y = y;
prev_x = INVALID_DATAPOINT_POS;
prev_y = INVALID_DATAPOINT_POS;
BaseGraphWindow(const WindowDesc *desc, WindowNumber window_number, int left,
int top, int height, bool has_negative_values, StringID format_str_y_axis) :
Window(desc, window_number), has_negative_values(has_negative_values),
format_str_y_axis(format_str_y_axis)
{
InvalidateWindow(WC_GRAPH_LEGEND, 0);
this->num_vert_lines = 24;
/* Initialise the dataset */
this->OnTick();
this->graph_location.left = left;
this->graph_location.right = left + GRAPH_X_POSITION_BEGINNING + this->num_vert_lines * GRAPH_X_POSITION_SEPARATION - 1;
this->graph_location.top = top;
this->graph_location.bottom = top + height - 1;
void InitializeWindow(const WindowDesc *desc)
this->FindWindowPlacementAndResize(desc);
this->UpdateStatistics(true);
public:
virtual void OnPaint()
this->DrawWidgets();
this->DrawGraph(this->graph_location);
virtual OverflowSafeInt64 GetGraphData(const Company *c, int j)
return INVALID_DATAPOINT;
virtual void OnClick(Point pt, int widget)
/* Clicked on legend? */
if (widget == BGW_KEY_BUTTON) ShowGraphLegend();
virtual void OnTick()
this->UpdateStatistics(false);
/**
* Update the statistics.
* @param initialize Initialize the data structure.
void UpdateStatistics(bool initialize)
uint excluded_companies = _legend_excluded_companies;
/* Exclude the companies which aren't valid */
for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
if (!Company::IsValidID(c)) SetBit(excluded_companies, c);
byte nums = 0;
const Company *c;
FOR_ALL_COMPANIES(c) {
nums = min(this->num_vert_lines, max(nums, c->num_valid_stat_ent));
int mo = (_cur_month / 3 - nums) * 3;
int yr = _cur_year;
while (mo < 0) {
yr--;
mo += 12;
if (this->excluded_data == excluded_companies && this->num_on_x_axis == nums &&
if (!initialize && this->excluded_data == excluded_companies && this->num_on_x_axis == nums &&
this->year == yr && this->month == mo) {
/* There's no reason to get new stats */
return;
this->excluded_data = excluded_companies;
this->num_on_x_axis = nums;
this->year = yr;
this->month = mo;
int numd = 0;
for (CompanyID k = COMPANY_FIRST; k < MAX_COMPANIES; k++) {
c = Company::GetIfValid(k);
if (c != NULL) {
this->colours[numd] = _colour_gradient[c->colour][6];
for (int j = this->num_on_x_axis, i = 0; --j >= 0;) {
this->cost[numd][i] = (j >= c->num_valid_stat_ent) ? INVALID_DATAPOINT : GetGraphData(c, j);
i++;
numd++;
this->num_dataset = numd;
};
/********************/
/* OPERATING PROFIT */
struct OperatingProfitGraphWindow : BaseGraphWindow {
OperatingProfitGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
BaseGraphWindow(desc, window_number, 2, 18, 136, true, STR_JUST_CURRCOMPACT)
this->InitializeWindow(desc);
return c->old_economy[j].income + c->old_economy[j].expenses;
static const Widget _operating_profit_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_BLACK_CROSS, STR_TOOLTIP_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, COLOUR_GREY, 11, 525, 0, 13, STR_GRAPH_OPERATING_PROFIT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS},
{ WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_GREY, 526, 575, 0, 13, STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP},
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 575, 14, 173, 0x0, STR_NULL},
{ WIDGETS_END},
static const NWidgetPart _nested_operating_profit_widgets[] = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY, BGW_CLOSEBOX),
NWidget(WWT_CAPTION, COLOUR_GREY, BGW_CAPTION), SetDataTip(STR_GRAPH_OPERATING_PROFIT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, BGW_KEY_BUTTON), SetMinimalSize(50, 14), SetDataTip(STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP),
EndContainer(),
NWidget(WWT_PANEL, COLOUR_GREY, BGW_BACKGROUND), SetMinimalSize(576, 160), EndContainer(),
static const WindowDesc _operating_profit_desc(
WDP_AUTO, WDP_AUTO, 576, 174, 576, 174,
WC_OPERATING_PROFIT, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_operating_profit_widgets, _nested_operating_profit_widgets, lengthof(_nested_operating_profit_widgets)
);
void ShowOperatingProfitGraph()
AllocateWindowDescFront<OperatingProfitGraphWindow>(&_operating_profit_desc, 0);
/****************/
/* INCOME GRAPH */
struct IncomeGraphWindow : BaseGraphWindow {
IncomeGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
BaseGraphWindow(desc, window_number, 2, 18, 104, false, STR_JUST_CURRCOMPACT)
return c->old_economy[j].income;
static const Widget _income_graph_widgets[] = {
{ WWT_CAPTION, RESIZE_NONE, COLOUR_GREY, 11, 525, 0, 13, STR_GRAPH_INCOME_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 575, 14, 141, 0x0, STR_NULL},
static const NWidgetPart _nested_income_graph_widgets[] = {
NWidget(WWT_CAPTION, COLOUR_GREY, BGW_CAPTION), SetDataTip(STR_GRAPH_INCOME_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
NWidget(WWT_PANEL, COLOUR_GREY, BGW_BACKGROUND), SetMinimalSize(576, 128), EndContainer(),
static const WindowDesc _income_graph_desc(
WDP_AUTO, WDP_AUTO, 576, 142, 576, 142,
WC_INCOME_GRAPH, WC_NONE,
_income_graph_widgets, _nested_income_graph_widgets, lengthof(_nested_income_graph_widgets)
void ShowIncomeGraph()
AllocateWindowDescFront<IncomeGraphWindow>(&_income_graph_desc, 0);
/*******************/
/* DELIVERED CARGO */
struct DeliveredCargoGraphWindow : BaseGraphWindow {
DeliveredCargoGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
BaseGraphWindow(desc, window_number, 2, 18, 104, false, STR_JUST_COMMA)
return c->old_economy[j].delivered_cargo;
static const Widget _delivered_cargo_graph_widgets[] = {
{ WWT_CAPTION, RESIZE_NONE, COLOUR_GREY, 11, 525, 0, 13, STR_GRAPH_CARGO_DELIVERED_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS},
static const NWidgetPart _nested_delivered_cargo_graph_widgets[] = {
NWidget(WWT_CAPTION, COLOUR_GREY, BGW_CAPTION), SetDataTip(STR_GRAPH_CARGO_DELIVERED_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
static const WindowDesc _delivered_cargo_graph_desc(
WC_DELIVERED_CARGO, WC_NONE,
_delivered_cargo_graph_widgets, _nested_delivered_cargo_graph_widgets, lengthof(_nested_delivered_cargo_graph_widgets)
void ShowDeliveredCargoGraph()
AllocateWindowDescFront<DeliveredCargoGraphWindow>(&_delivered_cargo_graph_desc, 0);
/***********************/
/* PERFORMANCE HISTORY */
/** Widget numbers of the performance history window. */
enum PerformanceHistoryGraphWidgets {
PHW_CLOSEBOX,
PHW_CAPTION,
PHW_KEY,
PHW_DETAILED_PERFORMANCE,
PHW_BACKGROUND,
struct PerformanceHistoryGraphWindow : BaseGraphWindow {
PerformanceHistoryGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
BaseGraphWindow(desc, window_number, 2, 18, 200, false, STR_JUST_COMMA)
return c->old_economy[j].performance_history;
if (widget == PHW_DETAILED_PERFORMANCE) ShowPerformanceRatingDetail();
this->BaseGraphWindow::OnClick(pt, widget);
static const Widget _performance_history_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_BLACK_CROSS, STR_TOOLTIP_CLOSE_WINDOW}, // PHW_CLOSEBOX
{ WWT_CAPTION, RESIZE_NONE, COLOUR_GREY, 11, 475, 0, 13, STR_GRAPH_COMPANY_PERFORMANCE_RATINGS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS}, // PHW_CAPTION
{ WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_GREY, 526, 575, 0, 13, STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP}, // PHW_KEY
{ WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_GREY, 476, 525, 0, 13, STR_PERFORMANCE_DETAIL_KEY, STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP}, // PHW_DETAILED_PERFORMANCE
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 575, 14, 237, 0x0, STR_NULL}, // PHW_BACKGROUND
static const NWidgetPart _nested_performance_history_widgets[] = {
NWidget(WWT_CLOSEBOX, COLOUR_GREY, PHW_CLOSEBOX),
NWidget(WWT_CAPTION, COLOUR_GREY, PHW_CAPTION), SetDataTip(STR_GRAPH_COMPANY_PERFORMANCE_RATINGS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, PHW_DETAILED_PERFORMANCE), SetMinimalSize(50, 14), SetDataTip(STR_PERFORMANCE_DETAIL_KEY, STR_GRAPH_PERFORMANCE_DETAIL_TOOLTIP),
NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, PHW_KEY), SetMinimalSize(50, 14), SetDataTip(STR_GRAPH_KEY_BUTTON, STR_GRAPH_KEY_TOOLTIP),
NWidget(WWT_PANEL, COLOUR_GREY, PHW_BACKGROUND), SetMinimalSize(576, 224), EndContainer(),
static const WindowDesc _performance_history_desc(
WDP_AUTO, WDP_AUTO, 576, 238, 576, 238,
WC_PERFORMANCE_HISTORY, WC_NONE,
_performance_history_widgets, _nested_performance_history_widgets, lengthof(_nested_performance_history_widgets)
void ShowPerformanceHistoryGraph()
AllocateWindowDescFront<PerformanceHistoryGraphWindow>(&_performance_history_desc, 0);
/*****************/
/* COMPANY VALUE */
struct CompanyValueGraphWindow : BaseGraphWindow {
CompanyValueGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
BaseGraphWindow(desc, window_number, 2, 18, 200, false, STR_JUST_CURRCOMPACT)
return c->old_economy[j].company_value;
static const Widget _company_value_graph_widgets[] = {
{ WWT_CAPTION, RESIZE_NONE, COLOUR_GREY, 11, 525, 0, 13, STR_GRAPH_COMPANY_VALUES_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 575, 14, 237, 0x0, STR_NULL},
static const NWidgetPart _nested_company_value_graph_widgets[] = {
NWidget(WWT_CAPTION, COLOUR_GREY, BGW_CAPTION), SetDataTip(STR_GRAPH_COMPANY_VALUES_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
NWidget(WWT_PANEL, COLOUR_GREY, BGW_BACKGROUND), SetMinimalSize(576, 224), EndContainer(),
static const WindowDesc _company_value_graph_desc(
WC_COMPANY_VALUE, WC_NONE,
_company_value_graph_widgets, _nested_company_value_graph_widgets, lengthof(_nested_company_value_graph_widgets)
void ShowCompanyValueGraph()
AllocateWindowDescFront<CompanyValueGraphWindow>(&_company_value_graph_desc, 0);
/* PAYMENT RATES */
/** Widget numbers of the cargo payment rates. */
enum CargoPaymentRatesWidgets {
CPW_CLOSEBOX,
CPW_CAPTION,
CPW_BACKGROUND,
CPW_CARGO_FIRST,
struct PaymentRatesGraphWindow : BaseGraphWindow {
PaymentRatesGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
BaseGraphWindow(desc, window_number, 2, 24, 200, false, STR_JUST_CURRCOMPACT)
uint num_active = 0;
const CargoSpec *cs;
FOR_ALL_CARGOSPECS(cs) {
num_active++;
/* Resize the window to fit the cargo types */
ResizeWindow(this, 0, max(num_active, 12U) * 8);
/* Add widgets for each cargo type */
this->widget_count += num_active;
this->widget = ReallocT(this->widget, this->widget_count + 1);
this->widget[this->widget_count].type = WWT_LAST;
/* Set the properties of each widget */
for (uint i = 0; i != num_active; i++) {
Widget *wi = &this->widget[CPW_CARGO_FIRST + i];
wi->type = WWT_PANEL;
wi->display_flags = RESIZE_NONE;
wi->colour = COLOUR_ORANGE;
wi->left = 493;
wi->right = 562;
wi->top = 24 + i * 8;
wi->bottom = wi->top + 7;
wi->data = 0;
wi->tooltips = STR_GRAPH_CARGO_PAYMENT_TOGGLE_CARGO;
if (!HasBit(_legend_excluded_cargo, i)) this->LowerWidget(i + CPW_CARGO_FIRST);
this->SetDirty();
this->num_on_x_axis = 20;
this->num_vert_lines = 20;
this->month = 0xFF;
this->x_values_start = 10;
this->x_values_increment = 10;
this->graph_location.right = this->graph_location.left + GRAPH_X_POSITION_BEGINNING + this->num_vert_lines * GRAPH_X_POSITION_SEPARATION - 1;
this->graph_location.bottom = this->graph_location.top + (this->height - 38) - 1;
this->OnHundredthTick();
Status change: