changeset 18565:021a10db1a99 draft

(svn r23410) -Add: A window with a detailed overview over the infrastructure of a company.
author michi_cc <michi_cc@openttd.org>
date Sat, 03 Dec 2011 23:40:08 +0000
parents 8f049145265b
children 9b9dc36d3eb2
files src/company_base.h src/company_gui.cpp src/company_gui.h src/lang/english.txt src/saveload/afterload.cpp src/window.cpp src/window_type.h
diffstat 7 files changed, 413 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/company_base.h
+++ b/src/company_base.h
@@ -30,6 +30,15 @@
 	Money company_value;
 };
 
+struct CompanyInfrastructure {
+	uint32 road[ROADTYPE_END]; ///< Count of company owned track bits for each road type.
+	uint32 signal;             ///< Count of company owned signals.
+	uint32 rail[RAILTYPE_END]; ///< Count of company owned track bits for each rail type.
+	uint32 water;              ///< Count of company owned track bits for canals.
+	uint32 station;            ///< Count of company owned station tiles.
+	uint32 airport;            ///< Count of company owned airports.
+};
+
 typedef Pool<Company, CompanyByte, 1, MAX_COMPANIES> CompanyPool;
 extern CompanyPool _company_pool;
 
@@ -108,6 +117,8 @@
 	GroupStatistics group_all[VEH_COMPANY_END];      ///< NOSAVE: Statistics for the ALL_GROUP group.
 	GroupStatistics group_default[VEH_COMPANY_END];  ///< NOSAVE: Statistics for the DEFAULT_GROUP group.
 
