Changeset - r12598:0d0ca7781863
[Not reviewed]
master
0 2 0
rubidium - 15 years ago 2009-08-03 14:44:08
rubidium@openttd.org
(svn r17051) -Codechange: make the graph legend window use nested widgets
2 files changed with 30 insertions and 42 deletions:
0 comments (0 inline, 0 general)
src/company_cmd.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/** @file company_cmd.cpp Handling of companies. */
 

	
 
#include "stdafx.h"
 
#include "openttd.h"
 
#include "engine_base.h"
 
#include "company_func.h"
 
#include "company_gui.h"
 
#include "town.h"
 
#include "news_func.h"
 
#include "command_func.h"
 
#include "network/network.h"
 
#include "network/network_func.h"
 
#include "network/network_base.h"
 
#include "ai/ai.hpp"
 
#include "company_manager_face.h"
 
#include "group.h"
 
#include "window_func.h"
 
#include "tile_map.h"
 
#include "strings_func.h"
 
#include "gfx_func.h"
 
#include "date_func.h"
 
#include "sound_func.h"
 
#include "autoreplace_func.h"
 
#include "autoreplace_gui.h"
 
#include "string_func.h"
 
#include "road_func.h"
 
#include "rail.h"
 
#include "sprite.h"
 
#include "core/pool_func.hpp"
 
#include "settings_func.h"
 

	
 
#include "table/strings.h"
 

	
 
CompanyByte _local_company;
 
CompanyByte _current_company;
 
/* NOSAVE: can be determined from company structs */
 
Colours _company_colours[MAX_COMPANIES];
 
CompanyManagerFace _company_manager_face; ///< for company manager face storage in openttd.cfg
 
uint _next_competitor_start;              ///< the number of ticks before the next AI is started
 
uint _cur_company_tick_index;             ///< used to generate a name for one company that doesn't have a name yet per tick
 

	
 
CompanyPool _company_pool("Company");
 
INSTANTIATE_POOL_METHODS(Company)
 

	
 
Company::Company(uint16 name_1, bool is_ai) :
 
	name_1(name_1),
 
	location_of_HQ(INVALID_TILE),
 
	is_ai(is_ai)
 
{
 
	for (uint j = 0; j < 4; j++) this->share_owners[j] = COMPANY_SPECTATOR;
 
}
 

	
 
Company::~Company()
 
{
 
	free(this->name);
 
	free(this->president_name);
 
	free(this->num_engines);
 

	
 
	if (CleaningPool()) return;
 

	
 
	DeleteCompanyWindows(this->index);
 
	InvalidateWindowData(WC_GRAPH_LEGEND, 0, this->index);
 
}
 

	
 
/**
 
 * Sets the local company and updates the settings that are set on a
 
 * per-company basis to reflect the core's state in the GUI.
 
 * @param new_company the new company
 
 * @pre Company::IsValidID(new_company) || new_company == COMPANY_SPECTATOR || new_company == OWNER_NONE
 
 */
 
void SetLocalCompany(CompanyID new_company)
 
{
 
	/* company could also be COMPANY_SPECTATOR or OWNER_NONE */
 
	assert(Company::IsValidID(new_company) || new_company == COMPANY_SPECTATOR || new_company == OWNER_NONE);
 

	
 
	_local_company = new_company;
 

	
 
	/* Delete any construction windows... */
 
	DeleteConstructionWindows();
 

	
 
	/* ... and redraw the whole screen. */
 
	MarkWholeScreenDirty();
 
}
 

	
 
uint16 GetDrawStringCompanyColour(CompanyID company)
 
{
 
	/* Get the colour for DrawString-subroutines which matches the colour
 
	 * of the company */
 
	if (!Company::IsValidID(company)) return _colour_gradient[COLOUR_WHITE][4] | IS_PALETTE_COLOUR;
 
	return (_colour_gradient[_company_colours[company]][4]) | IS_PALETTE_COLOUR;
 
}
 

	
 
