File diff r26252:4aac4994c704 → r26253:da15255c652b
src/company_gui.cpp
Show inline comments
 
@@ -51,53 +51,33 @@
 
/** Company GUI constants. */
 
static const uint EXP_LINESPACE  = 2;      ///< Amount of vertical space for a horizontal (sub-)total line.
 
static const uint EXP_BLOCKSPACE = 10;     ///< Amount of vertical space between two blocks of numbers.
 
static const int  EXP_INDENT     = 10;     ///< Amount of horizontal space for an indented line.
 

	
 
static void DoSelectCompanyManagerFace(Window *parent);
 
static void ShowCompanyInfrastructure(CompanyID company);
 

	
 
/** Standard unsorted list of expenses. */
 
static ExpensesType _expenses_list_1[] = {
 
	EXPENSES_CONSTRUCTION,
 
	EXPENSES_NEW_VEHICLES,
 
	EXPENSES_TRAIN_RUN,
 
	EXPENSES_ROADVEH_RUN,
 
	EXPENSES_AIRCRAFT_RUN,
 
	EXPENSES_SHIP_RUN,
 
	EXPENSES_PROPERTY,
 
	EXPENSES_TRAIN_INC,
 
	EXPENSES_ROADVEH_INC,
 
	EXPENSES_AIRCRAFT_INC,
 
	EXPENSES_SHIP_INC,
 
	EXPENSES_LOAN_INT,
 
	EXPENSES_OTHER,
 
	EXPENSES_T_TRAIN_CON,
 
	EXPENSES_T_ROAD_CON,
 
	EXPENSES_T_AIRCRAFT_CON,
 
	EXPENSES_T_SHIP_CON,
 
	EXPENSES_T_TREES_CON,
 
	EXPENSES_T_SCENERY_CON,
 
	EXPENSES_T_LANDSCAPING,
 
	EXPENSES_T_DEMOLITION,
 
/** List of revenues. */
 
static ExpensesType _expenses_list_revenue[] = {
 
	EXPENSES_TRAIN_REVENUE,
 
	EXPENSES_ROADVEH_REVENUE,
 
	EXPENSES_AIRCRAFT_REVENUE,
 
	EXPENSES_SHIP_REVENUE,
 
	EXPENSES_T_REWARD_INC,
 
	EXPENSES_T_DILAPIDATION,
 
};
 

	
 
/** Grouped list of expenses. */
 
static ExpensesType _expenses_list_2[] = {
 
	EXPENSES_TRAIN_INC,
 
	EXPENSES_ROADVEH_INC,
 
	EXPENSES_AIRCRAFT_INC,
 
	EXPENSES_SHIP_INC,
 
	EXPENSES_T_REWARD_INC,
 
	INVALID_EXPENSES,
 
/** List of operating expenses. */
 
static ExpensesType _expenses_list_operating_costs[] = {
 
	EXPENSES_TRAIN_RUN,
 
	EXPENSES_ROADVEH_RUN,
 
	EXPENSES_AIRCRAFT_RUN,
 
	EXPENSES_SHIP_RUN,
 
	EXPENSES_PROPERTY,
 
	EXPENSES_T_DILAPIDATION,
 
	EXPENSES_LOAN_INT,
 
	INVALID_EXPENSES,
 
	EXPENSES_LOAN_INTEREST,
 
};
 

	
 
/** List of capital expenses. */
 
static ExpensesType _expenses_list_capital_costs[] = {
 
	EXPENSES_T_TRAIN_CON,
 
	EXPENSES_T_ROAD_CON,
 
	EXPENSES_T_AIRCRAFT_CON,
 
@@ -109,76 +89,128 @@ static ExpensesType _expenses_list_2[] =
 
	EXPENSES_T_LANDSCAPING,
 
	EXPENSES_T_DEMOLITION,
 
	EXPENSES_OTHER,
 
	INVALID_EXPENSES,
 
};
 

	
 
/** Expense list container. */
 
struct ExpensesList {
 
	const ExpensesType *et;   ///< Expenses items.
 
	const uint length;        ///< Number of items in list.
 
	const uint num_subtotals; ///< Number of sub-totals in the list.
 

	
 
	ExpensesList(ExpensesType *et, int length, int num_subtotals) : et(et), length(length), num_subtotals(num_subtotals)
 

	
 
	ExpensesList(ExpensesType *et, int length) : et(et), length(length)
 
	{
 
	}
 

	
 
	uint GetHeight() const
 
	{
 
		/* heading + line + texts of expenses + sub-totals + total line + total text */
 
		return FONT_HEIGHT_NORMAL + EXP_LINESPACE + this->length * FONT_HEIGHT_NORMAL + num_subtotals * (EXP_BLOCKSPACE + EXP_LINESPACE) + EXP_LINESPACE + FONT_HEIGHT_NORMAL;
 
		/* Add up the height of all the lines.  */
 
		return this->length * FONT_HEIGHT_NORMAL;
 
	}
 

	
 
	/** Compute width of the expenses categories in pixels. */
 
	uint GetCategoriesWidth() const
 
	uint GetListWidth() const
 
	{
 
		uint width = 0;
 
		bool invalid_expenses_measured = false; // Measure 'Total' width only once.
 
		for (uint i = 0; i < this->length; i++) {
 
			ExpensesType et = this->et[i];
 
			if (et == INVALID_EXPENSES) {
 
				if (!invalid_expenses_measured) {
 
					width = std::max(width, GetStringBoundingBox(STR_FINANCES_TOTAL_CAPTION).width);
 
					invalid_expenses_measured = true;
 
				}
 
			} else {
 
				width = std::max(width, GetStringBoundingBox(STR_FINANCES_SECTION_CONSTRUCTION + et).width);
 
			}
 
			width = std::max(width, GetStringBoundingBox(STR_FINANCES_SECTION_CONSTRUCTION + et).width);
 
		}
 
		return width;
 
	}
 
};
 

	
 
/** Types of expense lists */
 
static const ExpensesList _expenses_list_types[] = {
 
	ExpensesList(_expenses_list_1, lengthof(_expenses_list_1), 0),
 
	ExpensesList(_expenses_list_2, lengthof(_expenses_list_2), 3),
 
	ExpensesList(_expenses_list_revenue, lengthof(_expenses_list_revenue)),
 
	ExpensesList(_expenses_list_operating_costs, lengthof(_expenses_list_operating_costs)),
 
	ExpensesList(_expenses_list_capital_costs, lengthof(_expenses_list_capital_costs)),
 
};
 

	
 
/**
 
 * Get the total height of the "categories" column.
 
 * @return The total height in pixels.
 
 */
 
static uint GetTotalCategoriesHeight()
 
{
 
	/* There's an empty line and blockspace on the year row */
 
	uint total_height = FONT_HEIGHT_NORMAL + EXP_BLOCKSPACE;
 

	
 
	for (uint i = 0; i < lengthof(_expenses_list_types); i++) {
 
		/* Title + expense list + total line + total + blockspace after category */
 
		total_height += FONT_HEIGHT_NORMAL + _expenses_list_types[i].GetHeight() + EXP_LINESPACE + FONT_HEIGHT_NORMAL + EXP_BLOCKSPACE;
 
	}
 

	
 
	/* Total income */
 
	total_height += EXP_LINESPACE + FONT_HEIGHT_NORMAL + EXP_BLOCKSPACE;
 

	
 
	return total_height;
 
}
 

	
 
/**
 
 * Get the required width of the "categories" column, equal to the widest element.
 
 * @return The required width in pixels.
 
 */
 
static uint GetMaxCategoriesWidth()
 
{
 
	uint max_width = 0;
 

	
 
	/* Loop through categories to check max widths. */
 
	for (uint i = 0; i < lengthof(_expenses_list_types); i++) {
 
		/* Title of category */
 
		max_width = std::max(max_width, GetStringBoundingBox(STR_FINANCES_REVENUE_TITLE + i).width);
 
		/* Entries in category */
 
		max_width = std::max(max_width, _expenses_list_types[i].GetListWidth());
 
	}
 

	
 
	return max_width;
 
}
 

	
 
/**
 
 * Draw a category of expenses (revenue, operating expenses, capital expenses).
 
 */
 
static void DrawCategory(const Rect &r, int start_y, ExpensesList list)
 
{
 
	int offs_left = _current_text_dir == TD_LTR ? EXP_INDENT : 0;
 
	int offs_right = _current_text_dir == TD_LTR ? 0 : EXP_INDENT;
 

	
 
	int y = start_y;
 
	ExpensesType et;
 

	
 
	for (uint i = 0; i < list.length; i++) {
 
		et = list.et[i];
 
		DrawString(r.left + offs_left, r.right - offs_right, y, STR_FINANCES_SECTION_CONSTRUCTION + et);
 
		y += FONT_HEIGHT_NORMAL;
 
	}
 
}
 

	
 
/**
 
 * Draw the expenses categories.
 
 * @param r Available space for drawing.
 
 * @note The environment must provide padding at the left and right of \a r.
 
 */
 
static void DrawCategories(const Rect &r)
 
{
 
	int y = r.top;
 

	
 
	DrawString(r.left, r.right, y, STR_FINANCES_EXPENDITURE_INCOME_TITLE, TC_FROMSTRING, SA_HOR_CENTER, true);
 
	y += FONT_HEIGHT_NORMAL + EXP_LINESPACE;
 

	
 
	int type = _settings_client.gui.expenses_layout;
 
	for (uint i = 0; i < _expenses_list_types[type].length; i++) {
 
		const ExpensesType et = _expenses_list_types[type].et[i];
 
		if (et == INVALID_EXPENSES) {
 
			y += EXP_LINESPACE;
 
			DrawString(r.left, r.right, y, STR_FINANCES_TOTAL_CAPTION, TC_FROMSTRING, SA_RIGHT);
 
			y += FONT_HEIGHT_NORMAL + EXP_BLOCKSPACE;
 
		} else {
 
			DrawString(r.left, r.right, y, STR_FINANCES_SECTION_CONSTRUCTION + et);
 
			y += FONT_HEIGHT_NORMAL;
 
		}
 
	/* Start with an empty space in the year row, plus the blockspace under the year. */
 
	int y = r.top + FONT_HEIGHT_NORMAL + EXP_BLOCKSPACE;
 

	
 
	for (uint i = 0; i < lengthof(_expenses_list_types); i++) {
 
		/* Draw category title and advance y */
 
		DrawString(r.left, r.right, y, (STR_FINANCES_REVENUE_TITLE + i), TC_FROMSTRING, SA_LEFT);
 
		y += FONT_HEIGHT_NORMAL;
 

	
 
		/* Draw category items and advance y */
 
		DrawCategory(r, y, _expenses_list_types[i]);
 
		y += _expenses_list_types[i].GetHeight();
 

	
 
		/* Advance y by the height of the total and associated total line */
 
		y += EXP_LINESPACE + FONT_HEIGHT_NORMAL;
 

	
 
		/* Advance y by a blockspace after this category block */
 
		y += EXP_BLOCKSPACE;
 
	}
 

	
 
	DrawString(r.left, r.right, y + EXP_LINESPACE, STR_FINANCES_TOTAL_CAPTION, TC_FROMSTRING, SA_RIGHT);
 
	/* Draw total profit/loss */
 
	y += EXP_LINESPACE;
 
	DrawString(r.left, r.right, y, STR_FINANCES_NET_PROFIT, TC_FROMSTRING, SA_LEFT);
 
}
 

	
 
/**
 
@@ -187,8 +219,9 @@ static void DrawCategories(const Rect &r
 
 * @param left   Left coordinate of the space to draw in.
 
 * @param right  Right coordinate of the space to draw in.
 
 * @param top    Top coordinate of the space to draw in.
 
 * @param colour The TextColour of the string.
 
 */
 
static void DrawPrice(Money amount, int left, int right, int top)
 
static void DrawPrice(Money amount, int left, int right, int top, TextColour colour)
 
{
 
	StringID str = STR_FINANCES_NEGATIVE_INCOME;
 
	if (amount < 0) {
 
@@ -196,10 +229,38 @@ static void DrawPrice(Money amount, int 
 
		str++;
 
	}
 
	SetDParam(0, amount);
 
	DrawString(left, right, top, str, TC_FROMSTRING, SA_RIGHT);
 
	DrawString(left, right, top, str, colour, SA_RIGHT);
 
}
 

	
 
/**
 
 * Draw a category of expenses/revenues in the year column.
 
 * @return The income sum of the category.
 
 */
 
static Money DrawYearCategory (const Rect &r, int start_y, ExpensesList list, const Money(*tbl)[EXPENSES_END])
 
{
 
	int y = start_y;
 
	ExpensesType et;
 
	Money sum = 0;
 

	
 
	for (uint i = 0; i < list.length; i++) {
 
		et = list.et[i];
 
		Money cost = (*tbl)[et];
 
		sum += cost;
 
		if (cost != 0) DrawPrice(cost, r.left, r.right, y, TC_BLACK);
 
		y += FONT_HEIGHT_NORMAL;
 
	}
 

	
 
	/* Draw the total at the bottom of the category. */
 
	GfxFillRect(r.left, y, r.right, y, PC_BLACK);
 
	y += EXP_LINESPACE;
 
	if (sum != 0) DrawPrice(sum, r.left, r.right, y, TC_WHITE);
 

	
 
	/* Return the sum for the yearly total. */
 
	return sum;
 
}
 

	
 

	
 
/**
 
 * Draw a column with prices.
 
 * @param r    Available space for drawing.
 
 * @param year Year being drawn.
 
@@ -209,35 +270,25 @@ static void DrawPrice(Money amount, int 
 
static void DrawYearColumn(const Rect &r, int year, const Money (*tbl)[EXPENSES_END])
 
{
 
	int y = r.top;
 

	
 
	Money sum;
 

	
 
	/* Year header */
 
	SetDParam(0, year);
 
	DrawString(r.left, r.right, y, STR_FINANCES_YEAR, TC_FROMSTRING, SA_RIGHT, true);
 
	y += FONT_HEIGHT_NORMAL + EXP_LINESPACE;
 

	
 
	Money sum = 0;
 
	Money subtotal = 0;
 
	int type = _settings_client.gui.expenses_layout;
 
	for (uint i = 0; i < _expenses_list_types[type].length; i++) {
 
		const ExpensesType et = _expenses_list_types[type].et[i];
 
		if (et == INVALID_EXPENSES) {
 
			Money cost = subtotal;
 
			subtotal = 0;
 
			GfxFillRect(r.left, y, r.right, y, PC_BLACK);
 
			y += EXP_LINESPACE;
 
			DrawPrice(cost, r.left, r.right, y);
 
			y += FONT_HEIGHT_NORMAL + EXP_BLOCKSPACE;
 
		} else {
 
			Money cost = (*tbl)[et];
 
			subtotal += cost;
 
			sum += cost;
 
			if (cost != 0) DrawPrice(cost, r.left, r.right, y);
 
			y += FONT_HEIGHT_NORMAL;
 
		}
 
	y += FONT_HEIGHT_NORMAL + EXP_BLOCKSPACE;
 

	
 
	/* Categories */
 
	for (uint i = 0; i < lengthof(_expenses_list_types); i++) {
 
		y += FONT_HEIGHT_NORMAL;
 
		sum += DrawYearCategory(r, y, _expenses_list_types[i], tbl);
 
		/* Expense list + expense category title + expense category total + blockspace after category */
 
		y += _expenses_list_types[i].GetHeight() + EXP_LINESPACE + FONT_HEIGHT_NORMAL + EXP_BLOCKSPACE;
 
	}
 

	
 
	/* Total income. */
 
	GfxFillRect(r.left, y, r.right, y, PC_BLACK);
 
	y += EXP_LINESPACE;
 
	DrawPrice(sum, r.left, r.right, y);
 
	DrawPrice(sum, r.left, r.right, y, TC_WHITE);
 
}
 

	
 
static const NWidgetPart _nested_company_finances_widgets[] = {
 
@@ -261,22 +312,24 @@ static const NWidgetPart _nested_company
 
	NWidget(WWT_PANEL, COLOUR_GREY),
 
		NWidget(NWID_HORIZONTAL), SetPadding(WD_FRAMERECT_TOP, WD_FRAMERECT_RIGHT, WD_FRAMERECT_BOTTOM, WD_FRAMERECT_LEFT),
 
			NWidget(NWID_VERTICAL), // Vertical column with 'bank balance', 'loan'
 
				NWidget(WWT_TEXT, COLOUR_GREY), SetDataTip(STR_FINANCES_OWN_FUNDS_TITLE, STR_NULL), SetFill(1, 0),
 
				NWidget(WWT_TEXT, COLOUR_GREY), SetDataTip(STR_FINANCES_LOAN_TITLE, STR_NULL), SetFill(1, 0),
 
				NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetFill(1, 0),
 
				NWidget(WWT_TEXT, COLOUR_GREY), SetDataTip(STR_FINANCES_BANK_BALANCE_TITLE, STR_NULL), SetFill(1, 0),
 
				NWidget(WWT_TEXT, COLOUR_GREY), SetDataTip(STR_FINANCES_LOAN_TITLE, STR_NULL), SetFill(1, 0),
 
				NWidget(NWID_SPACER), SetFill(0, 1),
 
			EndContainer(),
 
			NWidget(NWID_SPACER), SetFill(0, 0), SetMinimalSize(30, 0),
 
			NWidget(NWID_VERTICAL), // Vertical column with bank balance amount, loan amount, and total.
 
				NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_BALANCE_VALUE), SetDataTip(STR_FINANCES_TOTAL_CURRENCY, STR_NULL), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
 
				NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_OWN_VALUE), SetDataTip(STR_FINANCES_TOTAL_CURRENCY, STR_NULL), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
 
				NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_LOAN_VALUE), SetDataTip(STR_FINANCES_TOTAL_CURRENCY, STR_NULL), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
 
				NWidget(WWT_EMPTY, COLOUR_GREY, WID_CF_LOAN_LINE), SetMinimalSize(0, 2), SetFill(1, 0),
 
				NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_TOTAL_VALUE), SetDataTip(STR_FINANCES_TOTAL_CURRENCY, STR_NULL), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
 
				NWidget(WWT_EMPTY, COLOUR_GREY, WID_CF_BALANCE_LINE), SetMinimalSize(0, 2), SetFill(1, 0),
 
				NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_BALANCE_VALUE), SetDataTip(STR_FINANCES_TOTAL_CURRENCY, STR_NULL), SetAlignment(SA_VERT_CENTER | SA_RIGHT),
 
			EndContainer(),
 
			NWidget(NWID_SELECTION, INVALID_COLOUR, WID_CF_SEL_MAXLOAN),
 
				NWidget(NWID_HORIZONTAL),
 
					NWidget(NWID_SPACER), SetFill(0, 1), SetMinimalSize(25, 0),
 
					NWidget(NWID_VERTICAL), // Max loan information
 
						NWidget(WWT_EMPTY, COLOUR_GREY, WID_CF_MAXLOAN_GAP), SetFill(0, 0),
 
						NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_INTEREST_RATE), SetDataTip(STR_FINANCES_INTEREST_RATE, STR_NULL),
 
						NWidget(WWT_TEXT, COLOUR_GREY, WID_CF_MAXLOAN_VALUE), SetDataTip(STR_FINANCES_MAX_LOAN, STR_NULL),
 
						NWidget(NWID_SPACER), SetFill(0, 1),
 
					EndContainer(),
 