+	CompanyInfrastructure infrastructure; ///< NOSAVE: Counts of company owned infrastructure.
+
 	/**
 	 * Is this company a valid company, controlled by the computer (a NoAI program)?
 	 * @param index Index in the pool.
--- a/src/company_gui.cpp
+++ b/src/company_gui.cpp
@@ -31,6 +31,9 @@
 #include "core/geometry_func.hpp"
 #include "economy_func.h"
 #include "object_type.h"
+#include "rail.h"
+#include "engine_base.h"
+#include "window_func.h"
 
 #include "table/strings.h"
 
@@ -39,6 +42,7 @@
 static const uint EXP_BLOCKSPACE = 10;     ///< Amount of vertical space between two blocks of numbers.
 
 static void DoSelectCompanyManagerFace(Window *parent);
+static void ShowCompanyInfrastructure(CompanyID company);
 
 /** Standard unsorted list of expenses. */
 static ExpensesType _expenses_list_1[] = {
@@ -138,6 +142,7 @@
 	CFW_SEL_BUTTONS,   ///< Selection of buttons
 	CFW_INCREASE_LOAN, ///< Increase loan
 	CFW_REPAY_LOAN,    ///< Decrease loan
+	CFW_INFRASTRUCTURE,///< View company infrastructure
 };
 
 /**
@@ -276,6 +281,7 @@
 		NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
 			NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CFW_INCREASE_LOAN), SetFill(1, 0), SetDataTip(STR_FINANCES_BORROW_BUTTON, STR_FINANCES_BORROW_TOOLTIP),
 			NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CFW_REPAY_LOAN), SetFill(1, 0), SetDataTip(STR_FINANCES_REPAY_BUTTON, STR_FINANCES_REPAY_TOOLTIP),
+			NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CFW_INFRASTRUCTURE), SetFill(1, 0), SetDataTip(STR_FINANCES_INFRASTRUCTURE_BUTTON, STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP),
 		EndContainer(),
 	EndContainer(),
 };
@@ -457,6 +463,10 @@
 			case CFW_REPAY_LOAN: // repay loan
 				DoCommandP(0, 0, _ctrl_pressed, CMD_DECREASE_LOAN | CMD_MSG(STR_ERROR_CAN_T_REPAY_LOAN));
 				break;
+
+			case CFW_INFRASTRUCTURE: // show infrastructure details
+				ShowCompanyInfrastructure((CompanyID)this->window_number);
+				break;
 		}
 	}
 
@@ -1603,6 +1613,286 @@
 }
 
 
+/** Names of the widgets of the #CompanyInfrastructureWindow. */
+enum CompanyInfrastructureWindowWidgets {
+	CIW_WIDGET_CAPTION,
+	CIW_WIDGET_RAIL_DESC,
+	CIW_WIDGET_RAIL_COUNT,
+	CIW_WIDGET_ROAD_DESC,
+	CIW_WIDGET_ROAD_COUNT,
+	CIW_WIDGET_WATER_DESC,
+	CIW_WIDGET_WATER_COUNT,
+	CIW_WIDGET_STATION_DESC,
+	CIW_WIDGET_STATION_COUNT,
+};
+
+static const NWidgetPart _nested_company_infrastructure_widgets[] = {
+	NWidget(NWID_HORIZONTAL),
+		NWidget(WWT_CLOSEBOX, COLOUR_GREY),
+		NWidget(WWT_CAPTION, COLOUR_GREY, CIW_WIDGET_CAPTION), SetDataTip(STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
+		NWidget(WWT_SHADEBOX, COLOUR_GREY),
+		NWidget(WWT_STICKYBOX, COLOUR_GREY),
+	EndContainer(),
+	NWidget(WWT_PANEL, COLOUR_GREY),
+		NWidget(NWID_VERTICAL), SetPIP(WD_FRAMERECT_TOP, 4, WD_FRAMETEXT_BOTTOM),
+			NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
+				NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_RAIL_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0),
+				NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_RAIL_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1),
+			EndContainer(),
+			NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
+				NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_ROAD_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0),
+				NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_ROAD_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1),
+			EndContainer(),
+			NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
+				NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_WATER_DESC), SetMinimalTextLines(2, 0), SetFill(1, 0),
+				NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_WATER_COUNT), SetMinimalTextLines(2, 0), SetFill(0, 1),
+			EndContainer(),
+			NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
+				NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_STATION_DESC), SetMinimalTextLines(3, 0), SetFill(1, 0),
+				NWidget(WWT_EMPTY, COLOUR_GREY, CIW_WIDGET_STATION_COUNT), SetMinimalTextLines(3, 0), SetFill(0, 1),
+			EndContainer(),
+		EndContainer(),
+	EndContainer(),
+};
+
+/**
+ * Window with detailed information about the company's infrastructure.
+ */
+struct CompanyInfrastructureWindow : Window
+{
+	RailTypes railtypes; ///< Valid railtypes.
+	RoadTypes roadtypes; ///< Valid roadtypes.
+
+	CompanyInfrastructureWindow(const WindowDesc *desc, WindowNumber window_number) : Window()
+	{
+		this->UpdateRailRoadTypes();
+
+		this->InitNested(desc, window_number);
+		this->owner = (Owner)this->window_number;
+	}
+
+	void UpdateRailRoadTypes()
+	{
+		this->railtypes = RAILTYPES_NONE;
+		this->roadtypes = ROADTYPES_ROAD; // Road is always available.
+
+		/* Find the used railtypes. */
+		Engine *e;
+		FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) {
+			if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue;
+
+			this->railtypes |= GetRailTypeInfo(e->u.rail.railtype)->introduces_railtypes;
+		}
+
+		/* Get the date introduced railtypes as well. */
+		this->railtypes = AddDateIntroducedRailTypes(this->railtypes, MAX_DAY);
+
+		/* Tram is only visible when there will be a tram. */
+		FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) {
+			if (!HasBit(e->info.climates, _settings_game.game_creation.landscape)) continue;
+			if (!HasBit(e->info.misc_flags, EF_ROAD_TRAM)) continue;
+
+			this->roadtypes |= ROADTYPES_TRAM;
+			break;
+		}
+	}
+
+	virtual void SetStringParameters(int widget) const
+	{
+		switch (widget) {
+			case CIW_WIDGET_CAPTION:
+				SetDParam(0, (CompanyID)this->window_number);
+				break;
+		}
+	}
+
+	virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
+	{
+		const Company *c = Company::Get((CompanyID)this->window_number);
+
+		switch (widget) {
+			case CIW_WIDGET_RAIL_DESC: {
+				uint lines = 1;
+
+				for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) {
+					if (HasBit(this->railtypes, rt)) {
+						lines++;
+						SetDParam(0, GetRailTypeInfo(rt)->strings.name);
+						size->width = max(size->width, GetStringBoundingBox(STR_WHITE_STRING).width + WD_FRAMERECT_LEFT);
+					}
+				}
+				if (this->railtypes != RAILTYPES_NONE) {
+					lines++;
+					size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS).width + WD_FRAMERECT_LEFT);
+				}
+
+				size->height = max(size->height, lines * FONT_HEIGHT_NORMAL);
+				break;
+			}
+
+			case CIW_WIDGET_ROAD_DESC: {
+				uint lines = 1;
+
+				if (HasBit(this->roadtypes, ROADTYPE_ROAD)) {
+					lines++;
+					size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD).width + WD_FRAMERECT_LEFT);
+				}
+				if (HasBit(this->roadtypes, ROADTYPE_TRAM)) {
+					lines++;
+					size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY).width + WD_FRAMERECT_LEFT);
+				}
+
+				size->height = max(size->height, lines * FONT_HEIGHT_NORMAL);
+				break;
+			}
+
+			case CIW_WIDGET_RAIL_COUNT:
+			case CIW_WIDGET_ROAD_COUNT:
+			case CIW_WIDGET_WATER_COUNT:
+			case CIW_WIDGET_STATION_COUNT: {
+				/* Find the maximum count that is displayed. */
+				uint32 max_val = 100000; // Some random number to reserve enough space.
+				for (RailType rt = RAILTYPE_BEGIN; rt < RAILTYPE_END; rt++) {
+					max_val = max(max_val, c->infrastructure.rail[rt]);
+				}
+				max_val = max(max_val, c->infrastructure.signal);
+				for (RoadType rt = ROADTYPE_BEGIN; rt < ROADTYPE_END; rt++) {
+					max_val = max(max_val, c->infrastructure.road[rt]);
+				}
+				max_val = max(max_val, c->infrastructure.water);
+				max_val = max(max_val, c->infrastructure.station);
+				max_val = max(max_val, c->infrastructure.airport);
+
+				SetDParam(0, max_val);
+				size->width = max(size->width, GetStringBoundingBox(STR_WHITE_COMMA).width + 15); // Reserve some wiggle room.
+				break;
+			}
+		}
+	}
+
+	virtual void DrawWidget(const Rect &r, int widget) const
+	{
+		const Company *c = Company::Get((CompanyID)this->window_number);
+		int y = r.top;
+
+		int offs_left = _current_text_dir == TD_LTR ? WD_FRAMERECT_LEFT : 0;
+		int offs_right = _current_text_dir == TD_LTR ? 0 : WD_FRAMERECT_LEFT;
+
+		switch (widget) {
+			case CIW_WIDGET_RAIL_DESC:
+				DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT);
+
+				if (this->railtypes != RAILTYPES_NONE) {
+					/* Draw name of each valid railtype. */
+					for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
+						if (HasBit(this->railtypes, rt)) {
+							SetDParam(0, GetRailTypeInfo(rt)->strings.name);
+							DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_WHITE_STRING);
+						}
+					}
+					DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS);
+				} else {
+					/* No valid railtype. */
+					DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE);
+				}
+
+				break;
+
+			case CIW_WIDGET_RAIL_COUNT:
+				/* Draw infrastructure count for each valid railtype. */
+				for (RailType rt = RAILTYPE_BEGIN; rt != RAILTYPE_END; rt++) {
+					if (HasBit(this->railtypes, rt)) {
+						SetDParam(0, c->infrastructure.rail[rt]);
+						DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, STR_WHITE_COMMA);
+					}
+				}
+				if (this->railtypes != RAILTYPES_NONE) {
+					SetDParam(0, c->infrastructure.signal);
+					DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, STR_WHITE_COMMA);
+				}
+				break;
+
+			case CIW_WIDGET_ROAD_DESC:
+				DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT);
+
+				if (this->roadtypes != ROADTYPES_NONE) {
+					if (HasBit(this->roadtypes, ROADTYPE_ROAD)) DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD);
+					if (HasBit(this->roadtypes, ROADTYPE_TRAM)) DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY);
+				} else {
+					/* No valid roadtypes. */
+					DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE);
+				}
+
+				break;
+
+			case CIW_WIDGET_ROAD_COUNT:
+				if (HasBit(this->roadtypes, ROADTYPE_ROAD)) {
+					SetDParam(0, c->infrastructure.road[ROADTYPE_ROAD]);
+					DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, STR_WHITE_COMMA);
+				}
+				if (HasBit(this->roadtypes, ROADTYPE_TRAM)) {
+					SetDParam(0, c->infrastructure.road[ROADTYPE_TRAM]);
+					DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, STR_WHITE_COMMA);
+				}
+				break;
+
+			case CIW_WIDGET_WATER_DESC:
+				DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT);
+				DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS);
+				break;
+
+			case CIW_WIDGET_WATER_COUNT:
+				SetDParam(0, c->infrastructure.water);
+				DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, STR_WHITE_COMMA);
+				break;
+
+			case CIW_WIDGET_STATION_DESC:
+				DrawString(r.left, r.right, y, STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT);
+				DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS);
+				DrawString(r.left + offs_left, r.right - offs_right, y += FONT_HEIGHT_NORMAL, STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS);
+				break;
+
+			case CIW_WIDGET_STATION_COUNT:
+				SetDParam(0, c->infrastructure.station);
+				DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, STR_WHITE_COMMA);
+				SetDParam(0, c->infrastructure.airport);
+				DrawString(r.left, r.right, y += FONT_HEIGHT_NORMAL, STR_WHITE_COMMA);
+				break;
+		}
+	}
+
+	/**
+	 * Some data on this window has become invalid.
+	 * @param data Information about the changed data.
+	 * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
+	 */
+	virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
+	{
+		if (!gui_scope) return;
+
+		this->UpdateRailRoadTypes();
+		this->ReInit();
+	}
+};
+
+static const WindowDesc _company_infrastructure_desc(
+	WDP_AUTO, 0, 0,
+	WC_COMPANY_INFRASTRUCTURE, WC_NONE,
+	WDF_UNCLICK_BUTTONS,
+	_nested_company_infrastructure_widgets, lengthof(_nested_company_infrastructure_widgets)
+);
+
+/**
+ * Open the infrastructure window of a company.
+ * @param company Company to show infrastructure of.
+ */
+static void ShowCompanyInfrastructure(CompanyID company)
+{
+	if (!Company::IsValidID(company)) return;
+	AllocateWindowDescFront<CompanyInfrastructureWindow>(&_company_infrastructure_desc, company);
+}
+
+
 /** Names of the widgets of the #CompanyWindow. Keep them in the same order as in the widget array */
 enum CompanyWindowWidgets {
 	CW_WIDGET_CAPTION,
@@ -1616,6 +1906,8 @@
 	CW_WIDGET_DESC_VEHICLE,
 	CW_WIDGET_DESC_VEHICLE_COUNTS,
 	CW_WIDGET_DESC_COMPANY_VALUE,
+	CW_WIDGET_DESC_INFRASTRUCTURE,
+	CW_WIDGET_DESC_INFRASTRUCTURE_COUNTS,
 	CW_WIDGET_DESC_OWNERS,
 
 	CW_WIDGET_SELECT_BUTTONS,     ///< Selection widget for the button bar.
@@ -1633,6 +1925,8 @@
 	CW_WIDGET_SELECT_RELOCATE,    ///< View/hide the 'Relocate HQ' button.
 	CW_WIDGET_RELOCATE_HQ,
 
+	CW_WIDGET_VIEW_INFRASTRUCTURE,
+
 	CW_WIDGET_HAS_PASSWORD,       ///< Draw a lock when the company has a password
 	CW_WIDGET_SELECT_MULTIPLAYER, ///< Multiplayer selection panel.
 	CW_WIDGET_COMPANY_PASSWORD,
@@ -1683,6 +1977,19 @@
 					EndContainer(),
 				EndContainer(),
 				NWidget(WWT_TEXT, COLOUR_GREY, CW_WIDGET_DESC_COMPANY_VALUE), SetDataTip(STR_COMPANY_VIEW_COMPANY_VALUE, STR_NULL), SetFill(1, 0),
+					NWidget(NWID_VERTICAL), SetPIP(4, 2, 4),
+						NWidget(NWID_HORIZONTAL), SetPIP(0, 4, 0),
+							NWidget(NWID_VERTICAL),
+								NWidget(WWT_TEXT, COLOUR_GREY, CW_WIDGET_DESC_INFRASTRUCTURE), SetDataTip(STR_COMPANY_VIEW_INFRASTRUCTURE, STR_NULL),
+								NWidget(NWID_SPACER), SetFill(0, 1),
+							EndContainer(),
+							NWidget(WWT_EMPTY, INVALID_COLOUR, CW_WIDGET_DESC_INFRASTRUCTURE_COUNTS), SetMinimalTextLines(5, 0), SetFill(1, 0),
+							NWidget(NWID_VERTICAL),
+								NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, CW_WIDGET_VIEW_INFRASTRUCTURE), SetDataTip(STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON, STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP),
+								NWidget(NWID_SPACER), SetFill(0, 1), SetMinimalSize(90, 0),
+							EndContainer(),
+						EndContainer(),
+					EndContainer(),
 				NWidget(NWID_HORIZONTAL),
 					NWidget(NWID_VERTICAL), SetPIP(5, 5, 4),
 						NWidget(WWT_EMPTY, INVALID_COLOUR, CW_WIDGET_DESC_OWNERS), SetMinimalTextLines(3, 0),