void DrawCompanyIcon(CompanyID c, int x, int y)
 
{
 
	DrawSprite(SPR_PLAYER_ICON, COMPANY_SPRITE_COLOUR(c), x, y);
 
}
 

	
 
/**
 
 * Checks whether a company manager's face is a valid encoding.
 
 * Unused bits are not enforced to be 0.
 
 * @param cmf the fact to check
 
 * @return true if and only if the face is valid
 
 */
 
bool IsValidCompanyManagerFace(CompanyManagerFace cmf)
 
{
 
	if (!AreCompanyManagerFaceBitsValid(cmf, CMFV_GEN_ETHN, GE_WM)) return false;
 

	
 
	GenderEthnicity ge   = (GenderEthnicity)GetCompanyManagerFaceBits(cmf, CMFV_GEN_ETHN, GE_WM);
 
	bool has_moustache   = !HasBit(ge, GENDER_FEMALE) && GetCompanyManagerFaceBits(cmf, CMFV_HAS_MOUSTACHE,   ge) != 0;
 
	bool has_tie_earring = !HasBit(ge, GENDER_FEMALE) || GetCompanyManagerFaceBits(cmf, CMFV_HAS_TIE_EARRING, ge) != 0;
 
	bool has_glasses     = GetCompanyManagerFaceBits(cmf, CMFV_HAS_GLASSES, ge) != 0;
 

	
 
	if (!AreCompanyManagerFaceBitsValid(cmf, CMFV_EYE_COLOUR, ge)) return false;
 
	for (CompanyManagerFaceVariable cmfv = CMFV_CHEEKS; cmfv < CMFV_END; cmfv++) {
 
		switch (cmfv) {
 
			case CMFV_MOUSTACHE:   if (!has_moustache)   continue; break;
 
			case CMFV_LIPS:        // FALL THROUGH
 
			case CMFV_NOSE:        if (has_moustache)    continue; break;
 
			case CMFV_TIE_EARRING: if (!has_tie_earring) continue; break;
 
			case CMFV_GLASSES:     if (!has_glasses)     continue; break;
 
			default: break;
 
		}
 
		if (!AreCompanyManagerFaceBitsValid(cmf, cmfv, ge)) return false;
 
	}
 

	
 
	return true;
 
}
 

	
 
void InvalidateCompanyWindows(const Company *company)
 
{
 
	CompanyID cid = company->index;
 

	
 
	if (cid == _local_company) InvalidateWindow(WC_STATUS_BAR, 0);
 
	InvalidateWindow(WC_FINANCES, cid);
 
}
 

	
 
bool CheckCompanyHasMoney(CommandCost cost)
 
{
 
	if (cost.GetCost() > 0) {
 
		const Company *c = Company::GetIfValid(_current_company);
 
		if (c != NULL && cost.GetCost() > c->money) {
 
			SetDParam(0, cost.GetCost());
 
			_error_message = STR_ERROR_NOT_ENOUGH_CASH_REQUIRES_CURRENCY;
 
			return false;
 
		}
 
	}
 
	return true;
 
}
 

	
 
static void SubtractMoneyFromAnyCompany(Company *c, CommandCost cost)
 