@@ -329,12 +382,16 @@ struct CompanyFinancesWindow : Window {
 
				break;
 
			}
 

	
 
			case WID_CF_TOTAL_VALUE: {
 
			case WID_CF_OWN_VALUE: {
 
				const Company *c = Company::Get((CompanyID)this->window_number);
 
				SetDParam(0, c->money - c->current_loan);
 
				break;
 
			}
 

	
 
			case WID_CF_INTEREST_RATE:
 
				SetDParam(0, _settings_game.difficulty.initial_interest);
 
				break;
 

	
 
			case WID_CF_MAXLOAN_VALUE:
 
				SetDParam(0, _economy.max_loan);
 
				break;
 
@@ -348,27 +405,26 @@ struct CompanyFinancesWindow : Window {
 

	
 
	void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
 
	{
 
		int type = _settings_client.gui.expenses_layout;
 
		switch (widget) {
 
			case WID_CF_EXPS_CATEGORY:
 
				size->width  = _expenses_list_types[type].GetCategoriesWidth();
 
				size->height = _expenses_list_types[type].GetHeight();
 
				size->width  = GetMaxCategoriesWidth();
 
				size->height = GetTotalCategoriesHeight();
 
				break;
 

	
 
			case WID_CF_EXPS_PRICE1:
 
			case WID_CF_EXPS_PRICE2:
 
			case WID_CF_EXPS_PRICE3:
 
				size->height = _expenses_list_types[type].GetHeight();
 
				size->height = GetTotalCategoriesHeight();
 
				FALLTHROUGH;
 

	
 
			case WID_CF_BALANCE_VALUE:
 
			case WID_CF_LOAN_VALUE:
 
			case WID_CF_TOTAL_VALUE:
 
			case WID_CF_OWN_VALUE:
 
				SetDParamMaxValue(0, CompanyFinancesWindow::max_money);
 
				size->width = std::max(GetStringBoundingBox(STR_FINANCES_NEGATIVE_INCOME).width, GetStringBoundingBox(STR_FINANCES_POSITIVE_INCOME).width) + padding.width;
 
				break;
 

	
 
			case WID_CF_MAXLOAN_GAP:
 
			case WID_CF_INTEREST_RATE:
 
				size->height = FONT_HEIGHT_NORMAL;
 
				break;
 
		}
 
@@ -393,7 +449,7 @@ struct CompanyFinancesWindow : Window {
 
				break;
 
			}
 

	
 
			case WID_CF_LOAN_LINE:
 
			case WID_CF_BALANCE_LINE:
 
				GfxFillRect(r.left, r.top, r.right, r.top, PC_BLACK);
 
				break;
 
		}
 
@@ -419,8 +475,7 @@ struct CompanyFinancesWindow : Window {
 
		if (!this->IsShaded()) {
 
			if (!this->small) {
 
				/* Check that the expenses panel height matches the height needed for the layout. */
 
				int type = _settings_client.gui.expenses_layout;
 
				if (_expenses_list_types[type].GetHeight() != this->GetWidget<NWidgetBase>(WID_CF_EXPS_CATEGORY)->current_y) {
 
				if (GetTotalCategoriesHeight() != this->GetWidget<NWidgetBase>(WID_CF_EXPS_CATEGORY)->current_y) {
 
					this->SetupWidgets();
 
					this->ReInit();
 
					return;