@@ -1857,6 +2164,16 @@
 				}
 				break;
 
+			case CW_WIDGET_DESC_INFRASTRUCTURE_COUNTS:
+				SetDParam(0, UINT_MAX);
+				size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL).width);
+				size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD).width);
+				size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_WATER).width);
+				size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_STATION).width);
+				size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT).width);
+				size->width = max(size->width, GetStringBoundingBox(STR_COMPANY_VIEW_INFRASTRUCTURE_NONE).width);
+				break;
+
 			case CW_WIDGET_DESC_OWNERS: {
 				const Company *c2;
 
@@ -1922,6 +2239,47 @@
 				break;
 			}
 
+			case CW_WIDGET_DESC_INFRASTRUCTURE_COUNTS: {
+				uint y = r.top;
+
+				/* Collect rail and road counts. */
+				uint rail_pices = c->infrastructure.signal;
+				uint road_pieces = 0;
+				for (uint i = 0; i < lengthof(c->infrastructure.rail); i++) rail_pices += c->infrastructure.rail[i];
+				for (uint i = 0; i < lengthof(c->infrastructure.road); i++) road_pieces += c->infrastructure.road[i];
+
+				if (rail_pices == 0 && road_pieces == 0 && c->infrastructure.water == 0 && c->infrastructure.station == 0 && c->infrastructure.airport == 0) {
+					DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_NONE);
+				} else {
+					if (rail_pices != 0) {
+						SetDParam(0, rail_pices);
+						DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL);
+						y += FONT_HEIGHT_NORMAL;
+					}
+					if (road_pieces != 0) {
+						SetDParam(0, road_pieces);
+						DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD);
+						y += FONT_HEIGHT_NORMAL;
+					}
+					if (c->infrastructure.water != 0) {
+						SetDParam(0, c->infrastructure.water);
+						DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_WATER);
+						y += FONT_HEIGHT_NORMAL;
+					}
+					if (c->infrastructure.station != 0) {
+						SetDParam(0, c->infrastructure.station);
+						DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_STATION);
+						y += FONT_HEIGHT_NORMAL;
+					}
+					if (c->infrastructure.airport != 0) {
+						SetDParam(0, c->infrastructure.airport);
+						DrawString(r.left, r.right, y, STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT);
+					}
+				}
+
+				break;
+			}
+
 			case CW_WIDGET_DESC_OWNERS: {
 				const Company *c2;
 				uint y = r.top;
@@ -2024,6 +2382,10 @@
 				this->SetWidgetDirty(CW_WIDGET_RELOCATE_HQ);
 				break;
 
+			case CW_WIDGET_VIEW_INFRASTRUCTURE:
+				ShowCompanyInfrastructure((CompanyID)this->window_number);
+				break;
+
 			case CW_WIDGET_BUY_SHARE:
 				DoCommandP(0, this->window_number, 0, CMD_BUY_SHARE_IN_COMPANY | CMD_MSG(STR_ERROR_CAN_T_BUY_25_SHARE_IN_THIS));
 				break;
@@ -2117,6 +2479,17 @@
 	AllocateWindowDescFront<CompanyWindow>(&_company_desc, company);
 }
 