{
 
	if (cost.GetCost() == 0) return;
 
	assert(cost.GetExpensesType() != INVALID_EXPENSES);
 

	
 
	c->money -= cost.GetCost();
 
	c->yearly_expenses[0][cost.GetExpensesType()] += cost.GetCost();
 

	
 
	if (HasBit(1 << EXPENSES_TRAIN_INC    |
src/graph_gui.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/** @file graph_gui.cpp GUI that shows performance graphs. */
 

	
 
#include "stdafx.h"
 
#include "openttd.h"
 
#include "gui.h"
 
#include "window_gui.h"
 
#include "company_base.h"
 
#include "company_gui.h"
 
#include "economy_func.h"
 
#include "cargotype.h"
 
#include "strings_func.h"
 
#include "window_func.h"
 
#include "date_func.h"
 
#include "gfx_func.h"
 
#include "sortlist_type.h"
 

	
 
#include "table/strings.h"
 

	
 
/* Bitmasks of company and cargo indices that shouldn't be drawn. */
 
static uint _legend_excluded_companies;
 
static uint _legend_excluded_cargo;
 

	
 
/* Apparently these don't play well with enums. */
 
static const OverflowSafeInt64 INVALID_DATAPOINT(INT64_MAX); // Value used for a datapoint that shouldn't be drawn.
 
static const uint INVALID_DATAPOINT_POS = UINT_MAX;  // Used to determine if the previous point was drawn.
 

	
 
/****************/
 
/* GRAPH LEGEND */
 
/****************/
 

	
 
/** Widget numbers of the graph legend window. */
 
enum GraphLegendWidgetNumbers {
 
	GLW_CLOSEBOX,
 
	GLW_CAPTION,
 
	GLW_BACKGROUND,
 

	
 
	GLW_FIRST_COMPANY,
 
	GLW_LAST_COMPANY = GLW_FIRST_COMPANY + MAX_COMPANIES - 1,
 
};
 

	
 
struct GraphLegendWindow : Window {
 
	GraphLegendWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
 
	GraphLegendWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
 
	{
 
		for (uint i = GLW_FIRST_COMPANY; i < this->widget_count; i++) {
 
			if (!HasBit(_legend_excluded_companies, i - GLW_FIRST_COMPANY)) this->LowerWidget(i);
 
		this->InitNested(desc, window_number);
 

	
 
		for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
 
			if (!HasBit(_legend_excluded_companies, c)) this->LowerWidget(c + GLW_FIRST_COMPANY);
 

	
 
			this->OnInvalidateData(c);
 
		}
 

	
 
		this->FindWindowPlacementAndResize(desc);
 
	}
 

	
 
	virtual void OnPaint()
 
	{
 
		for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
 
			if (Company::IsValidID(c)) continue;
 
		this->DrawWidgets();
 
	}
 

	
 
			SetBit(_legend_excluded_companies, c);
 
			this->RaiseWidget(c + GLW_FIRST_COMPANY);
 
		}
 

	
 
		this->DrawWidgets();
 
	virtual void DrawWidget(const Rect &r, int widget) const
 
	{
 
		if (!IsInsideMM(widget, GLW_FIRST_COMPANY, MAX_COMPANIES + GLW_FIRST_COMPANY)) return;
 

	
 
		const Company *c;
 
		FOR_ALL_COMPANIES(c) {
 
			DrawCompanyIcon(c->index, 4, 18 + c->index * 12);
 
		CompanyID cid = (CompanyID)(widget - GLW_FIRST_COMPANY);
 

	
 
		if (!Company::IsValidID(cid)) return;
 

	
 
			SetDParam(0, c->index);
 
			SetDParam(1, c->index);
 
			DrawString(21, this->width - 4, 17 + c->index * 12, STR_COMPANY_NAME_COMPANY_NUM, HasBit(_legend_excluded_companies, c->index) ? TC_BLACK : TC_WHITE);
 
		}
 
		DrawCompanyIcon(cid, r.left + 2, r.top + 2);
 

	
 
		SetDParam(0, cid);
 
		SetDParam(1, cid);
 
		DrawString(r.left + 19, r.right - 2, r.top + 1, STR_COMPANY_NAME_COMPANY_NUM, HasBit(_legend_excluded_companies, cid) ? TC_BLACK : TC_WHITE);
 
	}
 

	
 
	virtual void OnClick(Point pt, int widget)
 
	{
 
		if (!IsInsideMM(widget, GLW_FIRST_COMPANY, MAX_COMPANIES + GLW_FIRST_COMPANY)) return;
 

	
 
		ToggleBit(_legend_excluded_companies, widget - GLW_FIRST_COMPANY);
 
		this->ToggleWidgetLoweredState(widget);
 
		this->SetDirty();
 
		InvalidateWindow(WC_INCOME_GRAPH, 0);
 
		InvalidateWindow(WC_OPERATING_PROFIT, 0);
 
		InvalidateWindow(WC_DELIVERED_CARGO, 0);
 
		InvalidateWindow(WC_PERFORMANCE_HISTORY, 0);
 
		InvalidateWindow(WC_COMPANY_VALUE, 0);
 
	}
 

	
 
	virtual void OnInvalidateData(int data)
 
	{
 
		if (Company::IsValidID(data)) return;
 

	
 
		SetBit(_legend_excluded_companies, data);
 
		this->RaiseWidget(data + GLW_FIRST_COMPANY);
 
	}
 
};
 

	
 
/**
 
 * Construct a vertical list of buttons, one for each company.
 
 * @param biggest_index Storage for collecting the biggest index used in the returned tree.
 
 * @return Panel with company buttons.
 
 * @postcond \c *biggest_index contains the largest used index in the tree.
 
 */
 
static NWidgetBase *MakeNWidgetCompanyLines(int *biggest_index)
 
{
 
	NWidgetVertical *vert = new NWidgetVertical();
 

	
 
	for (int widnum = GLW_FIRST_COMPANY; widnum <= GLW_LAST_COMPANY; widnum++) {
 
		NWidgetBackground *panel = new NWidgetBackground(WWT_PANEL, COLOUR_GREY, widnum);
 
		panel->SetMinimalSize(246, 12);
 
		panel->SetFill(false, false);
 
		panel->SetDataTip(0x0, STR_GRAPH_KEY_COMPANY_SELECTION);
 
		vert->Add(panel);
 
	}
 
	*biggest_index = GLW_LAST_COMPANY;
 
	return vert;
 
}
 

	
 
static const Widget _graph_legend_widgets[] = {
 
{   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_GREY,     0,    10,     0,    13, STR_BLACK_CROSS,       STR_TOOLTIP_CLOSE_WINDOW},           // GLW_CLOSEBOX
 
{    WWT_CAPTION,   RESIZE_NONE,  COLOUR_GREY,    11,   249,     0,    13, STR_GRAPH_KEY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS}, // GLW_CAPTION
 
{      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     0,   249,    14,   195, 0x0,                   STR_NULL},                           // GLW_BACKGROUND
 
{      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,    16,    27, 0x0,                   STR_GRAPH_KEY_COMPANY_SELECTION},    // GLW_FIRST_COMPANY
 
{      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,    28,    39, 0x0,                   STR_GRAPH_KEY_COMPANY_SELECTION},
 
{      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,    40,    51, 0x0,                   STR_GRAPH_KEY_COMPANY_SELECTION},
 
{      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,    52,    63, 0x0,                   STR_GRAPH_KEY_COMPANY_SELECTION},
 
{      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,    64,    75, 0x0,                   STR_GRAPH_KEY_COMPANY_SELECTION},
 
{      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,    76,    87, 0x0,                   STR_GRAPH_KEY_COMPANY_SELECTION},
 
{      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,    88,    99, 0x0,                   STR_GRAPH_KEY_COMPANY_SELECTION},
 
{      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,   100,   111, 0x0,                   STR_GRAPH_KEY_COMPANY_SELECTION},
 
{      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,   112,   123, 0x0,                   STR_GRAPH_KEY_COMPANY_SELECTION},
 
{      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,   124,   135, 0x0,                   STR_GRAPH_KEY_COMPANY_SELECTION},
 
{      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,   136,   147, 0x0,                   STR_GRAPH_KEY_COMPANY_SELECTION},
 
{      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,   148,   159, 0x0,                   STR_GRAPH_KEY_COMPANY_SELECTION},
 
{      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,   160,   171, 0x0,                   STR_GRAPH_KEY_COMPANY_SELECTION},
 
{      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,   172,   183, 0x0,                   STR_GRAPH_KEY_COMPANY_SELECTION},
 
{      WWT_PANEL,   RESIZE_NONE,  COLOUR_GREY,     2,   247,   184,   195, 0x0,                   STR_GRAPH_KEY_COMPANY_SELECTION},    // GLW_LAST_COMPANY
 
{   WIDGETS_END},
 
};
 

	
 
static const NWidgetPart _nested_graph_legend_widgets[] = {
 
	NWidget(NWID_HORIZONTAL),
 
		NWidget(WWT_CLOSEBOX, COLOUR_GREY, GLW_CLOSEBOX),
 
		NWidget(WWT_CAPTION, COLOUR_GREY, GLW_CAPTION), SetDataTip(STR_GRAPH_KEY_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
 
	EndContainer(),
 
	NWidget(WWT_PANEL, COLOUR_GREY, GLW_BACKGROUND),
 
		NWidget(NWID_SPACER), SetMinimalSize(0, 2),
 
		NWidget(NWID_HORIZONTAL),
 
			NWidget(NWID_SPACER), SetMinimalSize(2, 0),
 
			NWidgetFunction(MakeNWidgetCompanyLines),
 
			NWidget(NWID_SPACER), SetMinimalSize(2, 0),
 
		EndContainer(),
 
	EndContainer(),
 
};
 

	
 
static const WindowDesc _graph_legend_desc(
 
	WDP_AUTO, WDP_AUTO, 250, 196, 250, 196,
 
	WC_GRAPH_LEGEND, WC_NONE,
 
	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 
	_graph_legend_widgets, _nested_graph_legend_widgets, lengthof(_nested_graph_legend_widgets)
 
	NULL, _nested_graph_legend_widgets, lengthof(_nested_graph_legend_widgets)
 
);
 

	
 
static void ShowGraphLegend()
 
{
 
	AllocateWindowDescFront<GraphLegendWindow>(&_graph_legend_desc, 0);
 
}
 

	
 
/******************/
 
/* BASE OF GRAPHS */
 
/*****************/
 

	
 
/** Widget numbers of a base graph window. */
 
enum CompanyValueWidgets {
 
	BGW_CLOSEBOX,
 
	BGW_CAPTION,
 
	BGW_KEY_BUTTON,
 
	BGW_BACKGROUND,
 
};
 

	
 
struct BaseGraphWindow : Window {
 
protected:
 
	enum {
 
		GRAPH_MAX_DATASETS = 32,
 
		GRAPH_AXIS_LINE_COLOUR  = 215,
 

	
 
		GRAPH_X_POSITION_BEGINNING  = 44,  ///< Start the graph 44 pixels from gd_left
 
		GRAPH_X_POSITION_SEPARATION = 22,  ///< There are 22 pixels between each X value
 

	
 
		GRAPH_NUM_LINES_Y = 9, ///< How many horizontal lines to draw.
 
		/* 9 is convenient as that means the distance between them is the gd_height of the graph / 8,
 
		 * which is the same
 
		 * as height >> 3. */
 
	};
 

	
 
	uint excluded_data; ///< bitmask of the datasets that shouldn't be displayed.
 
	byte num_dataset;
 
	byte num_on_x_axis;
 
	bool has_negative_values;
 
	byte num_vert_lines;
 
	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.
 
	StringID format_str_y_axis;
 
	byte colours[GRAPH_MAX_DATASETS];
 
	OverflowSafeInt64 cost[GRAPH_MAX_DATASETS][24]; ///< last 2 years
 

	
 
	void DrawGraph() 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;
 

	
 
		/* 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;
 

	
 
		for (int i = 0; i < this->num_vert_lines; i++) {
 
			GfxFillRect(x, this->gd_top, x, 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;
 

	
 
		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));
 
		}
 

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

	
0 comments (0 inline, 0 general)