Changeset - r12600:116a0e553143
[Not reviewed]
master
0 1 0
rubidium - 15 years ago 2009-08-03 15:23:49
rubidium@openttd.org
(svn r17053) -Codechange: pass a Rect to DrawGraph so it knows where to draw
1 file changed with 41 insertions and 30 deletions:
0 comments (0 inline, 0 general)
src/graph_gui.cpp
Show inline comments
 
@@ -178,78 +178,81 @@ protected:
 
	static const TextColour graph_axis_label_colour = TC_BLACK; ///< colour of the graph axis label.
 

	
 
	/* The starting month and year that values are plotted against. If month is
 
	 * 0xFF, use x_values_start and x_values_increment below instead. */
 
	byte month;
 
	Year year;
 

	
 
	/* These values are used if the graph is being plotted against values
 
	 * rather than the dates specified by month and year. */
 
	uint16 x_values_start;
 
	uint16 x_values_increment;
 

	
 
	int gd_left, gd_top;  ///< Where to start drawing the graph, in pixels.
 
	uint gd_height;    ///< The height of the graph in pixels.
 
	Rect graph_location;
 
	StringID format_str_y_axis;
 
	byte colours[GRAPH_MAX_DATASETS];
 
	OverflowSafeInt64 cost[GRAPH_MAX_DATASETS][24]; ///< last 2 years
 

	
 
	void DrawGraph() const
 
	/**
 
	 * Actually draw the graph.
 
	 * @param r the rectangle of the data field of the graph
 
	 */
 
	void DrawGraph(Rect &r) const
 
	{
 
		uint x, y;                       ///< Reused whenever x and y coordinates are needed.
 
		OverflowSafeInt64 highest_value; ///< Highest value to be drawn.
 
		int x_axis_offset;               ///< Distance from the top of the graph to the x axis.
 

	
 
		/* the colours and cost array of GraphDrawer must accomodate
 
		 * both values for cargo and companies. So if any are higher, quit */
 
		assert(GRAPH_MAX_DATASETS >= (int)NUM_CARGO && GRAPH_MAX_DATASETS >= (int)MAX_COMPANIES);
 
		assert(this->num_vert_lines > 0);
 

	
 
		byte grid_colour = _colour_gradient[COLOUR_GREY][4];
 

	
 
		/* The coordinates of the opposite edges of the graph. */
 
		int bottom = this->gd_top + this->gd_height - 1;
 
		int right  = this->gd_left + GRAPH_X_POSITION_BEGINNING + this->num_vert_lines * GRAPH_X_POSITION_SEPARATION - 1;
 
		assert(r.left + GRAPH_X_POSITION_BEGINNING + this->num_vert_lines * GRAPH_X_POSITION_SEPARATION - 1 == r.right);
 
		int height = r.bottom - r.top + 1;
 

	
 
		/* Draw the vertical grid lines. */
 

	
 
		/* Don't draw the first line, as that's where the axis will be. */
 
		x = this->gd_left + GRAPH_X_POSITION_BEGINNING + GRAPH_X_POSITION_SEPARATION;
 
		x = r.left + GRAPH_X_POSITION_BEGINNING + GRAPH_X_POSITION_SEPARATION;
 

	
 
		for (int i = 0; i < this->num_vert_lines; i++) {
 
			GfxFillRect(x, this->gd_top, x, bottom, grid_colour);
 
			GfxFillRect(x, r.top, x, r.bottom, grid_colour);
 
			x += GRAPH_X_POSITION_SEPARATION;
 
		}
 

	
 
		/* Draw the horizontal grid lines. */
 
		x = this->gd_left + GRAPH_X_POSITION_BEGINNING;
 
		y = this->gd_height + this->gd_top;
 
		x = r.left + GRAPH_X_POSITION_BEGINNING;
 
		y = r.bottom;
 

	
 
		for (int i = 0; i < GRAPH_NUM_LINES_Y; i++) {
 
			GfxFillRect(x, y, right, y, grid_colour);
 
			y -= (this->gd_height / (GRAPH_NUM_LINES_Y - 1));
 
			GfxFillRect(x, y, r.right, y, grid_colour);
 
			y -= height / (GRAPH_NUM_LINES_Y - 1);
 
		}
 

	
 
		/* Draw the y axis. */
 
		GfxFillRect(x, this->gd_top, x, bottom, GRAPH_AXIS_LINE_COLOUR);
 
		GfxFillRect(x, r.top, x, r.bottom, GRAPH_AXIS_LINE_COLOUR);
 

	
 
		/* Find the distance from the gd_top of the graph to the x axis. */
 
		x_axis_offset = this->gd_height;
 
		x_axis_offset = height;
 

	
 
		/* The graph is currently symmetrical about the x axis. */
 
		if (this->has_negative_values) x_axis_offset /= 2;
 

	
 
		/* Draw the x axis. */
 
		y = x_axis_offset + this->gd_top;
 
		GfxFillRect(x, y, right, y, GRAPH_AXIS_LINE_COLOUR);
 
		y = x_axis_offset + r.top;
 
		GfxFillRect(x, y, r.right, y, GRAPH_AXIS_LINE_COLOUR);
 

	
 
		/* Find the largest value that will be drawn. */
 
		if (this->num_on_x_axis == 0)
 
			return;
 

	
 
		assert(this->num_on_x_axis > 0);
 
		assert(this->num_dataset > 0);
 

	
 
		/* Start of with a value of twice the gd_height of the graph in pixels. It's a
 
		 * bit arbitrary, but it makes the cargo payment graph look a little nicer,
 
		 * and prevents division by zero when calculating where the datapoint
 
		 * should be drawn. */
 
@@ -274,75 +277,75 @@ protected:
 
		 * axis labels used. */
 
		int round_val = highest_value % (GRAPH_NUM_LINES_Y - 1);
 
		if (round_val != 0) highest_value += (GRAPH_NUM_LINES_Y - 1 - round_val);
 

	
 
		/* draw text strings on the y axis */
 
		int64 y_label = highest_value;
 
		int64 y_label_separation = highest_value / (GRAPH_NUM_LINES_Y - 1);
 

	
 
		/* If there are negative values, the graph goes from highest_value to
 
		 * -highest_value, not highest_value to 0. */
 
		if (this->has_negative_values) y_label_separation *= 2;
 

	
 
		x = this->gd_left + GRAPH_X_POSITION_BEGINNING + 1;
 
		y = this->gd_top - 3;
 
		x = r.left + GRAPH_X_POSITION_BEGINNING + 1;
 
		y = r.top - 3;
 

	
 
		for (int i = 0; i < GRAPH_NUM_LINES_Y; i++) {
 
			SetDParam(0, this->format_str_y_axis);
 
			SetDParam(1, y_label);
 
			DrawString(x - GRAPH_X_POSITION_BEGINNING, x, y, STR_GRAPH_Y_LABEL, graph_axis_label_colour, SA_RIGHT);
 

	
 
			y_label -= y_label_separation;
 
			y += (this->gd_height / (GRAPH_NUM_LINES_Y - 1));
 
			y += height / (GRAPH_NUM_LINES_Y - 1);
 
		}
 

	
 
		/* draw strings on the x axis */
 
		if (this->month != 0xFF) {
 
			x = this->gd_left + GRAPH_X_POSITION_BEGINNING;
 
			y = this->gd_top + this->gd_height + 1;
 
			x = r.left + GRAPH_X_POSITION_BEGINNING;
 
			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 = this->gd_left + GRAPH_X_POSITION_BEGINNING;
 
			y = this->gd_top + this->gd_height + 1;
 
			x = r.left + GRAPH_X_POSITION_BEGINNING;
 
			y = r.bottom + 2;
 
			uint16 label = this->x_values_start;
 

	
 
			for (int i = 0; i < this->num_on_x_axis; i++) {
 
				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;
 
				x += GRAPH_X_POSITION_SEPARATION;
 
			}
 
		}
 

	
 
		/* 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 = this->gd_left + GRAPH_X_POSITION_BEGINNING + (GRAPH_X_POSITION_SEPARATION / 2);
 
				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.
 
@@ -355,64 +358,70 @@ protected:
 
						 * 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);
 
						} else {
 
							datapoint >>= reduce_range;
 
						}
 

	
 
						y = this->gd_top + x_axis_offset - (x_axis_offset * datapoint) / (highest_value >> 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;
 
					} else {
 
						prev_x = INVALID_DATAPOINT_POS;
 
						prev_y = INVALID_DATAPOINT_POS;
 
					}
 

	
 
					x += GRAPH_X_POSITION_SEPARATION;
 
				}
 
			}
 
		}
 
	}
 

	
 

	
 
	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),
 
			gd_left(left), gd_top(top), gd_height(height), format_str_y_axis(format_str_y_axis)
 
			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;
 
	}
 

	
 
public:
 
	virtual void OnPaint()
 
	{
 
		this->DrawWidgets();
 

	
 
		this->DrawGraph();
 
		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();
 
	}
 
@@ -757,31 +766,33 @@ struct PaymentRatesGraphWindow : BaseGra
 
			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->gd_height = this->height - 38;
 
		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;
 

	
 
		/* Initialise the dataset */
 
		this->OnHundredthTick();
 

	
 
		this->FindWindowPlacementAndResize(desc);
 
	}
 

	
 
	virtual void OnPaint()
 
	{
 
		this->DrawWidgets();
 

	
 
		int x = 495;
 
		int y = 24;
 
@@ -800,28 +811,28 @@ struct PaymentRatesGraphWindow : BaseGra
 
				 * when the button is clicked */
 
				byte clk_dif = this->IsWidgetLowered(i + CPW_CARGO_FIRST) ? 1 : 0;
 

	
 
				GfxFillRect(x + clk_dif, y + clk_dif, x + 8 + clk_dif, y + 5 + clk_dif, 0);
 
				GfxFillRect(x + 1 + clk_dif, y + 1 + clk_dif, x + 7 + clk_dif, y + 4 + clk_dif, cs->legend_colour);
 
				SetDParam(0, cs->name);
 
				DrawString(x + 14 + clk_dif, this->width, y + clk_dif, STR_GRAPH_CARGO_PAYMENT_CARGO);
 
				y += 8;
 
			}
 
			i++;
 
		}
 

	
 
		this->DrawGraph();
 
		this->DrawGraph(this->graph_location);
 

	
 
		DrawString(2 + 46, this->width, 24 + this->gd_height + 7, STR_GRAPH_CARGO_PAYMENT_RATES_X_LABEL);
 
		DrawString(2 + 84, this->width, 24 - 9, STR_GRAPH_CARGO_PAYMENT_RATES_TITLE);
 
		DrawString(2 + 46, this->width, this->graph_location.bottom + 8, STR_GRAPH_CARGO_PAYMENT_RATES_X_LABEL);
 
		DrawString(2 + 84, this->width, this->graph_location.top - 9, STR_GRAPH_CARGO_PAYMENT_RATES_TITLE);
 
	}
 

	
 
	virtual void OnClick(Point pt, int widget)
 
	{
 
		if (widget >= CPW_CARGO_FIRST) {
 
			ToggleBit(_legend_excluded_cargo, widget - CPW_CARGO_FIRST);
 
			this->ToggleWidgetLoweredState(widget);
 
			this->excluded_data = _legend_excluded_cargo;
 
			this->SetDirty();
 
		}
 
	}
 

	
0 comments (0 inline, 0 general)