+/**
+ * Redraw all windows with company infrastructure counts.
+ * @param company The company to redraw the windows of.
+ */
+void DirtyCompanyInfrastructureWindows(CompanyID company)
+{
+	SetWindowDirty(WC_COMPANY, company);
+	SetWindowDirty(WC_COMPANY_INFRASTRUCTURE, company);
+}
+
+
 /** widget numbers of the #BuyCompanyWindow. */
 enum BuyCompanyWidgets {
 	BCW_CAPTION,
--- a/src/company_gui.h
+++ b/src/company_gui.h
@@ -24,5 +24,6 @@
 
 void InvalidateCompanyWindows(const Company *c);
 void DeleteCompanyWindows(CompanyID company);
+void DirtyCompanyInfrastructureWindows(CompanyID company);
 
 #endif /* COMPANY_GUI_H */
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -2724,6 +2724,7 @@
 STR_FINANCES_BORROW_TOOLTIP                                     :{BLACK}Increase size of loan. Ctrl+Click borrows as much as possible
 STR_FINANCES_REPAY_BUTTON                                       :{BLACK}Repay {CURRENCY_LONG}
 STR_FINANCES_REPAY_TOOLTIP                                      :{BLACK}Repay part of loan. Ctrl+Click repays as much loan as possible
+STR_FINANCES_INFRASTRUCTURE_BUTTON                              :{BLACK}Infrastructure
 
 # Company view
 STR_COMPANY_VIEW_CAPTION                                        :{WHITE}{COMPANY} {BLACK}{COMPANY_NUM}
@@ -2739,6 +2740,13 @@
 STR_COMPANY_VIEW_VEHICLES_NONE                                  :{WHITE}None
 STR_COMPANY_VIEW_COMPANY_VALUE                                  :{GOLD}Company value: {WHITE}{CURRENCY_LONG}
 STR_COMPANY_VIEW_SHARES_OWNED_BY                                :{WHITE}({COMMA}% owned by {COMPANY})
+STR_COMPANY_VIEW_INFRASTRUCTURE                                 :{GOLD}Infrastructure:
+STR_COMPANY_VIEW_INFRASTRUCTURE_RAIL                            :{WHITE}{COMMA} rail pieces
+STR_COMPANY_VIEW_INFRASTRUCTURE_ROAD                            :{WHITE}{COMMA} road pieces
+STR_COMPANY_VIEW_INFRASTRUCTURE_WATER                           :{WHITE}{COMMA} water tiles
+STR_COMPANY_VIEW_INFRASTRUCTURE_STATION                         :{WHITE}{COMMA} station tiles
+STR_COMPANY_VIEW_INFRASTRUCTURE_AIRPORT                         :{WHITE}{COMMA} airports
+STR_COMPANY_VIEW_INFRASTRUCTURE_NONE                            :{WHITE}None
 
 STR_COMPANY_VIEW_BUILD_HQ_BUTTON                                :{BLACK}Build HQ
 STR_COMPANY_VIEW_BUILD_HQ_TOOLTIP                               :{BLACK}Build company headquarters
@@ -2746,6 +2754,8 @@
 STR_COMPANY_VIEW_VIEW_HQ_TOOLTIP                                :{BLACK}View company headquarters
 STR_COMPANY_VIEW_RELOCATE_HQ                                    :{BLACK}Relocate HQ
 STR_COMPANY_VIEW_RELOCATE_COMPANY_HEADQUARTERS                  :{BLACK}Rebuild company headquarters elsewhere for 1% cost of company value. Shift+Click shows estimated cost without relocating HQ
+STR_COMPANY_VIEW_INFRASTRUCTURE_BUTTON                          :{BLACK}Details
+STR_COMPANY_VIEW_INFRASTRUCTURE_TOOLTIP                         :{BLACK}View detailed infrastructure counts
 
 STR_COMPANY_VIEW_NEW_FACE_BUTTON                                :{BLACK}New Face
 STR_COMPANY_VIEW_NEW_FACE_TOOLTIP                               :{BLACK}Select new face for manager
@@ -2766,6 +2776,19 @@
 
 STR_BUY_COMPANY_MESSAGE                                         :{WHITE}We are looking for a transport company to take-over our company.{}{}Do you want to purchase {COMPANY} for {CURRENCY_LONG}?
 
+# Company infrastructure window
+STR_COMPANY_INFRASTRUCTURE_VIEW_CAPTION                         :{WHITE}Infrastructure of {COMPANY}
+STR_COMPANY_INFRASTRUCTURE_VIEW_RAIL_SECT                       :{GOLD}Rail pieces:
+STR_COMPANY_INFRASTRUCTURE_VIEW_SIGNALS                         :{WHITE}Signals
+STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD_SECT                       :{GOLD}Road pieces:
+STR_COMPANY_INFRASTRUCTURE_VIEW_ROAD                            :{WHITE}Road
+STR_COMPANY_INFRASTRUCTURE_VIEW_TRAMWAY                         :{WHITE}Tramway
+STR_COMPANY_INFRASTRUCTURE_VIEW_WATER_SECT                      :{GOLD}Water tiles:
+STR_COMPANY_INFRASTRUCTURE_VIEW_CANALS                          :{WHITE}Canals
+STR_COMPANY_INFRASTRUCTURE_VIEW_STATION_SECT                    :{GOLD}Stations:
+STR_COMPANY_INFRASTRUCTURE_VIEW_STATIONS                        :{WHITE}Station tiles
+STR_COMPANY_INFRASTRUCTURE_VIEW_AIRPORTS                        :{WHITE}Airports
+
 # Industry directory
 STR_INDUSTRY_DIRECTORY_CAPTION                                  :{WHITE}Industries
 STR_INDUSTRY_DIRECTORY_NONE                                     :{ORANGE}- None -
@@ -4308,6 +4331,7 @@
 STR_TINY_COMMA                                                  :{TINY_FONT}{COMMA}
 STR_BLUE_COMMA                                                  :{BLUE}{COMMA}
 STR_RED_COMMA                                                   :{RED}{COMMA}
+STR_WHITE_COMMA                                                 :{WHITE}{COMMA}
 STR_TINY_BLACK_DECIMAL                                          :{TINY_FONT}{BLACK}{DECIMAL}
 STR_COMPANY_MONEY                                               :{WHITE}{CURRENCY_LONG}
 STR_BLACK_DATE_LONG                                             :{BLACK}{DATE_LONG}
--- a/src/saveload/afterload.cpp
+++ b/src/saveload/afterload.cpp
@@ -2752,6 +2752,8 @@
 	DeleteInvalidEngineNews();
 	/* Update livery selection windows */
 	for (CompanyID i = COMPANY_FIRST; i < MAX_COMPANIES; i++) InvalidateWindowData(WC_COMPANY_COLOUR, i);
+	/* Update company infrastructure counts. */
+	InvalidateWindowClassesData(WC_COMPANY_INFRASTRUCTURE);
 	/* redraw the whole screen */
 	MarkWholeScreenDirty();
 	CheckTrainsLengths();
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -825,6 +825,7 @@
 			case WC_AIRCRAFT_LIST:
 			case WC_BUY_COMPANY:
 			case WC_COMPANY:
+			case WC_COMPANY_INFRASTRUCTURE:
 				continue;
 
 			default:
--- a/src/window_type.h
+++ b/src/window_type.h
@@ -113,6 +113,7 @@
 	WC_GRF_PARAMETERS,
 	WC_BUILD_OBJECT,
 	WC_NEWGRF_TEXTFILE,
+	WC_COMPANY_INFRASTRUCTURE,
 
 	WC_INVALID = 0xFFFF
 };