(svn r13189) [NoAI] -Sync: with trunk r13055:13185. noai
authorglx
Mon, 19 May 2008 15:13:58 +0000
branchnoai
changeset 10645 8cbdb511a674
parent 10644 6c4314786d68
child 10648 1ebb27f31a71
(svn r13189) [NoAI] -Sync: with trunk r13055:13185.
projects/openttd_vs80.vcproj
projects/openttd_vs90.vcproj
source.list
src/ai/ai_gui.cpp
src/aircraft_cmd.cpp
src/aircraft_gui.cpp
src/airport_gui.cpp
src/autoreplace_cmd.cpp
src/autoreplace_gui.cpp
src/blitter/factory.hpp
src/bridge_gui.cpp
src/build_vehicle_gui.cpp
src/cheat_gui.cpp
src/console.cpp
src/console_cmds.cpp
src/currency.cpp
src/depot_gui.cpp
src/disaster_cmd.cpp
src/dock_gui.cpp
src/driver.h
src/economy.cpp
src/elrail.cpp
src/engine.cpp
src/engine_func.h
src/engine_gui.cpp
src/genworld_gui.cpp
src/graph_gui.cpp
src/group_gui.cpp
src/gui.h
src/industry.h
src/industry_cmd.cpp
src/industry_gui.cpp
src/intro_gui.cpp
src/main_gui.cpp
src/misc.cpp
src/misc_gui.cpp
src/music/dmusic.cpp
src/music_gui.cpp
src/network/network_gui.cpp
src/network/network_gui.h
src/newgrf.cpp
src/newgrf_gui.cpp
src/news_func.h
src/news_gui.cpp
src/news_type.h
src/oldloader.cpp
src/openttd.cpp
src/order_cmd.cpp
src/order_gui.cpp
src/osk_gui.cpp
src/player_face.h
src/player_gui.cpp
src/players.cpp
src/querystring_gui.h
src/rail_cmd.cpp
src/rail_gui.cpp
src/rail_map.h
src/road_cmd.cpp
src/road_gui.cpp
src/roadveh_cmd.cpp
src/saveload.cpp
src/settings.cpp
src/settings_gui.cpp
src/ship_cmd.cpp
src/signal.cpp
src/signal_func.h
src/signs_gui.cpp
src/smallmap_gui.cpp
src/sortlist_type.h
src/station.cpp
src/station_cmd.cpp
src/station_gui.cpp
src/station_gui.h
src/statusbar_gui.cpp
src/statusbar_gui.h
src/stdafx.h
src/subsidy_gui.cpp
src/table/engines.h
src/terraform_cmd.cpp
src/terraform_gui.cpp
src/tilehighlight_func.h
src/timetable_gui.cpp
src/toolbar_gui.cpp
src/toolbar_gui.h
src/town_cmd.cpp
src/town_gui.cpp
src/track_func.h
src/train_cmd.cpp
src/train_gui.cpp
src/transparency_gui.cpp
src/tree_gui.cpp
src/tunnelbridge_cmd.cpp
src/vehicle.cpp
src/vehicle_func.h
src/vehicle_gui.cpp
src/vehicle_gui.h
src/viewport.cpp
src/water_cmd.cpp
src/widget.cpp
src/widgets/dropdown.cpp
src/win32.cpp
src/window.cpp
src/window_gui.h
src/window_type.h
src/yapf/yapf_road.cpp
--- a/projects/openttd_vs80.vcproj	Mon May 19 14:14:33 2008 +0000
+++ b/projects/openttd_vs80.vcproj	Mon May 19 15:13:58 2008 +0000
@@ -1292,6 +1292,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\querystring_gui.h"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\queue.h"
 				>
 			</File>
@@ -1420,6 +1424,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\sortlist_type.h"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\sound_func.h"
 				>
 			</File>
@@ -1452,6 +1460,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\statusbar_gui.h"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\stdafx.h"
 				>
 			</File>
@@ -2212,10 +2224,6 @@
 				>
 			</File>
 			<File
-				RelativePath=".\..\src\ai\ai_factory.hpp"
-				>
-			</File>
-			<File
 				RelativePath=".\..\src\ai\ai_gui.cpp"
 				>
 			</File>
@@ -2224,6 +2232,14 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\ai\ai_info.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\..\src\ai\ai_info.hpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\ai\ai_squirrel.cpp"
 				>
 			</File>
--- a/projects/openttd_vs90.vcproj	Mon May 19 14:14:33 2008 +0000
+++ b/projects/openttd_vs90.vcproj	Mon May 19 15:13:58 2008 +0000
@@ -1289,6 +1289,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\querystring_gui.h"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\queue.h"
 				>
 			</File>
@@ -1417,6 +1421,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\sortlist_type.h"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\sound_func.h"
 				>
 			</File>
@@ -1449,6 +1457,10 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\statusbar_gui.h"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\stdafx.h"
 				>
 			</File>
@@ -2209,10 +2221,6 @@
 				>
 			</File>
 			<File
-				RelativePath=".\..\src\ai\ai_factory.hpp"
-				>
-			</File>
-			<File
 				RelativePath=".\..\src\ai\ai_gui.cpp"
 				>
 			</File>
@@ -2221,6 +2229,14 @@
 				>
 			</File>
 			<File
+				RelativePath=".\..\src\ai\ai_info.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\..\src\ai\ai_info.hpp"
+				>
+			</File>
+			<File
 				RelativePath=".\..\src\ai\ai_squirrel.cpp"
 				>
 			</File>
--- a/source.list	Mon May 19 14:14:33 2008 +0000
+++ b/source.list	Mon May 19 15:13:58 2008 +0000
@@ -92,7 +92,7 @@
 				thread_morphos.cpp
 			#else
 				thread_pthread.cpp
-			#endif
+			#end
 		#end
 		fiber_thread.cpp
 	#end
@@ -248,6 +248,7 @@
 player_func.h
 player_gui.h
 player_type.h
+querystring_gui.h
 queue.h
 rail.h
 rail_gui.h
@@ -280,6 +281,7 @@
 signs_type.h
 slope_func.h
 slope_type.h
+sortlist_type.h
 sound_func.h
 sound_type.h
 sprite.h
@@ -288,6 +290,7 @@
 station_func.h
 station_gui.h
 station_type.h
+statusbar_gui.h
 stdafx.h
 string_func.h
 string_type.h
--- a/src/ai/ai_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/ai/ai_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -55,7 +55,7 @@
 	static PlayerID ai_debug_player;
 	int redraw_timer;
 
-	AIDebugWindow(const WindowDesc *desc, void *data, WindowNumber number) : Window(desc, data, number)
+	AIDebugWindow(const WindowDesc *desc, WindowNumber number) : Window(desc, number)
 	{
 		/* Disable the players who are not active or not an AI */
 		for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
@@ -74,7 +74,7 @@
 	virtual void OnPaint()
 	{
 		/* Draw standard stuff */
-		DrawWindowWidgets(this);
+		this->DrawWidgets();
 
 		/* Check if the currently selected player is still active. */
 		if (ai_debug_player == INVALID_PLAYER || !GetPlayer(ai_debug_player)->is_active) {
@@ -246,8 +246,7 @@
 	WDP_AUTO, WDP_AUTO, 299, 228, 299, 228,
 	WC_PERFORMANCE_DETAIL, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_ai_debug_widgets,
-	NULL
+	_ai_debug_widgets
 };
 
 void ShowAIDebugWindow()
--- a/src/aircraft_cmd.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/aircraft_cmd.cpp	Mon May 19 15:13:58 2008 +0000
@@ -447,7 +447,7 @@
 		}
 
 		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
-		RebuildVehicleLists();
+		InvalidateWindowClassesData(WC_AIRCRAFT_LIST, 0);
 		InvalidateWindow(WC_COMPANY, v->owner);
 		if (IsLocalPlayer())
 			InvalidateAutoreplaceWindow(v->engine_type, v->group_id); //updates the replace Aircraft window
@@ -462,11 +462,10 @@
 static void DoDeleteAircraft(Vehicle *v)
 {
 	DeleteWindowById(WC_VEHICLE_VIEW, v->index);
-	RebuildVehicleLists();
 	InvalidateWindow(WC_COMPANY, v->owner);
 	DeleteDepotHighlightOfVehicle(v);
 	DeleteVehicleChain(v);
-	InvalidateWindowClasses(WC_AIRCRAFT_LIST);
+	InvalidateWindowClassesData(WC_AIRCRAFT_LIST, 0);
 }
 
 /** Sell an aircraft.
@@ -657,7 +656,7 @@
 		v->cargo_subtype = new_subtype;
 		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
 		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
-		RebuildVehicleLists();
+		InvalidateWindowClassesData(WC_AIRCRAFT_LIST, 0);
 	}
 
 	return cost;
@@ -1404,7 +1403,7 @@
 
 	SetDParam(1, st->index);
 	AddNewsItem(newsitem,
-		NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ACCIDENT, DNC_NONE,
+		NS_ACCIDENT_VEHICLE,
 		v->index,
 		0);
 
@@ -1449,7 +1448,7 @@
 		/* show newsitem of celebrating citizens */
 		AddNewsItem(
 			STR_A033_CITIZENS_CELEBRATE_FIRST,
-			NM_THIN, NF_VIEWPORT | NF_VEHICLE, (v->owner == _local_player) ? NT_ARRIVAL_PLAYER : NT_ARRIVAL_OTHER, DNC_NONE,
+			(v->owner == _local_player) ? NS_ARRIVAL_PLAYER : NS_ARRIVAL_OTHER,
 			v->index,
 			0);
 	}
--- a/src/aircraft_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/aircraft_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -13,6 +13,7 @@
 #include "vehicle_func.h"
 #include "gfx_func.h"
 #include "order_func.h"
+#include "window_gui.h"
 
 #include "table/sprites.h"
 #include "table/strings.h"
--- a/src/airport_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/airport_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -65,53 +65,65 @@
 	BuildAirClick_Demolish,
 };
 
-static void BuildAirToolbWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT:
-			DrawWindowWidgets(w);
-			break;
-
-		case WE_CLICK:
-			if (e->we.click.widget - 3 >= 0)
-				_build_air_button_proc[e->we.click.widget - 3](w);
-			break;
-
-		case WE_KEYPRESS: {
-			switch (e->we.keypress.keycode) {
-				case '1': BuildAirClick_Airport(w); break;
-				case '2': BuildAirClick_Demolish(w); break;
-				default: return;
-			}
-		} break;
+struct BuildAirToolbarWindow : Window {
+	BuildAirToolbarWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+	{
+		this->FindWindowPlacementAndResize(desc);
+		if (_patches.link_terraform_toolbar) ShowTerraformToolbar(this);
+	}
 
-		case WE_PLACE_OBJ:
-			_place_proc(e->we.place.tile);
-			break;
-
-		case WE_PLACE_DRAG:
-			VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.select_method);
-			break;
+	~BuildAirToolbarWindow()
+	{
+		if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
+	}
 
-		case WE_PLACE_MOUSEUP:
-			if (e->we.place.pt.x != -1 && e->we.place.select_proc == DDSP_DEMOLISH_AREA) {
-				GUIPlaceProcDragXY(e);
-			}
-			break;
-
-		case WE_ABORT_PLACE_OBJ:
-			w->RaiseButtons();
+	virtual void OnPaint()
+	{
+		this->DrawWidgets();
+	}
 
-			w = FindWindowById(WC_BUILD_STATION, 0);
-			if (w != 0)
-				WP(w, def_d).close = true;
-			break;
+	virtual void OnClick(Point pt, int widget)
+	{
+		if (widget - 3 >= 0) {
+			_build_air_button_proc[widget - 3](this);
+		}
+	}
 
-		case WE_DESTROY:
-			if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
-			break;
+
+	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+	{
+		switch (keycode) {
+			case '1': BuildAirClick_Airport(this); break;
+			case '2': BuildAirClick_Demolish(this); break;
+			default: return ES_NOT_HANDLED;
+		}
+		return ES_HANDLED;
 	}
-}
+
+	virtual void OnPlaceObject(Point pt, TileIndex tile)
+	{
+		_place_proc(tile);
+	}
+
+	virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
+	{
+		VpSelectTilesWithMethod(pt.x, pt.y, select_method);
+	}
+
+	virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
+	{
+		if (pt.x != -1 && select_proc == DDSP_DEMOLISH_AREA) {
+			GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
+		}
+	}
+
+	virtual void OnPlaceObjectAbort()
+	{
+		this->RaiseButtons();
+
+		delete FindWindowById(WC_BUILD_STATION, 0);
+	}
+};
 
 static const Widget _air_toolbar_widgets[] = {
 {   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,            STR_018B_CLOSE_WINDOW },
@@ -128,7 +140,6 @@
 	WC_BUILD_TOOLBAR, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
 	_air_toolbar_widgets,
-	BuildAirToolbWndProc
 };
 
 void ShowBuildAirToolbar()
@@ -136,114 +147,107 @@
 	if (!IsValidPlayer(_current_player)) return;
 
 	DeleteWindowByClass(WC_BUILD_TOOLBAR);
-	Window *w = AllocateWindowDescFront<Window>(&_air_toolbar_desc, TRANSPORT_AIR);
-	if (_patches.link_terraform_toolbar) ShowTerraformToolbar(w);
+	AllocateWindowDescFront<BuildAirToolbarWindow>(&_air_toolbar_desc, TRANSPORT_AIR);
 }
 
-enum {
-	BAW_BOTTOMPANEL = 10,
-	BAW_SMALL_AIRPORT,
-	BAW_CITY_AIRPORT,
-	BAW_HELIPORT,
-	BAW_METRO_AIRPORT,
-	BAW_STR_INTERNATIONAL_AIRPORT,
-	BAW_COMMUTER_AIRPORT,
-	BAW_HELIDEPOT,
-	BAW_STR_INTERCONTINENTAL_AIRPORT,
-	BAW_HELISTATION,
-	BAW_LAST_AIRPORT = BAW_HELISTATION,
-	BAW_AIRPORT_COUNT = BAW_LAST_AIRPORT - BAW_SMALL_AIRPORT + 1,
-	BAW_BTN_DONTHILIGHT = BAW_LAST_AIRPORT + 1,
-	BAW_BTN_DOHILIGHT,
-};
-
-static void BuildAirportPickerWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_CREATE:
-			w->SetWidgetLoweredState(BAW_BTN_DONTHILIGHT, !_station_show_coverage);
-			w->SetWidgetLoweredState(BAW_BTN_DOHILIGHT, _station_show_coverage);
-			w->LowerWidget(_selected_airport_type + BAW_SMALL_AIRPORT);
-			break;
-
-		case WE_PAINT: {
-			int i; // airport enabling loop
-			uint32 avail_airports;
-			const AirportFTAClass *airport;
-
-			if (WP(w, def_d).close) return;
-
-			avail_airports = GetValidAirports();
-
-			w->RaiseWidget(_selected_airport_type + BAW_SMALL_AIRPORT);
-			if (!HasBit(avail_airports, 0) && _selected_airport_type == AT_SMALL) _selected_airport_type = AT_LARGE;
-			if (!HasBit(avail_airports, 1) && _selected_airport_type == AT_LARGE) _selected_airport_type = AT_SMALL;
-			w->LowerWidget(_selected_airport_type + BAW_SMALL_AIRPORT);
-
-			/* 'Country Airport' starts at widget BAW_SMALL_AIRPORT, and if its bit is set, it is
-			 * available, so take its opposite value to set the disabled state.
-			 * There are 9 buildable airports
-			 * XXX TODO : all airports should be held in arrays, with all relevant data.
-			 * This should be part of newgrf-airports, i suppose
-			 */
-			for (i = 0; i < BAW_AIRPORT_COUNT; i++) w->SetWidgetDisabledState(i + BAW_SMALL_AIRPORT, !HasBit(avail_airports, i));
-
-			/* select default the coverage area to 'Off' (16) */
-			airport = GetAirport(_selected_airport_type);
-			SetTileSelectSize(airport->size_x, airport->size_y);
+class AirportPickerWindow : public PickerWindowBase {
 
-			int rad = _patches.modified_catchment ? airport->catchment : (uint)CA_UNMODIFIED;
-
-			if (_station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
-
-			DrawWindowWidgets(w);
-			/* strings such as 'Size' and 'Coverage Area' */
-			int text_end = DrawStationCoverageAreaText(2, 206, SCT_ALL, rad, false);
-			text_end = DrawStationCoverageAreaText(2, text_end + 4, SCT_ALL, rad, true) + 4;
-			if (text_end != w->widget[BAW_BOTTOMPANEL].bottom) {
-				w->SetDirty();
-				ResizeWindowForWidget(w, BAW_BOTTOMPANEL, 0, text_end - w->widget[BAW_BOTTOMPANEL].bottom);
-				w->SetDirty();
-			}
-			break;
-		}
+	enum {
+		BAW_BOTTOMPANEL = 10,
+		BAW_SMALL_AIRPORT,
+		BAW_CITY_AIRPORT,
+		BAW_HELIPORT,
+		BAW_METRO_AIRPORT,
+		BAW_STR_INTERNATIONAL_AIRPORT,
+		BAW_COMMUTER_AIRPORT,
+		BAW_HELIDEPOT,
+		BAW_STR_INTERCONTINENTAL_AIRPORT,
+		BAW_HELISTATION,
+		BAW_LAST_AIRPORT = BAW_HELISTATION,
+		BAW_AIRPORT_COUNT = BAW_LAST_AIRPORT - BAW_SMALL_AIRPORT + 1,
+		BAW_BTN_DONTHILIGHT = BAW_LAST_AIRPORT + 1,
+		BAW_BTN_DOHILIGHT,
+	};
 
-		case WE_CLICK: {
-			switch (e->we.click.widget) {
-				case BAW_SMALL_AIRPORT: case BAW_CITY_AIRPORT: case BAW_HELIPORT: case BAW_METRO_AIRPORT:
-				case BAW_STR_INTERNATIONAL_AIRPORT: case BAW_COMMUTER_AIRPORT: case BAW_HELIDEPOT:
-				case BAW_STR_INTERCONTINENTAL_AIRPORT: case BAW_HELISTATION:
-					w->RaiseWidget(_selected_airport_type + BAW_SMALL_AIRPORT);
-					_selected_airport_type = e->we.click.widget - BAW_SMALL_AIRPORT;
-					w->LowerWidget(_selected_airport_type + BAW_SMALL_AIRPORT);
-					SndPlayFx(SND_15_BEEP);
-					w->SetDirty();
-					break;
+public:
 
-				case BAW_BTN_DONTHILIGHT: case BAW_BTN_DOHILIGHT:
-					_station_show_coverage = (e->we.click.widget != BAW_BTN_DONTHILIGHT);
-					w->SetWidgetLoweredState(BAW_BTN_DONTHILIGHT, !_station_show_coverage);
-					w->SetWidgetLoweredState(BAW_BTN_DOHILIGHT, _station_show_coverage);
-					SndPlayFx(SND_15_BEEP);
-					w->SetDirty();
-					break;
-			}
-		} break;
+	AirportPickerWindow(const WindowDesc *desc) : PickerWindowBase(desc)
+	{
+		this->SetWidgetLoweredState(BAW_BTN_DONTHILIGHT, !_station_show_coverage);
+		this->SetWidgetLoweredState(BAW_BTN_DOHILIGHT, _station_show_coverage);
+		this->LowerWidget(_selected_airport_type + BAW_SMALL_AIRPORT);
 
-		case WE_TICK: {
-			if (WP(w, def_d).close) {
-				delete w;
-				return;
-			}
+		this->FindWindowPlacementAndResize(desc);
+	}
 
-			CheckRedrawStationCoverage(w);
-		} break;
+	virtual void OnPaint()
+	{
+		int i; // airport enabling loop
+		uint32 avail_airports;
+		const AirportFTAClass *airport;
 
-		case WE_DESTROY:
-			if (!WP(w, def_d).close) ResetObjectToPlace();
-			break;
+		avail_airports = GetValidAirports();
+
+		this->RaiseWidget(_selected_airport_type + BAW_SMALL_AIRPORT);
+		if (!HasBit(avail_airports, 0) && _selected_airport_type == AT_SMALL) _selected_airport_type = AT_LARGE;
+		if (!HasBit(avail_airports, 1) && _selected_airport_type == AT_LARGE) _selected_airport_type = AT_SMALL;
+		this->LowerWidget(_selected_airport_type + BAW_SMALL_AIRPORT);
+
+		/* 'Country Airport' starts at widget BAW_SMALL_AIRPORT, and if its bit is set, it is
+		 * available, so take its opposite value to set the disabled state.
+		 * There are 9 buildable airports
+		 * XXX TODO : all airports should be held in arrays, with all relevant data.
+		 * This should be part of newgrf-airports, i suppose
+		 */
+		for (i = 0; i < BAW_AIRPORT_COUNT; i++) this->SetWidgetDisabledState(i + BAW_SMALL_AIRPORT, !HasBit(avail_airports, i));
+
+		/* select default the coverage area to 'Off' (16) */
+		airport = GetAirport(_selected_airport_type);
+		SetTileSelectSize(airport->size_x, airport->size_y);
+
+		int rad = _patches.modified_catchment ? airport->catchment : (uint)CA_UNMODIFIED;
+
+		if (_station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
+
+		this->DrawWidgets();
+		/* strings such as 'Size' and 'Coverage Area' */
+		int text_end = DrawStationCoverageAreaText(2, 206, SCT_ALL, rad, false);
+		text_end = DrawStationCoverageAreaText(2, text_end + 4, SCT_ALL, rad, true) + 4;
+		if (text_end != this->widget[BAW_BOTTOMPANEL].bottom) {
+			this->SetDirty();
+			ResizeWindowForWidget(this, BAW_BOTTOMPANEL, 0, text_end - this->widget[BAW_BOTTOMPANEL].bottom);
+			this->SetDirty();
+		}
 	}
-}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case BAW_SMALL_AIRPORT: case BAW_CITY_AIRPORT: case BAW_HELIPORT: case BAW_METRO_AIRPORT:
+			case BAW_STR_INTERNATIONAL_AIRPORT: case BAW_COMMUTER_AIRPORT: case BAW_HELIDEPOT:
+			case BAW_STR_INTERCONTINENTAL_AIRPORT: case BAW_HELISTATION:
+				this->RaiseWidget(_selected_airport_type + BAW_SMALL_AIRPORT);
+				_selected_airport_type = widget - BAW_SMALL_AIRPORT;
+				this->LowerWidget(_selected_airport_type + BAW_SMALL_AIRPORT);
+				SndPlayFx(SND_15_BEEP);
+				this->SetDirty();
+				break;
+
+			case BAW_BTN_DONTHILIGHT: case BAW_BTN_DOHILIGHT:
+				_station_show_coverage = (widget != BAW_BTN_DONTHILIGHT);
+				this->SetWidgetLoweredState(BAW_BTN_DONTHILIGHT, !_station_show_coverage);
+				this->SetWidgetLoweredState(BAW_BTN_DOHILIGHT, _station_show_coverage);
+				SndPlayFx(SND_15_BEEP);
+				this->SetDirty();
+				break;
+		}
+	}
+
+	virtual void OnTick()
+	{
+		CheckRedrawStationCoverage(this);
+	}
+};
 
 static const Widget _build_airport_picker_widgets[] = {
 {   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                         STR_018B_CLOSE_WINDOW},
@@ -277,12 +281,11 @@
 	WC_BUILD_STATION, WC_BUILD_TOOLBAR,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 	_build_airport_picker_widgets,
-	BuildAirportPickerWndProc
 };
 
 static void ShowBuildAirportPicker()
 {
-	new Window(&_build_airport_desc);
+	new AirportPickerWindow(&_build_airport_desc);
 }
 
 void InitializeAirportGui()
--- a/src/autoreplace_cmd.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/autoreplace_cmd.cpp	Mon May 19 15:13:58 2008 +0000
@@ -216,7 +216,7 @@
 			// copy/clone the orders
 			DoCommand(0, (old_v->index << 16) | new_v->index, old_v->IsOrderListShared() ? CO_SHARE : CO_COPY, DC_EXEC, CMD_CLONE_ORDER);
 			new_v->cur_order_index = old_v->cur_order_index;
-			ChangeVehicleViewWindow(old_v, new_v);
+			ChangeVehicleViewWindow(old_v->index, new_v->index);
 			new_v->profit_this_year = old_v->profit_this_year;
 			new_v->profit_last_year = old_v->profit_last_year;
 			new_v->service_interval = old_v->service_interval;
@@ -323,7 +323,7 @@
 		if (v == NULL) {
 			/* We sold all the wagons and the train is still not short enough */
 			SetDParam(0, front->unitnumber);
-			AddNewsItem(STR_TRAIN_TOO_LONG_AFTER_REPLACEMENT, NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, DNC_NONE, front->index, 0);
+			AddNewsItem(STR_TRAIN_TOO_LONG_AFTER_REPLACEMENT, NS_ADVICE, front->index, 0);
 			return cost;
 		}
 
@@ -480,7 +480,7 @@
 					default: NOT_REACHED(); message = 0; break;
 				}
 
-				AddNewsItem(message, NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, DNC_NONE, v->index, 0);
+				AddNewsItem(message, NS_ADVICE, v->index, 0);
 			}
 		}
 	}
--- a/src/autoreplace_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/autoreplace_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -21,6 +21,7 @@
 #include "widgets/dropdown_func.h"
 #include "engine_func.h"
 #include "engine_base.h"
+#include "window_gui.h"
 
 #include "table/sprites.h"
 #include "table/strings.h"
@@ -249,7 +250,7 @@
 	}
 
 public:
-	ReplaceVehicleWindow(const WindowDesc *desc, VehicleType vehicletype, GroupID id_g) : Window(desc, NULL, window_number)
+	ReplaceVehicleWindow(const WindowDesc *desc, VehicleType vehicletype, GroupID id_g) : Window(desc, vehicletype)
 	{
 		this->wagon_btnstate = true; // start with locomotives (all other vehicles will not read this bool)
 		new (&this->list[0]) EngineList();
@@ -360,7 +361,7 @@
 			this->widget[RVW_WIDGET_TRAIN_RAILTYPE_DROPDOWN].data = _rail_types_list[sel_railtype];
 		}
 
-		DrawWindowWidgets(this);
+		this->DrawWidgets();
 
 		/* sets up the string for the vehicle that is being replaced to */
 		if (selected_id[0] != INVALID_ENGINE) {
@@ -532,7 +533,6 @@
 	WC_REPLACE_VEHICLE, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
 	_replace_vehicle_widgets,
-	NULL
 };
 
 static const WindowDesc _replace_vehicle_desc = {
@@ -540,7 +540,6 @@
 	WC_REPLACE_VEHICLE, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
 	_replace_vehicle_widgets,
-	NULL
 };
 
 RailType ReplaceVehicleWindow::sel_railtype = RAILTYPE_RAIL;
--- a/src/blitter/factory.hpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/blitter/factory.hpp	Mon May 19 15:13:58 2008 +0000
@@ -56,7 +56,13 @@
 		name(NULL)
 	{}
 
-	virtual ~BlitterFactoryBase() { if (this->name != NULL) GetBlitters().erase(this->name); free(this->name); }
+	virtual ~BlitterFactoryBase()
+	{
+		if (this->name == NULL) return;
+		GetBlitters().erase(this->name);
+		if (GetBlitters().empty()) delete &GetBlitters();
+		free(this->name);
+	}
 
 	/**
 	 * Find the requested blitter and return his class.
--- a/src/bridge_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/bridge_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -17,146 +17,329 @@
 #include "viewport_func.h"
 #include "gfx_func.h"
 #include "tunnelbridge.h"
+#include "sortlist_type.h"
+#include "widgets/dropdown_func.h"
 
 #include "table/strings.h"
 
-static struct BridgeData {
-	uint8 last_size;
-	uint count;
-	TileIndex start_tile;
-	TileIndex end_tile;
-	uint32 type; ///< Data type for the bridge. Bit 16,15 = transport type, 14..8 = road/rail pieces, 7..0 = type of bridge
-	BridgeType indexes[MAX_BRIDGES];
-	Money costs[MAX_BRIDGES];
+/* Save the sorting during runtime */
+static Listing _bridge_sorting = {false, 0};
 
-	BridgeData()
-		: last_size(4)
-		, count(0)
-		{};
-} _bridgedata;
+/**
+ * Carriage for the data we need if we want to build a bridge
+ */
+struct BuildBridgeData {
+	BridgeType index;
+	const BridgeSpec *spec;
+	Money cost;
+};
 
+typedef GUIList<BuildBridgeData> GUIBridgeList;
+
+/** Sort the bridges by their index */
+static int CDECL BridgeIndexSorter(const void *a, const void *b)
+{
+	const BuildBridgeData* ba = (BuildBridgeData*)a;
+	const BuildBridgeData* bb = (BuildBridgeData*)b;
+	int r = ba->index - bb->index;
+
+	return (_bridge_sorting.order) ? -r : r;
+}
+
+/** Sort the bridges by their price */
+static int CDECL BridgePriceSorter(const void *a, const void *b)
+{
+	const BuildBridgeData* ba = (BuildBridgeData*)a;
+	const BuildBridgeData* bb = (BuildBridgeData*)b;
+	int r = ba->cost - bb->cost;
+
+	return (_bridge_sorting.order) ? -r : r;
+}
+
+/** Sort the bridges by their maximum speed */
+static int CDECL BridgeSpeedSorter(const void *a, const void *b)
+{
+	const BuildBridgeData* ba = (BuildBridgeData*)a;
+	const BuildBridgeData* bb = (BuildBridgeData*)b;
+	int r = ba->spec->speed - bb->spec->speed;
+
+	return (_bridge_sorting.order) ? -r : r;
+}
+
+typedef int CDECL BridgeSortListingTypeFunction(const void*, const void*);
+
+/* Availible bridge sorting functions */
+static BridgeSortListingTypeFunction* const _bridge_sorter[] = {
+	&BridgeIndexSorter,
+	&BridgePriceSorter,
+	&BridgeSpeedSorter
+};
+
+/* Names of the sorting functions */
+static const StringID _bridge_sort_listing[] = {
+	STR_SORT_BY_NUMBER,
+	STR_ENGINE_SORT_COST,
+	STR_SORT_BY_MAX_SPEED,
+	INVALID_STRING_ID
+};
+
+/**
+ * Callback executed after a build Bridge CMD has been called
+ *
+ * @param scucess True if the build succeded
+ * @param tile The tile where the command has been executed
+ * @param p1 not used
+ * @param p2 not used
+ */
 void CcBuildBridge(bool success, TileIndex tile, uint32 p1, uint32 p2)
 {
 	if (success) SndPlayTileFx(SND_27_BLACKSMITH_ANVIL, tile);
 }
 
-static void BuildBridge(Window *w, int i)
-{
-	delete w;
-	DoCommandP(_bridgedata.end_tile, _bridgedata.start_tile,
-		_bridgedata.type | _bridgedata.indexes[i], CcBuildBridge,
-		CMD_BUILD_BRIDGE | CMD_MSG(STR_5015_CAN_T_BUILD_BRIDGE_HERE));
-}
-
 /* Names of the build bridge selection window */
 enum BuildBridgeSelectionWidgets {
 	BBSW_CLOSEBOX = 0,
 	BBSW_CAPTION,
+	BBSW_DROPDOWN_ORDER,
+	BBSW_DROPDOWN_CRITERIA,
 	BBSW_BRIDGE_LIST,
 	BBSW_SCROLLBAR,
 	BBSW_RESIZEBOX
 };
 
-static void BuildBridgeWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_CREATE:
-			w->resize.step_height = 22;
-			w->vscroll.count = _bridgedata.count;
+class BuildBridgeWindow : public Window {
+private:
+	/* The last size of the build bridge window
+	 * is saved during runtime */
+	static uint last_size;
 
-			if (_bridgedata.last_size <= 4) {
-				w->vscroll.cap = 4;
-			} else {
-				/* Resize the bridge selection window if we used a bigger one the last time */
-				w->vscroll.cap = (w->vscroll.count > _bridgedata.last_size) ? _bridgedata.last_size : w->vscroll.count;
-				ResizeWindow(w, 0, (w->vscroll.cap - 4) * w->resize.step_height);
-				w->widget[BBSW_BRIDGE_LIST].data = (w->vscroll.cap << 8) + 1;
-			}
-			break;
-
-		case WE_PAINT: {
-			DrawWindowWidgets(w);
+	TileIndex start_tile;
+	TileIndex end_tile;
+	uint32 type;
+	GUIBridgeList *bridges;
 
-			uint y = 15;
-			for (uint i = 0; (i < w->vscroll.cap) && ((i + w->vscroll.pos) < _bridgedata.count); i++) {
-				const BridgeSpec *b = GetBridgeSpec(_bridgedata.indexes[i + w->vscroll.pos]);
+	void BuildBridge(uint8 i)
+	{
+		DoCommandP(this->end_tile, this->start_tile, this->type | this->bridges->sort_list[i].index,
+				CcBuildBridge, CMD_BUILD_BRIDGE | CMD_MSG(STR_5015_CAN_T_BUILD_BRIDGE_HERE));
+	}
 
-				SetDParam(2, _bridgedata.costs[i + w->vscroll.pos]);
-				SetDParam(1, b->speed * 10 / 16);
-				SetDParam(0, b->material);
+	/** Sort the builable bridges */
+	void SortBridgeList()
+	{
+		/* Skip sorting if resort bit is not set */
+		if (!(bridges->flags & VL_RESORT)) return;
 
-				DrawSprite(b->sprite, b->pal, 3, y);
-				DrawString(44, y, STR_500D, TC_FROMSTRING);
-				y += w->resize.step_height;
-			}
-			break;
+		qsort(this->bridges->sort_list, this->bridges->list_length, sizeof(this->bridges->sort_list[0]), _bridge_sorter[_bridge_sorting.criteria]);
+
+		/* Display the current sort variant */
+		this->widget[BBSW_DROPDOWN_CRITERIA].data = _bridge_sort_listing[this->bridges->sort_type];
+
+		bridges->flags &= ~VL_RESORT;
+
+		/* Set the modified widgets dirty */
+		this->InvalidateWidget(BBSW_DROPDOWN_CRITERIA);
+		this->InvalidateWidget(BBSW_BRIDGE_LIST);
+	}
+
+public:
+	BuildBridgeWindow(const WindowDesc *desc, TileIndex start, TileIndex end, uint32 br_type, GUIBridgeList *bl) : Window(desc),
+		start_tile(start),
+		end_tile(end),
+		type(br_type),
+		bridges(bl)
+	{
+		this->SortBridgeList();
+
+		/* Change the data, or the caption of the gui. Set it to road or rail, accordingly */
+		this->widget[BBSW_CAPTION].data = (GB(this->type, 15, 2) == TRANSPORT_ROAD) ? STR_1803_SELECT_ROAD_BRIDGE : STR_100D_SELECT_RAIL_BRIDGE;
+
+		this->resize.step_height = 22;
+		this->vscroll.count = bl->list_length;
+
+		if (this->last_size <= 4) {
+			this->vscroll.cap = 4;
+		} else {
+			/* Resize the bridge selection window if we used a bigger one the last time */
+			this->vscroll.cap = (this->vscroll.count > this->last_size) ? this->last_size : this->vscroll.count;
+			ResizeWindow(this, 0, (this->vscroll.cap - 4) * this->resize.step_height);
+			this->widget[BBSW_BRIDGE_LIST].data = (this->vscroll.cap << 8) + 1;
 		}
 
-		case WE_KEYPRESS: {
-			const uint8 i = e->we.keypress.keycode - '1';
-			if (i < 9 && i < _bridgedata.count) {
-				e->we.keypress.cont = false;
-				BuildBridge(w, i);
-			}
+		this->FindWindowPlacementAndResize(desc);
+	}
 
-			break;
-		}
+	~BuildBridgeWindow()
+	{
+		free(this->bridges->sort_list);
+		delete bridges;
+	}
 
-		case WE_CLICK:
-			if (e->we.click.widget == BBSW_BRIDGE_LIST) {
-				uint ind = ((int)e->we.click.pt.y - 14) / w->resize.step_height;
-				if (ind < w->vscroll.cap) {
-					ind += w->vscroll.pos;
-					if (ind < _bridgedata.count) {
-						BuildBridge(w, ind);
+	virtual void OnPaint()
+	{
+		this->DrawWidgets();
+
+		this->DrawSortButtonState(BBSW_DROPDOWN_ORDER, (this->bridges->flags & VL_DESC) ? SBS_DOWN : SBS_UP);
+
+		uint y = this->widget[BBSW_BRIDGE_LIST].top + 2;
+
+		for (uint i = this->vscroll.pos; (i < (this->vscroll.cap + this->vscroll.pos)) && (i < this->bridges->list_length); i++) {
+			const BridgeSpec *b = this->bridges->sort_list[i].spec;
+
+			SetDParam(2, this->bridges->sort_list[i].cost);
+			SetDParam(1, b->speed * 10 / 16);
+			SetDParam(0, b->material);
+
+			DrawSprite(b->sprite, b->pal, 3, y);
+			DrawString(44, y, STR_500D, TC_FROMSTRING);
+			y += this->resize.step_height;
+
+		}
+	}
+
+	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+	{
+		const uint8 i = keycode - '1';
+		if (i < 9 && i < this->bridges->list_length) {
+			/* Build the requested bridge */
+			this->BuildBridge(i);
+			delete this;
+			return ES_HANDLED;
+		}
+		return ES_NOT_HANDLED;
+	}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			default: break;
+			case BBSW_BRIDGE_LIST: {
+				uint i = ((int)pt.y - this->widget[BBSW_BRIDGE_LIST].top) / this->resize.step_height;
+				if (i < this->vscroll.cap) {
+					i += this->vscroll.pos;
+					if (i < this->bridges->list_length) {
+						this->BuildBridge(i);
+						delete this;
 					}
 				}
-			}
-			break;
+			} break;
 
-		case WE_RESIZE:
-			w->vscroll.cap += e->we.sizing.diff.y / (int)w->resize.step_height;
-			w->widget[BBSW_BRIDGE_LIST].data = (w->vscroll.cap << 8) + 1;
-			SetVScrollCount(w, _bridgedata.count);
+			case BBSW_DROPDOWN_ORDER:
+				/* Revers the sort order */
+				this->bridges->flags ^= VL_DESC;
+				_bridge_sorting.order = !_bridge_sorting.order;
 
-			_bridgedata.last_size = w->vscroll.cap;
-			break;
+				this->bridges->flags |= VL_RESORT;
+				this->SortBridgeList();
+				break;
+
+			case BBSW_DROPDOWN_CRITERIA:
+				ShowDropDownMenu(this, _bridge_sort_listing, bridges->sort_type, BBSW_DROPDOWN_CRITERIA, 0, 0);
+				break;
+		}
 	}
-}
+
+	virtual void OnDropdownSelect(int widget, int index)
+	{
+		if (widget == BBSW_DROPDOWN_CRITERIA && this->bridges->sort_type != index) {
+			this->bridges->sort_type = index;
+			_bridge_sorting.criteria = index;
+
+			this->bridges->flags |= VL_RESORT;
+			this->SortBridgeList();
+		}
+	}
+
+	virtual void OnResize(Point new_size, Point delta)
+	{
+		this->vscroll.cap += delta.y / (int)this->resize.step_height;
+		this->widget[BBSW_BRIDGE_LIST].data = (this->vscroll.cap << 8) + 1;
+		SetVScrollCount(this, this->bridges->list_length);
+
+		this->last_size = this->vscroll.cap;
+	}
+};
+
+/* Set the default size of the Build Bridge Window */
+uint BuildBridgeWindow::last_size = 4;
 
 /* Widget definition for the rail bridge selection window */
 static const Widget _build_bridge_widgets[] = {
 {   WWT_CLOSEBOX,   RESIZE_NONE,  7,   0,  10,   0,  13, STR_00C5,                    STR_018B_CLOSE_WINDOW},            // BBSW_CLOSEBOX
 {    WWT_CAPTION,   RESIZE_NONE,  7,  11, 199,   0,  13, STR_100D_SELECT_RAIL_BRIDGE, STR_018C_WINDOW_TITLE_DRAG_THIS},  // BBSW_CAPTION
-{     WWT_MATRIX, RESIZE_BOTTOM,  7,   0, 187,  14, 101, 0x401,                       STR_101F_BRIDGE_SELECTION_CLICK},  // BBSW_BRIDGE_LIST
-{  WWT_SCROLLBAR, RESIZE_BOTTOM,  7, 188, 199,  14,  89, 0x0,                         STR_0190_SCROLL_BAR_SCROLLS_LIST}, // BBSW_SCROLLBAR
-{  WWT_RESIZEBOX,     RESIZE_TB,  7, 188, 199,  90, 101, 0x0,                         STR_RESIZE_BUTTON},                // BBSW_RESIZEBOX
+
+{    WWT_TEXTBTN,   RESIZE_NONE,  7,   0,  80,  14,  25, STR_SORT_BY,                 STR_SORT_ORDER_TIP},               // BBSW_DROPDOWN_ORDER
+{   WWT_DROPDOWN,   RESIZE_NONE,  7,  81, 199,  14,  25, 0x0,                         STR_SORT_CRITERIA_TIP},            // BBSW_DROPDOWN_CRITERIA
+
+{     WWT_MATRIX, RESIZE_BOTTOM,  7,   0, 187,  26, 113, 0x401,                       STR_101F_BRIDGE_SELECTION_CLICK},  // BBSW_BRIDGE_LIST
+{  WWT_SCROLLBAR, RESIZE_BOTTOM,  7, 188, 199,  26, 101, 0x0,                         STR_0190_SCROLL_BAR_SCROLLS_LIST}, // BBSW_SCROLLBAR
+{  WWT_RESIZEBOX,     RESIZE_TB,  7, 188, 199, 102, 113, 0x0,                         STR_RESIZE_BUTTON},                // BBSW_RESIZEBOX
 {   WIDGETS_END},
 };
 
 /* Window definition for the rail bridge selection window */
 static const WindowDesc _build_bridge_desc = {
-	WDP_AUTO, WDP_AUTO, 200, 102, 200, 102,
+	WDP_AUTO, WDP_AUTO, 200, 114, 200, 114,
 	WC_BUILD_BRIDGE, WC_BUILD_TOOLBAR,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE,
 	_build_bridge_widgets,
-	BuildBridgeWndProc
 };
 
+/**
+ * Add a buildable bridge to the list.
+ *  If the list is empty a new one is created.
+ *
+ * @param bl The list which we want to manage
+ * @param item The item to add
+ * @return The pointer to the list
+ */
+static GUIBridgeList *PushBridgeList(GUIBridgeList *bl, BuildBridgeData item)
+{
+	if (bl == NULL) {
+		/* Create the list if needed */
+		bl = new GUIBridgeList();
+		bl->flags |= VL_RESORT;
+		if (_bridge_sorting.order) bl->flags |= VL_DESC;
+		bl->list_length = 1;
+		bl->sort_type = _bridge_sorting.criteria;
+	} else {
+		/* Resize the list */
+		bl->list_length++;
+	}
+
+	bl->sort_list = ReallocT(bl->sort_list, bl->list_length);
+
+	bl->sort_list[bl->list_length - 1] = item;
+
+	return bl;
+}
+
+/**
+ * Prepare the data for the build a bridge window.
+ *  If we can't build a bridge under the given conditions
+ *  show an error message.
+ *
+ * @parma start The start tile of the bridge
+ * @param end The end tile of the bridge
+ * @param transport_type The transport type
+ * @param bridge_type The bridge type
+ */
 void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transport_type, byte bridge_type)
 {
 	DeleteWindowById(WC_BUILD_BRIDGE, 0);
 
-	_bridgedata.type = (transport_type << 15) | (bridge_type << 8); //prepare the parameter for use only once
-	_bridgedata.start_tile = start;
-	_bridgedata.end_tile = end;
+	/* Data type for the bridge.
+	 * Bit 16,15 = transport type,
+	 *     14..8 = road/rail pieces,
+	 *      7..0 = type of bridge */
+	uint32 type = (transport_type << 15) | (bridge_type << 8);
 
 	/* only query bridge building possibility once, result is the same for all bridges!
 	 * returns CMD_ERROR on failure, and price on success */
 	StringID errmsg = INVALID_STRING_ID;
-	CommandCost ret = DoCommand(end, start, _bridgedata.type, DC_AUTO | DC_QUERY_COST, CMD_BUILD_BRIDGE);
+	CommandCost ret = DoCommand(end, start, type, DC_AUTO | DC_QUERY_COST, CMD_BUILD_BRIDGE);
 
-	uint8 j = 0;
+	GUIBridgeList *bl = NULL;
 	if (CmdFailed(ret)) {
 		errmsg = _error_message;
 	} else {
@@ -171,22 +354,19 @@
 		for (BridgeType brd_type = 0; brd_type != MAX_BRIDGES; brd_type++) {
 			if (CheckBridge_Stuff(brd_type, bridge_len)) {
 				/* bridge is accepted, add to list */
-				const BridgeSpec *b = GetBridgeSpec(brd_type);
+				BuildBridgeData item;
+				item.index = brd_type;
+				item.spec = GetBridgeSpec(brd_type);
 				/* Add to terraforming & bulldozing costs the cost of the
 				 * bridge itself (not computed with DC_QUERY_COST) */
-				_bridgedata.costs[j] = ret.GetCost() + (((int64)tot_bridgedata_len * _price.build_bridge * b->price) >> 8);
-				_bridgedata.indexes[j] = brd_type;
-				j++;
+				item.cost = ret.GetCost() + (((int64)tot_bridgedata_len * _price.build_bridge * item.spec->price) >> 8);
+				bl = PushBridgeList(bl, item);
 			}
 		}
-
-		_bridgedata.count = j;
 	}
 
-	if (j != 0) {
-		Window *w = new Window(&_build_bridge_desc);
-		/* Change the data, or the caption of the gui. Set it to road or rail, accordingly */
-		w->widget[BBSW_CAPTION].data = (transport_type == TRANSPORT_ROAD) ? STR_1803_SELECT_ROAD_BRIDGE : STR_100D_SELECT_RAIL_BRIDGE;
+	if (bl != NULL) {
+		new BuildBridgeWindow(&_build_bridge_desc, start, end, type, bl);
 	} else {
 		ShowErrorMessage(errmsg, STR_5015_CAN_T_BUILD_BRIDGE_HERE, TileX(end) * TILE_SIZE, TileY(end) * TILE_SIZE);
 	}
--- a/src/build_vehicle_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/build_vehicle_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -28,27 +28,11 @@
 #include "gfx_func.h"
 #include "widgets/dropdown_func.h"
 #include "string_func.h"
+#include "window_gui.h"
 
 #include "table/sprites.h"
 #include "table/strings.h"
 
-struct buildvehicle_d {
-	VehicleType vehicle_type;
-	union {
-		RailTypeByte railtype;
-		AirportFTAClass::Flags flags;
-		RoadTypes roadtypes;
-	} filter;
-	byte sel_index;  ///< deprecated value, used for 'unified' ship and road
-	bool descending_sort_order;
-	byte sort_criteria;
-	bool regenerate_list;
-	EngineID sel_engine;
-	EngineID rename_engine;
-	EngineList eng_list;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(buildvehicle_d));
-
 enum BuildVehicleWidgets {
 	BUILD_VEHICLE_WIDGET_CLOSEBOX = 0,
 	BUILD_VEHICLE_WIDGET_CAPTION,
@@ -78,52 +62,7 @@
 	{   WIDGETS_END},
 };
 
-/* Setup widget strings to fit the different types of vehicles */
-static void SetupWindowStrings(Window *w, VehicleType type)
-{
-	switch (type) {
-		default: NOT_REACHED();
-
-		case VEH_TRAIN:
-			w->widget[BUILD_VEHICLE_WIDGET_CAPTION].data    = STR_JUST_STRING;
-			w->widget[BUILD_VEHICLE_WIDGET_LIST].tooltips   = STR_8843_TRAIN_VEHICLE_SELECTION;
-			w->widget[BUILD_VEHICLE_WIDGET_BUILD].data      = STR_881F_BUILD_VEHICLE;
-			w->widget[BUILD_VEHICLE_WIDGET_BUILD].tooltips  = STR_8844_BUILD_THE_HIGHLIGHTED_TRAIN;
-			w->widget[BUILD_VEHICLE_WIDGET_RENAME].data     = STR_8820_RENAME;
-			w->widget[BUILD_VEHICLE_WIDGET_RENAME].tooltips = STR_8845_RENAME_TRAIN_VEHICLE_TYPE;
-			break;
-
-		case VEH_ROAD:
-			w->widget[BUILD_VEHICLE_WIDGET_CAPTION].data    = STR_9006_NEW_ROAD_VEHICLES;
-			w->widget[BUILD_VEHICLE_WIDGET_LIST].tooltips   = STR_9026_ROAD_VEHICLE_SELECTION;
-			w->widget[BUILD_VEHICLE_WIDGET_BUILD].data      = STR_9007_BUILD_VEHICLE;
-			w->widget[BUILD_VEHICLE_WIDGET_BUILD].tooltips  = STR_9027_BUILD_THE_HIGHLIGHTED_ROAD;
-			w->widget[BUILD_VEHICLE_WIDGET_RENAME].data     = STR_9034_RENAME;
-			w->widget[BUILD_VEHICLE_WIDGET_RENAME].tooltips = STR_9035_RENAME_ROAD_VEHICLE_TYPE;
-			break;
-
-		case VEH_SHIP:
-			w->widget[BUILD_VEHICLE_WIDGET_CAPTION].data    = STR_9808_NEW_SHIPS;
-			w->widget[BUILD_VEHICLE_WIDGET_LIST].tooltips   = STR_9825_SHIP_SELECTION_LIST_CLICK;
-			w->widget[BUILD_VEHICLE_WIDGET_BUILD].data      = STR_9809_BUILD_SHIP;
-			w->widget[BUILD_VEHICLE_WIDGET_BUILD].tooltips  = STR_9826_BUILD_THE_HIGHLIGHTED_SHIP;
-			w->widget[BUILD_VEHICLE_WIDGET_RENAME].data     = STR_9836_RENAME;
-			w->widget[BUILD_VEHICLE_WIDGET_RENAME].tooltips = STR_9837_RENAME_SHIP_TYPE;
-			break;
-
-		case VEH_AIRCRAFT:
-			w->widget[BUILD_VEHICLE_WIDGET_CAPTION].data    = STR_A005_NEW_AIRCRAFT;
-			w->widget[BUILD_VEHICLE_WIDGET_LIST].tooltips   = STR_A025_AIRCRAFT_SELECTION_LIST;
-			w->widget[BUILD_VEHICLE_WIDGET_BUILD].data      = STR_A006_BUILD_AIRCRAFT;
-			w->widget[BUILD_VEHICLE_WIDGET_BUILD].tooltips  = STR_A026_BUILD_THE_HIGHLIGHTED_AIRCRAFT;
-			w->widget[BUILD_VEHICLE_WIDGET_RENAME].data     = STR_A037_RENAME;
-			w->widget[BUILD_VEHICLE_WIDGET_RENAME].tooltips = STR_A038_RENAME_AIRCRAFT_TYPE;
-			break;
-	}
-}
-
 static bool _internal_sort_order; // descending/ascending
-
 static byte _last_sort_criteria[]    = {0, 0, 0, 0};
 static bool _last_sort_order[]       = {false, false, false, false};
 
@@ -216,8 +155,8 @@
 	const RailVehicleInfo *rvi_a = RailVehInfo(*(const EngineID*)a);
 	const RailVehicleInfo *rvi_b = RailVehInfo(*(const EngineID*)b);
 
-	int va = rvi_a->power << (rvi_a->railveh_type == RAILVEH_MULTIHEAD ? 1 : 0);
-	int vb = rvi_b->power << (rvi_b->railveh_type == RAILVEH_MULTIHEAD ? 1 : 0);
+	int va = rvi_a->power;
+	int vb = rvi_b->power;
 	int r = va - vb;
 
 	return _internal_sort_order ? -r : r;
@@ -600,7 +539,7 @@
 
 	/* Max speed - Engine power */
 	SetDParam(0, GetEngineProperty(engine_number, 0x09, rvi->max_speed) * 10 / 16);
-	SetDParam(1, GetEngineProperty(engine_number, 0x0B, rvi->power) << multihead);
+	SetDParam(1, GetEngineProperty(engine_number, 0x0B, rvi->power));
 	DrawString(x, y, STR_PURCHASE_INFO_SPEED_POWER, TC_FROMSTRING);
 	y += 10;
 
@@ -613,7 +552,7 @@
 
 	/* Running cost */
 	if (rvi->running_cost_class != 0xFF) {
-		SetDParam(0, (GetEngineProperty(engine_number, 0x0D, rvi->running_cost) * GetPriceByIndex(rvi->running_cost_class) >> 8) << multihead);
+		SetDParam(0, GetEngineProperty(engine_number, 0x0D, rvi->running_cost) * GetPriceByIndex(rvi->running_cost_class) >> 8);
 		DrawString(x, y, STR_PURCHASE_INFO_RUNNINGCOST, TC_FROMSTRING);
 		y += 10;
 	}
@@ -785,143 +724,6 @@
 	return y;
 }
 
-/* Figure out what train EngineIDs to put in the list */
-static void GenerateBuildTrainList(Window *w)
-{
-	EngineID sel_id = INVALID_ENGINE;
-	int num_engines = 0;
-	int num_wagons  = 0;
-	buildvehicle_d *bv = &WP(w, buildvehicle_d);
-
-	bv->filter.railtype = (w->window_number <= VEH_END) ? RAILTYPE_END : GetRailType(w->window_number);
-
-	bv->eng_list.clear();
-
-	/* Make list of all available train engines and wagons.
-	 * Also check to see if the previously selected engine is still available,
-	 * and if not, reset selection to INVALID_ENGINE. This could be the case
-	 * when engines become obsolete and are removed */
-	const Engine *e;
-	FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) {
-		EngineID eid = e->index;
-		const RailVehicleInfo *rvi = &e->u.rail;
-
-		if (bv->filter.railtype != RAILTYPE_END && !HasPowerOnRail(rvi->railtype, bv->filter.railtype)) continue;
-		if (!IsEngineBuildable(eid, VEH_TRAIN, _local_player)) continue;
-
-		bv->eng_list.push_back(eid);
-		if (rvi->railveh_type != RAILVEH_WAGON) {
-			num_engines++;
-		} else {
-			num_wagons++;
-		}
-
-		if (eid == bv->sel_engine) sel_id = eid;
-	}
-
-	bv->sel_engine = sel_id;
-
-	/* make engines first, and then wagons, sorted by ListPositionOfEngine() */
-	_internal_sort_order = false;
-	EngList_Sort(&bv->eng_list, TrainEnginesThenWagonsSorter);
-
-	/* and then sort engines */
-	_internal_sort_order = bv->descending_sort_order;
-	EngList_SortPartial(&bv->eng_list, _sorter[0][bv->sort_criteria], 0, num_engines);
-
-	/* and finally sort wagons */
-	EngList_SortPartial(&bv->eng_list, _sorter[0][bv->sort_criteria], num_engines, num_wagons);
-}
-
-/* Figure out what road vehicle EngineIDs to put in the list */
-static void GenerateBuildRoadVehList(Window *w)
-{
-	EngineID sel_id = INVALID_ENGINE;
-	buildvehicle_d *bv = &WP(w, buildvehicle_d);
-
-	bv->eng_list.clear();
-
-	const Engine *e;
-	FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) {
-		EngineID eid = e->index;
-		if (!IsEngineBuildable(eid, VEH_ROAD, _local_player)) continue;
-		if (!HasBit(bv->filter.roadtypes, HasBit(EngInfo(eid)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD)) continue;
-		bv->eng_list.push_back(eid);
-
-		if (eid == bv->sel_engine) sel_id = eid;
-	}
-	bv->sel_engine = sel_id;
-}
-
-/* Figure out what ship EngineIDs to put in the list */
-static void GenerateBuildShipList(Window *w)
-{
-	EngineID sel_id = INVALID_ENGINE;
-	buildvehicle_d *bv = &WP(w, buildvehicle_d);
-
-	bv->eng_list.clear();
-
-	const Engine *e;
-	FOR_ALL_ENGINES_OF_TYPE(e, VEH_SHIP) {
-		EngineID eid = e->index;
-		if (!IsEngineBuildable(eid, VEH_SHIP, _local_player)) continue;
-		bv->eng_list.push_back(eid);
-
-		if (eid == bv->sel_engine) sel_id = eid;
-	}
-	bv->sel_engine = sel_id;
-}
-
-/* Figure out what aircraft EngineIDs to put in the list */
-static void GenerateBuildAircraftList(Window *w)
-{
-	EngineID sel_id = INVALID_ENGINE;
-	buildvehicle_d *bv = &WP(w, buildvehicle_d);
-
-	bv->eng_list.clear();
-
-	/* Make list of all available planes.
-	 * Also check to see if the previously selected plane is still available,
-	 * and if not, reset selection to INVALID_ENGINE. This could be the case
-	 * when planes become obsolete and are removed */
-	const Engine *e;
-	FOR_ALL_ENGINES_OF_TYPE(e, VEH_AIRCRAFT) {
-		EngineID eid = e->index;
-		if (!IsEngineBuildable(eid, VEH_AIRCRAFT, _local_player)) continue;
-		/* First VEH_END window_numbers are fake to allow a window open for all different types at once */
-		if (w->window_number > VEH_END && !CanAircraftUseStation(eid, w->window_number)) continue;
-
-		bv->eng_list.push_back(eid);
-		if (eid == bv->sel_engine) sel_id = eid;
-	}
-
-	bv->sel_engine = sel_id;
-}
-
-/* Generate the list of vehicles */
-static void GenerateBuildList(Window *w)
-{
-	buildvehicle_d *bv = &WP(w, buildvehicle_d);
-
-	switch (bv->vehicle_type) {
-		default: NOT_REACHED();
-		case VEH_TRAIN:
-			GenerateBuildTrainList(w);
-			return; // trains should not reach the last sorting
-		case VEH_ROAD:
-			GenerateBuildRoadVehList(w);
-			break;
-		case VEH_SHIP:
-			GenerateBuildShipList(w);
-			break;
-		case VEH_AIRCRAFT:
-			GenerateBuildAircraftList(w);
-			break;
-	}
-	_internal_sort_order = bv->descending_sort_order;
-	EngList_Sort(&bv->eng_list, _sorter[bv->vehicle_type][bv->sort_criteria]);
-}
-
 static void DrawVehicleEngine(VehicleType type, int x, int y, EngineID engine, SpriteID pal)
 {
 	switch (type) {
@@ -990,199 +792,400 @@
 	}
 }
 
-static void DrawBuildVehicleWindow(Window *w)
-{
-	const buildvehicle_d *bv = &WP(w, buildvehicle_d);
-	uint max = min(w->vscroll.pos + w->vscroll.cap, bv->eng_list.size());
-
-	w->SetWidgetDisabledState(BUILD_VEHICLE_WIDGET_BUILD, w->window_number <= VEH_END);
-
-	SetVScrollCount(w, bv->eng_list.size());
-	SetDParam(0, bv->filter.railtype + STR_881C_NEW_RAIL_VEHICLES); // This should only affect rail vehicles
 
-	/* Set text of sort by dropdown */
-	w->widget[BUILD_VEHICLE_WIDGET_SORT_DROPDOWN].data = _sort_listing[bv->vehicle_type][bv->sort_criteria];
-
-	DrawWindowWidgets(w);
-
-	DrawEngineList(bv->vehicle_type, w->widget[BUILD_VEHICLE_WIDGET_LIST].left + 2, w->widget[BUILD_VEHICLE_WIDGET_LIST].top + 1, bv->eng_list, w->vscroll.pos, max, bv->sel_engine, 0, DEFAULT_GROUP);
+struct BuildVehicleWindow : Window {
+	VehicleType vehicle_type;
+	union {
+		RailTypeByte railtype;
+		AirportFTAClass::Flags flags;
+		RoadTypes roadtypes;
+	} filter;
+	byte sel_index;  ///< deprecated value, used for 'unified' ship and road
+	bool descending_sort_order;
+	byte sort_criteria;
+	bool regenerate_list;
+	EngineID sel_engine;
+	EngineID rename_engine;
+	EngineList eng_list;
 
-	if (bv->sel_engine != INVALID_ENGINE) {
-		const Widget *wi = &w->widget[BUILD_VEHICLE_WIDGET_PANEL];
-		int text_end = DrawVehiclePurchaseInfo(2, wi->top + 1, wi->right - wi->left - 2, bv->sel_engine);
+	BuildVehicleWindow(const WindowDesc *desc, TileIndex tile, VehicleType type) : Window(desc, tile == 0 ? (int)type : tile)
+	{
+		this->vehicle_type = type;
+		int vlh = GetVehicleListHeight(this->vehicle_type);
 
-		if (text_end > wi->bottom) {
-			w->SetDirty();
-			ResizeWindowForWidget(w, BUILD_VEHICLE_WIDGET_PANEL, 0, text_end - wi->bottom);
-			w->SetDirty();
+		ResizeWindow(this, 0, vlh - 14);
+		this->resize.step_height = vlh;
+		this->vscroll.cap = 1;
+		this->widget[BUILD_VEHICLE_WIDGET_LIST].data = 0x101;
+
+		this->resize.width  = this->width;
+		this->resize.height = this->height;
+
+		this->caption_color = (tile != 0) ? GetTileOwner(tile) : _local_player;
+
+		this->sel_engine      = INVALID_ENGINE;
+		this->regenerate_list = false;
+
+		this->sort_criteria         = _last_sort_criteria[type];
+		this->descending_sort_order = _last_sort_order[type];
+
+		switch (type) {
+			default: NOT_REACHED();
+			case VEH_TRAIN:
+				this->filter.railtype = (tile == 0) ? RAILTYPE_END : GetRailType(tile);
+				break;
+			case VEH_ROAD:
+				this->filter.roadtypes = (tile == 0) ? ROADTYPES_ALL : GetRoadTypes(tile);
+			case VEH_SHIP:
+				break;
+			case VEH_AIRCRAFT:
+				this->filter.flags =
+					tile == 0 ? AirportFTAClass::ALL : GetStationByTile(tile)->Airport()->flags;
+				break;
+		}
+		this->SetupWindowStrings(type);
+		ResizeButtons(this, BUILD_VEHICLE_WIDGET_BUILD, BUILD_VEHICLE_WIDGET_RENAME);
+
+		this->GenerateBuildList(); // generate the list, since we need it in the next line
+		/* Select the first engine in the list as default when opening the window */
+		if (this->eng_list.size() > 0) this->sel_engine = this->eng_list[0];
+
+		this->FindWindowPlacementAndResize(desc);
+	}
+
+	/* Setup widget strings to fit the different types of vehicles */
+	void SetupWindowStrings(VehicleType type)
+	{
+		switch (type) {
+			default: NOT_REACHED();
+
+			case VEH_TRAIN:
+				this->widget[BUILD_VEHICLE_WIDGET_CAPTION].data    = STR_JUST_STRING;
+				this->widget[BUILD_VEHICLE_WIDGET_LIST].tooltips   = STR_8843_TRAIN_VEHICLE_SELECTION;
+				this->widget[BUILD_VEHICLE_WIDGET_BUILD].data      = STR_881F_BUILD_VEHICLE;
+				this->widget[BUILD_VEHICLE_WIDGET_BUILD].tooltips  = STR_8844_BUILD_THE_HIGHLIGHTED_TRAIN;
+				this->widget[BUILD_VEHICLE_WIDGET_RENAME].data     = STR_8820_RENAME;
+				this->widget[BUILD_VEHICLE_WIDGET_RENAME].tooltips = STR_8845_RENAME_TRAIN_VEHICLE_TYPE;
+				break;
+
+			case VEH_ROAD:
+				this->widget[BUILD_VEHICLE_WIDGET_CAPTION].data    = STR_9006_NEW_ROAD_VEHICLES;
+				this->widget[BUILD_VEHICLE_WIDGET_LIST].tooltips   = STR_9026_ROAD_VEHICLE_SELECTION;
+				this->widget[BUILD_VEHICLE_WIDGET_BUILD].data      = STR_9007_BUILD_VEHICLE;
+				this->widget[BUILD_VEHICLE_WIDGET_BUILD].tooltips  = STR_9027_BUILD_THE_HIGHLIGHTED_ROAD;
+				this->widget[BUILD_VEHICLE_WIDGET_RENAME].data     = STR_9034_RENAME;
+				this->widget[BUILD_VEHICLE_WIDGET_RENAME].tooltips = STR_9035_RENAME_ROAD_VEHICLE_TYPE;
+				break;
+
+			case VEH_SHIP:
+				this->widget[BUILD_VEHICLE_WIDGET_CAPTION].data    = STR_9808_NEW_SHIPS;
+				this->widget[BUILD_VEHICLE_WIDGET_LIST].tooltips   = STR_9825_SHIP_SELECTION_LIST_CLICK;
+				this->widget[BUILD_VEHICLE_WIDGET_BUILD].data      = STR_9809_BUILD_SHIP;
+				this->widget[BUILD_VEHICLE_WIDGET_BUILD].tooltips  = STR_9826_BUILD_THE_HIGHLIGHTED_SHIP;
+				this->widget[BUILD_VEHICLE_WIDGET_RENAME].data     = STR_9836_RENAME;
+				this->widget[BUILD_VEHICLE_WIDGET_RENAME].tooltips = STR_9837_RENAME_SHIP_TYPE;
+				break;
+
+			case VEH_AIRCRAFT:
+				this->widget[BUILD_VEHICLE_WIDGET_CAPTION].data    = STR_A005_NEW_AIRCRAFT;
+				this->widget[BUILD_VEHICLE_WIDGET_LIST].tooltips   = STR_A025_AIRCRAFT_SELECTION_LIST;
+				this->widget[BUILD_VEHICLE_WIDGET_BUILD].data      = STR_A006_BUILD_AIRCRAFT;
+				this->widget[BUILD_VEHICLE_WIDGET_BUILD].tooltips  = STR_A026_BUILD_THE_HIGHLIGHTED_AIRCRAFT;
+				this->widget[BUILD_VEHICLE_WIDGET_RENAME].data     = STR_A037_RENAME;
+				this->widget[BUILD_VEHICLE_WIDGET_RENAME].tooltips = STR_A038_RENAME_AIRCRAFT_TYPE;
+				break;
 		}
 	}
 
-	DrawSortButtonState(w, BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING, bv->descending_sort_order ? SBS_DOWN : SBS_UP);
-}
-
-static void BuildVehicleClickEvent(Window *w, WindowEvent *e)
-{
-	buildvehicle_d *bv = &WP(w, buildvehicle_d);
+	/* Figure out what train EngineIDs to put in the list */
+	void GenerateBuildTrainList()
+	{
+		EngineID sel_id = INVALID_ENGINE;
+		int num_engines = 0;
+		int num_wagons  = 0;
 
-	switch (e->we.click.widget) {
-		case BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING:
-			bv->descending_sort_order ^= true;
-			_last_sort_order[bv->vehicle_type] = bv->descending_sort_order;
-			bv->regenerate_list = true;
-			w->SetDirty();
-			break;
+		this->filter.railtype = (this->window_number <= VEH_END) ? RAILTYPE_END : GetRailType(this->window_number);
 
-		case BUILD_VEHICLE_WIDGET_LIST: {
-			uint i = (e->we.click.pt.y - w->widget[BUILD_VEHICLE_WIDGET_LIST].top) / GetVehicleListHeight(bv->vehicle_type) + w->vscroll.pos;
-			size_t num_items = bv->eng_list.size();
-			bv->sel_engine = (i < num_items) ? bv->eng_list[i] : INVALID_ENGINE;
-			w->SetDirty();
-			break;
+		this->eng_list.clear();
+
+		/* Make list of all available train engines and wagons.
+		* Also check to see if the previously selected engine is still available,
+		* and if not, reset selection to INVALID_ENGINE. This could be the case
+		* when engines become obsolete and are removed */
+		const Engine *e;
+		FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) {
+			EngineID eid = e->index;
+			const RailVehicleInfo *rvi = &e->u.rail;
+
+			if (this->filter.railtype != RAILTYPE_END && !HasPowerOnRail(rvi->railtype, this->filter.railtype)) continue;
+			if (!IsEngineBuildable(eid, VEH_TRAIN, _local_player)) continue;
+
+			this->eng_list.push_back(eid);
+			if (rvi->railveh_type != RAILVEH_WAGON) {
+				num_engines++;
+			} else {
+				num_wagons++;
+			}
+
+			if (eid == this->sel_engine) sel_id = eid;
 		}
 
-		case BUILD_VEHICLE_WIDGET_SORT_DROPDOWN: // Select sorting criteria dropdown menu
-			ShowDropDownMenu(w, _sort_listing[bv->vehicle_type], bv->sort_criteria, BUILD_VEHICLE_WIDGET_SORT_DROPDOWN, 0, 0);
-			break;
+		this->sel_engine = sel_id;
 
-		case BUILD_VEHICLE_WIDGET_BUILD: {
-			EngineID sel_eng = bv->sel_engine;
-			if (sel_eng != INVALID_ENGINE) {
-				switch (bv->vehicle_type) {
-					default: NOT_REACHED();
-					case VEH_TRAIN:
-						DoCommandP(w->window_number, sel_eng, 0, (RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) ? CcBuildWagon : CcBuildLoco,
-								   CMD_BUILD_RAIL_VEHICLE | CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE));
-						break;
-					case VEH_ROAD:
-						DoCommandP(w->window_number, sel_eng, 0, CcBuildRoadVeh, CMD_BUILD_ROAD_VEH | CMD_MSG(STR_9009_CAN_T_BUILD_ROAD_VEHICLE));
-						break;
-					case VEH_SHIP:
-						DoCommandP(w->window_number, sel_eng, 0, CcBuildShip, CMD_BUILD_SHIP | CMD_MSG(STR_980D_CAN_T_BUILD_SHIP));
-						break;
-					case VEH_AIRCRAFT:
-						DoCommandP(w->window_number, sel_eng, 0, CcBuildAircraft, CMD_BUILD_AIRCRAFT | CMD_MSG(STR_A008_CAN_T_BUILD_AIRCRAFT));
-						break;
-				}
-			}
-			break;
+		/* make engines first, and then wagons, sorted by ListPositionOfEngine() */
+		_internal_sort_order = false;
+		EngList_Sort(&this->eng_list, TrainEnginesThenWagonsSorter);
+
+		/* and then sort engines */
+		_internal_sort_order = this->descending_sort_order;
+		EngList_SortPartial(&this->eng_list, _sorter[0][this->sort_criteria], 0, num_engines);
+
+		/* and finally sort wagons */
+		EngList_SortPartial(&this->eng_list, _sorter[0][this->sort_criteria], num_engines, num_wagons);
+	}
+
+	/* Figure out what road vehicle EngineIDs to put in the list */
+	void GenerateBuildRoadVehList()
+	{
+		EngineID sel_id = INVALID_ENGINE;
+
+		this->eng_list.clear();
+
+		const Engine *e;
+		FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) {
+			EngineID eid = e->index;
+			if (!IsEngineBuildable(eid, VEH_ROAD, _local_player)) continue;
+			if (!HasBit(this->filter.roadtypes, HasBit(EngInfo(eid)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD)) continue;
+			this->eng_list.push_back(eid);
+
+			if (eid == this->sel_engine) sel_id = eid;
+		}
+		this->sel_engine = sel_id;
+	}
+
+	/* Figure out what ship EngineIDs to put in the list */
+	void GenerateBuildShipList()
+	{
+		EngineID sel_id = INVALID_ENGINE;
+		this->eng_list.clear();
+
+		const Engine *e;
+		FOR_ALL_ENGINES_OF_TYPE(e, VEH_SHIP) {
+			EngineID eid = e->index;
+			if (!IsEngineBuildable(eid, VEH_SHIP, _local_player)) continue;
+			this->eng_list.push_back(eid);
+
+			if (eid == this->sel_engine) sel_id = eid;
+		}
+		this->sel_engine = sel_id;
+	}
+
+	/* Figure out what aircraft EngineIDs to put in the list */
+	void GenerateBuildAircraftList()
+	{
+		EngineID sel_id = INVALID_ENGINE;
+
+		this->eng_list.clear();
+
+		/* Make list of all available planes.
+		* Also check to see if the previously selected plane is still available,
+		* and if not, reset selection to INVALID_ENGINE. This could be the case
+		* when planes become obsolete and are removed */
+		const Engine *e;
+		FOR_ALL_ENGINES_OF_TYPE(e, VEH_AIRCRAFT) {
+			EngineID eid = e->index;
+			if (!IsEngineBuildable(eid, VEH_AIRCRAFT, _local_player)) continue;
+			/* First VEH_END window_numbers are fake to allow a window open for all different types at once */
+			if (this->window_number > VEH_END && !CanAircraftUseStation(eid, this->window_number)) continue;
+
+			this->eng_list.push_back(eid);
+			if (eid == this->sel_engine) sel_id = eid;
 		}
 
-		case BUILD_VEHICLE_WIDGET_RENAME: {
-			EngineID sel_eng = bv->sel_engine;
-			if (sel_eng != INVALID_ENGINE) {
-				StringID str = STR_NULL;
+		this->sel_engine = sel_id;
+	}
 
-				bv->rename_engine = sel_eng;
-				switch (bv->vehicle_type) {
-					default: NOT_REACHED();
-					case VEH_TRAIN:    str = STR_886A_RENAME_TRAIN_VEHICLE_TYPE; break;
-					case VEH_ROAD:     str = STR_9036_RENAME_ROAD_VEHICLE_TYPE;  break;
-					case VEH_SHIP:     str = STR_9838_RENAME_SHIP_TYPE;          break;
-					case VEH_AIRCRAFT: str = STR_A039_RENAME_AIRCRAFT_TYPE;      break;
+	/* Generate the list of vehicles */
+	void GenerateBuildList()
+	{
+		switch (this->vehicle_type) {
+			default: NOT_REACHED();
+			case VEH_TRAIN:
+				this->GenerateBuildTrainList();
+				return; // trains should not reach the last sorting
+			case VEH_ROAD:
+				this->GenerateBuildRoadVehList();
+				break;
+			case VEH_SHIP:
+				this->GenerateBuildShipList();
+				break;
+			case VEH_AIRCRAFT:
+				this->GenerateBuildAircraftList();
+				break;
+		}
+		_internal_sort_order = this->descending_sort_order;
+		EngList_Sort(&this->eng_list, _sorter[this->vehicle_type][this->sort_criteria]);
+	}
+
+	void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING:
+				this->descending_sort_order ^= true;
+				_last_sort_order[this->vehicle_type] = this->descending_sort_order;
+				this->regenerate_list = true;
+				this->SetDirty();
+				break;
+
+			case BUILD_VEHICLE_WIDGET_LIST: {
+				uint i = (pt.y - this->widget[BUILD_VEHICLE_WIDGET_LIST].top) / GetVehicleListHeight(this->vehicle_type) + this->vscroll.pos;
+				size_t num_items = this->eng_list.size();
+				this->sel_engine = (i < num_items) ? this->eng_list[i] : INVALID_ENGINE;
+				this->SetDirty();
+				break;
+			}
+
+			case BUILD_VEHICLE_WIDGET_SORT_DROPDOWN: // Select sorting criteria dropdown menu
+				ShowDropDownMenu(this, _sort_listing[this->vehicle_type], this->sort_criteria, BUILD_VEHICLE_WIDGET_SORT_DROPDOWN, 0, 0);
+				break;
+
+			case BUILD_VEHICLE_WIDGET_BUILD: {
+				EngineID sel_eng = this->sel_engine;
+				if (sel_eng != INVALID_ENGINE) {
+					switch (this->vehicle_type) {
+						default: NOT_REACHED();
+						case VEH_TRAIN:
+							DoCommandP(this->window_number, sel_eng, 0, (RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) ? CcBuildWagon : CcBuildLoco,
+										CMD_BUILD_RAIL_VEHICLE | CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE));
+							break;
+						case VEH_ROAD:
+							DoCommandP(this->window_number, sel_eng, 0, CcBuildRoadVeh, CMD_BUILD_ROAD_VEH | CMD_MSG(STR_9009_CAN_T_BUILD_ROAD_VEHICLE));
+							break;
+						case VEH_SHIP:
+							DoCommandP(this->window_number, sel_eng, 0, CcBuildShip, CMD_BUILD_SHIP | CMD_MSG(STR_980D_CAN_T_BUILD_SHIP));
+							break;
+						case VEH_AIRCRAFT:
+							DoCommandP(this->window_number, sel_eng, 0, CcBuildAircraft, CMD_BUILD_AIRCRAFT | CMD_MSG(STR_A008_CAN_T_BUILD_AIRCRAFT));
+							break;
+					}
 				}
-				SetDParam(0, sel_eng);
-				ShowQueryString(STR_ENGINE_NAME, str, 31, 160, w, CS_ALPHANUMERAL);
+				break;
 			}
-			break;
+
+			case BUILD_VEHICLE_WIDGET_RENAME: {
+				EngineID sel_eng = this->sel_engine;
+				if (sel_eng != INVALID_ENGINE) {
+					StringID str = STR_NULL;
+
+					this->rename_engine = sel_eng;
+					switch (this->vehicle_type) {
+						default: NOT_REACHED();
+						case VEH_TRAIN:    str = STR_886A_RENAME_TRAIN_VEHICLE_TYPE; break;
+						case VEH_ROAD:     str = STR_9036_RENAME_ROAD_VEHICLE_TYPE;  break;
+						case VEH_SHIP:     str = STR_9838_RENAME_SHIP_TYPE;          break;
+						case VEH_AIRCRAFT: str = STR_A039_RENAME_AIRCRAFT_TYPE;      break;
+					}
+					SetDParam(0, sel_eng);
+					ShowQueryString(STR_ENGINE_NAME, str, 31, 160, this, CS_ALPHANUMERAL);
+				}
+				break;
+			}
 		}
 	}
-}
-
-static void NewVehicleWndProc(Window *w, WindowEvent *e)
-{
-	buildvehicle_d *bv = &WP(w, buildvehicle_d);
-
-	switch (e->event) {
-		case WE_CREATE: {
-			bv->vehicle_type = *(VehicleType*)e->we.create.data;
-			int vlh = GetVehicleListHeight(bv->vehicle_type);
-
-			ResizeWindow(w, 0, vlh - 14);
-			w->resize.step_height = vlh;
-			w->vscroll.cap = 1;
-			w->widget[BUILD_VEHICLE_WIDGET_LIST].data = 0x101;
-
-			w->resize.width  = w->width;
-			w->resize.height = w->height;
-		} break;
-
-		case WE_INVALIDATE_DATA:
-			bv->regenerate_list = true;
-			w->SetDirty();
-			break;
-
-		case WE_DESTROY:
-			bv->eng_list.~EngineList(); // call destructor explicitly
-			break;
 
-		case WE_PAINT:
-			if (bv->regenerate_list) {
-				bv->regenerate_list = false;
-				GenerateBuildList(w);
-			}
-			DrawBuildVehicleWindow(w);
-			break;
-
-		case WE_CLICK:
-			BuildVehicleClickEvent(w, e);
-			break;
+	virtual void OnInvalidateData(int data)
+	{
+		this->regenerate_list = true;
+	}
 
-		case WE_DOUBLE_CLICK:
-			if (e->we.click.widget == BUILD_VEHICLE_WIDGET_LIST) {
-				/* When double clicking, we want to buy a vehicle */
-				e->we.click.widget = BUILD_VEHICLE_WIDGET_BUILD;
-				BuildVehicleClickEvent(w, e);
-			}
-			break;
-
-		case WE_ON_EDIT_TEXT: {
-			if (!StrEmpty(e->we.edittext.str)) {
-				StringID str = STR_NULL;
-				_cmd_text = e->we.edittext.str;
-				switch (bv->vehicle_type) {
-					default: NOT_REACHED();
-					case VEH_TRAIN:    str = STR_886B_CAN_T_RENAME_TRAIN_VEHICLE; break;
-					case VEH_ROAD:     str = STR_9037_CAN_T_RENAME_ROAD_VEHICLE;  break;
-					case VEH_SHIP:     str = STR_9839_CAN_T_RENAME_SHIP_TYPE;     break;
-					case VEH_AIRCRAFT: str = STR_A03A_CAN_T_RENAME_AIRCRAFT_TYPE; break;
-				}
-				DoCommandP(0, bv->rename_engine, 0, NULL, CMD_RENAME_ENGINE | CMD_MSG(str));
-			}
-			break;
+	virtual void OnPaint()
+	{
+		if (this->regenerate_list) {
+			this->regenerate_list = false;
+			this->GenerateBuildList();
 		}
 
-		case WE_DROPDOWN_SELECT: // we have selected a dropdown item in the list
-			if (bv->sort_criteria != e->we.dropdown.index) {
-				bv->sort_criteria = e->we.dropdown.index;
-				_last_sort_criteria[bv->vehicle_type] = bv->sort_criteria;
-				bv->regenerate_list = true;
-			}
-			w->SetDirty();
-			break;
+		uint max = min(this->vscroll.pos + this->vscroll.cap, this->eng_list.size());
 
-		case WE_RESIZE:
-			if (e->we.sizing.diff.x != 0) ResizeButtons(w, BUILD_VEHICLE_WIDGET_BUILD, BUILD_VEHICLE_WIDGET_RENAME);
-			if (e->we.sizing.diff.y == 0) break;
+		this->SetWidgetDisabledState(BUILD_VEHICLE_WIDGET_BUILD, this->window_number <= VEH_END);
 
-			w->vscroll.cap += e->we.sizing.diff.y / (int)GetVehicleListHeight(bv->vehicle_type);
-			w->widget[BUILD_VEHICLE_WIDGET_LIST].data = (w->vscroll.cap << 8) + 1;
-			break;
+		SetVScrollCount(this, this->eng_list.size());
+		SetDParam(0, this->filter.railtype + STR_881C_NEW_RAIL_VEHICLES); // This should only affect rail vehicles
+
+		/* Set text of sort by dropdown */
+		this->widget[BUILD_VEHICLE_WIDGET_SORT_DROPDOWN].data = _sort_listing[this->vehicle_type][this->sort_criteria];
+
+		this->DrawWidgets();
+
+		DrawEngineList(this->vehicle_type, this->widget[BUILD_VEHICLE_WIDGET_LIST].left + 2, this->widget[BUILD_VEHICLE_WIDGET_LIST].top + 1, this->eng_list, this->vscroll.pos, max, this->sel_engine, 0, DEFAULT_GROUP);
+
+		if (this->sel_engine != INVALID_ENGINE) {
+			const Widget *wi = &this->widget[BUILD_VEHICLE_WIDGET_PANEL];
+			int text_end = DrawVehiclePurchaseInfo(2, wi->top + 1, wi->right - wi->left - 2, this->sel_engine);
+
+			if (text_end > wi->bottom) {
+				this->SetDirty();
+				ResizeWindowForWidget(this, BUILD_VEHICLE_WIDGET_PANEL, 0, text_end - wi->bottom);
+				this->SetDirty();
+			}
+		}
+
+		this->DrawSortButtonState(BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING, this->descending_sort_order ? SBS_DOWN : SBS_UP);
 	}
-}
+
+	virtual void OnDoubleClick(Point pt, int widget)
+	{
+		if (widget == BUILD_VEHICLE_WIDGET_LIST) {
+			/* When double clicking, we want to buy a vehicle */
+			this->OnClick(pt, BUILD_VEHICLE_WIDGET_BUILD);
+		}
+	}
+
+	virtual void OnQueryTextFinished(char *str)
+	{
+		if (!StrEmpty(str)) {
+			StringID err_str = STR_NULL;
+			_cmd_text = str;
+			switch (this->vehicle_type) {
+				default: NOT_REACHED();
+				case VEH_TRAIN:    err_str = STR_886B_CAN_T_RENAME_TRAIN_VEHICLE; break;
+				case VEH_ROAD:     err_str = STR_9037_CAN_T_RENAME_ROAD_VEHICLE;  break;
+				case VEH_SHIP:     err_str = STR_9839_CAN_T_RENAME_SHIP_TYPE;     break;
+				case VEH_AIRCRAFT: err_str = STR_A03A_CAN_T_RENAME_AIRCRAFT_TYPE; break;
+			}
+			DoCommandP(0, this->rename_engine, 0, NULL, CMD_RENAME_ENGINE | CMD_MSG(err_str));
+		}
+	}
+
+	virtual void OnDropdownSelect(int widget, int index)
+	{
+		if (this->sort_criteria != index) {
+			this->sort_criteria = index;
+			_last_sort_criteria[this->vehicle_type] = this->sort_criteria;
+			this->regenerate_list = true;
+		}
+		this->SetDirty();
+	}
+
+	virtual void OnResize(Point new_size, Point delta)
+	{
+		if (delta.x != 0) ResizeButtons(this, BUILD_VEHICLE_WIDGET_BUILD, BUILD_VEHICLE_WIDGET_RENAME);
+		if (delta.y == 0) return;
+
+		this->vscroll.cap += delta.y / (int)GetVehicleListHeight(this->vehicle_type);
+		this->widget[BUILD_VEHICLE_WIDGET_LIST].data = (this->vscroll.cap << 8) + 1;
+	}
+};
 
 static const WindowDesc _build_vehicle_desc = {
 	WDP_AUTO, WDP_AUTO, 240, 174, 240, 256,
 	WC_BUILD_VEHICLE, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
 	_build_vehicle_widgets,
-	NewVehicleWndProc
 };
 
 void ShowBuildVehicleWindow(TileIndex tile, VehicleType type)
 {
-	buildvehicle_d *bv;
-	Window *w;
 	/* We want to be able to open both Available Train as Available Ships,
 	 *  so if tile == 0 (Available XXX Window), use 'type' as unique number.
 	 *  As it always is a low value, it won't collide with any real tile
@@ -1193,39 +1196,5 @@
 
 	DeleteWindowById(WC_BUILD_VEHICLE, num);
 
-	w = AllocateWindowDescFront<Window>(&_build_vehicle_desc, num, &type);
-
-	if (w == NULL) return;
-
-	w->caption_color = (tile != 0) ? GetTileOwner(tile) : _local_player;
-
-	bv = &WP(w, buildvehicle_d);
-	new (&bv->eng_list) EngineList();
-	bv->sel_engine      = INVALID_ENGINE;
-
-	bv->regenerate_list = false;
-
-	bv->sort_criteria         = _last_sort_criteria[type];
-	bv->descending_sort_order = _last_sort_order[type];
-
-	switch (type) {
-		default: NOT_REACHED();
-		case VEH_TRAIN:
-			WP(w, buildvehicle_d).filter.railtype = (tile == 0) ? RAILTYPE_END : GetRailType(tile);
-			break;
-		case VEH_ROAD:
-			WP(w, buildvehicle_d).filter.roadtypes = (tile == 0) ? ROADTYPES_ALL : GetRoadTypes(tile);
-		case VEH_SHIP:
-			break;
-		case VEH_AIRCRAFT:
-			bv->filter.flags =
-				tile == 0 ? AirportFTAClass::ALL : GetStationByTile(tile)->Airport()->flags;
-			break;
-	}
-	SetupWindowStrings(w, type);
-	ResizeButtons(w, BUILD_VEHICLE_WIDGET_BUILD, BUILD_VEHICLE_WIDGET_RENAME);
-
-	GenerateBuildList(w); // generate the list, since we need it in the next line
-	/* Select the first engine in the list as default when opening the window */
-	if (bv->eng_list.size() > 0) bv->sel_engine = bv->eng_list[0];
+	new BuildVehicleWindow(&_build_vehicle_desc, tile, type);
 }
--- a/src/cheat_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/cheat_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -120,114 +120,117 @@
 {   WIDGETS_END},
 };
 
-static void CheatsWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			int clk = WP(w, def_d).data_1;
-
-			DrawWindowWidgets(w);
-			DrawStringMultiCenter(200, 25, STR_CHEATS_WARNING, w->width - 50);
-
-			for (int i = 0, x = 0, y = 45; i != lengthof(_cheats_ui); i++) {
-				const CheatEntry *ce = &_cheats_ui[i];
-
-				DrawSprite((*ce->been_used) ? SPR_BOX_CHECKED : SPR_BOX_EMPTY, PAL_NONE, x + 5, y + 2);
-
-				switch (ce->type) {
-					case SLE_BOOL: {
-						bool on = (*(bool*)ce->variable);
-
-						DrawFrameRect(x + 20, y + 1, x + 30 + 9, y + 9, on ? 6 : 4, on ? FR_LOWERED : FR_NONE);
-						SetDParam(0, on ? STR_CONFIG_PATCHES_ON : STR_CONFIG_PATCHES_OFF);
-					} break;
-
-					default: {
-						int32 val = (int32)ReadValue(ce->variable, ce->type);
-						char buf[512];
+struct CheatWindow : Window {
+	int clicked;
 
-						/* Draw [<][>] boxes for settings of an integer-type */
-						DrawArrowButtons(x + 20, y, 3, clk - (i * 2), true, true);
-
-						switch (ce->str) {
-							/* Display date for change date cheat */
-							case STR_CHEAT_CHANGE_DATE: SetDParam(0, _date); break;
-
-							/* Draw colored flag for change player cheat */
-							case STR_CHEAT_CHANGE_PLAYER:
-								SetDParam(0, val);
-								GetString(buf, STR_CHEAT_CHANGE_PLAYER, lastof(buf));
-								DrawPlayerIcon(_current_player, 60 + GetStringBoundingBox(buf).width, y + 2);
-								break;
+	CheatWindow(const WindowDesc *desc) : Window(desc)
+	{
+	}
 
-							/* Set correct string for switch climate cheat */
-							case STR_CHEAT_SWITCH_CLIMATE: val += STR_TEMPERATE_LANDSCAPE;
+	virtual void OnPaint()
+	{
+		this->DrawWidgets();
+		DrawStringMultiCenter(200, 25, STR_CHEATS_WARNING, width - 50);
 
-							/* Fallthrough */
-							default: SetDParam(0, val);
-						}
-					} break;
-				}
+		for (int i = 0, x = 0, y = 45; i != lengthof(_cheats_ui); i++) {
+			const CheatEntry *ce = &_cheats_ui[i];
 
-				DrawString(50, y + 1, ce->str, TC_FROMSTRING);
+			DrawSprite((*ce->been_used) ? SPR_BOX_CHECKED : SPR_BOX_EMPTY, PAL_NONE, x + 5, y + 2);
 
-				y += 12;
+			switch (ce->type) {
+				case SLE_BOOL: {
+					bool on = (*(bool*)ce->variable);
+
+					DrawFrameRect(x + 20, y + 1, x + 30 + 9, y + 9, on ? 6 : 4, on ? FR_LOWERED : FR_NONE);
+					SetDParam(0, on ? STR_CONFIG_PATCHES_ON : STR_CONFIG_PATCHES_OFF);
+				} break;
+
+				default: {
+					int32 val = (int32)ReadValue(ce->variable, ce->type);
+					char buf[512];
+
+					/* Draw [<][>] boxes for settings of an integer-type */
+					DrawArrowButtons(x + 20, y, 3, clicked - (i * 2), true, true);
+
+					switch (ce->str) {
+						/* Display date for change date cheat */
+						case STR_CHEAT_CHANGE_DATE: SetDParam(0, _date); break;
+
+						/* Draw colored flag for change player cheat */
+						case STR_CHEAT_CHANGE_PLAYER:
+							SetDParam(0, val);
+							GetString(buf, STR_CHEAT_CHANGE_PLAYER, lastof(buf));
+							DrawPlayerIcon(_current_player, 60 + GetStringBoundingBox(buf).width, y + 2);
+							break;
+
+						/* Set correct string for switch climate cheat */
+						case STR_CHEAT_SWITCH_CLIMATE: val += STR_TEMPERATE_LANDSCAPE;
+
+						/* Fallthrough */
+						default: SetDParam(0, val);
+					}
+				} break;
 			}
-			break;
+
+			DrawString(50, y + 1, ce->str, TC_FROMSTRING);
+
+			y += 12;
+		}
+	}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		uint btn = (pt.y - 46) / 12;
+		uint x = pt.x;
+
+		/* Not clicking a button? */
+		if (!IsInsideMM(x, 20, 40) || btn >= lengthof(_cheats_ui)) return;
+
+		const CheatEntry *ce = &_cheats_ui[btn];
+		int value = (int32)ReadValue(ce->variable, ce->type);
+		int oldvalue = value;
+
+		*ce->been_used = true;
+
+		switch (ce->type) {
+			case SLE_BOOL:
+				value ^= 1;
+				if (ce->proc != NULL) ce->proc(value, 0);
+				break;
+
+			default:
+				/* Take whatever the function returns */
+				value = ce->proc(value + ((x >= 30) ? 1 : -1), (x >= 30) ? 1 : -1);
+
+				/* The first cheat (money), doesn't return a different value. */
+				if (value != oldvalue || btn == 0) this->clicked = btn * 2 + 1 + ((x >= 30) ? 1 : 0);
+				break;
 		}
 
-		case WE_CLICK: {
-			uint btn = (e->we.click.pt.y - 46) / 12;
-			uint x = e->we.click.pt.x;
-
-			/* Not clicking a button? */
-			if (!IsInsideMM(x, 20, 40) || btn >= lengthof(_cheats_ui)) break;
-
-			const CheatEntry *ce = &_cheats_ui[btn];
-			int value = (int32)ReadValue(ce->variable, ce->type);
-			int oldvalue = value;
-
-			*ce->been_used = true;
-
-			switch (ce->type) {
-				case SLE_BOOL:
-					value ^= 1;
-					if (ce->proc != NULL) ce->proc(value, 0);
-					break;
+		if (value != oldvalue) WriteValue(ce->variable, ce->type, (int64)value);
 
-				default:
-					/* Take whatever the function returns */
-					value = ce->proc(value + ((x >= 30) ? 1 : -1), (x >= 30) ? 1 : -1);
-
-					if (value != oldvalue) WP(w, def_d).data_1 = btn * 2 + 1 + ((x >= 30) ? 1 : 0);
-					break;
-			}
-
-			if (value != oldvalue) WriteValue(ce->variable, ce->type, (int64)value);
+		flags4 |= 5 << WF_TIMEOUT_SHL;
 
-			w->flags4 |= 5 << WF_TIMEOUT_SHL;
-
-			w->SetDirty();
-		} break;
+		SetDirty();
+	}
 
-		case WE_TIMEOUT:
-			WP(w, def_d).data_1 = 0;
-			w->SetDirty();
-			break;
+	virtual void OnTimeout()
+	{
+		this->clicked = 0;
+		this->SetDirty();
 	}
-}
+};
 
 static const WindowDesc _cheats_desc = {
 	240, 22, 400, 170, 400, 170,
 	WC_CHEATS, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
 	_cheat_widgets,
-	CheatsWndProc
 };
 
 
 void ShowCheatWindow()
 {
 	DeleteWindowById(WC_CHEATS, 0);
-	new Window(&_cheats_desc);
+	new CheatWindow(&_cheats_desc);
 }
--- a/src/console.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/console.cpp	Mon May 19 15:13:58 2008 +0000
@@ -77,137 +77,167 @@
 static void IConsoleHistoryAdd(const char *cmd);
 static void IConsoleHistoryNavigate(int direction);
 
-/* ** console window ** */
-static void IConsoleWndProc(Window *w, WindowEvent *e)
+struct IConsoleWindow : Window
 {
-	static byte iconsole_scroll = ICON_BUFFER;
+	static byte scroll;
 
-	switch (e->event) {
-		case WE_PAINT: {
-			int i = iconsole_scroll;
-			int max = (w->height / ICON_LINE_HEIGHT) - 1;
-			int delta = 0;
-			GfxFillRect(w->left, w->top, w->width, w->height - 1, 0);
-			while ((i > 0) && (i > iconsole_scroll - max) && (_iconsole_buffer[i] != NULL)) {
-				DoDrawString(_iconsole_buffer[i], 5,
-					w->height - (iconsole_scroll + 2 - i) * ICON_LINE_HEIGHT, _iconsole_cbuffer[i]);
-				i--;
-			}
-			/* If the text is longer than the window, don't show the starting ']' */
-			delta = w->width - 10 - _iconsole_cmdline.width - ICON_RIGHT_BORDERWIDTH;
-			if (delta > 0) {
-				DoDrawString("]", 5, w->height - ICON_LINE_HEIGHT, _icolour_cmd);
-				delta = 0;
-			}
+	IConsoleWindow(const WindowDesc *desc) : Window(desc)
+	{
+		_iconsole_mode = ICONSOLE_OPENED;
+		SetBit(_no_scroll, SCROLL_CON); // override cursor arrows; the gamefield will not scroll
 
-			DoDrawString(_iconsole_cmdline.buf, 10 + delta, w->height - ICON_LINE_HEIGHT, _icolour_cmd);
+		this->height = _screen.height / 3;
+		this->width  = _screen.width;
+	}
 
-			if (_iconsole_cmdline.caret)
-				DoDrawString("_", 10 + delta + _iconsole_cmdline.caretxoffs, w->height - ICON_LINE_HEIGHT, TC_WHITE);
-			break;
+	~IConsoleWindow()
+	{
+		_iconsole_mode = ICONSOLE_CLOSED;
+		ClrBit(_no_scroll, SCROLL_CON);
+	}
+
+	virtual void OnPaint()
+	{
+		int i = IConsoleWindow::scroll;
+		int max = (this->height / ICON_LINE_HEIGHT) - 1;
+		int delta = 0;
+		GfxFillRect(this->left, this->top, this->width, this->height - 1, 0);
+		while ((i > 0) && (i > IConsoleWindow::scroll - max) && (_iconsole_buffer[i] != NULL)) {
+			DoDrawString(_iconsole_buffer[i], 5,
+				this->height - (IConsoleWindow::scroll + 2 - i) * ICON_LINE_HEIGHT, _iconsole_cbuffer[i]);
+			i--;
 		}
-		case WE_MOUSELOOP:
-			if (HandleCaret(&_iconsole_cmdline)) w->SetDirty();
-			break;
-		case WE_DESTROY:
-			_iconsole_mode = ICONSOLE_CLOSED;
-			break;
-		case WE_KEYPRESS:
-			e->we.keypress.cont = false;
-			switch (e->we.keypress.keycode) {
-				case WKC_UP:
-					IConsoleHistoryNavigate(+1);
-					w->SetDirty();
-					break;
-				case WKC_DOWN:
-					IConsoleHistoryNavigate(-1);
-					w->SetDirty();
-					break;
-				case WKC_SHIFT | WKC_PAGEUP:
-					if (iconsole_scroll - (w->height / ICON_LINE_HEIGHT) - 1 < 0) {
-						iconsole_scroll = 0;
-					} else {
-						iconsole_scroll -= (w->height / ICON_LINE_HEIGHT) - 1;
-					}
-					w->SetDirty();
-					break;
-				case WKC_SHIFT | WKC_PAGEDOWN:
-					if (iconsole_scroll + (w->height / ICON_LINE_HEIGHT) - 1 > ICON_BUFFER) {
-						iconsole_scroll = ICON_BUFFER;
-					} else {
-						iconsole_scroll += (w->height / ICON_LINE_HEIGHT) - 1;
-					}
-					w->SetDirty();
-					break;
-				case WKC_SHIFT | WKC_UP:
-					if (iconsole_scroll <= 0) {
-						iconsole_scroll = 0;
-					} else {
-						--iconsole_scroll;
-					}
-					w->SetDirty();
-					break;
-				case WKC_SHIFT | WKC_DOWN:
-					if (iconsole_scroll >= ICON_BUFFER) {
-						iconsole_scroll = ICON_BUFFER;
-					} else {
-						++iconsole_scroll;
-					}
-					w->SetDirty();
-					break;
-				case WKC_BACKQUOTE:
-					IConsoleSwitch();
-					break;
-				case WKC_RETURN: case WKC_NUM_ENTER:
-					IConsolePrintF(_icolour_cmd, "] %s", _iconsole_cmdline.buf);
-					IConsoleHistoryAdd(_iconsole_cmdline.buf);
+		/* If the text is longer than the window, don't show the starting ']' */
+		delta = this->width - 10 - _iconsole_cmdline.width - ICON_RIGHT_BORDERWIDTH;
+		if (delta > 0) {
+			DoDrawString("]", 5, this->height - ICON_LINE_HEIGHT, _icolour_cmd);
+			delta = 0;
+		}
 
-					IConsoleCmdExec(_iconsole_cmdline.buf);
-					IConsoleClearCommand();
-					break;
-				case WKC_CTRL | WKC_RETURN:
-					_iconsole_mode = (_iconsole_mode == ICONSOLE_FULL) ? ICONSOLE_OPENED : ICONSOLE_FULL;
-					IConsoleResize(w);
-					MarkWholeScreenDirty();
-					break;
-				case (WKC_CTRL | 'V'):
-					if (InsertTextBufferClipboard(&_iconsole_cmdline)) {
-						IConsoleResetHistoryPos();
-						w->SetDirty();
-					}
-					break;
-				case (WKC_CTRL | 'L'):
-					IConsoleCmdExec("clear");
-					break;
-				case (WKC_CTRL | 'U'):
-					DeleteTextBufferAll(&_iconsole_cmdline);
-					w->SetDirty();
-					break;
-				case WKC_BACKSPACE: case WKC_DELETE:
-					if (DeleteTextBufferChar(&_iconsole_cmdline, e->we.keypress.keycode)) {
-						IConsoleResetHistoryPos();
-						w->SetDirty();
-					}
-					break;
-				case WKC_LEFT: case WKC_RIGHT: case WKC_END: case WKC_HOME:
-					if (MoveTextBufferPos(&_iconsole_cmdline, e->we.keypress.keycode)) {
-						IConsoleResetHistoryPos();
-						w->SetDirty();
-					}
-					break;
-				default:
-					if (IsValidChar(e->we.keypress.key, CS_ALPHANUMERAL)) {
-						iconsole_scroll = ICON_BUFFER;
-						InsertTextBufferChar(&_iconsole_cmdline, e->we.keypress.key);
-						IConsoleResetHistoryPos();
-						w->SetDirty();
-					} else {
-						e->we.keypress.cont = true;
-					}
-			break;
+		DoDrawString(_iconsole_cmdline.buf, 10 + delta, this->height - ICON_LINE_HEIGHT, _icolour_cmd);
+
+		if (_iconsole_cmdline.caret) {
+			DoDrawString("_", 10 + delta + _iconsole_cmdline.caretxoffs, this->height - ICON_LINE_HEIGHT, TC_WHITE);
 		}
 	}
-}
+
+	virtual void OnMouseLoop()
+	{
+		if (HandleCaret(&_iconsole_cmdline)) this->SetDirty();
+	}
+
+	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+	{
+		switch (keycode) {
+			case WKC_UP:
+				IConsoleHistoryNavigate(+1);
+				this->SetDirty();
+				break;
+
+			case WKC_DOWN:
+				IConsoleHistoryNavigate(-1);
+				this->SetDirty();
+				break;
+
+			case WKC_SHIFT | WKC_PAGEUP:
+				if (IConsoleWindow::scroll - (this->height / ICON_LINE_HEIGHT) - 1 < 0) {
+					IConsoleWindow::scroll = 0;
+				} else {
+					IConsoleWindow::scroll -= (this->height / ICON_LINE_HEIGHT) - 1;
+				}
+				this->SetDirty();
+				break;
+
+			case WKC_SHIFT | WKC_PAGEDOWN:
+				if (IConsoleWindow::scroll + (this->height / ICON_LINE_HEIGHT) - 1 > ICON_BUFFER) {
+					IConsoleWindow::scroll = ICON_BUFFER;
+				} else {
+					IConsoleWindow::scroll += (this->height / ICON_LINE_HEIGHT) - 1;
+				}
+				this->SetDirty();
+				break;
+
+			case WKC_SHIFT | WKC_UP:
+				if (IConsoleWindow::scroll <= 0) {
+					IConsoleWindow::scroll = 0;
+				} else {
+					--IConsoleWindow::scroll;
+				}
+				this->SetDirty();
+				break;
+
+			case WKC_SHIFT | WKC_DOWN:
+				if (IConsoleWindow::scroll >= ICON_BUFFER) {
+					IConsoleWindow::scroll = ICON_BUFFER;
+				} else {
+					++IConsoleWindow::scroll;
+				}
+				this->SetDirty();
+				break;
+
+			case WKC_BACKQUOTE:
+				IConsoleSwitch();
+				break;
+
+			case WKC_RETURN: case WKC_NUM_ENTER:
+				IConsolePrintF(_icolour_cmd, "] %s", _iconsole_cmdline.buf);
+				IConsoleHistoryAdd(_iconsole_cmdline.buf);
+
+				IConsoleCmdExec(_iconsole_cmdline.buf);
+				IConsoleClearCommand();
+				break;
+
+			case WKC_CTRL | WKC_RETURN:
+				_iconsole_mode = (_iconsole_mode == ICONSOLE_FULL) ? ICONSOLE_OPENED : ICONSOLE_FULL;
+				IConsoleResize(this);
+				MarkWholeScreenDirty();
+				break;
+
+			case (WKC_CTRL | 'V'):
+				if (InsertTextBufferClipboard(&_iconsole_cmdline)) {
+					IConsoleResetHistoryPos();
+					this->SetDirty();
+				}
+				break;
+
+			case (WKC_CTRL | 'L'):
+				IConsoleCmdExec("clear");
+				break;
+
+			case (WKC_CTRL | 'U'):
+				DeleteTextBufferAll(&_iconsole_cmdline);
+				this->SetDirty();
+				break;
+
+			case WKC_BACKSPACE: case WKC_DELETE:
+				if (DeleteTextBufferChar(&_iconsole_cmdline, keycode)) {
+					IConsoleResetHistoryPos();
+					this->SetDirty();
+				}
+				break;
+
+			case WKC_LEFT: case WKC_RIGHT: case WKC_END: case WKC_HOME:
+				if (MoveTextBufferPos(&_iconsole_cmdline, keycode)) {
+					IConsoleResetHistoryPos();
+					this->SetDirty();
+				}
+				break;
+
+			default:
+				if (IsValidChar(key, CS_ALPHANUMERAL)) {
+					IConsoleWindow::scroll = ICON_BUFFER;
+					InsertTextBufferChar(&_iconsole_cmdline, key);
+					IConsoleResetHistoryPos();
+					this->SetDirty();
+				} else {
+					return ES_NOT_HANDLED;
+				}
+		}
+		return ES_HANDLED;
+	}
+};
+
+byte IConsoleWindow::scroll = ICON_BUFFER;
 
 static const Widget _iconsole_window_widgets[] = {
 	{WIDGETS_END}
@@ -218,7 +248,6 @@
 	WC_CONSOLE, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
 	_iconsole_window_widgets,
-	IConsoleWndProc,
 };
 
 void IConsoleInit()
@@ -317,17 +346,12 @@
 void IConsoleSwitch()
 {
 	switch (_iconsole_mode) {
-		case ICONSOLE_CLOSED: {
-			Window *w = new Window(&_iconsole_window_desc);
-			w->height = _screen.height / 3;
-			w->width = _screen.width;
-			_iconsole_mode = ICONSOLE_OPENED;
-			SetBit(_no_scroll, SCROLL_CON); // override cursor arrows; the gamefield will not scroll
-		} break;
+		case ICONSOLE_CLOSED:
+			new IConsoleWindow(&_iconsole_window_desc);
+			break;
+
 		case ICONSOLE_OPENED: case ICONSOLE_FULL:
 			DeleteWindowById(WC_CONSOLE, 0);
-			_iconsole_mode = ICONSOLE_CLOSED;
-			ClrBit(_no_scroll, SCROLL_CON);
 			break;
 	}
 
--- a/src/console_cmds.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/console_cmds.cpp	Mon May 19 15:13:58 2008 +0000
@@ -537,7 +537,11 @@
 
 	if (argc < 3) return false;
 
-	SEND_COMMAND(PACKET_CLIENT_RCON)(argv[1], argv[2]);
+	if (_network_server) {
+		IConsoleCmdExec(argv[2]);
+	} else {
+		SEND_COMMAND(PACKET_CLIENT_RCON)(argv[1], argv[2]);
+	}
 	return true;
 }
 
--- a/src/currency.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/currency.cpp	Mon May 19 15:13:58 2008 +0000
@@ -154,7 +154,7 @@
 			_currency_specs[_opt.currency].to_euro != CF_ISEURO &&
 			_cur_year >= _currency_specs[_opt.currency].to_euro) {
 		_opt.currency = 2; // this is the index of euro above.
-		AddNewsItem(STR_EURO_INTRODUCE, NM_NORMAL, NF_NONE, NT_ECONOMY, DNC_NONE, 0, 0);
+		AddNewsItem(STR_EURO_INTRODUCE, NS_ECONOMY, 0, 0);
 	}
 }
 
--- a/src/depot_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/depot_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -25,6 +25,7 @@
 #include "order_func.h"
 #include "depot_base.h"
 #include "tilehighlight_func.h"
+#include "window_gui.h"
 
 #include "table/strings.h"
 #include "table/sprites.h"
@@ -101,27 +102,11 @@
 };
 
 
-struct depot_d {
-	VehicleID sel;
-	VehicleType type;
-	bool generate_list;
-	uint16 engine_list_length;
-	uint16 wagon_list_length;
-	uint16 engine_count;
-	uint16 wagon_count;
-	Vehicle **vehicle_list;
-	Vehicle **wagon_list;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(depot_d));
-
-static void DepotWndProc(Window *w, WindowEvent *e);
-
 static const WindowDesc _train_depot_desc = {
 	WDP_AUTO, WDP_AUTO, 36, 27, 36, 27,
 	WC_VEHICLE_DEPOT, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
 	_depot_widgets,
-	DepotWndProc
 };
 
 static const WindowDesc _road_depot_desc = {
@@ -129,7 +114,6 @@
 	WC_VEHICLE_DEPOT, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
 	_depot_widgets,
-	DepotWndProc
 };
 
 static const WindowDesc _ship_depot_desc = {
@@ -137,7 +121,6 @@
 	WC_VEHICLE_DEPOT, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
 	_depot_widgets,
-	DepotWndProc
 };
 
 static const WindowDesc _aircraft_depot_desc = {
@@ -145,10 +128,10 @@
 	WC_VEHICLE_DEPOT, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
 	_depot_widgets,
-	DepotWndProc
 };
 
 extern int WagonLengthToPixels(int len);
+extern void DepotSortList(Vehicle **v, uint16 length);
 
 /**
  * This is the Callback method after the cloning attempt of a vehicle
@@ -166,247 +149,6 @@
 	ShowVehicleViewWindow(v);
 }
 
-static void DepotSellAllConfirmationCallback(Window *w, bool confirmed)
-{
-	if (confirmed) {
-		TileIndex tile = w->window_number;
-		byte vehtype = WP(w, depot_d).type;
-		DoCommandP(tile, vehtype, 0, NULL, CMD_DEPOT_SELL_ALL_VEHICLES);
-	}
-}
-
-const Sprite *GetAircraftSprite(EngineID engine);
-
-/** Draw a vehicle in the depot window in the box with the top left corner at x,y
- * @param *w Window to draw in
- * @param *v Vehicle to draw
- * @param x Left side of the box to draw in
- * @param y Top of the box to draw in
- */
-static void DrawVehicleInDepot(Window *w, const Vehicle *v, int x, int y)
-{
-	byte diff_x = 0, diff_y = 0;
-
-	int sprite_y = y + w->resize.step_height - GetVehicleListHeight(v->type);
-
-	switch (v->type) {
-		case VEH_TRAIN:
-			DrawTrainImage(v, x + 21, sprite_y, WP(w, depot_d).sel, w->hscroll.cap + 4, w->hscroll.pos);
-
-			/* Number of wagons relative to a standard length wagon (rounded up) */
-			SetDParam(0, (v->u.rail.cached_total_length + 7) / 8);
-			DrawStringRightAligned(w->widget[DEPOT_WIDGET_MATRIX].right - 1, y + 4, STR_TINY_BLACK, TC_FROMSTRING); // Draw the counter
-			break;
-
-		case VEH_ROAD:     DrawRoadVehImage( v, x + 24, sprite_y, WP(w, depot_d).sel, 1); break;
-		case VEH_SHIP:     DrawShipImage(    v, x + 19, sprite_y - 1, WP(w, depot_d).sel); break;
-		case VEH_AIRCRAFT: {
-			const Sprite *spr = GetSprite(v->GetImage(DIR_W));
-			DrawAircraftImage(v, x + 12,
-							  y + max(spr->height + spr->y_offs - 14, 0), // tall sprites needs an y offset
-							  WP(w, depot_d).sel);
-		} break;
-		default: NOT_REACHED();
-	}
-
-	if (w->resize.step_height == 14) {
-		/* VEH_TRAIN and VEH_ROAD, which are low */
-		diff_x = 15;
-	} else {
-		/* VEH_SHIP and VEH_AIRCRAFT, which are tall */
-		diff_y = 12;
-	}
-
-	DrawSprite((v->vehstatus & VS_STOPPED) ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, PAL_NONE, x + diff_x, y + diff_y);
-
-	SetDParam(0, v->unitnumber);
-	DrawString(x, y + 2, (uint16)(v->max_age - 366) >= v->age ? STR_00E2 : STR_00E3, TC_FROMSTRING);
-}
-
-static void DrawDepotWindow(Window *w)
-{
-	Vehicle **vl = WP(w, depot_d).vehicle_list;
-	TileIndex tile = w->window_number;
-	int x, y, i, maxval;
-	uint16 hnum;
-	uint16 num = WP(w, depot_d).engine_count;
-
-	/* Set the row and number of boxes in each row based on the number of boxes drawn in the matrix */
-	uint16 rows_in_display   = w->widget[DEPOT_WIDGET_MATRIX].data >> 8;
-	uint16 boxes_in_each_row = w->widget[DEPOT_WIDGET_MATRIX].data & 0xFF;
-
-	/* setup disabled buttons */
-	w->SetWidgetsDisabledState(!IsTileOwner(tile, _local_player),
-		DEPOT_WIDGET_STOP_ALL,
-		DEPOT_WIDGET_START_ALL,
-		DEPOT_WIDGET_SELL,
-		DEPOT_WIDGET_SELL_CHAIN,
-		DEPOT_WIDGET_SELL_ALL,
-		DEPOT_WIDGET_BUILD,
-		DEPOT_WIDGET_CLONE,
-		DEPOT_WIDGET_AUTOREPLACE,
-		WIDGET_LIST_END);
-
-	/* determine amount of items for scroller */
-	if (WP(w, depot_d).type == VEH_TRAIN) {
-		hnum = 8;
-		for (num = 0; num < WP(w, depot_d).engine_count; num++) {
-			const Vehicle *v = vl[num];
-			hnum = max(hnum, v->u.rail.cached_total_length);
-		}
-		/* Always have 1 empty row, so people can change the setting of the train */
-		SetVScrollCount(w, WP(w, depot_d).engine_count + WP(w, depot_d).wagon_count + 1);
-		SetHScrollCount(w, WagonLengthToPixels(hnum));
-	} else {
-		SetVScrollCount(w, (num + w->hscroll.cap - 1) / w->hscroll.cap);
-	}
-
-	/* locate the depot struct */
-	if (WP(w, depot_d).type == VEH_AIRCRAFT) {
-		SetDParam(0, GetStationIndex(tile)); // Airport name
-	} else {
-		Depot *depot = GetDepotByTile(tile);
-		assert(depot != NULL);
-
-		SetDParam(0, depot->town_index);
-	}
-
-	DrawWindowWidgets(w);
-
-	num = w->vscroll.pos * boxes_in_each_row;
-	maxval = min(WP(w, depot_d).engine_count, num + (rows_in_display * boxes_in_each_row));
-
-	for (x = 2, y = 15; num < maxval; y += w->resize.step_height, x = 2) { // Draw the rows
-		byte i;
-
-		for (i = 0; i < boxes_in_each_row && num < maxval; i++, num++, x += w->resize.step_width) {
-			/* Draw all vehicles in the current row */
-			const Vehicle *v = vl[num];
-			DrawVehicleInDepot(w, v, x, y);
-		}
-	}
-
-	maxval = min(WP(w, depot_d).engine_count + WP(w, depot_d).wagon_count, (w->vscroll.pos * boxes_in_each_row) + (rows_in_display * boxes_in_each_row));
-
-	/* draw the train wagons, that do not have an engine in front */
-	for (; num < maxval; num++, y += 14) {
-		const Vehicle *v = WP(w, depot_d).wagon_list[num - WP(w, depot_d).engine_count];
-		const Vehicle *u;
-
-		DrawTrainImage(v, x + 50, y, WP(w, depot_d).sel, w->hscroll.cap - 29, 0);
-		DrawString(x, y + 2, STR_8816, TC_FROMSTRING);
-
-		/*Draw the train counter */
-		i = 0;
-		u = v;
-		do i++; while ((u = u->Next()) != NULL); // Determine length of train
-		SetDParam(0, i);                      // Set the counter
-		DrawStringRightAligned(w->widget[DEPOT_WIDGET_MATRIX].right - 1, y + 4, STR_TINY_BLACK, TC_FROMSTRING); // Draw the counter
-	}
-}
-
-struct GetDepotVehiclePtData {
-	Vehicle *head;
-	Vehicle *wagon;
-};
-
-enum DepotGUIAction {
-	MODE_ERROR,
-	MODE_DRAG_VEHICLE,
-	MODE_SHOW_VEHICLE,
-	MODE_START_STOP,
-};
-
-static DepotGUIAction GetVehicleFromDepotWndPt(const Window *w, int x, int y, Vehicle **veh, GetDepotVehiclePtData *d)
-{
-	Vehicle **vl = WP(w, depot_d).vehicle_list;
-	uint xt, row, xm = 0, ym = 0;
-	int pos, skip = 0;
-	uint16 boxes_in_each_row = w->widget[DEPOT_WIDGET_MATRIX].data & 0xFF;
-
-	if (WP(w, depot_d).type == VEH_TRAIN) {
-		xt = 0;
-		x -= 23;
-	} else {
-		xt = x / w->resize.step_width;
-		xm = x % w->resize.step_width;
-		if (xt >= w->hscroll.cap) return MODE_ERROR;
-
-		ym = (y - 14) % w->resize.step_height;
-	}
-
-	row = (y - 14) / w->resize.step_height;
-	if (row >= w->vscroll.cap) return MODE_ERROR;
-
-	pos = ((row + w->vscroll.pos) * boxes_in_each_row) + xt;
-
-	if (WP(w, depot_d).engine_count + WP(w, depot_d).wagon_count <= pos) {
-		if (WP(w, depot_d).type == VEH_TRAIN) {
-			d->head  = NULL;
-			d->wagon = NULL;
-			return MODE_DRAG_VEHICLE;
-		} else {
-			return MODE_ERROR; // empty block, so no vehicle is selected
-		}
-	}
-
-	if (WP(w, depot_d).engine_count > pos) {
-		*veh = vl[pos];
-		skip = w->hscroll.pos;
-	} else {
-		vl = WP(w, depot_d).wagon_list;
-		pos -= WP(w, depot_d).engine_count;
-		*veh = vl[pos];
-		/* free wagons don't have an initial loco. */
-		x -= _traininfo_vehicle_width;
-	}
-
-	switch (WP(w, depot_d).type) {
-		case VEH_TRAIN: {
-			Vehicle *v = *veh;
-			d->head = d->wagon = v;
-
-			/* either pressed the flag or the number, but only when it's a loco */
-			if (x < 0 && IsFrontEngine(v)) return (x >= -10) ? MODE_START_STOP : MODE_SHOW_VEHICLE;
-
-			skip = (skip * 8) / _traininfo_vehicle_width;
-			x = (x * 8) / _traininfo_vehicle_width;
-
-			/* Skip vehicles that are scrolled off the list */
-			x += skip;
-
-			/* find the vehicle in this row that was clicked */
-			while (v != NULL && (x -= v->u.rail.cached_veh_length) >= 0) v = v->Next();
-
-			/* if an articulated part was selected, find its parent */
-			while (v != NULL && IsArticulatedPart(v)) v = v->Previous();
-
-			d->wagon = v;
-
-			return MODE_DRAG_VEHICLE;
-			}
-			break;
-
-		case VEH_ROAD:
-			if (xm >= 24) return MODE_DRAG_VEHICLE;
-			if (xm <= 16) return MODE_SHOW_VEHICLE;
-			break;
-
-		case VEH_SHIP:
-			if (xm >= 19) return MODE_DRAG_VEHICLE;
-			if (ym <= 10) return MODE_SHOW_VEHICLE;
-			break;
-
-		case VEH_AIRCRAFT:
-			if (xm >= 12) return MODE_DRAG_VEHICLE;
-			if (ym <= 12) return MODE_SHOW_VEHICLE;
-			break;
-
-		default: NOT_REACHED();
-	}
-	return MODE_START_STOP;
-}
-
 static void TrainDepotMoveVehicle(Vehicle *wagon, VehicleID sel, Vehicle *head)
 {
 	Vehicle *v;
@@ -427,220 +169,6 @@
 	DoCommandP(v->tile, v->index + ((wagon == NULL ? INVALID_VEHICLE : wagon->index) << 16), _ctrl_pressed ? 1 : 0, NULL, CMD_MOVE_RAIL_VEHICLE | CMD_MSG(STR_8837_CAN_T_MOVE_VEHICLE));
 }
 
-static void DepotClick(Window *w, int x, int y)
-{
-	GetDepotVehiclePtData gdvp;
-	Vehicle *v = NULL;
-	DepotGUIAction mode = GetVehicleFromDepotWndPt(w, x, y, &v, &gdvp);
-
-	/* share / copy orders */
-	if (_thd.place_mode != VHM_NONE && mode != MODE_ERROR) {
-		_place_clicked_vehicle = (WP(w, depot_d).type == VEH_TRAIN ? gdvp.head : v);
-		return;
-	}
-
-	if (WP(w, depot_d).type == VEH_TRAIN) v = gdvp.wagon;
-
-	switch (mode) {
-		case MODE_ERROR: // invalid
-			return;
-
-		case MODE_DRAG_VEHICLE: { // start dragging of vehicle
-			VehicleID sel = WP(w, depot_d).sel;
-
-			if (WP(w, depot_d).type == VEH_TRAIN && sel != INVALID_VEHICLE) {
-				WP(w, depot_d).sel = INVALID_VEHICLE;
-				TrainDepotMoveVehicle(v, sel, gdvp.head);
-			} else if (v != NULL) {
-				int image = v->GetImage(DIR_W);
-
-				WP(w, depot_d).sel = v->index;
-				w->SetDirty();
-				SetObjectToPlaceWnd(image, GetVehiclePalette(v), VHM_DRAG, w);
-				_cursor.vehchain = _ctrl_pressed;
-			}
-			}
-			break;
-
-		case MODE_SHOW_VEHICLE: // show info window
-			ShowVehicleViewWindow(v);
-			break;
-
-		case MODE_START_STOP: { // click start/stop flag
-			uint command;
-
-			switch (WP(w, depot_d).type) {
-				case VEH_TRAIN:    command = CMD_START_STOP_TRAIN | CMD_MSG(STR_883B_CAN_T_STOP_START_TRAIN);          break;
-				case VEH_ROAD:     command = CMD_START_STOP_ROADVEH | CMD_MSG(STR_9015_CAN_T_STOP_START_ROAD_VEHICLE); break;
-				case VEH_SHIP:     command = CMD_START_STOP_SHIP | CMD_MSG(STR_9818_CAN_T_STOP_START_SHIP);            break;
-				case VEH_AIRCRAFT: command = CMD_START_STOP_AIRCRAFT | CMD_MSG(STR_A016_CAN_T_STOP_START_AIRCRAFT);    break;
-				default: NOT_REACHED(); command = 0;
-			}
-			DoCommandP(v->tile, v->index, 0, NULL, command);
-			}
-			break;
-
-		default: NOT_REACHED();
-	}
-}
-
-/**
- * Clones a vehicle
- * @param *v is the original vehicle to clone
- * @param *w is the window of the depot where the clone is build
- */
-static void HandleCloneVehClick(const Vehicle *v, const Window *w)
-{
-	uint error_str;
-
-	if (v == NULL) return;
-
-	if (!v->IsPrimaryVehicle()) {
-		v = v->First();
-		/* Do nothing when clicking on a train in depot with no loc attached */
-		if (v->type == VEH_TRAIN && !IsFrontEngine(v)) return;
-	}
-
-	switch (v->type) {
-		case VEH_TRAIN:    error_str = CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE); break;
-		case VEH_ROAD:     error_str = CMD_MSG(STR_9009_CAN_T_BUILD_ROAD_VEHICLE);     break;
-		case VEH_SHIP:     error_str = CMD_MSG(STR_980D_CAN_T_BUILD_SHIP);             break;
-		case VEH_AIRCRAFT: error_str = CMD_MSG(STR_A008_CAN_T_BUILD_AIRCRAFT);         break;
-		default: return;
-	}
-
-	DoCommandP(w->window_number, v->index, _ctrl_pressed ? 1 : 0, CcCloneVehicle, CMD_CLONE_VEHICLE | error_str);
-
-	ResetObjectToPlace();
-}
-
-static void ClonePlaceObj(const Window *w)
-{
-	const Vehicle *v = CheckMouseOverVehicle();
-
-	if (v != NULL) HandleCloneVehClick(v, w);
-}
-
-static void ResizeDepotButtons(Window *w)
-{
-	ResizeButtons(w, DEPOT_WIDGET_BUILD, DEPOT_WIDGET_LOCATION);
-
-	if (WP(w, depot_d).type == VEH_TRAIN) {
-		/* Divide the size of DEPOT_WIDGET_SELL into two equally big buttons so DEPOT_WIDGET_SELL and DEPOT_WIDGET_SELL_CHAIN will get the same size.
-		* This way it will stay the same even if DEPOT_WIDGET_SELL_CHAIN is resized for some reason                                                  */
-		w->widget[DEPOT_WIDGET_SELL_CHAIN].top    = ((w->widget[DEPOT_WIDGET_SELL_CHAIN].bottom - w->widget[DEPOT_WIDGET_SELL].top) / 2) + w->widget[DEPOT_WIDGET_SELL].top;
-		w->widget[DEPOT_WIDGET_SELL].bottom     = w->widget[DEPOT_WIDGET_SELL_CHAIN].top - 1;
-	}
-}
-
-/* Function to set up vehicle specific sprites and strings
- * Only use this if it's the same widget, that's used for more than one vehicle type and it needs different text/sprites
- * Vehicle specific text/sprites, that's in a widget, that's only shown for one vehicle type (like sell whole train) is set in the widget array
- */
-static void SetupStringsForDepotWindow(Window *w, VehicleType type)
-{
-	switch (type) {
-		default: NOT_REACHED();
-
-		case VEH_TRAIN:
-			w->widget[DEPOT_WIDGET_CAPTION].data      = STR_8800_TRAIN_DEPOT;
-			w->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_DEPOT_TRAIN_TIP;
-			w->widget[DEPOT_WIDGET_START_ALL].tooltips= STR_MASS_START_DEPOT_TRAIN_TIP;
-			w->widget[DEPOT_WIDGET_SELL].tooltips     = STR_8841_DRAG_TRAIN_VEHICLE_TO_HERE;
-			w->widget[DEPOT_WIDGET_SELL_ALL].tooltips = STR_DEPOT_SELL_ALL_BUTTON_TRAIN_TIP;
-			w->widget[DEPOT_WIDGET_MATRIX].tooltips   = STR_883F_TRAINS_CLICK_ON_TRAIN_FOR;
-
-			w->widget[DEPOT_WIDGET_BUILD].data        = STR_8815_NEW_VEHICLES;
-			w->widget[DEPOT_WIDGET_BUILD].tooltips    = STR_8840_BUILD_NEW_TRAIN_VEHICLE;
-			w->widget[DEPOT_WIDGET_CLONE].data        = STR_CLONE_TRAIN;
-			w->widget[DEPOT_WIDGET_CLONE].tooltips    = STR_CLONE_TRAIN_DEPOT_INFO;
-
-			w->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_8842_CENTER_MAIN_VIEW_ON_TRAIN;
-			w->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_TRAIN;
-			w->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_TRAIN_TIP;
-			w->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_TRAIN_TIP;
-
-			/* Sprites */
-			w->widget[DEPOT_WIDGET_SELL].data        = SPR_SELL_TRAIN;
-			w->widget[DEPOT_WIDGET_SELL_ALL].data    = SPR_SELL_ALL_TRAIN;
-			w->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_TRAIN;
-			break;
-
-		case VEH_ROAD:
-			w->widget[DEPOT_WIDGET_CAPTION].data      = STR_9003_ROAD_VEHICLE_DEPOT;
-			w->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_DEPOT_ROADVEH_TIP;
-			w->widget[DEPOT_WIDGET_START_ALL].tooltips= STR_MASS_START_DEPOT_ROADVEH_TIP;
-			w->widget[DEPOT_WIDGET_SELL].tooltips     = STR_9024_DRAG_ROAD_VEHICLE_TO_HERE;
-			w->widget[DEPOT_WIDGET_SELL_ALL].tooltips = STR_DEPOT_SELL_ALL_BUTTON_ROADVEH_TIP;
-			w->widget[DEPOT_WIDGET_MATRIX].tooltips   = STR_9022_VEHICLES_CLICK_ON_VEHICLE;
-
-			w->widget[DEPOT_WIDGET_BUILD].data        = STR_9004_NEW_VEHICLES;
-			w->widget[DEPOT_WIDGET_BUILD].tooltips    = STR_9023_BUILD_NEW_ROAD_VEHICLE;
-			w->widget[DEPOT_WIDGET_CLONE].data        = STR_CLONE_ROAD_VEHICLE;
-			w->widget[DEPOT_WIDGET_CLONE].tooltips    = STR_CLONE_ROAD_VEHICLE_DEPOT_INFO;
-
-			w->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_9025_CENTER_MAIN_VIEW_ON_ROAD;
-			w->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_LORRY;
-			w->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_ROADVEH_TIP;
-			w->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_ROADVEH_TIP;
-
-			/* Sprites */
-			w->widget[DEPOT_WIDGET_SELL].data        = SPR_SELL_ROADVEH;
-			w->widget[DEPOT_WIDGET_SELL_ALL].data    = SPR_SELL_ALL_ROADVEH;
-			w->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_ROADVEH;
-			break;
-
-		case VEH_SHIP:
-			w->widget[DEPOT_WIDGET_CAPTION].data      = STR_9803_SHIP_DEPOT;
-			w->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_DEPOT_SHIP_TIP;
-			w->widget[DEPOT_WIDGET_START_ALL].tooltips= STR_MASS_START_DEPOT_SHIP_TIP;
-			w->widget[DEPOT_WIDGET_SELL].tooltips     = STR_9821_DRAG_SHIP_TO_HERE_TO_SELL;
-			w->widget[DEPOT_WIDGET_SELL_ALL].tooltips = STR_DEPOT_SELL_ALL_BUTTON_SHIP_TIP;
-			w->widget[DEPOT_WIDGET_MATRIX].tooltips   = STR_981F_SHIPS_CLICK_ON_SHIP_FOR;
-
-			w->widget[DEPOT_WIDGET_BUILD].data        = STR_9804_NEW_SHIPS;
-			w->widget[DEPOT_WIDGET_BUILD].tooltips    = STR_9820_BUILD_NEW_SHIP;
-			w->widget[DEPOT_WIDGET_CLONE].data        = STR_CLONE_SHIP;
-			w->widget[DEPOT_WIDGET_CLONE].tooltips    = STR_CLONE_SHIP_DEPOT_INFO;
-
-			w->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_9822_CENTER_MAIN_VIEW_ON_SHIP;
-			w->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_SHIP;
-			w->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_SHIP_TIP;
-			w->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_SHIP_TIP;
-
-			/* Sprites */
-			w->widget[DEPOT_WIDGET_SELL].data        = SPR_SELL_SHIP;
-			w->widget[DEPOT_WIDGET_SELL_ALL].data    = SPR_SELL_ALL_SHIP;
-			w->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_SHIP;
-			break;
-
-		case VEH_AIRCRAFT:
-			w->widget[DEPOT_WIDGET_CAPTION].data      = STR_A002_AIRCRAFT_HANGAR;
-			w->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_HANGAR_TIP;
-			w->widget[DEPOT_WIDGET_START_ALL].tooltips= STR_MASS_START_HANGAR_TIP;
-			w->widget[DEPOT_WIDGET_SELL].tooltips     = STR_A023_DRAG_AIRCRAFT_TO_HERE_TO;
-			w->widget[DEPOT_WIDGET_SELL_ALL].tooltips = STR_DEPOT_SELL_ALL_BUTTON_AIRCRAFT_TIP;
-			w->widget[DEPOT_WIDGET_MATRIX].tooltips   = STR_A021_AIRCRAFT_CLICK_ON_AIRCRAFT;
-
-			w->widget[DEPOT_WIDGET_BUILD].data        = STR_A003_NEW_AIRCRAFT;
-			w->widget[DEPOT_WIDGET_BUILD].tooltips    = STR_A022_BUILD_NEW_AIRCRAFT;
-			w->widget[DEPOT_WIDGET_CLONE].data        = STR_CLONE_AIRCRAFT;
-			w->widget[DEPOT_WIDGET_CLONE].tooltips    = STR_CLONE_AIRCRAFT_INFO_HANGAR_WINDOW;
-
-			w->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_A024_CENTER_MAIN_VIEW_ON_HANGAR;
-			w->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_PLANE;
-			w->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_AIRCRAFT_TIP;
-			w->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_AIRCRAFT_TIP;
-
-			/* Sprites */
-			w->widget[DEPOT_WIDGET_SELL].data        = SPR_SELL_AIRCRAFT;
-			w->widget[DEPOT_WIDGET_SELL_ALL].data    = SPR_SELL_ALL_AIRCRAFT;
-			w->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_AIRCRAFT;
-			break;
-	}
-}
-
-
 /* Array to hold the block sizes
  * First part is the vehicle type, while the last is 0 = x, 1 = y */
 uint _block_sizes[4][2];
@@ -707,296 +235,746 @@
 	ResizeDefaultWindowSize(VEH_AIRCRAFT);
 }
 
-static void CreateDepotListWindow(Window *w, VehicleType type)
-{
-	WP(w, depot_d).type = type;
-	_backup_orders_tile = 0;
-
-	assert(IsPlayerBuildableVehicleType(type)); // ensure that we make the call with a valid type
-
-	/* Resize the window according to the vehicle type */
-
-	/* Set the number of blocks in each direction */
-	w->vscroll.cap = _resize_cap[type][0];
-	w->hscroll.cap = _resize_cap[type][1];
+static void DepotSellAllConfirmationCallback(Window *w, bool confirmed);
+const Sprite *GetAircraftSprite(EngineID engine);
 
-	/* Set the block size */
-	w->resize.step_width  = _block_sizes[type][0];
-	w->resize.step_height = _block_sizes[type][1];
+struct DepotWindow : Window {
+	VehicleID sel;
+	VehicleType type;
+	bool generate_list;
+	uint16 engine_list_length;
+	uint16 wagon_list_length;
+	uint16 engine_count;
+	uint16 wagon_count;
+	Vehicle **vehicle_list;
+	Vehicle **wagon_list;
 
-	/* Enlarge the window to fit with the selected number of blocks of the selected size */
-	ResizeWindow(w,
-				 _block_sizes[type][0] * w->hscroll.cap,
-				 _block_sizes[type][1] * w->vscroll.cap);
+	DepotWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+	{
+		this->sel = INVALID_VEHICLE;
+		this->vehicle_list  = NULL;
+		this->wagon_list    = NULL;
+		this->engine_count  = 0;
+		this->wagon_count   = 0;
+		this->generate_list = true;
 
-	if (type == VEH_TRAIN) {
-		/* Make space for the horizontal scrollbar vertically, and the unit
-		 * number, flag, and length counter horizontally. */
-		ResizeWindow(w, 36, 12);
-		/* substract the newly added space from the matrix since it was meant for the scrollbar */
-		w->widget[DEPOT_WIDGET_MATRIX].bottom -= 12;
+		this->FindWindowPlacementAndResize(desc);
 	}
 
-	/* Set the minimum window size to the current window size */
-	w->resize.width  = w->width;
-	w->resize.height = w->height;
+	~DepotWindow()
+	{
+		DeleteWindowById(WC_BUILD_VEHICLE, this->window_number);
+		free((void*)this->vehicle_list);
+		free((void*)this->wagon_list);
+	}
 
-	SetupStringsForDepotWindow(w, type);
+	/** Draw a vehicle in the depot window in the box with the top left corner at x,y
+	* @param *w Window to draw in
+	* @param *v Vehicle to draw
+	* @param x Left side of the box to draw in
+	* @param y Top of the box to draw in
+	*/
+	void DrawVehicleInDepot(Window *w, const Vehicle *v, int x, int y)
+	{
+		byte diff_x = 0, diff_y = 0;
 
-	w->widget[DEPOT_WIDGET_MATRIX].data =
-		(w->vscroll.cap * 0x100) // number of rows to draw on the background
-		+ (type == VEH_TRAIN ? 1 : w->hscroll.cap); // number of boxes in each row. Trains always have just one
+		int sprite_y = y + this->resize.step_height - GetVehicleListHeight(v->type);
+
+		switch (v->type) {
+			case VEH_TRAIN:
+				DrawTrainImage(v, x + 21, sprite_y, this->sel, this->hscroll.cap + 4, this->hscroll.pos);
+
+				/* Number of wagons relative to a standard length wagon (rounded up) */
+				SetDParam(0, (v->u.rail.cached_total_length + 7) / 8);
+				DrawStringRightAligned(this->widget[DEPOT_WIDGET_MATRIX].right - 1, y + 4, STR_TINY_BLACK, TC_FROMSTRING); // Draw the counter
+				break;
+
+			case VEH_ROAD:     DrawRoadVehImage( v, x + 24, sprite_y, this->sel, 1); break;
+			case VEH_SHIP:     DrawShipImage(    v, x + 19, sprite_y - 1, this->sel); break;
+			case VEH_AIRCRAFT: {
+				const Sprite *spr = GetSprite(v->GetImage(DIR_W));
+				DrawAircraftImage(v, x + 12,
+									y + max(spr->height + spr->y_offs - 14, 0), // tall sprites needs an y offset
+									this->sel);
+			} break;
+			default: NOT_REACHED();
+		}
+
+		if (this->resize.step_height == 14) {
+			/* VEH_TRAIN and VEH_ROAD, which are low */
+			diff_x = 15;
+		} else {
+			/* VEH_SHIP and VEH_AIRCRAFT, which are tall */
+			diff_y = 12;
+		}
+
+		DrawSprite((v->vehstatus & VS_STOPPED) ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, PAL_NONE, x + diff_x, y + diff_y);
+
+		SetDParam(0, v->unitnumber);
+		DrawString(x, y + 2, (uint16)(v->max_age - 366) >= v->age ? STR_00E2 : STR_00E3, TC_FROMSTRING);
+	}
+
+	void DrawDepotWindow(Window *w)
+	{
+		Vehicle **vl = this->vehicle_list;
+		TileIndex tile = this->window_number;
+		int x, y, i, maxval;
+		uint16 hnum;
+		uint16 num = this->engine_count;
+
+		/* Set the row and number of boxes in each row based on the number of boxes drawn in the matrix */
+		uint16 rows_in_display   = this->widget[DEPOT_WIDGET_MATRIX].data >> 8;
+		uint16 boxes_in_each_row = this->widget[DEPOT_WIDGET_MATRIX].data & 0xFF;
+
+		/* setup disabled buttons */
+		this->SetWidgetsDisabledState(!IsTileOwner(tile, _local_player),
+			DEPOT_WIDGET_STOP_ALL,
+			DEPOT_WIDGET_START_ALL,
+			DEPOT_WIDGET_SELL,
+			DEPOT_WIDGET_SELL_CHAIN,
+			DEPOT_WIDGET_SELL_ALL,
+			DEPOT_WIDGET_BUILD,
+			DEPOT_WIDGET_CLONE,
+			DEPOT_WIDGET_AUTOREPLACE,
+			WIDGET_LIST_END);
+
+		/* determine amount of items for scroller */
+		if (this->type == VEH_TRAIN) {
+			hnum = 8;
+			for (num = 0; num < this->engine_count; num++) {
+				const Vehicle *v = vl[num];
+				hnum = max(hnum, v->u.rail.cached_total_length);
+			}
+			/* Always have 1 empty row, so people can change the setting of the train */
+			SetVScrollCount(w, this->engine_count + this->wagon_count + 1);
+			SetHScrollCount(w, WagonLengthToPixels(hnum));
+		} else {
+			SetVScrollCount(w, (num + this->hscroll.cap - 1) / this->hscroll.cap);
+		}
+
+		/* locate the depot struct */
+		if (this->type == VEH_AIRCRAFT) {
+			SetDParam(0, GetStationIndex(tile)); // Airport name
+		} else {
+			Depot *depot = GetDepotByTile(tile);
+			assert(depot != NULL);
+
+			SetDParam(0, depot->town_index);
+		}
+
+		w->DrawWidgets();
+
+		num = this->vscroll.pos * boxes_in_each_row;
+		maxval = min(this->engine_count, num + (rows_in_display * boxes_in_each_row));
+
+		for (x = 2, y = 15; num < maxval; y += this->resize.step_height, x = 2) { // Draw the rows
+			byte i;
+
+			for (i = 0; i < boxes_in_each_row && num < maxval; i++, num++, x += this->resize.step_width) {
+				/* Draw all vehicles in the current row */
+				const Vehicle *v = vl[num];
+				DrawVehicleInDepot(w, v, x, y);
+			}
+		}
+
+		maxval = min(this->engine_count + this->wagon_count, (this->vscroll.pos * boxes_in_each_row) + (rows_in_display * boxes_in_each_row));
+
+		/* draw the train wagons, that do not have an engine in front */
+		for (; num < maxval; num++, y += 14) {
+			const Vehicle *v = this->wagon_list[num - this->engine_count];
+			const Vehicle *u;
+
+			DrawTrainImage(v, x + 50, y, this->sel, this->hscroll.cap - 29, 0);
+			DrawString(x, y + 2, STR_8816, TC_FROMSTRING);
+
+			/*Draw the train counter */
+			i = 0;
+			u = v;
+			do i++; while ((u = u->Next()) != NULL); // Determine length of train
+			SetDParam(0, i);                      // Set the counter
+			DrawStringRightAligned(this->widget[DEPOT_WIDGET_MATRIX].right - 1, y + 4, STR_TINY_BLACK, TC_FROMSTRING); // Draw the counter
+		}
+	}
+
+	struct GetDepotVehiclePtData {
+		Vehicle *head;
+		Vehicle *wagon;
+	};
+
+	enum DepotGUIAction {
+		MODE_ERROR,
+		MODE_DRAG_VEHICLE,
+		MODE_SHOW_VEHICLE,
+		MODE_START_STOP,
+	};
+
+	DepotGUIAction GetVehicleFromDepotWndPt(int x, int y, Vehicle **veh, GetDepotVehiclePtData *d) const
+	{
+		Vehicle **vl = this->vehicle_list;
+		uint xt, row, xm = 0, ym = 0;
+		int pos, skip = 0;
+		uint16 boxes_in_each_row = this->widget[DEPOT_WIDGET_MATRIX].data & 0xFF;
+
+		if (this->type == VEH_TRAIN) {
+			xt = 0;
+			x -= 23;
+		} else {
+			xt = x / this->resize.step_width;
+			xm = x % this->resize.step_width;
+			if (xt >= this->hscroll.cap) return MODE_ERROR;
+
+			ym = (y - 14) % this->resize.step_height;
+		}
+
+		row = (y - 14) / this->resize.step_height;
+		if (row >= this->vscroll.cap) return MODE_ERROR;
+
+		pos = ((row + this->vscroll.pos) * boxes_in_each_row) + xt;
+
+		if (this->engine_count + this->wagon_count <= pos) {
+			if (this->type == VEH_TRAIN) {
+				d->head  = NULL;
+				d->wagon = NULL;
+				return MODE_DRAG_VEHICLE;
+			} else {
+				return MODE_ERROR; // empty block, so no vehicle is selected
+			}
+		}
+
+		if (this->engine_count > pos) {
+			*veh = vl[pos];
+			skip = this->hscroll.pos;
+		} else {
+			vl = this->wagon_list;
+			pos -= this->engine_count;
+			*veh = vl[pos];
+			/* free wagons don't have an initial loco. */
+			x -= _traininfo_vehicle_width;
+		}
+
+		switch (this->type) {
+			case VEH_TRAIN: {
+				Vehicle *v = *veh;
+				d->head = d->wagon = v;
+
+				/* either pressed the flag or the number, but only when it's a loco */
+				if (x < 0 && IsFrontEngine(v)) return (x >= -10) ? MODE_START_STOP : MODE_SHOW_VEHICLE;
+
+				skip = (skip * 8) / _traininfo_vehicle_width;
+				x = (x * 8) / _traininfo_vehicle_width;
+
+				/* Skip vehicles that are scrolled off the list */
+				x += skip;
+
+				/* find the vehicle in this row that was clicked */
+				while (v != NULL && (x -= v->u.rail.cached_veh_length) >= 0) v = v->Next();
+
+				/* if an articulated part was selected, find its parent */
+				while (v != NULL && IsArticulatedPart(v)) v = v->Previous();
+
+				d->wagon = v;
+
+				return MODE_DRAG_VEHICLE;
+				}
+				break;
+
+			case VEH_ROAD:
+				if (xm >= 24) return MODE_DRAG_VEHICLE;
+				if (xm <= 16) return MODE_SHOW_VEHICLE;
+				break;
+
+			case VEH_SHIP:
+				if (xm >= 19) return MODE_DRAG_VEHICLE;
+				if (ym <= 10) return MODE_SHOW_VEHICLE;
+				break;
+
+			case VEH_AIRCRAFT:
+				if (xm >= 12) return MODE_DRAG_VEHICLE;
+				if (ym <= 12) return MODE_SHOW_VEHICLE;
+				break;
+
+			default: NOT_REACHED();
+		}
+		return MODE_START_STOP;
+	}
+
+	void DepotClick(int x, int y)
+	{
+		GetDepotVehiclePtData gdvp = { NULL, NULL };
+		Vehicle *v = NULL;
+		DepotGUIAction mode = this->GetVehicleFromDepotWndPt(x, y, &v, &gdvp);
+
+		/* share / copy orders */
+		if (_thd.place_mode != VHM_NONE && mode != MODE_ERROR) {
+			_place_clicked_vehicle = (this->type == VEH_TRAIN ? gdvp.head : v);
+			return;
+		}
+
+		if (this->type == VEH_TRAIN) v = gdvp.wagon;
+
+		switch (mode) {
+			case MODE_ERROR: // invalid
+				return;
+
+			case MODE_DRAG_VEHICLE: { // start dragging of vehicle
+				VehicleID sel = this->sel;
+
+				if (this->type == VEH_TRAIN && sel != INVALID_VEHICLE) {
+					this->sel = INVALID_VEHICLE;
+					TrainDepotMoveVehicle(v, sel, gdvp.head);
+				} else if (v != NULL) {
+					int image = v->GetImage(DIR_W);
+
+					this->sel = v->index;
+					this->SetDirty();
+					SetObjectToPlaceWnd(image, GetVehiclePalette(v), VHM_DRAG, this);
+					_cursor.vehchain = _ctrl_pressed;
+				}
+			} break;
+
+			case MODE_SHOW_VEHICLE: // show info window
+				ShowVehicleViewWindow(v);
+				break;
+
+			case MODE_START_STOP: { // click start/stop flag
+				uint command;
+
+				switch (this->type) {
+					case VEH_TRAIN:    command = CMD_START_STOP_TRAIN | CMD_MSG(STR_883B_CAN_T_STOP_START_TRAIN);          break;
+					case VEH_ROAD:     command = CMD_START_STOP_ROADVEH | CMD_MSG(STR_9015_CAN_T_STOP_START_ROAD_VEHICLE); break;
+					case VEH_SHIP:     command = CMD_START_STOP_SHIP | CMD_MSG(STR_9818_CAN_T_STOP_START_SHIP);            break;
+					case VEH_AIRCRAFT: command = CMD_START_STOP_AIRCRAFT | CMD_MSG(STR_A016_CAN_T_STOP_START_AIRCRAFT);    break;
+					default: NOT_REACHED(); command = 0;
+				}
+				DoCommandP(v->tile, v->index, 0, NULL, command);
+			} break;
+
+			default: NOT_REACHED();
+		}
+	}
+
+	/**
+	* Clones a vehicle
+	* @param *v is the original vehicle to clone
+	* @param *w is the window of the depot where the clone is build
+	*/
+	void HandleCloneVehClick(const Vehicle *v, const Window *w)
+	{
+		uint error_str;
+
+		if (v == NULL) return;
+
+		if (!v->IsPrimaryVehicle()) {
+			v = v->First();
+			/* Do nothing when clicking on a train in depot with no loc attached */
+			if (v->type == VEH_TRAIN && !IsFrontEngine(v)) return;
+		}
+
+		switch (v->type) {
+			case VEH_TRAIN:    error_str = CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE); break;
+			case VEH_ROAD:     error_str = CMD_MSG(STR_9009_CAN_T_BUILD_ROAD_VEHICLE);     break;
+			case VEH_SHIP:     error_str = CMD_MSG(STR_980D_CAN_T_BUILD_SHIP);             break;
+			case VEH_AIRCRAFT: error_str = CMD_MSG(STR_A008_CAN_T_BUILD_AIRCRAFT);         break;
+			default: return;
+		}
+
+		DoCommandP(this->window_number, v->index, _ctrl_pressed ? 1 : 0, CcCloneVehicle, CMD_CLONE_VEHICLE | error_str);
+
+		ResetObjectToPlace();
+	}
+
+	void ResizeDepotButtons(Window *w)
+	{
+		ResizeButtons(w, DEPOT_WIDGET_BUILD, DEPOT_WIDGET_LOCATION);
+
+		if (this->type == VEH_TRAIN) {
+			/* Divide the size of DEPOT_WIDGET_SELL into two equally big buttons so DEPOT_WIDGET_SELL and DEPOT_WIDGET_SELL_CHAIN will get the same size.
+			* This way it will stay the same even if DEPOT_WIDGET_SELL_CHAIN is resized for some reason                                                  */
+			this->widget[DEPOT_WIDGET_SELL_CHAIN].top    = ((this->widget[DEPOT_WIDGET_SELL_CHAIN].bottom - this->widget[DEPOT_WIDGET_SELL].top) / 2) + this->widget[DEPOT_WIDGET_SELL].top;
+			this->widget[DEPOT_WIDGET_SELL].bottom     = this->widget[DEPOT_WIDGET_SELL_CHAIN].top - 1;
+		}
+	}
+
+	/* Function to set up vehicle specific sprites and strings
+	 * Only use this if it's the same widget, that's used for more than one vehicle type and it needs different text/sprites
+	 * Vehicle specific text/sprites, that's in a widget, that's only shown for one vehicle type (like sell whole train) is set in the widget array
+	 */
+	void SetupStringsForDepotWindow(VehicleType type)
+	{
+		switch (type) {
+			default: NOT_REACHED();
+
+			case VEH_TRAIN:
+				this->widget[DEPOT_WIDGET_CAPTION].data      = STR_8800_TRAIN_DEPOT;
+				this->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_DEPOT_TRAIN_TIP;
+				this->widget[DEPOT_WIDGET_START_ALL].tooltips= STR_MASS_START_DEPOT_TRAIN_TIP;
+				this->widget[DEPOT_WIDGET_SELL].tooltips     = STR_8841_DRAG_TRAIN_VEHICLE_TO_HERE;
+				this->widget[DEPOT_WIDGET_SELL_ALL].tooltips = STR_DEPOT_SELL_ALL_BUTTON_TRAIN_TIP;
+				this->widget[DEPOT_WIDGET_MATRIX].tooltips   = STR_883F_TRAINS_CLICK_ON_TRAIN_FOR;
+
+				this->widget[DEPOT_WIDGET_BUILD].data        = STR_8815_NEW_VEHICLES;
+				this->widget[DEPOT_WIDGET_BUILD].tooltips    = STR_8840_BUILD_NEW_TRAIN_VEHICLE;
+				this->widget[DEPOT_WIDGET_CLONE].data        = STR_CLONE_TRAIN;
+				this->widget[DEPOT_WIDGET_CLONE].tooltips    = STR_CLONE_TRAIN_DEPOT_INFO;
+
+				this->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_8842_CENTER_MAIN_VIEW_ON_TRAIN;
+				this->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_TRAIN;
+				this->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_TRAIN_TIP;
+				this->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_TRAIN_TIP;
+
+				/* Sprites */
+				this->widget[DEPOT_WIDGET_SELL].data        = SPR_SELL_TRAIN;
+				this->widget[DEPOT_WIDGET_SELL_ALL].data    = SPR_SELL_ALL_TRAIN;
+				this->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_TRAIN;
+				break;
+
+			case VEH_ROAD:
+				this->widget[DEPOT_WIDGET_CAPTION].data      = STR_9003_ROAD_VEHICLE_DEPOT;
+				this->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_DEPOT_ROADVEH_TIP;
+				this->widget[DEPOT_WIDGET_START_ALL].tooltips= STR_MASS_START_DEPOT_ROADVEH_TIP;
+				this->widget[DEPOT_WIDGET_SELL].tooltips     = STR_9024_DRAG_ROAD_VEHICLE_TO_HERE;
+				this->widget[DEPOT_WIDGET_SELL_ALL].tooltips = STR_DEPOT_SELL_ALL_BUTTON_ROADVEH_TIP;
+				this->widget[DEPOT_WIDGET_MATRIX].tooltips   = STR_9022_VEHICLES_CLICK_ON_VEHICLE;
+
+				this->widget[DEPOT_WIDGET_BUILD].data        = STR_9004_NEW_VEHICLES;
+				this->widget[DEPOT_WIDGET_BUILD].tooltips    = STR_9023_BUILD_NEW_ROAD_VEHICLE;
+				this->widget[DEPOT_WIDGET_CLONE].data        = STR_CLONE_ROAD_VEHICLE;
+				this->widget[DEPOT_WIDGET_CLONE].tooltips    = STR_CLONE_ROAD_VEHICLE_DEPOT_INFO;
+
+				this->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_9025_CENTER_MAIN_VIEW_ON_ROAD;
+				this->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_LORRY;
+				this->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_ROADVEH_TIP;
+				this->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_ROADVEH_TIP;
+
+				/* Sprites */
+				this->widget[DEPOT_WIDGET_SELL].data        = SPR_SELL_ROADVEH;
+				this->widget[DEPOT_WIDGET_SELL_ALL].data    = SPR_SELL_ALL_ROADVEH;
+				this->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_ROADVEH;
+				break;
+
+			case VEH_SHIP:
+				this->widget[DEPOT_WIDGET_CAPTION].data      = STR_9803_SHIP_DEPOT;
+				this->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_DEPOT_SHIP_TIP;
+				this->widget[DEPOT_WIDGET_START_ALL].tooltips= STR_MASS_START_DEPOT_SHIP_TIP;
+				this->widget[DEPOT_WIDGET_SELL].tooltips     = STR_9821_DRAG_SHIP_TO_HERE_TO_SELL;
+				this->widget[DEPOT_WIDGET_SELL_ALL].tooltips = STR_DEPOT_SELL_ALL_BUTTON_SHIP_TIP;
+				this->widget[DEPOT_WIDGET_MATRIX].tooltips   = STR_981F_SHIPS_CLICK_ON_SHIP_FOR;
+
+				this->widget[DEPOT_WIDGET_BUILD].data        = STR_9804_NEW_SHIPS;
+				this->widget[DEPOT_WIDGET_BUILD].tooltips    = STR_9820_BUILD_NEW_SHIP;
+				this->widget[DEPOT_WIDGET_CLONE].data        = STR_CLONE_SHIP;
+				this->widget[DEPOT_WIDGET_CLONE].tooltips    = STR_CLONE_SHIP_DEPOT_INFO;
+
+				this->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_9822_CENTER_MAIN_VIEW_ON_SHIP;
+				this->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_SHIP;
+				this->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_SHIP_TIP;
+				this->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_SHIP_TIP;
+
+				/* Sprites */
+				this->widget[DEPOT_WIDGET_SELL].data        = SPR_SELL_SHIP;
+				this->widget[DEPOT_WIDGET_SELL_ALL].data    = SPR_SELL_ALL_SHIP;
+				this->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_SHIP;
+				break;
+
+			case VEH_AIRCRAFT:
+				this->widget[DEPOT_WIDGET_CAPTION].data      = STR_A002_AIRCRAFT_HANGAR;
+				this->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_HANGAR_TIP;
+				this->widget[DEPOT_WIDGET_START_ALL].tooltips= STR_MASS_START_HANGAR_TIP;
+				this->widget[DEPOT_WIDGET_SELL].tooltips     = STR_A023_DRAG_AIRCRAFT_TO_HERE_TO;
+				this->widget[DEPOT_WIDGET_SELL_ALL].tooltips = STR_DEPOT_SELL_ALL_BUTTON_AIRCRAFT_TIP;
+				this->widget[DEPOT_WIDGET_MATRIX].tooltips   = STR_A021_AIRCRAFT_CLICK_ON_AIRCRAFT;
+
+				this->widget[DEPOT_WIDGET_BUILD].data        = STR_A003_NEW_AIRCRAFT;
+				this->widget[DEPOT_WIDGET_BUILD].tooltips    = STR_A022_BUILD_NEW_AIRCRAFT;
+				this->widget[DEPOT_WIDGET_CLONE].data        = STR_CLONE_AIRCRAFT;
+				this->widget[DEPOT_WIDGET_CLONE].tooltips    = STR_CLONE_AIRCRAFT_INFO_HANGAR_WINDOW;
+
+				this->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_A024_CENTER_MAIN_VIEW_ON_HANGAR;
+				this->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_PLANE;
+				this->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_AIRCRAFT_TIP;
+				this->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_AIRCRAFT_TIP;
+
+				/* Sprites */
+				this->widget[DEPOT_WIDGET_SELL].data        = SPR_SELL_AIRCRAFT;
+				this->widget[DEPOT_WIDGET_SELL_ALL].data    = SPR_SELL_ALL_AIRCRAFT;
+				this->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_AIRCRAFT;
+				break;
+		}
+	}
+
+	void CreateDepotListWindow(VehicleType type)
+	{
+		this->type = type;
+		_backup_orders_tile = 0;
+
+		assert(IsPlayerBuildableVehicleType(type)); // ensure that we make the call with a valid type
+
+		/* Resize the window according to the vehicle type */
+
+		/* Set the number of blocks in each direction */
+		this->vscroll.cap = _resize_cap[type][0];
+		this->hscroll.cap = _resize_cap[type][1];
+
+		/* Set the block size */
+		this->resize.step_width  = _block_sizes[type][0];
+		this->resize.step_height = _block_sizes[type][1];
+
+		/* Enlarge the window to fit with the selected number of blocks of the selected size */
+		ResizeWindow(this,
+					_block_sizes[type][0] * this->hscroll.cap,
+					_block_sizes[type][1] * this->vscroll.cap);
+
+		if (type == VEH_TRAIN) {
+			/* Make space for the horizontal scrollbar vertically, and the unit
+			 * number, flag, and length counter horizontally. */
+			ResizeWindow(this, 36, 12);
+			/* substract the newly added space from the matrix since it was meant for the scrollbar */
+			this->widget[DEPOT_WIDGET_MATRIX].bottom -= 12;
+		}
+
+		/* Set the minimum window size to the current window size */
+		this->resize.width  = this->width;
+		this->resize.height = this->height;
+
+		this->SetupStringsForDepotWindow(type);
+
+		this->widget[DEPOT_WIDGET_MATRIX].data =
+			(this->vscroll.cap * 0x100) // number of rows to draw on the background
+			+ (type == VEH_TRAIN ? 1 : this->hscroll.cap); // number of boxes in each row. Trains always have just one
 
 
-	w->SetWidgetsHiddenState(type != VEH_TRAIN,
-		DEPOT_WIDGET_H_SCROLL,
-		DEPOT_WIDGET_SELL_CHAIN,
-		WIDGET_LIST_END);
-
-	ResizeDepotButtons(w);
-}
-
-void DepotSortList(Vehicle **v, uint16 length);
-
-static void DepotWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_CREATE:
-			WP(w, depot_d).sel = INVALID_VEHICLE;
-			WP(w, depot_d).vehicle_list  = NULL;
-			WP(w, depot_d).wagon_list    = NULL;
-			WP(w, depot_d).engine_count  = 0;
-			WP(w, depot_d).wagon_count   = 0;
-			WP(w, depot_d).generate_list = true;
-			break;
-
-		case WE_INVALIDATE_DATA:
-			WP(w, depot_d).generate_list = true;
-			break;
+		this->SetWidgetsHiddenState(type != VEH_TRAIN,
+			DEPOT_WIDGET_H_SCROLL,
+			DEPOT_WIDGET_SELL_CHAIN,
+			WIDGET_LIST_END);
 
-		case WE_PAINT:
-			if (WP(w, depot_d).generate_list) {
-				/* Generate the vehicle list
-				 * It's ok to use the wagon pointers for non-trains as they will be ignored */
-				BuildDepotVehicleList(WP(w, depot_d).type, w->window_number,
-					&WP(w, depot_d).vehicle_list, &WP(w, depot_d).engine_list_length, &WP(w, depot_d).engine_count,
-					&WP(w, depot_d).wagon_list,   &WP(w, depot_d).wagon_list_length,  &WP(w, depot_d).wagon_count);
-				WP(w, depot_d).generate_list = false;
-				DepotSortList(WP(w, depot_d).vehicle_list, WP(w, depot_d).engine_count);
-//#ifndef NDEBUG
-#if 0
-/* We disabled this check for now, but will keep it to quickly make this test again later (if we change some code) */
-			} else {
-				/* Here we got a piece of code, that only checks if we got a different number of vehicles in the depot list and the number of vehicles actually being in the depot.
-				 * IF they aren't the same, then WE_INVALIDATE_DATA should have been called somewhere, but it wasn't and we got a bug
-				 * Since this is a time consuming check and not nice to memory fragmentation, it may not stay for long, but it's a good way to check this
-				 * We can turn it on/off by switching between #ifndef NDEBUG and #if 0 */
-				Vehicle **engines = NULL, **wagons = NULL;
-				uint16 engine_count = 0, engine_length = 0;
-				uint16 wagon_count  = 0, wagon_length  = 0;
-				BuildDepotVehicleList(WP(w, depot_d).type, w->window_number, &engines, &engine_length, &engine_count,
-									  &wagons,  &wagon_length,  &wagon_count);
-
-				assert(engine_count == WP(w, depot_d).engine_count);
-				assert(wagon_count == WP(w, depot_d).wagon_count);
-				free((void*)engines);
-				free((void*)wagons);
-#endif
-			}
-			DrawDepotWindow(w);
-			break;
+		ResizeDepotButtons(this);
+	}
 
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case DEPOT_WIDGET_MATRIX: // List
-					DepotClick(w, e->we.click.pt.x, e->we.click.pt.y);
-					break;
-
-				case DEPOT_WIDGET_BUILD: // Build vehicle
-					ResetObjectToPlace();
-					ShowBuildVehicleWindow(w->window_number, WP(w, depot_d).type);
-					break;
-
-				case DEPOT_WIDGET_CLONE: // Clone button
-					w->InvalidateWidget(DEPOT_WIDGET_CLONE);
-					w->ToggleWidgetLoweredState(DEPOT_WIDGET_CLONE);
+	virtual void OnInvalidateData(int data)
+	{
+		this->generate_list = true;
+	}
 
-					if (w->IsWidgetLowered(DEPOT_WIDGET_CLONE)) {
-						static const CursorID clone_icons[] = {
-							SPR_CURSOR_CLONE_TRAIN, SPR_CURSOR_CLONE_ROADVEH,
-							SPR_CURSOR_CLONE_SHIP, SPR_CURSOR_CLONE_AIRPLANE
-						};
+	virtual void OnPaint()
+	{
+		if (this->generate_list) {
+			/* Generate the vehicle list
+			 * It's ok to use the wagon pointers for non-trains as they will be ignored */
+			BuildDepotVehicleList(this->type, this->window_number,
+				&this->vehicle_list, &this->engine_list_length, &this->engine_count,
+				&this->wagon_list,   &this->wagon_list_length,  &this->wagon_count);
+			this->generate_list = false;
+			DepotSortList(this->vehicle_list, this->engine_count);
+		}
+		DrawDepotWindow(this);
+	}
 
-						_place_clicked_vehicle = NULL;
-						SetObjectToPlaceWnd(clone_icons[WP(w, depot_d).type], PAL_NONE, VHM_RECT, w);
-					} else {
-						ResetObjectToPlace();
-					}
-						break;
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case DEPOT_WIDGET_MATRIX: // List
+				this->DepotClick(pt.x, pt.y);
+				break;
 
-				case DEPOT_WIDGET_LOCATION:
-					if (_ctrl_pressed) {
-						ShowExtraViewPortWindow(w->window_number);
-					} else {
-						ScrollMainWindowToTile(w->window_number);
-					}
-					break;
+			case DEPOT_WIDGET_BUILD: // Build vehicle
+				ResetObjectToPlace();
+				ShowBuildVehicleWindow(this->window_number, this->type);
+				break;
 
-				case DEPOT_WIDGET_STOP_ALL:
-				case DEPOT_WIDGET_START_ALL:
-					DoCommandP(w->window_number, 0, WP(w, depot_d).type | (e->we.click.widget == DEPOT_WIDGET_START_ALL ? (1 << 5) : 0), NULL, CMD_MASS_START_STOP);
+			case DEPOT_WIDGET_CLONE: // Clone button
+				this->InvalidateWidget(DEPOT_WIDGET_CLONE);
+				this->ToggleWidgetLoweredState(DEPOT_WIDGET_CLONE);
+
+				if (this->IsWidgetLowered(DEPOT_WIDGET_CLONE)) {
+					static const CursorID clone_icons[] = {
+						SPR_CURSOR_CLONE_TRAIN, SPR_CURSOR_CLONE_ROADVEH,
+						SPR_CURSOR_CLONE_SHIP, SPR_CURSOR_CLONE_AIRPLANE
+					};
+
+					_place_clicked_vehicle = NULL;
+					SetObjectToPlaceWnd(clone_icons[this->type], PAL_NONE, VHM_RECT, this);
+				} else {
+					ResetObjectToPlace();
+				}
 					break;
 
-				case DEPOT_WIDGET_SELL_ALL:
-					/* Only open the confimation window if there are anything to sell */
-					if (WP(w, depot_d).engine_count != 0 || WP(w, depot_d).wagon_count != 0) {
-						static const StringID confirm_captions[] = {
-							STR_8800_TRAIN_DEPOT,
-							STR_9003_ROAD_VEHICLE_DEPOT,
-							STR_9803_SHIP_DEPOT,
-							STR_A002_AIRCRAFT_HANGAR
-						};
-						TileIndex tile = w->window_number;
-						byte vehtype = WP(w, depot_d).type;
-
-						SetDParam(0, (vehtype == VEH_AIRCRAFT) ? GetStationIndex(tile) : GetDepotByTile(tile)->town_index);
-						ShowQuery(
-							confirm_captions[vehtype],
-							STR_DEPOT_SELL_CONFIRMATION_TEXT,
-							w,
-							DepotSellAllConfirmationCallback
-						);
-					}
-					break;
-
-				case DEPOT_WIDGET_VEHICLE_LIST:
-					ShowVehicleListWindow(GetTileOwner(w->window_number), WP(w, depot_d).type, (TileIndex)w->window_number);
-					break;
-
-				case DEPOT_WIDGET_AUTOREPLACE:
-					DoCommandP(w->window_number, WP(w, depot_d).type, 0, NULL, CMD_DEPOT_MASS_AUTOREPLACE);
-					break;
-
-			}
-			break;
-
-		case WE_PLACE_OBJ: {
-			ClonePlaceObj(w);
-		} break;
-
-		case WE_ABORT_PLACE_OBJ: {
-			/* abort clone */
-			w->RaiseWidget(DEPOT_WIDGET_CLONE);
-			w->InvalidateWidget(DEPOT_WIDGET_CLONE);
-
-			/* abort drag & drop */
-			WP(w, depot_d).sel = INVALID_VEHICLE;
-			w->InvalidateWidget(DEPOT_WIDGET_MATRIX);
-		} break;
-
-			/* check if a vehicle in a depot was clicked.. */
-		case WE_MOUSELOOP: {
-			const Vehicle *v = _place_clicked_vehicle;
-
-			/* since OTTD checks all open depot windows, we will make sure that it triggers the one with a clicked clone button */
-			if (v != NULL && w->IsWidgetLowered(DEPOT_WIDGET_CLONE)) {
-				_place_clicked_vehicle = NULL;
-				HandleCloneVehClick(v, w);
-			}
-		} break;
-
-		case WE_DESTROY:
-			DeleteWindowById(WC_BUILD_VEHICLE, w->window_number);
-			free((void*)WP(w, depot_d).vehicle_list);
-			free((void*)WP(w, depot_d).wagon_list);
-			break;
-
-		case WE_DRAGDROP:
-			switch (e->we.click.widget) {
-				case DEPOT_WIDGET_MATRIX: {
-					Vehicle *v;
-					VehicleID sel = WP(w, depot_d).sel;
-
-					WP(w, depot_d).sel = INVALID_VEHICLE;
-					w->SetDirty();
+			case DEPOT_WIDGET_LOCATION:
+				if (_ctrl_pressed) {
+					ShowExtraViewPortWindow(this->window_number);
+				} else {
+					ScrollMainWindowToTile(this->window_number);
+				}
+				break;
 
-					if (WP(w, depot_d).type == VEH_TRAIN) {
-						GetDepotVehiclePtData gdvp;
-
-						if (GetVehicleFromDepotWndPt(w, e->we.dragdrop.pt.x, e->we.dragdrop.pt.y, &v, &gdvp) == MODE_DRAG_VEHICLE &&
-							sel != INVALID_VEHICLE) {
-							if (gdvp.wagon != NULL && gdvp.wagon->index == sel && _ctrl_pressed) {
-								DoCommandP(GetVehicle(sel)->tile, GetVehicle(sel)->index, true, NULL, CMD_REVERSE_TRAIN_DIRECTION | CMD_MSG(STR_9033_CAN_T_MAKE_VEHICLE_TURN));
-							} else if (gdvp.wagon == NULL || gdvp.wagon->index != sel) {
-								TrainDepotMoveVehicle(gdvp.wagon, sel, gdvp.head);
-							} else if (gdvp.head != NULL && IsFrontEngine(gdvp.head)) {
-								ShowVehicleViewWindow(gdvp.head);
-							}
-						}
-					} else if (GetVehicleFromDepotWndPt(w, e->we.dragdrop.pt.x, e->we.dragdrop.pt.y, &v, NULL) == MODE_DRAG_VEHICLE &&
-						v != NULL &&
-						sel == v->index) {
-						ShowVehicleViewWindow(v);
-					}
-				} break;
-
-				case DEPOT_WIDGET_SELL: case DEPOT_WIDGET_SELL_CHAIN:
-					if (!w->IsWidgetDisabled(DEPOT_WIDGET_SELL) &&
-						WP(w, depot_d).sel != INVALID_VEHICLE) {
-						Vehicle *v;
-						uint command;
-						int sell_cmd;
-						bool is_engine;
-
-						if (w->IsWidgetDisabled(e->we.click.widget)) return;
-						if (WP(w, depot_d).sel == INVALID_VEHICLE) return;
-
-						w->HandleButtonClick(e->we.click.widget);
-
-						v = GetVehicle(WP(w, depot_d).sel);
-						WP(w, depot_d).sel = INVALID_VEHICLE;
-						w->SetDirty();
+			case DEPOT_WIDGET_STOP_ALL:
+			case DEPOT_WIDGET_START_ALL:
+				DoCommandP(this->window_number, 0, this->type | (widget == DEPOT_WIDGET_START_ALL ? (1 << 5) : 0), NULL, CMD_MASS_START_STOP);
+				break;
 
-						sell_cmd = (v->type == VEH_TRAIN && (e->we.click.widget == DEPOT_WIDGET_SELL_CHAIN || _ctrl_pressed)) ? 1 : 0;
-
-						is_engine = (!(v->type == VEH_TRAIN && !IsFrontEngine(v)));
-
-						if (is_engine) {
-							_backup_orders_tile = v->tile;
-							BackupVehicleOrders(v);
-						}
+			case DEPOT_WIDGET_SELL_ALL:
+				/* Only open the confimation window if there are anything to sell */
+				if (this->engine_count != 0 || this->wagon_count != 0) {
+					static const StringID confirm_captions[] = {
+						STR_8800_TRAIN_DEPOT,
+						STR_9003_ROAD_VEHICLE_DEPOT,
+						STR_9803_SHIP_DEPOT,
+						STR_A002_AIRCRAFT_HANGAR
+					};
+					TileIndex tile = this->window_number;
+					byte vehtype = this->type;
 
-						switch (v->type) {
-							case VEH_TRAIN:    command = CMD_SELL_RAIL_WAGON | CMD_MSG(STR_8839_CAN_T_SELL_RAILROAD_VEHICLE); break;
-							case VEH_ROAD:     command = CMD_SELL_ROAD_VEH | CMD_MSG(STR_9014_CAN_T_SELL_ROAD_VEHICLE);       break;
-							case VEH_SHIP:     command = CMD_SELL_SHIP | CMD_MSG(STR_980C_CAN_T_SELL_SHIP);                   break;
-							case VEH_AIRCRAFT: command = CMD_SELL_AIRCRAFT | CMD_MSG(STR_A01C_CAN_T_SELL_AIRCRAFT);           break;
-							default: NOT_REACHED(); command = 0;
+					SetDParam(0, (vehtype == VEH_AIRCRAFT) ? GetStationIndex(tile) : GetDepotByTile(tile)->town_index);
+					ShowQuery(
+						confirm_captions[vehtype],
+						STR_DEPOT_SELL_CONFIRMATION_TEXT,
+						this,
+						DepotSellAllConfirmationCallback
+					);
+				}
+				break;
+
+			case DEPOT_WIDGET_VEHICLE_LIST:
+				ShowVehicleListWindow(GetTileOwner(this->window_number), this->type, (TileIndex)this->window_number);
+				break;
+
+			case DEPOT_WIDGET_AUTOREPLACE:
+				DoCommandP(this->window_number, this->type, 0, NULL, CMD_DEPOT_MASS_AUTOREPLACE);
+				break;
+
+		}
+	}
+
+	virtual void OnPlaceObject(Point pt, TileIndex tile)
+	{
+		const Vehicle *v = CheckMouseOverVehicle();
+
+		if (v != NULL) HandleCloneVehClick(v, this);
+	}
+
+	virtual void OnPlaceObjectAbort()
+	{
+		/* abort clone */
+		this->RaiseWidget(DEPOT_WIDGET_CLONE);
+		this->InvalidateWidget(DEPOT_WIDGET_CLONE);
+
+		/* abort drag & drop */
+		this->sel = INVALID_VEHICLE;
+		this->InvalidateWidget(DEPOT_WIDGET_MATRIX);
+	};
+
+	/* check if a vehicle in a depot was clicked.. */
+	virtual void OnMouseLoop()
+	{
+		const Vehicle *v = _place_clicked_vehicle;
+
+		/* since OTTD checks all open depot windows, we will make sure that it triggers the one with a clicked clone button */
+		if (v != NULL && this->IsWidgetLowered(DEPOT_WIDGET_CLONE)) {
+			_place_clicked_vehicle = NULL;
+			HandleCloneVehClick(v, this);
+		}
+	}
+
+	virtual void OnDragDrop(Point pt, int widget)
+	{
+		switch (widget) {
+			case DEPOT_WIDGET_MATRIX: {
+				Vehicle *v;
+				VehicleID sel = this->sel;
+
+				this->sel = INVALID_VEHICLE;
+				this->SetDirty();
+
+				if (this->type == VEH_TRAIN) {
+					GetDepotVehiclePtData gdvp = { NULL, NULL };
+
+					if (this->GetVehicleFromDepotWndPt(pt.x, pt.y, &v, &gdvp) == MODE_DRAG_VEHICLE &&
+						sel != INVALID_VEHICLE) {
+						if (gdvp.wagon != NULL && gdvp.wagon->index == sel && _ctrl_pressed) {
+							DoCommandP(GetVehicle(sel)->tile, GetVehicle(sel)->index, true, NULL, CMD_REVERSE_TRAIN_DIRECTION | CMD_MSG(STR_9033_CAN_T_MAKE_VEHICLE_TURN));
+						} else if (gdvp.wagon == NULL || gdvp.wagon->index != sel) {
+							TrainDepotMoveVehicle(gdvp.wagon, sel, gdvp.head);
+						} else if (gdvp.head != NULL && IsFrontEngine(gdvp.head)) {
+							ShowVehicleViewWindow(gdvp.head);
 						}
-
-						if (!DoCommandP(v->tile, v->index, sell_cmd, NULL, command) && is_engine) _backup_orders_tile = 0;
 					}
-					break;
-				default:
-					WP(w, depot_d).sel = INVALID_VEHICLE;
-					w->SetDirty();
-			}
-			_cursor.vehchain = false;
-			break;
+				} else if (this->GetVehicleFromDepotWndPt(pt.x, pt.y, &v, NULL) == MODE_DRAG_VEHICLE &&
+					v != NULL &&
+					sel == v->index) {
+					ShowVehicleViewWindow(v);
+				}
+			} break;
 
-		case WE_RESIZE:
-			w->vscroll.cap += e->we.sizing.diff.y / (int)w->resize.step_height;
-			w->hscroll.cap += e->we.sizing.diff.x / (int)w->resize.step_width;
-			w->widget[DEPOT_WIDGET_MATRIX].data = (w->vscroll.cap << 8) + (WP(w, depot_d).type == VEH_TRAIN ? 1 : w->hscroll.cap);
-			ResizeDepotButtons(w);
-			break;
+			case DEPOT_WIDGET_SELL: case DEPOT_WIDGET_SELL_CHAIN:
+				if (!this->IsWidgetDisabled(DEPOT_WIDGET_SELL) &&
+					this->sel != INVALID_VEHICLE) {
+					Vehicle *v;
+					uint command;
+					int sell_cmd;
+					bool is_engine;
 
-		case WE_CTRL_CHANGED:
-			if (WP(w, depot_d).sel != INVALID_VEHICLE) {
-				_cursor.vehchain = _ctrl_pressed;
-				w->InvalidateWidget(DEPOT_WIDGET_MATRIX);
-			}
-			break;
+					if (this->IsWidgetDisabled(widget)) return;
+					if (this->sel == INVALID_VEHICLE) return;
+
+					this->HandleButtonClick(widget);
+
+					v = GetVehicle(this->sel);
+					this->sel = INVALID_VEHICLE;
+					this->SetDirty();
+
+					sell_cmd = (v->type == VEH_TRAIN && (widget == DEPOT_WIDGET_SELL_CHAIN || _ctrl_pressed)) ? 1 : 0;
+
+					is_engine = (!(v->type == VEH_TRAIN && !IsFrontEngine(v)));
+
+					if (is_engine) {
+						_backup_orders_tile = v->tile;
+						BackupVehicleOrders(v);
+					}
+
+					switch (v->type) {
+						case VEH_TRAIN:    command = CMD_SELL_RAIL_WAGON | CMD_MSG(STR_8839_CAN_T_SELL_RAILROAD_VEHICLE); break;
+						case VEH_ROAD:     command = CMD_SELL_ROAD_VEH | CMD_MSG(STR_9014_CAN_T_SELL_ROAD_VEHICLE);       break;
+						case VEH_SHIP:     command = CMD_SELL_SHIP | CMD_MSG(STR_980C_CAN_T_SELL_SHIP);                   break;
+						case VEH_AIRCRAFT: command = CMD_SELL_AIRCRAFT | CMD_MSG(STR_A01C_CAN_T_SELL_AIRCRAFT);           break;
+						default: NOT_REACHED(); command = 0;
+					}
+
+					if (!DoCommandP(v->tile, v->index, sell_cmd, NULL, command) && is_engine) _backup_orders_tile = 0;
+				}
+				break;
+			default:
+				this->sel = INVALID_VEHICLE;
+				this->SetDirty();
+		}
+		_cursor.vehchain = false;
+	}
+
+	virtual void OnResize(Point new_size, Point delta)
+	{
+		this->vscroll.cap += delta.y / (int)this->resize.step_height;
+		this->hscroll.cap += delta.x / (int)this->resize.step_width;
+		this->widget[DEPOT_WIDGET_MATRIX].data = (this->vscroll.cap << 8) + (this->type == VEH_TRAIN ? 1 : this->hscroll.cap);
+		ResizeDepotButtons(this);
+	}
+
+	virtual EventState OnCTRLStateChange()
+	{
+		if (this->sel != INVALID_VEHICLE) {
+			_cursor.vehchain = _ctrl_pressed;
+			this->InvalidateWidget(DEPOT_WIDGET_MATRIX);
+		}
+
+		return ES_HANDLED;
+	}
+};
+
+static void DepotSellAllConfirmationCallback(Window *win, bool confirmed)
+{
+	if (confirmed) {
+		DepotWindow *w = (DepotWindow*)win;
+		TileIndex tile = w->window_number;
+		byte vehtype = w->type;
+		DoCommandP(tile, vehtype, 0, NULL, CMD_DEPOT_SELL_ALL_VEHICLES);
 	}
 }
 
@@ -1006,24 +984,24 @@
  */
 void ShowDepotWindow(TileIndex tile, VehicleType type)
 {
-	Window *w;
+	DepotWindow *w;
 
 	switch (type) {
 		default: NOT_REACHED();
 		case VEH_TRAIN:
-			w = AllocateWindowDescFront<Window>(&_train_depot_desc, tile); break;
+			w = AllocateWindowDescFront<DepotWindow>(&_train_depot_desc, tile); break;
 		case VEH_ROAD:
-			w = AllocateWindowDescFront<Window>(&_road_depot_desc, tile); break;
+			w = AllocateWindowDescFront<DepotWindow>(&_road_depot_desc, tile); break;
 		case VEH_SHIP:
-			w = AllocateWindowDescFront<Window>(&_ship_depot_desc, tile); break;
+			w = AllocateWindowDescFront<DepotWindow>(&_ship_depot_desc, tile); break;
 		case VEH_AIRCRAFT:
-			w = AllocateWindowDescFront<Window>(&_aircraft_depot_desc, tile); break;
+			w = AllocateWindowDescFront<DepotWindow>(&_aircraft_depot_desc, tile); break;
 	}
 
-	if (w != NULL) {
-		w->caption_color = GetTileOwner(tile);
-		CreateDepotListWindow(w, type);
-	}
+	if (w == NULL) return;
+
+	w->caption_color = GetTileOwner(tile);
+	w->CreateDepotListWindow(type);
 }
 
 /** Removes the highlight of a vehicle in a depot window
@@ -1031,15 +1009,16 @@
  */
 void DeleteDepotHighlightOfVehicle(const Vehicle *v)
 {
-	Window *w;
+	DepotWindow *w;
 
 	/* If we haven't got any vehicles on the mouse pointer, we haven't got any highlighted in any depots either
-	 * If that is the case, we can skip looping though the windows and save time                                */
+	 * If that is the case, we can skip looping though the windows and save time
+	 */
 	if (_special_mouse_mode != WSM_DRAGDROP) return;
 
-	w = FindWindowById(WC_VEHICLE_DEPOT, v->tile);
+	w = dynamic_cast<DepotWindow*>(FindWindowById(WC_VEHICLE_DEPOT, v->tile));
 	if (w != NULL) {
-		WP(w, depot_d).sel = INVALID_VEHICLE;
+		w->sel = INVALID_VEHICLE;
 		ResetObjectToPlace();
 	}
 }
--- a/src/disaster_cmd.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/disaster_cmd.cpp	Mon May 19 15:13:58 2008 +0000
@@ -234,7 +234,7 @@
 
 				SetDParam(0, GetStationIndex(tile));
 				AddNewsItem(STR_B000_ZEPPELIN_DISASTER_AT,
-					NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ACCIDENT, DNC_NONE,
+					NS_ACCIDENT_VEHICLE,
 					v->index,
 					0);
 			}
@@ -367,7 +367,7 @@
 				u->vehstatus |= VS_CRASHED;
 
 				AddNewsItem(STR_B001_ROAD_VEHICLE_DESTROYED,
-					NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ACCIDENT, DNC_NONE,
+					NS_ACCIDENT_VEHICLE,
 					u->index,
 					0);
 			}
@@ -442,7 +442,7 @@
 			DestructIndustry(i);
 
 			SetDParam(0, i->town->index);
-			AddNewsItem(STR_B002_OIL_REFINERY_EXPLOSION, NM_THIN, NF_VIEWPORT | NF_TILE, NT_ACCIDENT, DNC_NONE, i->xy, 0);
+			AddNewsItem(STR_B002_OIL_REFINERY_EXPLOSION, NS_ACCIDENT_TILE, i->xy, 0);
 			SndPlayTileFx(SND_12_EXPLOSION, i->xy);
 		}
 	} else if (v->current_order.GetDestination() == 0) {
@@ -515,7 +515,7 @@
 			DestructIndustry(i);
 
 			SetDParam(0, i->town->index);
-			AddNewsItem(STR_B003_FACTORY_DESTROYED_IN_SUSPICIOUS, NM_THIN, NF_VIEWPORT | NF_TILE, NT_ACCIDENT, DNC_NONE, i->xy, 0);
+			AddNewsItem(STR_B003_FACTORY_DESTROYED_IN_SUSPICIOUS, NS_ACCIDENT_TILE, i->xy, 0);
 			SndPlayTileFx(SND_12_EXPLOSION, i->xy);
 		}
 	} else if (v->current_order.GetDestination() == 0) {
@@ -600,7 +600,7 @@
 		t = ClosestTownFromTile(v->dest_tile, (uint)-1);
 		SetDParam(0, t->index);
 		AddNewsItem(STR_B004_UFO_LANDS_NEAR,
-			NM_THIN, NF_VIEWPORT | NF_TILE, NT_ACCIDENT, DNC_NONE,
+			NS_ACCIDENT_TILE,
 			v->tile,
 			0);
 
@@ -978,7 +978,7 @@
 			if ((GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_CAN_SUBSIDENCE) && --index < 0) {
 				SetDParam(0, i->town->index);
 				AddNewsItem(STR_B005_COAL_MINE_SUBSIDENCE_LEAVES,
-					NM_THIN, NF_VIEWPORT | NF_TILE, NT_ACCIDENT, DNC_NONE, i->xy + TileDiffXY(1, 1), 0);
+					NS_ACCIDENT_TILE, i->xy + TileDiffXY(1, 1), 0);
 
 				{
 					TileIndex tile = i->xy;
--- a/src/dock_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/dock_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -125,80 +125,85 @@
 	BuildDocksClick_Buoy
 };
 
-static void BuildDocksToolbWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT:
-		DrawWindowWidgets(w);
-		w->SetWidgetsDisabledState(!CanBuildVehicleInfrastructure(VEH_SHIP), 7, 8, 9, WIDGET_LIST_END);
-		break;
-
-	case WE_CLICK:
-		if (e->we.click.widget - 3 >= 0 && e->we.click.widget != 5) _build_docks_button_proc[e->we.click.widget - 3](w);
-		break;
-
-	case WE_KEYPRESS:
-		switch (e->we.keypress.keycode) {
-			case '1': BuildDocksClick_Canal(w); break;
-			case '2': BuildDocksClick_Lock(w); break;
-			case '3': BuildDocksClick_Demolish(w); break;
-			case '4': BuildDocksClick_Depot(w); break;
-			case '5': BuildDocksClick_Dock(w); break;
-			case '6': BuildDocksClick_Buoy(w); break;
-			default:  return;
-		}
-		break;
-
-	case WE_PLACE_OBJ:
-		_place_proc(e->we.place.tile);
-		break;
-
-	case WE_PLACE_DRAG: {
-		VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.select_method);
-		return;
+struct BuildDocksToolbarWindow : Window {
+	BuildDocksToolbarWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+	{
+		this->FindWindowPlacementAndResize(desc);
+		if (_patches.link_terraform_toolbar) ShowTerraformToolbar(this);
 	}
 
-	case WE_PLACE_MOUSEUP:
-		if (e->we.place.pt.x != -1) {
-			switch (e->we.place.select_proc) {
+	~BuildDocksToolbarWindow()
+	{
+		if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
+	}
+
+	virtual void OnPaint()
+	{
+		this->SetWidgetsDisabledState(!CanBuildVehicleInfrastructure(VEH_SHIP), 7, 8, 9, WIDGET_LIST_END);
+		this->DrawWidgets();
+	}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		if (widget - 3 >= 0 && widget != 5) _build_docks_button_proc[widget - 3](this);
+	}
+
+	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+	{
+		switch (keycode) {
+			case '1': BuildDocksClick_Canal(this); break;
+			case '2': BuildDocksClick_Lock(this); break;
+			case '3': BuildDocksClick_Demolish(this); break;
+			case '4': BuildDocksClick_Depot(this); break;
+			case '5': BuildDocksClick_Dock(this); break;
+			case '6': BuildDocksClick_Buoy(this); break;
+			default:  return ES_NOT_HANDLED;
+		}
+		return ES_HANDLED;
+	}
+
+	virtual void OnPlaceObject(Point pt, TileIndex tile)
+	{
+		_place_proc(tile);
+	}
+
+	virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
+	{
+		VpSelectTilesWithMethod(pt.x, pt.y, select_method);
+	}
+
+	virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
+	{
+		if (pt.x != -1) {
+			switch (select_proc) {
 				case DDSP_DEMOLISH_AREA:
-					GUIPlaceProcDragXY(e);
+					GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
 					break;
 				case DDSP_CREATE_WATER:
-					DoCommandP(e->we.place.tile, e->we.place.starttile, 0, CcBuildCanal, CMD_BUILD_CANAL | CMD_MSG(STR_CANT_BUILD_CANALS));
+					DoCommandP(end_tile, start_tile, 0, CcBuildCanal, CMD_BUILD_CANAL | CMD_MSG(STR_CANT_BUILD_CANALS));
 					break;
+
 				default: break;
 			}
 		}
-		break;
-
-	case WE_ABORT_PLACE_OBJ:
-		w->RaiseButtons();
-
-		w = FindWindowById(WC_BUILD_STATION, 0);
-		if (w != NULL) WP(w, def_d).close = true;
+	}
 
-		w = FindWindowById(WC_BUILD_DEPOT, 0);
-		if (w != NULL) WP(w, def_d).close = true;
-		break;
+	virtual void OnPlaceObjectAbort()
+	{
+		this->RaiseButtons();
 
-	case WE_PLACE_PRESIZE: {
-		TileIndex tile_from;
-		TileIndex tile_to;
+		delete FindWindowById(WC_BUILD_STATION, 0);
+		delete FindWindowById(WC_BUILD_DEPOT, 0);
+	}
 
-		tile_from = e->we.place.tile;
-
+	virtual void OnPlacePresize(Point pt, TileIndex tile_from)
+	{
 		DiagDirection dir = GetInclinedSlopeDirection(GetTileSlope(tile_from, NULL));
-		tile_to = (dir != INVALID_DIAGDIR ? TileAddByDiagDir(tile_from, ReverseDiagDir(dir)) : tile_from);
+		TileIndex tile_to = (dir != INVALID_DIAGDIR ? TileAddByDiagDir(tile_from, ReverseDiagDir(dir)) : tile_from);
 
 		VpSetPresizeRange(tile_from, tile_to);
-	} break;
-
-	case WE_DESTROY:
-		if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
-		break;
 	}
-}
+};
 
 static const Widget _build_docks_toolb_widgets[] = {
 {   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                   STR_018B_CLOSE_WINDOW},
@@ -221,7 +226,6 @@
 	WC_BUILD_TOOLBAR, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
 	_build_docks_toolb_widgets,
-	BuildDocksToolbWndProc
 };
 
 void ShowBuildDocksToolbar()
@@ -229,20 +233,32 @@
 	if (!IsValidPlayer(_current_player)) return;
 
 	DeleteWindowByClass(WC_BUILD_TOOLBAR);
-	Window *w = AllocateWindowDescFront<Window>(&_build_docks_toolbar_desc, TRANSPORT_WATER);
-	if (_patches.link_terraform_toolbar) ShowTerraformToolbar(w);
+	AllocateWindowDescFront<BuildDocksToolbarWindow>(&_build_docks_toolbar_desc, TRANSPORT_WATER);
 }
 
-static void BuildDockStationWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_CREATE: w->LowerWidget(_station_show_coverage + 3); break;
+struct BuildDocksStationWindow : public PickerWindowBase {
+private:
+	enum BuildDockStationWidgets {
+		BDSW_CLOSE,
+		BDSW_CAPTION,
+		BDSW_BACKGROUND,
+		BDSW_LT_OFF,
+		BDSW_LT_ON,
+		BDSW_INFO,
+	};
 
-	case WE_PAINT: {
+public:
+	BuildDocksStationWindow(const WindowDesc *desc) : PickerWindowBase(desc)
+	{
+		this->LowerWidget(_station_show_coverage + BDSW_LT_OFF);
+		this->FindWindowPlacementAndResize(desc);
+	}
+
+	virtual void OnPaint()
+	{
 		int rad = (_patches.modified_catchment) ? CA_DOCK : CA_UNMODIFIED;
 
-		if (WP(w, def_d).close) return;
-		DrawWindowWidgets(w);
+		this->DrawWidgets();
 
 		if (_station_show_coverage) {
 			SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
@@ -252,50 +268,40 @@
 
 		int text_end = DrawStationCoverageAreaText(4, 50, SCT_ALL, rad, false);
 		text_end = DrawStationCoverageAreaText(4, text_end + 4, SCT_ALL, rad, true) + 4;
-		if (text_end != w->widget[2].bottom) {
-			w->SetDirty();
-			ResizeWindowForWidget(w, 2, 0, text_end - w->widget[2].bottom);
-			w->SetDirty();
+		if (text_end != this->widget[BDSW_BACKGROUND].bottom) {
+			this->SetDirty();
+			ResizeWindowForWidget(this, 2, 0, text_end - this->widget[BDSW_BACKGROUND].bottom);
+			this->SetDirty();
 		}
-
-		break;
 	}
 
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-			case 3:
-			case 4:
-				w->RaiseWidget(_station_show_coverage + 3);
-				_station_show_coverage = (e->we.click.widget != 3);
-				w->LowerWidget(_station_show_coverage + 3);
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case BDSW_LT_OFF:
+			case BDSW_LT_ON:
+				this->RaiseWidget(_station_show_coverage + BDSW_LT_OFF);
+				_station_show_coverage = (widget != BDSW_LT_OFF);
+				this->LowerWidget(_station_show_coverage + BDSW_LT_OFF);
 				SndPlayFx(SND_15_BEEP);
-				w->SetDirty();
+				this->SetDirty();
 				break;
 		}
-		break;
-
-	case WE_TICK:
-		if (WP(w, def_d).close) {
-			delete w;
-			return;
-		}
+	}
 
-		CheckRedrawStationCoverage(w);
-		break;
-
-	case WE_DESTROY:
-		if (!WP(w, def_d).close) ResetObjectToPlace();
-		break;
+	virtual void OnTick()
+	{
+		CheckRedrawStationCoverage(this);
 	}
-}
+};
 
 static const Widget _build_dock_station_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                         STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   147,     0,    13, STR_3068_DOCK,                    STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,    14,    74, 0x0,                              STR_NULL},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    14,    73,    30,    40, STR_02DB_OFF,                     STR_3065_DON_T_HIGHLIGHT_COVERAGE},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,    74,   133,    30,    40, STR_02DA_ON,                      STR_3064_HIGHLIGHT_COVERAGE_AREA},
-{      WWT_LABEL,   RESIZE_NONE,     7,     0,   147,    17,    30, STR_3066_COVERAGE_AREA_HIGHLIGHT, STR_NULL},
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                         STR_018B_CLOSE_WINDOW},             // BDSW_CLOSE
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   147,     0,    13, STR_3068_DOCK,                    STR_018C_WINDOW_TITLE_DRAG_THIS},   // BDSW_CAPTION
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   147,    14,    74, 0x0,                              STR_NULL},                          // BDSW_BACKGROUND
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    14,    73,    30,    40, STR_02DB_OFF,                     STR_3065_DON_T_HIGHLIGHT_COVERAGE}, // BDSW_LT_OFF
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,    74,   133,    30,    40, STR_02DA_ON,                      STR_3064_HIGHLIGHT_COVERAGE_AREA},  // BDSW_LT_ON
+{      WWT_LABEL,   RESIZE_NONE,     7,     0,   147,    17,    30, STR_3066_COVERAGE_AREA_HIGHLIGHT, STR_NULL},                          // BDSW_INFO
 {   WIDGETS_END},
 };
 
@@ -304,67 +310,72 @@
 	WC_BUILD_STATION, WC_BUILD_TOOLBAR,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 	_build_dock_station_widgets,
-	BuildDockStationWndProc
 };
 
 static void ShowBuildDockStationPicker()
 {
-	new Window(&_build_dock_station_desc);
+	new BuildDocksStationWindow(&_build_dock_station_desc);
 }
 
-static void UpdateDocksDirection()
-{
-	if (_ship_depot_direction != AXIS_X) {
-		SetTileSelectSize(1, 2);
-	} else {
-		SetTileSelectSize(2, 1);
+struct BuildDocksDepotWindow : public PickerWindowBase {
+private:
+	enum BuildDockDepotWidgets {
+		BDDW_CLOSE,
+		BDDW_CAPTION,
+		BDDW_BACKGROUND,
+		BDDW_X,
+		BDDW_Y,
+	};
+
+	static void UpdateDocksDirection()
+	{
+		if (_ship_depot_direction != AXIS_X) {
+			SetTileSelectSize(1, 2);
+		} else {
+			SetTileSelectSize(2, 1);
+		}
 	}
-}
 
-static void BuildDocksDepotWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_CREATE: w->LowerWidget(_ship_depot_direction + 3); break;
+public:
+	BuildDocksDepotWindow(const WindowDesc *desc) : PickerWindowBase(desc)
+	{
+		this->LowerWidget(_ship_depot_direction + BDDW_X);
+		UpdateDocksDirection();
+		this->FindWindowPlacementAndResize(desc);
+	}
 
-	case WE_PAINT:
-		DrawWindowWidgets(w);
+	virtual void OnPaint()
+	{
+		this->DrawWidgets();
 
 		DrawShipDepotSprite(67, 35, 0);
 		DrawShipDepotSprite(35, 51, 1);
 		DrawShipDepotSprite(135, 35, 2);
 		DrawShipDepotSprite(167, 51, 3);
-		return;
+	}
 
-	case WE_CLICK: {
-		switch (e->we.click.widget) {
-		case 3:
-		case 4:
-			w->RaiseWidget(_ship_depot_direction + 3);
-			_ship_depot_direction = (e->we.click.widget == 3 ? AXIS_X : AXIS_Y);
-			w->LowerWidget(_ship_depot_direction + 3);
-			SndPlayFx(SND_15_BEEP);
-			UpdateDocksDirection();
-			w->SetDirty();
-			break;
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case BDDW_X:
+			case BDDW_Y:
+				this->RaiseWidget(_ship_depot_direction + BDDW_X);
+				_ship_depot_direction = (widget == BDDW_X ? AXIS_X : AXIS_Y);
+				this->LowerWidget(_ship_depot_direction + BDDW_X);
+				SndPlayFx(SND_15_BEEP);
+				UpdateDocksDirection();
+				this->SetDirty();
+				break;
 		}
-	} break;
-
-	case WE_TICK:
-		if (WP(w, def_d).close) delete w;
-		break;
-
-	case WE_DESTROY:
-		if (!WP(w, def_d).close) ResetObjectToPlace();
-		break;
 	}
-}
+};
 
 static const Widget _build_docks_depot_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   203,     0,    13, STR_3800_SHIP_DEPOT_ORIENTATION, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   203,    14,    85, 0x0,                             STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,     3,   100,    17,    82, 0x0,                             STR_3803_SELECT_SHIP_DEPOT_ORIENTATION},
-{      WWT_PANEL,   RESIZE_NONE,    14,   103,   200,    17,    82, 0x0,                             STR_3803_SELECT_SHIP_DEPOT_ORIENTATION},
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},                  // BDDW_CLOSE
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   203,     0,    13, STR_3800_SHIP_DEPOT_ORIENTATION, STR_018C_WINDOW_TITLE_DRAG_THIS},        // BDDW_CAPTION
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   203,    14,    85, 0x0,                             STR_NULL},                               // BDDW_BACKGROUND
+{      WWT_PANEL,   RESIZE_NONE,    14,     3,   100,    17,    82, 0x0,                             STR_3803_SELECT_SHIP_DEPOT_ORIENTATION}, // BDDW_X
+{      WWT_PANEL,   RESIZE_NONE,    14,   103,   200,    17,    82, 0x0,                             STR_3803_SELECT_SHIP_DEPOT_ORIENTATION}, // BDDW_Y
 {   WIDGETS_END},
 };
 
@@ -373,14 +384,12 @@
 	WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 	_build_docks_depot_widgets,
-	BuildDocksDepotWndProc
 };
 
 
 static void ShowBuildDocksDepotPicker()
 {
-	new Window(&_build_docks_depot_desc);
-	UpdateDocksDirection();
+	new BuildDocksDepotWindow(&_build_docks_depot_desc);
 }
 
 
--- a/src/driver.h	Mon May 19 14:14:33 2008 +0000
+++ b/src/driver.h	Mon May 19 15:13:58 2008 +0000
@@ -43,7 +43,7 @@
 
 	static Drivers &GetDrivers()
 	{
-		static Drivers s_drivers;
+		static Drivers &s_drivers = *new Drivers();
 		return s_drivers;
 	}
 
@@ -71,7 +71,14 @@
 	 */
 	virtual ~DriverFactoryBase() {
 		if (this->name == NULL) return;
-		GetDrivers().erase(this->name);
+
+		/* Prefix the name with driver type to make it unique */
+		char buf[32];
+		strecpy(buf, GetDriverTypeName(type), lastof(buf));
+		strecpy(buf + 5, this->name, lastof(buf));
+
+		GetDrivers().erase(buf);
+		if (GetDrivers().empty()) delete &GetDrivers();
 		free(this->name);
 	}
 
--- a/src/economy.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/economy.cpp	Mon May 19 15:13:58 2008 +0000
@@ -29,7 +29,6 @@
 #include "newgrf_station.h"
 #include "unmovable.h"
 #include "cargotype.h"
-#include "player_face.h"
 #include "group.h"
 #include "strings_func.h"
 #include "tile_cmd.h"
@@ -528,8 +527,10 @@
 
 	switch (p->quarters_of_bankrupcy) {
 		case 2:
-			AddNewsItem((StringID)(owner | NB_BTROUBLE),
-				NM_CALLBACK, NF_NONE, NT_COMPANY_INFO, DNC_BANKRUPCY, 0, 0);
+			SetDParam(0, STR_7056_TRANSPORT_COMPANY_IN_TROUBLE);
+			SetDParam(1, STR_7057_WILL_BE_SOLD_OFF_OR_DECLARED);
+			SetDParam(2, owner);
+			AddNewsItem(STR_02B6, NS_COMPANY_TROUBLE, 0, owner);
 			for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
 				AI_Event(i, new AIEventCompanyInTrouble(owner));
 			}
@@ -538,8 +539,10 @@
 			/* XXX - In multiplayer, should we ask other players if it wants to take
 		          over when it is a human company? -- TrueLight */
 			if (IsHumanPlayer(owner)) {
-				AddNewsItem((StringID)(owner | NB_BTROUBLE),
-					NM_CALLBACK, NF_NONE, NT_COMPANY_INFO, DNC_BANKRUPCY, 0, 0);
+				SetDParam(0, STR_7056_TRANSPORT_COMPANY_IN_TROUBLE);
+				SetDParam(1, STR_7057_WILL_BE_SOLD_OFF_OR_DECLARED);
+				SetDParam(2, owner);
+				AddNewsItem(STR_02B6, NS_COMPANY_TROUBLE, 0, owner);
 				break;
 			}
 
@@ -559,8 +562,10 @@
 			DeletePlayerWindows(owner);
 
 			/* Show bankrupt news */
-			SetDParam(0, p->index);
-			AddNewsItem((StringID)(owner | NB_BBANKRUPT), NM_CALLBACK, NF_NONE, NT_COMPANY_INFO, DNC_BANKRUPCY, 0, 0);
+			SetDParam(0, STR_705C_BANKRUPT);
+			SetDParam(1, STR_705D_HAS_BEEN_CLOSED_DOWN_BY);
+			SetDParam(2, p->index);
+			AddNewsItem(STR_02B6, NS_COMPANY_BANKRUPT, 0, owner);
 
 			if (IsHumanPlayer(owner)) {
 				/* XXX - If we are in offline mode, leave the player playing. Eg. there
@@ -591,102 +596,6 @@
 	}
 }
 
-void DrawNewsBankrupcy(Window *w, const NewsItem *ni)
-{
-	DrawNewsBorder(w);
-
-	Player *p = GetPlayer((PlayerID)GB(ni->string_id, 0, 4));
-	DrawPlayerFace(p->face, p->player_color, 2, 23);
-	GfxFillRect(3, 23, 3 + 91, 23 + 118, PALETTE_TO_STRUCT_GREY | (1 << USE_COLORTABLE));
-
-	SetDParam(0, p->index);
-
-	DrawStringMultiCenter(49, 148, STR_7058_PRESIDENT, 94);
-
-	switch (ni->string_id & 0xF0) {
-	case NB_BTROUBLE:
-		DrawStringCentered(w->width >> 1, 1, STR_7056_TRANSPORT_COMPANY_IN_TROUBLE, TC_FROMSTRING);
-
-		SetDParam(0, p->index);
-
-		DrawStringMultiCenter(
-			((w->width - 101) >> 1) + 98,
-			90,
-			STR_7057_WILL_BE_SOLD_OFF_OR_DECLARED,
-			w->width - 101);
-		break;
-
-	case NB_BMERGER:
-		DrawStringCentered(w->width >> 1, 1, STR_7059_TRANSPORT_COMPANY_MERGER, TC_FROMSTRING);
-		SetDParam(0, ni->params[0]);
-		SetDParam(1, p->index);
-		SetDParam(2, ni->params[1]);
-		DrawStringMultiCenter(
-			((w->width - 101) >> 1) + 98,
-			90,
-			ni->params[1] == 0 ? STR_707F_HAS_BEEN_TAKEN_OVER_BY : STR_705A_HAS_BEEN_SOLD_TO_FOR,
-			w->width - 101);
-		break;
-
-	case NB_BBANKRUPT:
-		DrawStringCentered(w->width >> 1, 1, STR_705C_BANKRUPT, TC_FROMSTRING);
-		SetDParam(0, ni->params[0]);
-		DrawStringMultiCenter(
-			((w->width - 101) >> 1) + 98,
-			90,
-			STR_705D_HAS_BEEN_CLOSED_DOWN_BY,
-			w->width - 101);
-		break;
-
-	case NB_BNEWCOMPANY:
-		DrawStringCentered(w->width >> 1, 1, STR_705E_NEW_TRANSPORT_COMPANY_LAUNCHED, TC_FROMSTRING);
-		SetDParam(0, p->index);
-		SetDParam(1, ni->params[0]);
-		DrawStringMultiCenter(
-			((w->width - 101) >> 1) + 98,
-			90,
-			STR_705F_STARTS_CONSTRUCTION_NEAR,
-			w->width - 101);
-		break;
-
-	default:
-		NOT_REACHED();
-	}
-}
-
-StringID GetNewsStringBankrupcy(const NewsItem *ni)
-{
-	const Player *p = GetPlayer((PlayerID)GB(ni->string_id, 0, 4));
-
-	switch (ni->string_id & 0xF0) {
-	case NB_BTROUBLE:
-		SetDParam(0, STR_7056_TRANSPORT_COMPANY_IN_TROUBLE);
-		SetDParam(1, STR_7057_WILL_BE_SOLD_OFF_OR_DECLARED);
-		SetDParam(2, p->index);
-		return STR_02B6;
-	case NB_BMERGER:
-		SetDParam(0, STR_7059_TRANSPORT_COMPANY_MERGER);
-		SetDParam(1, ni->params[1] == 0 ? STR_707F_HAS_BEEN_TAKEN_OVER_BY : STR_705A_HAS_BEEN_SOLD_TO_FOR);
-		SetDParam(2, ni->params[0]);
-		SetDParam(3, p->index);
-		SetDParam(4, ni->params[1]);
-		return STR_02B6;
-	case NB_BBANKRUPT:
-		SetDParam(0, STR_705C_BANKRUPT);
-		SetDParam(1, STR_705D_HAS_BEEN_CLOSED_DOWN_BY);
-		SetDParam(2, ni->params[0]);
-		return STR_02B6;
-	case NB_BNEWCOMPANY:
-		SetDParam(0, STR_705E_NEW_TRANSPORT_COMPANY_LAUNCHED);
-		SetDParam(1, STR_705F_STARTS_CONSTRUCTION_NEAR);
-		SetDParam(2, p->index);
-		SetDParam(3, ni->params[0]);
-		return STR_02B6;
-	default:
-		NOT_REACHED();
-	}
-}
-
 static void PlayersGenStatistics()
 {
 	Station *st;
@@ -808,10 +717,10 @@
 
 	if (--_economy.fluct == 0) {
 		_economy.fluct = -(int)GB(Random(), 0, 2);
-		AddNewsItem(STR_7073_WORLD_RECESSION_FINANCIAL, NM_NORMAL, NF_NONE, NT_ECONOMY, DNC_NONE, 0, 0);
+		AddNewsItem(STR_7073_WORLD_RECESSION_FINANCIAL, NS_ECONOMY, 0, 0);
 	} else if (_economy.fluct == -12) {
 		_economy.fluct = GB(Random(), 0, 8) + 312;
-		AddNewsItem(STR_7074_RECESSION_OVER_UPTURN_IN, NM_NORMAL, NF_NONE, NT_ECONOMY, DNC_NONE, 0, 0);
+		AddNewsItem(STR_7074_RECESSION_OVER_UPTURN_IN, NS_ECONOMY, 0, 0);
 	}
 }
 
@@ -1151,7 +1060,7 @@
 
 		if (s->age == 12-1) {
 			pair = SetupSubsidyDecodeParam(s, 1);
-			AddNewsItem(STR_202E_OFFER_OF_SUBSIDY_EXPIRED, NM_NORMAL, NF_TILE | NF_TILE2, NT_SUBSIDIES, DNC_NONE, pair.a, pair.b);
+			AddNewsItem(STR_202E_OFFER_OF_SUBSIDY_EXPIRED, NS_SUBSIDIES, pair.a, pair.b);
 			s->cargo_type = CT_INVALID;
 			modified = true;
 			for (PlayerID i = PLAYER_FIRST; i != MAX_PLAYERS; i++) {
@@ -1161,7 +1070,7 @@
 			st = GetStation(s->to);
 			if (st->owner == _local_player) {
 				pair = SetupSubsidyDecodeParam(s, 1);
-				AddNewsItem(STR_202F_SUBSIDY_WITHDRAWN_SERVICE, NM_NORMAL, NF_TILE | NF_TILE2, NT_SUBSIDIES, DNC_NONE, pair.a, pair.b);
+				AddNewsItem(STR_202F_SUBSIDY_WITHDRAWN_SERVICE, NS_SUBSIDIES, pair.a, pair.b);
 			}
 			s->cargo_type = CT_INVALID;
 			modified = true;
@@ -1203,7 +1112,7 @@
 				if (!CheckSubsidyDuplicate(s)) {
 					s->age = 0;
 					pair = SetupSubsidyDecodeParam(s, 0);
-					AddNewsItem(STR_2030_SERVICE_SUBSIDY_OFFERED, NM_NORMAL, NF_TILE | NF_TILE2, NT_SUBSIDIES, DNC_NONE, pair.a, pair.b);
+					AddNewsItem(STR_2030_SERVICE_SUBSIDY_OFFERED, NS_SUBSIDIES, pair.a, pair.b);
 					for (PlayerID i = PLAYER_FIRST; i != MAX_PLAYERS; i++) {
 						AI_Event(i, new AIEventSubsidyOffer(s - _subsidies));
 					}
@@ -1423,7 +1332,7 @@
 			SetDParam(0, _current_player);
 			AddNewsItem(
 				STR_2031_SERVICE_SUBSIDY_AWARDED + _opt.diff.subsidy_multiplier,
-				NM_NORMAL, NF_TILE | NF_TILE2, NT_SUBSIDIES, DNC_NONE,
+				NS_SUBSIDIES,
 				pair.a, pair.b
 			);
 			for (PlayerID i = PLAYER_FIRST; i != MAX_PLAYERS; i++) {
@@ -1864,9 +1773,12 @@
 	Money value;
 	PlayerID pi = p->index;
 
-	SetDParam(0, p->index);
-	SetDParam(1, p->bankrupt_value);
-	AddNewsItem((StringID)(_current_player | NB_BMERGER), NM_CALLBACK, NF_NONE, NT_COMPANY_INFO, DNC_BANKRUPCY, 0, 0);
+	SetDParam(0, STR_7059_TRANSPORT_COMPANY_MERGER);
+	SetDParam(1, p->bankrupt_value == 0 ? STR_707F_HAS_BEEN_TAKEN_OVER_BY : STR_705A_HAS_BEEN_SOLD_TO_FOR);
+	SetDParam(2, p->index);
+	SetDParam(3, _current_player);
+	SetDParam(4, p->bankrupt_value);
+	AddNewsItem(STR_02B6, NS_COMPANY_MERGER, 0, _current_player);
 	for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
 		AI_Event(i, new AIEventCompanyMerger(pi, _current_player));
 	}
@@ -1894,7 +1806,10 @@
 	if (!IsHumanPlayer(p->index)) AI_PlayerDied(p->index);
 
 	DeletePlayerWindows(pi);
-	RebuildVehicleLists(); //Updates the open windows to add the newly acquired vehicles to the lists
+	InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
+	InvalidateWindowClassesData(WC_SHIPS_LIST, 0);
+	InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
+	InvalidateWindowClassesData(WC_AIRCRAFT_LIST, 0);
 }
 
 extern int GetAmountOwnedBy(const Player *p, PlayerID owner);
--- a/src/elrail.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/elrail.cpp	Mon May 19 15:13:58 2008 +0000
@@ -104,7 +104,7 @@
 			if (override != NULL && (IsTunnel(t) || GetTunnelBridgeLength(t, GetOtherBridgeEnd(t)) > 0)) {
 				*override = 1 << GetTunnelBridgeDirection(t);
 			}
-			return AxisToTrackBits(DiagDirToAxis(GetTunnelBridgeDirection(t)));
+			return DiagDirToDiagTrackBits(GetTunnelBridgeDirection(t));
 
 		case MP_ROAD:
 			if (!IsLevelCrossing(t)) return TRACK_BIT_NONE;
--- a/src/engine.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/engine.cpp	Mon May 19 15:13:58 2008 +0000
@@ -28,6 +28,7 @@
 #include "oldpool_func.h"
 #include "ai/ai.h"
 #include "core/alloc_func.hpp"
+#include "vehicle_func.h"
 #include "map"
 
 #include "table/strings.h"
@@ -121,7 +122,11 @@
  */
 void EngList_Sort(EngineList *el, EngList_SortTypeFunction compare)
 {
-	qsort(&((*el)[0]), el->size(), sizeof(EngineID), compare);
+	size_t size = el->size();
+	/* out-of-bounds access at the next line for size == 0 (even with operator[] at some systems)
+	 * generally, do not sort if there are less than 2 items */
+	if (size < 2) return;
+	qsort(&((*el)[0]), size, sizeof(EngineID), compare); // MorphOS doesn't know vector::at(int) ...
 }
 
 /** Sort selected range of items (on indices @ <begin, begin+num_items-1>)
@@ -134,9 +139,49 @@
 {
 	assert(begin <= (uint)el->size());
 	assert(begin + num_items <= (uint)el->size());
+	if (num_items < 2) return;
 	qsort(&((*el)[begin]), num_items, sizeof(EngineID), compare);
 }
 
+
+/** Sets cached values in Player::num_vehicles and Group::num_vehicles
+ */
+void SetCachedEngineCounts()
+{
+	uint engines = GetEnginePoolSize();
+
+	/* Set up the engine count for all players */
+	Player *p;
+	FOR_ALL_PLAYERS(p) {
+		free(p->num_engines);
+		p->num_engines = CallocT<EngineID>(engines);
+	}
+
+	/* Recalculate */
+	Group *g;
+	FOR_ALL_GROUPS(g) {
+		free(g->num_engines);
+		g->num_engines = CallocT<EngineID>(engines);
+	}
+
+	const Vehicle *v;
+	FOR_ALL_VEHICLES(v) {
+		if (!IsEngineCountable(v)) continue;
+
+		assert(v->engine_type < engines);
+
+		GetPlayer(v->owner)->num_engines[v->engine_type]++;
+
+		if (v->group_id == DEFAULT_GROUP) continue;
+
+		g = GetGroup(v->group_id);
+		assert(v->type == g->vehicle_type);
+		assert(v->owner == g->owner);
+
+		g->num_engines[v->engine_type]++;
+	}
+}
+
 void SetupEngines()
 {
 	_Engine_pool.CleanPool();
@@ -364,6 +409,8 @@
 	return e->type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON;
 }
 
+StringID GetEngineCategoryName(EngineID engine);
+
 static void NewVehicleAvailable(Engine *e)
 {
 	Vehicle *v;
@@ -416,7 +463,10 @@
 			if (p->is_active) SetBit(p->avail_roadtypes, HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD);
 		}
 	}
-	AddNewsItem(index, NM_CALLBACK, NF_NONE, NT_NEW_VEHICLES, DNC_VEHICLEAVAIL, 0, 0);
+
+	SetDParam(0, GetEngineCategoryName(index));
+	SetDParam(1, index);
+	AddNewsItem(STR_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE, NS_NEW_VEHICLES, index, 0);
 }
 
 void EnginesMonthlyLoop()
--- a/src/engine_func.h	Mon May 19 14:14:33 2008 +0000
+++ b/src/engine_func.h	Mon May 19 15:13:58 2008 +0000
@@ -27,6 +27,7 @@
 
 bool IsEngineBuildable(EngineID engine, VehicleType type, PlayerID player);
 CargoID GetEngineCargoType(EngineID engine);
+void SetCachedEngineCounts();
 
 typedef int CDECL EngList_SortTypeFunction(const void*, const void*); ///< argument type for EngList_Sort()
 void EngList_Sort(EngineList *el, EngList_SortTypeFunction compare);  ///< qsort of the engine list
--- a/src/engine_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/engine_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -19,7 +19,7 @@
 #include "table/strings.h"
 #include "table/sprites.h"
 
-static StringID GetEngineCategoryName(EngineID engine)
+StringID GetEngineCategoryName(EngineID engine)
 {
 	switch (GetEngine(engine)->type) {
 		default: NOT_REACHED();
@@ -66,55 +66,53 @@
 	{ DrawAircraftEngine, DrawAircraftEngineInfo },
 };
 
-static void EnginePreviewWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
-		EngineID engine = w->window_number;
-		const DrawEngineInfo* dei;
-		int width;
+struct EnginePreviewWindow : Window {
+	EnginePreviewWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+	{
+	}
 
-		DrawWindowWidgets(w);
+	virtual void OnPaint()
+	{
+		this->DrawWidgets();
 
+		EngineID engine = this->window_number;
 		SetDParam(0, GetEngineCategoryName(engine));
 		DrawStringMultiCenter(150, 44, STR_8101_WE_HAVE_JUST_DESIGNED_A, 296);
 
 		SetDParam(0, engine);
-		DrawStringCentered(w->width >> 1, 80, STR_ENGINE_NAME, TC_BLACK);
+		DrawStringCentered(this->width >> 1, 80, STR_ENGINE_NAME, TC_BLACK);
 
-		dei = &_draw_engine_list[GetEngine(engine)->type];
+		const DrawEngineInfo *dei = &_draw_engine_list[GetEngine(engine)->type];
 
-		width = w->width;
+		int width = this->width;
 		dei->engine_proc(width >> 1, 100, engine, 0);
 		dei->info_proc(engine, width >> 1, 130, width - 52);
-		break;
 	}
 
-	case WE_CLICK:
-		switch (e->we.click.widget) {
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
 			case 4:
-				DoCommandP(0, w->window_number, 0, NULL, CMD_WANT_ENGINE_PREVIEW);
+				DoCommandP(0, this->window_number, 0, NULL, CMD_WANT_ENGINE_PREVIEW);
 				/* Fallthrough */
 			case 3:
-				delete w;
+				delete this;
 				break;
 		}
-		break;
 	}
-}
+};
 
 static const WindowDesc _engine_preview_desc = {
 	WDP_CENTER, WDP_CENTER, 300, 192, 300, 192,
 	WC_ENGINE_PREVIEW, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 	_engine_preview_widgets,
-	EnginePreviewWndProc
 };
 
 
 void ShowEnginePreviewWindow(EngineID engine)
 {
-	AllocateWindowDescFront<Window>(&_engine_preview_desc, engine);
+	AllocateWindowDescFront<EnginePreviewWindow>(&_engine_preview_desc, engine);
 }
 
 static void DrawTrainEngineInfo(EngineID engine, int x, int y, int maxw)
@@ -174,20 +172,9 @@
 	DrawStringMultiCenter(x, y, STR_982E_COST_MAX_SPEED_CAPACITY, maxw);
 }
 
-
-StringID GetNewsStringNewVehicleAvail(const NewsItem *ni)
-{
-	EngineID engine = ni->string_id;
-	SetDParam(0, GetEngineCategoryName(engine));
-	SetDParam(1, engine);
-	return STR_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE;
-}
-
 void DrawNewsNewVehicleAvail(Window *w, const NewsItem *ni)
 {
-	DrawNewsBorder(w);
-
-	EngineID engine = ni->string_id;
+	EngineID engine = ni->data_a;
 	const DrawEngineInfo *dei = &_draw_engine_list[GetEngine(engine)->type];
 
 	SetDParam(0, GetEngineCategoryName(engine));
--- a/src/genworld_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/genworld_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -253,7 +253,7 @@
 	char name[64];
 	glwp_modes mode;
 
-	GenerateLandscapeWindow(const WindowDesc *desc, void *data = NULL, WindowNumber number = 0) : QueryStringBaseWindow(desc, NULL, number)
+	GenerateLandscapeWindow(const WindowDesc *desc, WindowNumber number = 0) : QueryStringBaseWindow(desc, number)
 	{
 		this->LowerWidget(_opt_newgame.landscape + GLAND_TEMPERATE);
 
@@ -315,7 +315,7 @@
 		SetDParam(2, 1 << _patches_newgame.map_y); // GLAND_MAPSIZE_Y_PULLDOWN
 		SetDParam(3, _patches_newgame.snow_line_height); // GLAND_SNOW_LEVEL_TEXT
 
-		DrawWindowWidgets(this);
+		this->DrawWidgets();
 
 		this->DrawEditBox(GLAND_RANDOM_EDITBOX);
 
@@ -470,17 +470,17 @@
 		this->HandleEditBox(GLAND_RANDOM_EDITBOX);
 	}
 
-	virtual bool OnKeyPress(uint16 key, uint16 keycode)
+	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
 	{
-		bool cont;
-		this->HandleEditBoxKey(GLAND_RANDOM_EDITBOX, key, keycode, cont);
+		EventState state;
+		this->HandleEditBoxKey(GLAND_RANDOM_EDITBOX, key, keycode, state);
 		/* the seed is unsigned, therefore atoi cannot be used.
 			* As 2^32 - 1 (MAX_UVALUE(uint32)) is a 'magic' value
 			* (use random seed) it should not be possible to be
 			* entered into the input field; the generate seed
 			* button can be used instead. */
 		_patches_newgame.generation_seed = minu(strtoul(this->edit_str_buf, NULL, sizeof(this->edit_str_buf) - 1), MAX_UVALUE(uint32) - 1);
-		return cont;
+		return state;
 	}
 
 	virtual void OnDropdownSelect(int widget, int index)
@@ -554,7 +554,6 @@
 	WC_GENERATE_LANDSCAPE, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
 	_generate_landscape_widgets,
-	NULL,
 };
 
 static const WindowDesc _heightmap_load_desc = {
@@ -562,7 +561,6 @@
 	WC_GENERATE_LANDSCAPE, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_STD_BTN | WDF_UNCLICK_BUTTONS,
 	_heightmap_load_widgets,
-	NULL,
 };
 
 static void _ShowGenerateLandscape(glwp_modes mode)
@@ -644,7 +642,7 @@
 {
 	uint widget_id;
 
-	CreateScenarioWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, NULL, window_number)
+	CreateScenarioWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
 	{
 		this->LowerWidget(_opt_newgame.landscape + CSCEN_TEMPERATE);
 	}
@@ -667,7 +665,7 @@
 		SetDParam(2, 1 << _patches_newgame.map_y); // CSCEN_MAPSIZE_Y_PULLDOWN
 		SetDParam(3, _patches_newgame.se_flat_world_height); // CSCEN_FLAT_LAND_HEIGHT_TEXT
 
-		DrawWindowWidgets(this);
+		this->DrawWidgets();
 	}
 
 	virtual void OnClick(Point pt, int widget)
@@ -801,7 +799,6 @@
 	WC_GENERATE_LANDSCAPE, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_STD_BTN | WDF_UNCLICK_BUTTONS,
 	_create_scenario_widgets,
-	NULL,
 };
 
 void ShowCreateScenario()
@@ -811,13 +808,20 @@
 }
 
 
-static const Widget _show_terrain_progress_widgets[] = {
-{    WWT_CAPTION,   RESIZE_NONE,    14,     0,   180,     0,    13, STR_GENERATION_WORLD,   STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   180,    14,    96, 0x0,                    STR_NULL},
-{    WWT_TEXTBTN,   RESIZE_NONE,    15,    20,   161,    74,    85, STR_GENERATION_ABORT,   STR_NULL}, // Abort button
+static const Widget _generate_progress_widgets[] = {
+{    WWT_CAPTION,   RESIZE_NONE,    14,     0,   180,     0,    13, STR_GENERATION_WORLD,   STR_018C_WINDOW_TITLE_DRAG_THIS}, // GPWW_CAPTION
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   180,    14,    96, 0x0,                    STR_NULL},                        // GPWW_BACKGROUND
+{    WWT_TEXTBTN,   RESIZE_NONE,    15,    20,   161,    74,    85, STR_GENERATION_ABORT,   STR_NULL},                        // GPWW_ABORT
 {   WIDGETS_END},
 };
 
+static const WindowDesc _generate_progress_desc = {
+	WDP_CENTER, WDP_CENTER, 181, 97, 181, 97,
+	WC_GENERATE_PROGRESS_WINDOW, WC_NONE,
+	WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	_generate_progress_widgets,
+};
+
 struct tp_info {
 	uint percent;
 	StringID cls;
@@ -837,51 +841,52 @@
 	}
 }
 
-static void ShowTerrainProgressProc(Window* w, WindowEvent* e)
-{
-	switch (e->event) {
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case 2:
-					if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
-					ShowQuery(
-						STR_GENERATION_ABORT_CAPTION,
-						STR_GENERATION_ABORT_MESSAGE,
-						w,
-						AbortGeneratingWorldCallback
-					);
-					break;
-			}
-			break;
-
-		case WE_PAINT:
-			DrawWindowWidgets(w);
+struct GenerateProgressWindow : public Window {
+private:
+	enum GenerationProgressWindowWidgets {
+		GPWW_CAPTION,
+		GPWW_BACKGROUND,
+		GPWW_ABORT,
+	};
 
-			/* Draw the % complete with a bar and a text */
-			DrawFrameRect(19, 20, (w->width - 18), 37, 14, FR_BORDERONLY);
-			DrawFrameRect(20, 21, (int)((w->width - 40) * _tp.percent / 100) + 20, 36, 10, FR_NONE);
-			SetDParam(0, _tp.percent);
-			DrawStringCentered(90, 25, STR_PROGRESS, TC_FROMSTRING);
-
-			/* Tell which class we are generating */
-			DrawStringCentered(90, 46, _tp.cls, TC_FROMSTRING);
+public:
+	GenerateProgressWindow() : Window(&_generate_progress_desc) {};
 
-			/* And say where we are in that class */
-			SetDParam(0, _tp.current);
-			SetDParam(1, _tp.total);
-			DrawStringCentered(90, 58, STR_GENERATION_PROGRESS, TC_FROMSTRING);
-
-			w->SetDirty();
-			break;
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case GPWW_ABORT:
+				if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
+				ShowQuery(
+					STR_GENERATION_ABORT_CAPTION,
+					STR_GENERATION_ABORT_MESSAGE,
+					this,
+					AbortGeneratingWorldCallback
+				);
+				break;
+		}
 	}
-}
 
-static const WindowDesc _show_terrain_progress_desc = {
-	WDP_CENTER, WDP_CENTER, 181, 97, 181, 97,
-	WC_GENERATE_PROGRESS_WINDOW, WC_NONE,
-	WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
-	_show_terrain_progress_widgets,
-	ShowTerrainProgressProc
+	virtual void OnPaint()
+	{
+		this->DrawWidgets();
+
+		/* Draw the % complete with a bar and a text */
+		DrawFrameRect(19, 20, (this->width - 18), 37, 14, FR_BORDERONLY);
+		DrawFrameRect(20, 21, (int)((this->width - 40) * _tp.percent / 100) + 20, 36, 10, FR_NONE);
+		SetDParam(0, _tp.percent);
+		DrawStringCentered(90, 25, STR_PROGRESS, TC_FROMSTRING);
+
+		/* Tell which class we are generating */
+		DrawStringCentered(90, 46, _tp.cls, TC_FROMSTRING);
+
+		/* And say where we are in that class */
+		SetDParam(0, _tp.current);
+		SetDParam(1, _tp.total);
+		DrawStringCentered(90, 58, STR_GENERATION_PROGRESS, TC_FROMSTRING);
+
+		this->SetDirty();
+	}
 };
 
 /**
@@ -901,7 +906,8 @@
  */
 void ShowGenerateWorldProgress()
 {
-	AllocateWindowDescFront<Window>(&_show_terrain_progress_desc, 0);
+	if (BringWindowToFrontById(WC_GENERATE_PROGRESS_WINDOW, 0)) return;
+	new GenerateProgressWindow();
 }
 
 static void _SetGeneratingWorldProgress(gwp_class cls, uint progress, uint total)
--- a/src/graph_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/graph_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -24,295 +24,62 @@
 static uint _legend_excluded_players;
 static uint _legend_excluded_cargo;
 
-/************************/
-/* GENERIC GRAPH DRAWER */
-/************************/
-
-enum {
-	GRAPH_MAX_DATASETS = 32,
-	GRAPH_AXIS_LABEL_COLOUR = TC_BLACK,
-	GRAPH_AXIS_LINE_COLOUR  = 215,
-
-	GRAPH_X_POSITION_BEGINNING  = 44,  ///< Start the graph 44 pixels from gw->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 height of the graph / 8,
-	 * which is the same
-	 * as height >> 3. */
-};
-
 /* 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.
 
-struct GraphDrawer {
-	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;
-
-	/* 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 left, top;  ///< Where to start drawing the graph, in pixels.
-	uint height;    ///< The height of the graph in pixels.
-	StringID format_str_y_axis;
-	byte colors[GRAPH_MAX_DATASETS];
-	OverflowSafeInt64 cost[GRAPH_MAX_DATASETS][24]; ///< last 2 years
-};
-
-static void DrawGraph(const GraphDrawer *gw)
-{
-	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 colors and cost array of GraphDrawer must accomodate
-	 * both values for cargo and players. So if any are higher, quit */
-	assert(GRAPH_MAX_DATASETS >= (int)NUM_CARGO && GRAPH_MAX_DATASETS >= (int)MAX_PLAYERS);
-	assert(gw->num_vert_lines > 0);
-
-	byte grid_colour = _colour_gradient[14][4];
-
-	/* The coordinates of the opposite edges of the graph. */
-	int bottom = gw->top + gw->height - 1;
-	int right  = gw->left + GRAPH_X_POSITION_BEGINNING + gw->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 = gw->left + GRAPH_X_POSITION_BEGINNING + GRAPH_X_POSITION_SEPARATION;
-
-	for (int i = 0; i < gw->num_vert_lines; i++) {
-		GfxFillRect(x, gw->top, x, bottom, grid_colour);
-		x += GRAPH_X_POSITION_SEPARATION;
-	}
-
-	/* Draw the horizontal grid lines. */
-	x = gw->left + GRAPH_X_POSITION_BEGINNING;
-	y = gw->height + gw->top;
-
-	for (int i = 0; i < GRAPH_NUM_LINES_Y; i++) {
-		GfxFillRect(x, y, right, y, grid_colour);
-		y -= (gw->height / (GRAPH_NUM_LINES_Y - 1));
-	}
-
-	/* Draw the y axis. */
-	GfxFillRect(x, gw->top, x, bottom, GRAPH_AXIS_LINE_COLOUR);
-
-	/* Find the distance from the top of the graph to the x axis. */
-	x_axis_offset = gw->height;
-
-	/* The graph is currently symmetrical about the x axis. */
-	if (gw->has_negative_values) x_axis_offset /= 2;
-
-	/* Draw the x axis. */
-	y = x_axis_offset + gw->top;
-	GfxFillRect(x, y, right, y, GRAPH_AXIS_LINE_COLOUR);
-
-	/* Find the largest value that will be drawn. */
-	if (gw->num_on_x_axis == 0)
-		return;
-
-	assert(gw->num_on_x_axis > 0);
-	assert(gw->num_dataset > 0);
-
-	/* Start of with a value of twice the 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. */
-	highest_value = x_axis_offset * 2;
-
-	for (int i = 0; i < gw->num_dataset; i++) {
-		if (!HasBit(gw->excluded_data, i)) {
-			for (int j = 0; j < gw->num_on_x_axis; j++) {
-				OverflowSafeInt64 datapoint = gw->cost[i][j];
-
-				if (datapoint != INVALID_DATAPOINT) {
-					/* For now, if the graph has negative values the scaling is
-					 * symmetrical about the x axis, so take the absolute value
-					 * of each data point. */
-					highest_value = max(highest_value, abs(datapoint));
-				}
-			}
-		}
-	}
-
-	/* Round up highest_value so that it will divide cleanly into the number of
-	 * 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 (gw->has_negative_values) y_label_separation *= 2;
-
-	x = gw->left + GRAPH_X_POSITION_BEGINNING + 1;
-	y = gw->top - 3;
-
-	for (int i = 0; i < GRAPH_NUM_LINES_Y; i++) {
-		SetDParam(0, gw->format_str_y_axis);
-		SetDParam(1, y_label);
-		DrawStringRightAligned(x, y, STR_0170, GRAPH_AXIS_LABEL_COLOUR);
-
-		y_label -= y_label_separation;
-		y += (gw->height / (GRAPH_NUM_LINES_Y - 1));
-	}
-
-	/* draw strings on the x axis */
-	if (gw->month != 0xFF) {
-		x = gw->left + GRAPH_X_POSITION_BEGINNING;
-		y = gw->top + gw->height + 1;
-		byte month = gw->month;
-		Year year  = gw->year;
-		for (int i = 0; i < gw->num_on_x_axis; i++) {
-			SetDParam(0, month + STR_0162_JAN);
-			SetDParam(1, month + STR_0162_JAN + 2);
-			SetDParam(2, year);
-			DrawString(x, y, month == 0 ? STR_016F : STR_016E, 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 = gw->left + GRAPH_X_POSITION_BEGINNING + (GRAPH_X_POSITION_SEPARATION / 2) + 1;
-		y = gw->top + gw->height + 1;
-		uint16 label = gw->x_values_start;
-
-		for (int i = 0; i < gw->num_on_x_axis; i++) {
-			SetDParam(0, label);
-			DrawStringCentered(x, y, STR_01CB, GRAPH_AXIS_LABEL_COLOUR);
-
-			label += gw->x_values_increment;
-			x += GRAPH_X_POSITION_SEPARATION;
-		}
-	}
-
-	/* draw lines and dots */
-	for (int i = 0; i < gw->num_dataset; i++) {
-		if (!HasBit(gw->excluded_data, i)) {
-			/* Centre the dot between the grid lines. */
-			x = gw->left + GRAPH_X_POSITION_BEGINNING + (GRAPH_X_POSITION_SEPARATION / 2);
-
-			byte color  = gw->colors[i];
-			uint prev_x = INVALID_DATAPOINT_POS;
-			uint prev_y = INVALID_DATAPOINT_POS;
-
-			for (int j = 0; j < gw->num_on_x_axis; j++) {
-				OverflowSafeInt64 datapoint = gw->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);
-					} else {
-						datapoint >>= reduce_range;
-					}
-
-					y = gw->top + x_axis_offset - (x_axis_offset * datapoint) / (highest_value >> reduce_range);
-
-					/* Draw the point. */
-					GfxFillRect(x - 1, y - 1, x + 1, y + 1, color);
-
-					/* Draw the line connected to the previous point. */
-					if (prev_x != INVALID_DATAPOINT_POS) GfxDrawLine(prev_x, prev_y, x, y, color);
-
-					prev_x = x;
-					prev_y = y;
-				} else {
-					prev_x = INVALID_DATAPOINT_POS;
-					prev_y = INVALID_DATAPOINT_POS;
-				}
-
-				x += GRAPH_X_POSITION_SEPARATION;
-			}
-		}
-	}
-}
-
 /****************/
 /* GRAPH LEGEND */
 /****************/
 
-static void GraphLegendWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_CREATE:
-			for (uint i = 3; i < w->widget_count; i++) {
-				if (!HasBit(_legend_excluded_players, i - 3)) w->LowerWidget(i);
-			}
-			break;
-
-		case WE_PAINT: {
-			const Player *p;
-
-			FOR_ALL_PLAYERS(p) {
-				if (p->is_active) continue;
-
-				SetBit(_legend_excluded_players, p->index);
-				w->RaiseWidget(p->index + 3);
-			}
-
-			DrawWindowWidgets(w);
-
-			FOR_ALL_PLAYERS(p) {
-				if (!p->is_active) continue;
-
-				DrawPlayerIcon(p->index, 4, 18 + p->index * 12);
-
-				SetDParam(0, p->index);
-				SetDParam(1, p->index);
-				DrawString(21, 17 + p->index * 12, STR_7021, HasBit(_legend_excluded_players, p->index) ? TC_BLACK : TC_WHITE);
-			}
-			break;
+struct GraphLegendWindow : Window {
+	GraphLegendWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+	{
+		for (uint i = 3; i < this->widget_count; i++) {
+			if (!HasBit(_legend_excluded_players, i - 3)) this->LowerWidget(i);
 		}
 
-		case WE_CLICK:
-			if (!IsInsideMM(e->we.click.widget, 3, 11)) return;
+		this->FindWindowPlacementAndResize(desc);
+	}
 
-			ToggleBit(_legend_excluded_players, e->we.click.widget - 3);
-			w->ToggleWidgetLoweredState(e->we.click.widget);
-			w->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);
-			break;
+	virtual void OnPaint()
+	{
+		const Player *p;
+
+		FOR_ALL_PLAYERS(p) {
+			if (p->is_active) continue;
+
+			SetBit(_legend_excluded_players, p->index);
+			this->RaiseWidget(p->index + 3);
+		}
+
+		this->DrawWidgets();
+
+		FOR_ALL_PLAYERS(p) {
+			if (!p->is_active) continue;
+
+			DrawPlayerIcon(p->index, 4, 18 + p->index * 12);
+
+			SetDParam(0, p->index);
+			SetDParam(1, p->index);
+			DrawString(21, 17 + p->index * 12, STR_7021, HasBit(_legend_excluded_players, p->index) ? TC_BLACK : TC_WHITE);
+		}
 	}
-}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		if (!IsInsideMM(widget, 3, 11)) return;
+
+		ToggleBit(_legend_excluded_players, widget - 3);
+		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);
+	}
+};
 
 static const Widget _graph_legend_widgets[] = {
 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},
@@ -334,90 +101,332 @@
 	WC_GRAPH_LEGEND, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 	_graph_legend_widgets,
-	GraphLegendWndProc
 };
 
 static void ShowGraphLegend()
 {
-	AllocateWindowDescFront<Window>(&_graph_legend_desc, 0);
+	AllocateWindowDescFront<GraphLegendWindow>(&_graph_legend_desc, 0);
 }
 
+/******************/
+/* BASE OF GRAPHS */
+/*****************/
+
+struct BaseGraphWindow : Window {
+protected:
+	enum {
+		GRAPH_MAX_DATASETS = 32,
+		GRAPH_AXIS_LABEL_COLOUR = TC_BLACK,
+		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;
+
+	/* 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 colors[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 colors and cost array of GraphDrawer must accomodate
+		* both values for cargo and players. So if any are higher, quit */
+		assert(GRAPH_MAX_DATASETS >= (int)NUM_CARGO && GRAPH_MAX_DATASETS >= (int)MAX_PLAYERS);
+		assert(this->num_vert_lines > 0);
+
+		byte grid_colour = _colour_gradient[14][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);
+
+		/* Find the distance from the gd_top of the graph to the x axis. */
+		x_axis_offset = this->gd_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);
+
+		/* 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. */
+		highest_value = x_axis_offset * 2;
+
+		for (int i = 0; i < this->num_dataset; i++) {
+			if (!HasBit(this->excluded_data, i)) {
+				for (int j = 0; j < this->num_on_x_axis; j++) {
+					OverflowSafeInt64 datapoint = this->cost[i][j];
+
+					if (datapoint != INVALID_DATAPOINT) {
+						/* For now, if the graph has negative values the scaling is
+						* symmetrical about the x axis, so take the absolute value
+						* of each data point. */
+						highest_value = max(highest_value, abs(datapoint));
+					}
+				}
+			}
+		}
+
+		/* Round up highest_value so that it will divide cleanly into the number of
+		* 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;
+
+		for (int i = 0; i < GRAPH_NUM_LINES_Y; i++) {
+			SetDParam(0, this->format_str_y_axis);
+			SetDParam(1, y_label);
+			DrawStringRightAligned(x, y, STR_0170, GRAPH_AXIS_LABEL_COLOUR);
+
+			y_label -= y_label_separation;
+			y += (this->gd_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;
+			byte month = this->month;
+			Year year  = this->year;
+			for (int i = 0; i < this->num_on_x_axis; i++) {
+				SetDParam(0, month + STR_0162_JAN);
+				SetDParam(1, month + STR_0162_JAN + 2);
+				SetDParam(2, year);
+				DrawString(x, y, month == 0 ? STR_016F : STR_016E, 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 + (GRAPH_X_POSITION_SEPARATION / 2) + 1;
+			y = this->gd_top + this->gd_height + 1;
+			uint16 label = this->x_values_start;
+
+			for (int i = 0; i < this->num_on_x_axis; i++) {
+				SetDParam(0, label);
+				DrawStringCentered(x, y, STR_01CB, GRAPH_AXIS_LABEL_COLOUR);
+
+				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);
+
+				byte color  = this->colors[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);
+						} else {
+							datapoint >>= reduce_range;
+						}
+
+						y = this->gd_top + x_axis_offset - (x_axis_offset * datapoint) / (highest_value >> reduce_range);
+
+						/* Draw the point. */
+						GfxFillRect(x - 1, y - 1, x + 1, y + 1, color);
+
+						/* Draw the line connected to the previous point. */
+						if (prev_x != INVALID_DATAPOINT_POS) GfxDrawLine(prev_x, prev_y, x, y, color);
+
+						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)
+	{
+		InvalidateWindow(WC_GRAPH_LEGEND, 0);
+	}
+
+public:
+	virtual void OnPaint()
+	{
+		this->DrawWidgets();
+
+		uint excluded_players = _legend_excluded_players;
+
+		/* Exclude the players which aren't valid */
+		const Player* p;
+		FOR_ALL_PLAYERS(p) {
+			if (!p->is_active) SetBit(excluded_players, p->index);
+		}
+		this->excluded_data = excluded_players;
+		this->num_vert_lines = 24;
+
+		byte nums = 0;
+		FOR_ALL_PLAYERS(p) {
+			if (p->is_active) nums = max(nums, p->num_valid_stat_ent);
+		}
+		this->num_on_x_axis = min(nums, 24);
+
+		int mo = (_cur_month / 3 - nums) * 3;
+		int yr = _cur_year;
+		while (mo < 0) {
+			yr--;
+			mo += 12;
+		}
+
+		this->year = yr;
+		this->month = mo;
+
+		int numd = 0;
+		FOR_ALL_PLAYERS(p) {
+			if (p->is_active) {
+				this->colors[numd] = _colour_gradient[p->player_color][6];
+				for (int j = this->num_on_x_axis, i = 0; --j >= 0;) {
+					this->cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_DATAPOINT : GetGraphData(p, j);
+					i++;
+				}
+			}
+			numd++;
+		}
+
+		this->num_dataset = numd;
+
+		this->DrawGraph();
+	}
+
+	virtual OverflowSafeInt64 GetGraphData(const Player *p, int j)
+	{
+		return INVALID_DATAPOINT;
+	}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		/* Clicked on legend? */
+		if (widget == 2) ShowGraphLegend();
+	}
+};
+
 /********************/
 /* OPERATING PROFIT */
 /********************/
 
-static void SetupGraphDrawerForPlayers(GraphDrawer *gd)
-{
-	const Player* p;
-	uint excluded_players = _legend_excluded_players;
-	byte nums;
-	int mo, yr;
-
-	/* Exclude the players which aren't valid */
-	FOR_ALL_PLAYERS(p) {
-		if (!p->is_active) SetBit(excluded_players, p->index);
-	}
-	gd->excluded_data = excluded_players;
-	gd->num_vert_lines = 24;
-
-	nums = 0;
-	FOR_ALL_PLAYERS(p) {
-		if (p->is_active) nums = max(nums, p->num_valid_stat_ent);
-	}
-	gd->num_on_x_axis = min(nums, 24);
-
-	mo = (_cur_month / 3 - nums) * 3;
-	yr = _cur_year;
-	while (mo < 0) {
-		yr--;
-		mo += 12;
+struct OperatingProfitGraphWindow : BaseGraphWindow {
+	OperatingProfitGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
+			BaseGraphWindow(desc, window_number, 2, 18, 136, true, STR_CURRCOMPACT)
+	{
+		this->FindWindowPlacementAndResize(desc);
 	}
 
-	gd->year = yr;
-	gd->month = mo;
-}
-
-static void OperatingProfitWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			GraphDrawer gd;
-			const Player* p;
-
-			DrawWindowWidgets(w);
-
-			gd.left = 2;
-			gd.top = 18;
-			gd.height = 136;
-			gd.has_negative_values = true;
-			gd.format_str_y_axis = STR_CURRCOMPACT;
-
-			SetupGraphDrawerForPlayers(&gd);
-
-			int numd = 0;
-			FOR_ALL_PLAYERS(p) {
-				if (p->is_active) {
-					gd.colors[numd] = _colour_gradient[p->player_color][6];
-					for (int j = gd.num_on_x_axis, i = 0; --j >= 0;) {
-						gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_DATAPOINT : (p->old_economy[j].income + p->old_economy[j].expenses);
-						i++;
-					}
-				}
-				numd++;
-			}
-
-			gd.num_dataset = numd;
-
-			DrawGraph(&gd);
-			break;
-		}
-
-		case WE_CLICK:
-			/* Clicked on legend? */
-			if (e->we.click.widget == 2) ShowGraphLegend();
-			break;
+	virtual OverflowSafeInt64 GetGraphData(const Player *p, int j)
+	{
+		return p->old_economy[j].income + p->old_economy[j].expenses;
 	}
-}
+};
 
 static const Widget _operating_profit_widgets[] = {
 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},
@@ -432,15 +441,12 @@
 	WC_OPERATING_PROFIT, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
 	_operating_profit_widgets,
-	OperatingProfitWndProc
 };
 
 
 void ShowOperatingProfitGraph()
 {
-	if (AllocateWindowDescFront<Window>(&_operating_profit_desc, 0)) {
-		InvalidateWindow(WC_GRAPH_LEGEND, 0);
-	}
+	AllocateWindowDescFront<OperatingProfitGraphWindow>(&_operating_profit_desc, 0);
 }
 
 
@@ -448,45 +454,18 @@
 /* INCOME GRAPH */
 /****************/
 
-static void IncomeGraphWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			GraphDrawer gd;
-			const Player* p;
-
-			DrawWindowWidgets(w);
-
-			gd.left = 2;
-			gd.top = 18;
-			gd.height = 104;
-			gd.has_negative_values = false;
-			gd.format_str_y_axis = STR_CURRCOMPACT;
-			SetupGraphDrawerForPlayers(&gd);
+struct IncomeGraphWindow : BaseGraphWindow {
+	IncomeGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
+			BaseGraphWindow(desc, window_number, 2, 18, 104, false, STR_CURRCOMPACT)
+	{
+		this->FindWindowPlacementAndResize(desc);
+	}
 
-			int numd = 0;
-			FOR_ALL_PLAYERS(p) {
-				if (p->is_active) {
-					gd.colors[numd] = _colour_gradient[p->player_color][6];
-					for (int j = gd.num_on_x_axis, i = 0; --j >= 0;) {
-						gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_DATAPOINT : p->old_economy[j].income;
-						i++;
-					}
-				}
-				numd++;
-			}
-
-			gd.num_dataset = numd;
-
-			DrawGraph(&gd);
-			break;
-		}
-
-		case WE_CLICK:
-			if (e->we.click.widget == 2) ShowGraphLegend();
-			break;
+	virtual OverflowSafeInt64 GetGraphData(const Player *p, int j)
+	{
+		return p->old_economy[j].income;
 	}
-}
+};
 
 static const Widget _income_graph_widgets[] = {
 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},
@@ -501,59 +480,29 @@
 	WC_INCOME_GRAPH, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
 	_income_graph_widgets,
-	IncomeGraphWndProc
 };
 
 void ShowIncomeGraph()
 {
-	if (AllocateWindowDescFront<Window>(&_income_graph_desc, 0)) {
-		InvalidateWindow(WC_GRAPH_LEGEND, 0);
-	}
+	AllocateWindowDescFront<IncomeGraphWindow>(&_income_graph_desc, 0);
 }
 
 /*******************/
 /* DELIVERED CARGO */
 /*******************/
 
-static void DeliveredCargoGraphWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			GraphDrawer gd;
-			const Player* p;
-
-			DrawWindowWidgets(w);
-
-			gd.left = 2;
-			gd.top = 18;
-			gd.height = 104;
-			gd.has_negative_values = false;
-			gd.format_str_y_axis = STR_7024;
-			SetupGraphDrawerForPlayers(&gd);
+struct DeliveredCargoGraphWindow : BaseGraphWindow {
+	DeliveredCargoGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
+			BaseGraphWindow(desc, window_number, 2, 18, 104, false, STR_7024)
+	{
+		this->FindWindowPlacementAndResize(desc);
+	}
 
-			int numd = 0;
-			FOR_ALL_PLAYERS(p) {
-				if (p->is_active) {
-					gd.colors[numd] = _colour_gradient[p->player_color][6];
-					for (int j = gd.num_on_x_axis, i = 0; --j >= 0;) {
-						gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_DATAPOINT : (OverflowSafeInt64)p->old_economy[j].delivered_cargo;
-						i++;
-					}
-				}
-				numd++;
-			}
-
-			gd.num_dataset = numd;
-
-			DrawGraph(&gd);
-			break;
-		}
-
-		case WE_CLICK:
-			if (e->we.click.widget == 2) ShowGraphLegend();
-			break;
+	virtual OverflowSafeInt64 GetGraphData(const Player *p, int j)
+	{
+		return p->old_economy[j].delivered_cargo;
 	}
-}
+};
 
 static const Widget _delivered_cargo_graph_widgets[] = {
 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                          STR_018B_CLOSE_WINDOW},
@@ -568,60 +517,35 @@
 	WC_DELIVERED_CARGO, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
 	_delivered_cargo_graph_widgets,
-	DeliveredCargoGraphWndProc
 };
 
 void ShowDeliveredCargoGraph()
 {
-	if (AllocateWindowDescFront<Window>(&_delivered_cargo_graph_desc, 0)) {
-		InvalidateWindow(WC_GRAPH_LEGEND, 0);
-	}
+	AllocateWindowDescFront<DeliveredCargoGraphWindow>(&_delivered_cargo_graph_desc, 0);
 }
 
 /***********************/
 /* PERFORMANCE HISTORY */
 /***********************/
 
-static void PerformanceHistoryWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			GraphDrawer gd;
-			const Player* p;
-
-			DrawWindowWidgets(w);
-
-			gd.left = 2;
-			gd.top = 18;
-			gd.height = 200;
-			gd.has_negative_values = false;
-			gd.format_str_y_axis = STR_7024;
-			SetupGraphDrawerForPlayers(&gd);
+struct PerformanceHistoryGraphWindow : BaseGraphWindow {
+	PerformanceHistoryGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
+			BaseGraphWindow(desc, window_number, 2, 18, 200, false, STR_7024)
+	{
+		this->FindWindowPlacementAndResize(desc);
+	}
 
-			int numd = 0;
-			FOR_ALL_PLAYERS(p) {
-				if (p->is_active) {
-					gd.colors[numd] = _colour_gradient[p->player_color][6];
-					for (int j = gd.num_on_x_axis, i = 0; --j >= 0;) {
-						gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_DATAPOINT : (OverflowSafeInt64)p->old_economy[j].performance_history;
-						i++;
-					}
-				}
-				numd++;
-			}
+	virtual OverflowSafeInt64 GetGraphData(const Player *p, int j)
+	{
+		return p->old_economy[j].performance_history;
+	}
 
-			gd.num_dataset = numd;
-
-			DrawGraph(&gd);
-			break;
-		}
-
-		case WE_CLICK:
-			if (e->we.click.widget == 2) ShowGraphLegend();
-			if (e->we.click.widget == 3) ShowPerformanceRatingDetail();
-			break;
+	virtual void OnClick(Point pt, int widget)
+	{
+		if (widget == 3) ShowPerformanceRatingDetail();
+		this->BaseGraphWindow::OnClick(pt, widget);
 	}
-}
+};
 
 static const Widget _performance_history_widgets[] = {
 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                             STR_018B_CLOSE_WINDOW},
@@ -637,59 +561,29 @@
 	WC_PERFORMANCE_HISTORY, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
 	_performance_history_widgets,
-	PerformanceHistoryWndProc
 };
 
 void ShowPerformanceHistoryGraph()
 {
-	if (AllocateWindowDescFront<Window>(&_performance_history_desc, 0)) {
-		InvalidateWindow(WC_GRAPH_LEGEND, 0);
-	}
+	AllocateWindowDescFront<PerformanceHistoryGraphWindow>(&_performance_history_desc, 0);
 }
 
 /*****************/
 /* COMPANY VALUE */
 /*****************/
 
-static void CompanyValueGraphWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			GraphDrawer gd;
-			const Player* p;
-
-			DrawWindowWidgets(w);
-
-			gd.left = 2;
-			gd.top = 18;
-			gd.height = 200;
-			gd.has_negative_values = false;
-			gd.format_str_y_axis = STR_CURRCOMPACT;
-			SetupGraphDrawerForPlayers(&gd);
+struct CompanyValueGraphWindow : BaseGraphWindow {
+	CompanyValueGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
+			BaseGraphWindow(desc, window_number, 2, 18, 200, false, STR_CURRCOMPACT)
+	{
+		this->FindWindowPlacementAndResize(desc);
+	}
 
-			int numd = 0;
-			FOR_ALL_PLAYERS(p) {
-				if (p->is_active) {
-					gd.colors[numd] = _colour_gradient[p->player_color][6];
-					for (int j = gd.num_on_x_axis, i = 0; --j >= 0;) {
-						gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_DATAPOINT : p->old_economy[j].company_value;
-						i++;
-					}
-				}
-				numd++;
-			}
-
-			gd.num_dataset = numd;
-
-			DrawGraph(&gd);
-			break;
-		}
-
-		case WE_CLICK:
-			if (e->we.click.widget == 2) ShowGraphLegend();
-			break;
+	virtual OverflowSafeInt64 GetGraphData(const Player *p, int j)
+	{
+		return p->old_economy[j].company_value;
 	}
-}
+};
 
 static const Widget _company_value_graph_widgets[] = {
 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                STR_018B_CLOSE_WINDOW},
@@ -704,90 +598,117 @@
 	WC_COMPANY_VALUE, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
 	_company_value_graph_widgets,
-	CompanyValueGraphWndProc
 };
 
 void ShowCompanyValueGraph()
 {
-	if (AllocateWindowDescFront<Window>(&_company_value_graph_desc, 0)) {
-		InvalidateWindow(WC_GRAPH_LEGEND, 0);
-	}
+	AllocateWindowDescFront<CompanyValueGraphWindow>(&_company_value_graph_desc, 0);
 }
 
 /*****************/
 /* PAYMENT RATES */
 /*****************/
 
-static void CargoPaymentRatesWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			GraphDrawer gd;
-
-			DrawWindowWidgets(w);
-
-			int x = 495;
-			int y = 24;
-
-			gd.excluded_data = _legend_excluded_cargo;
-			gd.left = 2;
-			gd.top = 24;
-			gd.height = w->height - 38;
-			gd.has_negative_values = false;
-			gd.format_str_y_axis = STR_CURRCOMPACT;
-			gd.num_on_x_axis = 20;
-			gd.num_vert_lines = 20;
-			gd.month = 0xFF;
-			gd.x_values_start     = 10;
-			gd.x_values_increment = 10;
-
-			uint i = 0;
-			for (CargoID c = 0; c < NUM_CARGO; c++) {
-				const CargoSpec *cs = GetCargo(c);
-				if (!cs->IsValid()) continue;
-
-				/* Only draw labels for widgets that exist. If the widget doesn't
-				 * exist then the local player has used the climate cheat or
-				 * changed the NewGRF configuration with this window open. */
-				if (i + 3 < w->widget_count) {
-					/* Since the buttons have no text, no images,
-					 * both the text and the colored box have to be manually painted.
-					 * clk_dif will move one pixel down and one pixel to the right
-					 * when the button is clicked */
-					byte clk_dif = w->IsWidgetLowered(i + 3) ? 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, y + clk_dif, STR_7065, TC_FROMSTRING);
-					y += 8;
-				}
-
-				gd.colors[i] = cs->legend_colour;
-				for (uint j = 0; j != 20; j++) {
-					gd.cost[i][j] = GetTransportedGoodsIncome(10, 20, j * 6 + 6, c);
-				}
-
-				i++;
-			}
-			gd.num_dataset = i;
-
-			DrawGraph(&gd);
-
-			DrawString(2 + 46, 24 + gd.height + 7, STR_7062_DAYS_IN_TRANSIT, TC_FROMSTRING);
-			DrawString(2 + 84, 24 - 9, STR_7063_PAYMENT_FOR_DELIVERING, TC_FROMSTRING);
-			break;
+struct PaymentRatesGraphWindow : BaseGraphWindow {
+	PaymentRatesGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
+			BaseGraphWindow(desc, window_number, 2, 24, 200, false, STR_CURRCOMPACT)
+	{
+		uint num_active = 0;
+		for (CargoID c = 0; c < NUM_CARGO; c++) {
+			if (GetCargo(c)->IsValid()) num_active++;
 		}
 
-		case WE_CLICK:
-			if (e->we.click.widget >= 3) {
-				ToggleBit(_legend_excluded_cargo, e->we.click.widget - 3);
-				w->ToggleWidgetLoweredState(e->we.click.widget);
-				w->SetDirty();
+		/* 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[3 + i];
+			wi->type     = WWT_PANEL;
+			wi->display_flags = RESIZE_NONE;
+			wi->color    = 12;
+			wi->left     = 493;
+			wi->right    = 562;
+			wi->top      = 24 + i * 8;
+			wi->bottom   = wi->top + 7;
+			wi->data     = 0;
+			wi->tooltips = STR_7064_TOGGLE_GRAPH_FOR_CARGO;
+
+			if (!HasBit(_legend_excluded_cargo, i)) this->LowerWidget(i + 3);
+		}
+
+		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->FindWindowPlacementAndResize(desc);
+	}
+
+	virtual void OnPaint()
+	{
+		this->DrawWidgets();
+
+		this->excluded_data = _legend_excluded_cargo;
+
+		int x = 495;
+		int y = 24;
+
+		uint i = 0;
+		for (CargoID c = 0; c < NUM_CARGO; c++) {
+			const CargoSpec *cs = GetCargo(c);
+			if (!cs->IsValid()) continue;
+
+			/* Only draw labels for widgets that exist. If the widget doesn't
+				* exist then the local player has used the climate cheat or
+				* changed the NewGRF configuration with this window open. */
+			if (i + 3 < this->widget_count) {
+				/* Since the buttons have no text, no images,
+					* both the text and the colored box have to be manually painted.
+					* clk_dif will move one pixel down and one pixel to the right
+					* when the button is clicked */
+				byte clk_dif = this->IsWidgetLowered(i + 3) ? 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, y + clk_dif, STR_7065, TC_FROMSTRING);
+				y += 8;
 			}
-			break;
+
+			this->colors[i] = cs->legend_colour;
+			for (uint j = 0; j != 20; j++) {
+				this->cost[i][j] = GetTransportedGoodsIncome(10, 20, j * 6 + 6, c);
+			}
+
+			i++;
+		}
+		this->num_dataset = i;
+
+		this->DrawGraph();
+
+		DrawString(2 + 46, 24 + this->gd_height + 7, STR_7062_DAYS_IN_TRANSIT, TC_FROMSTRING);
+		DrawString(2 + 84, 24 - 9, STR_7063_PAYMENT_FOR_DELIVERING, TC_FROMSTRING);
 	}
-}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		if (widget >= 3) {
+			ToggleBit(_legend_excluded_cargo, widget - 3);
+			this->ToggleWidgetLoweredState(widget);
+			this->SetDirty();
+		}
+	}
+};
 
 static const Widget _cargo_payment_rates_widgets[] = {
 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                     STR_018B_CLOSE_WINDOW},
@@ -801,46 +722,12 @@
 	WC_PAYMENT_RATES, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 	_cargo_payment_rates_widgets,
-	CargoPaymentRatesWndProc
 };
 
 
 void ShowCargoPaymentRates()
 {
-	Window *w = AllocateWindowDescFront<Window>(&_cargo_payment_rates_desc, 0);
-	if (w == NULL) return;
-
-	/* Count the number of active cargo types */
-	uint num_active = 0;
-	for (CargoID c = 0; c < NUM_CARGO; c++) {
-		if (GetCargo(c)->IsValid()) num_active++;
-	}
-
-	/* Resize the window to fit the cargo types */
-	ResizeWindow(w, 0, max(num_active, 12U) * 8);
-
-	/* Add widgets for each cargo type */
-	w->widget_count += num_active;
-	w->widget = ReallocT(w->widget, w->widget_count + 1);
-	w->widget[w->widget_count].type = WWT_LAST;
-
-	/* Set the properties of each widget */
-	for (uint i = 0; i != num_active; i++) {
-		Widget *wi = &w->widget[3 + i];
-		wi->type     = WWT_PANEL;
-		wi->display_flags = RESIZE_NONE;
-		wi->color    = 12;
-		wi->left     = 493;
-		wi->right    = 562;
-		wi->top      = 24 + i * 8;
-		wi->bottom   = wi->top + 7;
-		wi->data     = 0;
-		wi->tooltips = STR_7064_TOGGLE_GRAPH_FOR_CARGO;
-
-		if (!HasBit(_legend_excluded_cargo, i)) w->LowerWidget(i + 3);
-	}
-
-	w->SetDirty();
+	AllocateWindowDescFront<PaymentRatesGraphWindow>(&_cargo_payment_rates_desc, 0);
 }
 
 /************************/
@@ -879,35 +766,35 @@
 	return p2->old_economy[1].performance_history - p1->old_economy[1].performance_history;
 }
 
-static void CompanyLeagueWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			const Player* plist[MAX_PLAYERS];
-			const Player* p;
-
-			DrawWindowWidgets(w);
-
-			uint pl_num = 0;
-			FOR_ALL_PLAYERS(p) if (p->is_active) plist[pl_num++] = p;
+struct CompanyLeagueWindow : Window {
+	CompanyLeagueWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+	{
+	}
 
-			qsort((void*)plist, pl_num, sizeof(*plist), PerfHistComp);
+	virtual void OnPaint()
+	{
+		const Player *plist[MAX_PLAYERS];
+		const Player *p;
 
-			for (uint i = 0; i != pl_num; i++) {
-				p = plist[i];
-				SetDParam(0, i + STR_01AC_1ST);
-				SetDParam(1, p->index);
-				SetDParam(2, p->index);
-				SetDParam(3, GetPerformanceTitleFromValue(p->old_economy[1].performance_history));
+		this->DrawWidgets();
 
-				DrawString(2, 15 + i * 10, i == 0 ? STR_7054 : STR_7055, TC_FROMSTRING);
-				DrawPlayerIcon(p->index, 27, 16 + i * 10);
-			}
+		uint pl_num = 0;
+		FOR_ALL_PLAYERS(p) if (p->is_active) plist[pl_num++] = p;
 
-			break;
+		qsort((void*)plist, pl_num, sizeof(*plist), PerfHistComp);
+
+		for (uint i = 0; i != pl_num; i++) {
+			p = plist[i];
+			SetDParam(0, i + STR_01AC_1ST);
+			SetDParam(1, p->index);
+			SetDParam(2, p->index);
+			SetDParam(3, GetPerformanceTitleFromValue(p->old_economy[1].performance_history));
+
+			DrawString(2, 15 + i * 10, i == 0 ? STR_7054 : STR_7055, TC_FROMSTRING);
+			DrawPlayerIcon(p->index, 27, 16 + i * 10);
 		}
 	}
-}
+};
 
 
 static const Widget _company_league_widgets[] = {
@@ -923,208 +810,204 @@
 	WC_COMPANY_LEAGUE, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
 	_company_league_widgets,
-	CompanyLeagueWndProc
 };
 
 void ShowCompanyLeagueTable()
 {
-	AllocateWindowDescFront<Window>(&_company_league_desc, 0);
+	AllocateWindowDescFront<CompanyLeagueWindow>(&_company_league_desc, 0);
 }
 
 /*****************************/
 /* PERFORMANCE RATING DETAIL */
 /*****************************/
 
-static void PerformanceRatingDetailWndProc(Window *w, WindowEvent *e)
-{
-	static PlayerID _performance_rating_detail_player = INVALID_PLAYER;
-
-	switch (e->event) {
-		case WE_PAINT: {
-			byte x;
-			uint16 y = 14;
-			int total_score = 0;
-			int color_done, color_notdone;
-
-			/* Draw standard stuff */
-			DrawWindowWidgets(w);
-
-			/* Check if the currently selected player is still active. */
-			if (_performance_rating_detail_player == INVALID_PLAYER || !GetPlayer(_performance_rating_detail_player)->is_active) {
-				if (_performance_rating_detail_player != INVALID_PLAYER) {
-					/* Raise and disable the widget for the previous selection. */
-					w->RaiseWidget(_performance_rating_detail_player + 13);
-					w->DisableWidget(_performance_rating_detail_player + 13);
-					w->SetDirty();
-
-					_performance_rating_detail_player = INVALID_PLAYER;
-				}
-
-				for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
-					if (GetPlayer(i)->is_active) {
-						/* Lower the widget corresponding to this player. */
-						w->LowerWidget(i + 13);
-						w->SetDirty();
+struct PerformanceRatingDetailWindow : Window {
+	static PlayerID player;
+	int timeout;
 
-						_performance_rating_detail_player = i;
-						break;
-					}
-				}
-			}
-
-			/* If there are no active players, don't display anything else. */
-			if (_performance_rating_detail_player == INVALID_PLAYER) break;
+	PerformanceRatingDetailWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+	{
+		/* Disable the players who are not active */
+		for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
+			this->SetWidgetDisabledState(i + 13, !GetPlayer(i)->is_active);
+		}
 
-			/* Paint the player icons */
-			for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
-				if (!GetPlayer(i)->is_active) {
-					/* Check if we have the player as an active player */
-					if (!w->IsWidgetDisabled(i + 13)) {
-						/* Bah, player gone :( */
-						w->DisableWidget(i + 13);
+		this->UpdatePlayerStats();
 
-						/* We need a repaint */
-						w->SetDirty();
-					}
-					continue;
-				}
+		if (player != INVALID_PLAYER) this->LowerWidget(player + 13);
 
-				/* Check if we have the player marked as inactive */
-				if (w->IsWidgetDisabled(i + 13)) {
-					/* New player! Yippie :p */
-					w->EnableWidget(i + 13);
-					/* We need a repaint */
-					w->SetDirty();
-				}
+		this->FindWindowPlacementAndResize(desc);
+	}
 
-				x = (i == _performance_rating_detail_player) ? 1 : 0;
-				DrawPlayerIcon(i, i * 37 + 13 + x, 16 + x);
+	void UpdatePlayerStats()
+	{
+		/* Update all player stats with the current data
+		 * (this is because _score_info is not saved to a savegame) */
+		Player *p;
+		FOR_ALL_PLAYERS(p) {
+			if (p->is_active) UpdateCompanyRatingAndValue(p, false);
+		}
+
+		this->timeout = DAY_TICKS * 5;
+
+	}
+
+	virtual void OnPaint()
+	{
+		byte x;
+		uint16 y = 14;
+		int total_score = 0;
+		int color_done, color_notdone;
+
+		/* Draw standard stuff */
+		this->DrawWidgets();
+
+		/* Check if the currently selected player is still active. */
+		if (player == INVALID_PLAYER || !GetPlayer(player)->is_active) {
+			if (player != INVALID_PLAYER) {
+				/* Raise and disable the widget for the previous selection. */
+				this->RaiseWidget(player + 13);
+				this->DisableWidget(player + 13);
+				this->SetDirty();
+
+				player = INVALID_PLAYER;
 			}
 
-			/* The colors used to show how the progress is going */
-			color_done = _colour_gradient[COLOUR_GREEN][4];
-			color_notdone = _colour_gradient[COLOUR_RED][4];
-
-			/* Draw all the score parts */
-			for (ScoreID i = SCORE_BEGIN; i < SCORE_END; i++) {
-				int val    = _score_part[_performance_rating_detail_player][i];
-				int needed = _score_info[i].needed;
-				int score  = _score_info[i].score;
-
-				y += 20;
-				/* SCORE_TOTAL has his own rulez ;) */
-				if (i == SCORE_TOTAL) {
-					needed = total_score;
-					score = SCORE_MAX;
-				} else {
-					total_score += score;
-				}
-
-				DrawString(7, y, STR_PERFORMANCE_DETAIL_VEHICLES + i, TC_FROMSTRING);
-
-				/* Draw the score */
-				SetDParam(0, score);
-				DrawStringRightAligned(107, y, SET_PERFORMANCE_DETAIL_INT, TC_FROMSTRING);
-
-				/* Calculate the %-bar */
-				x = Clamp(val, 0, needed) * 50 / needed;
-
-				/* SCORE_LOAN is inversed */
-				if (val < 0 && i == SCORE_LOAN) x = 0;
+			for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
+				if (GetPlayer(i)->is_active) {
+					/* Lower the widget corresponding to this player. */
+					this->LowerWidget(i + 13);
+					this->SetDirty();
 
-				/* Draw the bar */
-				if (x !=  0) GfxFillRect(112,     y - 2, 112 + x,  y + 10, color_done);
-				if (x != 50) GfxFillRect(112 + x, y - 2, 112 + 50, y + 10, color_notdone);
-
-				/* Calculate the % */
-				x = Clamp(val, 0, needed) * 100 / needed;
-
-				/* SCORE_LOAN is inversed */
-				if (val < 0 && i == SCORE_LOAN) x = 0;
-
-				/* Draw it */
-				SetDParam(0, x);
-				DrawStringCentered(137, y, STR_PERFORMANCE_DETAIL_PERCENT, TC_FROMSTRING);
-
-				/* SCORE_LOAN is inversed */
-				if (i == SCORE_LOAN) val = needed - val;
-
-				/* Draw the amount we have against what is needed
-				 * For some of them it is in currency format */
-				SetDParam(0, val);
-				SetDParam(1, needed);
-				switch (i) {
-					case SCORE_MIN_PROFIT:
-					case SCORE_MIN_INCOME:
-					case SCORE_MAX_INCOME:
-					case SCORE_MONEY:
-					case SCORE_LOAN:
-						DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY, TC_FROMSTRING);
-						break;
-					default:
-						DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_INT, TC_FROMSTRING);
+					player = i;
+					break;
 				}
 			}
-
-			break;
 		}
 
-		case WE_CLICK:
-			/* Check which button is clicked */
-			if (IsInsideMM(e->we.click.widget, 13, 21)) {
-				/* Is it no on disable? */
-				if (!w->IsWidgetDisabled(e->we.click.widget)) {
-					w->RaiseWidget(_performance_rating_detail_player + 13);
-					_performance_rating_detail_player = (PlayerID)(e->we.click.widget - 13);
-					w->LowerWidget(_performance_rating_detail_player + 13);
-					w->SetDirty();
+		/* If there are no active players, don't display anything else. */
+		if (player == INVALID_PLAYER) return;
+
+		/* Paint the player icons */
+		for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
+			if (!GetPlayer(i)->is_active) {
+				/* Check if we have the player as an active player */
+				if (!this->IsWidgetDisabled(i + 13)) {
+					/* Bah, player gone :( */
+					this->DisableWidget(i + 13);
+
+					/* We need a repaint */
+					this->SetDirty();
 				}
-			}
-			break;
-
-		case WE_CREATE: {
-			Player *p2;
-
-			/* Disable the players who are not active */
-			for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
-				w->SetWidgetDisabledState(i + 13, !GetPlayer(i)->is_active);
-			}
-			/* Update all player stats with the current data
-			 * (this is because _score_info is not saved to a savegame) */
-			FOR_ALL_PLAYERS(p2) {
-				if (p2->is_active) UpdateCompanyRatingAndValue(p2, false);
+				continue;
 			}
 
-			w->custom[0] = DAY_TICKS;
-			w->custom[1] = 5;
+			/* Check if we have the player marked as inactive */
+			if (this->IsWidgetDisabled(i + 13)) {
+				/* New player! Yippie :p */
+				this->EnableWidget(i + 13);
+				/* We need a repaint */
+				this->SetDirty();
+			}
 
-			if (_performance_rating_detail_player != INVALID_PLAYER) w->LowerWidget(_performance_rating_detail_player + 13);
-			w->SetDirty();
-
-			break;
+			x = (i == player) ? 1 : 0;
+			DrawPlayerIcon(i, i * 37 + 13 + x, 16 + x);
 		}
 
-		case WE_TICK:
-			if (_pause_game != 0) break;
+		/* The colors used to show how the progress is going */
+		color_done = _colour_gradient[COLOUR_GREEN][4];
+		color_notdone = _colour_gradient[COLOUR_RED][4];
 
-			/* Update the player score every 5 days */
-			if (--w->custom[0] == 0) {
-				w->custom[0] = DAY_TICKS;
-				if (--w->custom[1] == 0) {
-					Player *p2;
+		/* Draw all the score parts */
+		for (ScoreID i = SCORE_BEGIN; i < SCORE_END; i++) {
+			int val    = _score_part[player][i];
+			int needed = _score_info[i].needed;
+			int score  = _score_info[i].score;
 
-					w->custom[1] = 5;
-					FOR_ALL_PLAYERS(p2) {
-						/* Skip if player is not active */
-						if (p2->is_active) UpdateCompanyRatingAndValue(p2, false);
-					}
-					w->SetDirty();
-				}
+			y += 20;
+			/* SCORE_TOTAL has his own rulez ;) */
+			if (i == SCORE_TOTAL) {
+				needed = total_score;
+				score = SCORE_MAX;
+			} else {
+				total_score += score;
 			}
 
-			break;
+			DrawString(7, y, STR_PERFORMANCE_DETAIL_VEHICLES + i, TC_FROMSTRING);
+
+			/* Draw the score */
+			SetDParam(0, score);
+			DrawStringRightAligned(107, y, SET_PERFORMANCE_DETAIL_INT, TC_FROMSTRING);
+
+			/* Calculate the %-bar */
+			x = Clamp(val, 0, needed) * 50 / needed;
+
+			/* SCORE_LOAN is inversed */
+			if (val < 0 && i == SCORE_LOAN) x = 0;
+
+			/* Draw the bar */
+			if (x !=  0) GfxFillRect(112,     y - 2, 112 + x,  y + 10, color_done);
+			if (x != 50) GfxFillRect(112 + x, y - 2, 112 + 50, y + 10, color_notdone);
+
+			/* Calculate the % */
+			x = Clamp(val, 0, needed) * 100 / needed;
+
+			/* SCORE_LOAN is inversed */
+			if (val < 0 && i == SCORE_LOAN) x = 0;
+
+			/* Draw it */
+			SetDParam(0, x);
+			DrawStringCentered(137, y, STR_PERFORMANCE_DETAIL_PERCENT, TC_FROMSTRING);
+
+			/* SCORE_LOAN is inversed */
+			if (i == SCORE_LOAN) val = needed - val;
+
+			/* Draw the amount we have against what is needed
+				* For some of them it is in currency format */
+			SetDParam(0, val);
+			SetDParam(1, needed);
+			switch (i) {
+				case SCORE_MIN_PROFIT:
+				case SCORE_MIN_INCOME:
+				case SCORE_MAX_INCOME:
+				case SCORE_MONEY:
+				case SCORE_LOAN:
+					DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY, TC_FROMSTRING);
+					break;
+				default:
+					DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_INT, TC_FROMSTRING);
+			}
+		}
 	}
-}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		/* Check which button is clicked */
+		if (IsInsideMM(widget, 13, 21)) {
+			/* Is it no on disable? */
+			if (!this->IsWidgetDisabled(widget)) {
+				this->RaiseWidget(player + 13);
+				player = (PlayerID)(widget - 13);
+				this->LowerWidget(player + 13);
+				this->SetDirty();
+			}
+		}
+	}
+
+	virtual void OnTick()
+	{
+		if (_pause_game != 0) return;
+
+		/* Update the player score every 5 days */
+		if (--this->timeout == 0) {
+			this->UpdatePlayerStats();
+			this->SetDirty();
+		}
+	}
+};
+
+PlayerID PerformanceRatingDetailWindow::player = INVALID_PLAYER;
+
 
 static const Widget _performance_rating_detail_widgets[] = {
 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,               STR_018B_CLOSE_WINDOW},
@@ -1158,10 +1041,9 @@
 	WC_PERFORMANCE_DETAIL, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 	_performance_rating_detail_widgets,
-	PerformanceRatingDetailWndProc
 };
 
 void ShowPerformanceRatingDetail()
 {
-	AllocateWindowDescFront<Window>(&_performance_rating_detail_desc, 0);
+	AllocateWindowDescFront<PerformanceRatingDetailWindow>(&_performance_rating_detail_desc, 0);
 }
--- a/src/group_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/group_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -187,9 +187,10 @@
 	VehicleID vehicle_sel;
 	GUIGroupList groups;
 
-	VehicleGroupWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, NULL, window_number)
+	VehicleGroupWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
 	{
 		const PlayerID owner = (PlayerID)GB(this->window_number, 0, 8);
+		this->vehicle_type = (VehicleType)GB(this->window_number, 11, 5);
 
 		this->caption_color = owner;
 		this->hscroll.cap = 224;
@@ -222,8 +223,6 @@
 			case VEH_AIRCRAFT: this->sorting = &_sorting.aircraft; break;
 		}
 
-		this->vehicle_type = (VehicleType)GB(this->window_number, 11, 5);
-
 		this->vehicles.sort_list = NULL;
 		this->vehicles.sort_type = this->sorting->criteria;
 		this->vehicles.flags = VL_REBUILD | (this->sorting->order ? VL_DESC : VL_NONE);
@@ -287,8 +286,8 @@
 
 	virtual void OnInvalidateData(int data)
 	{
-		this->vehicles.flags |= VL_REBUILD;
-		this->groups.flags |= VL_REBUILD;
+		this->vehicles.flags |= (data == 0 ? VL_REBUILD : VL_RESORT);
+		this->groups.flags |= (data == 0 ? VL_REBUILD : VL_RESORT);
 		if (!(IsAllGroupID(this->group_sel) || IsDefaultGroupID(this->group_sel) || IsValidGroupID(this->group_sel))) {
 			this->group_sel = ALL_GROUP;
 			HideDropDownMenu(this);
@@ -404,7 +403,7 @@
 		/* Set text of sort by dropdown */
 		this->widget[GRP_WIDGET_SORT_BY_DROPDOWN].data = _vehicle_sort_listing[this->vehicles.sort_type];
 
-		DrawWindowWidgets(this);
+		this->DrawWidgets();
 
 		/* Draw Matrix Group
 			* The selected group is drawn in white */
@@ -452,7 +451,7 @@
 			DrawStringRightAligned(187, y1 + 1, STR_GROUP_TINY_NUM, (this->group_sel == g->index) ? TC_WHITE : TC_BLACK);
 		}
 
-		DrawSortButtonState(this, GRP_WIDGET_SORT_BY_ORDER, this->vehicles.flags & VL_DESC ? SBS_DOWN : SBS_UP);
+		this->DrawSortButtonState(GRP_WIDGET_SORT_BY_ORDER, this->vehicles.flags & VL_DESC ? SBS_DOWN : SBS_UP);
 
 		/* Draw Matrix Vehicle according to the vehicle list built before */
 		max = min(this->vscroll2.pos + this->vscroll2.cap, this->vehicles.list_length);
@@ -758,7 +757,6 @@
 	WC_TRAINS_LIST, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
 	_group_widgets,
-	NULL
 };
 
 void ShowPlayerGroup(PlayerID player, VehicleType vehicle_type)
--- a/src/gui.h	Mon May 19 14:14:33 2008 +0000
+++ b/src/gui.h	Mon May 19 15:13:58 2008 +0000
@@ -52,7 +52,6 @@
 void PlaceLandBlockInfo();
 void ShowAboutWindow();
 void ShowBuildTreesToolbar();
-void ShowBuildTreesScenToolbar();
 void ShowTownDirectory();
 void ShowIndustryDirectory();
 void ShowSubsidiesList();
--- a/src/industry.h	Mon May 19 14:14:33 2008 +0000
+++ b/src/industry.h	Mon May 19 15:13:58 2008 +0000
@@ -354,9 +354,6 @@
 #define FOR_ALL_INDUSTRIES_FROM(i, start) for (i = GetIndustry(start); i != NULL; i = (i->index + 1U < GetIndustryPoolSize()) ? GetIndustry(i->index + 1U) : NULL) if (i->IsValid())
 #define FOR_ALL_INDUSTRIES(i) FOR_ALL_INDUSTRIES_FROM(i, 0)
 
-extern const Industry **_industry_sort;
-extern bool _industry_sort_dirty;
-
 static const uint8 IT_INVALID = 255;
 
 #endif /* INDUSTRY_H */
--- a/src/industry_cmd.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/industry_cmd.cpp	Mon May 19 15:13:58 2008 +0000
@@ -55,9 +55,6 @@
 int _total_industries;                      //general counter
 uint16 _industry_counts[NUM_INDUSTRYTYPES]; // Number of industries per type ingame
 
-const Industry **_industry_sort;
-bool _industry_sort_dirty;
-
 IndustrySpec _industry_specs[NUM_INDUSTRYTYPES];
 IndustryTileSpec _industry_tile_specs[NUM_INDUSTRYTILES];
 
@@ -168,12 +165,11 @@
 		} END_TILE_LOOP(tile_cur, 42, 42, this->xy - TileDiff(21, 21))
 	}
 
-	_industry_sort_dirty = true;
 	DecIndustryTypeCount(this->type);
 
 	DeleteSubsidyWithIndustry(this->index);
 	DeleteWindowById(WC_INDUSTRY_VIEW, this->index);
-	InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0);
+	InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 0);
 	this->xy = 0;
 }
 
@@ -1556,8 +1552,7 @@
 	if (GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_PLANT_ON_BUILT) {
 		for (j = 0; j != 50; j++) PlantRandomFarmField(i);
 	}
-	_industry_sort_dirty = true;
-	InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0);
+	InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 0);
 }
 
 /** Helper function for Build/Fund an industry
@@ -1651,7 +1646,7 @@
 							SetDParam(1, ind->town->index);
 						}
 						AddNewsItem(indspec->new_industry_text,
-								NM_THIN, NF_VIEWPORT | NF_TILE, NT_OPENCLOSE, DNC_NONE, ind->xy, 0);
+								NS_OPENCLOSE, ind->xy, 0);
 						break;
 					}
 				}
@@ -1870,7 +1865,7 @@
 		SetDParam(1, ind->town->index);
 	}
 	AddNewsItem(ind_spc->new_industry_text,
-		NM_THIN, NF_VIEWPORT | NF_TILE, NT_OPENCLOSE, DNC_NONE, ind->xy, 0);
+		NS_OPENCLOSE, ind->xy, 0);
 }
 
 /**
@@ -2002,12 +1997,12 @@
 */
 static void ReportNewsProductionChangeIndustry(Industry *ind, CargoID type, int percent)
 {
-	NewsType nt;
+	NewsSubtype ns;
 
 	switch (WhoCanServiceIndustry(ind)) {
-		case 0: nt = NT_INDUSTRY_NOBODY; break;
-		case 1: nt = NT_INDUSTRY_OTHER;  break;
-		case 2: nt = NT_INDUSTRY_PLAYER; break;
+		case 0: ns = NS_INDUSTRY_NOBODY; break;
+		case 1: ns = NS_INDUSTRY_OTHER;  break;
+		case 2: ns = NS_INDUSTRY_PLAYER; break;
 		default: NOT_REACHED(); break;
 	}
 	SetDParam(2, abs(percent));
@@ -2015,7 +2010,7 @@
 	SetDParam(1, ind->index);
 	AddNewsItem(
 		percent >= 0 ? STR_INDUSTRY_PROD_GOUP : STR_INDUSTRY_PROD_GODOWN,
-		NM_THIN, NF_VIEWPORT | NF_TILE, nt, DNC_NONE,
+		ns,
 		ind->xy + TileDiffXY(1, 1), 0
 	);
 }
@@ -2183,15 +2178,15 @@
 	}
 
 	if (!suppress_message && str != STR_NULL) {
-		NewsType nt;
+		NewsSubtype ns;
 		/* Compute news category */
 		if (closeit) {
-			nt = NT_OPENCLOSE;
+			ns = NS_OPENCLOSE;
 		} else {
 			switch (WhoCanServiceIndustry(i)) {
-				case 0: nt = NT_INDUSTRY_NOBODY; break;
-				case 1: nt = NT_INDUSTRY_OTHER;  break;
-				case 2: nt = NT_INDUSTRY_PLAYER; break;
+				case 0: ns = NS_INDUSTRY_NOBODY; break;
+				case 1: ns = NS_INDUSTRY_OTHER;  break;
+				case 2: ns = NS_INDUSTRY_PLAYER; break;
 				default: NOT_REACHED(); break;
 			}
 		}
@@ -2209,7 +2204,7 @@
 		}
 		/* and report the news to the user */
 		AddNewsItem(str,
-			NM_THIN, NF_VIEWPORT | NF_TILE, nt, DNC_NONE,
+			ns,
 			i->xy + TileDiffXY(1, 1), 0);
 	}
 }
@@ -2240,8 +2235,7 @@
 	_current_player = old_player;
 
 	/* production-change */
-	_industry_sort_dirty = true;
-	InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0);
+	InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 1);
 }
 
 
@@ -2251,7 +2245,6 @@
 	_Industry_pool.AddBlockToPool();
 
 	ResetIndustryCounts();
-	_industry_sort_dirty = true;
 	_industry_sound_tile = 0;
 }
 
--- a/src/industry_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/industry_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -26,6 +26,7 @@
 #include "settings_type.h"
 #include "tilehighlight_func.h"
 #include "string_func.h"
+#include "sortlist_type.h"
 
 #include "table/strings.h"
 #include "table/sprites.h"
@@ -90,7 +91,6 @@
 	WC_BUILD_INDUSTRY, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE,
 	_build_industry_widgets,
-	NULL,
 };
 
 class BuildIndustryWindow : public Window {
@@ -103,14 +103,60 @@
 	StringID text[NUM_INDUSTRYTYPES + 1];       ///< Text coming from CBM_IND_FUND_MORE_TEXT (if ever)
 	bool enabled[NUM_INDUSTRYTYPES + 1];        ///< availability state, coming from CBID_INDUSTRY_AVAILABLE (if ever)
 
-public:
-	BuildIndustryWindow() : Window(&_build_industry_desc)
+	void SetupArrays()
 	{
 		IndustryType ind;
 		const IndustrySpec *indsp;
 
+		this->count = 0;
+
+		for (uint i = 0; i < lengthof(this->index); i++) {
+			this->index[i]   = INVALID_INDUSTRYTYPE;
+			this->text[i]    = STR_NULL;
+			this->enabled[i] = false;
+		}
+
+		if (_game_mode == GM_EDITOR) { // give room for the Many Random "button"
+			this->index[this->count] = INVALID_INDUSTRYTYPE;
+			this->count++;
+			this->timer_enabled = false;
+		}
+		/* Fill the arrays with industries.
+		 * The tests performed after the enabled allow to load the industries
+		 * In the same way they are inserted by grf (if any)
+		 */
+		for (ind = 0; ind < NUM_INDUSTRYTYPES; ind++) {
+			indsp = GetIndustrySpec(ind);
+			if (indsp->enabled){
+				/* Rule is that editor mode loads all industries.
+				 * In game mode, all non raw industries are loaded too
+				 * and raw ones are loaded only when setting allows it */
+				if (_game_mode != GM_EDITOR && indsp->IsRawIndustry() && _patches.raw_industry_construction == 0) {
+					/* Unselect if the industry is no longer in the list */
+					if (this->selected_type == ind) this->selected_index = -1;
+					continue;
+				}
+				this->index[this->count] = ind;
+				this->enabled[this->count] = (_game_mode == GM_EDITOR) || CheckIfCallBackAllowsAvailability(ind, IACT_USERCREATION);
+				/* Keep the selection to the correct line */
+				if (this->selected_type == ind) this->selected_index = this->count;
+				this->count++;
+			}
+		}
+
+		/* first indutry type is selected if the current selection is invalid.
+		 * I'll be damned if there are none available ;) */
+		if (this->selected_index == -1) {
+			this->selected_index = 0;
+			this->selected_type = this->index[0];
+		}
+	}
+
+public:
+	BuildIndustryWindow() : Window(&_build_industry_desc)
+	{
 		/* Shorten the window to the equivalant of the additionnal purchase
-		 * info coming from the callback.  SO it will only be available to tis full
+		 * info coming from the callback.  SO it will only be available to its full
 		 * height when newindistries are loaded */
 		if (!_loaded_newgrf_features.has_newindustries) {
 			this->widget[DPIW_INFOPANEL].bottom -= 44;
@@ -123,45 +169,15 @@
 
 		this->timer_enabled = _loaded_newgrf_features.has_newindustries;
 
-		/* Initialize structures */
-		this->count = 0;
-
-		for (uint i = 0; i < lengthof(this->index); i++) {
-			this->index[i]   = 0xFF;
-			this->text[i]    = STR_NULL;
-			this->enabled[i] = false;
-		}
-
 		this->vscroll.cap = 8; // rows in grid, same in scroller
 		this->resize.step_height = 13;
 
-		if (_game_mode == GM_EDITOR) { // give room for the Many Random "button"
-			this->index[this->count] = INVALID_INDUSTRYTYPE;
-			this->count++;
-			this->timer_enabled = false;
-		}
+		this->selected_index = -1;
+		this->selected_type = INVALID_INDUSTRYTYPE;
 
-		/* Fill the _fund_gui structure with industries.
-		 * The tests performed after the enabled allow to load the industries
-		 * In the same way they are inserted by grf (if any)
-		 */
-		for (ind = 0; ind < NUM_INDUSTRYTYPES; ind++) {
-			indsp = GetIndustrySpec(ind);
-			if (indsp->enabled){
-				/* Rule is that editor mode loads all industries.
-				 * In game mode, all non raw industries are loaded too
-				 * and raw ones are loaded only when setting allows it */
-				if (_game_mode != GM_EDITOR && indsp->IsRawIndustry() && _patches.raw_industry_construction == 0) continue;
-				this->index[this->count] = ind;
-				this->enabled[this->count] = (_game_mode == GM_EDITOR) || CheckIfCallBackAllowsAvailability(ind, IACT_USERCREATION);
-				this->count++;
-			}
-		}
+		/* Initialize arrays */
+		this->SetupArrays();
 
-		/* first indutry type is selected.
-		 * I'll be damned if there are none available ;) */
-		this->selected_index = 0;
-		this->selected_type = this->index[0];
 		this->callback_timer = DAY_TICKS;
 
 		this->FindWindowPlacementAndResize(&_build_industry_desc);
@@ -188,7 +204,7 @@
 
 		SetVScrollCount(this, this->count);
 
-		DrawWindowWidgets(this);
+		this->DrawWidgets();
 
 		/* and now with the matrix painting */
 		for (byte i = 0; i < this->vscroll.cap && ((i + this->vscroll.pos) < this->count); i++) {
@@ -392,6 +408,12 @@
 	{
 		this->RaiseButtons();
 	}
+
+	virtual void OnInvalidateData(int data = 0)
+	{
+		this->SetupArrays();
+		this->SetDirty();
+	}
 };
 
 void ShowBuildIndustryWindow()
@@ -440,7 +462,7 @@
 	byte production_offset_y; ///< The offset of the production texts/buttons
 
 public:
-	IndustryViewWindow(const WindowDesc *desc, void *data, WindowNumber window_number) : Window(desc, data, window_number)
+	IndustryViewWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
 	{
 		this->flags4 |= WF_DISABLE_VP_SCROLL;
 		this->editbox_line = 0;
@@ -459,7 +481,7 @@
 		bool has_accept = false;
 
 		SetDParam(0, this->window_number);
-		DrawWindowWidgets(this);
+		this->DrawWidgets();
 
 		if (HasBit(ind->callback_flags, CBM_IND_PRODUCTION_CARGO_ARRIVAL) || HasBit(ind->callback_flags, CBM_IND_PRODUCTION_256_TICKS)) {
 			for (byte j = 0; j < lengthof(i->accepts_cargo); j++) {
@@ -542,7 +564,7 @@
 			return;
 		}
 
-		DrawWindowViewport(this);
+		this->DrawViewport();
 	}
 
 	virtual void OnClick(Point pt, int widget)
@@ -657,7 +679,6 @@
 	WC_INDUSTRY_VIEW, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
 	_industry_view_widgets,
-	NULL
 };
 
 void ShowIndustryViewWindow(int industry)
@@ -675,7 +696,7 @@
 	IDW_SORTBYPROD,
 	IDW_SORTBYTRANSPORT,
 	IDW_SPACER,
-	IDW_INDUSRTY_LIST,
+	IDW_INDUSTRY_LIST,
 	IDW_SCROLLBAR,
 	IDW_RESIZE,
 };
@@ -696,12 +717,9 @@
 {   WIDGETS_END},
 };
 
-static uint _num_industry_sort;
-
 static char _bufcache[96];
 static const Industry* _last_industry;
-
-static byte _industry_sort_order;
+static int _internal_sort_order;
 
 static int CDECL GeneralIndustrySorter(const void *a, const void *b)
 {
@@ -709,7 +727,7 @@
 	const Industry* j = *(const Industry**)b;
 	int r;
 
-	switch (_industry_sort_order >> 1) {
+	switch (_internal_sort_order >> 1) {
 		default: NOT_REACHED();
 		case 0: /* Sort by Name (handled later) */
 			r = 0;
@@ -776,138 +794,171 @@
 		r = strcmp(buf1, _bufcache);
 	}
 
-	if (_industry_sort_order & 1) r = -r;
+	if (_internal_sort_order & 1) r = -r;
 	return r;
 }
 
+typedef GUIList<const Industry*> GUIIndustryList;
+
 /**
- * Makes a sorted industry list.
- * When there are no industries, the list has to be made. This so when one
- * starts a new game without industries after playing a game with industries
- * the list is not populated with invalid industries from the previous game.
+ * Rebuild industries list if the VL_REBUILD flag is set
+ *
+ * @param sl pointer to industry list
  */
-static void MakeSortedIndustryList()
+static void BuildIndustriesList(GUIIndustryList *sl)
 {
-	const Industry* i;
-	int n = 0;
+	uint n = 0;
+	const Industry *i;
+
+	if (!(sl->flags & VL_REBUILD)) return;
 
 	/* Create array for sorting */
-	_industry_sort = ReallocT(_industry_sort, GetMaxIndustryIndex() + 1);
+	const Industry **industry_sort = MallocT<const Industry*>(GetMaxIndustryIndex() + 1);
 
-	/* Don't attempt a sort if there are no industries */
-	if (GetNumIndustries() != 0) {
-		FOR_ALL_INDUSTRIES(i) _industry_sort[n++] = i;
-		qsort((void*)_industry_sort, n, sizeof(_industry_sort[0]), GeneralIndustrySorter);
-	}
+	DEBUG(misc, 3, "Building industry list");
 
-	_num_industry_sort = n;
-	_last_industry = NULL; // used for "cache"
+	FOR_ALL_INDUSTRIES(i) industry_sort[n++] = i;
 
-	DEBUG(misc, 3, "Resorting industries list");
+	free((void*)sl->sort_list);
+	sl->sort_list = MallocT<const Industry*>(n);
+	sl->list_length = n;
+
+	for (uint i = 0; i < n; ++i) sl->sort_list[i] = industry_sort[i];
+
+	sl->flags &= ~VL_REBUILD;
+	sl->flags |= VL_RESORT;
+	free((void*)industry_sort);
 }
 
 
-static void IndustryDirectoryWndProc(Window *w, WindowEvent *e)
+/**
+ * Sort industry list if the VL_RESORT flag is set
+ *
+ * @param sl pointer to industry list
+ */
+static void SortIndustriesList(GUIIndustryList *sl)
 {
-	switch (e->event) {
-		case WE_PAINT: {
-			if (_industry_sort_dirty) {
-				_industry_sort_dirty = false;
-				MakeSortedIndustryList();
+	if (!(sl->flags & VL_RESORT)) return;
+
+	_internal_sort_order = (sl->sort_type << 1) | (sl->flags & VL_DESC);
+	_last_industry = NULL; // used for "cache" in namesorting
+	qsort((void*)sl->sort_list, sl->list_length, sizeof(sl->sort_list[0]), &GeneralIndustrySorter);
+
+	sl->flags &= ~VL_RESORT;
+}
+
+/**
+ * The list of industries.
+ */
+struct IndustryDirectoryWindow : public Window, public GUIIndustryList {
+	static Listing industry_sort;
+
+	IndustryDirectoryWindow(const WindowDesc *desc, WindowNumber number) : Window(desc, number)
+	{
+		this->vscroll.cap = 16;
+		this->resize.height = this->height - 6 * 10; // minimum 10 items
+		this->resize.step_height = 10;
+		this->FindWindowPlacementAndResize(desc);
+
+		this->sort_list = NULL;
+		this->flags = VL_REBUILD;
+		this->sort_type = industry_sort.criteria;
+		if (industry_sort.order) this->flags |= VL_DESC;
+	}
+
+	virtual void OnPaint()
+	{
+		BuildIndustriesList(this);
+		SortIndustriesList(this);
+
+		SetVScrollCount(this, this->list_length);
+
+		this->DrawWidgets();
+		this->DrawSortButtonState(IDW_SORTBYNAME + this->sort_type, this->flags & VL_DESC ? SBS_DOWN : SBS_UP);
+
+		int max = min(this->vscroll.pos + this->vscroll.cap, this->list_length);
+		int y = 28; // start of the list-widget
+
+		for (int n = this->vscroll.pos; n < max; ++n) {
+			const Industry* i = this->sort_list[n];
+			const IndustrySpec *indsp = GetIndustrySpec(i->type);
+			byte p = 0;
+
+			/* Industry name */
+			SetDParam(p++, i->index);
+
+			/* Industry productions */
+			for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
+				if (i->produced_cargo[j] == CT_INVALID) continue;
+				SetDParam(p++, i->produced_cargo[j]);
+				SetDParam(p++, i->last_month_production[j]);
+				SetDParam(p++, GetCargoSuffix(j + 3, CST_DIR, (Industry*)i, i->type, indsp));
 			}
 
-			SetVScrollCount(w, _num_industry_sort);
-
-			DrawWindowWidgets(w);
-			DrawSortButtonState(w, IDW_SORTBYNAME + (_industry_sort_order >> 1), _industry_sort_order & 1 ? SBS_DOWN : SBS_UP);
-
-			uint pos = w->vscroll.pos;
-			int n = 0;
-
-			while (pos < _num_industry_sort) {
-				const Industry* i = _industry_sort[pos];
-				const IndustrySpec *indsp = GetIndustrySpec(i->type);
-				byte p = 0;
-
-				/* Industry name */
-				SetDParam(p++, i->index);
-
-				/* Industry productions */
-				for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
-					if (i->produced_cargo[j] == CT_INVALID) continue;
-					SetDParam(p++, i->produced_cargo[j]);
-					SetDParam(p++, i->last_month_production[j]);
-					SetDParam(p++, GetCargoSuffix(j + 3, CST_DIR, (Industry*)i, i->type, indsp));
-				}
-
-				/* Transported productions */
-				for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
-					if (i->produced_cargo[j] == CT_INVALID) continue;
-					SetDParam(p++, i->last_month_pct_transported[j] * 100 >> 8);
-				}
-
-				/* Drawing the right string */
-				StringID str = STR_INDUSTRYDIR_ITEM_NOPROD;
-				if (p != 1) str = (p == 5) ? STR_INDUSTRYDIR_ITEM : STR_INDUSTRYDIR_ITEM_TWO;
-				DrawStringTruncated(4, 28 + n * 10, str, TC_FROMSTRING, w->widget[IDW_INDUSRTY_LIST].right - 4);
-
-				pos++;
-				if (++n == w->vscroll.cap) break;
+			/* Transported productions */
+			for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
+				if (i->produced_cargo[j] == CT_INVALID) continue;
+				SetDParam(p++, i->last_month_pct_transported[j] * 100 >> 8);
 			}
-		} break;
 
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case IDW_SORTBYNAME: {
-					_industry_sort_order = _industry_sort_order == 0 ? 1 : 0;
-					_industry_sort_dirty = true;
-					w->SetDirty();
-				} break;
-
-				case IDW_SORTBYTYPE: {
-					_industry_sort_order = _industry_sort_order == 2 ? 3 : 2;
-					_industry_sort_dirty = true;
-					w->SetDirty();
-				} break;
-
-				case IDW_SORTBYPROD: {
-					_industry_sort_order = _industry_sort_order == 4 ? 5 : 4;
-					_industry_sort_dirty = true;
-					w->SetDirty();
-				} break;
-
-				case IDW_SORTBYTRANSPORT: {
-					_industry_sort_order = _industry_sort_order == 6 ? 7 : 6;
-					_industry_sort_dirty = true;
-					w->SetDirty();
-				} break;
+			/* Drawing the right string */
+			StringID str = STR_INDUSTRYDIR_ITEM_NOPROD;
+			if (p != 1) str = (p == 5) ? STR_INDUSTRYDIR_ITEM : STR_INDUSTRYDIR_ITEM_TWO;
+			DrawStringTruncated(4, y, str, TC_FROMSTRING, this->widget[IDW_INDUSTRY_LIST].right - 4);
 
-				case IDW_INDUSRTY_LIST: {
-					int y = (e->we.click.pt.y - 28) / 10;
-					uint16 p;
+			y += 10;
+		}
+	}
 
-					if (!IsInsideMM(y, 0, w->vscroll.cap)) return;
-					p = y + w->vscroll.pos;
-					if (p < _num_industry_sort) {
-						if (_ctrl_pressed) {
-							ShowExtraViewPortWindow(_industry_sort[p]->xy);
-						} else {
-							ScrollMainWindowToTile(_industry_sort[p]->xy);
-						}
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case IDW_SORTBYNAME:
+			case IDW_SORTBYTYPE:
+			case IDW_SORTBYPROD:
+			case IDW_SORTBYTRANSPORT:
+				if (this->sort_type == (widget - IDW_SORTBYNAME)) {
+					this->flags ^= VL_DESC;
+				} else {
+					this->sort_type = widget - IDW_SORTBYNAME;
+					this->flags &= ~VL_DESC;
+				}
+				industry_sort.criteria = this->sort_type;
+				industry_sort.order = HasBit(this->flags, 0);
+				this->flags |= VL_RESORT;
+				this->SetDirty();
+				break;
+
+			case IDW_INDUSTRY_LIST: {
+				int y = (pt.y - 28) / 10;
+				uint16 p;
+
+				if (!IsInsideMM(y, 0, this->vscroll.cap)) return;
+				p = y + this->vscroll.pos;
+				if (p < this->list_length) {
+					if (_ctrl_pressed) {
+						ShowExtraViewPortWindow(this->sort_list[p]->xy);
+					} else {
+						ScrollMainWindowToTile(this->sort_list[p]->xy);
 					}
-				} break;
-			}
-			break;
+				}
+			} break;
+		}
+	}
 
-		case WE_100_TICKS:
-			w->SetDirty();
-			break;
+	virtual void OnResize(Point new_size, Point delta)
+	{
+		this->vscroll.cap += delta.y / 10;
+	}
 
-		case WE_RESIZE:
-			w->vscroll.cap += e->we.sizing.diff.y / 10;
-			break;
+	virtual void OnInvalidateData(int data)
+	{
+		this->flags |= (data == 0 ? VL_REBUILD : VL_RESORT);
+		this->InvalidateWidget(IDW_INDUSTRY_LIST);
 	}
-}
+};
+
+Listing IndustryDirectoryWindow::industry_sort = {0, 0};
 
 /** Window definition of the industy directory gui */
 static const WindowDesc _industry_directory_desc = {
@@ -915,17 +966,9 @@
 	WC_INDUSTRY_DIRECTORY, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
 	_industry_directory_widgets,
-	IndustryDirectoryWndProc
 };
 
 void ShowIndustryDirectory()
 {
-	Window *w = AllocateWindowDescFront<Window>(&_industry_directory_desc, 0);
-
-	if (w != NULL) {
-		w->vscroll.cap = 16;
-		w->resize.height = w->height - 6 * 10; // minimum 10 items
-		w->resize.step_height = 10;
-		w->SetDirty();
-	}
+	AllocateWindowDescFront<IndustryDirectoryWindow>(&_industry_directory_desc, 0);
 }
--- a/src/intro_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/intro_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -53,87 +53,91 @@
 	InvalidateWindowClasses(WC_SELECT_GAME);
 }
 
-enum SelectGameIntroWidgets {
-	SGI_GENERATE_GAME = 2,
-	SGI_LOAD_GAME,
-	SGI_PLAY_SCENARIO,
-	SGI_PLAY_HEIGHTMAP,
-	SGI_EDIT_SCENARIO,
-	SGI_PLAY_NETWORK,
-	SGI_TEMPERATE_LANDSCAPE,
-	SGI_ARCTIC_LANDSCAPE,
-	SGI_TROPIC_LANDSCAPE,
-	SGI_TOYLAND_LANDSCAPE,
-	SGI_OPTIONS,
-	SGI_DIFFICULTIES,
-	SGI_PATCHES_OPTIONS,
-	SGI_GRF_SETTINGS,
-	SGI_EXIT,
-};
+struct SelectGameWindow : public Window {
+private:
+	enum SelectGameIntroWidgets {
+		SGI_GENERATE_GAME = 2,
+		SGI_LOAD_GAME,
+		SGI_PLAY_SCENARIO,
+		SGI_PLAY_HEIGHTMAP,
+		SGI_EDIT_SCENARIO,
+		SGI_PLAY_NETWORK,
+		SGI_TEMPERATE_LANDSCAPE,
+		SGI_ARCTIC_LANDSCAPE,
+		SGI_TROPIC_LANDSCAPE,
+		SGI_TOYLAND_LANDSCAPE,
+		SGI_OPTIONS,
+		SGI_DIFFICULTIES,
+		SGI_PATCHES_OPTIONS,
+		SGI_GRF_SETTINGS,
+		SGI_EXIT,
+	};
 
-static void SelectGameWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_CREATE: w->LowerWidget(_opt_newgame.landscape + 8); break;
+public:
+	SelectGameWindow(const WindowDesc *desc) : Window(desc)
+	{
+		this->LowerWidget(_opt_newgame.landscape + SGI_TEMPERATE_LANDSCAPE);
+		this->FindWindowPlacementAndResize(desc);
+	}
 
-		case WE_PAINT:
-			w->SetWidgetLoweredState(SGI_TEMPERATE_LANDSCAPE, _opt_newgame.landscape == LT_TEMPERATE);
-			w->SetWidgetLoweredState(SGI_ARCTIC_LANDSCAPE, _opt_newgame.landscape == LT_ARCTIC);
-			w->SetWidgetLoweredState(SGI_TROPIC_LANDSCAPE, _opt_newgame.landscape == LT_TROPIC);
-			w->SetWidgetLoweredState(SGI_TOYLAND_LANDSCAPE, _opt_newgame.landscape == LT_TOYLAND);
-			SetDParam(0, STR_6801_EASY + _opt_newgame.diff_level);
-			DrawWindowWidgets(w);
-			break;
+	virtual void OnPaint()
+	{
+		this->SetWidgetLoweredState(SGI_TEMPERATE_LANDSCAPE, _opt_newgame.landscape == LT_TEMPERATE);
+		this->SetWidgetLoweredState(SGI_ARCTIC_LANDSCAPE, _opt_newgame.landscape == LT_ARCTIC);
+		this->SetWidgetLoweredState(SGI_TROPIC_LANDSCAPE, _opt_newgame.landscape == LT_TROPIC);
+		this->SetWidgetLoweredState(SGI_TOYLAND_LANDSCAPE, _opt_newgame.landscape == LT_TOYLAND);
+		SetDParam(0, STR_6801_EASY + _opt_newgame.diff_level);
+		this->DrawWidgets();
+	}
 
-		case WE_CLICK:
+	virtual void OnClick(Point pt, int widget)
+	{
 #ifdef ENABLE_NETWORK
-			/* Do not create a network server when you (just) have closed one of the game
-			 * creation/load windows for the network server. */
-			if (SGI_GENERATE_GAME <= e->we.click.widget && e->we.click.widget <= SGI_EDIT_SCENARIO) _is_network_server = false;
+		/* Do not create a network server when you (just) have closed one of the game
+		 * creation/load windows for the network server. */
+		if (IsInsideMM(widget, SGI_GENERATE_GAME, SGI_EDIT_SCENARIO + 1)) _is_network_server = false;
 #endif /* ENABLE_NETWORK */
 
-			switch (e->we.click.widget) {
-				case SGI_GENERATE_GAME:  ShowGenerateLandscape(); break;
-				case SGI_LOAD_GAME:      ShowSaveLoadDialog(SLD_LOAD_GAME); break;
-				case SGI_PLAY_SCENARIO:  ShowSaveLoadDialog(SLD_LOAD_SCENARIO); break;
-				case SGI_PLAY_HEIGHTMAP: ShowSaveLoadDialog(SLD_LOAD_HEIGHTMAP); break;
-				case SGI_EDIT_SCENARIO:  StartScenarioEditor(); break;
-
-				case SGI_PLAY_NETWORK:
-					if (!_network_available) {
-						ShowErrorMessage(INVALID_STRING_ID, STR_NETWORK_ERR_NOTAVAILABLE, 0, 0);
-					} else {
-						ShowNetworkGameWindow();
-					}
-					break;
+		switch (widget) {
+			case SGI_GENERATE_GAME:  ShowGenerateLandscape(); break;
+			case SGI_LOAD_GAME:      ShowSaveLoadDialog(SLD_LOAD_GAME); break;
+			case SGI_PLAY_SCENARIO:  ShowSaveLoadDialog(SLD_LOAD_SCENARIO); break;
+			case SGI_PLAY_HEIGHTMAP: ShowSaveLoadDialog(SLD_LOAD_HEIGHTMAP); break;
+			case SGI_EDIT_SCENARIO:  StartScenarioEditor(); break;
 
-				case SGI_TEMPERATE_LANDSCAPE: case SGI_ARCTIC_LANDSCAPE:
-				case SGI_TROPIC_LANDSCAPE: case SGI_TOYLAND_LANDSCAPE:
-					w->RaiseWidget(_opt_newgame.landscape + SGI_TEMPERATE_LANDSCAPE);
-					SetNewLandscapeType(e->we.click.widget - SGI_TEMPERATE_LANDSCAPE);
-					break;
+			case SGI_PLAY_NETWORK:
+				if (!_network_available) {
+					ShowErrorMessage(INVALID_STRING_ID, STR_NETWORK_ERR_NOTAVAILABLE, 0, 0);
+				} else {
+					ShowNetworkGameWindow();
+				}
+				break;
 
-				case SGI_OPTIONS:         ShowGameOptions(); break;
-				case SGI_DIFFICULTIES:    ShowGameDifficulty(); break;
-				case SGI_PATCHES_OPTIONS: ShowPatchesSelection(); break;
-				case SGI_GRF_SETTINGS:    ShowNewGRFSettings(true, true, false, &_grfconfig_newgame); break;
-				case SGI_EXIT:            HandleExitGameRequest(); break;
-			}
-			break;
+			case SGI_TEMPERATE_LANDSCAPE: case SGI_ARCTIC_LANDSCAPE:
+			case SGI_TROPIC_LANDSCAPE: case SGI_TOYLAND_LANDSCAPE:
+				this->RaiseWidget(_opt_newgame.landscape + SGI_TEMPERATE_LANDSCAPE);
+				SetNewLandscapeType(widget - SGI_TEMPERATE_LANDSCAPE);
+				break;
+
+			case SGI_OPTIONS:         ShowGameOptions(); break;
+			case SGI_DIFFICULTIES:    ShowGameDifficulty(); break;
+			case SGI_PATCHES_OPTIONS: ShowPatchesSelection(); break;
+			case SGI_GRF_SETTINGS:    ShowNewGRFSettings(true, true, false, &_grfconfig_newgame); break;
+			case SGI_EXIT:            HandleExitGameRequest(); break;
+		}
 	}
-}
+};
 
 static const WindowDesc _select_game_desc = {
 	WDP_CENTER, WDP_CENTER, 336, 195, 336, 195,
 	WC_SELECT_GAME, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
 	_select_game_widgets,
-	SelectGameWndProc
 };
 
 void ShowSelectGameWindow()
 {
-	new Window(&_select_game_desc);
+	new SelectGameWindow(&_select_game_desc);
 }
 
 static void AskExitGameCallback(Window *w, bool confirmed)
--- a/src/main_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/main_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -29,6 +29,7 @@
 #include "player_gui.h"
 #include "settings_type.h"
 #include "toolbar_gui.h"
+#include "statusbar_gui.h"
 #include "ai/ai_gui.hpp"
 #include "variables.h"
 #include "tilehighlight_func.h"
@@ -215,188 +216,194 @@
 
 extern void UpdateAllStationVirtCoord();
 
-static void MainWindowWndProc(Window *w, WindowEvent *e)
+struct MainWindow : Window
 {
-	switch (e->event) {
-		case WE_PAINT:
-			DrawWindowViewport(w);
-			if (_game_mode == GM_MENU) {
-				int off_x = _screen.width / 2;
-
-				DrawSprite(SPR_OTTD_O, PAL_NONE, off_x - 120, 50);
-				DrawSprite(SPR_OTTD_P, PAL_NONE, off_x -  86, 50);
-				DrawSprite(SPR_OTTD_E, PAL_NONE, off_x -  53, 50);
-				DrawSprite(SPR_OTTD_N, PAL_NONE, off_x -  22, 50);
-
-				DrawSprite(SPR_OTTD_T, PAL_NONE, off_x +  34, 50);
-				DrawSprite(SPR_OTTD_T, PAL_NONE, off_x +  65, 50);
-				DrawSprite(SPR_OTTD_D, PAL_NONE, off_x +  96, 50);
-			}
-			break;
+	MainWindow(int width, int height) : Window(0, 0, width, height, WC_MAIN_WINDOW, NULL)
+	{
+		InitializeWindowViewport(this, 0, 0, width, height, TileXY(32, 32), ZOOM_LVL_VIEWPORT);
+	}
 
-		case WE_KEYPRESS:
-			switch (e->we.keypress.keycode) {
-				case 'Q' | WKC_CTRL:
-				case 'Q' | WKC_META:
-					HandleExitGameRequest();
-					break;
-			}
+	virtual void OnPaint()
+	{
+		this->DrawViewport();
+		if (_game_mode == GM_MENU) {
+			int off_x = _screen.width / 2;
 
-			/* Disable all key shortcuts, except quit shortcuts when
-			* generating the world, otherwise they create threading
-			* problem during the generating, resulting in random
-			* assertions that are hard to trigger and debug */
-			if (IsGeneratingWorld()) break;
+			DrawSprite(SPR_OTTD_O, PAL_NONE, off_x - 120, 50);
+			DrawSprite(SPR_OTTD_P, PAL_NONE, off_x -  86, 50);
+			DrawSprite(SPR_OTTD_E, PAL_NONE, off_x -  53, 50);
+			DrawSprite(SPR_OTTD_N, PAL_NONE, off_x -  22, 50);
 
-			if (e->we.keypress.keycode == WKC_BACKQUOTE) {
-				IConsoleSwitch();
-				e->we.keypress.cont = false;
-				break;
-			}
+			DrawSprite(SPR_OTTD_T, PAL_NONE, off_x +  34, 50);
+			DrawSprite(SPR_OTTD_T, PAL_NONE, off_x +  65, 50);
+			DrawSprite(SPR_OTTD_D, PAL_NONE, off_x +  96, 50);
+		}
+	}
 
-			if (e->we.keypress.keycode == ('B' | WKC_CTRL)) {
-				e->we.keypress.cont = false;
-				extern bool _draw_bounding_boxes;
-				_draw_bounding_boxes = !_draw_bounding_boxes;
-				MarkWholeScreenDirty();
+	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+	{
+		switch (keycode) {
+			case 'Q' | WKC_CTRL:
+			case 'Q' | WKC_META:
+				HandleExitGameRequest();
+				return ES_HANDLED;
+		}
+
+		/* Disable all key shortcuts, except quit shortcuts when
+		* generating the world, otherwise they create threading
+		* problem during the generating, resulting in random
+		* assertions that are hard to trigger and debug */
+		if (IsGeneratingWorld()) return ES_NOT_HANDLED;
+
+		if (keycode == WKC_BACKQUOTE) {
+			IConsoleSwitch();
+			return ES_HANDLED;
+		}
+
+		if (keycode == ('B' | WKC_CTRL)) {
+			extern bool _draw_bounding_boxes;
+			_draw_bounding_boxes = !_draw_bounding_boxes;
+			MarkWholeScreenDirty();
+			return ES_HANDLED;
+		}
+
+		if (_game_mode == GM_MENU) return ES_NOT_HANDLED;
+
+		switch (keycode) {
+			case 'C':
+			case 'Z': {
+				Point pt = GetTileBelowCursor();
+				if (pt.x != -1) {
+					if (keycode == 'Z') MaxZoomInOut(ZOOM_IN, this);
+					ScrollMainWindowTo(pt.x, pt.y);
+				}
 				break;
 			}
 
-			if (_game_mode == GM_MENU) break;
-
-			switch (e->we.keypress.keycode) {
-				case 'C':
-				case 'Z': {
-					Point pt = GetTileBelowCursor();
-					if (pt.x != -1) {
-						if (e->we.keypress.keycode == 'Z') MaxZoomInOut(ZOOM_IN, w);
-						ScrollMainWindowTo(pt.x, pt.y);
-					}
-					break;
-				}
-
-				case WKC_ESC: ResetObjectToPlace(); break;
-				case WKC_DELETE: DeleteNonVitalWindows(); break;
-				case WKC_DELETE | WKC_SHIFT: DeleteAllNonVitalWindows(); break;
-				case 'R' | WKC_CTRL: MarkWholeScreenDirty(); break;
+			case WKC_ESC: ResetObjectToPlace(); break;
+			case WKC_DELETE: DeleteNonVitalWindows(); break;
+			case WKC_DELETE | WKC_SHIFT: DeleteAllNonVitalWindows(); break;
+			case 'R' | WKC_CTRL: MarkWholeScreenDirty(); break;
 
 #if defined(_DEBUG)
-				case '0' | WKC_ALT: // Crash the game
-					*(byte*)0 = 0;
-					break;
+			case '0' | WKC_ALT: // Crash the game
+				*(byte*)0 = 0;
+				break;
 
-				case '1' | WKC_ALT: // Gimme money
-					/* Server can not cheat in advertise mode either! */
-					if (!_networking || !_network_server || !_network_advertise)
-						DoCommandP(0, 10000000, 0, NULL, CMD_MONEY_CHEAT);
-					break;
+			case '1' | WKC_ALT: // Gimme money
+				/* Server can not cheat in advertise mode either! */
+				if (!_networking || !_network_server || !_network_advertise)
+					DoCommandP(0, 10000000, 0, NULL, CMD_MONEY_CHEAT);
+				break;
 
-				case '2' | WKC_ALT: // Update the coordinates of all station signs
-					UpdateAllStationVirtCoord();
-					break;
+			case '2' | WKC_ALT: // Update the coordinates of all station signs
+				UpdateAllStationVirtCoord();
+				break;
 #endif
 
-				case '1' | WKC_CTRL:
-				case '2' | WKC_CTRL:
-				case '3' | WKC_CTRL:
-				case '4' | WKC_CTRL:
-				case '5' | WKC_CTRL:
-				case '6' | WKC_CTRL:
-				case '7' | WKC_CTRL:
-				case '8' | WKC_CTRL:
-				case '9' | WKC_CTRL:
-					/* Transparency toggle hot keys */
-					ToggleTransparency((TransparencyOption)(e->we.keypress.keycode - ('1' | WKC_CTRL)));
-					MarkWholeScreenDirty();
-					break;
+			case '1' | WKC_CTRL:
+			case '2' | WKC_CTRL:
+			case '3' | WKC_CTRL:
+			case '4' | WKC_CTRL:
+			case '5' | WKC_CTRL:
+			case '6' | WKC_CTRL:
+			case '7' | WKC_CTRL:
+			case '8' | WKC_CTRL:
+			case '9' | WKC_CTRL:
+				/* Transparency toggle hot keys */
+				ToggleTransparency((TransparencyOption)(keycode - ('1' | WKC_CTRL)));
+				MarkWholeScreenDirty();
+				break;
 
-				case '1' | WKC_CTRL | WKC_SHIFT:
-				case '2' | WKC_CTRL | WKC_SHIFT:
-				case '3' | WKC_CTRL | WKC_SHIFT:
-				case '4' | WKC_CTRL | WKC_SHIFT:
-				case '5' | WKC_CTRL | WKC_SHIFT:
-				case '6' | WKC_CTRL | WKC_SHIFT:
-				case '7' | WKC_CTRL | WKC_SHIFT:
-				case '8' | WKC_CTRL | WKC_SHIFT:
-					/* Invisibility toggle hot keys */
-					ToggleInvisibilityWithTransparency((TransparencyOption)(e->we.keypress.keycode - ('1' | WKC_CTRL | WKC_SHIFT)));
-					MarkWholeScreenDirty();
-					break;
+			case '1' | WKC_CTRL | WKC_SHIFT:
+			case '2' | WKC_CTRL | WKC_SHIFT:
+			case '3' | WKC_CTRL | WKC_SHIFT:
+			case '4' | WKC_CTRL | WKC_SHIFT:
+			case '5' | WKC_CTRL | WKC_SHIFT:
+			case '6' | WKC_CTRL | WKC_SHIFT:
+			case '7' | WKC_CTRL | WKC_SHIFT:
+			case '8' | WKC_CTRL | WKC_SHIFT:
+				/* Invisibility toggle hot keys */
+				ToggleInvisibilityWithTransparency((TransparencyOption)(keycode - ('1' | WKC_CTRL | WKC_SHIFT)));
+				MarkWholeScreenDirty();
+				break;
 
-				case 'X' | WKC_CTRL:
-					ShowTransparencyToolbar();
-					break;
+			case 'X' | WKC_CTRL:
+				ShowTransparencyToolbar();
+				break;
 
-				case 'X':
-					ResetRestoreAllTransparency();
-					break;
+			case 'X':
+				ResetRestoreAllTransparency();
+				break;
 
 #ifdef ENABLE_NETWORK
-				case WKC_RETURN: case 'T': // smart chat; send to team if any, otherwise to all
-					if (_networking) {
-						const NetworkClientInfo *cio = NetworkFindClientInfoFromIndex(_network_own_client_index);
-						bool teamchat = false;
-
-						if (cio == NULL) break;
+			case WKC_RETURN: case 'T': // smart chat; send to team if any, otherwise to all
+				if (_networking) {
+					const NetworkClientInfo *cio = NetworkFindClientInfoFromIndex(_network_own_client_index);
+					bool teamchat = false;
 
-						/* Only players actually playing can speak to team. Eg spectators cannot */
-						if (_patches.prefer_teamchat && IsValidPlayer(cio->client_playas)) {
-							const NetworkClientInfo *ci;
-							FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
-								if (ci->client_playas == cio->client_playas && ci != cio) {
-									teamchat = true;
-									break;
-								}
+					if (cio == NULL) break;
+
+					/* Only players actually playing can speak to team. Eg spectators cannot */
+					if (_patches.prefer_teamchat && IsValidPlayer(cio->client_playas)) {
+						const NetworkClientInfo *ci;
+						FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
+							if (ci->client_playas == cio->client_playas && ci != cio) {
+								teamchat = true;
+								break;
 							}
 						}
-
-						ShowNetworkChatQueryWindow(teamchat ? DESTTYPE_TEAM : DESTTYPE_BROADCAST, cio->client_playas);
 					}
-					break;
 
-				case WKC_SHIFT | WKC_RETURN: case WKC_SHIFT | 'T': // send text message to all players
-					if (_networking) ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0);
-					break;
+					ShowNetworkChatQueryWindow(teamchat ? DESTTYPE_TEAM : DESTTYPE_BROADCAST, cio->client_playas);
+				}
+				break;
 
-				case WKC_CTRL | WKC_RETURN: case WKC_CTRL | 'T': // send text to all team mates
-					if (_networking) {
-						const NetworkClientInfo *cio = NetworkFindClientInfoFromIndex(_network_own_client_index);
-						if (cio == NULL) break;
+			case WKC_SHIFT | WKC_RETURN: case WKC_SHIFT | 'T': // send text message to all players
+				if (_networking) ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0);
+				break;
 
-						ShowNetworkChatQueryWindow(DESTTYPE_TEAM, cio->client_playas);
-					}
-					break;
+			case WKC_CTRL | WKC_RETURN: case WKC_CTRL | 'T': // send text to all team mates
+				if (_networking) {
+					const NetworkClientInfo *cio = NetworkFindClientInfoFromIndex(_network_own_client_index);
+					if (cio == NULL) break;
+
+					ShowNetworkChatQueryWindow(DESTTYPE_TEAM, cio->client_playas);
+				}
+				break;
 #endif
 
-				default: return;
-			}
-			e->we.keypress.cont = false;
-			break;
-
-		case WE_SCROLL: {
-			ViewPort *vp = IsPtInWindowViewport(w, _cursor.pos.x, _cursor.pos.y);
-
-			if (vp == NULL) {
-				_cursor.fix_at = false;
-				_scrolling_viewport = false;
-			}
+			default: return ES_NOT_HANDLED;
+		}
+		return ES_HANDLED;
+	}
 
-			w->viewport->scrollpos_x += ScaleByZoom(e->we.scroll.delta.x, vp->zoom);
-			w->viewport->scrollpos_y += ScaleByZoom(e->we.scroll.delta.y, vp->zoom);
-			w->viewport->dest_scrollpos_x = w->viewport->scrollpos_x;
-			w->viewport->dest_scrollpos_y = w->viewport->scrollpos_y;
-		} break;
+	virtual void OnScroll(Point delta)
+	{
+		ViewPort *vp = IsPtInWindowViewport(this, _cursor.pos.x, _cursor.pos.y);
 
-		case WE_MOUSEWHEEL:
-			ZoomInOrOutToCursorWindow(e->we.wheel.wheel < 0, w);
-			break;
+		if (vp == NULL) {
+			_cursor.fix_at = false;
+			_scrolling_viewport = false;
+		}
 
-		case WE_INVALIDATE_DATA:
-			/* Forward the message to the appropiate toolbar (ingame or scenario editor) */
-			InvalidateWindowData(WC_MAIN_TOOLBAR, 0, e->we.invalidate.data);
-			break;
+		this->viewport->scrollpos_x += ScaleByZoom(delta.x, vp->zoom);
+		this->viewport->scrollpos_y += ScaleByZoom(delta.y, vp->zoom);
+		this->viewport->dest_scrollpos_x = this->viewport->scrollpos_x;
+		this->viewport->dest_scrollpos_y = this->viewport->scrollpos_y;
+	};
+
+	virtual void OnMouseWheel(int wheel)
+	{
+		ZoomInOrOutToCursorWindow(wheel < 0, this);
 	}
-}
+
+	virtual void OnInvalidateData(int data)
+	{
+		/* Forward the message to the appropiate toolbar (ingame or scenario editor) */
+		InvalidateWindowData(WC_MAIN_TOOLBAR, 0, data);
+	}
+};
 
 
 void ShowSelectGameWindow();
@@ -410,11 +417,7 @@
 		memcpy(_colour_gradient[i], b + 0xC6, sizeof(_colour_gradient[i]));
 	}
 
-	int width = _screen.width;
-	int height = _screen.height;
-
-	Window *w = new Window(0, 0, width, height, MainWindowWndProc, WC_MAIN_WINDOW, NULL);
-	InitializeWindowViewport(w, 0, 0, width, height, TileXY(32, 32), ZOOM_LVL_VIEWPORT);
+	new MainWindow(_screen.width, _screen.height);
 
 	/* XXX: these are not done */
 	switch (_game_mode) {
@@ -430,12 +433,9 @@
 	}
 }
 
-extern void ShowStatusBar();
-
 void ShowVitalWindows()
 {
-	Window *w = AllocateToolbar();
-	DoZoomInOutWindow(ZOOM_NONE, w);
+	AllocateToolbar();
 
 	/* Status bad only for normal games */
 	if (_game_mode == GM_EDITOR) return;
--- a/src/misc.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/misc.cpp	Mon May 19 15:13:58 2008 +0000
@@ -28,6 +28,7 @@
 #include "animated_tile_func.h"
 #include "settings_type.h"
 #include "tilehighlight_func.h"
+#include "core/bitmath_func.hpp"
 
 #include "table/strings.h"
 #include "table/sprites.h"
--- a/src/misc_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/misc_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -69,7 +69,6 @@
 	WC_LAND_INFO, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 	_land_info_widgets,
-	NULL
 };
 
 class LandInfoWindow : public Window {
@@ -83,7 +82,7 @@
 
 	virtual void OnPaint()
 	{
-		DrawWindowWidgets(this);
+		this->DrawWidgets();
 
 		DoDrawStringCentered(140, 16, this->landinfo_data[0], TC_LIGHT_BLUE);
 		DoDrawStringCentered(140, 27, this->landinfo_data[1], TC_FROMSTRING);
@@ -206,107 +205,6 @@
 	}
 }
 
-struct scroller_d {
-	int height;
-	uint16 counter;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(scroller_d));
-
-static const char *credits[] = {
-	/*************************************************************************
-	 *                      maximum length of string which fits in window   -^*/
-	"Original design by Chris Sawyer",
-	"Original graphics by Simon Foster",
-	"",
-	"The OpenTTD team (in alphabetical order):",
-	"  Jean-Francois Claeys (Belugas) - GUI, newindustries and more",
-	"  Bjarni Corfitzen (Bjarni) - MacOSX port, coder and vehicles",
-	"  Matthijs Kooijman (blathijs) - Pathfinder-guru, pool rework",
-	"  Loïc Guilloux (glx) - General coding",
-	"  Christoph Elsenhans (frosch) - General coding",
-	"  Jaroslav Mazanec (KUDr) - YAPG (Yet Another Pathfinder God) ;)",
-	"  Jonathan Coome (Maedhros) - High priest of the newGRF Temple",
-	"  Attila Bán (MiHaMiX) - WebTranslator, Nightlies, Wiki and bugtracker host",
-	"  Owen Rudge (orudge) - Forum host, OS/2 port",
-	"  Peter Nelson (peter1138) - Spiritual descendant from newGRF gods",
-	"  Remko Bijker (Rubidium) - Lead coder and way more",
-	"  Benedikt Brüggemeier (skidd13) - Bug fixer and code reworker",
-	"  Zdenek Sojka (SmatZ) - Bug finder and fixer",
-	"",
-	"Inactive Developers:",
-	"  Victor Fischer (Celestar) - Programming everywhere you need him to",
-	"  Tamás Faragó (Darkvater) - Ex-Lead coder",
-	"  Christoph Mallon (Tron) - Programmer, code correctness police",
-	"",
-	"Retired Developers:",
-	"  Ludvig Strigeus (ludde) - OpenTTD author, main coder (0.1 - 0.3.3)",
-	"  Serge Paquet (vurlix) - Assistant project manager, coder (0.1 - 0.3.3)",
-	"  Dominik Scherer (dominik81) - Lead programmer, GUI expert (0.3.0 - 0.3.6)",
-	"  Patric Stout (TrueLight) - Programmer, webhoster (0.3 - pre0.6)",
-	"",
-	"Special thanks go out to:",
-	"  Josef Drexler - For his great work on TTDPatch",
-	"  Marcin Grzegorczyk - For his documentation of TTD internals",
-	"  Petr Baudis (pasky) - Many patches, newGRF support",
-	"  Stefan Meißner (sign_de) - For his work on the console",
-	"  Simon Sasburg (HackyKid) - Many bugfixes he has blessed us with",
-	"  Cian Duffy (MYOB) - BeOS port / manual writing",
-	"  Christian Rosentreter (tokai) - MorphOS / AmigaOS port",
-	"  Richard Kempton (richK) - additional airports, initial TGP implementation",
-	"",
-	"  Michael Blunck - Pre-Signals and Semaphores © 2003",
-	"  George - Canal/Lock graphics © 2003-2004",
-	"  David Dallaston - Tram tracks",
-	"  Marcin Grzegorczyk - Foundations for Tracks on Slopes",
-	"  All Translators - Who made OpenTTD a truly international game",
-	"  Bug Reporters - Without whom OpenTTD would still be full of bugs!",
-	"",
-	"",
-	"And last but not least:",
-	"  Chris Sawyer - For an amazing game!"
-};
-
-static void AboutWindowProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_CREATE: // Set up window counter and start position of scroller
-			WP(w, scroller_d).counter = 5;
-			WP(w, scroller_d).height = w->height - 40;
-			break;
-
-		case WE_PAINT: {
-			int y = WP(w, scroller_d).height;
-			DrawWindowWidgets(w);
-
-			/* Show original copyright and revision version */
-			DrawStringCentered(210, 17, STR_00B6_ORIGINAL_COPYRIGHT, TC_FROMSTRING);
-			DrawStringCentered(210, 17 + 10, STR_00B7_VERSION, TC_FROMSTRING);
-
-			/* Show all scrolling credits */
-			for (uint i = 0; i < lengthof(credits); i++) {
-				if (y >= 50 && y < (w->height - 40)) {
-					DoDrawString(credits[i], 10, y, TC_BLACK);
-				}
-				y += 10;
-			}
-
-			/* If the last text has scrolled start anew from the start */
-			if (y < 50) WP(w, scroller_d).height = w->height - 40;
-
-			DoDrawStringCentered(210, w->height - 25, "Website: http://www.openttd.org", TC_BLACK);
-			DrawStringCentered(210, w->height - 15, STR_00BA_COPYRIGHT_OPENTTD, TC_FROMSTRING);
-		} break;
-
-		case WE_TICK: // Timer to scroll the text and adjust the new top
-			if (--WP(w, scroller_d).counter == 0) {
-				WP(w, scroller_d).counter = 5;
-				WP(w, scroller_d).height--;
-				w->SetDirty();
-			}
-			break;
-	}
-}
-
 static const Widget _about_widgets[] = {
 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,         STR_018B_CLOSE_WINDOW},
 {    WWT_CAPTION,   RESIZE_NONE,    14,    11,   419,     0,    13, STR_015B_OPENTTD, STR_NULL},
@@ -320,21 +218,114 @@
 	WC_GAME_OPTIONS, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 	_about_widgets,
-	AboutWindowProc
 };
 
+struct AboutWindow : public Window {
+	int scroll_height;
+	uint16 counter;
+
+	AboutWindow() : Window(&_about_desc)
+	{
+		this->counter = 5;
+		this->scroll_height = this->height - 40;
+		this->FindWindowPlacementAndResize(&_about_desc);
+	}
+
+	virtual void OnPaint()
+	{
+		static const char *credits[] = {
+			/*************************************************************************
+			 *                      maximum length of string which fits in window   -^*/
+			"Original design by Chris Sawyer",
+			"Original graphics by Simon Foster",
+			"",
+			"The OpenTTD team (in alphabetical order):",
+			"  Jean-Francois Claeys (Belugas) - GUI, newindustries and more",
+			"  Bjarni Corfitzen (Bjarni) - MacOSX port, coder and vehicles",
+			"  Matthijs Kooijman (blathijs) - Pathfinder-guru, pool rework",
+			"  Loïc Guilloux (glx) - General coding",
+			"  Christoph Elsenhans (frosch) - General coding",
+			"  Jaroslav Mazanec (KUDr) - YAPG (Yet Another Pathfinder God) ;)",
+			"  Jonathan Coome (Maedhros) - High priest of the newGRF Temple",
+			"  Attila Bán (MiHaMiX) - WebTranslator, Nightlies, Wiki and bugtracker host",
+			"  Owen Rudge (orudge) - Forum host, OS/2 port",
+			"  Peter Nelson (peter1138) - Spiritual descendant from newGRF gods",
+			"  Remko Bijker (Rubidium) - Lead coder and way more",
+			"  Benedikt Brüggemeier (skidd13) - Bug fixer and code reworker",
+			"  Zdenek Sojka (SmatZ) - Bug finder and fixer",
+			"",
+			"Inactive Developers:",
+			"  Victor Fischer (Celestar) - Programming everywhere you need him to",
+			"  Tamás Faragó (Darkvater) - Ex-Lead coder",
+			"  Christoph Mallon (Tron) - Programmer, code correctness police",
+			"",
+			"Retired Developers:",
+			"  Ludvig Strigeus (ludde) - OpenTTD author, main coder (0.1 - 0.3.3)",
+			"  Serge Paquet (vurlix) - Assistant project manager, coder (0.1 - 0.3.3)",
+			"  Dominik Scherer (dominik81) - Lead programmer, GUI expert (0.3.0 - 0.3.6)",
+			"  Patric Stout (TrueLight) - Programmer, webhoster (0.3 - pre0.6)",
+			"",
+			"Special thanks go out to:",
+			"  Josef Drexler - For his great work on TTDPatch",
+			"  Marcin Grzegorczyk - For his documentation of TTD internals",
+			"  Petr Baudis (pasky) - Many patches, newGRF support",
+			"  Stefan Meißner (sign_de) - For his work on the console",
+			"  Simon Sasburg (HackyKid) - Many bugfixes he has blessed us with",
+			"  Cian Duffy (MYOB) - BeOS port / manual writing",
+			"  Christian Rosentreter (tokai) - MorphOS / AmigaOS port",
+			"  Richard Kempton (richK) - additional airports, initial TGP implementation",
+			"",
+			"  Michael Blunck - Pre-Signals and Semaphores © 2003",
+			"  George - Canal/Lock graphics © 2003-2004",
+			"  David Dallaston - Tram tracks",
+			"  Marcin Grzegorczyk - Foundations for Tracks on Slopes",
+			"  All Translators - Who made OpenTTD a truly international game",
+			"  Bug Reporters - Without whom OpenTTD would still be full of bugs!",
+			"",
+			"",
+			"And last but not least:",
+			"  Chris Sawyer - For an amazing game!"
+		};
+
+		this->DrawWidgets();
+
+		/* Show original copyright and revision version */
+		DrawStringCentered(210, 17, STR_00B6_ORIGINAL_COPYRIGHT, TC_FROMSTRING);
+		DrawStringCentered(210, 17 + 10, STR_00B7_VERSION, TC_FROMSTRING);
+
+		int y = this->scroll_height;
+
+		/* Show all scrolling credits */
+		for (uint i = 0; i < lengthof(credits); i++) {
+			if (y >= 50 && y < (this->height - 40)) {
+				DoDrawString(credits[i], 10, y, TC_BLACK);
+			}
+			y += 10;
+		}
+
+		/* If the last text has scrolled start a new from the start */
+		if (y < 50) this->scroll_height = this->height - 40;
+
+		DoDrawStringCentered(210, this->height - 25, "Website: http://www.openttd.org", TC_BLACK);
+		DrawStringCentered(210, this->height - 15, STR_00BA_COPYRIGHT_OPENTTD, TC_FROMSTRING);
+	}
+
+	virtual void OnTick()
+	{
+		if (--this->counter == 0) {
+			this->counter = 5;
+			this->scroll_height--;
+			this->SetDirty();
+		}
+	}
+};
 
 void ShowAboutWindow()
 {
 	DeleteWindowById(WC_GAME_OPTIONS, 0);
-	new Window(&_about_desc);
+	new AboutWindow();
 }
 
-static uint64 _errmsg_decode_params[20];
-static StringID _errmsg_message_1, _errmsg_message_2;
-static uint _errmsg_duration;
-
-
 static const Widget _errmsg_widgets[] = {
 {   WWT_CLOSEBOX,   RESIZE_NONE,     4,     0,    10,     0,    13, STR_00C5,         STR_018B_CLOSE_WINDOW},
 {    WWT_CAPTION,   RESIZE_NONE,     4,    11,   239,     0,    13, STR_00B2_MESSAGE, STR_NULL},
@@ -349,96 +340,96 @@
 {   WIDGETS_END},
 };
 
-static void ErrmsgWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT:
-			CopyInDParam(0, _errmsg_decode_params, lengthof(_errmsg_decode_params));
-			DrawWindowWidgets(w);
-			CopyInDParam(0, _errmsg_decode_params, lengthof(_errmsg_decode_params));
-
-			/* If the error message comes from a NewGRF, we must use the text ref. stack reserved for error messages.
-			* If the message doesn't come from a NewGRF, it won't use the TTDP-style text ref. stack, so we won't hurt anything
-			*/
-			SwitchToErrorRefStack();
-			RewindTextRefStack();
-
-			if (!IsWindowOfPrototype(w, _errmsg_face_widgets)) {
-				DrawStringMultiCenter(
-					120,
-					(_errmsg_message_1 == INVALID_STRING_ID ? 25 : 15),
-					_errmsg_message_2,
-					w->width - 2);
-				if (_errmsg_message_1 != INVALID_STRING_ID) {
-					DrawStringMultiCenter(
-						120,
-						30,
-						_errmsg_message_1,
-						w->width - 2);
-				}
-			} else {
-				const Player *p = GetPlayer((PlayerID)GetDParamX(_errmsg_decode_params,2));
-				DrawPlayerFace(p->face, p->player_color, 2, 16);
+struct ErrmsgWindow : public Window {
+private:
+	uint duration;
+	uint64 decode_params[20];
+	StringID message_1;
+	StringID message_2;
+	bool show_player_face;
 
-				DrawStringMultiCenter(
-					214,
-					(_errmsg_message_1 == INVALID_STRING_ID ? 65 : 45),
-					_errmsg_message_2,
-					w->width - 2);
-				if (_errmsg_message_1 != INVALID_STRING_ID) {
-					DrawStringMultiCenter(
-						214,
-						90,
-						_errmsg_message_1,
-						w->width - 2);
-				}
-			}
-
-			/* Switch back to the normal text ref. stack for NewGRF texts */
-			SwitchToNormalRefStack();
-			break;
+public:
+	ErrmsgWindow(Point pt, int width, int height, StringID msg1, StringID msg2, const Widget *widget, bool show_player_face) :
+			Window(pt.x, pt.y, width, height, WC_ERRMSG, widget),
+			show_player_face(show_player_face)
+	{
+		this->duration = _patches.errmsg_duration;
+		CopyOutDParam(this->decode_params, 0, lengthof(this->decode_params));
+		this->message_1 = msg1;
+		this->message_2 = msg2;
+		this->desc_flags = WDF_STD_BTN | WDF_DEF_WIDGET;
+		this->FindWindowPlacementAndResize(width, height);
+	}
 
-		case WE_MOUSELOOP:
-			if (_right_button_down) delete w;
-			break;
-
-		case WE_100_TICKS:
-			if (--_errmsg_duration == 0) delete w;
-			break;
+	virtual void OnPaint()
+	{
+		static int y[][3] = {
+			{15, 25, 30}, // _errmsg_widgets
+			{45, 65, 90}, // _errmsg_face_widgets
+		};
 
-		case WE_DESTROY:
-			SetRedErrorSquare(0);
-			extern StringID _switch_mode_errorstr;
-			_switch_mode_errorstr = INVALID_STRING_ID;
-			break;
+		CopyInDParam(0, this->decode_params, lengthof(this->decode_params));
+		this->DrawWidgets();
+		CopyInDParam(0, this->decode_params, lengthof(this->decode_params));
 
-		case WE_KEYPRESS:
-			if (e->we.keypress.keycode == WKC_SPACE) {
-				/* Don't continue. */
-				e->we.keypress.cont = false;
-				delete w;
-			}
-			break;
+		/* If the error message comes from a NewGRF, we must use the text ref. stack reserved for error messages.
+		 * If the message doesn't come from a NewGRF, it won't use the TTDP-style text ref. stack, so we won't hurt anything
+		 */
+		SwitchToErrorRefStack();
+		RewindTextRefStack();
+
+		if (this->show_player_face) {
+			const Player *p = GetPlayer((PlayerID)GetDParamX(this->decode_params, 2));
+			DrawPlayerFace(p->face, p->player_color, 2, 16);
+		}
+
+		byte j = (this->message_1 == INVALID_STRING_ID) ? 1 : 0;
+		DrawStringMultiCenter(this->width - 120, y[this->show_player_face][j], this->message_2, this->width - 2);
+		if (j == 0) {
+			DrawStringMultiCenter(this->width - 120, y[this->show_player_face][2], this->message_1, this->width - 2);
+		}
+
+		/* Switch back to the normal text ref. stack for NewGRF texts */
+		SwitchToNormalRefStack();
 	}
-}
+
+	virtual void OnMouseLoop()
+	{
+		if (_right_button_down) delete this;
+	}
+
+	virtual void OnHundredthTick()
+	{
+		if (--this->duration == 0) delete this;
+	}
+
+	~ErrmsgWindow()
+	{
+		SetRedErrorSquare(0);
+		extern StringID _switch_mode_errorstr;
+		_switch_mode_errorstr = INVALID_STRING_ID;
+	}
+
+	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+	{
+		if (keycode != WKC_SPACE) return ES_NOT_HANDLED;
+		delete this;
+		return ES_HANDLED;
+	}
+};
 
 void ShowErrorMessage(StringID msg_1, StringID msg_2, int x, int y)
 {
 	DeleteWindowById(WC_ERRMSG, 0);
 
-	if (msg_2 == STR_NULL) msg_2 = STR_EMPTY;
+	if (!_patches.errmsg_duration) return;
 
-	_errmsg_message_1 = msg_1;
-	_errmsg_message_2 = msg_2;
-	CopyOutDParam(_errmsg_decode_params, 0, lengthof(_errmsg_decode_params));
-	_errmsg_duration = _patches.errmsg_duration;
-	if (!_errmsg_duration) return;
+	if (msg_2 == STR_NULL) msg_2 = STR_EMPTY;
 
 	Point pt;
 	const ViewPort *vp;
-	Window *w;
 
-	if (_errmsg_message_1 != STR_013B_OWNED_BY || GetDParamX(_errmsg_decode_params,2) >= 8) {
+	if (msg_1 != STR_013B_OWNED_BY || GetDParam(2) >= 8) {
 		if ((x | y) != 0) {
 			pt = RemapCoords2(x, y);
 			vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
@@ -455,7 +446,7 @@
 			pt.x = (_screen.width - 240) >> 1;
 			pt.y = (_screen.height - 46) >> 1;
 		}
-		w = new Window(pt.x, pt.y, 240, 46, ErrmsgWndProc, WC_ERRMSG, _errmsg_widgets);
+		new ErrmsgWindow(pt, 240, 46, msg_1, msg_2, _errmsg_widgets, false);
 	} else {
 		if ((x | y) != 0) {
 			pt = RemapCoords2(x, y);
@@ -466,13 +457,10 @@
 			pt.x = (_screen.width - 334) >> 1;
 			pt.y = (_screen.height - 137) >> 1;
 		}
-		w = new Window(pt.x, pt.y, 334, 137, ErrmsgWndProc, WC_ERRMSG, _errmsg_face_widgets);
+		new ErrmsgWindow(pt, 334, 137, msg_1, msg_2, _errmsg_face_widgets, true);
 	}
-
-	w->desc_flags = WDF_STD_BTN | WDF_DEF_WIDGET;
 }
 
-
 void ShowEstimatedCostOrIncome(Money cost, int x, int y)
 {
 	StringID msg = STR_0805_ESTIMATED_COST;
@@ -542,7 +530,7 @@
 
 	TooltipsWindow(int x, int y, int width, int height, const Widget *widget,
 								 StringID str, uint paramcount, const uint64 params[]) :
-			Window(x, y, width, height, NULL, WC_TOOLTIPS, widget)
+			Window(x, y, width, height, WC_TOOLTIPS, widget)
 	{
 		this->string_id = str;
 		assert(sizeof(this->params[0]) == sizeof(params[0]));
@@ -893,9 +881,9 @@
 	return false;
 }
 
-int QueryString::HandleEditBoxKey(Window *w, int wid, uint16 key, uint16 keycode, bool &cont)
+int QueryString::HandleEditBoxKey(Window *w, int wid, uint16 key, uint16 keycode, Window::EventState &state)
 {
-	cont = false;
+	state = Window::ES_HANDLED;
 
 	switch (keycode) {
 		case WKC_ESC: return 2;
@@ -923,7 +911,7 @@
 			if (IsValidChar(key, this->afilter)) {
 				if (InsertTextBufferChar(&this->text, key)) w->InvalidateWidget(wid);
 			} else { // key wasn't caught. Continue only if standard entry specified
-				cont = (this->afilter == CS_ALPHANUMERAL);
+				state = (this->afilter == CS_ALPHANUMERAL) ? Window::ES_HANDLED : Window::ES_NOT_HANDLED;
 			}
 	}
 
@@ -973,9 +961,9 @@
 	_cur_dpi = old_dpi;
 }
 
-int QueryStringBaseWindow::HandleEditBoxKey(int wid, uint16 key, uint16 keycode, bool &cont)
+int QueryStringBaseWindow::HandleEditBoxKey(int wid, uint16 key, uint16 keycode, EventState &state)
 {
-	return this->QueryString::HandleEditBoxKey(this, wid, key, keycode, cont);
+	return this->QueryString::HandleEditBoxKey(this, wid, key, keycode, state);
 }
 
 void QueryStringBaseWindow::HandleEditBox(int wid)
@@ -997,10 +985,9 @@
 
 struct QueryStringWindow : public QueryStringBaseWindow
 {
-	Window *parent;
-
-	QueryStringWindow(const WindowDesc *desc, Window *parent) : QueryStringBaseWindow(desc), parent(parent)
+	QueryStringWindow(const WindowDesc *desc, Window *parent) : QueryStringBaseWindow(desc)
 	{
+		this->parent = parent;
 		SetBit(_no_scroll, SCROLL_EDIT);
 
 		this->FindWindowPlacementAndResize(desc);
@@ -1009,7 +996,7 @@
 	virtual void OnPaint()
 	{
 		SetDParam(0, this->caption);
-		DrawWindowWidgets(this);
+		this->DrawWidgets();
 
 		this->DrawEditBox(QUERY_STR_WIDGET_TEXT);
 	}
@@ -1024,6 +1011,7 @@
 			} else {
 				HandleOnEditText(this->text.buf);
 			}
+			this->handled = true;
 		}
 	}
 
@@ -1048,15 +1036,15 @@
 		this->HandleEditBox(QUERY_STR_WIDGET_TEXT);
 	}
 
-	virtual bool OnKeyPress(uint16 key, uint16 keycode)
+	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
 	{
-		bool cont;
-		switch (this->HandleEditBoxKey(QUERY_STR_WIDGET_TEXT, key, keycode, cont)) {
+		EventState state;
+		switch (this->HandleEditBoxKey(QUERY_STR_WIDGET_TEXT, key, keycode, state)) {
 			case 1: this->OnOk(); // Enter pressed, confirms change
 			/* FALL THROUGH */
 			case 2: delete this; break; // ESC pressed, closes window, abandons changes
 		}
-		return cont;
+		return state;
 	}
 
 	~QueryStringWindow()
@@ -1084,17 +1072,16 @@
 	WC_QUERY_STRING, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 	_query_string_widgets,
-	NULL
 };
 
 /** Show a query popup window with a textbox in it.
  * @param str StringID for the text shown in the textbox
  * @param caption StringID of text shown in caption of querywindow
  * @param maxlen maximum length in characters allowed. If bit 12 is set we
- * will not check the resulting string against to original string to return success
+ *               will not check the resulting string against to original string to return success
  * @param maxwidth maximum width in pixels allowed
  * @param parent pointer to a Window that will handle the events (ok/cancel) of this
- * window. If NULL, results are handled by global function HandleOnEditText
+ *        window. If NULL, results are handled by global function HandleOnEditText
  * @param afilter filters out unwanted character input */
 void ShowQueryString(StringID str, StringID caption, uint maxlen, uint maxwidth, Window *parent, CharSetFilter afilter)
 {
@@ -1163,7 +1150,7 @@
 	virtual void OnPaint()
 	{
 		CopyInDParam(0, this->params, lengthof(this->params));
-		DrawWindowWidgets(this);
+		this->DrawWidgets();
 		CopyInDParam(0, this->params, lengthof(this->params));
 
 		DrawStringMultiCenter(this->width / 2, (this->height / 2) - 10, this->message, this->width - 2);
@@ -1184,7 +1171,7 @@
 		}
 	}
 
-	virtual bool OnKeyPress(uint16 key, uint16 keycode)
+	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
 	{
 		/* ESC closes the window, Enter confirms the action */
 		switch (keycode) {
@@ -1197,9 +1184,9 @@
 				/* Fallthrough */
 			case WKC_ESC:
 				delete this;
-				return false;
+				return ES_HANDLED;
 		}
-		return true;
+		return ES_NOT_HANDLED;
 	}
 };
 
@@ -1218,7 +1205,6 @@
 	WC_CONFIRM_POPUP_QUERY, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_UNCLICK_BUTTONS | WDF_DEF_WIDGET | WDF_MODAL,
 	_query_widgets,
-	NULL
 };
 
 /** Show a modal confirmation window with standard 'yes' and 'no' buttons
@@ -1429,7 +1415,7 @@
 		int y;
 
 		SetVScrollCount(this, _fios_num);
-		DrawWindowWidgets(this);
+		this->DrawWidgets();
 		DrawFiosTexts(this->width);
 
 		if (_savegame_sort_dirty) {
@@ -1438,7 +1424,7 @@
 		}
 
 		GfxFillRect(this->widget[7].left + 1, this->widget[7].top + 1, this->widget[7].right, this->widget[7].bottom, 0xD7);
-		DrawSortButtonState(this, _savegame_sort_order & SORT_BY_NAME ? 2 : 3, _savegame_sort_order & SORT_DESCENDING ? SBS_DOWN : SBS_UP);
+		this->DrawSortButtonState(_savegame_sort_order & SORT_BY_NAME ? 2 : 3, _savegame_sort_order & SORT_DESCENDING ? SBS_DOWN : SBS_UP);
 
 		y = this->widget[7].top + 1;
 		for (pos = this->vscroll.pos; pos < _fios_num; pos++) {
@@ -1533,20 +1519,20 @@
 		}
 	}
 
-	virtual bool OnKeyPress(uint16 key, uint16 keycode)
+	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
 	{
 		if (keycode == WKC_ESC) {
 			delete this;
-			return false;
+			return ES_HANDLED;
 		}
 
-		bool cont = true;
+		EventState state = ES_NOT_HANDLED;
 		if ((_saveload_mode == SLD_SAVE_GAME || _saveload_mode == SLD_SAVE_SCENARIO) &&
-				this->HandleEditBoxKey(10, key, keycode, cont) == 1) { // Press Enter
+				this->HandleEditBoxKey(10, key, keycode, state) == 1) { // Press Enter
 			this->HandleButtonClick(12);
 		}
 
-		return cont;
+		return state;
 	}
 
 	virtual void OnTimeout()
@@ -1599,7 +1585,6 @@
 	WC_SAVELOAD, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_STD_BTN | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
 	_load_dialog_widgets,
-	NULL,
 };
 
 static const WindowDesc _save_dialog_desc = {
@@ -1607,7 +1592,6 @@
 	WC_SAVELOAD, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_STD_BTN | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
 	_save_dialog_widgets,
-	NULL,
 };
 
 /** These values are used to convert the file/operations mode into a corresponding file type.
--- a/src/music/dmusic.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/music/dmusic.cpp	Mon May 19 15:13:58 2008 +0000
@@ -5,6 +5,9 @@
 #ifdef WIN32_ENABLE_DIRECTMUSIC_SUPPORT
 
 #include "../stdafx.h"
+#ifdef WIN32_LEAN_AND_MEAN
+	#undef WIN32_LEAN_AND_MEAN // Don't exclude rarely-used stuff from Windows headers
+#endif
 #include "../debug.h"
 #include "../win32.h"
 #include "dmusic.h"
--- a/src/music_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/music_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -193,18 +193,40 @@
 	}
 }
 
-static void MusicTrackSelectionWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
+struct MusicTrackSelectionWindow : public Window {
+private:
+	enum MusicTrackSelectionWidgets {
+		MTSW_CLOSE,
+		MTSW_CAPTION,
+		MTSW_BACKGROUND,
+		MTSW_LIST_LEFT,
+		MTSW_LIST_RIGHT,
+		MTSW_ALL,
+		MTSW_OLD,
+		MTSW_NEW,
+		MTSW_EZY,
+		MTSW_CUSTOM1,
+		MTSW_CUSTOM2,
+		MTSW_CLEAR,
+		MTSW_SAVE,
+	};
+
+public:
+	MusicTrackSelectionWindow(const WindowDesc *desc, WindowNumber number) : Window(desc, number)
+	{
+		this->FindWindowPlacementAndResize(desc);
+	}
+
+	virtual void OnPaint()
+	{
 		const byte* p;
 		uint i;
 		int y;
 
-		w->SetWidgetDisabledState(11, msf.playlist <= 3);
-		w->LowerWidget(3);
-		w->LowerWidget(4);
-		DrawWindowWidgets(w);
+		this->SetWidgetDisabledState(MTSW_CLEAR, msf.playlist <= 3);
+		this->LowerWidget(MTSW_LIST_LEFT);
+		this->LowerWidget(MTSW_LIST_RIGHT);
+		this->DrawWidgets();
 
 		GfxFillRect(3, 23, 3 + 177, 23 + 191, 0);
 		GfxFillRect(251, 23, 251 + 177, 23 + 191, 0);
@@ -238,88 +260,88 @@
 			DrawString(252, y, (i < 10) ? STR_01EC_0 : STR_01ED, TC_FROMSTRING);
 			y += 6;
 		}
-		break;
 	}
 
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-		case 3: { // add to playlist
-			int y = (e->we.click.pt.y - 23) / 6;
-			uint i;
-			byte *p;
-
-			if (msf.playlist < 4) return;
-			if (!IsInsideMM(y, 0, NUM_SONGS_AVAILABLE)) return;
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case MTSW_LIST_LEFT: { // add to playlist
+				int y = (pt.y - 23) / 6;
+				uint i;
+				byte *p;
 
-			p = _playlists[msf.playlist];
-			for (i = 0; i != NUM_SONGS_PLAYLIST - 1; i++) {
-				if (p[i] == 0) {
-					p[i] = y + 1;
-					p[i + 1] = 0;
-					w->SetDirty();
-					SelectSongToPlay();
-					break;
+				if (msf.playlist < 4) return;
+				if (!IsInsideMM(y, 0, NUM_SONGS_AVAILABLE)) return;
+
+				p = _playlists[msf.playlist];
+				for (i = 0; i != NUM_SONGS_PLAYLIST - 1; i++) {
+					if (p[i] == 0) {
+						p[i] = y + 1;
+						p[i + 1] = 0;
+						this->SetDirty();
+						SelectSongToPlay();
+						break;
+					}
 				}
-			}
-		} break;
+			} break;
 
-		case 4: { // remove from playlist
-			int y = (e->we.click.pt.y - 23) / 6;
-			uint i;
-			byte *p;
+			case MTSW_LIST_RIGHT: { // remove from playlist
+				int y = (pt.y - 23) / 6;
+				uint i;
+				byte *p;
 
-			if (msf.playlist < 4) return;
-			if (!IsInsideMM(y, 0, NUM_SONGS_AVAILABLE)) return;
+				if (msf.playlist < 4) return;
+				if (!IsInsideMM(y, 0, NUM_SONGS_AVAILABLE)) return;
 
-			p = _playlists[msf.playlist];
-			for (i = y; i != NUM_SONGS_PLAYLIST - 1; i++) {
-				p[i] = p[i + 1];
+				p = _playlists[msf.playlist];
+				for (i = y; i != NUM_SONGS_PLAYLIST - 1; i++) {
+					p[i] = p[i + 1];
 				}
 
-			w->SetDirty();
-			SelectSongToPlay();
-		} break;
+				this->SetDirty();
+				SelectSongToPlay();
+			} break;
 
-		case 11: // clear
-			_playlists[msf.playlist][0] = 0;
-			w->SetDirty();
-			StopMusic();
-			SelectSongToPlay();
-			break;
+			case MTSW_CLEAR: // clear
+				_playlists[msf.playlist][0] = 0;
+				this->SetDirty();
+				StopMusic();
+				SelectSongToPlay();
+				break;
 
 #if 0
-		case 12: // save
-			ShowInfo("MusicTrackSelectionWndProc:save not implemented");
-			break;
+			case MTSW_SAVE: // save
+				ShowInfo("MusicTrackSelectionWndProc:save not implemented");
+				break;
 #endif
 
-		case 5: case 6: case 7: case 8: case 9: case 10: /* set playlist */
-			msf.playlist = e->we.click.widget - 5;
-			w->SetDirty();
-			InvalidateWindow(WC_MUSIC_WINDOW, 0);
-			StopMusic();
-			SelectSongToPlay();
-			break;
+			case MTSW_ALL: case MTSW_OLD: case MTSW_NEW:
+			case MTSW_EZY: case MTSW_CUSTOM1: case MTSW_CUSTOM2: // set playlist
+				msf.playlist = widget - MTSW_ALL;
+				this->SetDirty();
+				InvalidateWindow(WC_MUSIC_WINDOW, 0);
+				StopMusic();
+				SelectSongToPlay();
+				break;
 		}
-		break;
 	}
-}
+};
 
 static const Widget _music_track_selection_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                         STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   431,     0,    13, STR_01EB_MUSIC_PROGRAM_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   431,    14,   217, 0x0,                              STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,     2,   181,    22,   215, 0x0,                              STR_01FA_CLICK_ON_MUSIC_TRACK_TO},
-{      WWT_PANEL,   RESIZE_NONE,    14,   250,   429,    22,   215, 0x0,                              STR_CLICK_ON_TRACK_TO_REMOVE},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,    44,    51, 0x0,                              STR_01F3_SELECT_ALL_TRACKS_PROGRAM},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,    52,    59, 0x0,                              STR_01F4_SELECT_OLD_STYLE_MUSIC},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,    60,    67, 0x0,                              STR_01F5_SELECT_NEW_STYLE_MUSIC},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,    68,    75, 0x0,                              STR_0330_SELECT_EZY_STREET_STYLE},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,    76,    83, 0x0,                              STR_01F6_SELECT_CUSTOM_1_USER_DEFINED},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,    84,    91, 0x0,                              STR_01F7_SELECT_CUSTOM_2_USER_DEFINED},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,   108,   115, 0x0,                              STR_01F8_CLEAR_CURRENT_PROGRAM_CUSTOM1},
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                         STR_018B_CLOSE_WINDOW},                  // MTSW_CLOSE
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   431,     0,    13, STR_01EB_MUSIC_PROGRAM_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS},        // MTSW_CAPTION
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   431,    14,   217, 0x0,                              STR_NULL},                               // MTSW_BACKGROUND
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,   181,    22,   215, 0x0,                              STR_01FA_CLICK_ON_MUSIC_TRACK_TO},       // MTSW_LIST_LEFT
+{      WWT_PANEL,   RESIZE_NONE,    14,   250,   429,    22,   215, 0x0,                              STR_CLICK_ON_TRACK_TO_REMOVE},           // MTSW_LIST_RIGHT
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,    44,    51, 0x0,                              STR_01F3_SELECT_ALL_TRACKS_PROGRAM},     // MTSW_ALL
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,    52,    59, 0x0,                              STR_01F4_SELECT_OLD_STYLE_MUSIC},        // MTSW_OLD
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,    60,    67, 0x0,                              STR_01F5_SELECT_NEW_STYLE_MUSIC},        // MTSW_NEW
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,    68,    75, 0x0,                              STR_0330_SELECT_EZY_STREET_STYLE},       // MTSW_EZY
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,    76,    83, 0x0,                              STR_01F6_SELECT_CUSTOM_1_USER_DEFINED},  // MTSW_CUSTOM1
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,    84,    91, 0x0,                              STR_01F7_SELECT_CUSTOM_2_USER_DEFINED},  // MTSW_CUSTOM2
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,   108,   115, 0x0,                              STR_01F8_CLEAR_CURRENT_PROGRAM_CUSTOM1}, // MTSW_CLEAR
 #if 0
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,   124,   131, 0x0,                              STR_01F9_SAVE_MUSIC_SETTINGS},
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   186,   245,   124,   131, 0x0,                              STR_01F9_SAVE_MUSIC_SETTINGS},           // MTSW_SAVE
 #endif
 {   WIDGETS_END},
 };
@@ -329,24 +351,50 @@
 	WC_MUSIC_TRACK_SELECTION, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
 	_music_track_selection_widgets,
-	MusicTrackSelectionWndProc
 };
 
 static void ShowMusicTrackSelection()
 {
-	AllocateWindowDescFront<Window>(&_music_track_selection_desc, 0);
+	AllocateWindowDescFront<MusicTrackSelectionWindow>(&_music_track_selection_desc, 0);
 }
 
-static void MusicWindowWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
+struct MusicWindow : public Window {
+private:
+	enum MusicWidgets {
+		MW_CLOSE,
+		MW_CAPTION,
+		MW_PREV,
+		MW_NEXT,
+		MW_STOP,
+		MW_PLAY,
+		MW_SLIDERS,
+		MW_GAUGE,
+		MW_BACKGROUND,
+		MW_INFO,
+		MW_SHUFFLE,
+		MW_PROGRAMME,
+		MW_ALL,
+		MW_OLD,
+		MW_NEW,
+		MW_EZY,
+		MW_CUSTOM1,
+		MW_CUSTOM2,
+	};
+
+public:
+	MusicWindow(const WindowDesc *desc, WindowNumber number) : Window(desc, number)
+	{
+		this->FindWindowPlacementAndResize(desc);
+	}
+
+	virtual void OnPaint()
+	{
 		uint i;
 		StringID str;
 
-		w->RaiseWidget(7);
-		w->RaiseWidget(9);
-		DrawWindowWidgets(w);
+		this->RaiseWidget(MW_GAUGE);
+		this->RaiseWidget(MW_INFO);
+		this->DrawWidgets();
 
 		GfxFillRect(187, 16, 200, 33, 0);
 
@@ -403,92 +451,99 @@
 		DrawFrameRect(
 			214 + msf.effect_vol / 2, 22, 217 + msf.effect_vol / 2, 28, 14, FR_NONE
 		);
-	} break;
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-		case 2: // skip to prev
-			if (!_song_is_active)
-				return;
-			SkipToPrevSong();
-			break;
-		case 3: // skip to next
-			if (!_song_is_active)
-				return;
-			SkipToNextSong();
-			break;
-		case 4: // stop playing
-			msf.playing = false;
-			break;
-		case 5: // start playing
-			msf.playing = true;
-			break;
-		case 6: { // volume sliders
-			byte *vol, new_vol;
-			int x = e->we.click.pt.x - 88;
-
-			if (x < 0) return;
-
-			vol = &msf.music_vol;
-			if (x >= 106) {
-				vol = &msf.effect_vol;
-				x -= 106;
-			}
-
-			new_vol = min(max(x - 21, 0) * 2, 127);
-			if (new_vol != *vol) {
-				*vol = new_vol;
-				if (vol == &msf.music_vol)
-					MusicVolumeChanged(new_vol);
-				w->SetDirty();
-			}
-
-			_left_button_clicked = false;
-		} break;
-		case 10: //toggle shuffle
-			msf.shuffle ^= 1;
-			StopMusic();
-			SelectSongToPlay();
-			break;
-		case 11: //show track selection
-			ShowMusicTrackSelection();
-			break;
-		case 12: case 13: case 14: case 15: case 16: case 17: // playlist
-			msf.playlist = e->we.click.widget - 12;
-			w->SetDirty();
-			InvalidateWindow(WC_MUSIC_TRACK_SELECTION, 0);
-			StopMusic();
-			SelectSongToPlay();
-			break;
-		}
-		break;
-
-	case WE_TICK:
-		InvalidateWindowWidget(WC_MUSIC_WINDOW, 0, 7);
-		break;
 	}
 
-}
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case MW_PREV: // skip to prev
+				if (!_song_is_active) return;
+				SkipToPrevSong();
+				break;
+
+			case MW_NEXT: // skip to next
+				if (!_song_is_active) return;
+				SkipToNextSong();
+				break;
+
+			case MW_STOP: // stop playing
+				msf.playing = false;
+				break;
+
+			case MW_PLAY: // start playing
+				msf.playing = true;
+				break;
+
+			case MW_SLIDERS: { // volume sliders
+				byte *vol, new_vol;
+				int x = pt.x - 88;
+
+				if (x < 0) return;
+
+				vol = &msf.music_vol;
+				if (x >= 106) {
+					vol = &msf.effect_vol;
+					x -= 106;
+				}
+
+				new_vol = min(max(x - 21, 0) * 2, 127);
+				if (new_vol != *vol) {
+					*vol = new_vol;
+					if (vol == &msf.music_vol) MusicVolumeChanged(new_vol);
+					this->SetDirty();
+				}
+
+				_left_button_clicked = false;
+			} break;
+
+			case MW_SHUFFLE: //toggle shuffle
+				msf.shuffle ^= 1;
+				StopMusic();
+				SelectSongToPlay();
+				break;
+
+			case MW_PROGRAMME: //show track selection
+				ShowMusicTrackSelection();
+				break;
+
+			case MW_ALL: case MW_OLD: case MW_NEW:
+			case MW_EZY: case MW_CUSTOM1: case MW_CUSTOM2: // playlist
+				msf.playlist = widget - MW_ALL;
+				this->SetDirty();
+				InvalidateWindow(WC_MUSIC_TRACK_SELECTION, 0);
+				StopMusic();
+				SelectSongToPlay();
+				break;
+		}
+	}
+
+#if 0
+	virtual void OnTick()
+	{
+		this->InvalidateWidget(MW_GAUGE);
+	}
+#endif
+};
 
 static const Widget _music_window_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   299,     0,    13, STR_01D2_JAZZ_JUKEBOX, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,    14,     0,    21,    14,    35, SPR_IMG_SKIP_TO_PREV,  STR_01DE_SKIP_TO_PREVIOUS_TRACK},
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    22,    43,    14,    35, SPR_IMG_SKIP_TO_NEXT,  STR_01DF_SKIP_TO_NEXT_TRACK_IN_SELECTION},
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    44,    65,    14,    35, SPR_IMG_STOP_MUSIC,    STR_01E0_STOP_PLAYING_MUSIC},
-{ WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    66,    87,    14,    35, SPR_IMG_PLAY_MUSIC,    STR_01E1_START_PLAYING_MUSIC},
-{      WWT_PANEL,   RESIZE_NONE,    14,    88,   299,    14,    35, 0x0,                   STR_01E2_DRAG_SLIDERS_TO_SET_MUSIC},
-{      WWT_PANEL,   RESIZE_NONE,    14,   186,   201,    15,    34, 0x0,                   STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,     0,   299,    36,    57, 0x0,                   STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,    59,   240,    45,    53, 0x0,                   STR_NULL},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,     6,    55,    42,    49, 0x0,                   STR_01FB_TOGGLE_PROGRAM_SHUFFLE},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   244,   293,    42,    49, 0x0,                   STR_01FC_SHOW_MUSIC_TRACK_SELECTION},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,     0,    49,    58,    65, 0x0,                   STR_01F3_SELECT_ALL_TRACKS_PROGRAM},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,    50,    99,    58,    65, 0x0,                   STR_01F4_SELECT_OLD_STYLE_MUSIC},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   100,   149,    58,    65, 0x0,                   STR_01F5_SELECT_NEW_STYLE_MUSIC},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   150,   199,    58,    65, 0x0,                   STR_0330_SELECT_EZY_STREET_STYLE},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   200,   249,    58,    65, 0x0,                   STR_01F6_SELECT_CUSTOM_1_USER_DEFINED},
-{    WWT_PUSHBTN,   RESIZE_NONE,    14,   250,   299,    58,    65, 0x0,                   STR_01F7_SELECT_CUSTOM_2_USER_DEFINED},
+{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},                    // MW_CLOSE
+{    WWT_CAPTION,   RESIZE_NONE,    14,    11,   299,     0,    13, STR_01D2_JAZZ_JUKEBOX, STR_018C_WINDOW_TITLE_DRAG_THIS},          // MW_CAPTION
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,    14,     0,    21,    14,    35, SPR_IMG_SKIP_TO_PREV,  STR_01DE_SKIP_TO_PREVIOUS_TRACK},          // MW_PREV
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    22,    43,    14,    35, SPR_IMG_SKIP_TO_NEXT,  STR_01DF_SKIP_TO_NEXT_TRACK_IN_SELECTION}, // MW_NEXT
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    44,    65,    14,    35, SPR_IMG_STOP_MUSIC,    STR_01E0_STOP_PLAYING_MUSIC},              // MW_STOP
+{ WWT_PUSHIMGBTN,   RESIZE_NONE,    14,    66,    87,    14,    35, SPR_IMG_PLAY_MUSIC,    STR_01E1_START_PLAYING_MUSIC},             // MW_PLAY
+{      WWT_PANEL,   RESIZE_NONE,    14,    88,   299,    14,    35, 0x0,                   STR_01E2_DRAG_SLIDERS_TO_SET_MUSIC},       // MW_SLIDERS
+{      WWT_PANEL,   RESIZE_NONE,    14,   186,   201,    15,    34, 0x0,                   STR_NULL},                                 // MW_GAUGE
+{      WWT_PANEL,   RESIZE_NONE,    14,     0,   299,    36,    57, 0x0,                   STR_NULL},                                 // MW_BACKGROUND
+{      WWT_PANEL,   RESIZE_NONE,    14,    59,   240,    45,    53, 0x0,                   STR_NULL},                                 // MW_INFO
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,     6,    55,    42,    49, 0x0,                   STR_01FB_TOGGLE_PROGRAM_SHUFFLE},          // MW_SHUFFLE
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   244,   293,    42,    49, 0x0,                   STR_01FC_SHOW_MUSIC_TRACK_SELECTION},      // MW_PROGRAMME
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,     0,    49,    58,    65, 0x0,                   STR_01F3_SELECT_ALL_TRACKS_PROGRAM},       // MW_ALL
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,    50,    99,    58,    65, 0x0,                   STR_01F4_SELECT_OLD_STYLE_MUSIC},          // MW_OLD
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   100,   149,    58,    65, 0x0,                   STR_01F5_SELECT_NEW_STYLE_MUSIC},          // MW_NEW
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   150,   199,    58,    65, 0x0,                   STR_0330_SELECT_EZY_STREET_STYLE},         // MW_EZY
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   200,   249,    58,    65, 0x0,                   STR_01F6_SELECT_CUSTOM_1_USER_DEFINED},    // MW_CUSTOM1
+{    WWT_PUSHBTN,   RESIZE_NONE,    14,   250,   299,    58,    65, 0x0,                   STR_01F7_SELECT_CUSTOM_2_USER_DEFINED},    // MW_CUSTOM2
 {   WIDGETS_END},
 };
 
@@ -497,10 +552,9 @@
 	WC_MUSIC_WINDOW, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
 	_music_window_widgets,
-	MusicWindowWndProc
 };
 
 void ShowMusicWindow()
 {
-	AllocateWindowDescFront<Window>(&_music_window_desc, 0);
+	AllocateWindowDescFront<MusicWindow>(&_music_window_desc, 0);
 }
--- a/src/network/network_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/network/network_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -30,6 +30,7 @@
 #include "../settings_type.h"
 #include "../widgets/dropdown_func.h"
 #include "../querystring_gui.h"
+#include "../sortlist_type.h"
 
 #include "table/strings.h"
 #include "../table/sprites.h"
@@ -318,7 +319,7 @@
 
 		SetDParam(0, 0x00);
 		SetDParam(1, _lan_internet_types_dropdown[_network_lan_internet]);
-		DrawWindowWidgets(this);
+		this->DrawWidgets();
 
 		/* Edit box to set player name */
 		this->DrawEditBox(NGWW_PLAYER);
@@ -327,9 +328,9 @@
 
 		/* Sort based on widgets: name, clients, compatibility */
 		switch (this->servers.sort_type) {
-			case NGWW_NAME    - NGWW_NAME: DrawSortButtonState(this, NGWW_NAME,    arrow); break;
-			case NGWW_CLIENTS - NGWW_NAME: DrawSortButtonState(this, NGWW_CLIENTS, arrow); break;
-			case NGWW_INFO    - NGWW_NAME: DrawSortButtonState(this, NGWW_INFO,    arrow); break;
+			case NGWW_NAME    - NGWW_NAME: this->DrawSortButtonState(NGWW_NAME,    arrow); break;
+			case NGWW_CLIENTS - NGWW_NAME: this->DrawSortButtonState(NGWW_CLIENTS, arrow); break;
+			case NGWW_INFO    - NGWW_NAME: this->DrawSortButtonState(NGWW_INFO,    arrow); break;
 		}
 
 		uint16 y = NET_PRC__OFFSET_TOP_WIDGET + 3;
@@ -542,9 +543,9 @@
 		this->SetDirty();
 	}
 
-	virtual bool OnKeyPress(uint16 key, uint16 keycode)
+	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
 	{
-		bool cont = true;
+		EventState state = ES_NOT_HANDLED;
 		if (this->field != NGWW_PLAYER) {
 			if (this->server != NULL) {
 				if (keycode == WKC_DELETE) { // Press 'delete' to remove servers
@@ -553,10 +554,10 @@
 					this->server = NULL;
 				}
 			}
-			return cont;
+			return state;
 		}
 
-		if (this->HandleEditBoxKey(NGWW_PLAYER, keycode, key, cont) == 1) return cont; // enter pressed
+		if (this->HandleEditBoxKey(NGWW_PLAYER, keycode, key, state) == 1) return state; // enter pressed
 
 		/* The name is only allowed when it starts with a letter! */
 		if (StrEmpty(this->edit_str_buf) && this->edit_str_buf[0] != ' ') {
@@ -564,7 +565,7 @@
 		} else {
 			ttd_strlcpy(_network_player_name, "Player", lengthof(_network_player_name));
 		}
-		return cont;
+		return state;
 	}
 
 	virtual void OnQueryTextFinished(char *str)
@@ -641,7 +642,6 @@
 	WC_NETWORK_WINDOW, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_STD_BTN | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
 	_network_game_window_widgets,
-	NULL,
 };
 
 void ShowNetworkGameWindow()
@@ -727,7 +727,7 @@
 		SetDParam(3, _network_game_info.companies_max);
 		SetDParam(4, _network_game_info.spectators_max);
 		SetDParam(5, STR_NETWORK_LANG_ANY + _network_game_info.server_lang);
-		DrawWindowWidgets(this);
+		this->DrawWidgets();
 
 		/* editbox to set game name */
 		this->DrawEditBox(NSSW_GAMENAME);
@@ -891,16 +891,16 @@
 		if (this->field == NSSW_GAMENAME) this->HandleEditBox(NSSW_GAMENAME);
 	}
 
-	virtual bool OnKeyPress(uint16 key, uint16 keycode)
+	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
 	{
-		bool cont = true;
+		EventState state = ES_NOT_HANDLED;
 		if (this->field == NSSW_GAMENAME) {
-			if (this->HandleEditBoxKey(NSSW_GAMENAME, key, keycode, cont) == 1) return cont; // enter pressed
+			if (this->HandleEditBoxKey(NSSW_GAMENAME, key, keycode, state) == 1) return state; // enter pressed
 
 			ttd_strlcpy(_network_server_name, this->text.buf, sizeof(_network_server_name));
 		}
 
-		return cont;
+		return state;
 	}
 
 	virtual void OnQueryTextFinished(char *str)
@@ -976,7 +976,6 @@
 	WC_NETWORK_WINDOW, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
 	_network_start_server_window_widgets,
-	NULL,
 };
 
 static void ShowNetworkStartServerWindow()
@@ -1036,7 +1035,7 @@
 
 		/* Draw window widgets */
 		SetDParamStr(0, gi->server_name);
-		DrawWindowWidgets(this);
+		this->DrawWidgets();
 
 		/* Draw company list */
 		pos = this->vscroll.pos;
@@ -1190,7 +1189,6 @@
 	WC_NETWORK_WINDOW, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
 	_network_lobby_window_widgets,
-	NULL,
 };
 
 /* Show the networklobbywindow with the selected server
@@ -1217,14 +1215,6 @@
 // Max 10 actions per client
 #define MAX_CLIENTLIST_ACTION 10
 
-// Some standard bullshit.. defines variables ;)
-static void ClientListWndProc(Window *w, WindowEvent *e);
-static void ClientListPopupWndProc(Window *w, WindowEvent *e);
-static byte _selected_clientlist_item = 255;
-static byte _selected_clientlist_y = 0;
-static char _clientlist_action[MAX_CLIENTLIST_ACTION][50];
-static ClientList_Action_Proc *_clientlist_proc[MAX_CLIENTLIST_ACTION];
-
 enum {
 	CLNWND_OFFSET = 16,
 	CLNWND_ROWSIZE = 10
@@ -1244,12 +1234,11 @@
 {   WIDGETS_END},
 };
 
-static WindowDesc _client_list_desc = {
+static const WindowDesc _client_list_desc = {
 	WDP_AUTO, WDP_AUTO, 250, 1, 250, 1,
 	WC_CLIENT_LIST, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
 	_client_list_widgets,
-	ClientListWndProc
 };
 
 // Finds the Xth client-info that is active
@@ -1321,267 +1310,271 @@
 
 
 
-/**
- * An action is clicked! What do we do?
- */
-static void HandleClientListPopupClick(byte index, byte clientno)
-{
-	/* A click on the Popup of the ClientList.. handle the command */
-	if (index < MAX_CLIENTLIST_ACTION && _clientlist_proc[index] != NULL) {
-		_clientlist_proc[index](clientno);
-	}
-}
+struct NetworkClientListPopupWindow : Window {
+	int sel_index;
+	int client_no;
+	char action[MAX_CLIENTLIST_ACTION][50];
+	ClientList_Action_Proc *proc[MAX_CLIENTLIST_ACTION];
 
-/**
- * Finds the amount of clients and set the height correct
- */
-static bool CheckClientListHeight(Window *w)
-{
-	int num = 0;
-	const NetworkClientInfo *ci;
+	NetworkClientListPopupWindow(int x, int y, const Widget *widgets, int client_no) :
+			Window(x, y, 150, 100, WC_TOOLBAR_MENU, widgets),
+			sel_index(0), client_no(client_no)
+	{
+		/*
+		 * Fill the actions this client has.
+		 * Watch is, max 50 chars long!
+		 */
 
-	/* Should be replaced with a loop through all clients */
-	FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
-		num++;
+		const NetworkClientInfo *ci = NetworkFindClientInfo(client_no);
+
+		int i = 0;
+		if (_network_own_client_index != ci->client_index) {
+			GetString(this->action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT, lastof(this->action[i]));
+			this->proc[i++] = &ClientList_SpeakToClient;
+		}
+
+		if (IsValidPlayer(ci->client_playas) || ci->client_playas == PLAYER_SPECTATOR) {
+			GetString(this->action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY, lastof(this->action[i]));
+			this->proc[i++] = &ClientList_SpeakToCompany;
+		}
+		GetString(this->action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL, lastof(this->action[i]));
+		this->proc[i++] = &ClientList_SpeakToAll;
+
+		if (_network_own_client_index != ci->client_index) {
+			/* We are no spectator and the player we want to give money to is no spectator and money gifts are allowed */
+			if (IsValidPlayer(_network_playas) && IsValidPlayer(ci->client_playas) && _patches.give_money) {
+				GetString(this->action[i], STR_NETWORK_CLIENTLIST_GIVE_MONEY, lastof(this->action[i]));
+				this->proc[i++] = &ClientList_GiveMoney;
+			}
+		}
+
+		/* A server can kick clients (but not himself) */
+		if (_network_server && _network_own_client_index != ci->client_index) {
+			GetString(this->action[i], STR_NETWORK_CLIENTLIST_KICK, lastof(this->action[i]));
+			this->proc[i++] = &ClientList_Kick;
+
+			sprintf(this->action[i],"Ban"); // XXX GetString?
+			this->proc[i++] = &ClientList_Ban;
+		}
+
+		if (i == 0) {
+			GetString(this->action[i], STR_NETWORK_CLIENTLIST_NONE, lastof(this->action[i]));
+			this->proc[i++] = &ClientList_None;
+		}
+
+		/* Calculate the height */
+		int h = ClientListPopupHeight();
+
+		/* Allocate the popup */
+		this->widget[0].bottom = this->widget[0].top + h;
+		this->widget[0].right = this->widget[0].left + 150;
+
+		this->flags4 &= ~WF_WHITE_BORDER_MASK;
+
+		this->FindWindowPlacementAndResize(150, h + 1);
 	}
 
-	num *= CLNWND_ROWSIZE;
-
-	/* If height is changed */
-	if (w->height != CLNWND_OFFSET + num + 1) {
-		// XXX - magic unfortunately; (num + 2) has to be one bigger than heigh (num + 1)
-		w->SetDirty();
-		w->widget[3].bottom = w->widget[3].top + num + 2;
-		w->height = CLNWND_OFFSET + num + 1;
-		w->SetDirty();
-		return false;
-	}
-	return true;
-}
-
-/**
- * Finds the amount of actions in the popup and set the height correct
- */
-static uint ClientListPopupHeight()
-{
-	int num = 0;
-
-	// Find the amount of actions
-	for (int i = 0; i < MAX_CLIENTLIST_ACTION; i++) {
-		if (_clientlist_action[i][0] == '\0') continue;
-		if (_clientlist_proc[i] == NULL) continue;
-		num++;
+	/**
+	 * An action is clicked! What do we do?
+	 */
+	void HandleClientListPopupClick(byte index)
+	{
+		/* A click on the Popup of the ClientList.. handle the command */
+		if (index < MAX_CLIENTLIST_ACTION && this->proc[index] != NULL) {
+			this->proc[index](this->client_no);
+		}
 	}
 
-	num *= CLNWND_ROWSIZE;
+	/**
+	 * Finds the amount of actions in the popup and set the height correct
+	 */
+	uint ClientListPopupHeight()
+	{
+		int num = 0;
 
-	return num + 1;
-}
+		// Find the amount of actions
+		for (int i = 0; i < MAX_CLIENTLIST_ACTION; i++) {
+			if (this->action[i][0] == '\0') continue;
+			if (this->proc[i] == NULL) continue;
+			num++;
+		}
+
+		num *= CLNWND_ROWSIZE;
+
+		return num + 1;
+	}
+
+
+	virtual void OnPaint()
+	{
+		this->DrawWidgets();
+
+		/* Draw the actions */
+		int sel = this->sel_index;
+		int y = 1;
+		for (int i = 0; i < MAX_CLIENTLIST_ACTION; i++, y += CLNWND_ROWSIZE) {
+			if (this->action[i][0] == '\0') continue;
+			if (this->proc[i] == NULL) continue;
+
+			TextColour colour;
+			if (sel-- == 0) { // Selected item, highlight it
+				GfxFillRect(1, y, 150 - 2, y + CLNWND_ROWSIZE - 1, 0);
+				colour = TC_WHITE;
+			} else {
+				colour = TC_BLACK;
+			}
+
+			DoDrawString(this->action[i], 4, y, colour);
+		}
+	}
+
+	virtual void OnMouseLoop()
+	{
+		/* We selected an action */
+		int index = (_cursor.pos.y - this->top) / CLNWND_ROWSIZE;
+
+		if (_left_button_down) {
+			if (index == -1 || index == this->sel_index) return;
+
+			this->sel_index = index;
+			this->SetDirty();
+		} else {
+			if (index >= 0 && _cursor.pos.y >= this->top) {
+				HandleClientListPopupClick(index);
+			}
+
+			DeleteWindowById(WC_TOOLBAR_MENU, 0);
+		}
+	}
+};
 
 /**
  * Show the popup (action list)
  */
-static Window *PopupClientList(Window *w, int client_no, int x, int y)
+static void PopupClientList(int client_no, int x, int y)
 {
-	int i;
-	const NetworkClientInfo *ci;
 	DeleteWindowById(WC_TOOLBAR_MENU, 0);
 
-	/* Clean the current actions */
-	for (i = 0; i < MAX_CLIENTLIST_ACTION; i++) {
-		_clientlist_action[i][0] = '\0';
-		_clientlist_proc[i] = NULL;
-	}
-
-	/*
-	 * Fill the actions this client has.
-	 * Watch is, max 50 chars long!
-	 */
-
-	ci = NetworkFindClientInfo(client_no);
-	if (ci == NULL) return NULL;
-
-	i = 0;
-	if (_network_own_client_index != ci->client_index) {
-		GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT, lastof(_clientlist_action[i]));
-		_clientlist_proc[i++] = &ClientList_SpeakToClient;
-	}
-
-	if (IsValidPlayer(ci->client_playas) || ci->client_playas == PLAYER_SPECTATOR) {
-		GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY, lastof(_clientlist_action[i]));
-		_clientlist_proc[i++] = &ClientList_SpeakToCompany;
-	}
-	GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL, lastof(_clientlist_action[i]));
-	_clientlist_proc[i++] = &ClientList_SpeakToAll;
-
-	if (_network_own_client_index != ci->client_index) {
-		/* We are no spectator and the player we want to give money to is no spectator and money gifts are allowed */
-		if (IsValidPlayer(_network_playas) && IsValidPlayer(ci->client_playas) && _patches.give_money) {
-			GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_GIVE_MONEY, lastof(_clientlist_action[i]));
-			_clientlist_proc[i++] = &ClientList_GiveMoney;
-		}
-	}
-
-	/* A server can kick clients (but not himself) */
-	if (_network_server && _network_own_client_index != ci->client_index) {
-		GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_KICK, lastof(_clientlist_action[i]));
-		_clientlist_proc[i++] = &ClientList_Kick;
-
-		sprintf(_clientlist_action[i],"Ban"); // XXX GetString?
-		_clientlist_proc[i++] = &ClientList_Ban;
-	}
-
-	if (i == 0) {
-		GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_NONE, lastof(_clientlist_action[i]));
-		_clientlist_proc[i++] = &ClientList_None;
-	}
-
-	/* Calculate the height */
-	int h = ClientListPopupHeight();
+	if (NetworkFindClientInfo(client_no) == NULL) return;
 
-	/* Allocate the popup */
-	w = new Window(x, y, 150, h + 1, ClientListPopupWndProc, WC_TOOLBAR_MENU, _client_list_popup_widgets);
-	w->widget[0].bottom = w->widget[0].top + h;
-	w->widget[0].right = w->widget[0].left + 150;
-
-	w->flags4 &= ~WF_WHITE_BORDER_MASK;
-	WP(w, menu_d).item_count = 0;
-	// Save our client
-	WP(w, menu_d).main_button = client_no;
-	WP(w, menu_d).sel_index = 0;
-
-	return w;
-}
-
-/** Main handle for the client popup list
- * uses menu_d WP macro */
-static void ClientListPopupWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			DrawWindowWidgets(w);
-
-			/* Draw the actions */
-			int sel = WP(w, menu_d).sel_index;
-			int y = 1;
-			for (int i = 0; i < MAX_CLIENTLIST_ACTION; i++, y += CLNWND_ROWSIZE) {
-				if (_clientlist_action[i][0] == '\0') continue;
-				if (_clientlist_proc[i] == NULL) continue;
-
-				TextColour colour;
-				if (sel-- == 0) { // Selected item, highlight it
-					GfxFillRect(1, y, 150 - 2, y + CLNWND_ROWSIZE - 1, 0);
-					colour = TC_WHITE;
-				} else {
-					colour = TC_BLACK;
-				}
-
-				DoDrawString(_clientlist_action[i], 4, y, colour);
-			}
-		} break;
-
-		case WE_MOUSELOOP: {
-			/* We selected an action */
-			int index = (_cursor.pos.y - w->top) / CLNWND_ROWSIZE;
-
-			if (_left_button_down) {
-				if (index == -1 || index == WP(w, menu_d).sel_index) return;
-
-				WP(w, menu_d).sel_index = index;
-				w->SetDirty();
-			} else {
-				if (index >= 0 && _cursor.pos.y >= w->top) {
-					HandleClientListPopupClick(index, WP(w, menu_d).main_button);
-				}
-
-				DeleteWindowById(WC_TOOLBAR_MENU, 0);
-			}
-		} break;
-	}
+	new NetworkClientListPopupWindow(x, y, _client_list_popup_widgets, client_no);
 }
 
 /**
  * Main handle for clientlist
  */
-static void ClientListWndProc(Window *w, WindowEvent *e)
+struct NetworkClientListWindow : Window
 {
-	switch (e->event) {
-		case WE_PAINT: {
-			NetworkClientInfo *ci;
-			int i = 0;
-
-			/* Check if we need to reset the height */
-			if (!CheckClientListHeight(w)) break;
-
-			DrawWindowWidgets(w);
-
-			int y = CLNWND_OFFSET;
-
-			FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
-				TextColour colour;
-				if (_selected_clientlist_item == i++) { // Selected item, highlight it
-					GfxFillRect(1, y, 248, y + CLNWND_ROWSIZE - 1, 0);
-					colour = TC_WHITE;
-				} else {
-					colour = TC_BLACK;
-				}
-
-				if (ci->client_index == NETWORK_SERVER_INDEX) {
-					DrawString(4, y, STR_NETWORK_SERVER, colour);
-				} else {
-					DrawString(4, y, STR_NETWORK_CLIENT, colour);
-				}
+	byte selected_item;
+	byte selected_y;
 
-				/* Filter out spectators */
-				if (IsValidPlayer(ci->client_playas)) DrawPlayerIcon(ci->client_playas, 64, y + 1);
-
-				DoDrawString(ci->client_name, 81, y, colour);
-
-				y += CLNWND_ROWSIZE;
-			}
-		} break;
-
-		case WE_CLICK:
-			/* Show the popup with option */
-			if (_selected_clientlist_item != 255) {
-				PopupClientList(w, _selected_clientlist_item, e->we.click.pt.x + w->left, e->we.click.pt.y + w->top);
-			}
-			break;
+	NetworkClientListWindow(const WindowDesc *desc, WindowNumber window_number) :
+			Window(desc, window_number),
+			selected_item(0),
+			selected_y(255)
+	{
+		this->FindWindowPlacementAndResize(desc);
+	}
 
-		case WE_MOUSEOVER:
-			/* -1 means we left the current window */
-			if (e->we.mouseover.pt.y == -1) {
-				_selected_clientlist_y = 0;
-				_selected_clientlist_item = 255;
-				w->SetDirty();
-				break;
-			}
-			/* It did not change.. no update! */
-			if (e->we.mouseover.pt.y == _selected_clientlist_y) break;
+	/**
+	 * Finds the amount of clients and set the height correct
+	 */
+	bool CheckClientListHeight()
+	{
+		int num = 0;
+		const NetworkClientInfo *ci;
 
-			/* Find the new selected item (if any) */
-			_selected_clientlist_y = e->we.mouseover.pt.y;
-			if (e->we.mouseover.pt.y > CLNWND_OFFSET) {
-				_selected_clientlist_item = (e->we.mouseover.pt.y - CLNWND_OFFSET) / CLNWND_ROWSIZE;
+		/* Should be replaced with a loop through all clients */
+		FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
+			num++;
+		}
+
+		num *= CLNWND_ROWSIZE;
+
+		/* If height is changed */
+		if (this->height != CLNWND_OFFSET + num + 1) {
+			// XXX - magic unfortunately; (num + 2) has to be one bigger than heigh (num + 1)
+			this->SetDirty();
+			this->widget[3].bottom = this->widget[3].top + num + 2;
+			this->height = CLNWND_OFFSET + num + 1;
+			this->SetDirty();
+			return false;
+		}
+		return true;
+	}
+
+	virtual void OnPaint()
+	{
+		NetworkClientInfo *ci;
+		int i = 0;
+
+		/* Check if we need to reset the height */
+		if (!this->CheckClientListHeight()) return;
+
+		this->DrawWidgets();
+
+		int y = CLNWND_OFFSET;
+
+		FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
+			TextColour colour;
+			if (this->selected_item == i++) { // Selected item, highlight it
+				GfxFillRect(1, y, 248, y + CLNWND_ROWSIZE - 1, 0);
+				colour = TC_WHITE;
 			} else {
-				_selected_clientlist_item = 255;
+				colour = TC_BLACK;
 			}
 
-			/* Repaint */
-			w->SetDirty();
-			break;
+			if (ci->client_index == NETWORK_SERVER_INDEX) {
+				DrawString(4, y, STR_NETWORK_SERVER, colour);
+			} else {
+				DrawString(4, y, STR_NETWORK_CLIENT, colour);
+			}
 
-		case WE_DESTROY: case WE_CREATE:
-			/* When created or destroyed, data is reset */
-			_selected_clientlist_item = 255;
-			_selected_clientlist_y = 0;
-			break;
+			/* Filter out spectators */
+			if (IsValidPlayer(ci->client_playas)) DrawPlayerIcon(ci->client_playas, 64, y + 1);
+
+			DoDrawString(ci->client_name, 81, y, colour);
+
+			y += CLNWND_ROWSIZE;
+		}
 	}
-}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		/* Show the popup with option */
+		if (this->selected_item != 255) {
+			PopupClientList(this->selected_item, pt.x + this->left, pt.y + this->top);
+		}
+	}
+
+	virtual void OnMouseOver(Point pt, int widget)
+	{
+		/* -1 means we left the current window */
+		if (pt.y == -1) {
+			this->selected_y = 0;
+			this->selected_item = 255;
+			this->SetDirty();
+			return;
+		}
+		/* It did not change.. no update! */
+		if (pt.y == this->selected_y) return;
+
+		/* Find the new selected item (if any) */
+		this->selected_y = pt.y;
+		if (pt.y > CLNWND_OFFSET) {
+			this->selected_item = (pt.y - CLNWND_OFFSET) / CLNWND_ROWSIZE;
+		} else {
+			this->selected_item = 255;
+		}
+
+		/* Repaint */
+		this->SetDirty();
+	}
+};
 
 void ShowClientList()
 {
-	AllocateWindowDescFront<Window>(&_client_list_desc, 0);
+	AllocateWindowDescFront<NetworkClientListWindow>(&_client_list_desc, 0);
 }
 
 
@@ -1601,56 +1594,60 @@
 	ShowQueryString(STR_EMPTY, caption, 20, 180, FindWindowById(WC_NETWORK_STATUS_WINDOW, 0), CS_ALPHANUMERAL);
 }
 
-
-static void NetworkJoinStatusWindowWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			uint8 progress; // used for progress bar
-			DrawWindowWidgets(w);
+struct NetworkJoinStatusWindow : Window {
+	NetworkJoinStatusWindow(const WindowDesc *desc) : Window(desc)
+	{
+		this->parent = FindWindowById(WC_NETWORK_WINDOW, 0);
+	}
 
-			DrawStringCentered(125, 35, STR_NETWORK_CONNECTING_1 + _network_join_status, TC_GREY);
-			switch (_network_join_status) {
-				case NETWORK_JOIN_STATUS_CONNECTING: case NETWORK_JOIN_STATUS_AUTHORIZING:
-				case NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO:
-					progress = 10; // first two stages 10%
-					break;
-				case NETWORK_JOIN_STATUS_WAITING:
-					SetDParam(0, _network_join_waiting);
-					DrawStringCentered(125, 46, STR_NETWORK_CONNECTING_WAITING, TC_GREY);
-					progress = 15; // third stage is 15%
-					break;
-				case NETWORK_JOIN_STATUS_DOWNLOADING:
-					SetDParam(0, _network_join_kbytes);
-					SetDParam(1, _network_join_kbytes_total);
-					DrawStringCentered(125, 46, STR_NETWORK_CONNECTING_DOWNLOADING, TC_GREY);
-					/* Fallthrough */
-				default: /* Waiting is 15%, so the resting receivement of map is maximum 70% */
-					progress = 15 + _network_join_kbytes * (100 - 15) / _network_join_kbytes_total;
-			}
+	virtual void OnPaint()
+	{
+		uint8 progress; // used for progress bar
+		this->DrawWidgets();
 
-			/* Draw nice progress bar :) */
-			DrawFrameRect(20, 18, (int)((w->width - 20) * progress / 100), 28, 10, FR_NONE);
-		} break;
+		DrawStringCentered(125, 35, STR_NETWORK_CONNECTING_1 + _network_join_status, TC_GREY);
+		switch (_network_join_status) {
+			case NETWORK_JOIN_STATUS_CONNECTING: case NETWORK_JOIN_STATUS_AUTHORIZING:
+			case NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO:
+				progress = 10; // first two stages 10%
+				break;
+			case NETWORK_JOIN_STATUS_WAITING:
+				SetDParam(0, _network_join_waiting);
+				DrawStringCentered(125, 46, STR_NETWORK_CONNECTING_WAITING, TC_GREY);
+				progress = 15; // third stage is 15%
+				break;
+			case NETWORK_JOIN_STATUS_DOWNLOADING:
+				SetDParam(0, _network_join_kbytes);
+				SetDParam(1, _network_join_kbytes_total);
+				DrawStringCentered(125, 46, STR_NETWORK_CONNECTING_DOWNLOADING, TC_GREY);
+				/* Fallthrough */
+			default: /* Waiting is 15%, so the resting receivement of map is maximum 70% */
+				progress = 15 + _network_join_kbytes * (100 - 15) / _network_join_kbytes_total;
+		}
 
-		case WE_CLICK:
-			if (e->we.click.widget == 2) { //Disconnect button
-				NetworkDisconnect();
-				SwitchMode(SM_MENU);
-				ShowNetworkGameWindow();
-			}
-			break;
+		/* Draw nice progress bar :) */
+		DrawFrameRect(20, 18, (int)((this->width - 20) * progress / 100), 28, 10, FR_NONE);
+	}
 
-		case WE_ON_EDIT_TEXT:
-			if (StrEmpty(e->we.edittext.str)) {
-				NetworkDisconnect();
-				ShowNetworkGameWindow();
-			} else {
-				SEND_COMMAND(PACKET_CLIENT_PASSWORD)(pw_type, e->we.edittext.str);
-			}
-			break;
+	virtual void OnClick(Point pt, int widget)
+	{
+		if (widget == 2) { //Disconnect button
+			NetworkDisconnect();
+			SwitchMode(SM_MENU);
+			ShowNetworkGameWindow();
+		}
 	}
-}
+
+	virtual void OnQueryTextFinished(char *str)
+	{
+		if (StrEmpty(str)) {
+			NetworkDisconnect();
+			ShowNetworkGameWindow();
+		} else {
+			SEND_COMMAND(PACKET_CLIENT_PASSWORD)(pw_type, str);
+		}
+	}
+};
 
 static const Widget _network_join_status_window_widget[] = {
 {    WWT_CAPTION,   RESIZE_NONE,    14,     0,   249,     0,    13, STR_NETWORK_CONNECTING, STR_018C_WINDOW_TITLE_DRAG_THIS},
@@ -1664,15 +1661,12 @@
 	WC_NETWORK_STATUS_WINDOW, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_MODAL,
 	_network_join_status_window_widget,
-	NetworkJoinStatusWindowWndProc,
 };
 
 void ShowJoinStatusWindow()
 {
 	DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
-	Window *w = new Window(&_network_join_status_window_desc);
-	/* Parent the status window to the lobby */
-	if (w != NULL) w->parent = FindWindowById(WC_NETWORK_WINDOW, 0);
+	new NetworkJoinStatusWindow(&_network_join_status_window_desc);
 }
 
 static void SendChat(const char *buf, DestType type, int dest)
@@ -1853,7 +1847,7 @@
 			STR_NETWORK_CHAT_CLIENT_CAPTION
 		};
 
-		DrawWindowWidgets(this);
+		this->DrawWidgets();
 
 		assert((uint)this->dtype < lengthof(chat_captions));
 		DrawStringRightAligned(this->widget[2].left - 2, this->widget[2].top + 1, chat_captions[this->dtype], TC_BLACK);
@@ -1879,21 +1873,21 @@
 		this->HandleEditBox(2);
 	}
 
-	virtual bool OnKeyPress(uint16 key, uint16 keycode)
+	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
 	{
-		bool cont = true;
+		EventState state = ES_NOT_HANDLED;
 		if (keycode == WKC_TAB) {
 			ChatTabCompletion();
 		} else {
 			_chat_tab_completion_active = false;
-			switch (this->HandleEditBoxKey(2, key, keycode, cont)) {
+			switch (this->HandleEditBoxKey(2, key, keycode, state)) {
 				case 1: /* Return */
 					SendChat(this->text.buf, this->dtype, this->dest);
 				/* FALLTHROUGH */
 				case 2: /* Escape */ delete this; break;
 			}
 		}
-		return cont;
+		return state;
 	}
 };
 
@@ -1910,7 +1904,6 @@
 	WC_SEND_NETWORK_MSG, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET,
 	_chat_window_widgets,
-	NULL
 };
 
 void ShowNetworkChatQueryWindow(DestType type, int dest)
@@ -1932,8 +1925,9 @@
 };
 
 struct NetworkCompanyPasswordWindow : public QueryStringBaseWindow {
-	NetworkCompanyPasswordWindow(const WindowDesc *desc) : QueryStringBaseWindow(desc)
+	NetworkCompanyPasswordWindow(const WindowDesc *desc, Window *parent) : QueryStringBaseWindow(desc)
 	{
+		this->parent = parent;
 		this->afilter = CS_ALPHANUMERAL;
 		InitializeTextBuffer(&this->text, this->edit_str_buf, min(lengthof(_network_default_company_pass), lengthof(this->edit_str_buf)), 0);
 
@@ -1954,7 +1948,7 @@
 
 	virtual void OnPaint()
 	{
-		DrawWindowWidgets(this);
+		this->DrawWidgets();
 		this->DrawEditBox(4);
 	}
 
@@ -1985,10 +1979,10 @@
 		this->HandleEditBox(4);
 	}
 
-	virtual bool OnKeyPress(uint16 key, uint16 keycode)
+	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
 	{
-		bool cont;
-		switch (this->HandleEditBoxKey(4, key, keycode, cont)) {
+		EventState state;
+		switch (this->HandleEditBoxKey(4, key, keycode, state)) {
 			case 1: // Return
 				this->OnOk();
 				/* FALL THROUGH */
@@ -1997,7 +1991,7 @@
 				delete this;
 				break;
 		}
-		return cont;
+		return state;
 	}
 };
 
@@ -2018,14 +2012,13 @@
 	WC_COMPANY_PASSWORD_WINDOW, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
 	_ncp_window_widgets,
-	NULL
 };
 
-void ShowNetworkCompanyPasswordWindow()
+void ShowNetworkCompanyPasswordWindow(Window *parent)
 {
 	DeleteWindowById(WC_COMPANY_PASSWORD_WINDOW, 0);
 
-	new NetworkCompanyPasswordWindow(&_ncp_window_desc);
+	new NetworkCompanyPasswordWindow(&_ncp_window_desc, parent);
 }
 
 #endif /* ENABLE_NETWORK */
--- a/src/network/network_gui.h	Mon May 19 14:14:33 2008 +0000
+++ b/src/network/network_gui.h	Mon May 19 15:13:58 2008 +0000
@@ -5,6 +5,8 @@
 #ifndef NETWORK_GUI_H
 #define NETWORK_GUI_H
 
+#include "../window_type.h"
+
 #ifdef ENABLE_NETWORK
 
 #include "network_data.h"
@@ -15,7 +17,7 @@
 void ShowJoinStatusWindow();
 void ShowNetworkGameWindow();
 void ShowClientList();
-void ShowNetworkCompanyPasswordWindow();
+void ShowNetworkCompanyPasswordWindow(Window *parent);
 
 #else /* ENABLE_NETWORK */
 /* Network function stubs when networking is disabled */
@@ -23,7 +25,7 @@
 static inline void ShowNetworkChatQueryWindow(byte desttype, int dest) {}
 static inline void ShowClientList() {}
 static inline void ShowNetworkGameWindow() {}
-static inline void ShowNetworkCompanyPasswordWindow() {}
+static inline void ShowNetworkCompanyPasswordWindow(Window *parent) {}
 
 #endif /* ENABLE_NETWORK */
 
--- a/src/newgrf.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/newgrf.cpp	Mon May 19 15:13:58 2008 +0000
@@ -466,22 +466,14 @@
 				rvi->max_speed = speed;
 			} break;
 
-			case 0x0B: { // Power
-				uint16 power = grf_load_word(&buf);
-
-				if (rvi->railveh_type == RAILVEH_MULTIHEAD) power /= 2;
-
-				rvi->power = power;
-				dewagonize(power, e);
-			} break;
-
-			case 0x0D: { // Running cost factor
-				uint8 runcostfact = grf_load_byte(&buf);
-
-				if (rvi->railveh_type == RAILVEH_MULTIHEAD) runcostfact /= 2;
-
-				rvi->running_cost = runcostfact;
-			} break;
+			case 0x0B: // Power
+				rvi->power = grf_load_word(&buf);
+				dewagonize(rvi->power, e);
+				break;
+
+			case 0x0D: // Running cost factor
+				rvi->running_cost = grf_load_byte(&buf);
+				break;
 
 			case 0x0E: { // Running cost base
 				uint32 base = grf_load_dword(&buf);
@@ -513,18 +505,8 @@
 				uint8 dual = grf_load_byte(&buf);
 
 				if (dual != 0) {
-					if (rvi->railveh_type != RAILVEH_MULTIHEAD) {
-						// adjust power and running cost if needed
-						rvi->power /= 2;
-						rvi->running_cost /= 2;
-					}
 					rvi->railveh_type = RAILVEH_MULTIHEAD;
 				} else {
-					if (rvi->railveh_type == RAILVEH_MULTIHEAD) {
-						// adjust power and running cost if needed
-						rvi->power *= 2;
-						rvi->running_cost *= 2;
-					}
 					rvi->railveh_type = rvi->power == 0 ?
 						RAILVEH_WAGON : RAILVEH_SINGLEHEAD;
 				}
--- a/src/newgrf_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/newgrf_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -109,121 +109,126 @@
 }
 
 
-/* Dialogue for adding NewGRF files to the selection */
-struct newgrf_add_d {
+/**
+ * Window for adding NewGRF files
+ */
+struct NewGRFAddWindow : public Window {
+	/* Names of the add a newgrf window widgets */
+	enum AddNewGRFWindowWidgets {
+		ANGRFW_CLOSEBOX = 0,
+		ANGRFW_CAPTION,
+		ANGRFW_BACKGROUND,
+		ANGRFW_GRF_LIST,
+		ANGRFW_SCROLLBAR,
+		ANGRFW_GRF_INFO,
+		ANGRFW_ADD,
+		ANGRFW_RESCAN,
+		ANGRFW_RESIZE,
+	};
+
 	GRFConfig **list;
 	const GRFConfig *sel;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(newgrf_add_d));
-
-/* Names of the add a newgrf window widgets */
-enum AddNewGRFWindowWidgets {
-	ANGRFW_CLOSEBOX = 0,
-	ANGRFW_CAPTION,
-	ANGRFW_BACKGROUND,
-	ANGRFW_GRF_LIST,
-	ANGRFW_SCROLLBAR,
-	ANGRFW_GRF_INFO,
-	ANGRFW_ADD,
-	ANGRFW_RESCAN,
-	ANGRFW_RESIZE,
-};
 
-static void NewGRFAddDlgWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			const GRFConfig *c;
-			const Widget *wl = &w->widget[ANGRFW_GRF_LIST];
-			int n = 0;
-
-			/* Count the number of GRFs */
-			for (c = _all_grfs; c != NULL; c = c->next) n++;
-
-			w->vscroll.cap = (wl->bottom - wl->top) / 10;
-			SetVScrollCount(w, n);
+	NewGRFAddWindow(const WindowDesc *desc, GRFConfig **list) : Window(desc, 0)
+	{
+		this->list = list;
+		this->resize.step_height = 10;
 
-			w->SetWidgetDisabledState(ANGRFW_ADD, WP(w, newgrf_add_d).sel == NULL || WP(w, newgrf_add_d).sel->IsOpenTTDBaseGRF());
-			DrawWindowWidgets(w);
-
-			GfxFillRect(wl->left + 1, wl->top + 1, wl->right, wl->bottom, 0xD7);
+		this->FindWindowPlacementAndResize(desc);
+	}
 
-			uint y = wl->top + 1;
-			for (c = _all_grfs, n = 0; c != NULL && n < (w->vscroll.pos + w->vscroll.cap); c = c->next, n++) {
-				if (n >= w->vscroll.pos) {
-					bool h = c == WP(w, newgrf_add_d).sel;
-					const char *text = (c->name != NULL && !StrEmpty(c->name)) ? c->name : c->filename;
+	virtual void OnPaint()
+	{
+		const GRFConfig *c;
+		const Widget *wl = &this->widget[ANGRFW_GRF_LIST];
+		int n = 0;
 
-					/* Draw selection background */
-					if (h) GfxFillRect(3, y, w->width - 15, y + 9, 156);
-					DoDrawStringTruncated(text, 4, y, h ? TC_WHITE : TC_ORANGE, w->width - 18);
-					y += 10;
-				}
+		/* Count the number of GRFs */
+		for (c = _all_grfs; c != NULL; c = c->next) n++;
+
+		this->vscroll.cap = (wl->bottom - wl->top) / 10;
+		SetVScrollCount(this, n);
+
+		this->SetWidgetDisabledState(ANGRFW_ADD, this->sel == NULL || this->sel->IsOpenTTDBaseGRF());
+		this->DrawWidgets();
+
+		GfxFillRect(wl->left + 1, wl->top + 1, wl->right, wl->bottom, 0xD7);
+
+		uint y = wl->top + 1;
+		for (c = _all_grfs, n = 0; c != NULL && n < (this->vscroll.pos + this->vscroll.cap); c = c->next, n++) {
+			if (n >= this->vscroll.pos) {
+				bool h = c == this->sel;
+				const char *text = (c->name != NULL && !StrEmpty(c->name)) ? c->name : c->filename;
+
+				/* Draw selection background */
+				if (h) GfxFillRect(3, y, this->width - 15, y + 9, 156);
+				DoDrawStringTruncated(text, 4, y, h ? TC_WHITE : TC_ORANGE, this->width - 18);
+				y += 10;
+			}
+		}
+
+		if (this->sel != NULL) {
+			const Widget *wi = &this->widget[ANGRFW_GRF_INFO];
+			ShowNewGRFInfo(this->sel, wi->left + 2, wi->top + 2, wi->right - wi->left - 2, wi->bottom, false);
+		}
+	}
+
+	virtual void OnDoubleClick(Point pt, int widget)
+	{
+		if (widget == ANGRFW_GRF_LIST) this->OnClick(pt, ANGRFW_ADD);
+	}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case ANGRFW_GRF_LIST: {
+				/* Get row... */
+				const GRFConfig *c;
+				uint i = (pt.y - this->widget[ANGRFW_GRF_LIST].top) / 10 + this->vscroll.pos;
+
+				for (c = _all_grfs; c != NULL && i > 0; c = c->next, i--) {}
+				this->sel = c;
+				this->SetDirty();
+				break;
 			}
 
-			if (WP(w, newgrf_add_d).sel != NULL) {
-				const Widget *wi = &w->widget[ANGRFW_GRF_INFO];
-				ShowNewGRFInfo(WP(w, newgrf_add_d).sel, wi->left + 2, wi->top + 2, wi->right - wi->left - 2, wi->bottom, false);
-			}
-			break;
-		}
-
-		case WE_DOUBLE_CLICK:
-			if (e->we.click.widget != ANGRFW_GRF_LIST) break;
-			e->we.click.widget = ANGRFW_ADD;
-			/* Fall through */
-
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case ANGRFW_GRF_LIST: {
-					/* Get row... */
-					const GRFConfig *c;
-					uint i = (e->we.click.pt.y - w->widget[ANGRFW_GRF_LIST].top) / 10 + w->vscroll.pos;
-
-					for (c = _all_grfs; c != NULL && i > 0; c = c->next, i--) {}
-					WP(w, newgrf_add_d).sel = c;
-					w->SetDirty();
-					break;
-				}
-
-				case ANGRFW_ADD: // Add selection to list
-					if (WP(w, newgrf_add_d).sel != NULL) {
-						const GRFConfig *src = WP(w, newgrf_add_d).sel;
-						GRFConfig **list;
+			case ANGRFW_ADD: // Add selection to list
+				if (this->sel != NULL) {
+					const GRFConfig *src = this->sel;
+					GRFConfig **list;
 
-						/* Find last entry in the list, checking for duplicate grfid on the way */
-						for (list = WP(w, newgrf_add_d).list; *list != NULL; list = &(*list)->next) {
-							if ((*list)->grfid == src->grfid) {
-								ShowErrorMessage(INVALID_STRING_ID, STR_NEWGRF_DUPLICATE_GRFID, 0, 0);
-								return;
-							}
+					/* Find last entry in the list, checking for duplicate grfid on the way */
+					for (list = this->list; *list != NULL; list = &(*list)->next) {
+						if ((*list)->grfid == src->grfid) {
+							ShowErrorMessage(INVALID_STRING_ID, STR_NEWGRF_DUPLICATE_GRFID, 0, 0);
+							return;
 						}
-
-						/* Copy GRF details from scanned list */
-						GRFConfig *c = CallocT<GRFConfig>(1);
-						*c = *src;
-						c->filename = strdup(src->filename);
-						if (src->name      != NULL) c->name      = strdup(src->name);
-						if (src->info      != NULL) c->info      = strdup(src->info);
-						c->next = NULL;
+					}
 
-						/* Append GRF config to configuration list */
-						*list = c;
-
-						DeleteWindowByClass(WC_SAVELOAD);
-						InvalidateWindowData(WC_GAME_OPTIONS, 0);
-					}
-					break;
+					/* Copy GRF details from scanned list */
+					GRFConfig *c = CallocT<GRFConfig>(1);
+					*c = *src;
+					c->filename = strdup(src->filename);
+					if (src->name      != NULL) c->name      = strdup(src->name);
+					if (src->info      != NULL) c->info      = strdup(src->info);
+					c->next = NULL;
 
-				case ANGRFW_RESCAN: // Rescan list
-					WP(w, newgrf_add_d).sel = NULL;
-					ScanNewGRFFiles();
-					w->SetDirty();
-					break;
-			}
-			break;
+					/* Append GRF config to configuration list */
+					*list = c;
+
+					DeleteWindowByClass(WC_SAVELOAD);
+					InvalidateWindowData(WC_GAME_OPTIONS, 0);
+				}
+				break;
+
+			case ANGRFW_RESCAN: // Rescan list
+				this->sel = NULL;
+				ScanNewGRFFiles();
+				this->SetDirty();
+				break;
+		}
 	}
-}
+};
 
 /* Widget definition for the add a newgrf window */
 static const Widget _newgrf_add_dlg_widgets[] = {
@@ -245,303 +250,282 @@
 	WC_SAVELOAD, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_STD_BTN | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
 	_newgrf_add_dlg_widgets,
-	NewGRFAddDlgWndProc,
 };
 
 
-/* 'NewGRF Settings' dialogue */
-struct newgrf_d {
+static void NewGRFConfirmationCallback(Window *w, bool confirmed);
+
+/**
+ * Window for showing NewGRF files
+ */
+struct NewGRFWindow : public Window {
+	/* Names of the manage newgrfs window widgets */
+	enum ShowNewGRFStateWidgets {
+		SNGRFS_CLOSEBOX = 0,
+		SNGRFS_CAPTION,
+		SNGRFS_BACKGROUND,
+		SNGRFS_ADD,
+		SNGRFS_REMOVE,
+		SNGRFS_MOVE_UP,
+		SNGRFS_MOVE_DOWN,
+		SNGRFS_FILE_LIST,
+		SNGRFS_SCROLLBAR,
+		SNGRFS_NEWGRF_INFO,
+		SNGRFS_SET_PARAMETERS,
+		SNGRFS_APPLY_CHANGES,
+		SNGRFS_RESIZE,
+	};
+
 	GRFConfig **orig_list; ///< grf list the window is shown with
-	GRFConfig **list;      ///< temporary grf list to which changes are made
+	GRFConfig *list;       ///< temporary grf list to which changes are made
 	GRFConfig *sel;        ///< selected grf item
 	bool editable;         ///< is the window editable
 	bool show_params;      ///< are the grf-parameters shown in the info-panel
 	bool execute;          ///< on pressing 'apply changes' are grf changes applied immediately, or only list is updated
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(newgrf_d));
-
-
-/* Names of the manage newgrfs window widgets */
-enum ShowNewGRFStateWidgets {
-	SNGRFS_CLOSEBOX = 0,
-	SNGRFS_CAPTION,
-	SNGRFS_BACKGROUND,
-	SNGRFS_ADD,
-	SNGRFS_REMOVE,
-	SNGRFS_MOVE_UP,
-	SNGRFS_MOVE_DOWN,
-	SNGRFS_FILE_LIST,
-	SNGRFS_SCROLLBAR,
-	SNGRFS_NEWGRF_INFO,
-	SNGRFS_SET_PARAMETERS,
-	SNGRFS_APPLY_CHANGES,
-	SNGRFS_RESIZE,
-};
-
-static void SetupNewGRFState(Window *w)
-{
-	bool disable_all = WP(w, newgrf_d).sel == NULL || !WP(w, newgrf_d).editable;
-
-	w->SetWidgetDisabledState(SNGRFS_ADD, !WP(w, newgrf_d).editable);
-	w->SetWidgetsDisabledState(disable_all,
-		SNGRFS_REMOVE,
-		SNGRFS_MOVE_UP,
-		SNGRFS_MOVE_DOWN,
-		WIDGET_LIST_END
-	);
-	w->SetWidgetDisabledState(SNGRFS_SET_PARAMETERS, !WP(w, newgrf_d).show_params || disable_all);
-
-	if (!disable_all) {
-		/* All widgets are now enabled, so disable widgets we can't use */
-		if (WP(w, newgrf_d).sel == *WP(w, newgrf_d).list) w->DisableWidget(SNGRFS_MOVE_UP);
-		if (WP(w, newgrf_d).sel->next == NULL) w->DisableWidget(SNGRFS_MOVE_DOWN);
-		if (WP(w, newgrf_d).sel->IsOpenTTDBaseGRF()) w->DisableWidget(SNGRFS_REMOVE);
-	}
-}
-
-
-static void SetupNewGRFWindow(Window *w)
-{
-	const GRFConfig *c;
-	int i;
-
-	for (c = *WP(w, newgrf_d).list, i = 0; c != NULL; c = c->next, i++) {}
-
-	w->vscroll.cap = (w->widget[SNGRFS_FILE_LIST].bottom - w->widget[SNGRFS_FILE_LIST].top) / 14 + 1;
-	SetVScrollCount(w, i);
-	w->SetWidgetDisabledState(SNGRFS_APPLY_CHANGES, !WP(w, newgrf_d).editable);
-}
-
-
-/** Callback function for the newgrf 'apply changes' confirmation window
- * @param w Window which is calling this callback
- * @param confirmed boolean value, true when yes was clicked, false otherwise
- */
-static void NewGRFConfirmationCallback(Window *w, bool confirmed)
-{
-	if (confirmed) {
-		newgrf_d *nd = &WP(w, newgrf_d);
-		GRFConfig *c;
-		int i = 0;
 
-		CopyGRFConfigList(nd->orig_list, *nd->list, false);
-		ReloadNewGRFData();
-
-		/* Show new, updated list */
-		for (c = *nd->list; c != NULL && c != nd->sel; c = c->next, i++) {}
-		CopyGRFConfigList(nd->list, *nd->orig_list, false);
-		for (c = *nd->list; c != NULL && i > 0; c = c->next, i--) {}
-		nd->sel = c;
-
-		w->SetDirty();
-	}
-}
-
-
-static void NewGRFWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			const GRFConfig *c;
-			int i, y;
-
-			SetupNewGRFState(w);
-
-			DrawWindowWidgets(w);
-
-			/* Draw NewGRF list */
-			y = w->widget[SNGRFS_FILE_LIST].top;
-			for (c = *WP(w, newgrf_d).list, i = 0; c != NULL; c = c->next, i++) {
-				if (i >= w->vscroll.pos && i < w->vscroll.pos + w->vscroll.cap) {
-					const char *text = (c->name != NULL && !StrEmpty(c->name)) ? c->name : c->filename;
-					SpriteID pal;
-					byte txtoffset;
+	NewGRFWindow(const WindowDesc *desc, bool editable, bool show_params, bool exec_changes, GRFConfig **config) : Window(desc, 0)
+	{
+		this->resize.step_height = 14;
+		this->sel         = NULL;
+		this->list        = NULL;
+		this->orig_list   = config;
+		this->editable    = editable;
+		this->execute     = exec_changes;
+		this->show_params = show_params;
 
-					/* Pick a colour */
-					switch (c->status) {
-						case GCS_NOT_FOUND:
-						case GCS_DISABLED:
-							pal = PALETTE_TO_RED;
-							break;
-						case GCS_ACTIVATED:
-							pal = PALETTE_TO_GREEN;
-							break;
-						default:
-							pal = PALETTE_TO_BLUE;
-							break;
-					}
+		CopyGRFConfigList(&this->list, *config, false);
 
-					/* Do not show a "not-failure" colour when it actually failed to load */
-					if (pal != PALETTE_TO_RED) {
-						if (HasBit(c->flags, GCF_STATIC)) {
-							pal = PALETTE_TO_GREY;
-						} else if (HasBit(c->flags, GCF_COMPATIBLE)) {
-							pal = PALETTE_TO_ORANGE;
-						}
-					}
+		this->FindWindowPlacementAndResize(desc);
+		this->SetupNewGRFWindow();
+	}
 
-					DrawSprite(SPR_SQUARE, pal, 5, y + 2);
-					if (c->error != NULL) DrawSprite(SPR_WARNING_SIGN, 0, 20, y + 2);
-					txtoffset = c->error != NULL ? 35 : 25;
-					DoDrawStringTruncated(text, txtoffset, y + 3, WP(w, newgrf_d).sel == c ? TC_WHITE : TC_BLACK, w->width - txtoffset - 10);
-					y += 14;
-				}
-			}
-
-			if (WP(w, newgrf_d).sel != NULL) {
-				/* Draw NewGRF file info */
-				const Widget *wi = &w->widget[SNGRFS_NEWGRF_INFO];
-				ShowNewGRFInfo(WP(w, newgrf_d).sel, wi->left + 2, wi->top + 2, wi->right - wi->left - 2, wi->bottom, WP(w, newgrf_d).show_params);
-			}
-
-			break;
+	~NewGRFWindow()
+	{
+		if (!this->execute) {
+			CopyGRFConfigList(this->orig_list, this->list, true);
+			ResetGRFConfig(false);
+			ReloadNewGRFData();
 		}
 
-		case WE_INVALIDATE_DATA:
-			SetupNewGRFWindow(w);
-			break;
-
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case SNGRFS_ADD: { // Add GRF
-					GRFConfig **list = WP(w, newgrf_d).list;
-					Window *w;
-
-					DeleteWindowByClass(WC_SAVELOAD);
-					w = new Window(&_newgrf_add_dlg_desc);
-					w->resize.step_height = 10;
-
-					WP(w, newgrf_add_d).list = list;
-					break;
-				}
-
-				case SNGRFS_REMOVE: { // Remove GRF
-					GRFConfig **pc, *c, *newsel;
-
-					/* Choose the next GRF file to be the selected file */
-					newsel = WP(w, newgrf_d).sel->next;
+		/* Remove the temporary copy of grf-list used in window */
+		ClearGRFConfigList(&this->list);
+	}
 
-					for (pc = WP(w, newgrf_d).list; (c = *pc) != NULL; pc = &c->next) {
-						/* If the new selection is empty (i.e. we're deleting the last item
-						 * in the list, pick the file just before the selected file */
-						if (newsel == NULL && c->next == WP(w, newgrf_d).sel) newsel = c;
-
-						if (c == WP(w, newgrf_d).sel) {
-							*pc = c->next;
-							free(c);
-							break;
-						}
-					}
+	void SetupNewGRFWindow()
+	{
+		const GRFConfig *c;
+		int i;
 
-					WP(w, newgrf_d).sel = newsel;
-					SetupNewGRFWindow(w);
-					w->SetDirty();
-					break;
-				}
-
-				case SNGRFS_MOVE_UP: { // Move GRF up
-					GRFConfig **pc, *c;
-					if (WP(w, newgrf_d).sel == NULL) break;
+		for (c = this->list, i = 0; c != NULL; c = c->next, i++) {}
 
-					for (pc = WP(w, newgrf_d).list; (c = *pc) != NULL; pc = &c->next) {
-						if (c->next == WP(w, newgrf_d).sel) {
-							c->next = WP(w, newgrf_d).sel->next;
-							WP(w, newgrf_d).sel->next = c;
-							*pc = WP(w, newgrf_d).sel;
-							break;
-						}
-					}
-					w->SetDirty();
-					break;
+		this->vscroll.cap = (this->widget[SNGRFS_FILE_LIST].bottom - this->widget[SNGRFS_FILE_LIST].top) / 14 + 1;
+		SetVScrollCount(this, i);
+
+		this->SetWidgetDisabledState(SNGRFS_ADD, !this->editable);
+		this->SetWidgetDisabledState(SNGRFS_APPLY_CHANGES, !this->editable);
+	}
+
+	virtual void OnPaint()
+	{
+		bool disable_all = this->sel == NULL || !this->editable;
+
+		this->SetWidgetsDisabledState(disable_all,
+			SNGRFS_REMOVE,
+			SNGRFS_MOVE_UP,
+			SNGRFS_MOVE_DOWN,
+			WIDGET_LIST_END
+		);
+		this->SetWidgetDisabledState(SNGRFS_SET_PARAMETERS, !this->show_params || disable_all);
+
+		if (!disable_all) {
+			/* All widgets are now enabled, so disable widgets we can't use */
+			if (this->sel == this->list)       this->DisableWidget(SNGRFS_MOVE_UP);
+			if (this->sel->next == NULL)       this->DisableWidget(SNGRFS_MOVE_DOWN);
+			if (this->sel->IsOpenTTDBaseGRF()) this->DisableWidget(SNGRFS_REMOVE);
+		}
+
+		this->DrawWidgets();
+
+		/* Draw NewGRF list */
+		int y = this->widget[SNGRFS_FILE_LIST].top;
+		int i = 0;
+		for (const GRFConfig *c = this->list; c != NULL; c = c->next, i++) {
+			if (i >= this->vscroll.pos && i < this->vscroll.pos + this->vscroll.cap) {
+				const char *text = (c->name != NULL && !StrEmpty(c->name)) ? c->name : c->filename;
+				SpriteID pal;
+				byte txtoffset;
+
+				/* Pick a colour */
+				switch (c->status) {
+					case GCS_NOT_FOUND:
+					case GCS_DISABLED:
+						pal = PALETTE_TO_RED;
+						break;
+					case GCS_ACTIVATED:
+						pal = PALETTE_TO_GREEN;
+						break;
+					default:
+						pal = PALETTE_TO_BLUE;
+						break;
 				}
 
-				case SNGRFS_MOVE_DOWN: { // Move GRF down
-					GRFConfig **pc, *c;
-					if (WP(w, newgrf_d).sel == NULL) break;
-
-					for (pc = WP(w, newgrf_d).list; (c = *pc) != NULL; pc = &c->next) {
-						if (c == WP(w, newgrf_d).sel) {
-							*pc = c->next;
-							c->next = c->next->next;
-							(*pc)->next = c;
-							break;
-						}
+				/* Do not show a "not-failure" colour when it actually failed to load */
+				if (pal != PALETTE_TO_RED) {
+					if (HasBit(c->flags, GCF_STATIC)) {
+						pal = PALETTE_TO_GREY;
+					} else if (HasBit(c->flags, GCF_COMPATIBLE)) {
+						pal = PALETTE_TO_ORANGE;
 					}
-					w->SetDirty();
-					break;
-				}
-
-				case SNGRFS_FILE_LIST: { // Select a GRF
-					GRFConfig *c;
-					uint i = (e->we.click.pt.y - w->widget[SNGRFS_FILE_LIST].top) / 14 + w->vscroll.pos;
-
-					for (c = *WP(w, newgrf_d).list; c != NULL && i > 0; c = c->next, i--) {}
-					WP(w, newgrf_d).sel = c;
-
-					w->SetDirty();
-					break;
 				}
 
-				case SNGRFS_APPLY_CHANGES: // Apply changes made to GRF list
-					if (WP(w, newgrf_d).execute) {
-						ShowQuery(
-							STR_POPUP_CAUTION_CAPTION,
-							STR_NEWGRF_CONFIRMATION_TEXT,
-							w,
-							NewGRFConfirmationCallback
-						);
-					} else {
-						CopyGRFConfigList(WP(w, newgrf_d).orig_list, *WP(w, newgrf_d).list, true);
-						ResetGRFConfig(false);
-						ReloadNewGRFData();
-					}
-					break;
-
-				case SNGRFS_SET_PARAMETERS: { // Edit parameters
-					char buff[512];
-					if (WP(w, newgrf_d).sel == NULL) break;
-
-					GRFBuildParamList(buff, WP(w, newgrf_d).sel, lastof(buff));
-					ShowQueryString(BindCString(buff), STR_NEWGRF_PARAMETER_QUERY, 63, 250, w, CS_ALPHANUMERAL);
-					break;
-				}
+				DrawSprite(SPR_SQUARE, pal, 5, y + 2);
+				if (c->error != NULL) DrawSprite(SPR_WARNING_SIGN, 0, 20, y + 2);
+				txtoffset = c->error != NULL ? 35 : 25;
+				DoDrawStringTruncated(text, txtoffset, y + 3, this->sel == c ? TC_WHITE : TC_BLACK, this->width - txtoffset - 10);
+				y += 14;
 			}
-			break;
+		}
 
-		case WE_ON_EDIT_TEXT:
-			if (e->we.edittext.str != NULL) {
-				/* Parse our new "int list" */
-				GRFConfig *c = WP(w, newgrf_d).sel;
-				c->num_params = parse_intlist(e->we.edittext.str, (int*)c->param, lengthof(c->param));
-
-				/* parse_intlist returns -1 on error */
-				if (c->num_params == (byte)-1) c->num_params = 0;
-
-				w->SetDirty();
-			}
-			break;
+		if (this->sel != NULL) {
+			/* Draw NewGRF file info */
+			const Widget *wi = &this->widget[SNGRFS_NEWGRF_INFO];
+			ShowNewGRFInfo(this->sel, wi->left + 2, wi->top + 2, wi->right - wi->left - 2, wi->bottom, this->show_params);
+		}
+	}
 
-		case WE_DESTROY:
-			if (!WP(w, newgrf_d).execute) {
-				CopyGRFConfigList(WP(w, newgrf_d).orig_list, *WP(w, newgrf_d).list, true);
-				ResetGRFConfig(false);
-				ReloadNewGRFData();
-			}
-			/* Remove the temporary copy of grf-list used in window */
-			ClearGRFConfigList(WP(w, newgrf_d).list);
-			break;
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case SNGRFS_ADD: // Add GRF
+				DeleteWindowByClass(WC_SAVELOAD);
+				new NewGRFAddWindow(&_newgrf_add_dlg_desc, &this->list);
+				break;
 
-		case WE_RESIZE:
-			if (e->we.sizing.diff.x != 0) {
-				ResizeButtons(w, SNGRFS_ADD, SNGRFS_MOVE_DOWN);
-				ResizeButtons(w, SNGRFS_SET_PARAMETERS, SNGRFS_APPLY_CHANGES);
+			case SNGRFS_REMOVE: { // Remove GRF
+				GRFConfig **pc, *c, *newsel;
+
+				/* Choose the next GRF file to be the selected file */
+				newsel = this->sel->next;
+
+				for (pc = &this->list; (c = *pc) != NULL; pc = &c->next) {
+					/* If the new selection is empty (i.e. we're deleting the last item
+					 * in the list, pick the file just before the selected file */
+					if (newsel == NULL && c->next == this->sel) newsel = c;
+
+					if (c == this->sel) {
+						*pc = c->next;
+						free(c);
+						break;
+					}
+				}
+
+				this->sel = newsel;
+				this->SetupNewGRFWindow();
+				this->SetDirty();
+				break;
 			}
-			w->vscroll.cap += e->we.sizing.diff.y / 14;
-			w->widget[SNGRFS_FILE_LIST].data = (w->vscroll.cap << 8) + 1;
-			SetupNewGRFWindow(w);
-			break;
+
+			case SNGRFS_MOVE_UP: { // Move GRF up
+				GRFConfig **pc, *c;
+				if (this->sel == NULL) break;
+
+				for (pc = &this->list; (c = *pc) != NULL; pc = &c->next) {
+					if (c->next == this->sel) {
+						c->next = this->sel->next;
+						this->sel->next = c;
+						*pc = this->sel;
+						break;
+					}
+				}
+				this->SetDirty();
+				break;
+			}
+
+			case SNGRFS_MOVE_DOWN: { // Move GRF down
+				GRFConfig **pc, *c;
+				if (this->sel == NULL) break;
+
+				for (pc = &this->list; (c = *pc) != NULL; pc = &c->next) {
+					if (c == this->sel) {
+						*pc = c->next;
+						c->next = c->next->next;
+						(*pc)->next = c;
+						break;
+					}
+				}
+				this->SetDirty();
+				break;
+			}
+
+			case SNGRFS_FILE_LIST: { // Select a GRF
+				GRFConfig *c;
+				uint i = (pt.y - this->widget[SNGRFS_FILE_LIST].top) / 14 + this->vscroll.pos;
+
+				for (c = this->list; c != NULL && i > 0; c = c->next, i--) {}
+				this->sel = c;
+
+				this->SetDirty();
+				break;
+			}
+
+			case SNGRFS_APPLY_CHANGES: // Apply changes made to GRF list
+				if (this->execute) {
+					ShowQuery(
+						STR_POPUP_CAUTION_CAPTION,
+						STR_NEWGRF_CONFIRMATION_TEXT,
+						this,
+						NewGRFConfirmationCallback
+					);
+				} else {
+					CopyGRFConfigList(this->orig_list, this->list, true);
+					ResetGRFConfig(false);
+					ReloadNewGRFData();
+				}
+				break;
+
+			case SNGRFS_SET_PARAMETERS: { // Edit parameters
+				if (this->sel == NULL) break;
+
+				char buff[512];
+				GRFBuildParamList(buff, this->sel, lastof(buff));
+				ShowQueryString(BindCString(buff), STR_NEWGRF_PARAMETER_QUERY, 63, 250, this, CS_ALPHANUMERAL);
+				break;
+			}
+		}
 	}
-}
+
+	virtual void OnQueryTextFinished(char *str)
+	{
+		if (str == NULL) return;
+
+		/* Parse our new "int list" */
+		GRFConfig *c = this->sel;
+		c->num_params = parse_intlist(str, (int*)c->param, lengthof(c->param));
+
+		/* parse_intlist returns -1 on error */
+		if (c->num_params == (byte)-1) c->num_params = 0;
+
+		this->SetDirty();
+	}
+
+	virtual void OnResize(Point new_size, Point delta)
+	{
+		if (delta.x != 0) {
+			ResizeButtons(this, SNGRFS_ADD, SNGRFS_MOVE_DOWN);
+			ResizeButtons(this, SNGRFS_SET_PARAMETERS, SNGRFS_APPLY_CHANGES);
+		}
+
+		this->vscroll.cap += delta.y / 14;
+		this->widget[SNGRFS_FILE_LIST].data = (this->vscroll.cap << 8) + 1;
+
+		this->SetupNewGRFWindow();
+	}
+
+	virtual void OnInvalidateData(int data = 0)
+	{
+		this->SetupNewGRFWindow();
+	}
+};
 
 /* Widget definition of the manage newgrfs window */
 static const Widget _newgrf_widgets[] = {
@@ -567,9 +551,33 @@
 	WC_GAME_OPTIONS, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
 	_newgrf_widgets,
-	NewGRFWndProc,
 };
 
+/** Callback function for the newgrf 'apply changes' confirmation window
+ * @param w Window which is calling this callback
+ * @param confirmed boolean value, true when yes was clicked, false otherwise
+ */
+static void NewGRFConfirmationCallback(Window *w, bool confirmed)
+{
+	if (confirmed) {
+		NewGRFWindow *nw = dynamic_cast<NewGRFWindow*>(w);
+		GRFConfig *c;
+		int i = 0;
+
+		CopyGRFConfigList(nw->orig_list, nw->list, false);
+		ReloadNewGRFData();
+
+		/* Show new, updated list */
+		for (c = nw->list; c != NULL && c != nw->sel; c = c->next, i++) {}
+		CopyGRFConfigList(&nw->list, *nw->orig_list, false);
+		for (c = nw->list; c != NULL && i > 0; c = c->next, i--) {}
+		nw->sel = c;
+
+		w->SetDirty();
+	}
+}
+
+
 
 /** Setup the NewGRF gui
  * @param editable allow the user to make changes to the grfconfig in the window
@@ -579,23 +587,6 @@
  * @param config pointer to a linked-list of grfconfig's that will be shown */
 void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFConfig **config)
 {
-	static GRFConfig *local = NULL;
-	Window *w;
-
 	DeleteWindowByClass(WC_GAME_OPTIONS);
-	w = new Window(&_newgrf_desc);
-	if (w == NULL) return;
-
-	w->resize.step_height = 14;
-	CopyGRFConfigList(&local, *config, false);
-
-	/* Clear selections */
-	WP(w, newgrf_d).sel         = NULL;
-	WP(w, newgrf_d).list        = &local;
-	WP(w, newgrf_d).orig_list   = config;
-	WP(w, newgrf_d).editable    = editable;
-	WP(w, newgrf_d).execute     = exec_changes;
-	WP(w, newgrf_d).show_params = show_params;
-
-	SetupNewGRFWindow(w);
+	new NewGRFWindow(&_newgrf_desc, editable, show_params, exec_changes, config);
 }
--- a/src/news_func.h	Mon May 19 14:14:33 2008 +0000
+++ b/src/news_func.h	Mon May 19 15:13:58 2008 +0000
@@ -8,9 +8,8 @@
 #include "news_type.h"
 #include "vehicle_type.h"
 
-void AddNewsItem(StringID string, NewsMode mode, NewsFlag flag, NewsType type, NewsCallback callback, uint data_a, uint data_b);
+void AddNewsItem(StringID string, NewsSubtype subtype, uint data_a, uint data_b);
 void NewsLoop();
-void DrawNewsBorder(const Window *w);
 void InitNewsItemStructs();
 
 extern NewsItem _statusbar_news_item;
--- a/src/news_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/news_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -18,6 +18,8 @@
 #include "string_func.h"
 #include "widgets/dropdown_func.h"
 #include "map_func.h"
+#include "statusbar_gui.h"
+#include "player_face.h"
 
 #include "table/sprites.h"
 #include "table/strings.h"
@@ -60,12 +62,6 @@
 static NewsID _oldest_news = 0;             ///< points to first item in fifo queue
 static NewsID _latest_news = INVALID_NEWS;  ///< points to last item in fifo queue
 
-struct news_d {
-	uint16 chat_height;
-	NewsItem *ni;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(news_d));
-
 /** Forced news item.
  * Users can force an item by accessing the history or "last message".
  * If the message being shown was forced by the user, its index is stored in
@@ -73,23 +69,107 @@
 static NewsID _forced_news = INVALID_NEWS;
 
 static uint _total_news = 0; ///< Number of news items in FIFO queue @see _news_items
-
-void DrawNewsNewVehicleAvail(Window *w, const NewsItem *ni);
-void DrawNewsBankrupcy(Window *w, const NewsItem *ni);
 static void MoveToNextItem();
 
-StringID GetNewsStringNewVehicleAvail(const NewsItem *ni);
-StringID GetNewsStringBankrupcy(const NewsItem *ni);
 
-static DrawNewsCallbackProc * const _draw_news_callback[] = {
-	DrawNewsNewVehicleAvail,  ///< DNC_VEHICLEAVAIL
-	DrawNewsBankrupcy,        ///< DNC_BANKRUPCY
+typedef void DrawNewsCallbackProc(struct Window *w, const NewsItem *ni);
+void DrawNewsNewVehicleAvail(Window *w, const NewsItem *ni);
+
+static void DrawNewsBankrupcy(Window *w, const NewsItem *ni)
+{
+	Player *p = GetPlayer((PlayerID)(ni->data_b));
+	DrawPlayerFace(p->face, p->player_color, 2, 23);
+	GfxFillRect(3, 23, 3 + 91, 23 + 118, PALETTE_TO_STRUCT_GREY | (1 << USE_COLORTABLE));
+
+	SetDParam(0, p->index);
+
+	DrawStringMultiCenter(49, 148, STR_7058_PRESIDENT, 94);
+
+	switch (ni->subtype) {
+		case NS_COMPANY_TROUBLE:
+			DrawStringCentered(w->width >> 1, 1, STR_7056_TRANSPORT_COMPANY_IN_TROUBLE, TC_FROMSTRING);
+
+			SetDParam(0, p->index);
+
+			DrawStringMultiCenter(
+				((w->width - 101) >> 1) + 98,
+				90,
+				STR_7057_WILL_BE_SOLD_OFF_OR_DECLARED,
+				w->width - 101);
+			break;
+
+		case NS_COMPANY_MERGER:
+			DrawStringCentered(w->width >> 1, 1, STR_7059_TRANSPORT_COMPANY_MERGER, TC_FROMSTRING);
+			SetDParam(0, ni->params[2]);
+			SetDParam(1, p->index);
+			SetDParam(2, ni->params[4]);
+			DrawStringMultiCenter(
+				((w->width - 101) >> 1) + 98,
+				90,
+				ni->params[4] == 0 ? STR_707F_HAS_BEEN_TAKEN_OVER_BY : STR_705A_HAS_BEEN_SOLD_TO_FOR,
+				w->width - 101);
+			break;
+
+		case NS_COMPANY_BANKRUPT:
+			DrawStringCentered(w->width >> 1, 1, STR_705C_BANKRUPT, TC_FROMSTRING);
+			SetDParam(0, p->index);
+			DrawStringMultiCenter(
+				((w->width - 101) >> 1) + 98,
+				90,
+				STR_705D_HAS_BEEN_CLOSED_DOWN_BY,
+				w->width - 101);
+			break;
+
+		case NS_COMPANY_NEW:
+			DrawStringCentered(w->width >> 1, 1, STR_705E_NEW_TRANSPORT_COMPANY_LAUNCHED, TC_FROMSTRING);
+			SetDParam(0, p->index);
+			SetDParam(1, ni->params[3]);
+			DrawStringMultiCenter(
+				((w->width - 101) >> 1) + 98,
+				90,
+				STR_705F_STARTS_CONSTRUCTION_NEAR,
+				w->width - 101);
+			break;
+
+		default:
+			NOT_REACHED();
+	}
+}
+
+
+/**
+ * Data common to all news items of a given subtype (structure)
+ */
+struct NewsSubtypeData {
+	NewsType type;         ///< News category @see NewsType
+	NewsMode display_mode; ///< Display mode value @see NewsMode
+	NewsFlag flags;        ///< Initial NewsFlags bits @see NewsFlag
+	DrawNewsCallbackProc *callback; ///< Call-back function
 };
 
-extern GetNewsStringCallbackProc * const _get_news_string_callback[];
-GetNewsStringCallbackProc * const _get_news_string_callback[] = {
-	GetNewsStringNewVehicleAvail,  ///< DNC_VEHICLEAVAIL
-	GetNewsStringBankrupcy,        ///< DNC_BANKRUPCY
+/**
+ * Data common to all news items of a given subtype (actual data)
+ */
+static const struct NewsSubtypeData _news_subtype_data[NS_END] = {
+	/* type,             display_mode, flags,                  callback */
+	{ NT_ARRIVAL_PLAYER,  NM_THIN,     NF_VIEWPORT|NF_VEHICLE, NULL                    }, ///< NS_ARRIVAL_PLAYER
+	{ NT_ARRIVAL_OTHER,   NM_THIN,     NF_VIEWPORT|NF_VEHICLE, NULL                    }, ///< NS_ARRIVAL_OTHER
+	{ NT_ACCIDENT,        NM_THIN,     NF_VIEWPORT|NF_TILE,    NULL                    }, ///< NS_ACCIDENT_TILE
+	{ NT_ACCIDENT,        NM_THIN,     NF_VIEWPORT|NF_VEHICLE, NULL                    }, ///< NS_ACCIDENT_VEHICLE
+	{ NT_COMPANY_INFO,    NM_CALLBACK, NF_NONE,                DrawNewsBankrupcy       }, ///< NS_COMPANY_TROUBLE
+	{ NT_COMPANY_INFO,    NM_CALLBACK, NF_NONE,                DrawNewsBankrupcy       }, ///< NS_COMPANY_MERGER
+	{ NT_COMPANY_INFO,    NM_CALLBACK, NF_NONE,                DrawNewsBankrupcy       }, ///< NS_COMPANY_BANKRUPT
+	{ NT_COMPANY_INFO,    NM_CALLBACK, NF_TILE,                DrawNewsBankrupcy       }, ///< NS_COMPANY_NEW
+	{ NT_OPENCLOSE,       NM_THIN,     NF_VIEWPORT|NF_TILE,    NULL                    }, ///< NS_OPENCLOSE
+	{ NT_ECONOMY,         NM_NORMAL,   NF_NONE,                NULL                    }, ///< NS_ECONOMY
+	{ NT_INDUSTRY_PLAYER, NM_THIN,     NF_VIEWPORT|NF_TILE,    NULL                    }, ///< NS_INDUSTRY_PLAYER
+	{ NT_INDUSTRY_OTHER,  NM_THIN,     NF_VIEWPORT|NF_TILE,    NULL                    }, ///< NS_INDUSTRY_OTHER
+	{ NT_INDUSTRY_NOBODY, NM_THIN,     NF_VIEWPORT|NF_TILE,    NULL                    }, ///< NS_INDUSTRY_NOBODY
+	{ NT_ADVICE,          NM_SMALL,    NF_VIEWPORT|NF_VEHICLE, NULL                    }, ///< NS_ADVICE
+	{ NT_NEW_VEHICLES,    NM_CALLBACK, NF_NONE,                DrawNewsNewVehicleAvail }, ///< NS_NEW_VEHICLES
+	{ NT_ACCEPTANCE,      NM_SMALL,    NF_VIEWPORT|NF_TILE,    NULL                    }, ///< NS_ACCEPTANCE
+	{ NT_SUBSIDIES,       NM_NORMAL,   NF_TILE|NF_TILE2,       NULL                    }, ///< NS_SUBSIDIES
+	{ NT_GENERAL,         NM_NORMAL,   NF_TILE,                NULL                    }, ///< NS_GENERAL
 };
 
 /** Initialize the news-items data structures */
@@ -105,148 +185,154 @@
 	_total_news = 0;
 }
 
-void DrawNewsBorder(const Window *w)
-{
-	int left = 0;
-	int right = w->width - 1;
-	int top = 0;
-	int bottom = w->height - 1;
-
-	GfxFillRect(left, top, right, bottom, 0xF);
-
-	GfxFillRect(left, top, left, bottom, 0xD7);
-	GfxFillRect(right, top, right, bottom, 0xD7);
-	GfxFillRect(left, top, right, top, 0xD7);
-	GfxFillRect(left, bottom, right, bottom, 0xD7);
-
-	DrawString(left + 2, top + 1, STR_00C6, TC_FROMSTRING);
-}
-
-static void NewsWindowProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_CREATE: { // If chatbar is open at creation time, we need to go above it
-			const Window *w1 = FindWindowById(WC_SEND_NETWORK_MSG, 0);
-			WP(w, news_d).chat_height = (w1 != NULL) ? w1->height : 0;
-			break;
-		}
-
-		case WE_PAINT: {
-			const NewsItem *ni = WP(w, news_d).ni;
-
-			switch (ni->display_mode) {
-				case NM_NORMAL:
-				case NM_THIN: {
-					DrawNewsBorder(w);
-
-					DrawString(2, 1, STR_00C6, TC_FROMSTRING);
-
-					SetDParam(0, ni->date);
-					DrawStringRightAligned(428, 1, STR_01FF, TC_FROMSTRING);
-
-					if (!(ni->flags & NF_VIEWPORT)) {
-						CopyInDParam(0, ni->params, lengthof(ni->params));
-						DrawStringMultiCenter(215, ni->display_mode == NM_NORMAL ? 76 : 56,
-							ni->string_id, w->width - 4);
-					} else {
-						/* Back up transparency options to draw news view */
-						TransparencyOptionBits to_backup = _transparency_opt;
-						_transparency_opt = 0;
-						DrawWindowViewport(w);
-						_transparency_opt = to_backup;
+struct NewsWindow : Window {
+	uint16 chat_height;
+	NewsItem *ni;
 
-						/* Shade the viewport into gray, or color*/
-						ViewPort *vp = w->viewport;
-						GfxFillRect(vp->left - w->left, vp->top - w->top,
-							vp->left - w->left + vp->width - 1, vp->top - w->top + vp->height - 1,
-							(ni->flags & NF_INCOLOR ? PALETTE_TO_TRANSPARENT : PALETTE_TO_STRUCT_GREY) | (1 << USE_COLORTABLE)
-						);
+	NewsWindow(const WindowDesc *desc, NewsItem *ni) : Window(desc), ni(ni)
+	{
+		const Window *w = FindWindowById(WC_SEND_NETWORK_MSG, 0);
+		this->chat_height = (w != NULL) ? w->height : 0;
 
-						CopyInDParam(0, ni->params, lengthof(ni->params));
-						DrawStringMultiCenter(w->width / 2, 20, ni->string_id, w->width - 4);
-					}
-					break;
-				}
+		this->ni = &_news_items[_forced_news == INVALID_NEWS ? _current_news : _forced_news];
+		this->flags4 |= WF_DISABLE_VP_SCROLL;
 
-				case NM_CALLBACK:
-					_draw_news_callback[ni->callback](w, ni);
-					break;
+		this->FindWindowPlacementAndResize(desc);
+	}
 
-				default:
-					DrawWindowWidgets(w);
-					if (!(ni->flags & NF_VIEWPORT)) {
-						CopyInDParam(0, ni->params, lengthof(ni->params));
-						DrawStringMultiCenter(140, 38, ni->string_id, 276);
+	void DrawNewsBorder()
+	{
+		int left = 0;
+		int right = this->width - 1;
+		int top = 0;
+		int bottom = this->height - 1;
+
+		GfxFillRect(left, top, right, bottom, 0xF);
+
+		GfxFillRect(left, top, left, bottom, 0xD7);
+		GfxFillRect(right, top, right, bottom, 0xD7);
+		GfxFillRect(left, top, right, top, 0xD7);
+		GfxFillRect(left, bottom, right, bottom, 0xD7);
+
+		DrawString(left + 2, top + 1, STR_00C6, TC_FROMSTRING);
+	}
+
+	virtual void OnPaint()
+	{
+		const NewsMode display_mode = _news_subtype_data[this->ni->subtype].display_mode;
+
+		switch (display_mode) {
+			case NM_NORMAL:
+			case NM_THIN: {
+				this->DrawNewsBorder();
+
+				DrawString(2, 1, STR_00C6, TC_FROMSTRING);
+
+				SetDParam(0, this->ni->date);
+				DrawStringRightAligned(428, 1, STR_01FF, TC_FROMSTRING);
+
+				if (!(this->ni->flags & NF_VIEWPORT)) {
+					CopyInDParam(0, this->ni->params, lengthof(this->ni->params));
+					DrawStringMultiCenter(215, display_mode == NM_NORMAL ? 76 : 56,
+						this->ni->string_id, this->width - 4);
+				} else {
+					/* Back up transparency options to draw news view */
+					TransparencyOptionBits to_backup = _transparency_opt;
+					_transparency_opt = 0;
+					this->DrawViewport();
+					_transparency_opt = to_backup;
+
+					/* Shade the viewport into gray, or color*/
+					ViewPort *vp = this->viewport;
+					GfxFillRect(vp->left - this->left, vp->top - this->top,
+						vp->left - this->left + vp->width - 1, vp->top - this->top + vp->height - 1,
+						(this->ni->flags & NF_INCOLOR ? PALETTE_TO_TRANSPARENT : PALETTE_TO_STRUCT_GREY) | (1 << USE_COLORTABLE)
+					);
+
+					CopyInDParam(0, this->ni->params, lengthof(this->ni->params));
+					DrawStringMultiCenter(this->width / 2, 20, this->ni->string_id, this->width - 4);
+				}
+				break;
+			}
+
+			case NM_CALLBACK:
+				this->DrawNewsBorder();
+				(_news_subtype_data[this->ni->subtype].callback)(this, ni);
+				break;
+
+			default:
+				this->DrawWidgets();
+				if (!(this->ni->flags & NF_VIEWPORT)) {
+					CopyInDParam(0, this->ni->params, lengthof(this->ni->params));
+					DrawStringMultiCenter(140, 38, this->ni->string_id, 276);
+				} else {
+					this->DrawViewport();
+					CopyInDParam(0, this->ni->params, lengthof(this->ni->params));
+					DrawStringMultiCenter(this->width / 2, this->height - 16, this->ni->string_id, this->width - 4);
+				}
+				break;
+		}
+	}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case 1:
+				this->ni->duration = 0;
+				delete this;
+				_forced_news = INVALID_NEWS;
+				break;
+
+			case 0:
+				if (this->ni->flags & NF_VEHICLE) {
+					Vehicle *v = GetVehicle(this->ni->data_a);
+					ScrollMainWindowTo(v->x_pos, v->y_pos);
+				} else if (this->ni->flags & NF_TILE) {
+					if (_ctrl_pressed) {
+						ShowExtraViewPortWindow(this->ni->data_a);
+						if (this->ni->flags & NF_TILE2) {
+							ShowExtraViewPortWindow(this->ni->data_b);
+						}
 					} else {
-						DrawWindowViewport(w);
-						CopyInDParam(0, ni->params, lengthof(ni->params));
-						DrawStringMultiCenter(w->width / 2, w->height - 16, ni->string_id, w->width - 4);
-					}
-					break;
-			}
-			break;
-		}
-
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case 1: {
-					NewsItem *ni = WP(w, news_d).ni;
-					delete w;
-					ni->duration = 0;
-					_forced_news = INVALID_NEWS;
-					break;
-				}
-
-				case 0: {
-					NewsItem *ni = WP(w, news_d).ni;
-					if (ni->flags & NF_VEHICLE) {
-						Vehicle *v = GetVehicle(ni->data_a);
-						ScrollMainWindowTo(v->x_pos, v->y_pos);
-					} else if (ni->flags & NF_TILE) {
-						if (_ctrl_pressed) {
-							ShowExtraViewPortWindow(ni->data_a);
-							if (ni->flags & NF_TILE2) {
-								ShowExtraViewPortWindow(ni->data_b);
-							}
-						} else {
-							if (!ScrollMainWindowToTile(ni->data_a) && ni->flags & NF_TILE2) {
-								ScrollMainWindowToTile(ni->data_b);
-							}
+						if (!ScrollMainWindowToTile(this->ni->data_a) && this->ni->flags & NF_TILE2) {
+							ScrollMainWindowToTile(this->ni->data_b);
 						}
 					}
-					break;
 				}
-			}
-			break;
-
-		case WE_KEYPRESS:
-			if (e->we.keypress.keycode == WKC_SPACE) {
-				/* Don't continue. */
-				e->we.keypress.cont = false;
-				delete w;
-			}
-			break;
-
-		case WE_INVALIDATE_DATA: // The chatbar has notified us that is was either created or closed
-			WP(w, news_d).chat_height = e->we.invalidate.data;
-			break;
-
-		case WE_TICK: { // Scroll up newsmessages from the bottom in steps of 4 pixels
-			int y = max(w->top - 4, _screen.height - w->height - 12 - WP(w, news_d).chat_height);
-			if (y == w->top) return;
-
-			if (w->viewport != NULL) {
-				w->viewport->top += y - w->top;
-			}
-
-			int diff = Delta(w->top, y);
-			w->top = y;
-
-			SetDirtyBlocks(w->left, w->top - diff, w->left + w->width, w->top + w->height);
-			break;
+				break;
 		}
 	}
-}
+
+	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+	{
+		if (keycode == WKC_SPACE) {
+			/* Don't continue. */
+			delete this;
+			return ES_HANDLED;
+		}
+		return ES_NOT_HANDLED;
+	}
+
+	virtual void OnInvalidateData(int data)
+	{
+		/* The chatbar has notified us that is was either created or closed */
+		this->chat_height = data;
+	}
+
+	virtual void OnTick()
+	{
+		/* Scroll up newsmessages from the bottom in steps of 4 pixels */
+		int y = max(this->top - 4, _screen.height - this->height - 12 - this->chat_height);
+		if (y == this->top) return;
+
+		if (this->viewport != NULL) this->viewport->top += y - this->top;
+
+		int diff = Delta(this->top, y);
+		this->top = y;
+
+		SetDirtyBlocks(this->left, this->top - diff, this->left + this->width, this->top + this->height);
+	}
+};
 
 /**
  * Return the correct index in the pseudo-fifo
@@ -270,29 +356,14 @@
 
 /**
  * Add a new newsitem to be shown.
- * @param string String to display, can have special values based on parameter \a display_mode
- * @param display_mode, any of the NewsMode enums (NM_)
- * @param flags any of the NewsFlag enums (NF_)
- * @param type news category, any of the NewsType enums (NT_)
- * @param callback news callback function, any of the NewsCallback enums (DNC_)
+ * @param string String to display
+ * @param subtype news category, any of the NewsSubtype enums (NS_)
  * @param data_a news-specific value based on news type
  * @param data_b news-specific value based on news type
  *
- * @note If the display mode is NM_CALLBACK, special news is shown and parameter
- * \a string has a special meaning.
- *  - For DNC_TRAINAVAIL, DNC_ROADAVAIL, DNC_SHIPAVAIL, DNC_AIRCRAFTAVAIL messages: StringID is
- *    the index of the engine that is shown
- *
- *  - For DNC_BANKRUPCY: bytes 0-3 of StringID contains the player that is in trouble,
- *    and 4-7 contains what kind of bankrupcy message is shown.
- *    @see NewsBankrupcy
- *
- * @see NewsMode
- * @see NewsFlag
- * @see NewsType
- * @see NewsCallback
+ * @see NewsSubype
  */
-void AddNewsItem(StringID string, NewsMode display_mode, NewsFlag flags, NewsType type, NewsCallback callback, uint data_a, uint data_b)
+void AddNewsItem(StringID string, NewsSubtype subtype, uint data_a, uint data_b)
 {
 	if (_game_mode == GM_MENU) return;
 
@@ -323,14 +394,12 @@
 	memset(ni, 0, sizeof(*ni));
 
 	ni->string_id = string;
-	ni->display_mode = display_mode;
-	ni->flags = flags;
+	ni->subtype = subtype;
+	ni->flags = _news_subtype_data[subtype].flags;
 
 	/* show this news message in color? */
 	if (_cur_year >= _patches.colored_news_year) ni->flags |= NF_INCOLOR;
 
-	ni->type = type;
-	ni->callback = callback;
 	ni->data_a = data_a;
 	ni->data_b = data_b;
 	ni->date = _date;
@@ -376,7 +445,6 @@
 	WC_NEWS_WINDOW, WC_NONE,
 	WDF_DEF_WIDGET,
 	_news_type13_widgets,
-	NewsWindowProc
 };
 
 static const Widget _news_type2_widgets[] = {
@@ -390,7 +458,6 @@
 	WC_NEWS_WINDOW, WC_NONE,
 	WDF_DEF_WIDGET,
 	_news_type2_widgets,
-	NewsWindowProc
 };
 
 static const Widget _news_type0_widgets[] = {
@@ -406,7 +473,6 @@
 	WC_NEWS_WINDOW, WC_NONE,
 	WDF_DEF_WIDGET,
 	_news_type0_widgets,
-	NewsWindowProc
 };
 
 
@@ -416,16 +482,16 @@
 	ni->flags &= ~NF_FORCE_BIG;
 	ni->duration = 555;
 
-	SoundFx sound = _news_type_data[ni->type].sound;
+	SoundFx sound = _news_type_data[_news_subtype_data[ni->subtype].type].sound;
 	if (sound != 0) SndPlayFx(sound);
 
 	int top = _screen.height;
 	Window *w;
-	switch (ni->display_mode) {
+	switch (_news_subtype_data[ni->subtype].display_mode) {
 		case NM_NORMAL:
 		case NM_CALLBACK:
 			_news_type13_desc.top = top;
-			w = new Window(&_news_type13_desc);
+			w = new NewsWindow(&_news_type13_desc, ni);
 			if (ni->flags & NF_VIEWPORT) {
 				InitializeWindowViewport(w, 2, 58, 426, 110,
 					ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), ZOOM_LVL_NEWS);
@@ -434,7 +500,7 @@
 
 		case NM_THIN:
 			_news_type2_desc.top = top;
-			w = new Window(&_news_type2_desc);
+			w = new NewsWindow(&_news_type2_desc, ni);
 			if (ni->flags & NF_VIEWPORT) {
 				InitializeWindowViewport(w, 2, 58, 426, 70,
 					ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), ZOOM_LVL_NEWS);
@@ -443,7 +509,7 @@
 
 		default:
 			_news_type0_desc.top = top;
-			w = new Window(&_news_type0_desc);
+			w = new NewsWindow(&_news_type0_desc, ni);
 			if (ni->flags & NF_VIEWPORT) {
 				InitializeWindowViewport(w, 3, 17, 274, 47,
 					ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), ZOOM_LVL_NEWS);
@@ -453,9 +519,6 @@
 
 	/*DEBUG(misc, 0, " cur %3d, old %2d, lat %3d, for %3d, tot %2d",
 	  _current_news, _oldest_news, _latest_news, _forced_news, _total_news);*/
-
-	WP(w, news_d).ni = &_news_items[_forced_news == INVALID_NEWS ? _current_news : _forced_news];
-	w->flags4 |= WF_DISABLE_VP_SCROLL;
 }
 
 /** Show news item in the ticker */
@@ -464,8 +527,7 @@
 	if (_news_ticker_sound) SndPlayFx(SND_16_MORSE);
 
 	_statusbar_news_item = *ni;
-	Window *w = FindWindowById(WC_STATUS_BAR, 0);
-	if (w != NULL) WP(w, def_d).data_1 = 360;
+	InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SHOW_TICKER);
 }
 
 
@@ -482,8 +544,7 @@
 
 	/* Ticker message
 	 * Check if the status bar message is still being displayed? */
-	const Window *w = FindWindowById(WC_STATUS_BAR, 0);
-	if (w != NULL && WP(w, const def_d).data_1 > -1280) return false;
+	if (IsNewsTickerShown()) return false;
 
 	/* Newspaper message, decrement duration counter */
 	if (ni->duration != 0) ni->duration--;
@@ -502,21 +563,16 @@
 	if (_current_news != _latest_news) {
 		_current_news = (_current_news == INVALID_NEWS) ? _oldest_news : IncreaseIndex(_current_news);
 		NewsItem *ni = &_news_items[_current_news];
+		const NewsType type = _news_subtype_data[ni->subtype].type;
 
 		/* check the date, don't show too old items */
-		if (_date - _news_type_data[ni->type].age > ni->date) return;
+		if (_date - _news_type_data[type].age > ni->date) return;
 
-		switch (_news_type_data[ni->type].display) {
+		switch (_news_type_data[type].display) {
 			default: NOT_REACHED();
-			case ND_OFF: { // Off - show nothing only a small reminder in the status bar
-				Window *w = FindWindowById(WC_STATUS_BAR, 0);
-
-				if (w != NULL) {
-					WP(w, def_d).data_2 = 91;
-					w->SetDirty();
-				}
+			case ND_OFF: // Off - show nothing only a small reminder in the status bar
+				InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SHOW_REMINDER);
 				break;
-			}
 
 			case ND_SUMMARY: // Summary - show ticker, but if forced big, cascade to full
 				if (!(ni->flags & NF_FORCE_BIG)) {
@@ -607,12 +663,8 @@
 	char buffer[512], buffer2[512];
 	StringID str;
 
-	if (ni->display_mode == NM_CALLBACK) {
-		str = _get_news_string_callback[ni->callback](ni);
-	} else {
-		CopyInDParam(0, ni->params, lengthof(ni->params));
-		str = ni->string_id;
-	}
+	CopyInDParam(0, ni->params, lengthof(ni->params));
+	str = ni->string_id;
 
 	GetString(buffer, str, lastof(buffer));
 	/* Copy the just gotten string to another buffer to remove any formatting
@@ -642,45 +694,56 @@
 }
 
 
-static void MessageHistoryWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			int y = 19;
-
-			SetVScrollCount(w, _total_news);
-			DrawWindowWidgets(w);
-
-			if (_total_news == 0) break;
-			NewsID show = min(_total_news, w->vscroll.cap);
-
-			for (NewsID p = w->vscroll.pos; p < w->vscroll.pos + show; p++) {
-				/* get news in correct order */
-				const NewsItem *ni = &_news_items[getNews(p)];
-
-				SetDParam(0, ni->date);
-				DrawString(4, y, STR_SHORT_DATE, TC_WHITE);
+struct MessageHistoryWindow : Window {
+	MessageHistoryWindow(const WindowDesc *desc) : Window(desc)
+	{
+		this->vscroll.cap = 10;
+		this->vscroll.count = _total_news;
+		this->resize.step_height = 12;
+		this->resize.height = this->height - 12 * 6; // minimum of 4 items in the list, each item 12 high
+		this->resize.step_width = 1;
+		this->resize.width = 200; // can't make window any smaller than 200 pixel
 
-				DrawNewsString(82, y, TC_WHITE, ni, w->width - 95);
-				y += 12;
-			}
-			break;
-		}
+		this->FindWindowPlacementAndResize(desc);
+	}
 
-		case WE_CLICK:
-			if (e->we.click.widget == 3) {
-				int y = (e->we.click.pt.y - 19) / 12;
-				NewsID p = getNews(y + w->vscroll.pos);
+	virtual void OnPaint()
+	{
+		int y = 19;
 
-				if (p != INVALID_NEWS) ShowNewsMessage(p);
-			}
-			break;
+		SetVScrollCount(this, _total_news);
+		this->DrawWidgets();
 
-		case WE_RESIZE:
-			w->vscroll.cap += e->we.sizing.diff.y / 12;
-			break;
+		if (_total_news == 0) return;
+		NewsID show = min(_total_news, this->vscroll.cap);
+
+		for (NewsID p = this->vscroll.pos; p < this->vscroll.pos + show; p++) {
+			/* get news in correct order */
+			const NewsItem *ni = &_news_items[getNews(p)];
+
+			SetDParam(0, ni->date);
+			DrawString(4, y, STR_SHORT_DATE, TC_WHITE);
+
+			DrawNewsString(82, y, TC_WHITE, ni, this->width - 95);
+			y += 12;
+		}
 	}
-}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		if (widget == 3) {
+			int y = (pt.y - 19) / 12;
+			NewsID p = getNews(y + this->vscroll.pos);
+
+			if (p != INVALID_NEWS) ShowNewsMessage(p);
+		}
+	}
+
+	virtual void OnResize(Point new_size, Point delta)
+	{
+		this->vscroll.cap += delta.y / 12;
+	}
+};
 
 static const Widget _message_history_widgets[] = {
 {   WWT_CLOSEBOX,   RESIZE_NONE,    13,     0,    10,     0,    13, STR_00C5,            STR_018B_CLOSE_WINDOW},
@@ -697,24 +760,13 @@
 	WC_MESSAGE_HISTORY, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
 	_message_history_widgets,
-	MessageHistoryWndProc
 };
 
 /** Display window with news messages history */
 void ShowMessageHistory()
 {
 	DeleteWindowById(WC_MESSAGE_HISTORY, 0);
-	Window *w = new Window(&_message_history_desc);
-
-	if (w == NULL) return;
-
-	w->vscroll.cap = 10;
-	w->vscroll.count = _total_news;
-	w->resize.step_height = 12;
-	w->resize.height = w->height - 12 * 6; // minimum of 4 items in the list, each item 12 high
-	w->resize.step_width = 1;
-	w->resize.width = 200; // can't make window any smaller than 200 pixel
-	w->SetDirty();
+	new MessageHistoryWindow(&_message_history_desc);
 }
 
 
@@ -725,101 +777,96 @@
 	WIDGET_NEWSOPT_START_OPTION = 8,  ///< First widget that is part of a group [<] .. [.]
 };
 
-/**
- * Setup the disabled/enabled buttons in the message window
- * If the value is 'off' disable the [<] widget, and enable the [>] one
- * Same-wise for all the others. Starting value of 4 is the first widget
- * group. These are grouped as [<][>] .. [<][>], etc.
- * @param w Window been used
- * @param value to set in the widget
- * @param element index of the group of widget to set
- */
-static void SetMessageButtonStates(Window *w, byte value, int element)
-{
-	element *= NB_WIDG_PER_SETTING;
-
-	w->SetWidgetDisabledState(element + WIDGET_NEWSOPT_START_OPTION, value == 0);
-	w->SetWidgetDisabledState(element + WIDGET_NEWSOPT_START_OPTION + 2, value == 2);
-}
-
-/**
- * Event handler of the Message Options window
- * @param w window pointer
- * @param e event been triggered
- */
-static void MessageOptionsWndProc(Window *w, WindowEvent *e)
-{
-	static const StringID message_opt[] = {STR_OFF, STR_SUMMARY, STR_FULL, INVALID_STRING_ID};
-
-	/* WP(w, def_d).data_1 stores state of the ALL on/off/summary button */
-	switch (e->event) {
-		case WE_CREATE: {
-			NewsDisplay all_val;
-
-			/* Set up the initial disabled buttons in the case of 'off' or 'full' */
-			all_val = _news_type_data[0].display;
-			for (int i = 0; i < NT_END; i++) {
-				SetMessageButtonStates(w, _news_type_data[i].display, i);
-				/* If the value doesn't match the ALL-button value, set the ALL-button value to 'off' */
-				if (_news_type_data[i].display != all_val) all_val = ND_OFF;
-			}
-			/* If all values are the same value, the ALL-button will take over this value */
-			WP(w, def_d).data_1 = all_val;
-			break;
-		}
-
-		case WE_PAINT:
-			if (_news_ticker_sound) w->LowerWidget(WIDGET_NEWSOPT_SOUNDTICKER);
+static const StringID _message_opt[] = {STR_OFF, STR_SUMMARY, STR_FULL, INVALID_STRING_ID};
 
-			w->widget[WIDGET_NEWSOPT_DROP_SUMMARY].data = message_opt[WP(w, def_d).data_1];
-			DrawWindowWidgets(w);
-
-			/* Draw the string of each setting on each button. */
-			for (int i = 0, y = 26; i < NT_END; i++, y += 12) {
-				/* 51 comes from 13 + 89 (left and right of the button)+1, shiefted by one as to get division,
-				 * which will give centered position */
-				DrawStringCentered(51, y + 1, message_opt[_news_type_data[i].display], TC_BLACK);
-			}
-			break;
-
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case WIDGET_NEWSOPT_DROP_SUMMARY: // Dropdown menu for all settings
-					ShowDropDownMenu(w, message_opt, WP(w, def_d).data_1, WIDGET_NEWSOPT_DROP_SUMMARY, 0, 0);
-					break;
-
-				case WIDGET_NEWSOPT_SOUNDTICKER: // Change ticker sound on/off
-					_news_ticker_sound ^= 1;
-					w->ToggleWidgetLoweredState(e->we.click.widget);
-					w->InvalidateWidget(e->we.click.widget);
-					break;
+struct MessageOptionsWindow : Window {
+	int state;
 
-				default: { // Clicked on the [<] .. [>] widgets
-					int wid = e->we.click.widget - WIDGET_NEWSOPT_START_OPTION;
-					if (wid >= 0 && wid < (NB_WIDG_PER_SETTING * NT_END)) {
-						int element = wid / NB_WIDG_PER_SETTING;
-						byte val = (_news_type_data[element].display + ((wid % NB_WIDG_PER_SETTING) ? 1 : -1)) % 3;
+	MessageOptionsWindow(const WindowDesc *desc) : Window(desc)
+	{
+		NewsDisplay all_val;
 
-						SetMessageButtonStates(w, val, element);
-						_news_type_data[element].display = (NewsDisplay)val;
-						w->SetDirty();
-					}
-					break;
+		/* Set up the initial disabled buttons in the case of 'off' or 'full' */
+		all_val = _news_type_data[0].display;
+		for (int i = 0; i < NT_END; i++) {
+			this->SetMessageButtonStates(_news_type_data[i].display, i);
+			/* If the value doesn't match the ALL-button value, set the ALL-button value to 'off' */
+			if (_news_type_data[i].display != all_val) all_val = ND_OFF;
+		}
+		/* If all values are the same value, the ALL-button will take over this value */
+		this->state = all_val;
+	}
+
+	/**
+	 * Setup the disabled/enabled buttons in the message window
+	 * If the value is 'off' disable the [<] widget, and enable the [>] one
+	 * Same-wise for all the others. Starting value of 4 is the first widget
+	 * group. These are grouped as [<][>] .. [<][>], etc.
+	 * @param value to set in the widget
+	 * @param element index of the group of widget to set
+	 */
+	void SetMessageButtonStates(byte value, int element)
+	{
+		element *= NB_WIDG_PER_SETTING;
+
+		this->SetWidgetDisabledState(element + WIDGET_NEWSOPT_START_OPTION, value == 0);
+		this->SetWidgetDisabledState(element + WIDGET_NEWSOPT_START_OPTION + 2, value == 2);
+	}
+
+	virtual void OnPaint()
+	{
+		if (_news_ticker_sound) this->LowerWidget(WIDGET_NEWSOPT_SOUNDTICKER);
+
+		this->widget[WIDGET_NEWSOPT_DROP_SUMMARY].data = _message_opt[this->state];
+		this->DrawWidgets();
+
+		/* Draw the string of each setting on each button. */
+		for (int i = 0, y = 26; i < NT_END; i++, y += 12) {
+			/* 51 comes from 13 + 89 (left and right of the button)+1, shiefted by one as to get division,
+				* which will give centered position */
+			DrawStringCentered(51, y + 1, _message_opt[_news_type_data[i].display], TC_BLACK);
+		}
+	}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case WIDGET_NEWSOPT_DROP_SUMMARY: // Dropdown menu for all settings
+				ShowDropDownMenu(this, _message_opt, this->state, WIDGET_NEWSOPT_DROP_SUMMARY, 0, 0);
+				break;
+
+			case WIDGET_NEWSOPT_SOUNDTICKER: // Change ticker sound on/off
+				_news_ticker_sound ^= 1;
+				this->ToggleWidgetLoweredState(widget);
+				this->InvalidateWidget(widget);
+				break;
+
+			default: { // Clicked on the [<] .. [>] widgets
+				int wid = widget - WIDGET_NEWSOPT_START_OPTION;
+				if (wid >= 0 && wid < (NB_WIDG_PER_SETTING * NT_END)) {
+					int element = wid / NB_WIDG_PER_SETTING;
+					byte val = (_news_type_data[element].display + ((wid % NB_WIDG_PER_SETTING) ? 1 : -1)) % 3;
+
+					this->SetMessageButtonStates(val, element);
+					_news_type_data[element].display = (NewsDisplay)val;
+					this->SetDirty();
 				}
+				break;
 			}
-			break;
-
-		case WE_DROPDOWN_SELECT: // Select all settings for newsmessages
-			WP(w, def_d).data_1 = e->we.dropdown.index;
+		}
+	}
 
-			for (int i = 0; i < NT_END; i++) {
-				SetMessageButtonStates(w, e->we.dropdown.index, i);
-				_news_type_data[i].display = (NewsDisplay)e->we.dropdown.index;
-			}
-			w->SetDirty();
-			break;
+	virtual void OnDropdownSelect(int widget, int index)
+	{
+		this->state = index;
+
+		for (int i = 0; i < NT_END; i++) {
+			this->SetMessageButtonStates(index, i);
+			_news_type_data[i].display = (NewsDisplay)index;
+		}
+		this->SetDirty();
 	}
-}
+};
 
 
 /*
@@ -920,13 +967,12 @@
 	WC_GAME_OPTIONS, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
 	_message_options_widgets,
-	MessageOptionsWndProc
 };
 
 void ShowMessageOptions()
 {
 	DeleteWindowById(WC_GAME_OPTIONS, 0);
-	new Window(&_message_options_desc);
+	new MessageOptionsWindow(&_message_options_desc);
 }
 
 
@@ -961,8 +1007,8 @@
 			 * We also need an update of the current, forced and visible (open window)
 			 * news's as this shifting could change the items they were pointing to */
 			if (_total_news != 0) {
-				Window *w = FindWindowById(WC_NEWS_WINDOW, 0);
-				NewsID visible_news = (w != NULL) ? (NewsID)(WP(w, news_d).ni - _news_items) : INVALID_NEWS;
+				NewsWindow *w = dynamic_cast<NewsWindow*>(FindWindowById(WC_NEWS_WINDOW, 0));
+				NewsID visible_news = (w != NULL) ? (NewsID)(w->ni - _news_items) : INVALID_NEWS;
 
 				for (NewsID i = n;; i = DecreaseIndex(i)) {
 					_news_items[i] = _news_items[DecreaseIndex(i)];
@@ -970,7 +1016,7 @@
 					if (i != _latest_news) {
 						if (i == _current_news) _current_news = IncreaseIndex(_current_news);
 						if (i == _forced_news) _forced_news = IncreaseIndex(_forced_news);
-						if (i == visible_news) WP(w, news_d).ni = &_news_items[IncreaseIndex(visible_news)];
+						if (i == visible_news) w->ni = &_news_items[IncreaseIndex(visible_news)];
 					}
 
 					if (i == _oldest_news) break;
--- a/src/news_type.h	Mon May 19 14:14:33 2008 +0000
+++ b/src/news_type.h	Mon May 19 15:13:58 2008 +0000
@@ -5,7 +5,6 @@
 #ifndef NEWS_TYPE_H
 #define NEWS_TYPE_H
 
-#include "window_type.h"
 #include "date_type.h"
 #include "strings_type.h"
 #include "sound_type.h"
@@ -32,6 +31,31 @@
 };
 
 /**
+ * News subtypes.
+ */
+enum NewsSubtype {
+	NS_ARRIVAL_PLAYER,   ///< NT_ARRIVAL_PLAYER
+	NS_ARRIVAL_OTHER,    ///< NT_ARRIVAL_OTHER
+	NS_ACCIDENT_TILE,    ///< NT_ACCIDENT (tile)
+	NS_ACCIDENT_VEHICLE, ///< NT_ACCIDENT (vehicle)
+	NS_COMPANY_TROUBLE,  ///< NT_COMPANY_INFO (trouble)
+	NS_COMPANY_MERGER,   ///< NT_COMPANY_INFO (merger)
+	NS_COMPANY_BANKRUPT, ///< NT_COMPANY_INFO (bankrupt)
+	NS_COMPANY_NEW,      ///< NT_COMPANY_INFO (new company)
+	NS_OPENCLOSE,        ///< NT_OPENCLOSE
+	NS_ECONOMY,          ///< NT_ECONOMY
+	NS_INDUSTRY_PLAYER,  ///< NT_INDUSTRY_PLAYER
+	NS_INDUSTRY_OTHER,   ///< NT_INDUSTRY_OTHER
+	NS_INDUSTRY_NOBODY,  ///< NT_INDUSTRY_NOBODY
+	NS_ADVICE,           ///< NT_ADVICE
+	NS_NEW_VEHICLES,     ///< NT_NEW_VEHICLES
+	NS_ACCEPTANCE,       ///< NT_ACCEPTANCE
+	NS_SUBSIDIES,        ///< NT_SUBSIDIES
+	NS_GENERAL,          ///< NT_GENERAL
+	NS_END,              ///< end-of-array marker
+};
+
+/**
  * News mode.
  */
 enum NewsMode {
@@ -58,26 +82,6 @@
 
 
 /**
- * Special news items
- */
-enum NewsCallback {
-	DNC_VEHICLEAVAIL  = 0,    ///< Show new vehicle available message. StringID is EngineID
-	DNC_BANKRUPCY     = 1,    ///< Show bankrupcy message. StringID is PlayerID (0-3) and NewsBankrupcy (4-7)
-	DNC_NONE          = 0xFF, ///< No news callback.
-};
-
-/**
- * Kinds of bankrupcy
- * @note These flags are or'd with player index
- */
-enum NewsBankrupcy {
-	NB_BTROUBLE    = (1 << 4), ///< Company is in trouble (warning)
-	NB_BMERGER     = (2 << 4), ///< Company has been bought by another company
-	NB_BBANKRUPT   = (3 << 4), ///< Company has gone bankrupt
-	NB_BNEWCOMPANY = (4 << 4), ///< A new company has been started
-};
-
-/**
  * News display options
  */
 enum NewsDisplay {
@@ -97,22 +101,16 @@
 };
 
 struct NewsItem {
-	StringID string_id;    ///< Message text (sometimes also used for storing other info)
+	StringID string_id;    ///< Message text
 	uint16 duration;       ///< Remaining time for showing this news message
 	Date date;             ///< Date of the news
+	NewsSubtype subtype;   ///< News subtype @see NewsSubtype
 	NewsFlag flags;        ///< NewsFlags bits @see NewsFlag
-	NewsMode display_mode; ///< Display mode value @see NewsMode
-	NewsType type;         ///< News category @see NewsType
-	NewsCallback callback; ///< Call-back function
 
-	uint data_a;           ///< Reference to tile or vehicle
-	uint data_b;           ///< Reference to second tile or vehicle
+	uint data_a;           ///< Custom data 1 (usually tile or vehicle)
+	uint data_b;           ///< Custom data 2
 
 	uint64 params[10];
 };
 
-typedef bool ValidationProc(uint data_a, uint data_b);
-typedef void DrawNewsCallbackProc(Window *w, const NewsItem *ni);
-typedef StringID GetNewsStringCallbackProc(const NewsItem *ni);
-
 #endif /* NEWS_TYPE_H */
--- a/src/oldloader.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/oldloader.cpp	Mon May 19 15:13:58 2008 +0000
@@ -1516,7 +1516,13 @@
 				 * clear it for ourselves and let OTTD's rebuild PBS itself */
 				_m[i].m4 &= 0xF; /* Only keep the lower four bits; upper four is PBS */
 				break;
-			default: break;
+
+			case MP_WATER:
+				if (GetWaterClass(i) == 3) MakeRiver(i, Random());
+				break;
+
+			default:
+				break;
 		}
 	}
 
--- a/src/openttd.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/openttd.cpp	Mon May 19 15:13:58 2008 +0000
@@ -290,7 +290,6 @@
 {
 	/* Dynamic stuff needs to be initialized somewhere... */
 	_town_sort     = NULL;
-	_industry_sort = NULL;
 	_industry_mngr.ResetMapping();
 	_industile_mngr.ResetMapping();
 }
@@ -327,7 +326,6 @@
 	_Engine_pool.CleanPool();
 
 	free((void*)_town_sort);
-	free((void*)_industry_sort);
 
 	free(_config_file);
 
@@ -1344,42 +1342,17 @@
 	UpdateAllTownVirtCoords();
 	UpdateAllWaypointSigns();
 
-	/* Recalculate */
-	Group *g;
-	FOR_ALL_GROUPS(g) {
-		g->num_engines = CallocT<uint16>(GetEnginePoolSize());
-
-		const Vehicle *v;
-		FOR_ALL_VEHICLES(v) {
-			if (!IsEngineCountable(v)) continue;
-
-			if (v->group_id != g->index || v->type != g->vehicle_type || v->owner != g->owner) continue;
-
-			g->num_engines[v->engine_type]++;
+	Player *p;
+	FOR_ALL_PLAYERS(p) {
+		/* For each player, verify (while loading a scenario) that the inauguration date is the current year and set it
+		 * accordingly if it is not the case.  No need to set it on players that are not been used already,
+		 * thus the MIN_YEAR (which is really nothing more than Zero, initialized value) test */
+		if (_file_to_saveload.filetype == FT_SCENARIO && p->inaugurated_year != MIN_YEAR) {
+			p->inaugurated_year = _cur_year;
 		}
 	}
 
-	/* Set up the engine count for all players */
-	Player *players[MAX_PLAYERS];
-	const Vehicle *v;
-
-	for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
-		players[i] = GetPlayer(i);
-
-		/* For each player, verify (while loading a scenario) that the inauguration date is the current year and set it
-		 * accordingly if it is not the case.  No need to set it on players that are not been used already,
-		 * thus the MIN_YEAR (which is really nothing more than Zero, initialized value) test */
-		if (_file_to_saveload.filetype == FT_SCENARIO && players[i]->inaugurated_year != MIN_YEAR)
-			players[i]->inaugurated_year = _cur_year;
-
-		free(players[i]->num_engines);
-		players[i]->num_engines = CallocT<uint16>(GetEnginePoolSize());
-	}
-
-	FOR_ALL_VEHICLES(v) {
-		if (!IsEngineCountable(v)) continue;
-		players[v->owner]->num_engines[v->engine_type]++;
-	}
+	SetCachedEngineCounts();
 
 	return true;
 }
@@ -2434,9 +2407,7 @@
 
 			/* Move river flag and update canals to use water class */
 			if (IsTileType(t, MP_WATER)) {
-				if (_m[t].m5 == 2) {
-					MakeRiver(t, Random());
-				} else {
+				if (GetWaterClass(t) != WATER_CLASS_RIVER) {
 					if (IsWater(t)) {
 						Owner o = GetTileOwner(t);
 						if (o == OWNER_WATER) {
@@ -2574,11 +2545,14 @@
 	ResetVehiclePosHash();
 	AfterLoadVehicles(false);
 	StartupEngines();
+	SetCachedEngineCounts();
 	/* update station and waypoint graphics */
 	AfterLoadWaypoints();
 	AfterLoadStations();
 	/* Check and update house and town values */
 	UpdateHousesAndTowns();
+	/* Update livery selection windows */
+	for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) InvalidateWindowData(WC_PLAYER_COLOR, i, _loaded_newgrf_features.has_2CC);
 	/* redraw the whole screen */
 	MarkWholeScreenDirty();
 }
--- a/src/order_cmd.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/order_cmd.cpp	Mon May 19 15:13:58 2008 +0000
@@ -546,7 +546,7 @@
 		}
 
 		/* Make sure to rebuild the whole list */
-		RebuildVehicleLists();
+		InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
 	}
 
 	return CommandCost();
@@ -561,7 +561,7 @@
 	if (flags & DC_EXEC) {
 		DeleteVehicleOrders(dst);
 		InvalidateVehicleOrder(dst);
-		RebuildVehicleLists();
+		InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
 	}
 	return CommandCost();
 }
@@ -673,7 +673,7 @@
 			cur_order_id++;
 		}
 
-		RebuildVehicleLists();
+		InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
 	}
 
 	return CommandCost();
@@ -811,7 +811,7 @@
 		}
 
 		/* Make sure to rebuild the whole list */
-		RebuildVehicleLists();
+		InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
 	}
 
 	return CommandCost();
@@ -1075,7 +1075,7 @@
 				InvalidateVehicleOrder(dst);
 				InvalidateVehicleOrder(src);
 
-				RebuildVehicleLists();
+				InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
 			}
 		} break;
 
@@ -1134,7 +1134,7 @@
 
 				InvalidateVehicleOrder(dst);
 
-				RebuildVehicleLists();
+				InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
 			}
 		} break;
 
@@ -1444,7 +1444,7 @@
 		SetDParam(0, v->unitnumber);
 		AddNewsItem(
 			message,
-			NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, DNC_NONE,
+			NS_ADVICE,
 			v->index,
 			0
 		);
--- a/src/order_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/order_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -58,60 +58,6 @@
 	ORDER_WIDGET_RESIZE,
 };
 
-/** Under what reason are we using the PlaceObject functionality? */
-enum OrderPlaceObjectState {
-	OPOS_GOTO,
-	OPOS_CONDITIONAL,
-};
-
-struct order_d {
-	int sel;
-	OrderPlaceObjectState goto_type;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(order_d));
-
-/**
- * Return the memorised selected order.
- *
- * @param w current window
- * @return the memorised order if it is a vaild one
- *  else return the number of orders
- */
-static int OrderGetSel(const Window *w)
-{
-	const Vehicle *v = GetVehicle(w->window_number);
-	int num = WP(w, order_d).sel;
-
-	return (num >= 0 && num < v->num_orders) ? num : v->num_orders;
-}
-
-/**
- * Calculate the selected order.
- * The calculation is based on the relative (to the window) y click position and
- *  the position of the scrollbar.
- *
- * @param w current window
- * @param y Y-value of the click relative to the window origin
- * @param v current vehicle
- * @return the new selected order if the order is valid else return that
- *  an invalid one has been selected.
- */
-static int GetOrderFromOrderWndPt(Window *w, int y, const Vehicle *v)
-{
-	/*
-	 * Calculation description:
-	 * 15 = 14 (w->widget[ORDER_WIDGET_ORDER_LIST].top) + 1 (frame-line)
-	 * 10 = order text hight
-	 */
-	int sel = (y - w->widget[ORDER_WIDGET_ORDER_LIST].top - 1) / 10;
-
-	if ((uint)sel >= w->vscroll.cap) return INVALID_ORDER;
-
-	sel += w->vscroll.pos;
-
-	return (sel <= v->num_orders && sel >= 0) ? sel : INVALID_ORDER;
-}
-
 /** Order load types that could be given to station orders. */
 static const StringID _station_load_types[][5] = {
 	{
@@ -312,121 +258,6 @@
 }
 
 
-static void DrawOrdersWindow(Window *w)
-{
-	const Vehicle *v = GetVehicle(w->window_number);
-	bool shared_orders = v->IsOrderListShared();
-
-	SetVScrollCount(w, v->num_orders + 1);
-
-	int sel = OrderGetSel(w);
-	const Order *order = GetVehicleOrder(v, sel);
-
-	if (v->owner == _local_player) {
-		/* Set the strings for the dropdown boxes. */
-		w->widget[ORDER_WIDGET_NON_STOP].data        = _order_non_stop_drowdown[order == NULL ? 0 : order->GetNonStopType()];
-		w->widget[ORDER_WIDGET_FULL_LOAD].data       = _order_full_load_drowdown[order == NULL ? 0 : order->GetLoadType()];
-		w->widget[ORDER_WIDGET_UNLOAD].data          = _order_unload_drowdown[order == NULL ? 0 : order->GetUnloadType()];
-		w->widget[ORDER_WIDGET_COND_VARIABLE].data   = _order_conditional_variable[order == NULL ? 0 : order->GetConditionVariable()];
-		w->widget[ORDER_WIDGET_COND_COMPARATOR].data = _order_conditional_condition[order == NULL ? 0 : order->GetConditionComparator()];
-
-		/* skip */
-		w->SetWidgetDisabledState(ORDER_WIDGET_SKIP, v->num_orders <= 1);
-
-		/* delete */
-		w->SetWidgetDisabledState(ORDER_WIDGET_DELETE,
-				(uint)v->num_orders + ((shared_orders || v->num_orders != 0) ? 1 : 0) <= (uint)WP(w, order_d).sel);
-
-		/* non-stop only for trains */
-		w->SetWidgetDisabledState(ORDER_WIDGET_NON_STOP,  (v->type != VEH_TRAIN && v->type != VEH_ROAD) || order == NULL);
-		w->SetWidgetDisabledState(ORDER_WIDGET_FULL_LOAD, order == NULL || (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) != 0); // full load
-		w->SetWidgetDisabledState(ORDER_WIDGET_UNLOAD,    order == NULL || (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) != 0); // unload
-		/* Disable list of vehicles with the same shared orders if there is no list */
-		w->SetWidgetDisabledState(ORDER_WIDGET_SHARED_ORDER_LIST, !shared_orders || v->orders == NULL);
-		w->SetWidgetDisabledState(ORDER_WIDGET_REFIT,     order == NULL); // Refit
-		w->SetWidgetDisabledState(ORDER_WIDGET_SERVICE,   order == NULL); // Refit
-		w->HideWidget(ORDER_WIDGET_REFIT); // Refit
-		w->HideWidget(ORDER_WIDGET_SERVICE); // Service
-
-		w->HideWidget(ORDER_WIDGET_COND_VARIABLE);
-		w->HideWidget(ORDER_WIDGET_COND_COMPARATOR);
-		w->HideWidget(ORDER_WIDGET_COND_VALUE);
-	}
-
-	w->ShowWidget(ORDER_WIDGET_NON_STOP);
-	w->ShowWidget(ORDER_WIDGET_UNLOAD);
-	w->ShowWidget(ORDER_WIDGET_FULL_LOAD);
-
-	if (order != NULL) {
-		switch (order->GetType()) {
-			case OT_GOTO_STATION:
-				if (!GetStation(order->GetDestination())->IsBuoy()) break;
-				/* Fall-through */
-
-			case OT_GOTO_WAYPOINT:
-				w->DisableWidget(ORDER_WIDGET_FULL_LOAD);
-				w->DisableWidget(ORDER_WIDGET_UNLOAD);
-				break;
-
-			case OT_GOTO_DEPOT:
-				w->DisableWidget(ORDER_WIDGET_FULL_LOAD);
-
-				/* Remove unload and replace it with refit */
-				w->HideWidget(ORDER_WIDGET_UNLOAD);
-				w->ShowWidget(ORDER_WIDGET_REFIT);
-				w->HideWidget(ORDER_WIDGET_FULL_LOAD);
-				w->ShowWidget(ORDER_WIDGET_SERVICE);
-				break;
-
-			case OT_CONDITIONAL: {
-				w->HideWidget(ORDER_WIDGET_NON_STOP);
-				w->HideWidget(ORDER_WIDGET_UNLOAD);
-				w->HideWidget(ORDER_WIDGET_FULL_LOAD);
-				w->ShowWidget(ORDER_WIDGET_COND_VARIABLE);
-				w->ShowWidget(ORDER_WIDGET_COND_COMPARATOR);
-				w->ShowWidget(ORDER_WIDGET_COND_VALUE);
-
-				OrderConditionVariable ocv = order->GetConditionVariable();
-				w->SetWidgetDisabledState(ORDER_WIDGET_COND_COMPARATOR, ocv == OCV_UNCONDITIONALLY);
-				w->SetWidgetDisabledState(ORDER_WIDGET_COND_VALUE, ocv == OCV_REQUIRES_SERVICE || ocv == OCV_UNCONDITIONALLY);
-
-				uint value = order->GetConditionValue();
-				if (order->GetConditionVariable() == OCV_MAX_SPEED) value = ConvertSpeedToDisplaySpeed(value);
-				SetDParam(1, value);
-			} break;
-
-			default: // every other orders
-				w->DisableWidget(ORDER_WIDGET_NON_STOP);
-				w->DisableWidget(ORDER_WIDGET_FULL_LOAD);
-				w->DisableWidget(ORDER_WIDGET_UNLOAD);
-		}
-	}
-
-	SetDParam(0, v->index);
-	DrawWindowWidgets(w);
-
-	int y = 15;
-
-	int i = w->vscroll.pos;
-	order = GetVehicleOrder(v, i);
-	StringID str;
-	while (order != NULL) {
-		/* Don't draw anything if it extends past the end of the window. */
-		if (i - w->vscroll.pos >= w->vscroll.cap) break;
-
-		DrawOrderString(v, order, i, y, i == WP(w, order_d).sel, false);
-		y += 10;
-
-		i++;
-		order = order->next;
-	}
-
-	if (i - w->vscroll.pos < w->vscroll.cap) {
-		str = shared_orders ? STR_END_OF_SHARED_ORDERS : STR_882A_END_OF_ORDERS;
-		DrawString(2, y, str, (i == WP(w, order_d).sel) ? TC_WHITE : TC_BLACK);
-	}
-}
-
 static Order GetOrderCmdFromTile(const Vehicle *v, TileIndex tile)
 {
 	Order order;
@@ -510,548 +341,689 @@
 	return order;
 }
 
-static bool HandleOrderVehClick(const Vehicle *v, const Vehicle *u, Window *w)
-{
-	if (u->type != v->type) return false;
+struct OrdersWindow : public Window {
+private:
+	/** Under what reason are we using the PlaceObject functionality? */
+	enum OrderPlaceObjectState {
+		OPOS_GOTO,
+		OPOS_CONDITIONAL,
+	};
 
-	if (!u->IsPrimaryVehicle()) {
-		u = u->First();
-		if (!u->IsPrimaryVehicle()) return false;
-	}
+	int selected_order;
+	OrderPlaceObjectState goto_type;
+	const Vehicle *vehicle;
 
-	/* v is vehicle getting orders. Only copy/clone orders if vehicle doesn't have any orders yet
-	 * obviously if you press CTRL on a non-empty orders vehicle you know what you are doing */
-	if (v->num_orders != 0 && _ctrl_pressed == 0) return false;
-
-	if (DoCommandP(v->tile, v->index | (u->index << 16), _ctrl_pressed ? CO_SHARE : CO_COPY, NULL,
-		_ctrl_pressed ? CMD_CLONE_ORDER | CMD_MSG(STR_CANT_SHARE_ORDER_LIST) : CMD_CLONE_ORDER | CMD_MSG(STR_CANT_COPY_ORDER_LIST))) {
-		WP(w, order_d).sel = -1;
-		ResetObjectToPlace();
+	/**
+	 * Return the memorised selected order.
+	 * @return the memorised order if it is a vaild one
+	 *  else return the number of orders
+	 */
+	int OrderGetSel()
+	{
+		int num = this->selected_order;
+		return (num >= 0 && num < vehicle->num_orders) ? num : vehicle->num_orders;
 	}
 
-	return true;
-}
-
-static void OrdersPlaceObj(const Vehicle *v, TileIndex tile, Window *w)
-{
-	/* check if we're clicking on a vehicle first.. clone orders in that case. */
-	const Vehicle *u = CheckMouseOverVehicle();
-	if (u != NULL && HandleOrderVehClick(v, u, w)) return;
-
-	const Order cmd = GetOrderCmdFromTile(v, tile);
-	if (!cmd.IsValid()) return;
-
-	if (DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), cmd.Pack(), NULL, CMD_INSERT_ORDER | CMD_MSG(STR_8833_CAN_T_INSERT_NEW_ORDER))) {
-		if (WP(w, order_d).sel != -1) WP(w, order_d).sel++;
-		ResetObjectToPlace();
-	}
-}
+	/**
+	 * Calculate the selected order.
+	 * The calculation is based on the relative (to the window) y click position and
+	 *  the position of the scrollbar.
+	 *
+	 * @param y Y-value of the click relative to the window origin
+	 * @param v current vehicle
+	 * @return the new selected order if the order is valid else return that
+	 *  an invalid one has been selected.
+	 */
+	int GetOrderFromPt(int y)
+	{
+		/*
+		 * Calculation description:
+		 * 15 = 14 (w->widget[ORDER_WIDGET_ORDER_LIST].top) + 1 (frame-line)
+		 * 10 = order text hight
+		 */
+		int sel = (y - this->widget[ORDER_WIDGET_ORDER_LIST].top - 1) / 10;
 
-/**
- * Handle the click on the goto button.
- *
- * @param w current window
- * @param v current vehicle
- */
-static void OrderClick_Goto(Window *w, const Vehicle *v, int i)
-{
-	w->InvalidateWidget(ORDER_WIDGET_GOTO);
-	w->ToggleWidgetLoweredState(ORDER_WIDGET_GOTO);
-	if (w->IsWidgetLowered(ORDER_WIDGET_GOTO)) {
-		_place_clicked_vehicle = NULL;
-		SetObjectToPlaceWnd(ANIMCURSOR_PICKSTATION, PAL_NONE, VHM_RECT, w);
-		WP(w, order_d).goto_type = OPOS_GOTO;
-	} else {
-		ResetObjectToPlace();
-	}
-}
+		if ((uint)sel >= this->vscroll.cap) return INVALID_ORDER;
 
-/**
- * Handle the click on the full load button.
- *
- * @param w current window
- * @param v current vehicle
- * @param load_type the way to load.
- */
-static void OrderClick_FullLoad(Window *w, const Vehicle *v, int load_type)
-{
-	VehicleOrderID sel_ord = OrderGetSel(w);
-	const Order *order = GetVehicleOrder(v, sel_ord);
+		sel += this->vscroll.pos;
 
-	if (order->GetLoadType() == load_type) return;
-
-	if (load_type < 0) {
-		switch (order->GetLoadType()) {
-			case OLF_LOAD_IF_POSSIBLE: load_type = OLFB_FULL_LOAD;       break;
-			case OLFB_FULL_LOAD:       load_type = OLF_FULL_LOAD_ANY;    break;
-			case OLF_FULL_LOAD_ANY:    load_type = OLFB_NO_LOAD;         break;
-			case OLFB_NO_LOAD:         load_type = OLF_LOAD_IF_POSSIBLE; break;
-			default: NOT_REACHED();
-		}
+		return (sel <= vehicle->num_orders && sel >= 0) ? sel : INVALID_ORDER;
 	}
-	DoCommandP(v->tile, v->index + (sel_ord << 16), MOF_LOAD | (load_type << 4), NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
-}
-
-/**
- * Handle the click on the service.
- *
- * @param w current window
- * @param v current vehicle
- */
-static void OrderClick_Service(Window *w, const Vehicle *v, int i)
-{
-	DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), MOF_DEPOT_ACTION, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
-}
-
-/**
- * Handle the click on the service in nearest depot button.
- *
- * @param w current window
- * @param v current vehicle
- */
-static void OrderClick_NearestDepot(Window *w, const Vehicle *v, int i)
-{
-	Order order;
-	order.next = NULL;
-	order.index = 0;
-	order.MakeGoToDepot(0, ODTFB_PART_OF_ORDERS);
-	order.SetDepotActionType(ODATFB_NEAREST_DEPOT);
-
-	DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), order.Pack(), NULL, CMD_INSERT_ORDER | CMD_MSG(STR_8833_CAN_T_INSERT_NEW_ORDER));
-}
 
-/**
- * Handle the click on the conditional order button.
- *
- * @param w current window
- * @param v current vehicle
- */
-static void OrderClick_Conditional(Window *w, const Vehicle *v, int i)
-{
-	w->InvalidateWidget(ORDER_WIDGET_GOTO);
-	w->LowerWidget(ORDER_WIDGET_GOTO);
-	SetObjectToPlaceWnd(ANIMCURSOR_PICKSTATION, PAL_NONE, VHM_RECT, w);
-	WP(w, order_d).goto_type = OPOS_CONDITIONAL;
-}
+	bool HandleOrderVehClick(const Vehicle *u)
+	{
+		if (u->type != this->vehicle->type) return false;
 
-/**
- * Handle the click on the unload button.
- *
- * @param w current window
- * @param v current vehicle
- */
-static void OrderClick_Unload(Window *w, const Vehicle *v, int unload_type)
-{
-	VehicleOrderID sel_ord = OrderGetSel(w);
-	const Order *order = GetVehicleOrder(v, sel_ord);
+		if (!u->IsPrimaryVehicle()) {
+			u = u->First();
+			if (!u->IsPrimaryVehicle()) return false;
+		}
 
-	if (order->GetUnloadType() == unload_type) return;
+		/* v is vehicle getting orders. Only copy/clone orders if vehicle doesn't have any orders yet
+		 * obviously if you press CTRL on a non-empty orders vehicle you know what you are doing */
+		if (this->vehicle->num_orders != 0 && _ctrl_pressed == 0) return false;
 
-	if (unload_type < 0) {
-		switch (order->GetUnloadType()) {
-			case OUF_UNLOAD_IF_POSSIBLE: unload_type = OUFB_UNLOAD;            break;
-			case OUFB_UNLOAD:            unload_type = OUFB_TRANSFER;          break;
-			case OUFB_TRANSFER:          unload_type = OUFB_NO_UNLOAD;         break;
-			case OUFB_NO_UNLOAD:         unload_type = OUF_UNLOAD_IF_POSSIBLE; break;
-			default: NOT_REACHED();
+		if (DoCommandP(this->vehicle->tile, this->vehicle->index | (u->index << 16), _ctrl_pressed ? CO_SHARE : CO_COPY, NULL,
+			_ctrl_pressed ? CMD_CLONE_ORDER | CMD_MSG(STR_CANT_SHARE_ORDER_LIST) : CMD_CLONE_ORDER | CMD_MSG(STR_CANT_COPY_ORDER_LIST))) {
+			this->selected_order = -1;
+			ResetObjectToPlace();
+		}
+
+		return true;
+	}
+
+	/**
+	 * Handle the click on the goto button.
+	 *
+	 * @param w current window
+	 */
+	static void OrderClick_Goto(OrdersWindow *w, int i)
+	{
+		w->InvalidateWidget(ORDER_WIDGET_GOTO);
+		w->ToggleWidgetLoweredState(ORDER_WIDGET_GOTO);
+		if (w->IsWidgetLowered(ORDER_WIDGET_GOTO)) {
+			_place_clicked_vehicle = NULL;
+			SetObjectToPlaceWnd(ANIMCURSOR_PICKSTATION, PAL_NONE, VHM_RECT, w);
+			w->goto_type = OPOS_GOTO;
+		} else {
+			ResetObjectToPlace();
 		}
 	}
 
-	DoCommandP(v->tile, v->index + (sel_ord << 16), MOF_UNLOAD | (unload_type << 4), NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
-}
+	/**
+	 * Handle the click on the full load button.
+	 *
+	 * @param w current window
+	 * @param load_type the way to load.
+	 */
+	static void OrderClick_FullLoad(OrdersWindow *w, int load_type)
+	{
+		VehicleOrderID sel_ord = w->OrderGetSel();
+		const Order *order = GetVehicleOrder(w->vehicle, sel_ord);
 
-/**
- * Handle the click on the nonstop button.
- *
- * @param w current window
- * @param v current vehicle
- * @param non_stop what non-stop type to use; -1 to use the 'next' one.
- */
-static void OrderClick_Nonstop(Window *w, const Vehicle *v, int non_stop)
-{
-	VehicleOrderID sel_ord = OrderGetSel(w);
-	const Order *order = GetVehicleOrder(v, sel_ord);
+		if (order == NULL || order->GetLoadType() == load_type) return;
 
-	if (order->GetNonStopType() == non_stop) return;
-
-	/* Keypress if negative, so 'toggle' to the next */
-	if (non_stop < 0) {
-		non_stop = (order->GetNonStopType() + 1) % ONSF_END;
+		if (load_type < 0) {
+			switch (order->GetLoadType()) {
+				case OLF_LOAD_IF_POSSIBLE: load_type = OLFB_FULL_LOAD;       break;
+				case OLFB_FULL_LOAD:       load_type = OLF_FULL_LOAD_ANY;    break;
+				case OLF_FULL_LOAD_ANY:    load_type = OLFB_NO_LOAD;         break;
+				case OLFB_NO_LOAD:         load_type = OLF_LOAD_IF_POSSIBLE; break;
+				default: NOT_REACHED();
+			}
+		}
+		DoCommandP(w->vehicle->tile, w->vehicle->index + (sel_ord << 16), MOF_LOAD | (load_type << 4), NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
 	}
 
-	DoCommandP(v->tile, v->index + (sel_ord << 16), MOF_NON_STOP | non_stop << 4,  NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
-}
-
-/**
- * Handle the click on the transfer button.
- *
- * @param w current window
- * @param v current vehicle
- */
-static void OrderClick_Transfer(Window *w, const Vehicle *v, int i)
-{
-	VehicleOrderID sel_ord = OrderGetSel(w);
-	const Order *order = GetVehicleOrder(v, sel_ord);
-
-	DoCommandP(v->tile, v->index + (sel_ord << 16), MOF_UNLOAD | ((order->GetUnloadType() & ~OUFB_NO_UNLOAD) ^ OUFB_TRANSFER) << 4, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
-}
-
-/**
- * Handle the click on the skip button.
- * If ctrl is pressed skip to selected order.
- *  Else skip to current order + 1
- *
- * @param w current window
- * @param v current vehicle
- */
-static void OrderClick_Skip(Window *w, const Vehicle *v, int i)
-{
-	/* Don't skip when there's nothing to skip */
-	if (_ctrl_pressed && v->cur_order_index == OrderGetSel(w)) return;
-
-	DoCommandP(v->tile, v->index, _ctrl_pressed ? OrderGetSel(w) : ((v->cur_order_index + 1) % v->num_orders),
-			NULL, CMD_SKIP_TO_ORDER | CMD_MSG(_ctrl_pressed ? STR_CAN_T_SKIP_TO_ORDER : STR_CAN_T_SKIP_ORDER));
-}
-
-/**
- * Handle the click on the unload button.
- *
- * @param w current window
- * @param v current vehicle
- */
-static void OrderClick_Delete(Window *w, const Vehicle *v, int i)
-{
-	DoCommandP(v->tile, v->index, OrderGetSel(w), NULL, CMD_DELETE_ORDER | CMD_MSG(STR_8834_CAN_T_DELETE_THIS_ORDER));
-}
-
-/**
- * Handle the click on the refit button.
- * If ctrl is pressed cancel refitting.
- *  Else show the refit window.
- *
- * @param w current window
- * @param v current vehicle
- */
-static void OrderClick_Refit(Window *w, const Vehicle *v, int i)
-{
-	if (_ctrl_pressed) {
-		/* Cancel refitting */
-		DoCommandP(v->tile, v->index, (WP(w, order_d).sel << 16) | (CT_NO_REFIT << 8) | CT_NO_REFIT, NULL, CMD_ORDER_REFIT);
-	} else {
-		ShowVehicleRefitWindow(v, WP(w, order_d).sel);
+	/**
+	 * Handle the click on the service.
+	 *
+	 * @param w current window
+	 */
+	static void OrderClick_Service(OrdersWindow *w, int i)
+	{
+		DoCommandP(w->vehicle->tile, w->vehicle->index + (w->OrderGetSel() << 16), MOF_DEPOT_ACTION, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
 	}
-}
-
-typedef void OnButtonVehClick(Window *w, const Vehicle *v, int i);
-
-/**
- * Keycode function mapping.
- *
- * @see _order_keycodes[]
- * @note Keep them allways in sync with _order_keycodes[]!
- */
-static OnButtonVehClick* const _order_button_proc[] = {
-	OrderClick_Skip,
-	OrderClick_Delete,
-	OrderClick_Nonstop,
-	OrderClick_Goto,
-	OrderClick_FullLoad,
-	OrderClick_Unload,
-	OrderClick_Transfer,
-	OrderClick_Service,
-};
 
-static const uint16 _order_keycodes[] = {
-	'D', //skip order
-	'F', //delete order
-	'G', //non-stop
-	'H', //goto order
-	'J', //full load
-	'K'  //unload
-};
-
-static void OrdersWndProc(Window *w, WindowEvent *e)
-{
-	const Vehicle *v = GetVehicle(w->window_number);
-
-	switch (e->event) {
-		case WE_CREATE:
-			if (_patches.timetabling) {
-				w->widget[ORDER_WIDGET_CAPTION].right -= 61;
-			} else {
-				w->HideWidget(ORDER_WIDGET_TIMETABLE_VIEW);
-			}
-
-			break;
-
-		case WE_PAINT:
-			DrawOrdersWindow(w);
-			break;
-
-		case WE_CLICK:
-			if (w->widget[e->we.click.widget].type != WWT_DROPDOWN) HideDropDownMenu(w);
-			switch (e->we.click.widget) {
-				case ORDER_WIDGET_ORDER_LIST: {
-					ResetObjectToPlace();
-
-					int sel = GetOrderFromOrderWndPt(w, e->we.click.pt.y, v);
-
-					if (sel == INVALID_ORDER) {
-						/* This was a click on an empty part of the orders window, so
-						* deselect the currently selected order. */
-						WP(w, order_d).sel = -1;
-						w->SetDirty();
-						return;
-					}
+	/**
+	 * Handle the click on the service in nearest depot button.
+	 *
+	 * @param w current window
+	 */
+	static void OrderClick_NearestDepot(OrdersWindow *w, int i)
+	{
+		Order order;
+		order.next = NULL;
+		order.index = 0;
+		order.MakeGoToDepot(0, ODTFB_PART_OF_ORDERS);
+		order.SetDepotActionType(ODATFB_NEAREST_DEPOT);
 
-					if (_ctrl_pressed && sel < v->num_orders) {
-						const Order *ord = GetVehicleOrder(v, sel);
-						TileIndex xy;
-
-						switch (ord->GetType()) {
-							case OT_GOTO_STATION:  xy = GetStation(ord->GetDestination())->xy ; break;
-							case OT_GOTO_DEPOT:    xy = (v->type == VEH_AIRCRAFT) ?  GetStation(ord->GetDestination())->xy : GetDepot(ord->GetDestination())->xy;    break;
-							case OT_GOTO_WAYPOINT: xy = GetWaypoint(ord->GetDestination())->xy; break;
-							default:               xy = 0; break;
-						}
-
-						if (xy != 0) ScrollMainWindowToTile(xy);
-						return;
-					} else {
-						if (sel == WP(w, order_d).sel) {
-							/* Deselect clicked order */
-							WP(w, order_d).sel = -1;
-						} else {
-							/* Select clicked order */
-							WP(w, order_d).sel = sel;
+		DoCommandP(w->vehicle->tile, w->vehicle->index + (w->OrderGetSel() << 16), order.Pack(), NULL, CMD_INSERT_ORDER | CMD_MSG(STR_8833_CAN_T_INSERT_NEW_ORDER));
+	}
 
-							if (v->owner == _local_player) {
-								/* Activate drag and drop */
-								SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, VHM_DRAG, w);
-							}
-						}
-					}
-
-					w->SetDirty();
-				} break;
+	/**
+	 * Handle the click on the conditional order button.
+	 *
+	 * @param w current window
+	 */
+	static void OrderClick_Conditional(OrdersWindow *w, int i)
+	{
+		w->InvalidateWidget(ORDER_WIDGET_GOTO);
+		w->LowerWidget(ORDER_WIDGET_GOTO);
+		SetObjectToPlaceWnd(ANIMCURSOR_PICKSTATION, PAL_NONE, VHM_RECT, w);
+		w->goto_type = OPOS_CONDITIONAL;
+	}
 
-				case ORDER_WIDGET_SKIP:
-					OrderClick_Skip(w, v, 0);
-					break;
+	/**
+	 * Handle the click on the unload button.
+	 *
+	 * @param w current window
+	 */
+	static void OrderClick_Unload(OrdersWindow *w, int unload_type)
+	{
+		VehicleOrderID sel_ord = w->OrderGetSel();
+		const Order *order = GetVehicleOrder(w->vehicle, sel_ord);
 
-				case ORDER_WIDGET_DELETE:
-					OrderClick_Delete(w, v, 0);
-					break;
+		if (order == NULL || order->GetUnloadType() == unload_type) return;
 
-				case ORDER_WIDGET_NON_STOP: {
-					const Order *o = GetVehicleOrder(v, OrderGetSel(w));
-					ShowDropDownMenu(w, _order_non_stop_drowdown, o->GetNonStopType(), ORDER_WIDGET_NON_STOP, 0, o->IsType(OT_GOTO_STATION) ? 0 : (o->IsType(OT_GOTO_WAYPOINT) ? 3 : 12));
-				} break;
+		if (unload_type < 0) {
+			switch (order->GetUnloadType()) {
+				case OUF_UNLOAD_IF_POSSIBLE: unload_type = OUFB_UNLOAD;            break;
+				case OUFB_UNLOAD:            unload_type = OUFB_TRANSFER;          break;
+				case OUFB_TRANSFER:          unload_type = OUFB_NO_UNLOAD;         break;
+				case OUFB_NO_UNLOAD:         unload_type = OUF_UNLOAD_IF_POSSIBLE; break;
+				default: NOT_REACHED();
+			}
+		}
 
-				case ORDER_WIDGET_GOTO:
-					OrderClick_Goto(w, v, 0);
+		DoCommandP(w->vehicle->tile, w->vehicle->index + (sel_ord << 16), MOF_UNLOAD | (unload_type << 4), NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
+	}
+
+	/**
+	 * Handle the click on the nonstop button.
+	 *
+	 * @param w current window
+	 * @param non_stop what non-stop type to use; -1 to use the 'next' one.
+	 */
+	static void OrderClick_Nonstop(OrdersWindow *w, int non_stop)
+	{
+		VehicleOrderID sel_ord = w->OrderGetSel();
+		const Order *order = GetVehicleOrder(w->vehicle, sel_ord);
+
+		if (order == NULL || order->GetNonStopType() == non_stop) return;
+
+		/* Keypress if negative, so 'toggle' to the next */
+		if (non_stop < 0) {
+			non_stop = (order->GetNonStopType() + 1) % ONSF_END;
+		}
+
+		DoCommandP(w->vehicle->tile, w->vehicle->index + (sel_ord << 16), MOF_NON_STOP | non_stop << 4,  NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
+	}
+
+	/**
+	 * Handle the click on the transfer button.
+	 *
+	 * @param w current window
+	 */
+	static void OrderClick_Transfer(OrdersWindow *w, int i)
+	{
+		VehicleOrderID sel_ord = w->OrderGetSel();
+		const Order *order = GetVehicleOrder(w->vehicle, sel_ord);
+
+		if (order == NULL) return;
+
+		DoCommandP(w->vehicle->tile, w->vehicle->index + (sel_ord << 16), MOF_UNLOAD | ((order->GetUnloadType() & ~OUFB_NO_UNLOAD) ^ OUFB_TRANSFER) << 4, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
+	}
+
+	/**
+	 * Handle the click on the skip button.
+	 * If ctrl is pressed skip to selected order.
+	 *  Else skip to current order + 1
+	 *
+	 * @param w current window
+	 */
+	static void OrderClick_Skip(OrdersWindow *w, int i)
+	{
+		/* Don't skip when there's nothing to skip */
+		if (_ctrl_pressed && w->vehicle->cur_order_index == w->OrderGetSel()) return;
+
+		DoCommandP(w->vehicle->tile, w->vehicle->index, _ctrl_pressed ? w->OrderGetSel() : ((w->vehicle->cur_order_index + 1) % w->vehicle->num_orders),
+				NULL, CMD_SKIP_TO_ORDER | CMD_MSG(_ctrl_pressed ? STR_CAN_T_SKIP_TO_ORDER : STR_CAN_T_SKIP_ORDER));
+	}
+
+	/**
+	 * Handle the click on the unload button.
+	 *
+	 * @param w current window
+	 */
+	static void OrderClick_Delete(OrdersWindow *w, int i)
+	{
+		DoCommandP(w->vehicle->tile, w->vehicle->index, w->OrderGetSel(), NULL, CMD_DELETE_ORDER | CMD_MSG(STR_8834_CAN_T_DELETE_THIS_ORDER));
+	}
+
+	/**
+	 * Handle the click on the refit button.
+	 * If ctrl is pressed cancel refitting.
+	 *  Else show the refit window.
+	 *
+	 * @param w current window
+	 */
+	static void OrderClick_Refit(OrdersWindow *w, int i)
+	{
+		if (_ctrl_pressed) {
+			/* Cancel refitting */
+			DoCommandP(w->vehicle->tile, w->vehicle->index, (w->OrderGetSel() << 16) | (CT_NO_REFIT << 8) | CT_NO_REFIT, NULL, CMD_ORDER_REFIT);
+		} else {
+			ShowVehicleRefitWindow(w->vehicle, w->OrderGetSel());
+		}
+	}
+	typedef void Handler(OrdersWindow*, int);
+	struct KeyToEvent {
+		uint16 keycode;
+		Handler *proc;
+	};
+
+public:
+	OrdersWindow(const WindowDesc *desc, const Vehicle *v) : Window(desc, v->index)
+	{
+		this->caption_color = v->owner;
+		this->vscroll.cap = 6;
+		this->resize.step_height = 10;
+		this->selected_order = -1;
+		this->vehicle = v;
+		if (_patches.timetabling) {
+			this->widget[ORDER_WIDGET_CAPTION].right -= 61;
+		} else {
+			this->HideWidget(ORDER_WIDGET_TIMETABLE_VIEW);
+		}
+		this->FindWindowPlacementAndResize(desc);
+	}
+
+	virtual void OnPaint()
+	{
+		bool shared_orders = this->vehicle->IsOrderListShared();
+
+		SetVScrollCount(this, this->vehicle->num_orders + 1);
+
+		int sel = OrderGetSel();
+		const Order *order = GetVehicleOrder(this->vehicle, sel);
+
+		if (this->vehicle->owner == _local_player) {
+			/* Set the strings for the dropdown boxes. */
+			this->widget[ORDER_WIDGET_NON_STOP].data        = _order_non_stop_drowdown[order == NULL ? 0 : order->GetNonStopType()];
+			this->widget[ORDER_WIDGET_FULL_LOAD].data       = _order_full_load_drowdown[order == NULL ? 0 : order->GetLoadType()];
+			this->widget[ORDER_WIDGET_UNLOAD].data          = _order_unload_drowdown[order == NULL ? 0 : order->GetUnloadType()];
+			this->widget[ORDER_WIDGET_COND_VARIABLE].data   = _order_conditional_variable[order == NULL ? 0 : order->GetConditionVariable()];
+			this->widget[ORDER_WIDGET_COND_COMPARATOR].data = _order_conditional_condition[order == NULL ? 0 : order->GetConditionComparator()];
+
+			/* skip */
+			this->SetWidgetDisabledState(ORDER_WIDGET_SKIP, this->vehicle->num_orders <= 1);
+
+			/* delete */
+			this->SetWidgetDisabledState(ORDER_WIDGET_DELETE,
+					(uint)this->vehicle->num_orders + ((shared_orders || this->vehicle->num_orders != 0) ? 1 : 0) <= (uint)this->selected_order);
+
+			/* non-stop only for trains */
+			this->SetWidgetDisabledState(ORDER_WIDGET_NON_STOP,  (this->vehicle->type != VEH_TRAIN && this->vehicle->type != VEH_ROAD) || order == NULL);
+			this->SetWidgetDisabledState(ORDER_WIDGET_FULL_LOAD, order == NULL || (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) != 0); // full load
+			this->SetWidgetDisabledState(ORDER_WIDGET_UNLOAD,    order == NULL || (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) != 0); // unload
+			/* Disable list of vehicles with the same shared orders if there is no list */
+			this->SetWidgetDisabledState(ORDER_WIDGET_SHARED_ORDER_LIST, !shared_orders || this->vehicle->orders == NULL);
+			this->SetWidgetDisabledState(ORDER_WIDGET_REFIT,     order == NULL); // Refit
+			this->SetWidgetDisabledState(ORDER_WIDGET_SERVICE,   order == NULL); // Refit
+			this->HideWidget(ORDER_WIDGET_REFIT); // Refit
+			this->HideWidget(ORDER_WIDGET_SERVICE); // Service
+
+			this->HideWidget(ORDER_WIDGET_COND_VARIABLE);
+			this->HideWidget(ORDER_WIDGET_COND_COMPARATOR);
+			this->HideWidget(ORDER_WIDGET_COND_VALUE);
+		}
+
+		this->ShowWidget(ORDER_WIDGET_NON_STOP);
+		this->ShowWidget(ORDER_WIDGET_UNLOAD);
+		this->ShowWidget(ORDER_WIDGET_FULL_LOAD);
+
+		if (order != NULL) {
+			switch (order->GetType()) {
+				case OT_GOTO_STATION:
+					if (!GetStation(order->GetDestination())->IsBuoy()) break;
+					/* Fall-through */
+
+				case OT_GOTO_WAYPOINT:
+					this->DisableWidget(ORDER_WIDGET_FULL_LOAD);
+					this->DisableWidget(ORDER_WIDGET_UNLOAD);
 					break;
 
-				case ORDER_WIDGET_GOTO_DROPDOWN:
-					ShowDropDownMenu(w, v->type == VEH_AIRCRAFT ? _order_goto_dropdown_aircraft : _order_goto_dropdown, 0, ORDER_WIDGET_GOTO, 0, 0, w->widget[ORDER_WIDGET_GOTO_DROPDOWN].right - w->widget[ORDER_WIDGET_GOTO].left);
-					break;
-
-				case ORDER_WIDGET_FULL_LOAD:
-					ShowDropDownMenu(w, _order_full_load_drowdown, GetVehicleOrder(v, OrderGetSel(w))->GetLoadType(), ORDER_WIDGET_FULL_LOAD, 0, 2);
-					break;
-
-				case ORDER_WIDGET_UNLOAD:
-					ShowDropDownMenu(w, _order_unload_drowdown, GetVehicleOrder(v, OrderGetSel(w))->GetUnloadType(), ORDER_WIDGET_UNLOAD, 0, 8);
-					break;
-
-				case ORDER_WIDGET_REFIT:
-					OrderClick_Refit(w, v, 0);
-					break;
-
-				case ORDER_WIDGET_SERVICE:
-					OrderClick_Service(w, v, 0);
-					break;
-
-				case ORDER_WIDGET_TIMETABLE_VIEW:
-					ShowTimetableWindow(v);
-					break;
-
-				case ORDER_WIDGET_COND_VARIABLE:
-					ShowDropDownMenu(w, _order_conditional_variable, GetVehicleOrder(v, OrderGetSel(w))->GetConditionVariable(), ORDER_WIDGET_COND_VARIABLE, 0, 0);
-					break;
-
-				case ORDER_WIDGET_COND_COMPARATOR: {
-					const Order *o = GetVehicleOrder(v, OrderGetSel(w));
-					ShowDropDownMenu(w, _order_conditional_condition, o->GetConditionComparator(), ORDER_WIDGET_COND_COMPARATOR, 0, (o->GetConditionVariable() == OCV_REQUIRES_SERVICE) ? 0x3F : 0xC0);
-				} break;
-
-				case ORDER_WIDGET_COND_VALUE: {
-					const Order *order = GetVehicleOrder(v, OrderGetSel(w));
-					uint value = order->GetConditionValue();
-					if (order->GetConditionVariable() == OCV_MAX_SPEED) value = ConvertSpeedToDisplaySpeed(value);
-					SetDParam(0, value);
-					ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_ORDER_CONDITIONAL_VALUE_CAPT, 5, 100, w, CS_NUMERAL);
-				} break;
-
-				case ORDER_WIDGET_SHARED_ORDER_LIST:
-					ShowVehicleListWindow(v);
-					break;
-			}
-			break;
+				case OT_GOTO_DEPOT:
+					this->DisableWidget(ORDER_WIDGET_FULL_LOAD);
 
-		case WE_ON_EDIT_TEXT:
-			if (!StrEmpty(e->we.edittext.str)) {
-				VehicleOrderID sel = OrderGetSel(w);
-				uint value = atoi(e->we.edittext.str);
-
-				switch (GetVehicleOrder(v, sel)->GetConditionVariable()) {
-					case OCV_MAX_SPEED:
-						value = ConvertDisplaySpeedToSpeed(value);
-						break;
-
-					case OCV_RELIABILITY:
-					case OCV_LOAD_PERCENTAGE:
-						value = Clamp(value, 0, 100);
-
-					default:
-						break;
-				}
-				DoCommandP(v->tile, v->index + (sel << 16), MOF_COND_VALUE | Clamp(value, 0, 2047) << 4, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
-			}
-			break;
-
-		case WE_DROPDOWN_SELECT: // we have selected a dropdown item in the list
-			switch (e->we.dropdown.button) {
-				case ORDER_WIDGET_NON_STOP:
-					OrderClick_Nonstop(w, v, e->we.dropdown.index);
-					break;
-
-				case ORDER_WIDGET_FULL_LOAD:
-					OrderClick_FullLoad(w, v, e->we.dropdown.index);
-					break;
-
-				case ORDER_WIDGET_UNLOAD:
-					OrderClick_Unload(w, v, e->we.dropdown.index);
-					break;
-
-				case ORDER_WIDGET_GOTO:
-					switch (e->we.dropdown.index) {
-						case 0:
-							w->ToggleWidgetLoweredState(ORDER_WIDGET_GOTO);
-							OrderClick_Goto(w, v, 0);
-							break;
-
-						case 1: OrderClick_NearestDepot(w, v, 0); break;
-						case 2: OrderClick_Conditional(w, v, 0); break;
-						default: NOT_REACHED();
-					}
-					break;
-
-				case ORDER_WIDGET_COND_VARIABLE:
-					DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), MOF_COND_VARIABLE | e->we.dropdown.index << 4,  NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
+					/* Remove unload and replace it with refit */
+					this->HideWidget(ORDER_WIDGET_UNLOAD);
+					this->ShowWidget(ORDER_WIDGET_REFIT);
+					this->HideWidget(ORDER_WIDGET_FULL_LOAD);
+					this->ShowWidget(ORDER_WIDGET_SERVICE);
 					break;
 
-				case ORDER_WIDGET_COND_COMPARATOR:
-					DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), MOF_COND_COMPARATOR | e->we.dropdown.index << 4,  NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
-					break;
-			}
-			break;
+				case OT_CONDITIONAL: {
+					this->HideWidget(ORDER_WIDGET_NON_STOP);
+					this->HideWidget(ORDER_WIDGET_UNLOAD);
+					this->HideWidget(ORDER_WIDGET_FULL_LOAD);
+					this->ShowWidget(ORDER_WIDGET_COND_VARIABLE);
+					this->ShowWidget(ORDER_WIDGET_COND_COMPARATOR);
+					this->ShowWidget(ORDER_WIDGET_COND_VALUE);
 
-		case WE_DRAGDROP:
-			switch (e->we.click.widget) {
-				case ORDER_WIDGET_ORDER_LIST: {
-					int from_order = OrderGetSel(w);
-					int to_order = GetOrderFromOrderWndPt(w, e->we.dragdrop.pt.y, v);
+					OrderConditionVariable ocv = order->GetConditionVariable();
+					this->SetWidgetDisabledState(ORDER_WIDGET_COND_COMPARATOR, ocv == OCV_UNCONDITIONALLY);
+					this->SetWidgetDisabledState(ORDER_WIDGET_COND_VALUE, ocv == OCV_REQUIRES_SERVICE || ocv == OCV_UNCONDITIONALLY);
 
-					if (!(from_order == to_order || from_order == INVALID_ORDER || from_order > v->num_orders || to_order == INVALID_ORDER || to_order > v->num_orders) &&
-							DoCommandP(v->tile, v->index, from_order | (to_order << 16), NULL, CMD_MOVE_ORDER | CMD_MSG(STR_CAN_T_MOVE_THIS_ORDER))) {
-						WP(w, order_d).sel = -1;
+					uint value = order->GetConditionValue();
+					if (order->GetConditionVariable() == OCV_MAX_SPEED) value = ConvertSpeedToDisplaySpeed(value);
+					SetDParam(1, value);
+				} break;
+
+				default: // every other orders
+					this->DisableWidget(ORDER_WIDGET_NON_STOP);
+					this->DisableWidget(ORDER_WIDGET_FULL_LOAD);
+					this->DisableWidget(ORDER_WIDGET_UNLOAD);
+			}
+		}
+
+		SetDParam(0, this->vehicle->index);
+		this->DrawWidgets();
+
+		int y = 15;
+
+		int i = this->vscroll.pos;
+		order = GetVehicleOrder(this->vehicle, i);
+		StringID str;
+		while (order != NULL) {
+			/* Don't draw anything if it extends past the end of the window. */
+			if (i - this->vscroll.pos >= this->vscroll.cap) break;
+
+			DrawOrderString(this->vehicle, order, i, y, i == this->selected_order, false);
+			y += 10;
+
+			i++;
+			order = order->next;
+		}
+
+		if (i - this->vscroll.pos < this->vscroll.cap) {
+			str = shared_orders ? STR_END_OF_SHARED_ORDERS : STR_882A_END_OF_ORDERS;
+			DrawString(2, y, str, (i == this->selected_order) ? TC_WHITE : TC_BLACK);
+		}
+	}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		if (this->widget[widget].type != WWT_DROPDOWN) HideDropDownMenu(this);
+		switch (widget) {
+			case ORDER_WIDGET_ORDER_LIST: {
+				ResetObjectToPlace();
+
+				int sel = this->GetOrderFromPt(pt.y);
+
+				if (sel == INVALID_ORDER) {
+					/* This was a click on an empty part of the orders window, so
+					* deselect the currently selected order. */
+					this->selected_order = -1;
+					this->SetDirty();
+					return;
+				}
+
+				if (_ctrl_pressed && sel < this->vehicle->num_orders) {
+					const Order *ord = GetVehicleOrder(this->vehicle, sel);
+					TileIndex xy;
+
+					switch (ord->GetType()) {
+						case OT_GOTO_STATION:  xy = GetStation(ord->GetDestination())->xy ; break;
+						case OT_GOTO_DEPOT:    xy = (this->vehicle->type == VEH_AIRCRAFT) ?  GetStation(ord->GetDestination())->xy : GetDepot(ord->GetDestination())->xy;    break;
+						case OT_GOTO_WAYPOINT: xy = GetWaypoint(ord->GetDestination())->xy; break;
+						default:               xy = 0; break;
 					}
 
-				} break;
+					if (xy != 0) ScrollMainWindowToTile(xy);
+					return;
+				} else {
+					if (sel == this->selected_order) {
+						/* Deselect clicked order */
+						this->selected_order = -1;
+					} else {
+						/* Select clicked order */
+						this->selected_order = sel;
 
-				case ORDER_WIDGET_DELETE:
-					OrderClick_Delete(w, v, 0);
+						if (this->vehicle->owner == _local_player) {
+							/* Activate drag and drop */
+							SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, VHM_DRAG, this);
+						}
+					}
+				}
+
+				this->SetDirty();
+			} break;
+
+			case ORDER_WIDGET_SKIP:
+				OrderClick_Skip(this, 0);
+				break;
+
+			case ORDER_WIDGET_DELETE:
+				OrderClick_Delete(this, 0);
+				break;
+
+			case ORDER_WIDGET_NON_STOP: {
+				const Order *o = GetVehicleOrder(this->vehicle, this->OrderGetSel());
+				ShowDropDownMenu(this, _order_non_stop_drowdown, o->GetNonStopType(), ORDER_WIDGET_NON_STOP, 0, o->IsType(OT_GOTO_STATION) ? 0 : (o->IsType(OT_GOTO_WAYPOINT) ? 3 : 12));
+			} break;
+
+			case ORDER_WIDGET_GOTO:
+				OrderClick_Goto(this, 0);
+				break;
+
+			case ORDER_WIDGET_GOTO_DROPDOWN:
+				ShowDropDownMenu(this, this->vehicle->type == VEH_AIRCRAFT ? _order_goto_dropdown_aircraft : _order_goto_dropdown, 0, ORDER_WIDGET_GOTO, 0, 0, this->widget[ORDER_WIDGET_GOTO_DROPDOWN].right - this->widget[ORDER_WIDGET_GOTO].left);
+				break;
+
+			case ORDER_WIDGET_FULL_LOAD:
+				ShowDropDownMenu(this, _order_full_load_drowdown, GetVehicleOrder(this->vehicle, this->OrderGetSel())->GetLoadType(), ORDER_WIDGET_FULL_LOAD, 0, 2);
+				break;
+
+			case ORDER_WIDGET_UNLOAD:
+				ShowDropDownMenu(this, _order_unload_drowdown, GetVehicleOrder(this->vehicle, this->OrderGetSel())->GetUnloadType(), ORDER_WIDGET_UNLOAD, 0, 8);
+				break;
+
+			case ORDER_WIDGET_REFIT:
+				OrderClick_Refit(this, 0);
+				break;
+
+			case ORDER_WIDGET_SERVICE:
+				OrderClick_Service(this, 0);
+				break;
+
+			case ORDER_WIDGET_TIMETABLE_VIEW:
+				ShowTimetableWindow(this->vehicle);
+				break;
+
+			case ORDER_WIDGET_COND_VARIABLE:
+				ShowDropDownMenu(this, _order_conditional_variable, GetVehicleOrder(this->vehicle, this->OrderGetSel())->GetConditionVariable(), ORDER_WIDGET_COND_VARIABLE, 0, 0);
+				break;
+
+			case ORDER_WIDGET_COND_COMPARATOR: {
+				const Order *o = GetVehicleOrder(this->vehicle, this->OrderGetSel());
+				ShowDropDownMenu(this, _order_conditional_condition, o->GetConditionComparator(), ORDER_WIDGET_COND_COMPARATOR, 0, (o->GetConditionVariable() == OCV_REQUIRES_SERVICE) ? 0x3F : 0xC0);
+			} break;
+
+			case ORDER_WIDGET_COND_VALUE: {
+				const Order *order = GetVehicleOrder(this->vehicle, this->OrderGetSel());
+				uint value = order->GetConditionValue();
+				if (order->GetConditionVariable() == OCV_MAX_SPEED) value = ConvertSpeedToDisplaySpeed(value);
+				SetDParam(0, value);
+				ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_ORDER_CONDITIONAL_VALUE_CAPT, 5, 100, this, CS_NUMERAL);
+			} break;
+
+			case ORDER_WIDGET_SHARED_ORDER_LIST:
+				ShowVehicleListWindow(this->vehicle);
+				break;
+		}
+	}
+
+	virtual void OnQueryTextFinished(char *str)
+	{
+		if (!StrEmpty(str)) {
+			VehicleOrderID sel = this->OrderGetSel();
+			uint value = atoi(str);
+
+			switch (GetVehicleOrder(this->vehicle, sel)->GetConditionVariable()) {
+				case OCV_MAX_SPEED:
+					value = ConvertDisplaySpeedToSpeed(value);
+					break;
+
+				case OCV_RELIABILITY:
+				case OCV_LOAD_PERCENTAGE:
+					value = Clamp(value, 0, 100);
+
+				default:
 					break;
 			}
-
-			ResetObjectToPlace();
-			break;
+			DoCommandP(this->vehicle->tile, this->vehicle->index + (sel << 16), MOF_COND_VALUE | Clamp(value, 0, 2047) << 4, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
+		}
+	}
 
-		case WE_KEYPRESS:
-			if (v->owner != _local_player) break;
+	virtual void OnDropdownSelect(int widget, int index)
+	{
+		switch (widget) {
+			case ORDER_WIDGET_NON_STOP:
+				OrderClick_Nonstop(this, index);
+				break;
 
-			for (uint i = 0; i < lengthof(_order_keycodes); i++) {
-				if (e->we.keypress.keycode == _order_keycodes[i]) {
-					e->we.keypress.cont = false;
-					/* see if the button is disabled */
-					if (!w->IsWidgetDisabled(i + ORDER_WIDGET_SKIP)) _order_button_proc[i](w, v, -1);
-					break;
+			case ORDER_WIDGET_FULL_LOAD:
+				OrderClick_FullLoad(this, index);
+				break;
+
+			case ORDER_WIDGET_UNLOAD:
+				OrderClick_Unload(this, index);
+				break;
+
+			case ORDER_WIDGET_GOTO:
+				switch (index) {
+					case 0:
+						this->ToggleWidgetLoweredState(ORDER_WIDGET_GOTO);
+						OrderClick_Goto(this, 0);
+						break;
+
+					case 1: OrderClick_NearestDepot(this, 0); break;
+					case 2: OrderClick_Conditional(this, 0); break;
+					default: NOT_REACHED();
+				}
+				break;
+
+			case ORDER_WIDGET_COND_VARIABLE:
+				DoCommandP(this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 16), MOF_COND_VARIABLE | index << 4,  NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
+				break;
+
+			case ORDER_WIDGET_COND_COMPARATOR:
+				DoCommandP(this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 16), MOF_COND_COMPARATOR | index << 4,  NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
+				break;
+		}
+	}
+
+	virtual void OnDragDrop(Point pt, int widget)
+	{
+		switch (widget) {
+			case ORDER_WIDGET_ORDER_LIST: {
+				int from_order = this->OrderGetSel();
+				int to_order = this->GetOrderFromPt(pt.y);
+
+				if (!(from_order == to_order || from_order == INVALID_ORDER || from_order > this->vehicle->num_orders || to_order == INVALID_ORDER || to_order > this->vehicle->num_orders) &&
+						DoCommandP(this->vehicle->tile, this->vehicle->index, from_order | (to_order << 16), NULL, CMD_MOVE_ORDER | CMD_MSG(STR_CAN_T_MOVE_THIS_ORDER))) {
+					this->selected_order = -1;
+				}
+			} break;
+
+			case ORDER_WIDGET_DELETE:
+				OrderClick_Delete(this, 0);
+				break;
+		}
+
+		ResetObjectToPlace();
+	}
+
+	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+	{
+		static const KeyToEvent keytoevent[] = {
+			{'D', OrderClick_Skip},
+			{'F', OrderClick_Delete},
+			{'G', OrderClick_Goto},
+			{'H', OrderClick_Nonstop},
+			{'J', OrderClick_FullLoad},
+			{'K', OrderClick_Unload},
+			//{'?', OrderClick_Transfer},
+			//('?', OrderClick_Service},
+		};
+
+		if (this->vehicle->owner != _local_player) return ES_NOT_HANDLED;
+
+		for (uint i = 0; i < lengthof(keytoevent); i++) {
+			if (keycode == keytoevent[i].keycode) {
+				keytoevent[i].proc(this, -1);
+				return ES_HANDLED;
+			}
+		}
+		return ES_NOT_HANDLED;
+	}
+
+	virtual void OnPlaceObject(Point pt, TileIndex tile)
+	{
+		if (this->goto_type == OPOS_GOTO) {
+			/* check if we're clicking on a vehicle first.. clone orders in that case. */
+			const Vehicle *v = CheckMouseOverVehicle();
+			if (v != NULL && this->HandleOrderVehClick(v)) return;
+
+			const Order cmd = GetOrderCmdFromTile(this->vehicle, tile);
+			if (!cmd.IsValid()) return;
+
+			if (DoCommandP(this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 16), cmd.Pack(), NULL, CMD_INSERT_ORDER | CMD_MSG(STR_8833_CAN_T_INSERT_NEW_ORDER))) {
+				if (this->selected_order != -1) this->selected_order++;
+				ResetObjectToPlace();
+			}
+		}
+	}
+
+	virtual void OnPlaceObjectAbort()
+	{
+		if (this->goto_type == OPOS_CONDITIONAL) {
+			this->goto_type = OPOS_GOTO;
+			if (_cursor.pos.x >= (this->left + this->widget[ORDER_WIDGET_ORDER_LIST].left) &&
+					_cursor.pos.y >= (this->top  + this->widget[ORDER_WIDGET_ORDER_LIST].top) &&
+					_cursor.pos.x <= (this->left + this->widget[ORDER_WIDGET_ORDER_LIST].right) &&
+					_cursor.pos.y <= (this->top  + this->widget[ORDER_WIDGET_ORDER_LIST].bottom)) {
+				int order_id = this->GetOrderFromPt(_cursor.pos.y - this->top);
+				if (order_id != INVALID_ORDER) {
+					Order order;
+					order.next = NULL;
+					order.index = 0;
+					order.MakeConditional(order_id);
+
+					DoCommandP(this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 16), order.Pack(), NULL, CMD_INSERT_ORDER | CMD_MSG(STR_8833_CAN_T_INSERT_NEW_ORDER));
 				}
 			}
-			break;
-
-		case WE_PLACE_OBJ:
-			if (WP(w, order_d).goto_type == OPOS_GOTO) {
-				OrdersPlaceObj(GetVehicle(w->window_number), e->we.place.tile, w);
-			}
-			break;
-
-		case WE_ABORT_PLACE_OBJ:
-			if (WP(w, order_d).goto_type == OPOS_CONDITIONAL) {
-				WP(w, order_d).goto_type = OPOS_GOTO;
-				if (_cursor.pos.x >= (w->left + w->widget[ORDER_WIDGET_ORDER_LIST].left) &&
-						_cursor.pos.y >= (w->top  + w->widget[ORDER_WIDGET_ORDER_LIST].top) &&
-						_cursor.pos.x <= (w->left + w->widget[ORDER_WIDGET_ORDER_LIST].right) &&
-						_cursor.pos.y <= (w->top  + w->widget[ORDER_WIDGET_ORDER_LIST].bottom)) {
-					int order_id = GetOrderFromOrderWndPt(w, _cursor.pos.y - w->top, v);
-					if (order_id != INVALID_ORDER) {
-						Order order;
-						order.next = NULL;
-						order.index = 0;
-						order.MakeConditional(order_id);
-
-						DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), order.Pack(), NULL, CMD_INSERT_ORDER | CMD_MSG(STR_8833_CAN_T_INSERT_NEW_ORDER));
-					}
-				}
-			}
-			w->RaiseWidget(ORDER_WIDGET_GOTO);
-			w->InvalidateWidget(ORDER_WIDGET_GOTO);
-			break;
+		}
+		this->RaiseWidget(ORDER_WIDGET_GOTO);
+		this->InvalidateWidget(ORDER_WIDGET_GOTO);
+	}
 
-		/* check if a vehicle in a depot was clicked.. */
-		case WE_MOUSELOOP:
-			v = _place_clicked_vehicle;
-			/*
-			* Check if we clicked on a vehicle
-			* and if the GOTO button of this window is pressed
-			* This is because of all open order windows WE_MOUSELOOP is called
-			* and if you have 3 windows open, and this check is not done
-			* the order is copied to the last open window instead of the
-			* one where GOTO is enabled
-			*/
-			if (v != NULL && w->IsWidgetLowered(ORDER_WIDGET_GOTO)) {
-				_place_clicked_vehicle = NULL;
-				HandleOrderVehClick(GetVehicle(w->window_number), v, w);
+	virtual void OnMouseLoop()
+	{
+		const Vehicle *v = _place_clicked_vehicle;
+		/*
+		* Check if we clicked on a vehicle
+		* and if the GOTO button of this window is pressed
+		* This is because of all open order windows WE_MOUSELOOP is called
+		* and if you have 3 windows open, and this check is not done
+		* the order is copied to the last open window instead of the
+		* one where GOTO is enabled
+		*/
+		if (v != NULL && this->IsWidgetLowered(ORDER_WIDGET_GOTO)) {
+			_place_clicked_vehicle = NULL;
+			this->HandleOrderVehClick(v);
+		}
+	}
+
+	virtual void OnResize(Point new_size, Point delta)
+	{
+		/* Update the scroll + matrix */
+		this->vscroll.cap = (this->widget[ORDER_WIDGET_ORDER_LIST].bottom - this->widget[ORDER_WIDGET_ORDER_LIST].top) / 10;
+	}
+
+	virtual void OnTimeout()
+	{
+		/* unclick all buttons except for the 'goto' button (ORDER_WIDGET_GOTO), which is 'persistent' */
+		for (uint i = 0; i < this->widget_count; i++) {
+			if (this->IsWidgetLowered(i) && i != ORDER_WIDGET_GOTO) {
+				this->RaiseWidget(i);
+				this->InvalidateWidget(i);
 			}
-			break;
-
-		case WE_RESIZE:
-			/* Update the scroll + matrix */
-			w->vscroll.cap = (w->widget[ORDER_WIDGET_ORDER_LIST].bottom - w->widget[ORDER_WIDGET_ORDER_LIST].top) / 10;
-			break;
-
-		case WE_TIMEOUT: // handle button unclick ourselves...
-			/* unclick all buttons except for the 'goto' button (ORDER_WIDGET_GOTO), which is 'persistent' */
-			for (uint i = 0; i < w->widget_count; i++) {
-				if (w->IsWidgetLowered(i) && i != ORDER_WIDGET_GOTO) {
-					w->RaiseWidget(i);
-					w->InvalidateWidget(i);
-				}
-			}
-			break;
+		}
 	}
-}
+};
 
 /**
  * Widget definition for player train orders
@@ -1091,7 +1063,6 @@
 	WC_VEHICLE_ORDERS, WC_VEHICLE_VIEW,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE,
 	_orders_train_widgets,
-	OrdersWndProc
 };
 
 /**
@@ -1132,7 +1103,6 @@
 	WC_VEHICLE_ORDERS, WC_VEHICLE_VIEW,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE,
 	_orders_widgets,
-	OrdersWndProc
 };
 
 /**
@@ -1173,27 +1143,18 @@
 	WC_VEHICLE_ORDERS, WC_VEHICLE_VIEW,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
 	_other_orders_widgets,
-	OrdersWndProc
 };
 
 void ShowOrdersWindow(const Vehicle *v)
 {
-	Window *w;
 	VehicleID veh = v->index;
 
 	DeleteWindowById(WC_VEHICLE_ORDERS, veh);
 	DeleteWindowById(WC_VEHICLE_DETAILS, veh);
 
 	if (v->owner != _local_player) {
-		w = AllocateWindowDescFront<Window>(&_other_orders_desc, veh);
+		new OrdersWindow(&_other_orders_desc, v);
 	} else {
-		w = AllocateWindowDescFront<Window>((v->type == VEH_TRAIN || v->type == VEH_ROAD) ? &_orders_train_desc : &_orders_desc, veh);
-	}
-
-	if (w != NULL) {
-		w->caption_color = v->owner;
-		w->vscroll.cap = 6;
-		w->resize.step_height = 10;
-		WP(w, order_d).sel = -1;
+		new OrdersWindow((v->type == VEH_TRAIN || v->type == VEH_ROAD) ? &_orders_train_desc : &_orders_desc, v);
 	}
 }
--- a/src/osk_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/osk_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -42,6 +42,7 @@
 static byte _keystate = KEYS_NONE;
 
 struct OskWindow : public Window {
+	StringID caption;      ///< the caption for this window.
 	QueryString *qs;       ///< text-input
 	int text_btn;          ///< widget number of parent's text field
 	int ok_btn;            ///< widget number of parent's ok button (=0 when ok shouldn't be passed on)
@@ -54,7 +55,7 @@
 		this->parent = parent;
 		assert(parent != NULL);
 
-		if (parent->widget[button].data != 0) parent->caption = parent->widget[button].data;
+		this->caption = (parent->widget[button].data != STR_NULL) ? parent->widget[button].data : parent->caption;
 
 		this->qs         = parent;
 		this->text_btn   = button;
@@ -96,8 +97,8 @@
 
 		this->ChangeOskDiabledState(shift);
 
-		SetDParam(0, this->qs->caption);
-		DrawWindowWidgets(this);
+		SetDParam(0, this->caption);
+		this->DrawWidgets();
 
 		for (uint i = 0; i < OSK_KEYBOARD_ENTRIES; i++) {
 			DrawCharCentered(_keyboard[shift][i],
@@ -129,6 +130,8 @@
 			return;
 		}
 
+		bool delete_this = false;
+
 		switch (widget) {
 			case OSK_WIDGET_BACKSPACE:
 				if (DeleteTextBufferChar(&this->qs->text, WKC_BACKSPACE)) this->InvalidateWidget(OSK_WIDGET_TEXT);
@@ -169,25 +172,29 @@
 					/* pass information by simulating a button press on parent window */
 					if (this->ok_btn != 0) {
 						this->parent->OnClick(pt, this->ok_btn);
+						/* Window gets deleted when the parent window removes itself. */
+						return;
 					}
 				}
-				delete this;
+				delete_this = true;
 				break;
 
 			case OSK_WIDGET_CANCEL:
 				if (this->cancel_btn != 0) { // pass a cancel event to the parent window
 					this->parent->OnClick(pt, this->cancel_btn);
 					/* Window gets deleted when the parent window removes itself. */
+					return;
 				} else { // or reset to original string
 					strcpy(qs->text.buf, this->orig_str_buf);
 					UpdateTextBufferSize(&qs->text);
 					MoveTextBufferPos(&qs->text, WKC_END);
-					delete this;
+					delete_this = true;
 				}
 				break;
 		}
 		/* make sure that the parent window's textbox also gets updated */
 		if (this->parent != NULL) this->parent->InvalidateWidget(this->text_btn);
+		if (delete_this) delete this;
 	}
 
 	virtual void OnMouseLoop()
@@ -276,12 +283,11 @@
 {   WIDGETS_END},
 };
 
-WindowDesc _osk_desc = {
+static const WindowDesc _osk_desc = {
 	WDP_CENTER, WDP_CENTER, 256, 140, 256, 140,
 	WC_OSK, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
 	_osk_widgets,
-	NULL
 };
 
 /**
@@ -339,7 +345,7 @@
 }
 
 /**
- * Show the osk associated with a given textbox
+ * Show the on-screen keyboard (osk) associated with a given textbox
  * @param parent pointer to the Window where this keyboard originated from
  * @param q      querystr_d pointer to the query string of the parent, which is
  *               shared for both windows
--- a/src/player_face.h	Mon May 19 14:14:33 2008 +0000
+++ b/src/player_face.h	Mon May 19 15:13:58 2008 +0000
@@ -230,6 +230,5 @@
 void DrawPlayerFace(PlayerFace face, int color, int x, int y);
 PlayerFace ConvertFromOldPlayerFace(uint32 face);
 bool IsValidPlayerFace(PlayerFace pf);
-void DrawFaceStringLabel(const Window *w, byte widget_index, StringID str, uint8 val, bool is_bool_widget);
 
 #endif /* PLAYER_FACE_H */
--- a/src/player_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/player_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -35,34 +35,21 @@
 #include "table/sprites.h"
 #include "table/strings.h"
 
-/* player face selection window */
-struct facesel_d {
-	PlayerFace face; // player face bits
-	bool advanced;   // advance player face selection window
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(facesel_d));
-
-struct highscore_d {
-	uint32 background_img;
-	int8 rank;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(highscore_d));
-
 enum {
 	FIRST_GUI_CALL = INT_MAX,  ///< default value to specify thuis is the first call of the resizable gui
 };
 
 static void DoShowPlayerFinances(PlayerID player, bool show_small, bool show_stickied, int top = FIRST_GUI_CALL, int left = FIRST_GUI_CALL);
-static void DoSelectPlayerFace(PlayerID player, bool show_big, int top =  FIRST_GUI_CALL, int left = FIRST_GUI_CALL);
+static void DoSelectPlayerFace(Window *parent, bool show_big, int top =  FIRST_GUI_CALL, int left = FIRST_GUI_CALL);
 
-static void DrawPlayerEconomyStats(const Player *p, byte mode)
+static void DrawPlayerEconomyStats(const Player *p, bool small)
 {
 	int x, y, i, j, year;
 	const Money (*tbl)[EXPENSES_END];
 	Money sum, cost;
 	StringID str;
 
-	if (!(mode & 1)) { // normal sized economics window (mode&1) is minimized status
+	if (!small) { // normal sized economics window
 		/* draw categories */
 		DrawStringCenterUnderline(61, 15, STR_700F_EXPENDITURE_INCOME, TC_FROMSTRING);
 		for (i = 0; i != EXPENSES_END; i++)
@@ -161,73 +148,88 @@
 {   WIDGETS_END},
 };
 
-
-static void PlayerFinancesWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			PlayerID player = (PlayerID)w->window_number;
-			const Player *p = GetPlayer(player);
-
-			/* Recheck the size of the window as it might need to be resized due to the local player changing */
-			int new_height = ((player != _local_player) ? 0 : 12) + ((WP(w, def_d).data_1 != 0) ? 48 : 74 + 10 * EXPENSES_END);
-			if (w->height != new_height) {
-				/* Make window dirty before and after resizing */
-				w->SetDirty();
-				w->height = new_height;
-				w->SetDirty();
-
-				w->SetWidgetHiddenState(PFW_WIDGET_INCREASE_LOAN, player != _local_player);
-				w->SetWidgetHiddenState(PFW_WIDGET_REPAY_LOAN,    player != _local_player);
-			}
-
-			/* Borrow button only shows when there is any more money to loan */
-			w->SetWidgetDisabledState(PFW_WIDGET_INCREASE_LOAN, p->current_loan == _economy.max_loan);
+struct PlayerFinancesWindow : Window {
+	bool small;
 
-			/* Repay button only shows when there is any more money to repay */
-			w->SetWidgetDisabledState(PFW_WIDGET_REPAY_LOAN, player != _local_player || p->current_loan == 0);
-
-			SetDParam(0, p->index);
-			SetDParam(1, p->index);
-			SetDParam(2, LOAN_INTERVAL);
-			DrawWindowWidgets(w);
-
-			DrawPlayerEconomyStats(p, (byte)WP(w, def_d).data_1);
-		} break;
+	PlayerFinancesWindow(const WindowDesc *desc, PlayerID player, bool show_small,
+					bool show_stickied, int top, int left) :
+			Window(desc, player),
+			small(show_small)
+	{
+		this->caption_color = this->window_number;
 
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case PFW_WIDGET_TOGGLE_SIZE: {/* toggle size */
-					byte mode = (byte)WP(w, def_d).data_1;
-					bool stickied = !!(w->flags4 & WF_STICKY);
-					int oldtop = w->top;   ///< current top position of the window before closing it
-					int oldleft = w->left; ///< current left position of the window before closing it
-					PlayerID player = (PlayerID)w->window_number;
+		if (show_stickied) this->flags4 |= WF_STICKY;
 
-					delete w;
-					/* Open up the (toggled size) Finance window at the same position as the previous */
-					DoShowPlayerFinances(player, !HasBit(mode, 0), stickied, oldtop, oldleft);
-				}
+		/* Check if repositioning from default is required */
+		if (top != FIRST_GUI_CALL && left != FIRST_GUI_CALL) {
+			this->top = top;
+			this->left = left;
+		}
+	}
+
+	virtual void OnPaint()
+	{
+		PlayerID player = (PlayerID)this->window_number;
+		const Player *p = GetPlayer(player);
+
+		/* Recheck the size of the window as it might need to be resized due to the local player changing */
+		int new_height = ((player != _local_player) ? 0 : 12) + ((this->small != 0) ? 48 : 74 + 10 * EXPENSES_END);
+		if (this->height != new_height) {
+			/* Make window dirty before and after resizing */
+			this->SetDirty();
+			this->height = new_height;
+			this->SetDirty();
+
+			this->SetWidgetHiddenState(PFW_WIDGET_INCREASE_LOAN, player != _local_player);
+			this->SetWidgetHiddenState(PFW_WIDGET_REPAY_LOAN,    player != _local_player);
+		}
+
+		/* Borrow button only shows when there is any more money to loan */
+		this->SetWidgetDisabledState(PFW_WIDGET_INCREASE_LOAN, p->current_loan == _economy.max_loan);
+
+		/* Repay button only shows when there is any more money to repay */
+		this->SetWidgetDisabledState(PFW_WIDGET_REPAY_LOAN, player != _local_player || p->current_loan == 0);
+
+		SetDParam(0, p->index);
+		SetDParam(1, p->index);
+		SetDParam(2, LOAN_INTERVAL);
+		this->DrawWidgets();
+
+		DrawPlayerEconomyStats(p, this->small);
+	}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case PFW_WIDGET_TOGGLE_SIZE: {/* toggle size */
+				bool new_mode = !this->small;
+				bool stickied = !!(this->flags4 & WF_STICKY);
+				int oldtop = this->top;   ///< current top position of the window before closing it
+				int oldleft = this->left; ///< current left position of the window before closing it
+				PlayerID player = (PlayerID)this->window_number;
+
+				delete this;
+				/* Open up the (toggled size) Finance window at the same position as the previous */
+				DoShowPlayerFinances(player, new_mode, stickied, oldtop, oldleft);
+			}
+			break;
+
+			case PFW_WIDGET_INCREASE_LOAN: /* increase loan */
+				DoCommandP(0, 0, _ctrl_pressed, NULL, CMD_INCREASE_LOAN | CMD_MSG(STR_702C_CAN_T_BORROW_ANY_MORE_MONEY));
 				break;
 
-				case PFW_WIDGET_INCREASE_LOAN: /* increase loan */
-					DoCommandP(0, 0, _ctrl_pressed, NULL, CMD_INCREASE_LOAN | CMD_MSG(STR_702C_CAN_T_BORROW_ANY_MORE_MONEY));
-					break;
-
-				case PFW_WIDGET_REPAY_LOAN: /* repay loan */
-					DoCommandP(0, 0, _ctrl_pressed, NULL, CMD_DECREASE_LOAN | CMD_MSG(STR_702F_CAN_T_REPAY_LOAN));
-					break;
-			}
-			break;
+			case PFW_WIDGET_REPAY_LOAN: /* repay loan */
+				DoCommandP(0, 0, _ctrl_pressed, NULL, CMD_DECREASE_LOAN | CMD_MSG(STR_702F_CAN_T_REPAY_LOAN));
+				break;
+		}
 	}
-}
+};
 
 static const WindowDesc _player_finances_desc = {
 	WDP_AUTO, WDP_AUTO, 407, 86 + 10 * EXPENSES_END, 407, 86 + 10 * EXPENSES_END,
 	WC_FINANCES, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
 	_player_finances_widgets,
-	PlayerFinancesWndProc
 };
 
 static const WindowDesc _player_finances_small_desc = {
@@ -235,7 +237,6 @@
 	WC_FINANCES, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
 	_player_finances_small_widgets,
-	PlayerFinancesWndProc
 };
 
 /**
@@ -253,19 +254,8 @@
 {
 	if (!IsValidPlayer(player)) return;
 
-	Window *w = AllocateWindowDescFront<Window>(show_small ? &_player_finances_small_desc : &_player_finances_desc, player);
-	if (w != NULL) {
-		w->caption_color = w->window_number;
-		WP(w, def_d).data_1 = show_small;
-
-		if (show_stickied) w->flags4 |= WF_STICKY;
-
-		/* Check if repositioning from default is required */
-		if (top != FIRST_GUI_CALL && left != FIRST_GUI_CALL) {
-			w->top = top;
-			w->left = left;
-		}
-	}
+	if (BringWindowToFrontById(WC_FINANCES, player)) return;
+	new PlayerFinancesWindow(show_small ? &_player_finances_small_desc : &_player_finances_desc, player, show_small, show_stickied, top, left);
 }
 
 void ShowPlayerFinances(PlayerID player)
@@ -294,7 +284,7 @@
 };
 
 /* Association of liveries to livery classes */
-static const LiveryClass livery_class[LS_END] = {
+static const LiveryClass _livery_class[LS_END] = {
 	LC_OTHER,
 	LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL,
 	LC_ROAD, LC_ROAD,
@@ -303,34 +293,6 @@
 	LC_ROAD, LC_ROAD,
 };
 
-/* Number of liveries in each class, used to determine the height of the livery window */
-static const byte livery_height[] = {
-	1,
-	13,
-	4,
-	2,
-	3,
-};
-
-struct livery_d {
-	uint32 sel;
-	LiveryClass livery_class;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(livery_d));
-
-
-enum PlayerLiveryWindowWidgets {
-	PLW_WIDGET_CLASS_GENERAL = 2,
-	PLW_WIDGET_CLASS_RAIL,
-	PLW_WIDGET_CLASS_ROAD,
-	PLW_WIDGET_CLASS_SHIP,
-	PLW_WIDGET_CLASS_AIRCRAFT,
-
-	PLW_WIDGET_PRI_COL_DROPDOWN = 9,
-	PLW_WIDGET_SEC_COL_DROPDOWN,
-	PLW_WIDGET_MATRIX,
-};
-
 class DropDownListColourItem : public DropDownListItem {
 public:
 	DropDownListColourItem(int result, bool masked) : DropDownListItem(result, masked) {}
@@ -354,168 +316,211 @@
 	}
 };
 
-static void ShowColourDropDownMenu(Window *w, uint32 widget)
-{
-	uint32 used_colours = 0;
-	const Livery *livery;
-	LiveryScheme scheme;
+struct SelectPlayerLiveryWindow : public Window {
+private:
+	uint32 sel;
+	LiveryClass livery_class;
 
-	/* Disallow other player colours for the primary colour */
-	if (HasBit(WP(w, livery_d).sel, LS_DEFAULT) && widget == PLW_WIDGET_PRI_COL_DROPDOWN) {
-		const Player *p;
-		FOR_ALL_PLAYERS(p) {
-			if (p->is_active && p->index != _local_player) SetBit(used_colours, p->player_color);
+	enum PlayerLiveryWindowWidgets {
+		PLW_WIDGET_CLOSE,
+		PLW_WIDGET_CAPTION,
+		PLW_WIDGET_CLASS_GENERAL,
+		PLW_WIDGET_CLASS_RAIL,
+		PLW_WIDGET_CLASS_ROAD,
+		PLW_WIDGET_CLASS_SHIP,
+		PLW_WIDGET_CLASS_AIRCRAFT,
+		PLW_WIDGET_SPACER_CLASS,
+		PLW_WIDGET_SPACER_DROPDOWN,
+		PLW_WIDGET_PRI_COL_DROPDOWN,
+		PLW_WIDGET_SEC_COL_DROPDOWN,
+		PLW_WIDGET_MATRIX,
+	};
+
+	void ShowColourDropDownMenu(uint32 widget)
+	{
+		uint32 used_colours = 0;
+		const Livery *livery;
+		LiveryScheme scheme;
+
+		/* Disallow other player colours for the primary colour */
+		if (HasBit(this->sel, LS_DEFAULT) && widget == PLW_WIDGET_PRI_COL_DROPDOWN) {
+			const Player *p;
+			FOR_ALL_PLAYERS(p) {
+				if (p->is_active && p->index != _local_player) SetBit(used_colours, p->player_color);
+			}
+		}
+
+		/* Get the first selected livery to use as the default dropdown item */
+		for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
+			if (HasBit(this->sel, scheme)) break;
+		}
+		if (scheme == LS_END) scheme = LS_DEFAULT;
+		livery = &GetPlayer((PlayerID)this->window_number)->livery[scheme];
+
+		DropDownList *list = new DropDownList();
+		for (uint i = 0; i < lengthof(_colour_dropdown); i++) {
+			list->push_back(new DropDownListColourItem(i, HasBit(used_colours, i)));
+		}
+
+		ShowDropDownList(this, list, widget == PLW_WIDGET_PRI_COL_DROPDOWN ? livery->colour1 : livery->colour2, widget);
+	}
+
+public:
+	SelectPlayerLiveryWindow(const WindowDesc *desc, PlayerID player) : Window(desc, player)
+	{
+		this->caption_color = player;
+		this->livery_class = LC_OTHER;
+		this->sel = 1;
+		this->LowerWidget(PLW_WIDGET_CLASS_GENERAL);
+		this->OnInvalidateData(_loaded_newgrf_features.has_2CC);
+		this->FindWindowPlacementAndResize(desc);
+	}
+
+	virtual void OnPaint()
+	{
+		const Player *p = GetPlayer((PlayerID)this->window_number);
+		LiveryScheme scheme = LS_DEFAULT;
+		int y = 51;
+
+		/* Disable dropdown controls if no scheme is selected */
+		this->SetWidgetDisabledState(PLW_WIDGET_PRI_COL_DROPDOWN, this->sel == 0);
+		this->SetWidgetDisabledState(PLW_WIDGET_SEC_COL_DROPDOWN, this->sel == 0);
+
+		if (this->sel != 0) {
+			for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
+				if (HasBit(this->sel, scheme)) break;
+			}
+			if (scheme == LS_END) scheme = LS_DEFAULT;
+		}
+
+		SetDParam(0, STR_00D1_DARK_BLUE + p->livery[scheme].colour1);
+		SetDParam(1, STR_00D1_DARK_BLUE + p->livery[scheme].colour2);
+
+		this->DrawWidgets();
+
+		for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
+			if (_livery_class[scheme] == this->livery_class) {
+				bool sel = HasBit(this->sel, scheme) != 0;
+
+				if (scheme != LS_DEFAULT) {
+					DrawSprite(p->livery[scheme].in_use ? SPR_BOX_CHECKED : SPR_BOX_EMPTY, PAL_NONE, 2, y);
+				}
+
+				DrawString(15, y, STR_LIVERY_DEFAULT + scheme, sel ? TC_WHITE : TC_BLACK);
+
+				DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOR(p->livery[scheme].colour1), 152, y);
+				DrawString(165, y, STR_00D1_DARK_BLUE + p->livery[scheme].colour1, sel ? TC_WHITE : TC_GOLD);
+
+				if (!this->IsWidgetHidden(PLW_WIDGET_SEC_COL_DROPDOWN)) {
+					DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOR(p->livery[scheme].colour2), 277, y);
+					DrawString(290, y, STR_00D1_DARK_BLUE + p->livery[scheme].colour2, sel ? TC_WHITE : TC_GOLD);
+				}
+
+				y += 14;
+			}
 		}
 	}
 
-	/* Get the first selected livery to use as the default dropdown item */
-	for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
-		if (HasBit(WP(w, livery_d).sel, scheme)) break;
-	}
-	if (scheme == LS_END) scheme = LS_DEFAULT;
-	livery = &GetPlayer((PlayerID)w->window_number)->livery[scheme];
-
-	DropDownList *list = new DropDownList();
-	for (uint i = 0; i < lengthof(_colour_dropdown); i++) {
-		list->push_back(new DropDownListColourItem(i, HasBit(used_colours, i)));
-	}
-
-	ShowDropDownList(w, list, widget == PLW_WIDGET_PRI_COL_DROPDOWN ? livery->colour1 : livery->colour2, widget);
-}
+	virtual void OnClick(Point pt, int widget)
+	{
+		/* Number of liveries in each class, used to determine the height of the livery window */
+		static const byte livery_height[] = {
+			1,
+			13,
+			4,
+			2,
+			3,
+		};
 
-static void SelectPlayerLiveryWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_CREATE:
-			w->LowerWidget(WP(w, livery_d).livery_class + PLW_WIDGET_CLASS_GENERAL);
-			if (!_loaded_newgrf_features.has_2CC) {
-				w->HideWidget(PLW_WIDGET_SEC_COL_DROPDOWN);
-			}
-			break;
+		switch (widget) {
+			/* Livery Class buttons */
+			case PLW_WIDGET_CLASS_GENERAL:
+			case PLW_WIDGET_CLASS_RAIL:
+			case PLW_WIDGET_CLASS_ROAD:
+			case PLW_WIDGET_CLASS_SHIP:
+			case PLW_WIDGET_CLASS_AIRCRAFT: {
+				LiveryScheme scheme;
 
-		case WE_PAINT: {
-			const Player *p = GetPlayer((PlayerID)w->window_number);
-			LiveryScheme scheme = LS_DEFAULT;
-			int y = 51;
+				this->RaiseWidget(this->livery_class + PLW_WIDGET_CLASS_GENERAL);
+				this->livery_class = (LiveryClass)(widget - PLW_WIDGET_CLASS_GENERAL);
+				this->sel = 0;
+				this->LowerWidget(this->livery_class + PLW_WIDGET_CLASS_GENERAL);
 
-			/* Disable dropdown controls if no scheme is selected */
-			w->SetWidgetDisabledState(PLW_WIDGET_PRI_COL_DROPDOWN, (WP(w, livery_d).sel == 0));
-			w->SetWidgetDisabledState(PLW_WIDGET_SEC_COL_DROPDOWN, (WP(w, livery_d).sel == 0));
-
-			if (!(WP(w, livery_d).sel == 0)) {
-				for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
-					if (HasBit(WP(w, livery_d).sel, scheme)) break;
+				/* Select the first item in the list */
+				for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
+					if (_livery_class[scheme] == this->livery_class) {
+						this->sel = 1 << scheme;
+						break;
+					}
 				}
-				if (scheme == LS_END) scheme = LS_DEFAULT;
+				this->height = 49 + livery_height[this->livery_class] * 14;
+				this->widget[PLW_WIDGET_MATRIX].bottom = this->height - 1;
+				this->widget[PLW_WIDGET_MATRIX].data = livery_height[this->livery_class] << 8 | 1;
+				MarkWholeScreenDirty();
+				break;
 			}
 
-			SetDParam(0, STR_00D1_DARK_BLUE + p->livery[scheme].colour1);
-			SetDParam(1, STR_00D1_DARK_BLUE + p->livery[scheme].colour2);
-
-			DrawWindowWidgets(w);
-
-			for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
-				if (livery_class[scheme] == WP(w, livery_d).livery_class) {
-					bool sel = HasBit(WP(w, livery_d).sel, scheme) != 0;
+			case PLW_WIDGET_PRI_COL_DROPDOWN: /* First colour dropdown */
+				ShowColourDropDownMenu(PLW_WIDGET_PRI_COL_DROPDOWN);
+				break;
 
-					if (scheme != LS_DEFAULT) {
-						DrawSprite(p->livery[scheme].in_use ? SPR_BOX_CHECKED : SPR_BOX_EMPTY, PAL_NONE, 2, y);
-					}
-
-					DrawString(15, y, STR_LIVERY_DEFAULT + scheme, sel ? TC_WHITE : TC_BLACK);
+			case PLW_WIDGET_SEC_COL_DROPDOWN: /* Second colour dropdown */
+				ShowColourDropDownMenu(PLW_WIDGET_SEC_COL_DROPDOWN);
+				break;
 
-					DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOR(p->livery[scheme].colour1), 152, y);
-					DrawString(165, y, STR_00D1_DARK_BLUE + p->livery[scheme].colour1, sel ? TC_WHITE : TC_GOLD);
+			case PLW_WIDGET_MATRIX: {
+				LiveryScheme scheme;
+				LiveryScheme j = (LiveryScheme)((pt.y - 48) / 14);
 
-					if (_loaded_newgrf_features.has_2CC) {
-						DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOR(p->livery[scheme].colour2), 277, y);
-						DrawString(290, y, STR_00D1_DARK_BLUE + p->livery[scheme].colour2, sel ? TC_WHITE : TC_GOLD);
-					}
-
-					y += 14;
+				for (scheme = LS_BEGIN; scheme <= j; scheme++) {
+					if (_livery_class[scheme] != this->livery_class) j++;
+					if (scheme >= LS_END) return;
 				}
-			}
-			break;
-		}
-
-		case WE_CLICK: {
-			switch (e->we.click.widget) {
-				/* Livery Class buttons */
-				case PLW_WIDGET_CLASS_GENERAL:
-				case PLW_WIDGET_CLASS_RAIL:
-				case PLW_WIDGET_CLASS_ROAD:
-				case PLW_WIDGET_CLASS_SHIP:
-				case PLW_WIDGET_CLASS_AIRCRAFT: {
-					LiveryScheme scheme;
+				if (j >= LS_END) return;
 
-					w->RaiseWidget(WP(w, livery_d).livery_class + PLW_WIDGET_CLASS_GENERAL);
-					WP(w, livery_d).livery_class = (LiveryClass)(e->we.click.widget - PLW_WIDGET_CLASS_GENERAL);
-					WP(w, livery_d).sel = 0;
-					w->LowerWidget(WP(w, livery_d).livery_class + PLW_WIDGET_CLASS_GENERAL);
-
-					/* Select the first item in the list */
-					for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
-						if (livery_class[scheme] == WP(w, livery_d).livery_class) {
-							WP(w, livery_d).sel = 1 << scheme;
-							break;
-						}
-					}
-					w->height = 49 + livery_height[WP(w, livery_d).livery_class] * 14;
-					w->widget[PLW_WIDGET_MATRIX].bottom = w->height - 1;
-					w->widget[PLW_WIDGET_MATRIX].data = livery_height[WP(w, livery_d).livery_class] << 8 | 1;
-					MarkWholeScreenDirty();
-					break;
+				/* If clicking on the left edge, toggle using the livery */
+				if (pt.x < 10) {
+					DoCommandP(0, j | (2 << 8), !GetPlayer((PlayerID)this->window_number)->livery[j].in_use, NULL, CMD_SET_PLAYER_COLOR);
 				}
 
-				case PLW_WIDGET_PRI_COL_DROPDOWN: /* First colour dropdown */
-					ShowColourDropDownMenu(w, PLW_WIDGET_PRI_COL_DROPDOWN);
-					break;
-
-				case PLW_WIDGET_SEC_COL_DROPDOWN: /* Second colour dropdown */
-					ShowColourDropDownMenu(w, PLW_WIDGET_SEC_COL_DROPDOWN);
-					break;
-
-				case PLW_WIDGET_MATRIX: {
-					LiveryScheme scheme;
-					LiveryScheme j = (LiveryScheme)((e->we.click.pt.y - 48) / 14);
-
-					for (scheme = LS_BEGIN; scheme <= j; scheme++) {
-						if (livery_class[scheme] != WP(w, livery_d).livery_class) j++;
-						if (scheme >= LS_END) return;
-					}
-					if (j >= LS_END) return;
-
-					/* If clicking on the left edge, toggle using the livery */
-					if (e->we.click.pt.x < 10) {
-						DoCommandP(0, j | (2 << 8), !GetPlayer((PlayerID)w->window_number)->livery[j].in_use, NULL, CMD_SET_PLAYER_COLOR);
-					}
-
-					if (_ctrl_pressed) {
-						ToggleBit(WP(w, livery_d).sel, j);
-					} else {
-						WP(w, livery_d).sel = 1 << j;
-					}
-					w->SetDirty();
-					break;
+				if (_ctrl_pressed) {
+					ToggleBit(this->sel, j);
+				} else {
+					this->sel = 1 << j;
 				}
+				this->SetDirty();
+				break;
 			}
-			break;
-		}
-
-		case WE_DROPDOWN_SELECT: {
-			LiveryScheme scheme;
-
-			for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
-				if (HasBit(WP(w, livery_d).sel, scheme)) {
-					DoCommandP(0, scheme | (e->we.dropdown.button == PLW_WIDGET_PRI_COL_DROPDOWN ? 0 : 256), e->we.dropdown.index, NULL, CMD_SET_PLAYER_COLOR);
-				}
-			}
-			break;
 		}
 	}
-}
 
-static const Widget _select_player_livery_2cc_widgets[] = {
+	virtual void OnDropdownSelect(int widget, int index)
+	{
+		for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
+			if (HasBit(this->sel, scheme)) {
+				DoCommandP(0, scheme | (widget == PLW_WIDGET_PRI_COL_DROPDOWN ? 0 : 256), index, NULL, CMD_SET_PLAYER_COLOR);
+			}
+		}
+	}
+
+	virtual void OnInvalidateData(int data = 0)
+	{
+		static bool has2cc = true;
+
+		if (has2cc == !!data) return;
+
+		has2cc = !!data;
+
+		int r = this->widget[has2cc ? PLW_WIDGET_SEC_COL_DROPDOWN : PLW_WIDGET_PRI_COL_DROPDOWN].right;
+		this->SetWidgetHiddenState(PLW_WIDGET_SEC_COL_DROPDOWN, !has2cc);
+		this->widget[PLW_WIDGET_CAPTION].right = r;
+		this->widget[PLW_WIDGET_SPACER_CLASS].right = r;
+		this->widget[PLW_WIDGET_MATRIX].right = r;
+		this->width = r + 1;
+	}
+};
+
+static const Widget _select_player_livery_widgets[] = {
 { WWT_CLOSEBOX, RESIZE_NONE, 14,   0,  10,   0,  13, STR_00C5,                  STR_018B_CLOSE_WINDOW },
 {  WWT_CAPTION, RESIZE_NONE, 14,  11, 399,   0,  13, STR_7007_NEW_COLOR_SCHEME, STR_018C_WINDOW_TITLE_DRAG_THIS },
 {   WWT_IMGBTN, RESIZE_NONE, 14,   0,  21,  14,  35, SPR_IMG_COMPANY_GENERAL,   STR_LIVERY_GENERAL_TIP },
@@ -531,37 +536,11 @@
 { WIDGETS_END },
 };
 
-static const WindowDesc _select_player_livery_2cc_desc = {
+static const WindowDesc _select_player_livery_desc = {
 	WDP_AUTO, WDP_AUTO, 400, 49 + 1 * 14, 400, 49 + 1 * 14,
 	WC_PLAYER_COLOR, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_select_player_livery_2cc_widgets,
-	SelectPlayerLiveryWndProc
-};
-
-
-static const Widget _select_player_livery_widgets[] = {
-{ WWT_CLOSEBOX, RESIZE_NONE, 14,   0,  10,   0,  13, STR_00C5,                  STR_018B_CLOSE_WINDOW },
-{  WWT_CAPTION, RESIZE_NONE, 14,  11, 274,   0,  13, STR_7007_NEW_COLOR_SCHEME, STR_018C_WINDOW_TITLE_DRAG_THIS },
-{   WWT_IMGBTN, RESIZE_NONE, 14,   0,  21,  14,  35, SPR_IMG_COMPANY_GENERAL,   STR_LIVERY_GENERAL_TIP },
-{   WWT_IMGBTN, RESIZE_NONE, 14,  22,  43,  14,  35, SPR_IMG_TRAINLIST,         STR_LIVERY_TRAIN_TIP },
-{   WWT_IMGBTN, RESIZE_NONE, 14,  44,  65,  14,  35, SPR_IMG_TRUCKLIST,         STR_LIVERY_ROADVEH_TIP },
-{   WWT_IMGBTN, RESIZE_NONE, 14,  66,  87,  14,  35, SPR_IMG_SHIPLIST,          STR_LIVERY_SHIP_TIP },
-{   WWT_IMGBTN, RESIZE_NONE, 14,  88, 109,  14,  35, SPR_IMG_AIRPLANESLIST,     STR_LIVERY_AIRCRAFT_TIP },
-{    WWT_PANEL, RESIZE_NONE, 14, 110, 274,  14,  35, 0x0,                       STR_NULL },
-{    WWT_PANEL, RESIZE_NONE, 14,   0, 149,  36,  47, 0x0,                       STR_NULL },
-{ WWT_DROPDOWN, RESIZE_NONE, 14, 150, 274,  36,  47, STR_02BD,                  STR_LIVERY_PRIMARY_TIP },
-{ WWT_DROPDOWN, RESIZE_NONE, 14, 275, 275,  36,  47, STR_02E1,                  STR_LIVERY_SECONDARY_TIP },
-{   WWT_MATRIX, RESIZE_NONE, 14,   0, 274,  48,  48 + 1 * 14, (1 << 8) | 1,     STR_LIVERY_PANEL_TIP },
-{ WIDGETS_END },
-};
-
-static const WindowDesc _select_player_livery_desc = {
-	WDP_AUTO, WDP_AUTO, 275, 49 + 1 * 14, 275, 49 + 1 * 14,
-	WC_PLAYER_COLOR, WC_NONE,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 	_select_player_livery_widgets,
-	SelectPlayerLiveryWndProc
 };
 
 /**
@@ -608,62 +587,6 @@
 	}
 }
 
-/**
- * Names of the widgets. Keep them in the same order as in the widget array.
- * Do not change the order of the widgets from PFW_WIDGET_HAS_MOUSTACHE_EARRING to PFW_WIDGET_GLASSES_R,
- * this order is needed for the WE_CLICK event of DrawFaceStringLabel().
- */
-enum PlayerFaceWindowWidgets {
-	PFW_WIDGET_CLOSEBOX = 0,
-	PFW_WIDGET_CAPTION,
-	PFW_WIDGET_TOGGLE_LARGE_SMALL,
-	PFW_WIDGET_SELECT_FACE,
-	PFW_WIDGET_CANCEL,
-	PFW_WIDGET_ACCEPT,
-	PFW_WIDGET_MALE,
-	PFW_WIDGET_FEMALE,
-	PFW_WIDGET_RANDOM_NEW_FACE,
-	PFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON,
-	/* from here is the advanced player face selection window */
-	PFW_WIDGET_LOAD,
-	PFW_WIDGET_FACECODE,
-	PFW_WIDGET_SAVE,
-	PFW_WIDGET_ETHNICITY_EUR,
-	PFW_WIDGET_ETHNICITY_AFR,
-	PFW_WIDGET_HAS_MOUSTACHE_EARRING,
-	PFW_WIDGET_HAS_GLASSES,
-	PFW_WIDGET_EYECOLOUR_L,
-	PFW_WIDGET_EYECOLOUR,
-	PFW_WIDGET_EYECOLOUR_R,
-	PFW_WIDGET_CHIN_L,
-	PFW_WIDGET_CHIN,
-	PFW_WIDGET_CHIN_R,
-	PFW_WIDGET_EYEBROWS_L,
-	PFW_WIDGET_EYEBROWS,
-	PFW_WIDGET_EYEBROWS_R,
-	PFW_WIDGET_LIPS_MOUSTACHE_L,
-	PFW_WIDGET_LIPS_MOUSTACHE,
-	PFW_WIDGET_LIPS_MOUSTACHE_R,
-	PFW_WIDGET_NOSE_L,
-	PFW_WIDGET_NOSE,
-	PFW_WIDGET_NOSE_R,
-	PFW_WIDGET_HAIR_L,
-	PFW_WIDGET_HAIR,
-	PFW_WIDGET_HAIR_R,
-	PFW_WIDGET_JACKET_L,
-	PFW_WIDGET_JACKET,
-	PFW_WIDGET_JACKET_R,
-	PFW_WIDGET_COLLAR_L,
-	PFW_WIDGET_COLLAR,
-	PFW_WIDGET_COLLAR_R,
-	PFW_WIDGET_TIE_EARRING_L,
-	PFW_WIDGET_TIE_EARRING,
-	PFW_WIDGET_TIE_EARRING_R,
-	PFW_WIDGET_GLASSES_L,
-	PFW_WIDGET_GLASSES,
-	PFW_WIDGET_GLASSES_R,
-};
-
 /** Widget description for the normal/simple player face selection dialog */
 static const Widget _select_player_face_widgets[] = {
 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                STR_018B_CLOSE_WINDOW},              // PFW_WIDGET_CLOSEBOX
@@ -731,267 +654,352 @@
 {   WIDGETS_END},
 };
 
-/**
- * Draw dynamic a label to the left of the button and a value in the button
- *
- * @param w              Window on which the widget is located
- * @param widget_index   index of this widget in the window
- * @param str            the label which will be draw
- * @param val            the value which will be draw
- * @param is_bool_widget is it a bool button
- */
-void DrawFaceStringLabel(const Window *w, byte widget_index, StringID str, uint8 val, bool is_bool_widget)
+class SelectPlayerFaceWindow : public Window
 {
-	/* Write the label in gold (0x2) to the left of the button. */
-	DrawStringRightAligned(w->widget[widget_index].left - (is_bool_widget ? 5 : 14), w->widget[widget_index].top + 1, str, TC_GOLD);
-
-	if (!w->IsWidgetDisabled(widget_index)) {
-		if (is_bool_widget) {
-			/* if it a bool button write yes or no */
-			str = (val != 0) ? STR_FACE_YES : STR_FACE_NO;
-		} else {
-			/* else write the value + 1 */
-			SetDParam(0, val + 1);
-			str = STR_JUST_INT;
-		}
-
-		/* Draw the value/bool in white (0xC). If the button clicked adds 1px to x and y text coordinates (IsWindowWidgetLowered()). */
-		DrawStringCentered(w->widget[widget_index].left + (w->widget[widget_index].right - w->widget[widget_index].left) / 2 +
-			w->IsWidgetLowered(widget_index), w->widget[widget_index].top + 1 + w->IsWidgetLowered(widget_index), str, TC_WHITE);
-	}
-}
-
-/**
- * Player face selection window event definition
- *
- * @param w window pointer
- * @param e event been triggered
- */
-static void SelectPlayerFaceWndProc(Window *w, WindowEvent *e)
-{
-	PlayerFace *pf = &WP(w, facesel_d).face; // pointer to the player face bits
-	GenderEthnicity ge = (GenderEthnicity)GB(*pf, _pf_info[PFV_GEN_ETHN].offset, _pf_info[PFV_GEN_ETHN].length); // get the gender and ethnicity
-	bool is_female = HasBit(ge, GENDER_FEMALE); // get the gender: 0 == male and 1 == female
-	bool is_moust_male = !is_female && GetPlayerFaceBits(*pf, PFV_HAS_MOUSTACHE, ge) != 0; // is a male face with moustache
-
-	switch (e->event) {
-		case WE_PAINT:
-			/* lower the non-selected gender button */
-			w->SetWidgetLoweredState(PFW_WIDGET_MALE,  !is_female);
-			w->SetWidgetLoweredState(PFW_WIDGET_FEMALE, is_female);
+	PlayerFace face; // player face bits
+	bool advanced;   // advance player face selection window
 
-			/* advanced player face selection window */
-			if (WP(w, facesel_d).advanced) {
-				/* lower the non-selected ethnicity button */
-				w->SetWidgetLoweredState(PFW_WIDGET_ETHNICITY_EUR, !HasBit(ge, ETHNICITY_BLACK));
-				w->SetWidgetLoweredState(PFW_WIDGET_ETHNICITY_AFR,  HasBit(ge, ETHNICITY_BLACK));
-
-
-				/* Disable dynamically the widgets which PlayerFaceVariable has less than 2 options
-				* (or in other words you haven't any choice).
-				* If the widgets depend on a HAS-variable and this is false the widgets will be disabled, too. */
-
-				/* Eye colour buttons */
-				w->SetWidgetsDisabledState(_pf_info[PFV_EYE_COLOUR].valid_values[ge] < 2,
-					PFW_WIDGET_EYECOLOUR, PFW_WIDGET_EYECOLOUR_L, PFW_WIDGET_EYECOLOUR_R, WIDGET_LIST_END);
-
-				/* Chin buttons */
-				w->SetWidgetsDisabledState(_pf_info[PFV_CHIN].valid_values[ge] < 2,
-					PFW_WIDGET_CHIN, PFW_WIDGET_CHIN_L, PFW_WIDGET_CHIN_R, WIDGET_LIST_END);
-
-				/* Eyebrows buttons */
-				w->SetWidgetsDisabledState(_pf_info[PFV_EYEBROWS].valid_values[ge] < 2,
-					PFW_WIDGET_EYEBROWS, PFW_WIDGET_EYEBROWS_L, PFW_WIDGET_EYEBROWS_R, WIDGET_LIST_END);
+	GenderEthnicity ge;
+	bool is_female;
+	bool is_moust_male;
 
-				/* Lips or (if it a male face with a moustache) moustache buttons */
-				w->SetWidgetsDisabledState(_pf_info[is_moust_male ? PFV_MOUSTACHE : PFV_LIPS].valid_values[ge] < 2,
-					PFW_WIDGET_LIPS_MOUSTACHE, PFW_WIDGET_LIPS_MOUSTACHE_L, PFW_WIDGET_LIPS_MOUSTACHE_R, WIDGET_LIST_END);
-
-				/* Nose buttons | male faces with moustache haven't any nose options */
-				w->SetWidgetsDisabledState(_pf_info[PFV_NOSE].valid_values[ge] < 2 || is_moust_male,
-					PFW_WIDGET_NOSE, PFW_WIDGET_NOSE_L, PFW_WIDGET_NOSE_R, WIDGET_LIST_END);
-
-				/* Hair buttons */
-				w->SetWidgetsDisabledState(_pf_info[PFV_HAIR].valid_values[ge] < 2,
-					PFW_WIDGET_HAIR, PFW_WIDGET_HAIR_L, PFW_WIDGET_HAIR_R, WIDGET_LIST_END);
+	/**
+	 * Names of the widgets. Keep them in the same order as in the widget array.
+	 * Do not change the order of the widgets from PFW_WIDGET_HAS_MOUSTACHE_EARRING to PFW_WIDGET_GLASSES_R,
+	 * this order is needed for the WE_CLICK event of DrawFaceStringLabel().
+	 */
+	enum PlayerFaceWindowWidgets {
+		PFW_WIDGET_CLOSEBOX = 0,
+		PFW_WIDGET_CAPTION,
+		PFW_WIDGET_TOGGLE_LARGE_SMALL,
+		PFW_WIDGET_SELECT_FACE,
+		PFW_WIDGET_CANCEL,
+		PFW_WIDGET_ACCEPT,
+		PFW_WIDGET_MALE,
+		PFW_WIDGET_FEMALE,
+		PFW_WIDGET_RANDOM_NEW_FACE,
+		PFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON,
+		/* from here is the advanced player face selection window */
+		PFW_WIDGET_LOAD,
+		PFW_WIDGET_FACECODE,
+		PFW_WIDGET_SAVE,
+		PFW_WIDGET_ETHNICITY_EUR,
+		PFW_WIDGET_ETHNICITY_AFR,
+		PFW_WIDGET_HAS_MOUSTACHE_EARRING,
+		PFW_WIDGET_HAS_GLASSES,
+		PFW_WIDGET_EYECOLOUR_L,
+		PFW_WIDGET_EYECOLOUR,
+		PFW_WIDGET_EYECOLOUR_R,
+		PFW_WIDGET_CHIN_L,
+		PFW_WIDGET_CHIN,
+		PFW_WIDGET_CHIN_R,
+		PFW_WIDGET_EYEBROWS_L,
+		PFW_WIDGET_EYEBROWS,
+		PFW_WIDGET_EYEBROWS_R,
+		PFW_WIDGET_LIPS_MOUSTACHE_L,
+		PFW_WIDGET_LIPS_MOUSTACHE,
+		PFW_WIDGET_LIPS_MOUSTACHE_R,
+		PFW_WIDGET_NOSE_L,
+		PFW_WIDGET_NOSE,
+		PFW_WIDGET_NOSE_R,
+		PFW_WIDGET_HAIR_L,
+		PFW_WIDGET_HAIR,
+		PFW_WIDGET_HAIR_R,
+		PFW_WIDGET_JACKET_L,
+		PFW_WIDGET_JACKET,
+		PFW_WIDGET_JACKET_R,
+		PFW_WIDGET_COLLAR_L,
+		PFW_WIDGET_COLLAR,
+		PFW_WIDGET_COLLAR_R,
+		PFW_WIDGET_TIE_EARRING_L,
+		PFW_WIDGET_TIE_EARRING,
+		PFW_WIDGET_TIE_EARRING_R,
+		PFW_WIDGET_GLASSES_L,
+		PFW_WIDGET_GLASSES,
+		PFW_WIDGET_GLASSES_R,
+	};
+	/**
+	 * Draw dynamic a label to the left of the button and a value in the button
+	 *
+	 * @param widget_index   index of this widget in the window
+	 * @param str            the label which will be draw
+	 * @param val            the value which will be draw
+	 * @param is_bool_widget is it a bool button
+	 */
+	void DrawFaceStringLabel(byte widget_index, StringID str, uint8 val, bool is_bool_widget)
+	{
+		/* Write the label in gold (0x2) to the left of the button. */
+		DrawStringRightAligned(this->widget[widget_index].left - (is_bool_widget ? 5 : 14), this->widget[widget_index].top + 1, str, TC_GOLD);
 
-				/* Jacket buttons */
-				w->SetWidgetsDisabledState(_pf_info[PFV_JACKET].valid_values[ge] < 2,
-					PFW_WIDGET_JACKET, PFW_WIDGET_JACKET_L, PFW_WIDGET_JACKET_R, WIDGET_LIST_END);
-
-				/* Collar buttons */
-				w->SetWidgetsDisabledState(_pf_info[PFV_COLLAR].valid_values[ge] < 2,
-					PFW_WIDGET_COLLAR, PFW_WIDGET_COLLAR_L, PFW_WIDGET_COLLAR_R, WIDGET_LIST_END);
-
-				/* Tie/earring buttons | female faces without earring haven't any earring options */
-				w->SetWidgetsDisabledState(_pf_info[PFV_TIE_EARRING].valid_values[ge] < 2 ||
-						(is_female && GetPlayerFaceBits(*pf, PFV_HAS_TIE_EARRING, ge) == 0),
-					PFW_WIDGET_TIE_EARRING, PFW_WIDGET_TIE_EARRING_L, PFW_WIDGET_TIE_EARRING_R, WIDGET_LIST_END);
-
-				/* Glasses buttons | faces without glasses haven't any glasses options */
-				w->SetWidgetsDisabledState(_pf_info[PFV_GLASSES].valid_values[ge] < 2 || GetPlayerFaceBits(*pf, PFV_HAS_GLASSES, ge) == 0,
-					PFW_WIDGET_GLASSES, PFW_WIDGET_GLASSES_L, PFW_WIDGET_GLASSES_R, WIDGET_LIST_END);
+		if (!this->IsWidgetDisabled(widget_index)) {
+			if (is_bool_widget) {
+				/* if it a bool button write yes or no */
+				str = (val != 0) ? STR_FACE_YES : STR_FACE_NO;
+			} else {
+				/* else write the value + 1 */
+				SetDParam(0, val + 1);
+				str = STR_JUST_INT;
 			}
 
-			DrawWindowWidgets(w);
-
-			/* Draw dynamic button value and labels for the advanced player face selection window */
-			if (WP(w, facesel_d).advanced) {
-				if (is_female) {
-					/* Only for female faces */
-					DrawFaceStringLabel(w, PFW_WIDGET_HAS_MOUSTACHE_EARRING, STR_FACE_EARRING,   GetPlayerFaceBits(*pf, PFV_HAS_TIE_EARRING, ge), true );
-					DrawFaceStringLabel(w, PFW_WIDGET_TIE_EARRING,           STR_FACE_EARRING,   GetPlayerFaceBits(*pf, PFV_TIE_EARRING,     ge), false);
-				} else {
-					/* Only for male faces */
-					DrawFaceStringLabel(w, PFW_WIDGET_HAS_MOUSTACHE_EARRING, STR_FACE_MOUSTACHE, GetPlayerFaceBits(*pf, PFV_HAS_MOUSTACHE,   ge), true );
-					DrawFaceStringLabel(w, PFW_WIDGET_TIE_EARRING,           STR_FACE_TIE,       GetPlayerFaceBits(*pf, PFV_TIE_EARRING,     ge), false);
-				}
-				if (is_moust_male) {
-					/* Only for male faces with moustache */
-					DrawFaceStringLabel(w, PFW_WIDGET_LIPS_MOUSTACHE,        STR_FACE_MOUSTACHE, GetPlayerFaceBits(*pf, PFV_MOUSTACHE,       ge), false);
-				} else {
-					/* Only for female faces or male faces without moustache */
-					DrawFaceStringLabel(w, PFW_WIDGET_LIPS_MOUSTACHE,        STR_FACE_LIPS,      GetPlayerFaceBits(*pf, PFV_LIPS,            ge), false);
-				}
-				/* For all faces */
-				DrawFaceStringLabel(w, PFW_WIDGET_HAS_GLASSES,           STR_FACE_GLASSES,     GetPlayerFaceBits(*pf, PFV_HAS_GLASSES,     ge), true );
-				DrawFaceStringLabel(w, PFW_WIDGET_HAIR,                  STR_FACE_HAIR,        GetPlayerFaceBits(*pf, PFV_HAIR,            ge), false);
-				DrawFaceStringLabel(w, PFW_WIDGET_EYEBROWS,              STR_FACE_EYEBROWS,    GetPlayerFaceBits(*pf, PFV_EYEBROWS,        ge), false);
-				DrawFaceStringLabel(w, PFW_WIDGET_EYECOLOUR,             STR_FACE_EYECOLOUR,   GetPlayerFaceBits(*pf, PFV_EYE_COLOUR,      ge), false);
-				DrawFaceStringLabel(w, PFW_WIDGET_GLASSES,               STR_FACE_GLASSES,     GetPlayerFaceBits(*pf, PFV_GLASSES,         ge), false);
-				DrawFaceStringLabel(w, PFW_WIDGET_NOSE,                  STR_FACE_NOSE,        GetPlayerFaceBits(*pf, PFV_NOSE,            ge), false);
-				DrawFaceStringLabel(w, PFW_WIDGET_CHIN,                  STR_FACE_CHIN,        GetPlayerFaceBits(*pf, PFV_CHIN,            ge), false);
-				DrawFaceStringLabel(w, PFW_WIDGET_JACKET,                STR_FACE_JACKET,      GetPlayerFaceBits(*pf, PFV_JACKET,          ge), false);
-				DrawFaceStringLabel(w, PFW_WIDGET_COLLAR,                STR_FACE_COLLAR,      GetPlayerFaceBits(*pf, PFV_COLLAR,          ge), false);
-			}
-
-			/* Draw the player face picture */
-			DrawPlayerFace(*pf, GetPlayer((PlayerID)w->window_number)->player_color, 2, 16);
-			break;
-
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				/* Toggle size, advanced/simple face selection */
-				case PFW_WIDGET_TOGGLE_LARGE_SMALL:
-				case PFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON: {
-					int oldtop = w->top;     ///< current top position of the window before closing it
-					int oldleft = w->left;   ///< current top position of the window before closing it
-
-					DoCommandP(0, 0, *pf, NULL, CMD_SET_PLAYER_FACE);
-					delete w;
-					/* Open up the (toggled size) Face selection window at the same position as the previous */
-					DoSelectPlayerFace((PlayerID)w->window_number, !WP(w, facesel_d).advanced, oldtop, oldleft);
-				} break;
-
-				/* Cancel button */
-				case PFW_WIDGET_CANCEL:
-					delete w;
-					break;
-
-				/* OK button */
-				case PFW_WIDGET_ACCEPT:
-					DoCommandP(0, 0, *pf, NULL, CMD_SET_PLAYER_FACE);
-					delete w;
-					break;
-
-				/* Load button */
-				case PFW_WIDGET_LOAD:
-					*pf = _player_face;
-					ScaleAllPlayerFaceBits(*pf);
-					ShowErrorMessage(INVALID_STRING_ID, STR_FACE_LOAD_DONE, 0, 0);
-					w->SetDirty();
-					break;
-
-				/* 'Player face number' button, view and/or set player face number */
-				case PFW_WIDGET_FACECODE:
-					SetDParam(0, *pf);
-					ShowQueryString(STR_JUST_INT, STR_FACE_FACECODE_CAPTION, 10 + 1, 0, w, CS_NUMERAL);
-					break;
+			/* Draw the value/bool in white (0xC). If the button clicked adds 1px to x and y text coordinates (IsWindowWidgetLowered()). */
+			DrawStringCentered(this->widget[widget_index].left + (this->widget[widget_index].right - this->widget[widget_index].left) / 2 +
+				this->IsWidgetLowered(widget_index), this->widget[widget_index].top + 1 + this->IsWidgetLowered(widget_index), str, TC_WHITE);
+		}
+	}
 
-				/* Save button */
-				case PFW_WIDGET_SAVE:
-					_player_face = *pf;
-					ShowErrorMessage(INVALID_STRING_ID, STR_FACE_SAVE_DONE, 0, 0);
-					break;
-
-				/* Toggle gender (male/female) button */
-				case PFW_WIDGET_MALE:
-				case PFW_WIDGET_FEMALE:
-					SetPlayerFaceBits(*pf, PFV_GENDER, ge, e->we.click.widget - PFW_WIDGET_MALE);
-					ScaleAllPlayerFaceBits(*pf);
-					w->SetDirty();
-					break;
-
-				/* Randomize face button */
-				case PFW_WIDGET_RANDOM_NEW_FACE:
-					RandomPlayerFaceBits(*pf, ge, WP(w, facesel_d).advanced);
-					w->SetDirty();
-					break;
-
-				/* Toggle ethnicity (european/african) button */
-				case PFW_WIDGET_ETHNICITY_EUR:
-				case PFW_WIDGET_ETHNICITY_AFR:
-					SetPlayerFaceBits(*pf, PFV_ETHNICITY, ge, e->we.click.widget - PFW_WIDGET_ETHNICITY_EUR);
-					ScaleAllPlayerFaceBits(*pf);
-					w->SetDirty();
-					break;
-
-				default:
-					/* For all buttons from PFW_WIDGET_HAS_MOUSTACHE_EARRING to PFW_WIDGET_GLASSES_R is the same function.
-					* Therefor is this combined function.
-					* First it checks which PlayerFaceVariable will be change and then
-					* a: invert the value for boolean variables
-					* or b: it checks inside of IncreasePlayerFaceBits() if a left (_L) butten is pressed and then decrease else increase the variable */
-					if (WP(w, facesel_d).advanced && e->we.click.widget >= PFW_WIDGET_HAS_MOUSTACHE_EARRING && e->we.click.widget <= PFW_WIDGET_GLASSES_R) {
-						PlayerFaceVariable pfv; // which PlayerFaceVariable shall be edited
+	void UpdateData()
+	{
+		this->ge = (GenderEthnicity)GB(this->face, _pf_info[PFV_GEN_ETHN].offset, _pf_info[PFV_GEN_ETHN].length); // get the gender and ethnicity
+		this->is_female = HasBit(this->ge, GENDER_FEMALE); // get the gender: 0 == male and 1 == female
+		this->is_moust_male = !is_female && GetPlayerFaceBits(this->face, PFV_HAS_MOUSTACHE, this->ge) != 0; // is a male face with moustache
+	}
 
-						if (e->we.click.widget < PFW_WIDGET_EYECOLOUR_L) { // Bool buttons
-							switch (e->we.click.widget - PFW_WIDGET_HAS_MOUSTACHE_EARRING) {
-								default: NOT_REACHED();
-								case 0: pfv = is_female ? PFV_HAS_TIE_EARRING : PFV_HAS_MOUSTACHE; break; // Has earring/moustache button
-								case 1: pfv = PFV_HAS_GLASSES; break; // Has glasses button
-							}
-							SetPlayerFaceBits(*pf, pfv, ge, !GetPlayerFaceBits(*pf, pfv, ge));
-							ScaleAllPlayerFaceBits(*pf);
+public:
+	SelectPlayerFaceWindow(const WindowDesc *desc, Window *parent, bool advanced) : Window(desc, parent->window_number)
+	{
+		this->parent = parent;
+		this->FindWindowPlacementAndResize(desc);
+		this->caption_color = this->window_number;
+		this->face = GetPlayer((PlayerID)this->window_number)->face;
+		this->advanced = advanced;
 
-						} else { // Value buttons
-							switch ((e->we.click.widget - PFW_WIDGET_EYECOLOUR_L) / 3) {
-								default: NOT_REACHED();
-								case 0: pfv = PFV_EYE_COLOUR; break;  // Eye colour buttons
-								case 1: pfv = PFV_CHIN; break;        // Chin buttons
-								case 2: pfv = PFV_EYEBROWS; break;    // Eyebrows buttons
-								case 3: pfv = is_moust_male ? PFV_MOUSTACHE : PFV_LIPS; break; // Moustache or lips buttons
-								case 4: pfv = PFV_NOSE; break;        // Nose buttons
-								case 5: pfv = PFV_HAIR; break;        // Hair buttons
-								case 6: pfv = PFV_JACKET; break;      // Jacket buttons
-								case 7: pfv = PFV_COLLAR; break;      // Collar buttons
-								case 8: pfv = PFV_TIE_EARRING; break; // Tie/earring buttons
-								case 9: pfv = PFV_GLASSES; break;     // Glasses buttons
-							}
-							/* 0 == left (_L), 1 == middle or 2 == right (_R) - button click */
-							IncreasePlayerFaceBits(*pf, pfv, ge, (((e->we.click.widget - PFW_WIDGET_EYECOLOUR_L) % 3) != 0) ? 1 : -1);
-						}
+		this->UpdateData();
 
-						w->SetDirty();
-					}
-					break;
-			}
-			break;
+		/* Check if repositioning from default is required */
+		if (top != FIRST_GUI_CALL && left != FIRST_GUI_CALL) {
+			this->top = top;
+			this->left = left;
+		}
+	}
 
-		case WE_ON_EDIT_TEXT:
-			if (e->we.edittext.str == NULL) break;
-			/* Set a new player face number */
-			if (!StrEmpty(e->we.edittext.str)) {
-				*pf = strtoul(e->we.edittext.str, NULL, 10);
-				ScaleAllPlayerFaceBits(*pf);
-				ShowErrorMessage(INVALID_STRING_ID, STR_FACE_FACECODE_SET, 0, 0);
-				w->SetDirty();
+	virtual void OnPaint()
+	{
+		/* lower the non-selected gender button */
+		this->SetWidgetLoweredState(PFW_WIDGET_MALE,  !this->is_female);
+		this->SetWidgetLoweredState(PFW_WIDGET_FEMALE, this->is_female);
+
+		/* advanced player face selection window */
+		if (this->advanced) {
+			/* lower the non-selected ethnicity button */
+			this->SetWidgetLoweredState(PFW_WIDGET_ETHNICITY_EUR, !HasBit(this->ge, ETHNICITY_BLACK));
+			this->SetWidgetLoweredState(PFW_WIDGET_ETHNICITY_AFR,  HasBit(this->ge, ETHNICITY_BLACK));
+
+
+			/* Disable dynamically the widgets which PlayerFaceVariable has less than 2 options
+			* (or in other words you haven't any choice).
+			* If the widgets depend on a HAS-variable and this is false the widgets will be disabled, too. */
+
+			/* Eye colour buttons */
+			this->SetWidgetsDisabledState(_pf_info[PFV_EYE_COLOUR].valid_values[this->ge] < 2,
+				PFW_WIDGET_EYECOLOUR, PFW_WIDGET_EYECOLOUR_L, PFW_WIDGET_EYECOLOUR_R, WIDGET_LIST_END);
+
+			/* Chin buttons */
+			this->SetWidgetsDisabledState(_pf_info[PFV_CHIN].valid_values[this->ge] < 2,
+				PFW_WIDGET_CHIN, PFW_WIDGET_CHIN_L, PFW_WIDGET_CHIN_R, WIDGET_LIST_END);
+
+			/* Eyebrows buttons */
+			this->SetWidgetsDisabledState(_pf_info[PFV_EYEBROWS].valid_values[this->ge] < 2,
+				PFW_WIDGET_EYEBROWS, PFW_WIDGET_EYEBROWS_L, PFW_WIDGET_EYEBROWS_R, WIDGET_LIST_END);
+
+			/* Lips or (if it a male face with a moustache) moustache buttons */
+			this->SetWidgetsDisabledState(_pf_info[this->is_moust_male ? PFV_MOUSTACHE : PFV_LIPS].valid_values[this->ge] < 2,
+				PFW_WIDGET_LIPS_MOUSTACHE, PFW_WIDGET_LIPS_MOUSTACHE_L, PFW_WIDGET_LIPS_MOUSTACHE_R, WIDGET_LIST_END);
+
+			/* Nose buttons | male faces with moustache haven't any nose options */
+			this->SetWidgetsDisabledState(_pf_info[PFV_NOSE].valid_values[this->ge] < 2 || this->is_moust_male,
+				PFW_WIDGET_NOSE, PFW_WIDGET_NOSE_L, PFW_WIDGET_NOSE_R, WIDGET_LIST_END);
+
+			/* Hair buttons */
+			this->SetWidgetsDisabledState(_pf_info[PFV_HAIR].valid_values[this->ge] < 2,
+				PFW_WIDGET_HAIR, PFW_WIDGET_HAIR_L, PFW_WIDGET_HAIR_R, WIDGET_LIST_END);
+
+			/* Jacket buttons */
+			this->SetWidgetsDisabledState(_pf_info[PFV_JACKET].valid_values[this->ge] < 2,
+				PFW_WIDGET_JACKET, PFW_WIDGET_JACKET_L, PFW_WIDGET_JACKET_R, WIDGET_LIST_END);
+
+			/* Collar buttons */
+			this->SetWidgetsDisabledState(_pf_info[PFV_COLLAR].valid_values[this->ge] < 2,
+				PFW_WIDGET_COLLAR, PFW_WIDGET_COLLAR_L, PFW_WIDGET_COLLAR_R, WIDGET_LIST_END);
+
+			/* Tie/earring buttons | female faces without earring haven't any earring options */
+			this->SetWidgetsDisabledState(_pf_info[PFV_TIE_EARRING].valid_values[this->ge] < 2 ||
+					(this->is_female && GetPlayerFaceBits(this->face, PFV_HAS_TIE_EARRING, this->ge) == 0),
+				PFW_WIDGET_TIE_EARRING, PFW_WIDGET_TIE_EARRING_L, PFW_WIDGET_TIE_EARRING_R, WIDGET_LIST_END);
+
+			/* Glasses buttons | faces without glasses haven't any glasses options */
+			this->SetWidgetsDisabledState(_pf_info[PFV_GLASSES].valid_values[this->ge] < 2 || GetPlayerFaceBits(this->face, PFV_HAS_GLASSES, this->ge) == 0,
+				PFW_WIDGET_GLASSES, PFW_WIDGET_GLASSES_L, PFW_WIDGET_GLASSES_R, WIDGET_LIST_END);
+		}
+
+		this->DrawWidgets();
+
+		/* Draw dynamic button value and labels for the advanced player face selection window */
+		if (this->advanced) {
+			if (this->is_female) {
+				/* Only for female faces */
+				this->DrawFaceStringLabel(PFW_WIDGET_HAS_MOUSTACHE_EARRING, STR_FACE_EARRING,   GetPlayerFaceBits(this->face, PFV_HAS_TIE_EARRING, this->ge), true );
+				this->DrawFaceStringLabel(PFW_WIDGET_TIE_EARRING,           STR_FACE_EARRING,   GetPlayerFaceBits(this->face, PFV_TIE_EARRING,     this->ge), false);
 			} else {
-				ShowErrorMessage(INVALID_STRING_ID, STR_FACE_FACECODE_ERR, 0, 0);
+				/* Only for male faces */
+				this->DrawFaceStringLabel(PFW_WIDGET_HAS_MOUSTACHE_EARRING, STR_FACE_MOUSTACHE, GetPlayerFaceBits(this->face, PFV_HAS_MOUSTACHE,   this->ge), true );
+				this->DrawFaceStringLabel(PFW_WIDGET_TIE_EARRING,           STR_FACE_TIE,       GetPlayerFaceBits(this->face, PFV_TIE_EARRING,     this->ge), false);
 			}
-			break;
+			if (this->is_moust_male) {
+				/* Only for male faces with moustache */
+				this->DrawFaceStringLabel(PFW_WIDGET_LIPS_MOUSTACHE,        STR_FACE_MOUSTACHE, GetPlayerFaceBits(this->face, PFV_MOUSTACHE,       this->ge), false);
+			} else {
+				/* Only for female faces or male faces without moustache */
+				this->DrawFaceStringLabel(PFW_WIDGET_LIPS_MOUSTACHE,        STR_FACE_LIPS,      GetPlayerFaceBits(this->face, PFV_LIPS,            this->ge), false);
+			}
+			/* For all faces */
+			this->DrawFaceStringLabel(PFW_WIDGET_HAS_GLASSES,           STR_FACE_GLASSES,     GetPlayerFaceBits(this->face, PFV_HAS_GLASSES,     this->ge), true );
+			this->DrawFaceStringLabel(PFW_WIDGET_HAIR,                  STR_FACE_HAIR,        GetPlayerFaceBits(this->face, PFV_HAIR,            this->ge), false);
+			this->DrawFaceStringLabel(PFW_WIDGET_EYEBROWS,              STR_FACE_EYEBROWS,    GetPlayerFaceBits(this->face, PFV_EYEBROWS,        this->ge), false);
+			this->DrawFaceStringLabel(PFW_WIDGET_EYECOLOUR,             STR_FACE_EYECOLOUR,   GetPlayerFaceBits(this->face, PFV_EYE_COLOUR,      this->ge), false);
+			this->DrawFaceStringLabel(PFW_WIDGET_GLASSES,               STR_FACE_GLASSES,     GetPlayerFaceBits(this->face, PFV_GLASSES,         this->ge), false);
+			this->DrawFaceStringLabel(PFW_WIDGET_NOSE,                  STR_FACE_NOSE,        GetPlayerFaceBits(this->face, PFV_NOSE,            this->ge), false);
+			this->DrawFaceStringLabel(PFW_WIDGET_CHIN,                  STR_FACE_CHIN,        GetPlayerFaceBits(this->face, PFV_CHIN,            this->ge), false);
+			this->DrawFaceStringLabel(PFW_WIDGET_JACKET,                STR_FACE_JACKET,      GetPlayerFaceBits(this->face, PFV_JACKET,          this->ge), false);
+			this->DrawFaceStringLabel(PFW_WIDGET_COLLAR,                STR_FACE_COLLAR,      GetPlayerFaceBits(this->face, PFV_COLLAR,          this->ge), false);
+		}
+
+		/* Draw the player face picture */
+		DrawPlayerFace(this->face, GetPlayer((PlayerID)this->window_number)->player_color, 2, 16);
 	}
-}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			/* Toggle size, advanced/simple face selection */
+			case PFW_WIDGET_TOGGLE_LARGE_SMALL:
+			case PFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON: {
+				DoCommandP(0, 0, this->face, NULL, CMD_SET_PLAYER_FACE);
+
+				/* Backup some data before deletion */
+				int oldtop = this->top;     ///< current top position of the window before closing it
+				int oldleft = this->left;   ///< current top position of the window before closing it
+				bool adv = !this->advanced;
+				Window *parent = this->parent;
+
+				delete this;
+
+				/* Open up the (toggled size) Face selection window at the same position as the previous */
+				DoSelectPlayerFace(parent, adv, oldtop, oldleft);
+			} break;
+
+
+			/* OK button */
+			case PFW_WIDGET_ACCEPT:
+				DoCommandP(0, 0, this->face, NULL, CMD_SET_PLAYER_FACE);
+				/* Fall-Through */
+
+			/* Cancel button */
+			case PFW_WIDGET_CANCEL:
+				delete this;
+				break;
+
+			/* Load button */
+			case PFW_WIDGET_LOAD:
+				this->face = _player_face;
+				ScaleAllPlayerFaceBits(this->face);
+				ShowErrorMessage(INVALID_STRING_ID, STR_FACE_LOAD_DONE, 0, 0);
+				this->UpdateData();
+				this->SetDirty();
+				break;
+
+			/* 'Player face number' button, view and/or set player face number */
+			case PFW_WIDGET_FACECODE:
+				SetDParam(0, this->face);
+				ShowQueryString(STR_JUST_INT, STR_FACE_FACECODE_CAPTION, 10 + 1, 0, this, CS_NUMERAL);
+				break;
+
+			/* Save button */
+			case PFW_WIDGET_SAVE:
+				_player_face = this->face;
+				ShowErrorMessage(INVALID_STRING_ID, STR_FACE_SAVE_DONE, 0, 0);
+				break;
+
+			/* Toggle gender (male/female) button */
+			case PFW_WIDGET_MALE:
+			case PFW_WIDGET_FEMALE:
+				SetPlayerFaceBits(this->face, PFV_GENDER, this->ge, widget - PFW_WIDGET_MALE);
+				ScaleAllPlayerFaceBits(this->face);
+				this->UpdateData();
+				this->SetDirty();
+				break;
+
+			/* Randomize face button */
+			case PFW_WIDGET_RANDOM_NEW_FACE:
+				RandomPlayerFaceBits(this->face, this->ge, this->advanced);
+				this->UpdateData();
+				this->SetDirty();
+				break;
+
+			/* Toggle ethnicity (european/african) button */
+			case PFW_WIDGET_ETHNICITY_EUR:
+			case PFW_WIDGET_ETHNICITY_AFR:
+				SetPlayerFaceBits(this->face, PFV_ETHNICITY, this->ge, widget - PFW_WIDGET_ETHNICITY_EUR);
+				ScaleAllPlayerFaceBits(this->face);
+				this->UpdateData();
+				this->SetDirty();
+				break;
+
+			default:
+				/* For all buttons from PFW_WIDGET_HAS_MOUSTACHE_EARRING to PFW_WIDGET_GLASSES_R is the same function.
+				* Therefor is this combined function.
+				* First it checks which PlayerFaceVariable will be change and then
+				* a: invert the value for boolean variables
+				* or b: it checks inside of IncreasePlayerFaceBits() if a left (_L) butten is pressed and then decrease else increase the variable */
+				if (this->advanced && widget >= PFW_WIDGET_HAS_MOUSTACHE_EARRING && widget <= PFW_WIDGET_GLASSES_R) {
+					PlayerFaceVariable pfv; // which PlayerFaceVariable shall be edited
+
+					if (widget < PFW_WIDGET_EYECOLOUR_L) { // Bool buttons
+						switch (widget - PFW_WIDGET_HAS_MOUSTACHE_EARRING) {
+							default: NOT_REACHED();
+							case 0: pfv = this->is_female ? PFV_HAS_TIE_EARRING : PFV_HAS_MOUSTACHE; break; // Has earring/moustache button
+							case 1: pfv = PFV_HAS_GLASSES; break; // Has glasses button
+						}
+						SetPlayerFaceBits(this->face, pfv, this->ge, !GetPlayerFaceBits(this->face, pfv, this->ge));
+						ScaleAllPlayerFaceBits(this->face);
+					} else { // Value buttons
+						switch ((widget - PFW_WIDGET_EYECOLOUR_L) / 3) {
+							default: NOT_REACHED();
+							case 0: pfv = PFV_EYE_COLOUR; break;  // Eye colour buttons
+							case 1: pfv = PFV_CHIN; break;        // Chin buttons
+							case 2: pfv = PFV_EYEBROWS; break;    // Eyebrows buttons
+							case 3: pfv = this->is_moust_male ? PFV_MOUSTACHE : PFV_LIPS; break; // Moustache or lips buttons
+							case 4: pfv = PFV_NOSE; break;        // Nose buttons
+							case 5: pfv = PFV_HAIR; break;        // Hair buttons
+							case 6: pfv = PFV_JACKET; break;      // Jacket buttons
+							case 7: pfv = PFV_COLLAR; break;      // Collar buttons
+							case 8: pfv = PFV_TIE_EARRING; break; // Tie/earring buttons
+							case 9: pfv = PFV_GLASSES; break;     // Glasses buttons
+						}
+						/* 0 == left (_L), 1 == middle or 2 == right (_R) - button click */
+						IncreasePlayerFaceBits(this->face, pfv, this->ge, (((widget - PFW_WIDGET_EYECOLOUR_L) % 3) != 0) ? 1 : -1);
+					}
+					this->UpdateData();
+					this->SetDirty();
+				}
+				break;
+		}
+	}
+
+	virtual void OnQueryTextFinished(char *str)
+	{
+		if (str == NULL) return;
+		/* Set a new player face number */
+		if (!StrEmpty(str)) {
+			this->face = strtoul(str, NULL, 10);
+			ScaleAllPlayerFaceBits(this->face);
+			ShowErrorMessage(INVALID_STRING_ID, STR_FACE_FACECODE_SET, 0, 0);
+			this->UpdateData();
+			this->SetDirty();
+		} else {
+			ShowErrorMessage(INVALID_STRING_ID, STR_FACE_FACECODE_ERR, 0, 0);
+		}
+	}
+};
 
 /** normal/simple player face selection window description */
 static const WindowDesc _select_player_face_desc = {
@@ -999,7 +1007,6 @@
 	WC_PLAYER_FACE, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
 	_select_player_face_widgets,
-	SelectPlayerFaceWndProc
 };
 
 /** advanced player face selection window description */
@@ -1008,7 +1015,6 @@
 	WC_PLAYER_FACE, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
 	_select_player_face_adv_widgets,
-	SelectPlayerFaceWndProc
 };
 
 /**
@@ -1021,23 +1027,12 @@
  *
  * @pre is player a valid player
  */
-static void DoSelectPlayerFace(PlayerID player, bool adv, int top, int left)
+static void DoSelectPlayerFace(Window *parent, bool adv, int top, int left)
 {
-	if (!IsValidPlayer(player)) return;
-
-	Window *w = AllocateWindowDescFront<Window>(adv ? &_select_player_face_adv_desc : &_select_player_face_desc, player); // simple or advanced window
+	if (!IsValidPlayer((PlayerID)parent->window_number)) return;
 
-	if (w != NULL) {
-		w->caption_color = w->window_number;
-		WP(w, facesel_d).face = GetPlayer((PlayerID)w->window_number)->face;
-		WP(w, facesel_d).advanced = adv;
-
-		/* Check if repositioning from default is required */
-		if (top != FIRST_GUI_CALL && left != FIRST_GUI_CALL) {
-			w->top = top;
-			w->left = left;
-		}
-	}
+	if (BringWindowToFrontById(WC_PLAYER_FACE, parent->window_number)) return;
+	new SelectPlayerFaceWindow(adv ? &_select_player_face_adv_desc : &_select_player_face_desc, parent, adv); // simple or advanced window
 }
 
 
@@ -1165,238 +1160,232 @@
  * @param w window pointer
  * @param e event been triggered
  */
-static void PlayerCompanyWndProc(Window *w, WindowEvent *e)
+struct PlayerCompanyWindow : Window
 {
-	switch (e->event) {
-		case WE_PAINT: {
-			const Player *p = GetPlayer((PlayerID)w->window_number);
-			bool local = w->window_number == _local_player;
-
-			w->SetWidgetHiddenState(PCW_WIDGET_NEW_FACE,       !local);
-			w->SetWidgetHiddenState(PCW_WIDGET_COLOR_SCHEME,   !local);
-			w->SetWidgetHiddenState(PCW_WIDGET_PRESIDENT_NAME, !local);
-			w->SetWidgetHiddenState(PCW_WIDGET_COMPANY_NAME,   !local);
-			w->widget[PCW_WIDGET_BUILD_VIEW_HQ].data = (local && p->location_of_house == 0) ? STR_706F_BUILD_HQ : STR_7072_VIEW_HQ;
-			if (local && p->location_of_house != 0) w->widget[PCW_WIDGET_BUILD_VIEW_HQ].type = WWT_PUSHTXTBTN; //HQ is already built.
-			w->SetWidgetDisabledState(PCW_WIDGET_BUILD_VIEW_HQ, !local && p->location_of_house == 0);
-			w->SetWidgetHiddenState(PCW_WIDGET_RELOCATE_HQ,      !local || p->location_of_house == 0);
-			w->SetWidgetHiddenState(PCW_WIDGET_BUY_SHARE,        local);
-			w->SetWidgetHiddenState(PCW_WIDGET_SELL_SHARE,       local);
-			w->SetWidgetHiddenState(PCW_WIDGET_COMPANY_PASSWORD, !local || !_networking);
-
-			if (!local) {
-				if (_patches.allow_shares) { // Shares are allowed
-					/* If all shares are owned by someone (none by nobody), disable buy button */
-					w->SetWidgetDisabledState(PCW_WIDGET_BUY_SHARE, GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 0 ||
-							/* Only 25% left to buy. If the player is human, disable buying it up.. TODO issues! */
-							(GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 1 && !p->is_ai) ||
-							/* Spectators cannot do anything of course */
-							_local_player == PLAYER_SPECTATOR);
+	PlayerCompanyWindowWidgets query_widget;
 
-					/* If the player doesn't own any shares, disable sell button */
-					w->SetWidgetDisabledState(PCW_WIDGET_SELL_SHARE, (GetAmountOwnedBy(p, _local_player) == 0) ||
-							/* Spectators cannot do anything of course */
-							_local_player == PLAYER_SPECTATOR);
-				} else { // Shares are not allowed, disable buy/sell buttons
-					w->DisableWidget(PCW_WIDGET_BUY_SHARE);
-					w->DisableWidget(PCW_WIDGET_SELL_SHARE);
-				}
-			}
-
-			SetDParam(0, p->index);
-			SetDParam(1, p->index);
-
-			DrawWindowWidgets(w);
-
-			/* Player face */
-			DrawPlayerFace(p->face, p->player_color, 2, 16);
+	PlayerCompanyWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+	{
+		this->caption_color = this->window_number;
+	}
 
-			/* "xxx (Manager)" */
-			SetDParam(0, p->index);
-			DrawStringMultiCenter(48, 141, STR_7037_PRESIDENT, 94);
-
-			/* "Inaugurated:" */
-			SetDParam(0, p->inaugurated_year);
-			DrawString(110, 23, STR_7038_INAUGURATED, TC_FROMSTRING);
+	virtual void OnPaint()
+	{
+		const Player *p = GetPlayer((PlayerID)this->window_number);
+		bool local = this->window_number == _local_player;
 
-			/* "Colour scheme:" */
-			DrawString(110, 43, STR_7006_COLOR_SCHEME, TC_FROMSTRING);
-			/* Draw company-colour bus */
-			DrawSprite(SPR_VEH_BUS_SW_VIEW, PLAYER_SPRITE_COLOR(p->index), 215, 44);
-
-			/* "Vehicles:" */
-			DrawPlayerVehiclesAmount((PlayerID)w->window_number);
+		this->SetWidgetHiddenState(PCW_WIDGET_NEW_FACE,       !local);
+		this->SetWidgetHiddenState(PCW_WIDGET_COLOR_SCHEME,   !local);
+		this->SetWidgetHiddenState(PCW_WIDGET_PRESIDENT_NAME, !local);
+		this->SetWidgetHiddenState(PCW_WIDGET_COMPANY_NAME,   !local);
+		this->widget[PCW_WIDGET_BUILD_VIEW_HQ].data = (local && p->location_of_house == 0) ? STR_706F_BUILD_HQ : STR_7072_VIEW_HQ;
+		if (local && p->location_of_house != 0) this->widget[PCW_WIDGET_BUILD_VIEW_HQ].type = WWT_PUSHTXTBTN; //HQ is already built.
+		this->SetWidgetDisabledState(PCW_WIDGET_BUILD_VIEW_HQ, !local && p->location_of_house == 0);
+		this->SetWidgetHiddenState(PCW_WIDGET_RELOCATE_HQ,      !local || p->location_of_house == 0);
+		this->SetWidgetHiddenState(PCW_WIDGET_BUY_SHARE,        local);
+		this->SetWidgetHiddenState(PCW_WIDGET_SELL_SHARE,       local);
+		this->SetWidgetHiddenState(PCW_WIDGET_COMPANY_PASSWORD, !local || !_networking);
 
-			/* "Company value:" */
-			SetDParam(0, CalculateCompanyValue(p));
-			DrawString(110, 106, STR_7076_COMPANY_VALUE, TC_FROMSTRING);
+		if (!local) {
+			if (_patches.allow_shares) { // Shares are allowed
+				/* If all shares are owned by someone (none by nobody), disable buy button */
+				this->SetWidgetDisabledState(PCW_WIDGET_BUY_SHARE, GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 0 ||
+						/* Only 25% left to buy. If the player is human, disable buying it up.. TODO issues! */
+						(GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 1 && !p->is_ai) ||
+						/* Spectators cannot do anything of course */
+						_local_player == PLAYER_SPECTATOR);
 
-			/* Shares list */
-			DrawCompanyOwnerText(p);
-
-			break;
+				/* If the player doesn't own any shares, disable sell button */
+				this->SetWidgetDisabledState(PCW_WIDGET_SELL_SHARE, (GetAmountOwnedBy(p, _local_player) == 0) ||
+						/* Spectators cannot do anything of course */
+						_local_player == PLAYER_SPECTATOR);
+			} else { // Shares are not allowed, disable buy/sell buttons
+				this->DisableWidget(PCW_WIDGET_BUY_SHARE);
+				this->DisableWidget(PCW_WIDGET_SELL_SHARE);
+			}
 		}
 
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case PCW_WIDGET_NEW_FACE: DoSelectPlayerFace((PlayerID)w->window_number, false); break;
-
-				case PCW_WIDGET_COLOR_SCHEME: {
-					Window *wf = AllocateWindowDescFront<Window>(_loaded_newgrf_features.has_2CC ? &_select_player_livery_2cc_desc : &_select_player_livery_desc, w->window_number);
-					if (wf != NULL) {
-						wf->caption_color = wf->window_number;
-						WP(wf, livery_d).livery_class = LC_OTHER;
-						WP(wf, livery_d).sel = 1;
-						wf->LowerWidget(2);
-					}
-					break;
-				}
-
-				case PCW_WIDGET_PRESIDENT_NAME: {
-					const Player *p = GetPlayer((PlayerID)w->window_number);
-					WP(w, def_d).byte_1 = 0;
-					SetDParam(0, p->index);
-					ShowQueryString(STR_PLAYER_NAME, STR_700B_PRESIDENT_S_NAME, 31, 94, w, CS_ALPHANUMERAL);
-					break;
-				}
-
-				case PCW_WIDGET_COMPANY_NAME: {
-					Player *p = GetPlayer((PlayerID)w->window_number);
-					WP(w, def_d).byte_1 = 1;
-					SetDParam(0, p->index);
-					ShowQueryString(STR_COMPANY_NAME, STR_700A_COMPANY_NAME, 31, 150, w, CS_ALPHANUMERAL);
-					break;
-				}
+		SetDParam(0, p->index);
+		SetDParam(1, p->index);
 
-				case PCW_WIDGET_BUILD_VIEW_HQ: {
-					TileIndex tile = GetPlayer((PlayerID)w->window_number)->location_of_house;
-					if (tile == 0) {
-						if ((byte)w->window_number != _local_player)
-							return;
-						SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, VHM_RECT, w);
-						SetTileSelectSize(2, 2);
-						w->LowerWidget(PCW_WIDGET_BUILD_VIEW_HQ);
-						w->InvalidateWidget(PCW_WIDGET_BUILD_VIEW_HQ);
+		this->DrawWidgets();
+
+		/* Player face */
+		DrawPlayerFace(p->face, p->player_color, 2, 16);
+
+		/* "xxx (Manager)" */
+		SetDParam(0, p->index);
+		DrawStringMultiCenter(48, 141, STR_7037_PRESIDENT, 94);
+
+		/* "Inaugurated:" */
+		SetDParam(0, p->inaugurated_year);
+		DrawString(110, 23, STR_7038_INAUGURATED, TC_FROMSTRING);
+
+		/* "Colour scheme:" */
+		DrawString(110, 43, STR_7006_COLOR_SCHEME, TC_FROMSTRING);
+		/* Draw company-colour bus */
+		DrawSprite(SPR_VEH_BUS_SW_VIEW, PLAYER_SPRITE_COLOR(p->index), 215, 44);
+
+		/* "Vehicles:" */
+		DrawPlayerVehiclesAmount((PlayerID)this->window_number);
+
+		/* "Company value:" */
+		SetDParam(0, CalculateCompanyValue(p));
+		DrawString(110, 106, STR_7076_COMPANY_VALUE, TC_FROMSTRING);
+
+		/* Shares list */
+		DrawCompanyOwnerText(p);
+	}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case PCW_WIDGET_NEW_FACE: DoSelectPlayerFace(this, false); break;
+
+			case PCW_WIDGET_COLOR_SCHEME:
+				if (BringWindowToFrontById(WC_PLAYER_COLOR, this->window_number)) break;
+				new SelectPlayerLiveryWindow(&_select_player_livery_desc, (PlayerID)this->window_number);
+				break;
+
+			case PCW_WIDGET_PRESIDENT_NAME:
+				this->query_widget = PCW_WIDGET_PRESIDENT_NAME;
+				SetDParam(0, this->window_number);
+				ShowQueryString(STR_PLAYER_NAME, STR_700B_PRESIDENT_S_NAME, 31, 94, this, CS_ALPHANUMERAL);
+				break;
+
+			case PCW_WIDGET_COMPANY_NAME:
+				this->query_widget = PCW_WIDGET_COMPANY_NAME;
+				SetDParam(0, this->window_number);
+				ShowQueryString(STR_COMPANY_NAME, STR_700A_COMPANY_NAME, 31, 150, this, CS_ALPHANUMERAL);
+				break;
+
+			case PCW_WIDGET_BUILD_VIEW_HQ: {
+				TileIndex tile = GetPlayer((PlayerID)this->window_number)->location_of_house;
+				if (tile == 0) {
+					if ((byte)this->window_number != _local_player) return;
+					SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, VHM_RECT, this);
+					SetTileSelectSize(2, 2);
+					this->LowerWidget(PCW_WIDGET_BUILD_VIEW_HQ);
+					this->InvalidateWidget(PCW_WIDGET_BUILD_VIEW_HQ);
+				} else {
+					if (_ctrl_pressed) {
+						ShowExtraViewPortWindow(tile);
 					} else {
-						if (_ctrl_pressed) {
-							ShowExtraViewPortWindow(tile);
-						} else {
-							ScrollMainWindowToTile(tile);
-						}
+						ScrollMainWindowToTile(tile);
 					}
-					break;
 				}
+				break;
+			}
 
-				case PCW_WIDGET_RELOCATE_HQ:
-					SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, VHM_RECT, w);
-					SetTileSelectSize(2, 2);
-					w->LowerWidget(PCW_WIDGET_RELOCATE_HQ);
-					w->InvalidateWidget(PCW_WIDGET_RELOCATE_HQ);
-					break;
+			case PCW_WIDGET_RELOCATE_HQ:
+				SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, VHM_RECT, this);
+				SetTileSelectSize(2, 2);
+				this->LowerWidget(PCW_WIDGET_RELOCATE_HQ);
+				this->InvalidateWidget(PCW_WIDGET_RELOCATE_HQ);
+				break;
 
-				case PCW_WIDGET_BUY_SHARE:
-					DoCommandP(0, w->window_number, 0, NULL, CMD_BUY_SHARE_IN_COMPANY | CMD_MSG(STR_707B_CAN_T_BUY_25_SHARE_IN_THIS));
-					break;
+			case PCW_WIDGET_BUY_SHARE:
+				DoCommandP(0, this->window_number, 0, NULL, CMD_BUY_SHARE_IN_COMPANY | CMD_MSG(STR_707B_CAN_T_BUY_25_SHARE_IN_THIS));
+				break;
 
-				case PCW_WIDGET_SELL_SHARE:
-					DoCommandP(0, w->window_number, 0, NULL, CMD_SELL_SHARE_IN_COMPANY | CMD_MSG(STR_707C_CAN_T_SELL_25_SHARE_IN));
-					break;
+			case PCW_WIDGET_SELL_SHARE:
+				DoCommandP(0, this->window_number, 0, NULL, CMD_SELL_SHARE_IN_COMPANY | CMD_MSG(STR_707C_CAN_T_SELL_25_SHARE_IN));
+				break;
 
 #ifdef ENABLE_NETWORK
-				case PCW_WIDGET_COMPANY_PASSWORD:
-					if (w->window_number == _local_player) ShowNetworkCompanyPasswordWindow();
-					break;
+			case PCW_WIDGET_COMPANY_PASSWORD:
+				if (this->window_number == _local_player) ShowNetworkCompanyPasswordWindow(this);
+				break;
 #endif /* ENABLE_NETWORK */
-			}
-			break;
-
-		case WE_TICK:
-			/* redraw the window every now and then */
-			if ((++w->vscroll.pos & 0x1F) == 0) w->SetDirty();
-			break;
-
-		case WE_PLACE_OBJ:
-			if (DoCommandP(e->we.place.tile, 0, 0, NULL, CMD_BUILD_COMPANY_HQ | CMD_NO_WATER | CMD_MSG(STR_7071_CAN_T_BUILD_COMPANY_HEADQUARTERS)))
-				ResetObjectToPlace();
-				w->widget[PCW_WIDGET_BUILD_VIEW_HQ].type = WWT_PUSHTXTBTN; // this button can now behave as a normal push button
-				w->RaiseButtons();
-			break;
+		}
+	}
 
-		case WE_ABORT_PLACE_OBJ:
-			w->RaiseButtons();
-			break;
-
-		case WE_DESTROY:
-			DeleteWindowById(WC_PLAYER_FACE, w->window_number);
-			if (w->window_number == _local_player) DeleteWindowById(WC_COMPANY_PASSWORD_WINDOW, 0);
-			break;
-
-		case WE_ON_EDIT_TEXT:
-			if (StrEmpty(e->we.edittext.str)) break;
+	virtual void OnTick()
+	{
+		/* redraw the window every now and then */
+		if ((++this->vscroll.pos & 0x1F) == 0) this->SetDirty();
+	}
 
-			_cmd_text = e->we.edittext.str;
-			switch (WP(w, def_d).byte_1) {
-				case 0: /* Change president name */
-					DoCommandP(0, 0, 0, NULL, CMD_CHANGE_PRESIDENT_NAME | CMD_MSG(STR_700D_CAN_T_CHANGE_PRESIDENT));
-					break;
-				case 1: /* Change company name */
-					DoCommandP(0, 0, 0, NULL, CMD_CHANGE_COMPANY_NAME | CMD_MSG(STR_700C_CAN_T_CHANGE_COMPANY_NAME));
-					break;
-			}
-			break;
+	virtual void OnPlaceObject(Point pt, TileIndex tile)
+	{
+		if (DoCommandP(tile, 0, 0, NULL, CMD_BUILD_COMPANY_HQ | CMD_NO_WATER | CMD_MSG(STR_7071_CAN_T_BUILD_COMPANY_HEADQUARTERS)))
+			ResetObjectToPlace();
+			this->widget[PCW_WIDGET_BUILD_VIEW_HQ].type = WWT_PUSHTXTBTN; // this button can now behave as a normal push button
+			this->RaiseButtons();
 	}
-}
 
+	virtual void OnPlaceObjectAbort()
+	{
+		this->RaiseButtons();
+	}
+
+	virtual void OnQueryTextFinished(char *str)
+	{
+		if (StrEmpty(str)) return;
+
+		_cmd_text = str;
+		switch (this->query_widget) {
+			default: NOT_REACHED();
+
+			case PCW_WIDGET_PRESIDENT_NAME:
+				DoCommandP(0, 0, 0, NULL, CMD_CHANGE_PRESIDENT_NAME | CMD_MSG(STR_700D_CAN_T_CHANGE_PRESIDENT));
+				break;
+
+			case PCW_WIDGET_COMPANY_NAME:
+				DoCommandP(0, 0, 0, NULL, CMD_CHANGE_COMPANY_NAME | CMD_MSG(STR_700C_CAN_T_CHANGE_COMPANY_NAME));
+				break;
+		}
+	}
+};
 
 static const WindowDesc _player_company_desc = {
 	WDP_AUTO, WDP_AUTO, 360, 170, 360, 170,
 	WC_COMPANY, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
 	_player_company_widgets,
-	PlayerCompanyWndProc
 };
 
 void ShowPlayerCompany(PlayerID player)
 {
-	Window *w;
-
 	if (!IsValidPlayer(player)) return;
 
-	w = AllocateWindowDescFront<Window>(&_player_company_desc, player);
-	if (w != NULL) w->caption_color = w->window_number;
+	AllocateWindowDescFront<PlayerCompanyWindow>(&_player_company_desc, player);
 }
 
 
 
-static void BuyCompanyWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			Player *p = GetPlayer((PlayerID)w->window_number);
-			SetDParam(0, STR_COMPANY_NAME);
-			SetDParam(1, p->index);
-			DrawWindowWidgets(w);
-
-			DrawPlayerFace(p->face, p->player_color, 2, 16);
+struct BuyCompanyWindow : Window {
+	BuyCompanyWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+	{
+	}
 
-			SetDParam(0, p->index);
-			SetDParam(1, p->bankrupt_value);
-			DrawStringMultiCenter(214, 65, STR_705B_WE_ARE_LOOKING_FOR_A_TRANSPORT, 238);
-		} break;
+	virtual void OnPaint()
+	{
+		Player *p = GetPlayer((PlayerID)this->window_number);
+		SetDParam(0, STR_COMPANY_NAME);
+		SetDParam(1, p->index);
+		this->DrawWidgets();
 
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case 3:
-					delete w;
-					break;
-				case 4: {
-					DoCommandP(0, w->window_number, 0, NULL, CMD_BUY_COMPANY | CMD_MSG(STR_7060_CAN_T_BUY_COMPANY));
-					break;
-				}
-			}
-			break;
+		DrawPlayerFace(p->face, p->player_color, 2, 16);
+
+		SetDParam(0, p->index);
+		SetDParam(1, p->bankrupt_value);
+		DrawStringMultiCenter(214, 65, STR_705B_WE_ARE_LOOKING_FOR_A_TRANSPORT, 238);
 	}
-}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case 3:
+				delete this;
+				break;
+
+			case 4:
+				DoCommandP(0, this->window_number, 0, NULL, CMD_BUY_COMPANY | CMD_MSG(STR_7060_CAN_T_BUY_COMPANY));
+				break;
+		}
+	}
+};
 
 static const Widget _buy_company_widgets[] = {
 {   WWT_CLOSEBOX,   RESIZE_NONE,     5,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},
@@ -1412,117 +1401,165 @@
 	WC_BUY_COMPANY, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 	_buy_company_widgets,
-	BuyCompanyWndProc
 };
 
 
 void ShowBuyCompanyDialog(uint player)
 {
-	AllocateWindowDescFront<Window>(&_buy_company_desc, player);
+	AllocateWindowDescFront<BuyCompanyWindow>(&_buy_company_desc, player);
 }
 
 /********** HIGHSCORE and ENDGAME windows */
 
-/* Always draw a maximized window and within there the centered background */
-static void SetupHighScoreEndWindow(Window *w, uint *x, uint *y)
-{
-	uint i;
-	/* resize window to "full-screen" */
-	w->width = _screen.width;
-	w->height = _screen.height;
-	w->widget[0].right = w->width - 1;
-	w->widget[0].bottom = w->height - 1;
+extern StringID EndGameGetPerformanceTitleFromValue(uint value);
 
-	DrawWindowWidgets(w);
 
-	/* Center Highscore/Endscreen background */
-	*x = max(0, (_screen.width  / 2) - (640 / 2));
-	*y = max(0, (_screen.height / 2) - (480 / 2));
-	for (i = 0; i < 10; i++) // the image is split into 10 50px high parts
-		DrawSprite(WP(w, highscore_d).background_img + i, PAL_NONE, *x, *y + (i * 50));
-}
+struct EndGameHighScoreBaseWindow : Window
+{
+	uint32 background_img;
+	int8 rank;
 
-extern StringID EndGameGetPerformanceTitleFromValue(uint value);
+	EndGameHighScoreBaseWindow(const WindowDesc *desc) : Window(desc)
+	{
+	}
+
+	/* Always draw a maximized window and within there the centered background */
+	void SetupHighScoreEndWindow(uint *x, uint *y)
+	{
+		/* resize window to "full-screen" */
+		this->width = _screen.width;
+		this->height = _screen.height;
+		this->widget[0].right = this->width - 1;
+		this->widget[0].bottom = this->height - 1;
+
+		this->DrawWidgets();
+
+		/* Center Highscore/Endscreen background */
+		*x = max(0, (_screen.width  / 2) - (640 / 2));
+		*y = max(0, (_screen.height / 2) - (480 / 2));
+		for (uint i = 0; i < 10; i++) { // the image is split into 10 50px high parts
+			DrawSprite(this->background_img + i, PAL_NONE, *x, *y + (i * 50));
+		}
+	}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		delete this;
+	}
+};
 
 /** End game window shown at the end of the game */
-static void EndGameWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			const Player *p;
-			uint x, y;
-
-			SetupHighScoreEndWindow(w, &x, &y);
-
-			if (!IsValidPlayer(_local_player)) break;
+struct EndGameWindow : EndGameHighScoreBaseWindow {
+	EndGameWindow(const WindowDesc *desc) : EndGameHighScoreBaseWindow(desc)
+	{
+		/* Pause in single-player to have a look at the highscore at your own leisure */
+		if (!_networking) DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
 
-			p = GetPlayer(_local_player);
-			/* We need to get performance from last year because the image is shown
-			 * at the start of the new year when these things have already been copied */
-			if (WP(w, highscore_d).background_img == SPR_TYCOON_IMG2_BEGIN) { // Tycoon of the century \o/
-				SetDParam(0, p->index);
-				SetDParam(1, p->index);
-				SetDParam(2, EndGameGetPerformanceTitleFromValue(p->old_economy[0].performance_history));
-				DrawStringMultiCenter(x + (640 / 2), y + 107, STR_021C_OF_ACHIEVES_STATUS, 640);
-			} else {
-				SetDParam(0, p->index);
-				SetDParam(1, EndGameGetPerformanceTitleFromValue(p->old_economy[0].performance_history));
-				DrawStringMultiCenter(x + (640 / 2), y + 157, STR_021B_ACHIEVES_STATUS, 640);
+		this->background_img = SPR_TYCOON_IMG1_BEGIN;
+
+		if (_local_player != PLAYER_SPECTATOR) {
+			const Player *p = GetPlayer(_local_player);
+			if (p->old_economy[0].performance_history == SCORE_MAX) {
+				this->background_img = SPR_TYCOON_IMG2_BEGIN;
 			}
-		} break;
-
-		case WE_CLICK: /* Close the window (and show the highscore window) */
-			delete w;
-			break;
+		}
 
-		case WE_DESTROY: /* Show the highscore window when this one is closed */
-			if (!_networking) DoCommandP(0, 0, 0, NULL, CMD_PAUSE); // unpause
-			ShowHighscoreTable(w->window_number, WP(w, highscore_d).rank);
-			break;
+		/* In a network game show the endscores of the custom difficulty 'network' which is the last one
+		 * as well as generate a TOP5 of that game, and not an all-time top5. */
+		if (_networking) {
+			this->window_number = lengthof(_highscore_table) - 1;
+			this->rank = SaveHighScoreValueNetwork();
+		} else {
+			/* in single player _local player is always valid */
+			const Player *p = GetPlayer(_local_player);
+			this->window_number = _opt.diff_level;
+			this->rank = SaveHighScoreValue(p);
+		}
+
+		MarkWholeScreenDirty();
 	}
-}
 
-static void HighScoreWndProc(Window *w, WindowEvent *e)
+	~EndGameWindow()
+	{
+		if (!_networking) DoCommandP(0, 0, 0, NULL, CMD_PAUSE); // unpause
+		ShowHighscoreTable(this->window_number, this->rank);
+	}
+
+	virtual void OnPaint()
+	{
+		const Player *p;
+		uint x, y;
+
+		this->SetupHighScoreEndWindow(&x, &y);
+
+		if (!IsValidPlayer(_local_player)) return;
+
+		p = GetPlayer(_local_player);
+		/* We need to get performance from last year because the image is shown
+		 * at the start of the new year when these things have already been copied */
+		if (this->background_img == SPR_TYCOON_IMG2_BEGIN) { // Tycoon of the century \o/
+			SetDParam(0, p->index);
+			SetDParam(1, p->index);
+			SetDParam(2, EndGameGetPerformanceTitleFromValue(p->old_economy[0].performance_history));
+			DrawStringMultiCenter(x + (640 / 2), y + 107, STR_021C_OF_ACHIEVES_STATUS, 640);
+		} else {
+			SetDParam(0, p->index);
+			SetDParam(1, EndGameGetPerformanceTitleFromValue(p->old_economy[0].performance_history));
+			DrawStringMultiCenter(x + (640 / 2), y + 157, STR_021B_ACHIEVES_STATUS, 640);
+		}
+	}
+};
+
+struct HighScoreWindow : EndGameHighScoreBaseWindow
 {
-	switch (e->event) {
-		case WE_PAINT: {
-			const HighScore *hs = _highscore_table[w->window_number];
-			uint x, y;
-			uint8 i;
-
-			SetupHighScoreEndWindow(w, &x, &y);
-
-			SetDParam(0, _patches.ending_year);
-			SetDParam(1, w->window_number + STR_6801_EASY);
-			DrawStringMultiCenter(x + (640 / 2), y + 62, !_networking ? STR_0211_TOP_COMPANIES_WHO_REACHED : STR_TOP_COMPANIES_NETWORK_GAME, 500);
-
-			/* Draw Highscore peepz */
-			for (i = 0; i < lengthof(_highscore_table[0]); i++) {
-				SetDParam(0, i + 1);
-				DrawString(x + 40, y + 140 + (i * 55), STR_0212, TC_BLACK);
+	HighScoreWindow(const WindowDesc *desc, int difficulty, int8 ranking) : EndGameHighScoreBaseWindow(desc)
+	{
+		/* pause game to show the chart */
+		if (!_networking) DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
 
-				if (hs[i].company[0] != '\0') {
-					TextColour colour = (WP(w, highscore_d).rank == (int8)i) ? TC_RED : TC_BLACK; // draw new highscore in red
-
-					DoDrawString(hs[i].company, x + 71, y + 140 + (i * 55), colour);
-					SetDParam(0, hs[i].title);
-					SetDParam(1, hs[i].score);
-					DrawString(x + 71, y + 160 + (i * 55), STR_HIGHSCORE_STATS, colour);
-				}
-			}
-		} break;
+		/* Close all always on-top windows to get a clean screen */
+		if (_game_mode != GM_MENU) HideVitalWindows();
 
-		case WE_CLICK: /* Onclick to close window, and in destroy event handle the rest */
-			delete w;
-			break;
+		MarkWholeScreenDirty();
+		this->window_number = difficulty; // show highscore chart for difficulty...
+		this->background_img = SPR_HIGHSCORE_CHART_BEGIN; // which background to show
+		this->rank = ranking;
+	}
 
-		case WE_DESTROY: /* Get back all the hidden windows */
-			if (_game_mode != GM_MENU) ShowVitalWindows();
+	~HighScoreWindow()
+	{
+		if (_game_mode != GM_MENU) ShowVitalWindows();
 
-			if (!_networking) DoCommandP(0, 0, 0, NULL, CMD_PAUSE); // unpause
-			break;
+		if (!_networking) DoCommandP(0, 0, 0, NULL, CMD_PAUSE); // unpause
+	}
+
+	virtual void OnPaint()
+	{
+		const HighScore *hs = _highscore_table[this->window_number];
+		uint x, y;
+
+		this->SetupHighScoreEndWindow(&x, &y);
+
+		SetDParam(0, _patches.ending_year);
+		SetDParam(1, this->window_number + STR_6801_EASY);
+		DrawStringMultiCenter(x + (640 / 2), y + 62, !_networking ? STR_0211_TOP_COMPANIES_WHO_REACHED : STR_TOP_COMPANIES_NETWORK_GAME, 500);
+
+		/* Draw Highscore peepz */
+		for (uint8 i = 0; i < lengthof(_highscore_table[0]); i++) {
+			SetDParam(0, i + 1);
+			DrawString(x + 40, y + 140 + (i * 55), STR_0212, TC_BLACK);
+
+			if (hs[i].company[0] != '\0') {
+				TextColour colour = (this->rank == i) ? TC_RED : TC_BLACK; // draw new highscore in red
+
+				DoDrawString(hs[i].company, x + 71, y + 140 + (i * 55), colour);
+				SetDParam(0, hs[i].title);
+				SetDParam(1, hs[i].score);
+				DrawString(x + 71, y + 160 + (i * 55), STR_HIGHSCORE_STATS, colour);
+			}
 		}
-}
+	}
+};
 
 static const Widget _highscore_widgets[] = {
 {      WWT_PANEL, RESIZE_NONE, 16, 0, 640, 0, 480, 0x0, STR_NULL},
@@ -1534,7 +1571,6 @@
 	WC_HIGHSCORE, WC_NONE,
 	0,
 	_highscore_widgets,
-	HighScoreWndProc
 };
 
 static const WindowDesc _endgame_desc = {
@@ -1542,7 +1578,6 @@
 	WC_ENDSCREEN, WC_NONE,
 	0,
 	_highscore_widgets,
-	EndGameWndProc
 };
 
 /** Show the highscore table for a given difficulty. When called from
@@ -1550,61 +1585,18 @@
  * and is thus highlighted */
 void ShowHighscoreTable(int difficulty, int8 ranking)
 {
-	Window *w;
-
-	/* pause game to show the chart */
-	if (!_networking) DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
-
-	/* Close all always on-top windows to get a clean screen */
-	if (_game_mode != GM_MENU) HideVitalWindows();
-
 	DeleteWindowByClass(WC_HIGHSCORE);
-	w = new Window(&_highscore_desc);
-
-	if (w != NULL) {
-		MarkWholeScreenDirty();
-		w->window_number = difficulty; // show highscore chart for difficulty...
-		WP(w, highscore_d).background_img = SPR_HIGHSCORE_CHART_BEGIN; // which background to show
-		WP(w, highscore_d).rank = ranking;
-	}
+	new HighScoreWindow(&_highscore_desc, difficulty, ranking);
 }
 
 /** Show the endgame victory screen in 2050. Update the new highscore
  * if it was high enough */
 void ShowEndGameChart()
 {
-	Window *w;
-
 	/* Dedicated server doesn't need the highscore window */
 	if (_network_dedicated) return;
-	/* Pause in single-player to have a look at the highscore at your own leisure */
-	if (!_networking) DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
 
 	HideVitalWindows();
 	DeleteWindowByClass(WC_ENDSCREEN);
-	w = new Window(&_endgame_desc);
-
-	if (w != NULL) {
-		MarkWholeScreenDirty();
-
-		WP(w, highscore_d).background_img = SPR_TYCOON_IMG1_BEGIN;
-
-		if (_local_player != PLAYER_SPECTATOR) {
-			const Player *p = GetPlayer(_local_player);
-			if (p->old_economy[0].performance_history == SCORE_MAX)
-				WP(w, highscore_d).background_img = SPR_TYCOON_IMG2_BEGIN;
-		}
-
-		/* In a network game show the endscores of the custom difficulty 'network' which is the last one
-		 * as well as generate a TOP5 of that game, and not an all-time top5. */
-		if (_networking) {
-			w->window_number = lengthof(_highscore_table) - 1;
-			WP(w, highscore_d).rank = SaveHighScoreValueNetwork();
-		} else {
-			/* in single player _local player is always valid */
-			const Player *p = GetPlayer(_local_player);
-			w->window_number = _opt.diff_level;
-			WP(w, highscore_d).rank = SaveHighScoreValue(p);
-		}
-	}
+	new EndGameWindow(&_endgame_desc);
 }
--- a/src/players.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/players.cpp	Mon May 19 15:13:58 2008 +0000
@@ -355,8 +355,11 @@
 		MarkWholeScreenDirty();
 
 		if (!IsHumanPlayer(p->index)) {
-			SetDParam(0, t->index);
-			AddNewsItem((StringID)(p->index | NB_BNEWCOMPANY), NM_CALLBACK, NF_TILE, NT_COMPANY_INFO, DNC_BANKRUPCY, p->last_build_coordinate, 0);
+			SetDParam(0, STR_705E_NEW_TRANSPORT_COMPANY_LAUNCHED);
+			SetDParam(1, STR_705F_STARTS_CONSTRUCTION_NEAR);
+			SetDParam(2, p->index);
+			SetDParam(3, t->index);
+			AddNewsItem(STR_02B6, NS_COMPANY_NEW, p->last_build_coordinate, p->index);
 		}
 		for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
 			if (i != p->index) AI_Event(i, new AIEventCompanyNew(p->index));
@@ -930,8 +933,10 @@
 		DeletePlayerWindows(p->index);
 
 		/* Show the bankrupt news */
-		SetDParam(0, p->index);
-		AddNewsItem((StringID)(p->index | NB_BBANKRUPT), NM_CALLBACK, NF_NONE, NT_COMPANY_INFO, DNC_BANKRUPCY, 0, 0);
+		SetDParam(0, STR_705C_BANKRUPT);
+		SetDParam(1, STR_705D_HAS_BEEN_CLOSED_DOWN_BY);
+		SetDParam(2, p->index);
+		AddNewsItem(STR_02B6, NS_COMPANY_BANKRUPT, 0, p->index);
 
 		/* Remove the company */
 		ChangeOwnershipOfPlayerItems(p->index, PLAYER_SPECTATOR);
--- a/src/querystring_gui.h	Mon May 19 14:14:33 2008 +0000
+++ b/src/querystring_gui.h	Mon May 19 15:13:58 2008 +0000
@@ -17,20 +17,20 @@
 
 	void DrawEditBox(Window *w, int wid);
 	void HandleEditBox(Window *w, int wid);
-	int HandleEditBoxKey(Window *w, int wid, uint16 key, uint16 keycode, bool &cont);
+	int HandleEditBoxKey(Window *w, int wid, uint16 key, uint16 keycode, Window::EventState &state);
 };
 
 struct QueryStringBaseWindow : public Window, public QueryString {
 	char edit_str_buf[64];
 	char orig_str_buf[64];
 
-	QueryStringBaseWindow(const WindowDesc *desc, void *data = NULL, WindowNumber window_number = 0) : Window(desc, data, window_number)
+	QueryStringBaseWindow(const WindowDesc *desc, WindowNumber window_number = 0) : Window(desc, window_number)
 	{
 	}
 
 	void DrawEditBox(int wid);
 	void HandleEditBox(int wid);
-	int HandleEditBoxKey(int wid, uint16 key, uint16 keycode, bool &cont);
+	int HandleEditBoxKey(int wid, uint16 key, uint16 keycode, EventState &state);
 };
 
 void ShowOnScreenKeyboard(QueryStringBaseWindow *parent, int button, int cancel, int ok);
--- a/src/rail_cmd.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/rail_cmd.cpp	Mon May 19 15:13:58 2008 +0000
@@ -777,7 +777,7 @@
 		d->town_index = ClosestTownFromTile(tile, (uint)-1)->index;
 
 		AddSideToSignalBuffer(tile, INVALID_DIAGDIR, _current_player);
-		YapfNotifyTrackLayoutChange(tile, TrackdirToTrack(DiagdirToDiagTrackdir(dir)));
+		YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
 	}
 
 	return cost.AddCost(_price.build_train_depot);
@@ -1246,7 +1246,7 @@
 						case RAIL_TILE_WAYPOINT:
 							if (flags & DC_EXEC) {
 								/* notify YAPF about the track layout change */
-								YapfNotifyTrackLayoutChange(tile, AxisToTrack(GetWaypointAxis(tile)));
+								YapfNotifyTrackLayoutChange(tile, GetRailWaypointTrack(tile));
 							}
 							cost.AddCost(RailConvertCost(type, totype));
 							break;
@@ -1254,7 +1254,7 @@
 						case RAIL_TILE_DEPOT:
 							if (flags & DC_EXEC) {
 								/* notify YAPF about the track layout change */
-								YapfNotifyTrackLayoutChange(tile, AxisToTrack(DiagDirToAxis(GetRailDepotDirection(tile))));
+								YapfNotifyTrackLayoutChange(tile, GetRailDepotTrack(tile));
 
 								/* Update build vehicle window related to this depot */
 								InvalidateWindowData(WC_VEHICLE_DEPOT, tile);
@@ -1295,7 +1295,7 @@
 						VehicleFromPos(tile, NULL, &UpdateTrainPowerProc);
 						VehicleFromPos(endtile, NULL, &UpdateTrainPowerProc);
 
-						Track track = AxisToTrack(DiagDirToAxis(GetTunnelBridgeDirection(tile)));
+						Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile));
 
 						YapfNotifyTrackLayoutChange(tile, track);
 						YapfNotifyTrackLayoutChange(endtile, track);
@@ -1344,7 +1344,7 @@
 		DoClearSquare(tile);
 		delete GetDepotByTile(tile);
 		AddSideToSignalBuffer(tile, dir, owner);
-		YapfNotifyTrackLayoutChange(tile, TrackdirToTrack(DiagdirToDiagTrackdir(dir)));
+		YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
 	}
 
 	return CommandCost(EXPENSES_CONSTRUCTION, _price.remove_train_depot);
@@ -2149,7 +2149,7 @@
 
 			if (side != INVALID_DIAGDIR && side != dir) break;
 
-			trackbits = AxisToTrackBits(DiagDirToAxis(dir));
+			trackbits = DiagDirToDiagTrackBits(dir);
 			break;
 		}
 
--- a/src/rail_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/rail_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -42,25 +42,25 @@
 #include "table/sprites.h"
 #include "table/strings.h"
 
-static RailType _cur_railtype;
-static bool _remove_button_clicked;
-static DiagDirection _build_depot_direction;
-static byte _waypoint_count = 1;
-static byte _cur_waypoint_type;
-static bool _convert_signal_button;       ///< convert signal button in the signal GUI pressed
-static SignalVariant _cur_signal_variant; ///< set the signal variant (for signal GUI)
-static SignalType _cur_signal_type;       ///< set the signal type (for signal GUI)
+static RailType _cur_railtype;               ///< Rail type of the current build-rail toolbar.
+static bool _remove_button_clicked;          ///< Flag whether 'remove' toggle-button is currently enabled
+static DiagDirection _build_depot_direction; ///< Currently selected depot direction
+static byte _waypoint_count = 1;             ///< Number of waypoint types
+static byte _cur_waypoint_type;              ///< Currently selected waypoint type
+static bool _convert_signal_button;          ///< convert signal button in the signal GUI pressed
+static SignalVariant _cur_signal_variant;    ///< set the signal variant (for signal GUI)
+static SignalType _cur_signal_type;          ///< set the signal type (for signal GUI)
 
 static struct {
-	byte orientation;
-	byte numtracks;
-	byte platlength;
-	bool dragdrop;
+	byte orientation;                 ///< Currently selected rail station orientation
+	byte numtracks;                   ///< Currently selected number of tracks in station (if not \c dragdrop )
+	byte platlength;                  ///< Currently selected platform length of station (if not \c dragdrop )
+	bool dragdrop;                    ///< Use drag & drop to place a station
 
-	bool newstations;
-	StationClassIDByte station_class;
-	byte station_type;
-	byte station_count;
+	bool newstations;                 ///< Are custom station definitions available?
+	StationClassIDByte station_class; ///< Currently selected custom station class (if newstations is \c true )
+	byte station_type;                ///< Station type within the currently selected custom station class (if newstations is \c true )
+	byte station_count;               ///< Number of custom stations (if newstations is \c true )
 } _railstation;
 
 
@@ -111,6 +111,12 @@
 	VpStartPlaceSizing(tile, VPM_RAILDIRS, DDSP_PLACE_AUTORAIL);
 }
 
+/**
+ * Try to add an additional rail-track at the entrance of a depot
+ * @param tile  Tile to use for adding the rail-track
+ * @param extra Track to add
+ * @see CcRailDepot()
+ */
 static void PlaceExtraDepotRail(TileIndex tile, uint16 extra)
 {
 	if (GetRailTileType(tile) != RAIL_TILE_NORMAL) return;
@@ -119,10 +125,11 @@
 	DoCommandP(tile, _cur_railtype, extra & 0xFF, NULL, CMD_BUILD_SINGLE_RAIL | CMD_NO_WATER);
 }
 
+/** Additional pieces of track to add at the entrance of a depot. */
 static const uint16 _place_depot_extra[12] = {
-	0x0604, 0x2102, 0x1202, 0x0505,
-	0x2400, 0x2801, 0x1800, 0x1401,
-	0x2203, 0x0904, 0x0A05, 0x1103,
+	0x0604, 0x2102, 0x1202, 0x0505,  // First additional track for directions 0..3
+	0x2400, 0x2801, 0x1800, 0x1401,  // Second additional track
+	0x2203, 0x0904, 0x0A05, 0x1103,  // Third additional track
 };
 
 
@@ -235,6 +242,7 @@
 	VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_BUILD_BRIDGE);
 }
 
+/** Command callback for building a tunnel */
 void CcBuildRailTunnel(bool success, TileIndex tile, uint32 p1, uint32 p2)
 {
 	if (success) {
@@ -285,7 +293,7 @@
 };
 
 
-/** Toogles state of the Remove button of Build rail toolbar
+/** Toggles state of the Remove button of Build rail toolbar
  * @param w window the button belongs to
  */
 static void ToggleRailButton_Remove(Window *w)
@@ -316,36 +324,71 @@
 }
 
 
+/**
+ * The "rail N"-button click proc of the build-rail toolbar.
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
 static void BuildRailClick_N(Window *w)
 {
 	HandlePlacePushButton(w, RTW_BUILD_NS, GetRailTypeInfo(_cur_railtype)->cursor.rail_ns, VHM_RECT, PlaceRail_N);
 }
 
+/**
+ * The "rail NE"-button click proc of the build-rail toolbar.
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
 static void BuildRailClick_NE(Window *w)
 {
 	HandlePlacePushButton(w, RTW_BUILD_X, GetRailTypeInfo(_cur_railtype)->cursor.rail_swne, VHM_RECT, PlaceRail_NE);
 }
 
+/**
+ * The "rail E"-button click proc of the build-rail toolbar.
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
 static void BuildRailClick_E(Window *w)
 {
 	HandlePlacePushButton(w, RTW_BUILD_EW, GetRailTypeInfo(_cur_railtype)->cursor.rail_ew, VHM_RECT, PlaceRail_E);
 }
 
+/**
+ * The "rail NW"-button click proc of the build-rail toolbar.
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
 static void BuildRailClick_NW(Window *w)
 {
 	HandlePlacePushButton(w, RTW_BUILD_Y, GetRailTypeInfo(_cur_railtype)->cursor.rail_nwse, VHM_RECT, PlaceRail_NW);
 }
 
+/**
+ * The "auto-rail"-button click proc of the build-rail toolbar.
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
 static void BuildRailClick_AutoRail(Window *w)
 {
 	HandlePlacePushButton(w, RTW_AUTORAIL, GetRailTypeInfo(_cur_railtype)->cursor.autorail, VHM_RAIL, PlaceRail_AutoRail);
 }
 
+/**
+ * The "demolish"-button click proc of the build-rail toolbar.
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
 static void BuildRailClick_Demolish(Window *w)
 {
 	HandlePlacePushButton(w, RTW_DEMOLISH, ANIMCURSOR_DEMOLISH, VHM_RECT, PlaceProc_DemolishArea);
 }
 
+/**
+ * The "build depot"-button click proc of the build-rail toolbar.
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
 static void BuildRailClick_Depot(Window *w)
 {
 	if (HandlePlacePushButton(w, RTW_BUILD_DEPOT, GetRailTypeInfo(_cur_railtype)->cursor.depot, VHM_RECT, PlaceRail_Depot)) {
@@ -353,6 +396,12 @@
 	}
 }
 
+/**
+ * The "build waypoint"-button click proc of the build-rail toolbar.
+ * If there are newGRF waypoints, also open a window to pick the waypoint type.
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
 static void BuildRailClick_Waypoint(Window *w)
 {
 	_waypoint_count = GetNumCustomStations(STAT_CLASS_WAYP);
@@ -362,12 +411,22 @@
 	}
 }
 
+/**
+ * The "build station"-button click proc of the build-rail toolbar.
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
 static void BuildRailClick_Station(Window *w)
 {
 	if (HandlePlacePushButton(w, RTW_BUILD_STATION, SPR_CURSOR_RAIL_STATION, VHM_RECT, PlaceRail_Station)) ShowStationBuilder();
 }
 
-/** The "build signal"-button proc from BuildRailToolbWndProc() (start ShowSignalBuilder() and/or HandleAutoSignalPlacement()) */
+/**
+ * The "build signal"-button click proc of the build-rail toolbar.
+ * Start ShowSignalBuilder() and/or HandleAutoSignalPlacement().
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
 static void BuildRailClick_AutoSignals(Window *w)
 {
 	if (_patches.enable_signal_gui != _ctrl_pressed) {
@@ -377,16 +436,31 @@
 	}
 }
 
+/**
+ * The "build bridge"-button click proc of the build-rail toolbar.
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
 static void BuildRailClick_Bridge(Window *w)
 {
 	HandlePlacePushButton(w, RTW_BUILD_BRIDGE, SPR_CURSOR_BRIDGE, VHM_RECT, PlaceRail_Bridge);
 }
 
+/**
+ * The "build tunnel"-button click proc of the build-rail toolbar.
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
 static void BuildRailClick_Tunnel(Window *w)
 {
 	HandlePlacePushButton(w, RTW_BUILD_TUNNEL, GetRailTypeInfo(_cur_railtype)->cursor.tunnel, VHM_SPECIAL, PlaceRail_Tunnel);
 }
 
+/**
+ * The "remove"-button click proc of the build-rail toolbar.
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
 static void BuildRailClick_Remove(Window *w)
 {
 	if (w->IsWidgetDisabled(RTW_REMOVE)) return;
@@ -416,6 +490,12 @@
 	}
 }
 
+/**
+ * The "convert-rail"-button click proc of the build-rail toolbar.
+ * Switches to 'convert-rail' mode
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
 static void BuildRailClick_Convert(Window *w)
 {
 	HandlePlacePushButton(w, RTW_CONVERT_RAIL, GetRailTypeInfo(_cur_railtype)->cursor.convert, VHM_RECT, PlaceRail_ConvertRail);
@@ -526,90 +606,105 @@
 };
 
 
-static void UpdateRemoveWidgetStatus(Window *w, int clicked_widget)
-{
-	switch (clicked_widget) {
-		case RTW_REMOVE:
-			/* If it is the removal button that has been clicked, do nothing,
-			 * as it is up to the other buttons to drive removal status */
-			return;
-			break;
-		case RTW_BUILD_NS:
-		case RTW_BUILD_X:
-		case RTW_BUILD_EW:
-		case RTW_BUILD_Y:
-		case RTW_AUTORAIL:
-		case RTW_BUILD_WAYPOINT:
-		case RTW_BUILD_STATION:
-		case RTW_BUILD_SIGNALS:
-			/* Removal button is enabled only if the rail/signal/waypoint/station
-			 * button is still lowered.  Once raised, it has to be disabled */
-			w->SetWidgetDisabledState(RTW_REMOVE, !w->IsWidgetLowered(clicked_widget));
-			break;
-
-		default:
-			/* When any other buttons than rail/signal/waypoint/station, raise and
-			 * disable the removal button */
-			w->DisableWidget(RTW_REMOVE);
-			w->RaiseWidget(RTW_REMOVE);
-			break;
-	}
-}
+/**
+ * Based on the widget clicked, update the status of the 'remove' button.
+ * @param w              Rail toolbar window
+ * @param clicked_widget Widget clicked in the toolbar
+ */
+struct BuildRailToolbarWindow : Window {
+	BuildRailToolbarWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+	{
+		this->DisableWidget(RTW_REMOVE);
 
-/**
- * Railway toolbar window event definition
- *
- * @param w window pointer
- * @param e event been triggered
- */
-static void BuildRailToolbWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_CREATE: w->DisableWidget(RTW_REMOVE); break;
-
-	case WE_PAINT: DrawWindowWidgets(w); break;
+		this->FindWindowPlacementAndResize(desc);
+		if (_patches.link_terraform_toolbar) ShowTerraformToolbar(this);
+	}
 
-	case WE_CLICK:
-		if (e->we.click.widget >= RTW_BUILD_NS) {
-			_remove_button_clicked = false;
-			_build_railroad_button_proc[e->we.click.widget - RTW_BUILD_NS](w);
+	~BuildRailToolbarWindow()
+	{
+		if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
+	}
+
+	void UpdateRemoveWidgetStatus(int clicked_widget)
+	{
+		switch (clicked_widget) {
+			case RTW_REMOVE:
+				/* If it is the removal button that has been clicked, do nothing,
+				* as it is up to the other buttons to drive removal status */
+				return;
+				break;
+			case RTW_BUILD_NS:
+			case RTW_BUILD_X:
+			case RTW_BUILD_EW:
+			case RTW_BUILD_Y:
+			case RTW_AUTORAIL:
+			case RTW_BUILD_WAYPOINT:
+			case RTW_BUILD_STATION:
+			case RTW_BUILD_SIGNALS:
+				/* Removal button is enabled only if the rail/signal/waypoint/station
+				* button is still lowered.  Once raised, it has to be disabled */
+				this->SetWidgetDisabledState(RTW_REMOVE, !this->IsWidgetLowered(clicked_widget));
+				break;
+
+			default:
+				/* When any other buttons than rail/signal/waypoint/station, raise and
+				* disable the removal button */
+				this->DisableWidget(RTW_REMOVE);
+				this->RaiseWidget(RTW_REMOVE);
+				break;
 		}
-		UpdateRemoveWidgetStatus(w, e->we.click.widget);
-		if (_ctrl_pressed) RailToolbar_CtrlChanged(w);
-		break;
+	}
 
-	case WE_KEYPRESS:
+	virtual void OnPaint()
+	{
+		this->DrawWidgets();
+	}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		if (widget >= RTW_BUILD_NS) {
+			_remove_button_clicked = false;
+			_build_railroad_button_proc[widget - RTW_BUILD_NS](this);
+		}
+		this->UpdateRemoveWidgetStatus(widget);
+		if (_ctrl_pressed) RailToolbar_CtrlChanged(this);
+	}
+
+	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+	{
+		EventState state = ES_NOT_HANDLED;
 		for (uint8 i = 0; i != lengthof(_rail_keycodes); i++) {
-			if (e->we.keypress.keycode == _rail_keycodes[i]) {
-				e->we.keypress.cont = false;
+			if (keycode == _rail_keycodes[i]) {
 				_remove_button_clicked = false;
-				_build_railroad_button_proc[i](w);
-				UpdateRemoveWidgetStatus(w, i + RTW_BUILD_NS);
-				if (_ctrl_pressed) RailToolbar_CtrlChanged(w);
+				_build_railroad_button_proc[i](this);
+				this->UpdateRemoveWidgetStatus(i + RTW_BUILD_NS);
+				if (_ctrl_pressed) RailToolbar_CtrlChanged(this);
+				state = ES_HANDLED;
 				break;
 			}
 		}
 		MarkTileDirty(_thd.pos.x, _thd.pos.y); // redraw tile selection
-		break;
-
-	case WE_PLACE_OBJ:
-		_place_proc(e->we.place.tile);
-		return;
-
-	case WE_PLACE_DRAG: {
-		/* no dragging if you have pressed the convert button */
-		if (FindWindowById(WC_BUILD_SIGNAL, 0) != NULL && _convert_signal_button && w->IsWidgetLowered(RTW_BUILD_SIGNALS)) return;
-
-		VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.select_method);
-		return;
+		return state;
 	}
 
-	case WE_PLACE_MOUSEUP:
-		if (e->we.place.pt.x != -1) {
-			TileIndex start_tile = e->we.place.starttile;
-			TileIndex end_tile = e->we.place.tile;
+	virtual void OnPlaceObject(Point pt, TileIndex tile)
+	{
+		_place_proc(tile);
+	}
 
-			switch (e->we.place.select_proc) {
+	virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
+	{
+		/* no dragging if you have pressed the convert button */
+		if (FindWindowById(WC_BUILD_SIGNAL, 0) != NULL && _convert_signal_button && this->IsWidgetLowered(RTW_BUILD_SIGNALS)) return;
+
+		VpSelectTilesWithMethod(pt.x, pt.y, select_method);
+	}
+
+	virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
+	{
+		if (pt.x != -1) {
+			switch (select_proc) {
+				default: NOT_REACHED();
 				case DDSP_BUILD_BRIDGE:
 					ResetObjectToPlace();
 					ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_RAIL, _cur_railtype);
@@ -624,7 +719,7 @@
 					break;
 
 				case DDSP_DEMOLISH_AREA:
-					GUIPlaceProcDragXY(e);
+					GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
 					break;
 
 				case DDSP_CONVERT_RAIL:
@@ -642,42 +737,36 @@
 
 				case DDSP_PLACE_RAIL_NE:
 				case DDSP_PLACE_RAIL_NW:
-					DoRailroadTrack(e->we.place.select_proc == DDSP_PLACE_RAIL_NE ? TRACK_X : TRACK_Y);
+					DoRailroadTrack(select_proc == DDSP_PLACE_RAIL_NE ? TRACK_X : TRACK_Y);
 					break;
 			}
 		}
-		break;
-
-	case WE_ABORT_PLACE_OBJ:
-		w->RaiseButtons();
-		w->DisableWidget(RTW_REMOVE);
-		w->InvalidateWidget(RTW_REMOVE);
+	}
 
-		w = FindWindowById(WC_BUILD_SIGNAL, 0);
-		if (w != NULL) WP(w, def_d).close = true;
-		w = FindWindowById(WC_BUILD_STATION, 0);
-		if (w != NULL) WP(w, def_d).close = true;
-		w = FindWindowById(WC_BUILD_DEPOT, 0);
-		if (w != NULL) WP(w, def_d).close = true;
-		break;
+	virtual void OnPlaceObjectAbort()
+	{
+		this->RaiseButtons();
+		this->DisableWidget(RTW_REMOVE);
+		this->InvalidateWidget(RTW_REMOVE);
 
-	case WE_PLACE_PRESIZE: {
-		TileIndex tile = e->we.place.tile;
+		delete FindWindowById(WC_BUILD_SIGNAL, 0);
+		delete FindWindowById(WC_BUILD_STATION, 0);
+		delete FindWindowById(WC_BUILD_DEPOT, 0);
+	}
 
+	virtual void OnPlacePresize(Point pt, TileIndex tile)
+	{
 		DoCommand(tile, 0, 0, DC_AUTO, CMD_BUILD_TUNNEL);
 		VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile);
-	} break;
-
-	case WE_DESTROY:
-		if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
-		break;
+	}
 
-	case WE_CTRL_CHANGED:
+	virtual EventState OnCTRLStateChange()
+	{
 		/* do not toggle Remove button by Ctrl when placing station */
-		if (!w->IsWidgetLowered(RTW_BUILD_STATION) && RailToolbar_CtrlChanged(w)) e->we.ctrl.cont = false;
-		break;
+		if (!this->IsWidgetLowered(RTW_BUILD_STATION) && RailToolbar_CtrlChanged(this)) return ES_HANDLED;
+		return ES_NOT_HANDLED;
 	}
-}
+};
 
 /** Widget definition for the rail toolbar */
 static const Widget _build_rail_widgets[] = {
@@ -712,7 +801,6 @@
 	WC_BUILD_TOOLBAR, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
 	_build_rail_widgets,
-	BuildRailToolbWndProc
 };
 
 
@@ -736,66 +824,39 @@
 	w->widget[RTW_BUILD_TUNNEL].data = rti->gui_sprites.build_tunnel;
 }
 
+/**
+ * Open the build rail toolbar window for a specific rail type.
+ * The window may be opened in the 'normal' way by clicking at the rail icon in
+ * the main toolbar, or by means of selecting one of the functions of the
+ * toolbar. In the latter case, the corresponding widget is also selected.
+ *
+ * If the terraform toolbar is linked to the toolbar, that window is also opened.
+ *
+ * @param railtype Rail type to open the window for
+ * @param button   Widget clicked (\c -1 means no button clicked)
+ */
 void ShowBuildRailToolbar(RailType railtype, int button)
 {
-	Window *w;
+	BuildRailToolbarWindow *w;
 
 	if (!IsValidPlayer(_current_player)) return;
 	if (!ValParamRailtype(railtype)) return;
 
 	// don't recreate the window if we're clicking on a button and the window exists.
-	if (button < 0 || !(w = FindWindowById(WC_BUILD_TOOLBAR, TRANSPORT_RAIL))) {
+	if (button < 0 || !(w = dynamic_cast<BuildRailToolbarWindow*>(FindWindowById(WC_BUILD_TOOLBAR, TRANSPORT_RAIL)))) {
 		DeleteWindowByClass(WC_BUILD_TOOLBAR);
 		_cur_railtype = railtype;
-		w = AllocateWindowDescFront<Window>(&_build_rail_desc, TRANSPORT_RAIL);
+		w = AllocateWindowDescFront<BuildRailToolbarWindow>(&_build_rail_desc, TRANSPORT_RAIL);
 		SetupRailToolbar(railtype, w);
 	}
 
 	_remove_button_clicked = false;
 	if (w != NULL && button >= RTW_CLOSEBOX) {
 		_build_railroad_button_proc[button](w);
-		UpdateRemoveWidgetStatus(w, button + RTW_BUILD_NS);
+		w->UpdateRemoveWidgetStatus(button + RTW_BUILD_NS);
 	}
-	if (_patches.link_terraform_toolbar) ShowTerraformToolbar(w);
 }
 
-/** Enum referring to the widgets of the rail stations window */
-enum BuildRailStationWidgets {
-	BRSW_CLOSEBOX = 0,
-	BRSW_CAPTION,
-	BRSW_BACKGROUND,
-
-	BRSW_PLATFORM_DIR_X,
-	BRSW_PLATFORM_DIR_Y,
-
-	BRSW_PLATFORM_NUM_BEGIN = BRSW_PLATFORM_DIR_Y,
-	BRSW_PLATFORM_NUM_1,
-	BRSW_PLATFORM_NUM_2,
-	BRSW_PLATFORM_NUM_3,
-	BRSW_PLATFORM_NUM_4,
-	BRSW_PLATFORM_NUM_5,
-	BRSW_PLATFORM_NUM_6,
-	BRSW_PLATFORM_NUM_7,
-
-	BRSW_PLATFORM_LEN_BEGIN = BRSW_PLATFORM_NUM_7,
-	BRSW_PLATFORM_LEN_1,
-	BRSW_PLATFORM_LEN_2,
-	BRSW_PLATFORM_LEN_3,
-	BRSW_PLATFORM_LEN_4,
-	BRSW_PLATFORM_LEN_5,
-	BRSW_PLATFORM_LEN_6,
-	BRSW_PLATFORM_LEN_7,
-
-	BRSW_PLATFORM_DRAG_N_DROP,
-
-	BRSW_HIGHLIGHT_OFF,
-	BRSW_HIGHLIGHT_ON,
-
-	BRSW_NEWST_DROPDOWN,
-	BRSW_NEWST_LIST,
-	BRSW_NEWST_SCROLL
-};
-
 /* TODO: For custom stations, respect their allowed platforms/lengths bitmasks!
  * --pasky */
 
@@ -819,64 +880,124 @@
 			CMD_BUILD_RAILROAD_STATION | CMD_NO_WATER | CMD_MSG(STR_100F_CAN_T_BUILD_RAILROAD_STATION));
 }
 
-/* Check if the currently selected station size is allowed */
-static void CheckSelectedSize(Window *w, const StationSpec *statspec)
-{
-	if (statspec == NULL || _railstation.dragdrop) return;
+struct BuildRailStationWindow : public PickerWindowBase {
+private:
+	/** Enum referring to the widgets of the rail stations window */
+	enum BuildRailStationWidgets {
+		BRSW_CLOSEBOX = 0,
+		BRSW_CAPTION,
+		BRSW_BACKGROUND,
 
-	if (HasBit(statspec->disallowed_platforms, _railstation.numtracks - 1)) {
-		w->RaiseWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
-		_railstation.numtracks = 1;
-		while (HasBit(statspec->disallowed_platforms, _railstation.numtracks - 1)) {
-			_railstation.numtracks++;
+		BRSW_PLATFORM_DIR_X,
+		BRSW_PLATFORM_DIR_Y,
+
+		BRSW_PLATFORM_NUM_BEGIN = BRSW_PLATFORM_DIR_Y,
+		BRSW_PLATFORM_NUM_1,
+		BRSW_PLATFORM_NUM_2,
+		BRSW_PLATFORM_NUM_3,
+		BRSW_PLATFORM_NUM_4,
+		BRSW_PLATFORM_NUM_5,
+		BRSW_PLATFORM_NUM_6,
+		BRSW_PLATFORM_NUM_7,
+
+		BRSW_PLATFORM_LEN_BEGIN = BRSW_PLATFORM_NUM_7,
+		BRSW_PLATFORM_LEN_1,
+		BRSW_PLATFORM_LEN_2,
+		BRSW_PLATFORM_LEN_3,
+		BRSW_PLATFORM_LEN_4,
+		BRSW_PLATFORM_LEN_5,
+		BRSW_PLATFORM_LEN_6,
+		BRSW_PLATFORM_LEN_7,
+
+		BRSW_PLATFORM_DRAG_N_DROP,
+
+		BRSW_HIGHLIGHT_OFF,
+		BRSW_HIGHLIGHT_ON,
+
+		BRSW_NEWST_DROPDOWN,
+		BRSW_NEWST_LIST,
+		BRSW_NEWST_SCROLL
+	};
+
+	/**
+	 * Verify whether the currently selected station size is allowed after selecting a new station class/type.
+	 * If not, change the station size variables ( _railstation.numtracks and _railstation.platlength ).
+	 * @param statspec Specification of the new station class/type
+	 */
+	void CheckSelectedSize(const StationSpec *statspec)
+	{
+		if (statspec == NULL || _railstation.dragdrop) return;
+
+		/* If current number of tracks is not allowed, make it as big as possible (which is always less than currently selected) */
+		if (HasBit(statspec->disallowed_platforms, _railstation.numtracks - 1)) {
+			this->RaiseWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
+			_railstation.numtracks = 1;
+			while (HasBit(statspec->disallowed_platforms, _railstation.numtracks - 1)) {
+				_railstation.numtracks++;
+			}
+			this->LowerWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
 		}
-		w->LowerWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
+
+		if (HasBit(statspec->disallowed_lengths, _railstation.platlength - 1)) {
+			this->RaiseWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
+			_railstation.platlength = 1;
+			while (HasBit(statspec->disallowed_lengths, _railstation.platlength - 1)) {
+				_railstation.platlength++;
+			}
+			this->LowerWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
+		}
 	}
 
-	if (HasBit(statspec->disallowed_lengths, _railstation.platlength - 1)) {
-		w->RaiseWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
-		_railstation.platlength = 1;
-		while (HasBit(statspec->disallowed_lengths, _railstation.platlength - 1)) {
-			_railstation.platlength++;
+	/** Build a dropdown list of available station classes */
+	static DropDownList *BuildStationClassDropDown()
+	{
+		DropDownList *list = new DropDownList();
+
+		for (uint i = 0; i < GetNumStationClasses(); i++) {
+			if (i == STAT_CLASS_WAYP) continue;
+			list->push_back(new DropDownListStringItem(GetStationClassName((StationClassID)i), i, false));
 		}
-		w->LowerWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
+
+		return list;
 	}
-}
+/**
+ * Window event handler of station build window.
+ * @param w Staion build window
+ * @param e Window event to handle
+ */
 
-static DropDownList *BuildStationClassDropDown()
-{
-	DropDownList *list = new DropDownList();
+public:
+	BuildRailStationWindow(const WindowDesc *desc, bool newstation) : PickerWindowBase(desc)
+	{
+		this->LowerWidget(_railstation.orientation + BRSW_PLATFORM_DIR_X);
+		if (_railstation.dragdrop) {
+			this->LowerWidget(BRSW_PLATFORM_DRAG_N_DROP);
+		} else {
+			this->LowerWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
+			this->LowerWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
+		}
+		this->SetWidgetLoweredState(BRSW_HIGHLIGHT_OFF, !_station_show_coverage);
+		this->SetWidgetLoweredState(BRSW_HIGHLIGHT_ON, _station_show_coverage);
 
-	for (uint i = 0; i < GetNumStationClasses(); i++) {
-		if (i == STAT_CLASS_WAYP) continue;
-		list->push_back(new DropDownListStringItem(GetStationClassName((StationClassID)i), i, false));
+		this->FindWindowPlacementAndResize(desc);
+
+		_railstation.newstations = newstation;
+
+		if (newstation) {
+			_railstation.station_count = GetNumCustomStations(_railstation.station_class);
+
+			this->vscroll.count = _railstation.station_count;
+			this->vscroll.cap   = 5;
+			this->vscroll.pos   = Clamp(_railstation.station_type - 2, 0, this->vscroll.count - this->vscroll.cap);
+		}
 	}
 
-	return list;
-}
-
-static void StationBuildWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_CREATE:
-		w->LowerWidget(_railstation.orientation + BRSW_PLATFORM_DIR_X);
-		if (_railstation.dragdrop) {
-			w->LowerWidget(BRSW_PLATFORM_DRAG_N_DROP);
-		} else {
-			w->LowerWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
-			w->LowerWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
-		}
-		w->SetWidgetLoweredState(BRSW_HIGHLIGHT_OFF, !_station_show_coverage);
-		w->SetWidgetLoweredState(BRSW_HIGHLIGHT_ON, _station_show_coverage);
-		break;
-
-	case WE_PAINT: {
+	virtual void OnPaint()
+	{
 		bool newstations = _railstation.newstations;
 		DrawPixelInfo tmp_dpi, *old_dpi;
 		const StationSpec *statspec = newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
 
-		if (WP(w, def_d).close) return;
-
 		if (_railstation.dragdrop) {
 			SetTileSelectSize(1, 1);
 		} else {
@@ -895,16 +1016,16 @@
 		for (uint bits = 0; bits < 7; bits++) {
 			bool disable = bits >= _patches.station_spread;
 			if (statspec == NULL) {
-				w->SetWidgetDisabledState(bits + BRSW_PLATFORM_NUM_1, disable);
-				w->SetWidgetDisabledState(bits + BRSW_PLATFORM_LEN_1, disable);
+				this->SetWidgetDisabledState(bits + BRSW_PLATFORM_NUM_1, disable);
+				this->SetWidgetDisabledState(bits + BRSW_PLATFORM_LEN_1, disable);
 			} else {
-				w->SetWidgetDisabledState(bits + BRSW_PLATFORM_NUM_1, HasBit(statspec->disallowed_platforms, bits) || disable);
-				w->SetWidgetDisabledState(bits + BRSW_PLATFORM_LEN_1, HasBit(statspec->disallowed_lengths,   bits) || disable);
+				this->SetWidgetDisabledState(bits + BRSW_PLATFORM_NUM_1, HasBit(statspec->disallowed_platforms, bits) || disable);
+				this->SetWidgetDisabledState(bits + BRSW_PLATFORM_LEN_1, HasBit(statspec->disallowed_lengths,   bits) || disable);
 			}
 		}
 
 		SetDParam(0, GetStationClassName(_railstation.station_class));
-		DrawWindowWidgets(w);
+		this->DrawWidgets();
 
 		int y_offset = newstations ? 90 : 0;
 
@@ -935,16 +1056,16 @@
 
 		int text_end = DrawStationCoverageAreaText(2, 166 + y_offset, SCT_ALL, rad, false);
 		text_end = DrawStationCoverageAreaText(2, text_end + 4, SCT_ALL, rad, true) + 4;
-		if (text_end != w->widget[BRSW_BACKGROUND].bottom) {
-			w->SetDirty();
-			ResizeWindowForWidget(w, BRSW_BACKGROUND, 0, text_end - w->widget[BRSW_BACKGROUND].bottom);
-			w->SetDirty();
+		if (text_end != this->widget[BRSW_BACKGROUND].bottom) {
+			this->SetDirty();
+			ResizeWindowForWidget(this, BRSW_BACKGROUND, 0, text_end - this->widget[BRSW_BACKGROUND].bottom);
+			this->SetDirty();
 		}
 
 		if (newstations) {
 			uint y = 35;
 
-			for (uint16 i = w->vscroll.pos; i < _railstation.station_count && i < (uint)(w->vscroll.pos + w->vscroll.cap); i++) {
+			for (uint16 i = this->vscroll.pos; i < _railstation.station_count && i < (uint)(this->vscroll.pos + this->vscroll.cap); i++) {
 				const StationSpec *statspec = GetCustomStationSpec(_railstation.station_class, i);
 
 				if (statspec != NULL && statspec->name != 0) {
@@ -960,181 +1081,175 @@
 				y += 14;
 			}
 		}
-	} break;
-
-	case WE_CLICK: {
-		switch (e->we.click.widget) {
-		case BRSW_PLATFORM_DIR_X:
-		case BRSW_PLATFORM_DIR_Y:
-			w->RaiseWidget(_railstation.orientation + BRSW_PLATFORM_DIR_X);
-			_railstation.orientation = e->we.click.widget - BRSW_PLATFORM_DIR_X;
-			w->LowerWidget(_railstation.orientation + BRSW_PLATFORM_DIR_X);
-			SndPlayFx(SND_15_BEEP);
-			w->SetDirty();
-			break;
+	}
 
-		case BRSW_PLATFORM_NUM_1:
-		case BRSW_PLATFORM_NUM_2:
-		case BRSW_PLATFORM_NUM_3:
-		case BRSW_PLATFORM_NUM_4:
-		case BRSW_PLATFORM_NUM_5:
-		case BRSW_PLATFORM_NUM_6:
-		case BRSW_PLATFORM_NUM_7: {
-			w->RaiseWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
-			w->RaiseWidget(BRSW_PLATFORM_DRAG_N_DROP);
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case BRSW_PLATFORM_DIR_X:
+			case BRSW_PLATFORM_DIR_Y:
+				this->RaiseWidget(_railstation.orientation + BRSW_PLATFORM_DIR_X);
+				_railstation.orientation = widget - BRSW_PLATFORM_DIR_X;
+				this->LowerWidget(_railstation.orientation + BRSW_PLATFORM_DIR_X);
+				SndPlayFx(SND_15_BEEP);
+				this->SetDirty();
+				break;
 
-			_railstation.numtracks = e->we.click.widget - BRSW_PLATFORM_NUM_BEGIN;
-			_railstation.dragdrop = false;
+			case BRSW_PLATFORM_NUM_1:
+			case BRSW_PLATFORM_NUM_2:
+			case BRSW_PLATFORM_NUM_3:
+			case BRSW_PLATFORM_NUM_4:
+			case BRSW_PLATFORM_NUM_5:
+			case BRSW_PLATFORM_NUM_6:
+			case BRSW_PLATFORM_NUM_7: {
+				this->RaiseWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
+				this->RaiseWidget(BRSW_PLATFORM_DRAG_N_DROP);
 
-			const StationSpec *statspec = _railstation.newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
-			if (statspec != NULL && HasBit(statspec->disallowed_lengths, _railstation.platlength - 1)) {
-				/* The previously selected number of platforms in invalid */
-				for (uint i = 0; i < 7; i++) {
-					if (!HasBit(statspec->disallowed_lengths, i)) {
-						w->RaiseWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
-						_railstation.platlength = i + 1;
-						break;
+				_railstation.numtracks = widget - BRSW_PLATFORM_NUM_BEGIN;
+				_railstation.dragdrop = false;
+
+				const StationSpec *statspec = _railstation.newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
+				if (statspec != NULL && HasBit(statspec->disallowed_lengths, _railstation.platlength - 1)) {
+					/* The previously selected number of platforms in invalid */
+					for (uint i = 0; i < 7; i++) {
+						if (!HasBit(statspec->disallowed_lengths, i)) {
+							this->RaiseWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
+							_railstation.platlength = i + 1;
+							break;
+						}
 					}
 				}
-			}
-
-			w->LowerWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
-			w->LowerWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
-			SndPlayFx(SND_15_BEEP);
-			w->SetDirty();
-			break;
-		}
 
-		case BRSW_PLATFORM_LEN_1:
-		case BRSW_PLATFORM_LEN_2:
-		case BRSW_PLATFORM_LEN_3:
-		case BRSW_PLATFORM_LEN_4:
-		case BRSW_PLATFORM_LEN_5:
-		case BRSW_PLATFORM_LEN_6:
-		case BRSW_PLATFORM_LEN_7: {
-			w->RaiseWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
-			w->RaiseWidget(BRSW_PLATFORM_DRAG_N_DROP);
-
-			_railstation.platlength = e->we.click.widget - BRSW_PLATFORM_LEN_BEGIN;
-			_railstation.dragdrop = false;
-
-			const StationSpec *statspec = _railstation.newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
-			if (statspec != NULL && HasBit(statspec->disallowed_platforms, _railstation.numtracks - 1)) {
-				/* The previously selected number of tracks in invalid */
-				for (uint i = 0; i < 7; i++) {
-					if (!HasBit(statspec->disallowed_platforms, i)) {
-						w->RaiseWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
-						_railstation.numtracks = i + 1;
-						break;
-					}
-				}
+				this->LowerWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
+				this->LowerWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
+				SndPlayFx(SND_15_BEEP);
+				this->SetDirty();
+				break;
 			}
 
-			w->LowerWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
-			w->LowerWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
-			SndPlayFx(SND_15_BEEP);
-			w->SetDirty();
-			break;
-		}
+			case BRSW_PLATFORM_LEN_1:
+			case BRSW_PLATFORM_LEN_2:
+			case BRSW_PLATFORM_LEN_3:
+			case BRSW_PLATFORM_LEN_4:
+			case BRSW_PLATFORM_LEN_5:
+			case BRSW_PLATFORM_LEN_6:
+			case BRSW_PLATFORM_LEN_7: {
+				this->RaiseWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
+				this->RaiseWidget(BRSW_PLATFORM_DRAG_N_DROP);
 
-		case BRSW_PLATFORM_DRAG_N_DROP: {
-			_railstation.dragdrop ^= true;
-			w->ToggleWidgetLoweredState(BRSW_PLATFORM_DRAG_N_DROP);
+				_railstation.platlength = widget - BRSW_PLATFORM_LEN_BEGIN;
+				_railstation.dragdrop = false;
 
-			/* get the first allowed length/number of platforms */
-			const StationSpec *statspec = _railstation.newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
-			if (statspec != NULL && HasBit(statspec->disallowed_lengths, _railstation.platlength - 1)) {
-				for (uint i = 0; i < 7; i++) {
-					if (!HasBit(statspec->disallowed_lengths, i)) {
-						w->RaiseWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
-						_railstation.platlength = i + 1;
-						break;
+				const StationSpec *statspec = _railstation.newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
+				if (statspec != NULL && HasBit(statspec->disallowed_platforms, _railstation.numtracks - 1)) {
+					/* The previously selected number of tracks in invalid */
+					for (uint i = 0; i < 7; i++) {
+						if (!HasBit(statspec->disallowed_platforms, i)) {
+							this->RaiseWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
+							_railstation.numtracks = i + 1;
+							break;
+						}
 					}
 				}
-			}
-			if (statspec != NULL && HasBit(statspec->disallowed_platforms, _railstation.numtracks - 1)) {
-				for (uint i = 0; i < 7; i++) {
-					if (!HasBit(statspec->disallowed_platforms, i)) {
-						w->RaiseWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
-						_railstation.numtracks = i + 1;
-						break;
-					}
-				}
+
+				this->LowerWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
+				this->LowerWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
+				SndPlayFx(SND_15_BEEP);
+				this->SetDirty();
+				break;
 			}
 
-			w->SetWidgetLoweredState(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN, !_railstation.dragdrop);
-			w->SetWidgetLoweredState(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN, !_railstation.dragdrop);
-			SndPlayFx(SND_15_BEEP);
-			w->SetDirty();
-		} break;
-
-		case BRSW_HIGHLIGHT_OFF:
-		case BRSW_HIGHLIGHT_ON:
-			_station_show_coverage = (e->we.click.widget != BRSW_HIGHLIGHT_OFF);
-			w->SetWidgetLoweredState(BRSW_HIGHLIGHT_OFF, !_station_show_coverage);
-			w->SetWidgetLoweredState(BRSW_HIGHLIGHT_ON, _station_show_coverage);
-			SndPlayFx(SND_15_BEEP);
-			w->SetDirty();
-			break;
-
-		case BRSW_NEWST_DROPDOWN:
-			ShowDropDownList(w, BuildStationClassDropDown(), _railstation.station_class, BRSW_NEWST_DROPDOWN);
-			break;
-
-		case BRSW_NEWST_LIST: {
-			const StationSpec *statspec;
-			int y = (e->we.click.pt.y - 32) / 14;
+			case BRSW_PLATFORM_DRAG_N_DROP: {
+				_railstation.dragdrop ^= true;
+				this->ToggleWidgetLoweredState(BRSW_PLATFORM_DRAG_N_DROP);
 
-			if (y >= w->vscroll.cap) return;
-			y += w->vscroll.pos;
-			if (y >= _railstation.station_count) return;
-
-			/* Check station availability callback */
-			statspec = GetCustomStationSpec(_railstation.station_class, y);
-			if (statspec != NULL &&
-				HasBit(statspec->callbackmask, CBM_STATION_AVAIL) &&
-				GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) return;
-
-			_railstation.station_type = y;
+				/* get the first allowed length/number of platforms */
+				const StationSpec *statspec = _railstation.newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
+				if (statspec != NULL && HasBit(statspec->disallowed_lengths, _railstation.platlength - 1)) {
+					for (uint i = 0; i < 7; i++) {
+						if (!HasBit(statspec->disallowed_lengths, i)) {
+							this->RaiseWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
+							_railstation.platlength = i + 1;
+							break;
+						}
+					}
+				}
+				if (statspec != NULL && HasBit(statspec->disallowed_platforms, _railstation.numtracks - 1)) {
+					for (uint i = 0; i < 7; i++) {
+						if (!HasBit(statspec->disallowed_platforms, i)) {
+							this->RaiseWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
+							_railstation.numtracks = i + 1;
+							break;
+						}
+					}
+				}
 
-			CheckSelectedSize(w, statspec);
+				this->SetWidgetLoweredState(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN, !_railstation.dragdrop);
+				this->SetWidgetLoweredState(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN, !_railstation.dragdrop);
+				SndPlayFx(SND_15_BEEP);
+				this->SetDirty();
+			} break;
 
-			SndPlayFx(SND_15_BEEP);
-			w->SetDirty();
-			break;
+			case BRSW_HIGHLIGHT_OFF:
+			case BRSW_HIGHLIGHT_ON:
+				_station_show_coverage = (widget != BRSW_HIGHLIGHT_OFF);
+				this->SetWidgetLoweredState(BRSW_HIGHLIGHT_OFF, !_station_show_coverage);
+				this->SetWidgetLoweredState(BRSW_HIGHLIGHT_ON, _station_show_coverage);
+				SndPlayFx(SND_15_BEEP);
+				this->SetDirty();
+				break;
+
+			case BRSW_NEWST_DROPDOWN:
+				ShowDropDownList(this, BuildStationClassDropDown(), _railstation.station_class, BRSW_NEWST_DROPDOWN);
+				break;
+
+			case BRSW_NEWST_LIST: {
+				const StationSpec *statspec;
+				int y = (pt.y - 32) / 14;
+
+				if (y >= this->vscroll.cap) return;
+				y += this->vscroll.pos;
+				if (y >= _railstation.station_count) return;
+
+				/* Check station availability callback */
+				statspec = GetCustomStationSpec(_railstation.station_class, y);
+				if (statspec != NULL &&
+					HasBit(statspec->callbackmask, CBM_STATION_AVAIL) &&
+					GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) return;
+
+				_railstation.station_type = y;
+
+				this->CheckSelectedSize(statspec);
+
+				SndPlayFx(SND_15_BEEP);
+				this->SetDirty();
+				break;
+			}
 		}
-		}
-	} break;
+	}
 
-	case WE_DROPDOWN_SELECT:
-		if (_railstation.station_class != e->we.dropdown.index) {
-			_railstation.station_class = (StationClassID)e->we.dropdown.index;
+	virtual void OnDropdownSelect(int widget, int index)
+	{
+		if (_railstation.station_class != index) {
+			_railstation.station_class = (StationClassID)index;
 			_railstation.station_type  = 0;
 			_railstation.station_count = GetNumCustomStations(_railstation.station_class);
 
-			CheckSelectedSize(w, GetCustomStationSpec(_railstation.station_class, _railstation.station_type));
+			this->CheckSelectedSize(GetCustomStationSpec(_railstation.station_class, _railstation.station_type));
 
-			w->vscroll.count = _railstation.station_count;
-			w->vscroll.pos   = _railstation.station_type;
+			this->vscroll.count = _railstation.station_count;
+			this->vscroll.pos   = _railstation.station_type;
 		}
 
 		SndPlayFx(SND_15_BEEP);
-		w->SetDirty();
-		break;
+		this->SetDirty();
+	}
 
-	case WE_TICK:
-		if (WP(w, def_d).close) {
-			delete w;
-			return;
-		}
-		CheckRedrawStationCoverage(w);
-		break;
-
-	case WE_DESTROY:
-		if (!WP(w, def_d).close) ResetObjectToPlace();
-		break;
+	virtual void OnTick()
+	{
+		CheckRedrawStationCoverage(this);
 	}
-}
+};
 
 /** Widget definition of the standard build rail station window */
 static const Widget _station_builder_widgets[] = {
@@ -1201,36 +1316,29 @@
 {   WIDGETS_END},
 };
 
+/** High level window description of the default station-build window */
 static const WindowDesc _station_builder_desc = {
 	WDP_AUTO, WDP_AUTO, 148, 200, 148, 200,
 	WC_BUILD_STATION, WC_BUILD_TOOLBAR,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 	_station_builder_widgets,
-	StationBuildWndProc
 };
 
+/** High level window description of the newGRF station-build window */
 static const WindowDesc _newstation_builder_desc = {
 	WDP_AUTO, WDP_AUTO, 148, 290, 148, 290,
 	WC_BUILD_STATION, WC_BUILD_TOOLBAR,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 	_newstation_builder_widgets,
-	StationBuildWndProc
 };
 
+/** Open station build window */
 static void ShowStationBuilder()
 {
-	Window *w;
 	if (GetNumStationClasses() <= 2 && GetNumCustomStations(STAT_CLASS_DFLT) == 1) {
-		w = new Window(&_station_builder_desc);
-		_railstation.newstations = false;
+		new BuildRailStationWindow(&_station_builder_desc, false);
 	} else {
-		w = new Window(&_newstation_builder_desc);
-		_railstation.newstations = true;
-		_railstation.station_count = GetNumCustomStations(_railstation.station_class);
-
-		w->vscroll.count = _railstation.station_count;
-		w->vscroll.cap   = 5;
-		w->vscroll.pos   = Clamp(_railstation.station_type - 2, 0, w->vscroll.count - w->vscroll.cap);
+		new BuildRailStationWindow(&_newstation_builder_desc, true);
 	}
 }
 
@@ -1252,108 +1360,99 @@
 	BSW_DRAG_SIGNALS_DENSITY_INCREASE,
 };
 
-/**
- * Draw dynamic a signal-sprite in a button in the signal GUI
- * Draw the sprite +1px to the right and down if the button is lowered and change the sprite to sprite + 1 (red to green light)
- *
- * @param w            Window on which the widget is located
- * @param widget_index index of this widget in the window
- * @param image        the sprite to draw
- * @param xrel         the relativ x value of the sprite in the grf
- * @param xsize        the width of the sprite
- */
-static void DrawSignalSprite(const Window *w, byte widget_index, SpriteID image, int8 xrel, uint8 xsize)
-{
-	DrawSprite(image + w->IsWidgetLowered(widget_index), PAL_NONE,
-			w->widget[widget_index].left + (w->widget[widget_index].right - w->widget[widget_index].left) / 2 - xrel - xsize / 2 +
-			w->IsWidgetLowered(widget_index), w->widget[widget_index].bottom - 3 + w->IsWidgetLowered(widget_index));
-}
-
-/**
- * Signal selection window event definition
- *
- * @param w window pointer
- * @param e event been triggered
- */
-static void SignalBuildWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT:
-			w->LowerWidget((_cur_signal_variant == SIG_ELECTRIC ? BSW_ELECTRIC_NORM : BSW_SEMAPHORE_NORM) + _cur_signal_type);
-
-			w->SetWidgetLoweredState(BSW_CONVERT, _convert_signal_button);
-
-			w->SetWidgetDisabledState(BSW_DRAG_SIGNALS_DENSITY_DECREASE, _patches.drag_signals_density == 1);
-			w->SetWidgetDisabledState(BSW_DRAG_SIGNALS_DENSITY_INCREASE, _patches.drag_signals_density == 20);
-
-			DrawWindowWidgets(w);
-
-			/* The 'hardcoded' off sets are needed because they are reused sprites. */
-			DrawSignalSprite(w, BSW_SEMAPHORE_NORM,  SPR_IMG_SIGNAL_SEMAPHORE_NORM,   0, 12); // xsize of sprite + 1 ==  9
-			DrawSignalSprite(w, BSW_SEMAPHORE_ENTRY, SPR_IMG_SIGNAL_SEMAPHORE_ENTRY, -1, 13); // xsize of sprite + 1 == 10
-			DrawSignalSprite(w, BSW_SEMAPHORE_EXIT,  SPR_IMG_SIGNAL_SEMAPHORE_EXIT,   0, 12); // xsize of sprite + 1 ==  9
-			DrawSignalSprite(w, BSW_SEMAPHORE_COMBO, SPR_IMG_SIGNAL_SEMAPHORE_COMBO,  0, 12); // xsize of sprite + 1 ==  9
-			DrawSignalSprite(w, BSW_ELECTRIC_NORM,   SPR_IMG_SIGNAL_ELECTRIC_NORM,   -1,  4);
-			DrawSignalSprite(w, BSW_ELECTRIC_ENTRY,  SPR_IMG_SIGNAL_ELECTRIC_ENTRY,  -2,  6);
-			DrawSignalSprite(w, BSW_ELECTRIC_EXIT,   SPR_IMG_SIGNAL_ELECTRIC_EXIT,   -2,  6);
-			DrawSignalSprite(w, BSW_ELECTRIC_COMBO,  SPR_IMG_SIGNAL_ELECTRIC_COMBO,  -2,  6);
+struct BuildSignalWindow : public PickerWindowBase {
+private:
+	/**
+	 * Draw dynamic a signal-sprite in a button in the signal GUI
+	 * Draw the sprite +1px to the right and down if the button is lowered and change the sprite to sprite + 1 (red to green light)
+	 *
+	 * @param widget_index index of this widget in the window
+	 * @param image        the sprite to draw
+	 * @param xrel         the relativ x value of the sprite in the grf
+	 * @param xsize        the width of the sprite
+	 */
+	void DrawSignalSprite(byte widget_index, SpriteID image, int8 xrel, uint8 xsize)
+	{
+		DrawSprite(image + this->IsWidgetLowered(widget_index), PAL_NONE,
+				this->widget[widget_index].left + (this->widget[widget_index].right - this->widget[widget_index].left) / 2 - xrel - xsize / 2 +
+				this->IsWidgetLowered(widget_index), this->widget[widget_index].bottom - 3 + this->IsWidgetLowered(widget_index));
+	}
 
-			/* Draw dragging signal density value in the BSW_DRAG_SIGNALS_DENSITY widget */
-			SetDParam(0, _patches.drag_signals_density);
-			DrawStringCentered(w->widget[BSW_DRAG_SIGNALS_DENSITY].left + (w->widget[BSW_DRAG_SIGNALS_DENSITY].right -
-					w->widget[BSW_DRAG_SIGNALS_DENSITY].left) / 2 + 1,
-					w->widget[BSW_DRAG_SIGNALS_DENSITY].top + 2, STR_JUST_INT, TC_ORANGE);
-			break;
-
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case BSW_SEMAPHORE_NORM:
-				case BSW_SEMAPHORE_ENTRY:
-				case BSW_SEMAPHORE_EXIT:
-				case BSW_SEMAPHORE_COMBO:
-				case BSW_ELECTRIC_NORM:
-				case BSW_ELECTRIC_ENTRY:
-				case BSW_ELECTRIC_EXIT:
-				case BSW_ELECTRIC_COMBO:
-					w->RaiseWidget((_cur_signal_variant == SIG_ELECTRIC ? BSW_ELECTRIC_NORM : BSW_SEMAPHORE_NORM) + _cur_signal_type);
-
-					_cur_signal_type = (SignalType)((uint)((e->we.click.widget - BSW_SEMAPHORE_NORM) % (SIGTYPE_COMBO + 1)));
-					_cur_signal_variant = e->we.click.widget >= BSW_ELECTRIC_NORM ? SIG_ELECTRIC : SIG_SEMAPHORE;
-					break;
-
-				case BSW_CONVERT:
-					_convert_signal_button = !_convert_signal_button;
-					break;
+public:
+	BuildSignalWindow(const WindowDesc *desc) : PickerWindowBase(desc)
+	{
+		this->FindWindowPlacementAndResize(desc);
+	};
 
-				case BSW_DRAG_SIGNALS_DENSITY_DECREASE:
-					if (_patches.drag_signals_density > 1) {
-						_patches.drag_signals_density--;
-						SetWindowDirty(FindWindowById(WC_GAME_OPTIONS, 0));
-					}
-					break;
-
-				case BSW_DRAG_SIGNALS_DENSITY_INCREASE:
-					if (_patches.drag_signals_density < 20) {
-						_patches.drag_signals_density++;
-						SetWindowDirty(FindWindowById(WC_GAME_OPTIONS, 0));
-					}
-					break;
+	virtual void OnPaint()
+	{
+		this->LowerWidget((_cur_signal_variant == SIG_ELECTRIC ? BSW_ELECTRIC_NORM : BSW_SEMAPHORE_NORM) + _cur_signal_type);
 
-				default: break;
-			}
-
-			w->SetDirty();
-			break;
+		this->SetWidgetLoweredState(BSW_CONVERT, _convert_signal_button);
 
-		case WE_TICK:
-			if (WP(w, def_d).close) delete w;
-			return;
+		this->SetWidgetDisabledState(BSW_DRAG_SIGNALS_DENSITY_DECREASE, _patches.drag_signals_density == 1);
+		this->SetWidgetDisabledState(BSW_DRAG_SIGNALS_DENSITY_INCREASE, _patches.drag_signals_density == 20);
 
-		case WE_DESTROY:
-			if (!WP(w, def_d).close) ResetObjectToPlace();
-			break;
+		this->DrawWidgets();
+
+		/* The 'hardcoded' off sets are needed because they are reused sprites. */
+		this->DrawSignalSprite(BSW_SEMAPHORE_NORM,  SPR_IMG_SIGNAL_SEMAPHORE_NORM,   0, 12); // xsize of sprite + 1 ==  9
+		this->DrawSignalSprite(BSW_SEMAPHORE_ENTRY, SPR_IMG_SIGNAL_SEMAPHORE_ENTRY, -1, 13); // xsize of sprite + 1 == 10
+		this->DrawSignalSprite(BSW_SEMAPHORE_EXIT,  SPR_IMG_SIGNAL_SEMAPHORE_EXIT,   0, 12); // xsize of sprite + 1 ==  9
+		this->DrawSignalSprite(BSW_SEMAPHORE_COMBO, SPR_IMG_SIGNAL_SEMAPHORE_COMBO,  0, 12); // xsize of sprite + 1 ==  9
+		this->DrawSignalSprite(BSW_ELECTRIC_NORM,   SPR_IMG_SIGNAL_ELECTRIC_NORM,   -1,  4);
+		this->DrawSignalSprite(BSW_ELECTRIC_ENTRY,  SPR_IMG_SIGNAL_ELECTRIC_ENTRY,  -2,  6);
+		this->DrawSignalSprite(BSW_ELECTRIC_EXIT,   SPR_IMG_SIGNAL_ELECTRIC_EXIT,   -2,  6);
+		this->DrawSignalSprite(BSW_ELECTRIC_COMBO,  SPR_IMG_SIGNAL_ELECTRIC_COMBO,  -2,  6);
+
+		/* Draw dragging signal density value in the BSW_DRAG_SIGNALS_DENSITY widget */
+		SetDParam(0, _patches.drag_signals_density);
+		DrawStringCentered(this->widget[BSW_DRAG_SIGNALS_DENSITY].left + (this->widget[BSW_DRAG_SIGNALS_DENSITY].right -
+				this->widget[BSW_DRAG_SIGNALS_DENSITY].left) / 2 + 1,
+				this->widget[BSW_DRAG_SIGNALS_DENSITY].top + 2, STR_JUST_INT, TC_ORANGE);
+	}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case BSW_SEMAPHORE_NORM:
+			case BSW_SEMAPHORE_ENTRY:
+			case BSW_SEMAPHORE_EXIT:
+			case BSW_SEMAPHORE_COMBO:
+			case BSW_ELECTRIC_NORM:
+			case BSW_ELECTRIC_ENTRY:
+			case BSW_ELECTRIC_EXIT:
+			case BSW_ELECTRIC_COMBO:
+				this->RaiseWidget((_cur_signal_variant == SIG_ELECTRIC ? BSW_ELECTRIC_NORM : BSW_SEMAPHORE_NORM) + _cur_signal_type);
+
+				_cur_signal_type = (SignalType)((uint)((widget - BSW_SEMAPHORE_NORM) % (SIGTYPE_COMBO + 1)));
+				_cur_signal_variant = widget >= BSW_ELECTRIC_NORM ? SIG_ELECTRIC : SIG_SEMAPHORE;
+				break;
+
+			case BSW_CONVERT:
+				_convert_signal_button = !_convert_signal_button;
+				break;
+
+			case BSW_DRAG_SIGNALS_DENSITY_DECREASE:
+				if (_patches.drag_signals_density > 1) {
+					_patches.drag_signals_density--;
+					SetWindowDirty(FindWindowById(WC_GAME_OPTIONS, 0));
+				}
+				break;
+
+			case BSW_DRAG_SIGNALS_DENSITY_INCREASE:
+				if (_patches.drag_signals_density < 20) {
+					_patches.drag_signals_density++;
+					SetWindowDirty(FindWindowById(WC_GAME_OPTIONS, 0));
+				}
+				break;
+
+			default: break;
 		}
-}
+
+		this->SetDirty();
+	}
+};
 
 /** Widget definition of the build signal window */
 static const Widget _signal_builder_widgets[] = {
@@ -1384,7 +1483,6 @@
 	WC_BUILD_SIGNAL, WC_BUILD_TOOLBAR,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
 	_signal_builder_widgets,
-	SignalBuildWndProc
 };
 
 /**
@@ -1392,59 +1490,55 @@
  */
 static void ShowSignalBuilder()
 {
-	new Window(&_signal_builder_desc);
+	new BuildSignalWindow(&_signal_builder_desc);
 }
 
-/** Enum referring to the widgets of the build rail depot window */
-enum BuildRailDepotWidgets {
-	BRDW_CLOSEBOX = 0,
-	BRDW_CAPTION,
-	BRDW_BACKGROUND,
-	BRDW_DEPOT_NE,
-	BRDW_DEPOT_SE,
-	BRDW_DEPOT_SW,
-	BRDW_DEPOT_NW,
-};
+struct BuildRailDepotWindow : public PickerWindowBase {
+private:
+	/** Enum referring to the widgets of the build rail depot window */
+	enum BuildRailDepotWidgets {
+		BRDW_CLOSEBOX = 0,
+		BRDW_CAPTION,
+		BRDW_BACKGROUND,
+		BRDW_DEPOT_NE,
+		BRDW_DEPOT_SE,
+		BRDW_DEPOT_SW,
+		BRDW_DEPOT_NW,
+	};
 
-static void BuildTrainDepotWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_CREATE: w->LowerWidget(_build_depot_direction + BRDW_DEPOT_NE); break;
+public:
+	BuildRailDepotWindow(const WindowDesc *desc) : PickerWindowBase(desc)
+	{
+		this->LowerWidget(_build_depot_direction + BRDW_DEPOT_NE);
+		this->FindWindowPlacementAndResize(desc);
+	}
 
-	case WE_PAINT: {
-		DrawWindowWidgets(w);
+	virtual void OnPaint()
+	{
+		this->DrawWidgets();
 
 		DrawTrainDepotSprite(70, 17, DIAGDIR_NE, _cur_railtype);
 		DrawTrainDepotSprite(70, 69, DIAGDIR_SE, _cur_railtype);
 		DrawTrainDepotSprite( 2, 69, DIAGDIR_SW, _cur_railtype);
 		DrawTrainDepotSprite( 2, 17, DIAGDIR_NW, _cur_railtype);
-		break;
-		}
+	}
 
-	case WE_CLICK:
-		switch (e->we.click.widget) {
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
 			case BRDW_DEPOT_NE:
 			case BRDW_DEPOT_SE:
 			case BRDW_DEPOT_SW:
 			case BRDW_DEPOT_NW:
-				w->RaiseWidget(_build_depot_direction + BRDW_DEPOT_NE);
-				_build_depot_direction = (DiagDirection)(e->we.click.widget - BRDW_DEPOT_NE);
-				w->LowerWidget(_build_depot_direction + BRDW_DEPOT_NE);
+				this->RaiseWidget(_build_depot_direction + BRDW_DEPOT_NE);
+				_build_depot_direction = (DiagDirection)(widget - BRDW_DEPOT_NE);
+				this->LowerWidget(_build_depot_direction + BRDW_DEPOT_NE);
 				SndPlayFx(SND_15_BEEP);
-				w->SetDirty();
+				this->SetDirty();
 				break;
 		}
-		break;
-
-	case WE_TICK:
-		if (WP(w, def_d).close) delete w;
-		return;
-
-	case WE_DESTROY:
-		if (!WP(w, def_d).close) ResetObjectToPlace();
-		break;
 	}
-}
+};
 
 /** Widget definition of the build rail depot window */
 static const Widget _build_depot_widgets[] = {
@@ -1463,44 +1557,51 @@
 	WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 	_build_depot_widgets,
-	BuildTrainDepotWndProc
 };
 
 static void ShowBuildTrainDepotPicker()
 {
-	new Window(&_build_depot_desc);
+	new BuildRailDepotWindow(&_build_depot_desc);
 }
 
-/** Enum referring to the widgets of the build NewGRF rail waypoint window */
-enum BuildRailWaypointWidgets {
-	BRWW_CLOSEBOX = 0,
-	BRWW_CAPTION,
-	BRWW_BACKGROUND,
-	BRWW_WAYPOINT_1,
-	BRWW_WAYPOINT_2,
-	BRWW_WAYPOINT_3,
-	BRWW_WAYPOINT_4,
-	BRWW_WAYPOINT_5,
-	BRWW_SCROLL,
-};
+struct BuildRailWaypointWindow : PickerWindowBase {
+private:
+	/** Enum referring to the widgets of the build NewGRF rail waypoint window */
+	enum BuildRailWaypointWidgets {
+		BRWW_CLOSEBOX = 0,
+		BRWW_CAPTION,
+		BRWW_BACKGROUND,
+		BRWW_WAYPOINT_1,
+		BRWW_WAYPOINT_2,
+		BRWW_WAYPOINT_3,
+		BRWW_WAYPOINT_4,
+		BRWW_WAYPOINT_5,
+		BRWW_SCROLL,
+	};
 
-static void BuildWaypointWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT: {
+public:
+	BuildRailWaypointWindow(const WindowDesc *desc) : PickerWindowBase(desc)
+	{
+		this->hscroll.cap = 5;
+		this->hscroll.count = _waypoint_count;
+		this->FindWindowPlacementAndResize(desc);
+	};
+
+	virtual void OnPaint()
+	{
 		uint i;
 
-		for (i = 0; i < w->hscroll.cap; i++) {
-			w->SetWidgetLoweredState(i + BRWW_WAYPOINT_1, (w->hscroll.pos + i) == _cur_waypoint_type);
+		for (i = 0; i < this->hscroll.cap; i++) {
+			this->SetWidgetLoweredState(i + BRWW_WAYPOINT_1, (this->hscroll.pos + i) == _cur_waypoint_type);
 		}
 
-		DrawWindowWidgets(w);
+		this->DrawWidgets();
 
-		for (i = 0; i < w->hscroll.cap; i++) {
-			if (w->hscroll.pos + i < w->hscroll.count) {
-				const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, w->hscroll.pos + i);
+		for (i = 0; i < this->hscroll.cap; i++) {
+			if (this->hscroll.pos + i < this->hscroll.count) {
+				const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, this->hscroll.pos + i);
 
-				DrawWaypointSprite(2 + i * 68, 25, w->hscroll.pos + i, _cur_railtype);
+				DrawWaypointSprite(2 + i * 68, 25, this->hscroll.pos + i, _cur_railtype);
 
 				if (statspec != NULL &&
 						HasBit(statspec->callbackmask, CBM_STATION_AVAIL) &&
@@ -1509,16 +1610,17 @@
 				}
 			}
 		}
-		break;
 	}
-	case WE_CLICK: {
-		switch (e->we.click.widget) {
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
 			case BRWW_WAYPOINT_1:
 			case BRWW_WAYPOINT_2:
 			case BRWW_WAYPOINT_3:
 			case BRWW_WAYPOINT_4:
 			case BRWW_WAYPOINT_5: {
-				byte type = e->we.click.widget - BRWW_WAYPOINT_1 + w->hscroll.pos;
+				byte type = widget - BRWW_WAYPOINT_1 + this->hscroll.pos;
 
 				/* Check station availability callback */
 				const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, type);
@@ -1528,22 +1630,12 @@
 
 				_cur_waypoint_type = type;
 				SndPlayFx(SND_15_BEEP);
-				w->SetDirty();
+				this->SetDirty();
 				break;
 			}
 		}
-		break;
 	}
-
-	case WE_TICK:
-		if (WP(w, def_d).close) delete w;
-		break;
-
-	case WE_DESTROY:
-		if (!WP(w, def_d).close) ResetObjectToPlace();
-		break;
-	}
-}
+};
 
 /** Widget definition for the build NewGRF rail waypoint window */
 static const Widget _build_waypoint_widgets[] = {
@@ -1566,17 +1658,16 @@
 	WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 	_build_waypoint_widgets,
-	BuildWaypointWndProc
 };
 
 static void ShowBuildWaypointPicker()
 {
-	Window *w = new Window(&_build_waypoint_desc);
-	w->hscroll.cap = 5;
-	w->hscroll.count = _waypoint_count;
+	new BuildRailWaypointWindow(&_build_waypoint_desc);
 }
 
-
+/**
+ * Initialize rail building GUI settings
+ */
 void InitializeRailGui()
 {
 	_build_depot_direction = DIAGDIR_NW;
@@ -1585,6 +1676,10 @@
 	_railstation.dragdrop = true;
 }
 
+/**
+ * Re-initialize rail-build toolbar after toggling support for electric trains
+ * @param disable Boolean whether electric trains are disabled (removed from the game)
+ */
 void ReinitGuiAfterToggleElrail(bool disable)
 {
 	extern RailType _last_built_railtype;
@@ -1600,6 +1695,7 @@
 	MarkWholeScreenDirty();
 }
 
+/** Set the initial (default) railtype to use */
 static void SetDefaultRailGui()
 {
 	if (_local_player == PLAYER_SPECTATOR || !IsValidPlayer(_local_player)) return;
--- a/src/rail_map.h	Mon May 19 14:14:33 2008 +0000
+++ b/src/rail_map.h	Mon May 19 15:13:58 2008 +0000
@@ -168,6 +168,17 @@
 	return (DiagDirection)GB(_m[t].m5, 0, 2);
 }
 
+/**
+ * Returns the track of a depot, ignoring direction
+ * @pre IsRailDepotTile(t)
+ * @param t the tile to get the depot track from
+ * @return the track of the depot
+ */
+static inline Track GetRailDepotTrack(TileIndex t)
+{
+	return DiagDirToDiagTrack(GetRailDepotDirection(t));
+}
+
 
 /**
  * Returns the axis of the waypoint
--- a/src/road_cmd.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/road_cmd.cpp	Mon May 19 15:13:58 2008 +0000
@@ -43,6 +43,37 @@
 #include "table/sprites.h"
 #include "table/strings.h"
 
+
+bool RoadVehiclesAreBuilt()
+{
+	const Vehicle* v;
+
+	FOR_ALL_VEHICLES(v) {
+		if (v->type == VEH_ROAD) return true;
+	}
+	return false;
+}
+
+/**
+ * Change the side of the road vehicles drive on (server only).
+ * @param tile unused
+ * @param flags operation to perform
+ * @param p1 the side of the road; 0 = left side and 1 = right side
+ * @param p2 unused
+ */
+CommandCost CmdSetRoadDriveSide(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+	/* Check boundaries and you can only change this if NO vehicles have been built yet,
+	 * except in the intro-menu where of course it's always possible to do so. */
+	if (p1 > 1 || (_game_mode != GM_MENU && RoadVehiclesAreBuilt())) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		_opt_ptr->road_side = p1;
+		InvalidateWindow(WC_GAME_OPTIONS, 0);
+	}
+	return CommandCost();
+}
+
 #define M(x) (1 << (x))
 /* Level crossings may only be built on these slopes */
 static const uint32 VALID_LEVEL_CROSSING_SLOPES = (M(SLOPE_SEN) | M(SLOPE_ENW) | M(SLOPE_NWS) | M(SLOPE_NS) | M(SLOPE_WSE) | M(SLOPE_EW) | M(SLOPE_FLAT));
@@ -1390,7 +1421,7 @@
 
 					if (side != INVALID_DIAGDIR && side != dir) break;
 
-					trackdirbits = TrackBitsToTrackdirBits(AxisToTrackBits(DiagDirToAxis(dir)));
+					trackdirbits = TrackBitsToTrackdirBits(DiagDirToDiagTrackBits(dir));
 					break;
 				}
 			}
--- a/src/road_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/road_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -400,220 +400,222 @@
 	'R',
 };
 
-/**
- * Update the remove button lowered state of the road toolbar
- *
- * @param w The toolbar window
- * @param clicked_widget The widget which the player clicked just now
- */
-static void UpdateOptionWidgetStatus(Window *w, RoadToolbarWidgets clicked_widget)
-{
-	/* The remove and the one way button state is driven
-	 * by the other buttons so they don't act on themselfs.
-	 * Both are only valid if they are able to apply as options. */
-	switch (clicked_widget) {
-		case RTW_REMOVE:
-			w->RaiseWidget(RTW_ONE_WAY);
-			w->InvalidateWidget(RTW_ONE_WAY);
-			break;
-
-		case RTW_ONE_WAY:
-			w->RaiseWidget(RTW_REMOVE);
-			w->InvalidateWidget(RTW_REMOVE);
-			break;
-
-		case RTW_BUS_STATION:
-		case RTW_TRUCK_STATION:
-			w->DisableWidget(RTW_ONE_WAY);
-			w->SetWidgetDisabledState(RTW_REMOVE, !w->IsWidgetLowered(clicked_widget));
-			break;
+struct BuildRoadToolbarWindow : Window {
+	BuildRoadToolbarWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+	{
+		this->SetWidgetsDisabledState(true,
+			RTW_REMOVE,
+			RTW_ONE_WAY,
+			WIDGET_LIST_END);
 
-		case RTW_ROAD_X:
-		case RTW_ROAD_Y:
-		case RTW_AUTOROAD:
-			w->SetWidgetsDisabledState(!w->IsWidgetLowered(clicked_widget),
-				RTW_REMOVE,
-				RTW_ONE_WAY,
-				WIDGET_LIST_END);
-			break;
-
-		default:
-			/* When any other buttons than road/station, raise and
-			 * disable the removal button */
-			w->SetWidgetsDisabledState(true,
-				RTW_REMOVE,
-				RTW_ONE_WAY,
-				WIDGET_LIST_END);
-			w->SetWidgetsLoweredState (false,
-				RTW_REMOVE,
-				RTW_ONE_WAY,
-				WIDGET_LIST_END);
-			break;
+		this->FindWindowPlacementAndResize(desc);
+		if (_patches.link_terraform_toolbar) ShowTerraformToolbar(this);
 	}
-}
 
-static void BuildRoadToolbWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_CREATE:
-			w->SetWidgetsDisabledState(true,
-				RTW_REMOVE,
-				RTW_ONE_WAY,
-				WIDGET_LIST_END);
-			break;
+	~BuildRoadToolbarWindow()
+	{
+		if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
+	}
 
-		case WE_PAINT:
-			w->SetWidgetsDisabledState(!CanBuildVehicleInfrastructure(VEH_ROAD),
-				RTW_DEPOT,
-				RTW_BUS_STATION,
-				RTW_TRUCK_STATION,
-				WIDGET_LIST_END);
-			DrawWindowWidgets(w);
-			break;
+	/**
+	 * Update the remove button lowered state of the road toolbar
+	 *
+	 * @param clicked_widget The widget which the player clicked just now
+	 */
+	void UpdateOptionWidgetStatus(RoadToolbarWidgets clicked_widget)
+	{
+		/* The remove and the one way button state is driven
+		 * by the other buttons so they don't act on themselfs.
+		 * Both are only valid if they are able to apply as options. */
+		switch (clicked_widget) {
+			case RTW_REMOVE:
+				this->RaiseWidget(RTW_ONE_WAY);
+				this->InvalidateWidget(RTW_ONE_WAY);
+				break;
 
-		case WE_CLICK:
-			if (e->we.click.widget >= RTW_ROAD_X) {
+			case RTW_ONE_WAY:
+				this->RaiseWidget(RTW_REMOVE);
+				this->InvalidateWidget(RTW_REMOVE);
+				break;
+
+			case RTW_BUS_STATION:
+			case RTW_TRUCK_STATION:
+				this->DisableWidget(RTW_ONE_WAY);
+				this->SetWidgetDisabledState(RTW_REMOVE, !this->IsWidgetLowered(clicked_widget));
+				break;
+
+			case RTW_ROAD_X:
+			case RTW_ROAD_Y:
+			case RTW_AUTOROAD:
+				this->SetWidgetsDisabledState(!this->IsWidgetLowered(clicked_widget),
+					RTW_REMOVE,
+					RTW_ONE_WAY,
+					WIDGET_LIST_END);
+				break;
+
+			default:
+				/* When any other buttons than road/station, raise and
+				 * disable the removal button */
+				this->SetWidgetsDisabledState(true,
+					RTW_REMOVE,
+					RTW_ONE_WAY,
+					WIDGET_LIST_END);
+				this->SetWidgetsLoweredState (false,
+					RTW_REMOVE,
+					RTW_ONE_WAY,
+					WIDGET_LIST_END);
+				break;
+		}
+	}
+
+	virtual void OnPaint()
+	{
+		this->SetWidgetsDisabledState(!CanBuildVehicleInfrastructure(VEH_ROAD),
+			RTW_DEPOT,
+			RTW_BUS_STATION,
+			RTW_TRUCK_STATION,
+			WIDGET_LIST_END);
+		this->DrawWidgets();
+	}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		if (widget >= RTW_ROAD_X) {
+			_remove_button_clicked = false;
+			_one_way_button_clicked = false;
+			_build_road_button_proc[widget - RTW_ROAD_X](this);
+		}
+		this->UpdateOptionWidgetStatus((RoadToolbarWidgets)widget);
+		if (_ctrl_pressed) RoadToolbar_CtrlChanged(this);
+	}
+
+	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+	{
+		EventState state = ES_NOT_HANDLED;
+		for (uint i = 0; i != lengthof(_road_keycodes); i++) {
+			if (keycode == _road_keycodes[i]) {
 				_remove_button_clicked = false;
 				_one_way_button_clicked = false;
-				_build_road_button_proc[e->we.click.widget - RTW_ROAD_X](w);
+				_build_road_button_proc[i](this);
+				this->UpdateOptionWidgetStatus((RoadToolbarWidgets)(i + RTW_ROAD_X));
+				if (_ctrl_pressed) RoadToolbar_CtrlChanged(this);
+				state = ES_HANDLED;
+				break;
 			}
-			UpdateOptionWidgetStatus(w, (RoadToolbarWidgets)e->we.click.widget);
-			if (_ctrl_pressed) RoadToolbar_CtrlChanged(w);
-			break;
-
-		case WE_KEYPRESS:
-			for (uint i = 0; i != lengthof(_road_keycodes); i++) {
-				if (e->we.keypress.keycode == _road_keycodes[i]) {
-					e->we.keypress.cont = false;
-					_remove_button_clicked = false;
-					_one_way_button_clicked = false;
-					_build_road_button_proc[i](w);
-					UpdateOptionWidgetStatus(w, (RoadToolbarWidgets)(i + RTW_ROAD_X));
-					if (_ctrl_pressed) RoadToolbar_CtrlChanged(w);
-					break;
-				}
-			}
-			MarkTileDirty(_thd.pos.x, _thd.pos.y); // redraw tile selection
-			break;
-
-		case WE_PLACE_OBJ:
-			_remove_button_clicked = w->IsWidgetLowered(RTW_REMOVE);
-			_one_way_button_clicked = w->IsWidgetLowered(RTW_ONE_WAY);
-			_place_proc(e->we.place.tile);
-			break;
+		}
+		MarkTileDirty(_thd.pos.x, _thd.pos.y); // redraw tile selection
+		return state;
+	}
 
-		case WE_ABORT_PLACE_OBJ:
-			w->RaiseButtons();
-			w->SetWidgetsDisabledState(true,
-				RTW_REMOVE,
-				RTW_ONE_WAY,
-				WIDGET_LIST_END);
-			w->InvalidateWidget(RTW_REMOVE);
-			w->InvalidateWidget(RTW_ONE_WAY);
+	virtual void OnPlaceObject(Point pt, TileIndex tile)
+	{
+		_remove_button_clicked = this->IsWidgetLowered(RTW_REMOVE);
+		_one_way_button_clicked = this->IsWidgetLowered(RTW_ONE_WAY);
+		_place_proc(tile);
+	}
 
-			w = FindWindowById(WC_BUS_STATION, 0);
-			if (w != NULL) WP(w, def_d).close = true;
-			w = FindWindowById(WC_TRUCK_STATION, 0);
-			if (w != NULL) WP(w, def_d).close = true;
-			w = FindWindowById(WC_BUILD_DEPOT, 0);
-			if (w != NULL) WP(w, def_d).close = true;
-			break;
+	virtual void OnPlaceObjectAbort()
+	{
+		this->RaiseButtons();
+		this->SetWidgetsDisabledState(true,
+			RTW_REMOVE,
+			RTW_ONE_WAY,
+			WIDGET_LIST_END);
+		this->InvalidateWidget(RTW_REMOVE);
+		this->InvalidateWidget(RTW_ONE_WAY);
 
-		case WE_PLACE_DRAG:
-			/* Here we update the end tile flags
-			* of the road placement actions.
-			* At first we reset the end halfroad
-			* bits and if needed we set them again. */
-			switch (e->we.place.select_proc) {
-				case DDSP_PLACE_ROAD_X_DIR:
-					_place_road_flag &= ~RF_END_HALFROAD_X;
-					if (e->we.place.pt.x & 8) _place_road_flag |= RF_END_HALFROAD_X;
-					break;
+		delete FindWindowById(WC_BUS_STATION, 0);
+		delete FindWindowById(WC_TRUCK_STATION, 0);
+		delete FindWindowById(WC_BUILD_DEPOT, 0);
+	}
 
-				case DDSP_PLACE_ROAD_Y_DIR:
-					_place_road_flag &= ~RF_END_HALFROAD_Y;
-					if (e->we.place.pt.y & 8) _place_road_flag |= RF_END_HALFROAD_Y;
+	virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
+	{
+		/* Here we update the end tile flags
+		 * of the road placement actions.
+		 * At first we reset the end halfroad
+		 * bits and if needed we set them again. */
+		switch (select_proc) {
+			case DDSP_PLACE_ROAD_X_DIR:
+				_place_road_flag &= ~RF_END_HALFROAD_X;
+				if (pt.x & 8) _place_road_flag |= RF_END_HALFROAD_X;
+				break;
+
+			case DDSP_PLACE_ROAD_Y_DIR:
+				_place_road_flag &= ~RF_END_HALFROAD_Y;
+				if (pt.y & 8) _place_road_flag |= RF_END_HALFROAD_Y;
+				break;
+
+			case DDSP_PLACE_AUTOROAD:
+				_place_road_flag &= ~(RF_END_HALFROAD_Y | RF_END_HALFROAD_X);
+				if (pt.y & 8) _place_road_flag |= RF_END_HALFROAD_Y;
+				if (pt.x & 8) _place_road_flag |= RF_END_HALFROAD_X;
+
+				/* For autoroad we need to update the
+				 * direction of the road */
+				if (_thd.size.x > _thd.size.y || (_thd.size.x == _thd.size.y &&
+						( (_tile_fract_coords.x < _tile_fract_coords.y && (_tile_fract_coords.x + _tile_fract_coords.y) < 16) ||
+						(_tile_fract_coords.x > _tile_fract_coords.y && (_tile_fract_coords.x + _tile_fract_coords.y) > 16) ))) {
+					/* Set dir = X */
+					_place_road_flag &= ~RF_DIR_Y;
+				} else {
+					/* Set dir = Y */
+					_place_road_flag |= RF_DIR_Y;
+				}
+
+				break;
+
+			default:
+				break;
+		}
+
+		VpSelectTilesWithMethod(pt.x, pt.y, select_method);
+	}
+
+	virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
+	{
+		if (pt.x != -1) {
+			switch (select_proc) {
+				default: NOT_REACHED();
+				case DDSP_BUILD_BRIDGE:
+					ResetObjectToPlace();
+					ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_ROAD, RoadTypeToRoadTypes(_cur_roadtype));
 					break;
 
-				case DDSP_PLACE_AUTOROAD:
-					_place_road_flag &= ~(RF_END_HALFROAD_Y | RF_END_HALFROAD_X);
-					if (e->we.place.pt.y & 8) _place_road_flag |= RF_END_HALFROAD_Y;
-					if (e->we.place.pt.x & 8) _place_road_flag |= RF_END_HALFROAD_X;
-
-					/* For autoroad we need to update the
-					* direction of the road */
-					if (_thd.size.x > _thd.size.y || (_thd.size.x == _thd.size.y &&
-							( (_tile_fract_coords.x < _tile_fract_coords.y && (_tile_fract_coords.x + _tile_fract_coords.y) < 16) ||
-							(_tile_fract_coords.x > _tile_fract_coords.y && (_tile_fract_coords.x + _tile_fract_coords.y) > 16) ))) {
-						/* Set dir = X */
-						_place_road_flag &= ~RF_DIR_Y;
-					} else {
-						/* Set dir = Y */
-						_place_road_flag |= RF_DIR_Y;
-					}
-
+				case DDSP_DEMOLISH_AREA:
+					GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
 					break;
 
-				default:
+				case DDSP_PLACE_ROAD_X_DIR:
+				case DDSP_PLACE_ROAD_Y_DIR:
+				case DDSP_PLACE_AUTOROAD:
+					/* Flag description:
+					* Use the first three bits (0x07) if dir == Y
+					* else use the last 2 bits (X dir has
+					* not the 3rd bit set) */
+					_place_road_flag = (RoadFlags)((_place_road_flag & RF_DIR_Y) ? (_place_road_flag & 0x07) : (_place_road_flag >> 3));
+
+					DoCommandP(end_tile, start_tile, _place_road_flag | (_cur_roadtype << 3) | (_one_way_button_clicked << 5), CcPlaySound1D,
+						(_ctrl_pressed || _remove_button_clicked) ?
+						CMD_REMOVE_LONG_ROAD | CMD_NO_WATER | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_road) :
+						CMD_BUILD_LONG_ROAD | CMD_NO_WATER | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_road));
 					break;
 			}
-
-			VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.select_method);
-			return;
-
-		case WE_PLACE_MOUSEUP:
-			if (e->we.place.pt.x != -1) {
-				TileIndex start_tile = e->we.place.starttile;
-				TileIndex end_tile = e->we.place.tile;
-
-				switch (e->we.place.select_proc) {
-					default: NOT_REACHED();
-					case DDSP_BUILD_BRIDGE:
-						ResetObjectToPlace();
-						ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_ROAD, RoadTypeToRoadTypes(_cur_roadtype));
-						break;
-
-					case DDSP_DEMOLISH_AREA:
-						GUIPlaceProcDragXY(e);
-						break;
+		}
+	}
 
-					case DDSP_PLACE_ROAD_X_DIR:
-					case DDSP_PLACE_ROAD_Y_DIR:
-					case DDSP_PLACE_AUTOROAD:
-						/* Flag description:
-						* Use the first three bits (0x07) if dir == Y
-						* else use the last 2 bits (X dir has
-						* not the 3rd bit set) */
-						_place_road_flag = (RoadFlags)((_place_road_flag & RF_DIR_Y) ? (_place_road_flag & 0x07) : (_place_road_flag >> 3));
-
-						DoCommandP(end_tile, start_tile, _place_road_flag | (_cur_roadtype << 3) | (_one_way_button_clicked << 5), CcPlaySound1D,
-							(_ctrl_pressed || _remove_button_clicked) ?
-							CMD_REMOVE_LONG_ROAD | CMD_NO_WATER | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_road) :
-							CMD_BUILD_LONG_ROAD | CMD_NO_WATER | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_road));
-						break;
-				}
-			}
-			break;
+	virtual void OnPlacePresize(Point pt, TileIndex tile)
+	{
+		DoCommand(tile, 0x200 | RoadTypeToRoadTypes(_cur_roadtype), 0, DC_AUTO, CMD_BUILD_TUNNEL);
+		VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile);
+	}
 
-		case WE_PLACE_PRESIZE: {
-			TileIndex tile = e->we.place.tile;
-
-			DoCommand(tile, 0x200 | RoadTypeToRoadTypes(_cur_roadtype), 0, DC_AUTO, CMD_BUILD_TUNNEL);
-			VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile);
-		} break;
-
-		case WE_DESTROY:
-			if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
-			break;
-
-		case WE_CTRL_CHANGED:
-			if (RoadToolbar_CtrlChanged(w)) e->we.ctrl.cont = false;
-			break;
-
-		default:
-			break;
+	virtual EventState OnCTRLStateChange()
+	{
+		if (RoadToolbar_CtrlChanged(this)) return ES_HANDLED;
+		return ES_NOT_HANDLED;
 	}
-}
+};
 
 /** Widget definition of the build road toolbar */
 static const Widget _build_road_widgets[] = {
@@ -641,7 +643,6 @@
 	WC_BUILD_TOOLBAR, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
 	_build_road_widgets,
-	BuildRoadToolbWndProc
 };
 
 /** Widget definition of the build tram toolbar */
@@ -670,7 +671,6 @@
 	WC_BUILD_TOOLBAR, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
 	_build_tramway_widgets,
-	BuildRoadToolbWndProc
 };
 
 void ShowBuildRoadToolbar(RoadType roadtype)
@@ -679,8 +679,7 @@
 	_cur_roadtype = roadtype;
 
 	DeleteWindowByClass(WC_BUILD_TOOLBAR);
-	Window *w = AllocateWindowDescFront<Window>(roadtype == ROADTYPE_ROAD ? &_build_road_desc : &_build_tramway_desc, TRANSPORT_ROAD);
-	if (_patches.link_terraform_toolbar) ShowTerraformToolbar(w);
+	AllocateWindowDescFront<BuildRoadToolbarWindow>(roadtype == ROADTYPE_ROAD ? &_build_road_desc : &_build_tramway_desc, TRANSPORT_ROAD);
 }
 
 /** Widget definition of the build road toolbar in the scenario editor */
@@ -708,72 +707,67 @@
 	WC_SCEN_BUILD_ROAD, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
 	_build_road_scen_widgets,
-	BuildRoadToolbWndProc
 };
 
 void ShowBuildRoadScenToolbar()
 {
 	_cur_roadtype = ROADTYPE_ROAD;
-	AllocateWindowDescFront<Window>(&_build_road_scen_desc, 0);
+	AllocateWindowDescFront<BuildRoadToolbarWindow>(&_build_road_scen_desc, 0);
 }
 
-/** Enum referring to the widgets of the build road depot window */
-enum BuildRoadDepotWidgets {
-	BRDW_CLOSEBOX = 0,
-	BRDW_CAPTION,
-	BRDW_BACKGROUND,
-	BRDW_DEPOT_NE,
-	BRDW_DEPOT_SE,
-	BRDW_DEPOT_SW,
-	BRDW_DEPOT_NW,
-};
-
-static void BuildRoadDepotWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_CREATE:
-			w->LowerWidget(_road_depot_orientation + BRDW_DEPOT_NE);
-			break;
-
-		case WE_PAINT:
-			DrawWindowWidgets(w);
-
-			DrawRoadDepotSprite(70, 17, DIAGDIR_NE, _cur_roadtype);
-			DrawRoadDepotSprite(70, 69, DIAGDIR_SE, _cur_roadtype);
-			DrawRoadDepotSprite( 2, 69, DIAGDIR_SW, _cur_roadtype);
-			DrawRoadDepotSprite( 2, 17, DIAGDIR_NW, _cur_roadtype);
-			break;
+struct BuildRoadDepotWindow : public PickerWindowBase {
+private:
+	/** Enum referring to the widgets of the build road depot window */
+	enum BuildRoadDepotWidgets {
+		BRDW_CLOSEBOX = 0,
+		BRDW_CAPTION,
+		BRDW_BACKGROUND,
+		BRDW_DEPOT_NE,
+		BRDW_DEPOT_SE,
+		BRDW_DEPOT_SW,
+		BRDW_DEPOT_NW,
+	};
 
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case BRDW_DEPOT_NW:
-				case BRDW_DEPOT_NE:
-				case BRDW_DEPOT_SW:
-				case BRDW_DEPOT_SE:
-					w->RaiseWidget(_road_depot_orientation + BRDW_DEPOT_NE);
-					_road_depot_orientation = (DiagDirection)(e->we.click.widget - BRDW_DEPOT_NE);
-					w->LowerWidget(_road_depot_orientation + BRDW_DEPOT_NE);
-					SndPlayFx(SND_15_BEEP);
-					w->SetDirty();
-					break;
+public:
+	BuildRoadDepotWindow(const WindowDesc *desc) : PickerWindowBase(desc)
+	{
+		this->LowerWidget(_road_depot_orientation + BRDW_DEPOT_NE);
+		if ( _cur_roadtype == ROADTYPE_TRAM) {
+			this->widget[BRDW_CAPTION].data = STR_TRAM_DEPOT_ORIENTATION;
+			for (int i = BRDW_DEPOT_NE; i <= BRDW_DEPOT_NW; i++) this->widget[i].tooltips = STR_SELECT_TRAM_VEHICLE_DEPOT;
+		}
+		this->FindWindowPlacementAndResize(desc);
+	}
 
-				default:
-					break;
-			}
-			break;
+	virtual void OnPaint()
+	{
+		this->DrawWidgets();
 
-		case WE_TICK:
-			if (WP(w, def_d).close) delete w;
-			break;
+		DrawRoadDepotSprite(70, 17, DIAGDIR_NE, _cur_roadtype);
+		DrawRoadDepotSprite(70, 69, DIAGDIR_SE, _cur_roadtype);
+		DrawRoadDepotSprite( 2, 69, DIAGDIR_SW, _cur_roadtype);
+		DrawRoadDepotSprite( 2, 17, DIAGDIR_NW, _cur_roadtype);
+	}
 
-		case WE_DESTROY:
-			if (!WP(w, def_d).close) ResetObjectToPlace();
-			break;
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case BRDW_DEPOT_NW:
+			case BRDW_DEPOT_NE:
+			case BRDW_DEPOT_SW:
+			case BRDW_DEPOT_SE:
+				this->RaiseWidget(_road_depot_orientation + BRDW_DEPOT_NE);
+				_road_depot_orientation = (DiagDirection)(widget - BRDW_DEPOT_NE);
+				this->LowerWidget(_road_depot_orientation + BRDW_DEPOT_NE);
+				SndPlayFx(SND_15_BEEP);
+				this->SetDirty();
+				break;
 
-		default:
-			break;
+			default:
+				break;
+		}
 	}
-}
+};
 
 /** Widget definition of the build road depot window */
 static const Widget _build_road_depot_widgets[] = {
@@ -787,155 +781,128 @@
 {   WIDGETS_END},
 };
 
-/** Widget definition of the build tram depot window */
-static const Widget _build_tram_depot_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},              // BRDW_CLOSEBOX
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   139,     0,    13, STR_TRAM_DEPOT_ORIENTATION,      STR_018C_WINDOW_TITLE_DRAG_THIS},    // BRDW_CAPTION
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   139,    14,   121, 0x0,                             STR_NULL},                           // BRDW_BACKGROUND
-{      WWT_PANEL,   RESIZE_NONE,    14,    71,   136,    17,    66, 0x0,                             STR_SELECT_TRAM_VEHICLE_DEPOT},      // BRDW_DEPOT_NE
-{      WWT_PANEL,   RESIZE_NONE,    14,    71,   136,    69,   118, 0x0,                             STR_SELECT_TRAM_VEHICLE_DEPOT},      // BRDW_DEPOT_SE
-{      WWT_PANEL,   RESIZE_NONE,    14,     3,    68,    69,   118, 0x0,                             STR_SELECT_TRAM_VEHICLE_DEPOT},      // BRDW_DEPOT_SW
-{      WWT_PANEL,   RESIZE_NONE,    14,     3,    68,    17,    66, 0x0,                             STR_SELECT_TRAM_VEHICLE_DEPOT},      // BRDW_DEPOT_NW
-{   WIDGETS_END},
-};
-
 static const WindowDesc _build_road_depot_desc = {
 	WDP_AUTO, WDP_AUTO, 140, 122, 140, 122,
 	WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 	_build_road_depot_widgets,
-	BuildRoadDepotWndProc
-};
-
-static const WindowDesc _build_tram_depot_desc = {
-	WDP_AUTO, WDP_AUTO, 140, 122, 140, 122,
-	WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_build_tram_depot_widgets,
-	BuildRoadDepotWndProc
 };
 
 static void ShowRoadDepotPicker()
 {
-	new Window(_cur_roadtype == ROADTYPE_ROAD ? &_build_road_depot_desc : &_build_tram_depot_desc);
+	new BuildRoadDepotWindow(&_build_road_depot_desc);
 }
 
-/** Enum referring to the widgets of the build road station window */
-enum BuildRoadStationWidgets {
-	BRSW_CLOSEBOX = 0,
-	BRSW_CAPTION,
-	BRSW_BACKGROUND,
-	BRSW_STATION_NE,
-	BRSW_STATION_SE,
-	BRSW_STATION_SW,
-	BRSW_STATION_NW,
-	BRSW_STATION_X,
-	BRSW_STATION_Y,
-	BRSW_LT_OFF,
-	BRSW_LT_ON,
-	BRSW_INFO,
-};
-
-static void RoadStationPickerWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_CREATE:
-			/* Trams don't have non-drivethrough stations */
-			if (_cur_roadtype == ROADTYPE_TRAM && _road_station_picker_orientation < DIAGDIR_END) {
-				_road_station_picker_orientation = DIAGDIR_END;
-			}
-			w->SetWidgetsDisabledState(_cur_roadtype == ROADTYPE_TRAM,
-				BRSW_STATION_NE,
-				BRSW_STATION_SE,
-				BRSW_STATION_SW,
-				BRSW_STATION_NW,
-				WIDGET_LIST_END);
-
-			w->LowerWidget(_road_station_picker_orientation + BRSW_STATION_NE);
-			w->LowerWidget(_station_show_coverage + BRSW_LT_OFF);
-			break;
-
-		case WE_PAINT: {
-			if (WP(w, def_d).close) return;
-
-			DrawWindowWidgets(w);
-
-			if (_station_show_coverage) {
-				int rad = _patches.modified_catchment ? CA_TRUCK /* = CA_BUS */ : CA_UNMODIFIED;
-				SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
-			} else {
-				SetTileSelectSize(1, 1);
-			}
-
-			StationType st = (w->window_class == WC_BUS_STATION) ? STATION_BUS : STATION_TRUCK;
-
-			StationPickerDrawSprite(103, 35, st, INVALID_RAILTYPE, ROADTYPE_ROAD, 0);
-			StationPickerDrawSprite(103, 85, st, INVALID_RAILTYPE, ROADTYPE_ROAD, 1);
-			StationPickerDrawSprite( 35, 85, st, INVALID_RAILTYPE, ROADTYPE_ROAD, 2);
-			StationPickerDrawSprite( 35, 35, st, INVALID_RAILTYPE, ROADTYPE_ROAD, 3);
-
-			StationPickerDrawSprite(171, 35, st, INVALID_RAILTYPE, _cur_roadtype, 4);
-			StationPickerDrawSprite(171, 85, st, INVALID_RAILTYPE, _cur_roadtype, 5);
+struct BuildRoadStationWindow : public PickerWindowBase {
+private:
+	/** Enum referring to the widgets of the build road station window */
+	enum BuildRoadStationWidgets {
+		BRSW_CLOSEBOX = 0,
+		BRSW_CAPTION,
+		BRSW_BACKGROUND,
+		BRSW_STATION_NE,
+		BRSW_STATION_SE,
+		BRSW_STATION_SW,
+		BRSW_STATION_NW,
+		BRSW_STATION_X,
+		BRSW_STATION_Y,
+		BRSW_LT_OFF,
+		BRSW_LT_ON,
+		BRSW_INFO,
+	};
 
-			int text_end = DrawStationCoverageAreaText(2, 146,
-				(w->window_class == WC_BUS_STATION) ? SCT_PASSENGERS_ONLY : SCT_NON_PASSENGERS_ONLY,
-				3, false);
-			text_end = DrawStationCoverageAreaText(2, text_end + 4,
-				(w->window_class == WC_BUS_STATION) ? SCT_PASSENGERS_ONLY : SCT_NON_PASSENGERS_ONLY,
-				3, true) + 4;
-			if (text_end > w->widget[BRSW_BACKGROUND].bottom) {
-				w->SetDirty();
-				ResizeWindowForWidget(w, BRSW_BACKGROUND, 0, text_end - w->widget[BRSW_BACKGROUND].bottom);
-				w->SetDirty();
-			}
-		} break;
-
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case BRSW_STATION_NE:
-				case BRSW_STATION_SE:
-				case BRSW_STATION_SW:
-				case BRSW_STATION_NW:
-				case BRSW_STATION_X:
-				case BRSW_STATION_Y:
-					w->RaiseWidget(_road_station_picker_orientation + BRSW_STATION_NE);
-					_road_station_picker_orientation = (DiagDirection)(e->we.click.widget - BRSW_STATION_NE);
-					w->LowerWidget(_road_station_picker_orientation + BRSW_STATION_NE);
-					SndPlayFx(SND_15_BEEP);
-					w->SetDirty();
-					break;
+public:
+	BuildRoadStationWindow(const WindowDesc *desc, RoadStopType rs) : PickerWindowBase(desc)
+	{
+		/* Trams don't have non-drivethrough stations */
+		if (_cur_roadtype == ROADTYPE_TRAM && _road_station_picker_orientation < DIAGDIR_END) {
+			_road_station_picker_orientation = DIAGDIR_END;
+		}
+		this->SetWidgetsDisabledState(_cur_roadtype == ROADTYPE_TRAM,
+			BRSW_STATION_NE,
+			BRSW_STATION_SE,
+			BRSW_STATION_SW,
+			BRSW_STATION_NW,
+			WIDGET_LIST_END);
 
-				case BRSW_LT_OFF:
-				case BRSW_LT_ON:
-					w->RaiseWidget(_station_show_coverage + BRSW_LT_OFF);
-					_station_show_coverage = (e->we.click.widget != BRSW_LT_OFF);
-					w->LowerWidget(_station_show_coverage + BRSW_LT_OFF);
-					SndPlayFx(SND_15_BEEP);
-					w->SetDirty();
-					break;
-
-				default:
-					break;
-			}
-			break;
+		this->window_class = (rs == ROADSTOP_BUS) ? WC_BUS_STATION : WC_TRUCK_STATION;
+		this->widget[BRSW_CAPTION].data = _road_type_infos[_cur_roadtype].picker_title[rs];
+		for (uint i = BRSW_STATION_NE; i < BRSW_LT_OFF; i++) this->widget[i].tooltips = _road_type_infos[_cur_roadtype].picker_tooltip[rs];
 
-		case WE_TICK:
-			if (WP(w, def_d).close) {
-				delete w;
-				return;
-			}
+		this->LowerWidget(_road_station_picker_orientation + BRSW_STATION_NE);
+		this->LowerWidget(_station_show_coverage + BRSW_LT_OFF);
+		this->FindWindowPlacementAndResize(desc);
+	}
 
-			CheckRedrawStationCoverage(w);
-			break;
+	virtual void OnPaint()
+	{
+		this->DrawWidgets();
 
-		case WE_DESTROY:
-			if (!WP(w, def_d).close) ResetObjectToPlace();
-			break;
+		if (_station_show_coverage) {
+			int rad = _patches.modified_catchment ? CA_TRUCK /* = CA_BUS */ : CA_UNMODIFIED;
+			SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
+		} else {
+			SetTileSelectSize(1, 1);
+		}
 
-		default:
-			break;
+		StationType st = (this->window_class == WC_BUS_STATION) ? STATION_BUS : STATION_TRUCK;
+
+		StationPickerDrawSprite(103, 35, st, INVALID_RAILTYPE, ROADTYPE_ROAD, 0);
+		StationPickerDrawSprite(103, 85, st, INVALID_RAILTYPE, ROADTYPE_ROAD, 1);
+		StationPickerDrawSprite( 35, 85, st, INVALID_RAILTYPE, ROADTYPE_ROAD, 2);
+		StationPickerDrawSprite( 35, 35, st, INVALID_RAILTYPE, ROADTYPE_ROAD, 3);
+
+		StationPickerDrawSprite(171, 35, st, INVALID_RAILTYPE, _cur_roadtype, 4);
+		StationPickerDrawSprite(171, 85, st, INVALID_RAILTYPE, _cur_roadtype, 5);
+
+		int text_end = DrawStationCoverageAreaText(2, 146,
+			(this->window_class == WC_BUS_STATION) ? SCT_PASSENGERS_ONLY : SCT_NON_PASSENGERS_ONLY,
+			3, false);
+		text_end = DrawStationCoverageAreaText(2, text_end + 4,
+			(this->window_class == WC_BUS_STATION) ? SCT_PASSENGERS_ONLY : SCT_NON_PASSENGERS_ONLY,
+			3, true) + 4;
+		if (text_end > this->widget[BRSW_BACKGROUND].bottom) {
+			this->SetDirty();
+			ResizeWindowForWidget(this, BRSW_BACKGROUND, 0, text_end - this->widget[BRSW_BACKGROUND].bottom);
+			this->SetDirty();
+		}
 	}
-}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case BRSW_STATION_NE:
+			case BRSW_STATION_SE:
+			case BRSW_STATION_SW:
+			case BRSW_STATION_NW:
+			case BRSW_STATION_X:
+			case BRSW_STATION_Y:
+				this->RaiseWidget(_road_station_picker_orientation + BRSW_STATION_NE);
+				_road_station_picker_orientation = (DiagDirection)(widget - BRSW_STATION_NE);
+				this->LowerWidget(_road_station_picker_orientation + BRSW_STATION_NE);
+				SndPlayFx(SND_15_BEEP);
+				this->SetDirty();
+				break;
+
+			case BRSW_LT_OFF:
+			case BRSW_LT_ON:
+				this->RaiseWidget(_station_show_coverage + BRSW_LT_OFF);
+				_station_show_coverage = (widget != BRSW_LT_OFF);
+				this->LowerWidget(_station_show_coverage + BRSW_LT_OFF);
+				SndPlayFx(SND_15_BEEP);
+				this->SetDirty();
+				break;
+
+			default:
+				break;
+		}
+	}
+
+	virtual void OnTick()
+	{
+		CheckRedrawStationCoverage(this);
+	}
+};
 
 /** Widget definition of the build raod station window */
 static const Widget _rv_station_picker_widgets[] = {
@@ -961,17 +928,11 @@
 	WC_BUS_STATION, WC_BUILD_TOOLBAR,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 	_rv_station_picker_widgets,
-	RoadStationPickerWndProc
 };
 
 static void ShowRVStationPicker(RoadStopType rs)
 {
-	Window *w = new Window(&_rv_station_picker_desc);
-	if (w == NULL) return;
-
-	w->window_class = (rs == ROADSTOP_BUS) ? WC_BUS_STATION : WC_TRUCK_STATION;
-	w->widget[BRSW_CAPTION].data = _road_type_infos[_cur_roadtype].picker_title[rs];
-	for (uint i = BRSW_STATION_NE; i < BRSW_LT_OFF; i++) w->widget[i].tooltips = _road_type_infos[_cur_roadtype].picker_tooltip[rs];
+	new BuildRoadStationWindow(&_rv_station_picker_desc, rs);
 }
 
 void InitializeRoadGui()
--- a/src/roadveh_cmd.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/roadveh_cmd.cpp	Mon May 19 15:13:58 2008 +0000
@@ -281,7 +281,7 @@
 		VehiclePositionChanged(v);
 
 		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
-		RebuildVehicleLists();
+		InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
 		InvalidateWindow(WC_COMPANY, v->owner);
 		if (IsLocalPlayer())
 			InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the replace Road window
@@ -382,7 +382,7 @@
 	if (flags & DC_EXEC) {
 		// Invalidate depot
 		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
-		RebuildVehicleLists();
+		InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
 		InvalidateWindow(WC_COMPANY, v->owner);
 		DeleteWindowById(WC_VEHICLE_VIEW, v->index);
 		DeleteDepotHighlightOfVehicle(v);
@@ -575,7 +575,7 @@
 
 	DeleteWindowById(WC_VEHICLE_VIEW, v->index);
 
-	RebuildVehicleLists();
+	InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
 	InvalidateWindow(WC_COMPANY, v->owner);
 
 	if (IsTileType(v->tile, MP_STATION)) ClearCrashedStation(v);
@@ -667,7 +667,7 @@
 	AddNewsItem(
 		(pass == 1) ?
 			STR_9031_ROAD_VEHICLE_CRASH_DRIVER : STR_9032_ROAD_VEHICLE_CRASH_DIE,
-		NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ACCIDENT, DNC_NONE,
+		NS_ACCIDENT_VEHICLE,
 		v->index,
 		0
 	);
@@ -833,7 +833,7 @@
 			SetDParam(0, st->index);
 			AddNewsItem(
 				v->u.road.roadtype == ROADTYPE_ROAD ? STR_902F_CITIZENS_CELEBRATE_FIRST : STR_CITIZENS_CELEBRATE_FIRST_PASSENGER_TRAM,
-				NM_THIN, NF_VIEWPORT | NF_VEHICLE, (v->owner == _local_player) ? NT_ARRIVAL_PLAYER : NT_ARRIVAL_OTHER, DNC_NONE,
+				(v->owner == _local_player) ? NS_ARRIVAL_PLAYER : NS_ARRIVAL_OTHER,
 				v->index,
 				0);
 		}
@@ -844,7 +844,7 @@
 			SetDParam(0, st->index);
 			AddNewsItem(
 				v->u.road.roadtype == ROADTYPE_ROAD ? STR_9030_CITIZENS_CELEBRATE_FIRST : STR_CITIZENS_CELEBRATE_FIRST_CARGO_TRAM,
-				NM_THIN, NF_VIEWPORT | NF_VEHICLE, (v->owner == _local_player) ? NT_ARRIVAL_PLAYER : NT_ARRIVAL_OTHER, DNC_NONE,
+				(v->owner == _local_player) ? NS_ARRIVAL_PLAYER : NS_ARRIVAL_OTHER,
 				v->index,
 				0
 			);
@@ -973,7 +973,7 @@
 	/* Check if vehicle is in a road stop, depot, tunnel or bridge or not on a straight road */
 	if (v->u.road.state >= RVSB_IN_ROAD_STOP || !IsStraightRoadTrackdir((Trackdir)(v->u.road.state & RVSB_TRACKDIR_MASK))) return;
 
-	od.trackdir = DiagdirToDiagTrackdir(DirToDiagDir(v->direction));
+	od.trackdir = DiagDirToDiagTrackdir(DirToDiagDir(v->direction));
 
 	/* Are the current and the next tile suitable for overtaking?
 	 *  - Does the track continue along od.trackdir
@@ -1138,7 +1138,7 @@
 			NPFFindStationOrTileData fstd;
 
 			NPFFillWithOrderData(&fstd, v);
-			Trackdir trackdir = DiagdirToDiagTrackdir(enterdir);
+			Trackdir trackdir = DiagDirToDiagTrackdir(enterdir);
 			//debug("Finding path. Enterdir: %d, Trackdir: %d", enterdir, trackdir);
 
 			NPFFoundTargetData ftd = PerfNPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, true, &fstd, TRANSPORT_ROAD, v->u.road.compatible_roadtypes, v->owner, INVALID_RAILTYPES);
@@ -1328,7 +1328,7 @@
 		}
 
 		if (diag_dir == INVALID_DIAGDIR) return INVALID_TRACKDIR;
-		dir = DiagdirToDiagTrackdir(diag_dir);
+		dir = DiagDirToDiagTrackdir(diag_dir);
 	} else {
 		if (already_reversed && prev->tile != tile) {
 			/*
@@ -2122,7 +2122,7 @@
 			v->cargo_subtype = new_subtype;
 			InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
 			InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
-			RebuildVehicleLists();
+			InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
 		}
 
 		if (only_this) break;
--- a/src/saveload.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/saveload.cpp	Mon May 19 15:13:58 2008 +0000
@@ -30,6 +30,7 @@
 #include "core/endian_func.hpp"
 #include "vehicle_base.h"
 #include "autoreplace_base.h"
+#include "statusbar_gui.h"
 #include <list>
 
 #include "table/strings.h"
@@ -1493,7 +1494,7 @@
 	_fast_forward = 0;
 	if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
 
-	InvalidateWindowData(WC_STATUS_BAR, 0, true);
+	InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
 	_ts.saveinprogress = true;
 }
 
@@ -1504,7 +1505,7 @@
 	_fast_forward = _ts.ff_state;
 	if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
 
-	InvalidateWindowData(WC_STATUS_BAR, 0, false);
+	InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
 	_ts.saveinprogress = false;
 }
 
@@ -1533,7 +1534,7 @@
 	SaveFileDone();
 }
 
-static ThreadObject *save_thread;
+static ThreadObject *_save_thread;
 
 /** We have written the whole game into memory, _Savegame_pool, now find
  * and appropiate compressor and start writing to file.
@@ -1603,10 +1604,10 @@
 
 void WaitTillSaved()
 {
-	if (save_thread == NULL) return;
+	if (_save_thread == NULL) return;
 
-	save_thread->Join();
-	save_thread = NULL;
+	_save_thread->Join();
+	_save_thread = NULL;
 }
 
 /**
@@ -1678,7 +1679,7 @@
 
 			SaveFileStart();
 			if (_network_server ||
-						(save_thread = ThreadObject::New(&SaveFileToDiskThread, NULL)) == NULL) {
+						(_save_thread = ThreadObject::New(&SaveFileToDiskThread, NULL)) == NULL) {
 				if (!_network_server) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
 
 				SaveOrLoadResult result = SaveFileToDisk(false);
--- a/src/settings.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/settings.cpp	Mon May 19 15:13:58 2008 +0000
@@ -1141,6 +1141,12 @@
 	return 0;
 }
 
+static int32 InvalidateBuildIndustryWindow(int32 p1)
+{
+	InvalidateWindowData(WC_BUILD_INDUSTRY, 0);
+	return 0;
+}
+
 static int32 CloseSignalGUI(int32 p1)
 {
 	if (p1 == 0) {
@@ -1482,7 +1488,7 @@
 	/***************************************************************************/
 	/* Economy section of the GUI-configure patches window */
 	SDT_BOOL(Patches, inflation,                  0, 0,  true,            STR_CONFIG_PATCHES_INFLATION,        NULL),
-	 SDT_VAR(Patches, raw_industry_construction,SLE_UINT8,0,MS,0,0, 2, 0, STR_CONFIG_PATCHES_RAW_INDUSTRY_CONSTRUCTION_METHOD, NULL),
+	 SDT_VAR(Patches, raw_industry_construction,SLE_UINT8,0,MS,0,0, 2, 0, STR_CONFIG_PATCHES_RAW_INDUSTRY_CONSTRUCTION_METHOD, InvalidateBuildIndustryWindow),
 	SDT_BOOL(Patches, multiple_industry_per_town, 0, 0, false,            STR_CONFIG_PATCHES_MULTIPINDTOWN,    NULL),
 	SDT_BOOL(Patches, same_industry_close,        0, 0, false,            STR_CONFIG_PATCHES_SAMEINDCLOSE,     NULL),
 	SDT_BOOL(Patches, bribe,                      0, 0,  true,            STR_CONFIG_PATCHES_BRIBE,            NULL),
--- a/src/settings_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/settings_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -20,7 +20,6 @@
 #include "strings_func.h"
 #include "functions.h"
 #include "window_func.h"
-#include "vehicle_base.h"
 #include "core/alloc_func.hpp"
 #include "string_func.h"
 #include "gfx_func.h"
@@ -102,17 +101,6 @@
 	return i;
 }
 
-static inline bool RoadVehiclesAreBuilt()
-{
-	const Vehicle* v;
-
-	FOR_ALL_VEHICLES(v) {
-		if (v->type == VEH_ROAD) return true;
-	}
-	return false;
-}
-
-
 enum GameOptionsWidgets {
 	GAMEOPT_CURRENCY_BTN    =  4,
 	GAMEOPT_DISTANCE_BTN    =  6,
@@ -151,199 +139,178 @@
 	ShowDropDownList(w, list, sel, GAMEOPT_TOWNNAME_BTN);
 }
 
-/**
- * Update/redraw the languages dropdown
- * @param w   the window the dropdown belongs to
- */
-static void ShowLangDropdown(Window *w)
-{
-	typedef std::map<StringID, int, StringIDCompare> LangList;
-
-	/* Sort language names */
-	LangList langs;
-	for (int i = 0; i < _dynlang.num; i++) langs[SPECSTR_LANGUAGE_START + i] = i;
-
-	DropDownList *list = new DropDownList();
-	for (LangList::iterator it = langs.begin(); it != langs.end(); it++) {
-		list->push_back(new DropDownListStringItem((*it).first, (*it).second, false));
-	}
-
-	ShowDropDownList(w, list, _dynlang.curr, GAMEOPT_LANG_BTN);
-}
-
 static void ShowCustCurrency();
 
-static void GameOptionsWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			int i;
-			StringID str = STR_02BE_DEFAULT;
-
-			w->SetWidgetDisabledState(GAMEOPT_VEHICLENAME_SAVE, !(_vehicle_design_names & 1));
-			if (!w->IsWidgetDisabled(GAMEOPT_VEHICLENAME_SAVE)) str = STR_02BF_CUSTOM;
-			SetDParam(0, str);
-			SetDParam(1, _currency_specs[_opt_ptr->currency].name);
-			SetDParam(2, STR_UNITS_IMPERIAL + _opt_ptr->units);
-			SetDParam(3, STR_02E9_DRIVE_ON_LEFT + _opt_ptr->road_side);
-			SetDParam(4, TownName(_opt_ptr->town_name));
-			SetDParam(5, _autosave_dropdown[_opt_ptr->autosave]);
-			SetDParam(6, SPECSTR_LANGUAGE_START + _dynlang.curr);
-			i = GetCurRes();
-			SetDParam(7, i == _num_resolutions ? STR_RES_OTHER : SPECSTR_RESOLUTION_START + i);
-			SetDParam(8, SPECSTR_SCREENSHOT_START + _cur_screenshot_format);
-			w->SetWidgetLoweredState(GAMEOPT_FULLSCREEN, _fullscreen);
-
-			DrawWindowWidgets(w);
-			DrawString(20, 175, STR_OPTIONS_FULLSCREEN, TC_FROMSTRING); // fullscreen
-		} break;
-
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case GAMEOPT_CURRENCY_BTN: /* Setup currencies dropdown */
-					ShowDropDownMenu(w, BuildCurrencyDropdown(), _opt_ptr->currency, GAMEOPT_CURRENCY_BTN, _game_mode == GM_MENU ? 0 : ~GetMaskOfAllowedCurrencies(), 0);
-					break;
-
-				case GAMEOPT_DISTANCE_BTN: /* Setup distance unit dropdown */
-					ShowDropDownMenu(w, _units_dropdown, _opt_ptr->units, GAMEOPT_DISTANCE_BTN, 0, 0);
-					break;
-
-				case GAMEOPT_ROADSIDE_BTN: { /* Setup road-side dropdown */
-					int i = 0;
-
-					/* You can only change the drive side if you are in the menu or ingame with
-					 * no vehicles present. In a networking game only the server can change it */
-					if ((_game_mode != GM_MENU && RoadVehiclesAreBuilt()) || (_networking && !_network_server))
-						i = (-1) ^ (1 << _opt_ptr->road_side); // disable the other value
-
-					ShowDropDownMenu(w, _driveside_dropdown, _opt_ptr->road_side, GAMEOPT_ROADSIDE_BTN, i, 0);
-				} break;
-
-				case GAMEOPT_TOWNNAME_BTN: /* Setup townname dropdown */
-					ShowTownnameDropdown(w, _opt_ptr->town_name);
-					break;
-
-				case GAMEOPT_AUTOSAVE_BTN: /* Setup autosave dropdown */
-					ShowDropDownMenu(w, _autosave_dropdown, _opt_ptr->autosave, GAMEOPT_AUTOSAVE_BTN, 0, 0);
-					break;
-
-				case GAMEOPT_VEHICLENAME_BTN: /* Setup customized vehicle-names dropdown */
-					ShowDropDownMenu(w, _designnames_dropdown, (_vehicle_design_names & 1) ? 1 : 0, GAMEOPT_VEHICLENAME_BTN, (_vehicle_design_names & 2) ? 0 : 2, 0);
-					break;
-
-				case GAMEOPT_VEHICLENAME_SAVE: /* Save customized vehicle-names to disk */
-					break;  // not implemented
-
-				case GAMEOPT_LANG_BTN: /* Setup interface language dropdown */
-					ShowLangDropdown(w);
-					break;
-
-				case GAMEOPT_RESOLUTION_BTN: /* Setup resolution dropdown */
-					ShowDropDownMenu(w, BuildDynamicDropdown(SPECSTR_RESOLUTION_START, _num_resolutions), GetCurRes(), GAMEOPT_RESOLUTION_BTN, 0, 0);
-					break;
-
-				case GAMEOPT_FULLSCREEN: /* Click fullscreen on/off */
-					/* try to toggle full-screen on/off */
-					if (!ToggleFullScreen(!_fullscreen)) {
-						ShowErrorMessage(INVALID_STRING_ID, STR_FULLSCREEN_FAILED, 0, 0);
-					}
-					w->SetWidgetLoweredState(GAMEOPT_FULLSCREEN, _fullscreen);
-					w->SetDirty();
-					break;
-
-				case GAMEOPT_SCREENSHOT_BTN: /* Setup screenshot format dropdown */
-					ShowDropDownMenu(w, BuildDynamicDropdown(SPECSTR_SCREENSHOT_START, _num_screenshot_formats), _cur_screenshot_format, GAMEOPT_SCREENSHOT_BTN, 0, 0);
-					break;
-			}
-			break;
-
-		case WE_DROPDOWN_SELECT:
-			switch (e->we.dropdown.button) {
-				case GAMEOPT_VEHICLENAME_BTN: /* Vehicle design names */
-					if (e->we.dropdown.index == 0) {
-						DeleteCustomEngineNames();
-						MarkWholeScreenDirty();
-					} else if (!(_vehicle_design_names & 1)) {
-						LoadCustomEngineNames();
-						MarkWholeScreenDirty();
-					}
-					break;
-
-				case GAMEOPT_CURRENCY_BTN: /* Currency */
-					if (e->we.dropdown.index == CUSTOM_CURRENCY_ID) ShowCustCurrency();
-					_opt_ptr->currency = e->we.dropdown.index;
-					MarkWholeScreenDirty();
-					break;
-
-				case GAMEOPT_DISTANCE_BTN: /* Measuring units */
-					_opt_ptr->units = e->we.dropdown.index;
-					MarkWholeScreenDirty();
-					break;
-
-				case GAMEOPT_ROADSIDE_BTN: /* Road side */
-					if (_opt_ptr->road_side != e->we.dropdown.index) { // only change if setting changed
-						DoCommandP(0, e->we.dropdown.index, 0, NULL, CMD_SET_ROAD_DRIVE_SIDE | CMD_MSG(STR_00B4_CAN_T_DO_THIS));
-						MarkWholeScreenDirty();
-					}
-					break;
-
-				case GAMEOPT_TOWNNAME_BTN: /* Town names */
-					if (_game_mode == GM_MENU) {
-						_opt_ptr->town_name = e->we.dropdown.index;
-						InvalidateWindow(WC_GAME_OPTIONS, 0);
-					}
-					break;
-
-				case GAMEOPT_AUTOSAVE_BTN: /* Autosave options */
-					_opt.autosave = _opt_newgame.autosave = e->we.dropdown.index;
-					w->SetDirty();
-					break;
-
-				case GAMEOPT_LANG_BTN: /* Change interface language */
-					ReadLanguagePack(e->we.dropdown.index);
-					CheckForMissingGlyphsInLoadedLanguagePack();
-					UpdateAllStationVirtCoord();
-					UpdateAllWaypointSigns();
-					MarkWholeScreenDirty();
-					break;
-
-				case GAMEOPT_RESOLUTION_BTN: /* Change resolution */
-					if (e->we.dropdown.index < _num_resolutions && ChangeResInGame(_resolutions[e->we.dropdown.index][0], _resolutions[e->we.dropdown.index][1]))
-						w->SetDirty();
-					break;
-
-				case GAMEOPT_SCREENSHOT_BTN: /* Change screenshot format */
-					SetScreenshotFormat(e->we.dropdown.index);
-					w->SetDirty();
-					break;
-			}
-			break;
-
-		case WE_DESTROY:
-			DeleteWindowById(WC_CUSTOM_CURRENCY, 0);
-			break;
+struct GameOptionsWindow : Window {
+	GameOptionsWindow(const WindowDesc *desc) : Window(desc)
+	{
+		this->FindWindowPlacementAndResize(desc);
 	}
 
-}
+	~GameOptionsWindow()
+	{
+		DeleteWindowById(WC_CUSTOM_CURRENCY, 0);
+	}
 
-/** Change the side of the road vehicles drive on (server only).
- * @param tile unused
- * @param flags operation to perform
- * @param p1 the side of the road; 0 = left side and 1 = right side
- * @param p2 unused
- */
-CommandCost CmdSetRoadDriveSide(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
-	/* Check boundaries and you can only change this if NO vehicles have been built yet,
-	 * except in the intro-menu where of course it's always possible to do so. */
-	if (p1 > 1 || (_game_mode != GM_MENU && RoadVehiclesAreBuilt())) return CMD_ERROR;
+	virtual void OnPaint()
+	{
+		StringID str = STR_02BE_DEFAULT;
 
-	if (flags & DC_EXEC) {
-		_opt_ptr->road_side = p1;
-		InvalidateWindow(WC_GAME_OPTIONS, 0);
+		this->SetWidgetDisabledState(GAMEOPT_VEHICLENAME_SAVE, !(_vehicle_design_names & 1));
+		if (!this->IsWidgetDisabled(GAMEOPT_VEHICLENAME_SAVE)) str = STR_02BF_CUSTOM;
+		SetDParam(0, str);
+		SetDParam(1, _currency_specs[_opt_ptr->currency].name);
+		SetDParam(2, STR_UNITS_IMPERIAL + _opt_ptr->units);
+		SetDParam(3, STR_02E9_DRIVE_ON_LEFT + _opt_ptr->road_side);
+		SetDParam(4, TownName(_opt_ptr->town_name));
+		SetDParam(5, _autosave_dropdown[_opt_ptr->autosave]);
+		SetDParam(6, SPECSTR_LANGUAGE_START + _dynlang.curr);
+		int i = GetCurRes();
+		SetDParam(7, i == _num_resolutions ? STR_RES_OTHER : SPECSTR_RESOLUTION_START + i);
+		SetDParam(8, SPECSTR_SCREENSHOT_START + _cur_screenshot_format);
+		this->SetWidgetLoweredState(GAMEOPT_FULLSCREEN, _fullscreen);
+
+		this->DrawWidgets();
+		DrawString(20, 175, STR_OPTIONS_FULLSCREEN, TC_FROMSTRING); // fullscreen
 	}
-	return CommandCost();
-}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case GAMEOPT_CURRENCY_BTN: // Setup currencies dropdown
+				ShowDropDownMenu(this, BuildCurrencyDropdown(), _opt_ptr->currency, GAMEOPT_CURRENCY_BTN, _game_mode == GM_MENU ? 0 : ~GetMaskOfAllowedCurrencies(), 0);
+				break;
+
+			case GAMEOPT_DISTANCE_BTN: // Setup distance unit dropdown
+				ShowDropDownMenu(this, _units_dropdown, _opt_ptr->units, GAMEOPT_DISTANCE_BTN, 0, 0);
+				break;
+
+			case GAMEOPT_ROADSIDE_BTN: { // Setup road-side dropdown
+				int i = 0;
+				extern bool RoadVehiclesAreBuilt();
+
+				/* You can only change the drive side if you are in the menu or ingame with
+				 * no vehicles present. In a networking game only the server can change it */
+				if ((_game_mode != GM_MENU && RoadVehiclesAreBuilt()) || (_networking && !_network_server)) {
+					i = (-1) ^ (1 << _opt_ptr->road_side); // disable the other value
+				}
+
+				ShowDropDownMenu(this, _driveside_dropdown, _opt_ptr->road_side, GAMEOPT_ROADSIDE_BTN, i, 0);
+			} break;
+
+			case GAMEOPT_TOWNNAME_BTN: // Setup townname dropdown
+				ShowTownnameDropdown(this, _opt_ptr->town_name);
+				break;
+
+			case GAMEOPT_AUTOSAVE_BTN: // Setup autosave dropdown
+				ShowDropDownMenu(this, _autosave_dropdown, _opt_ptr->autosave, GAMEOPT_AUTOSAVE_BTN, 0, 0);
+				break;
+
+			case GAMEOPT_VEHICLENAME_BTN: // Setup customized vehicle-names dropdown
+				ShowDropDownMenu(this, _designnames_dropdown, (_vehicle_design_names & 1) ? 1 : 0, GAMEOPT_VEHICLENAME_BTN, (_vehicle_design_names & 2) ? 0 : 2, 0);
+				break;
+
+			case GAMEOPT_VEHICLENAME_SAVE: // Save customized vehicle-names to disk
+				break;  // not implemented
+
+			case GAMEOPT_LANG_BTN: { // Setup interface language dropdown
+				typedef std::map<StringID, int, StringIDCompare> LangList;
+
+				/* Sort language names */
+				LangList langs;
+				for (int i = 0; i < _dynlang.num; i++) langs[SPECSTR_LANGUAGE_START + i] = i;
+
+				DropDownList *list = new DropDownList();
+				for (LangList::iterator it = langs.begin(); it != langs.end(); it++) {
+					list->push_back(new DropDownListStringItem((*it).first, (*it).second, false));
+				}
+
+				ShowDropDownList(this, list, _dynlang.curr, GAMEOPT_LANG_BTN);
+			} break;
+
+			case GAMEOPT_RESOLUTION_BTN: // Setup resolution dropdown
+				ShowDropDownMenu(this, BuildDynamicDropdown(SPECSTR_RESOLUTION_START, _num_resolutions), GetCurRes(), GAMEOPT_RESOLUTION_BTN, 0, 0);
+				break;
+
+			case GAMEOPT_FULLSCREEN: // Click fullscreen on/off
+				/* try to toggle full-screen on/off */
+				if (!ToggleFullScreen(!_fullscreen)) {
+					ShowErrorMessage(INVALID_STRING_ID, STR_FULLSCREEN_FAILED, 0, 0);
+				}
+				this->SetWidgetLoweredState(GAMEOPT_FULLSCREEN, _fullscreen);
+				this->SetDirty();
+				break;
+
+			case GAMEOPT_SCREENSHOT_BTN: // Setup screenshot format dropdown
+				ShowDropDownMenu(this, BuildDynamicDropdown(SPECSTR_SCREENSHOT_START, _num_screenshot_formats), _cur_screenshot_format, GAMEOPT_SCREENSHOT_BTN, 0, 0);
+				break;
+		}
+	}
+
+	virtual void OnDropdownSelect(int widget, int index)
+	{
+		switch (widget) {
+			case GAMEOPT_VEHICLENAME_BTN: // Vehicle design names
+				if (index == 0) {
+					DeleteCustomEngineNames();
+					MarkWholeScreenDirty();
+				} else if (!(_vehicle_design_names & 1)) {
+					LoadCustomEngineNames();
+					MarkWholeScreenDirty();
+				}
+				break;
+
+			case GAMEOPT_CURRENCY_BTN: /* Currency */
+				if (index == CUSTOM_CURRENCY_ID) ShowCustCurrency();
+				_opt_ptr->currency = index;
+				MarkWholeScreenDirty();
+				break;
+
+			case GAMEOPT_DISTANCE_BTN: // Measuring units
+				_opt_ptr->units = index;
+				MarkWholeScreenDirty();
+				break;
+
+			case GAMEOPT_ROADSIDE_BTN: // Road side
+				if (_opt_ptr->road_side != index) { // only change if setting changed
+					DoCommandP(0, index, 0, NULL, CMD_SET_ROAD_DRIVE_SIDE | CMD_MSG(STR_00B4_CAN_T_DO_THIS));
+					MarkWholeScreenDirty();
+				}
+				break;
+
+			case GAMEOPT_TOWNNAME_BTN: // Town names
+				if (_game_mode == GM_MENU) {
+					_opt_ptr->town_name = index;
+					InvalidateWindow(WC_GAME_OPTIONS, 0);
+				}
+				break;
+
+			case GAMEOPT_AUTOSAVE_BTN: // Autosave options
+				_opt.autosave = _opt_newgame.autosave = index;
+				this->SetDirty();
+				break;
+
+			case GAMEOPT_LANG_BTN: // Change interface language
+				ReadLanguagePack(index);
+				CheckForMissingGlyphsInLoadedLanguagePack();
+				UpdateAllStationVirtCoord();
+				UpdateAllWaypointSigns();
+				MarkWholeScreenDirty();
+				break;
+
+			case GAMEOPT_RESOLUTION_BTN: // Change resolution
+				if (index < _num_resolutions && ChangeResInGame(_resolutions[index][0], _resolutions[index][1])) {
+					this->SetDirty();
+				}
+				break;
+
+			case GAMEOPT_SCREENSHOT_BTN: // Change screenshot format
+				SetScreenshotFormat(index);
+				this->SetDirty();
+				break;
+		}
+	}
+};
 
 static const Widget _game_options_widgets[] = {
 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                          STR_018B_CLOSE_WINDOW},
@@ -382,14 +349,13 @@
 	WC_GAME_OPTIONS, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
 	_game_options_widgets,
-	GameOptionsWndProc
 };
 
 
 void ShowGameOptions()
 {
 	DeleteWindowById(WC_GAME_OPTIONS, 0);
-	new Window(&_game_options_desc);
+	new GameOptionsWindow(&_game_options_desc);
 }
 
 struct GameSettingData {
@@ -478,194 +444,6 @@
 
 extern void StartupEconomy();
 
-enum {
-	GAMEDIFF_WND_TOP_OFFSET = 45,
-	GAMEDIFF_WND_ROWSIZE    = 9
-};
-
-/* Temporary holding place of values in the difficulty window until 'Save' is clicked */
-static GameOptions _opt_mod_temp;
-// 0x383E = (1 << 13) | (1 << 12) | (1 << 11) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1)
-#define DIFF_INGAME_DISABLED_BUTTONS 0x383E
-
-#define NO_SETTINGS_BUTTON 0xFF
-
-/** Carriage for the game settings window data */
-struct difficulty_d {
-	bool clicked_increase;
-	uint8 clicked_button;
-	uint8 timeout;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(difficulty_d));
-
-/* Names of the game difficulty settings window */
-enum GameDifficultyWidgets {
-	GDW_CLOSEBOX = 0,
-	GDW_CAPTION,
-	GDW_UPPER_BG,
-	GDW_LVL_EASY,
-	GDW_LVL_MEDIUM,
-	GDW_LVL_HARD,
-	GDW_LVL_CUSTOM,
-	GDW_HIGHSCORE,
-	GDW_SETTING_BG,
-	GDW_LOWER_BG,
-	GDW_ACCEPT,
-	GDW_CANCEL,
-};
-
-static void GameDifficultyWndProc(Window *w, WindowEvent *e)
-{
-	difficulty_d *diffic_d = &WP(w, difficulty_d);
-	switch (e->event) {
-		case WE_CREATE:
-			diffic_d->clicked_increase = false;
-			diffic_d->clicked_button = NO_SETTINGS_BUTTON;
-			diffic_d->timeout = 0;
-			/* Hide the closebox to make sure that the user aborts or confirms his changes */
-			w->HideWidget(GDW_CLOSEBOX);
-			w->widget[GDW_CAPTION].left = 0;
-			/* Setup disabled buttons when creating window
-			 * disable all other difficulty buttons during gameplay except for 'custom' */
-			w->SetWidgetsDisabledState(_game_mode == GM_NORMAL,
-				GDW_LVL_EASY,
-				GDW_LVL_MEDIUM,
-				GDW_LVL_HARD,
-				GDW_LVL_CUSTOM,
-				WIDGET_LIST_END);
-			w->SetWidgetDisabledState(GDW_HIGHSCORE, _game_mode == GM_EDITOR || _networking); // highscore chart in multiplayer
-			w->SetWidgetDisabledState(GDW_ACCEPT, _networking && !_network_server); // Save-button in multiplayer (and if client)
-			w->LowerWidget(GDW_LVL_EASY + _opt_mod_temp.diff_level);
-			break;
-
-		case WE_PAINT: {
-			DrawWindowWidgets(w);
-
-			/* XXX - Disabled buttons in normal gameplay or during muliplayer as non server.
-			 *       Bitshifted for each button to see if that bit is set. If it is set, the
-			 *       button is disabled */
-			uint32 disabled = 0;
-			if (_networking && !_network_server) {
-				disabled = MAX_UVALUE(uint32); // Disable all
-			} else if (_game_mode == GM_NORMAL) {
-				disabled = DIFF_INGAME_DISABLED_BUTTONS;
-			}
-
-			int value;
-			int y = GAMEDIFF_WND_TOP_OFFSET;
-			for (uint i = 0; i != GAME_DIFFICULTY_NUM; i++) {
-				const GameSettingData *gsd = &_game_setting_info[i];
-				value = ((GDType*)&_opt_mod_temp.diff)[i];
-
-				DrawArrowButtons(5, y, 3,
-						(diffic_d->clicked_button == i) ? 1 + !!diffic_d->clicked_increase : 0,
-						!(HasBit(disabled, i) || gsd->min == value),
-						!(HasBit(disabled, i) || gsd->max == value));
-
-				value += _game_setting_info[i].str;
-				if (i == 4) value *= 1000; // XXX - handle currency option
-				SetDParam(0, value);
-				DrawString(30, y, STR_6805_MAXIMUM_NO_COMPETITORS + i, TC_FROMSTRING);
-
-				y += GAMEDIFF_WND_ROWSIZE + 2; // space items apart a bit
-			}
-		} break;
-
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case GDW_SETTING_BG: { /* Difficulty settings widget, decode click */
-					/* Don't allow clients to make any changes */
-					if (_networking && !_network_server) return;
-
-					const int x = e->we.click.pt.x - 5;
-					if (!IsInsideMM(x, 0, 21)) // Button area
-						return;
-
-					const int y = e->we.click.pt.y - GAMEDIFF_WND_TOP_OFFSET;
-					if (y < 0) return;
-
-					/* Get button from Y coord. */
-					const uint8 btn = y / (GAMEDIFF_WND_ROWSIZE + 2);
-					if (btn >= GAME_DIFFICULTY_NUM || y % (GAMEDIFF_WND_ROWSIZE + 2) >= 9)
-						return;
-
-					/* Clicked disabled button? */
-					if (_game_mode == GM_NORMAL && HasBit(DIFF_INGAME_DISABLED_BUTTONS, btn))
-						return;
-
-					diffic_d->timeout = 5;
-
-					int16 val = ((GDType*)&_opt_mod_temp.diff)[btn];
-
-					const GameSettingData *info = &_game_setting_info[btn]; // get information about the difficulty setting
-					if (x >= 10) {
-						/* Increase button clicked */
-						val = min(val + info->step, info->max);
-						diffic_d->clicked_increase = true;
-					} else {
-						/* Decrease button clicked */
-						val -= info->step;
-						val = max(val,  info->min);
-						diffic_d->clicked_increase = false;
-					}
-					diffic_d->clicked_button = btn;
-
-					/* save value in temporary variable */
-					((GDType*)&_opt_mod_temp.diff)[btn] = val;
-					w->RaiseWidget(GDW_LVL_EASY + _opt_mod_temp.diff_level);
-					SetDifficultyLevel(3, &_opt_mod_temp); // set difficulty level to custom
-					w->LowerWidget(GDW_LVL_CUSTOM);
-					w->SetDirty();
-				} break;
-
-				case GDW_LVL_EASY:
-				case GDW_LVL_MEDIUM:
-				case GDW_LVL_HARD:
-				case GDW_LVL_CUSTOM:
-					/* temporarily change difficulty level */
-					w->RaiseWidget(GDW_LVL_EASY + _opt_mod_temp.diff_level);
-					SetDifficultyLevel(e->we.click.widget - GDW_LVL_EASY, &_opt_mod_temp);
-					w->LowerWidget(GDW_LVL_EASY + _opt_mod_temp.diff_level);
-					w->SetDirty();
-					break;
-
-				case GDW_HIGHSCORE: // Highscore Table
-					ShowHighscoreTable(_opt_mod_temp.diff_level, -1);
-					break;
-
-				case GDW_ACCEPT: { // Save button - save changes
-					GDType btn, val;
-					for (btn = 0; btn != GAME_DIFFICULTY_NUM; btn++) {
-						val = ((GDType*)&_opt_mod_temp.diff)[btn];
-						/* if setting has changed, change it */
-						if (val != ((GDType*)&_opt_ptr->diff)[btn])
-							DoCommandP(0, btn, val, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
-					}
-					DoCommandP(0, UINT_MAX, _opt_mod_temp.diff_level, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
-					delete w;
-					/* If we are in the editor, we should reload the economy.
-					 * This way when you load a game, the max loan and interest rate
-					 * are loaded correctly. */
-					if (_game_mode == GM_EDITOR) StartupEconomy();
-					break;
-				}
-
-				case GDW_CANCEL: // Cancel button - close window, abandon changes
-					delete w;
-					break;
-			} break;
-
-		case WE_TICK: /* Handle the visual 'clicking' of the buttons */
-			if (diffic_d->timeout != 0) {
-				diffic_d->timeout--;
-				if (diffic_d->timeout == 0) diffic_d->clicked_button = NO_SETTINGS_BUTTON;
-				w->SetDirty();
-			}
-			break;
-	}
-}
-#undef DIFF_INGAME_DISABLED_BUTTONS
-
 /* Widget definition for the game difficulty settings window */
 static const Widget _game_difficulty_widgets[] = {
 {   WWT_CLOSEBOX,   RESIZE_NONE,    10,     0,    10,     0,    13, STR_00C5,                     STR_018B_CLOSE_WINDOW},           // GDW_CLOSEBOX
@@ -689,16 +467,198 @@
 	WC_GAME_OPTIONS, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 	_game_difficulty_widgets,
-	GameDifficultyWndProc
+};
+
+struct GameDifficultyWindow : public Window {
+private:
+	bool clicked_increase;
+	uint8 clicked_button;
+	uint8 timeout;
+
+	/* Temporary holding place of values in the difficulty window until 'Save' is clicked */
+	GameOptions opt_mod_temp;
+
+	enum {
+		GAMEDIFF_WND_TOP_OFFSET = 45,
+		GAMEDIFF_WND_ROWSIZE    = 9,
+		// 0x383E = (1 << 13) | (1 << 12) | (1 << 11) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1)
+		DIFF_INGAME_DISABLED_BUTTONS = 0x383E,
+		NO_SETTINGS_BUTTON = 0xFF,
+	};
+
+	/* Names of the game difficulty settings window */
+	enum GameDifficultyWidgets {
+		GDW_CLOSEBOX = 0,
+		GDW_CAPTION,
+		GDW_UPPER_BG,
+		GDW_LVL_EASY,
+		GDW_LVL_MEDIUM,
+		GDW_LVL_HARD,
+		GDW_LVL_CUSTOM,
+		GDW_HIGHSCORE,
+		GDW_SETTING_BG,
+		GDW_LOWER_BG,
+		GDW_ACCEPT,
+		GDW_CANCEL,
+	};
+
+public:
+	GameDifficultyWindow() : Window(&_game_difficulty_desc)
+	{
+		/* Copy current settings (ingame or in intro) to temporary holding place
+		 * change that when setting stuff, copy back on clicking 'OK' */
+		this->opt_mod_temp = *_opt_ptr;
+		this->clicked_increase = false;
+		this->clicked_button = NO_SETTINGS_BUTTON;
+		this->timeout = 0;
+		/* Hide the closebox to make sure that the user aborts or confirms his changes */
+		this->HideWidget(GDW_CLOSEBOX);
+		this->widget[GDW_CAPTION].left = 0;
+		/* Setup disabled buttons when creating window
+		 * disable all other difficulty buttons during gameplay except for 'custom' */
+		this->SetWidgetsDisabledState(_game_mode == GM_NORMAL,
+			GDW_LVL_EASY,
+			GDW_LVL_MEDIUM,
+			GDW_LVL_HARD,
+			GDW_LVL_CUSTOM,
+			WIDGET_LIST_END);
+		this->SetWidgetDisabledState(GDW_HIGHSCORE, _game_mode == GM_EDITOR || _networking); // highscore chart in multiplayer
+		this->SetWidgetDisabledState(GDW_ACCEPT, _networking && !_network_server); // Save-button in multiplayer (and if client)
+		this->LowerWidget(GDW_LVL_EASY + this->opt_mod_temp.diff_level);
+		this->FindWindowPlacementAndResize(&_game_difficulty_desc);
+	}
+
+	virtual void OnPaint()
+	{
+		this->DrawWidgets();
+
+		/* XXX - Disabled buttons in normal gameplay or during muliplayer as non server.
+		 *       Bitshifted for each button to see if that bit is set. If it is set, the
+		 *       button is disabled */
+		uint32 disabled = 0;
+		if (_networking && !_network_server) {
+			disabled = MAX_UVALUE(uint32); // Disable all
+		} else if (_game_mode == GM_NORMAL) {
+			disabled = DIFF_INGAME_DISABLED_BUTTONS;
+		}
+
+		int value;
+		int y = GAMEDIFF_WND_TOP_OFFSET;
+		for (uint i = 0; i != GAME_DIFFICULTY_NUM; i++) {
+			const GameSettingData *gsd = &_game_setting_info[i];
+			value = ((GDType*)&this->opt_mod_temp.diff)[i];
+
+			DrawArrowButtons(5, y, 3,
+					(this->clicked_button == i) ? 1 + !!this->clicked_increase : 0,
+					!(HasBit(disabled, i) || gsd->min == value),
+					!(HasBit(disabled, i) || gsd->max == value));
+
+			value += _game_setting_info[i].str;
+			if (i == 4) value *= 1000; // XXX - handle currency option
+			SetDParam(0, value);
+			DrawString(30, y, STR_6805_MAXIMUM_NO_COMPETITORS + i, TC_FROMSTRING);
+
+			y += GAMEDIFF_WND_ROWSIZE + 2; // space items apart a bit
+		}
+	}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case GDW_SETTING_BG: { /* Difficulty settings widget, decode click */
+				/* Don't allow clients to make any changes */
+				if (_networking && !_network_server) return;
+
+				const int x = pt.x - 5;
+				if (!IsInsideMM(x, 0, 21)) return; // Button area
+
+				const int y = pt.y - GAMEDIFF_WND_TOP_OFFSET;
+				if (y < 0) return;
+
+				/* Get button from Y coord. */
+				const uint8 btn = y / (GAMEDIFF_WND_ROWSIZE + 2);
+				if (btn >= GAME_DIFFICULTY_NUM || y % (GAMEDIFF_WND_ROWSIZE + 2) >= 9) return;
+
+				/* Clicked disabled button? */
+				if (_game_mode == GM_NORMAL && HasBit((int)DIFF_INGAME_DISABLED_BUTTONS, btn)) return;
+
+				this->timeout = 5;
+
+				int16 val = ((GDType*)&this->opt_mod_temp.diff)[btn];
+
+				const GameSettingData *info = &_game_setting_info[btn]; // get information about the difficulty setting
+				if (x >= 10) {
+					/* Increase button clicked */
+					val = min(val + info->step, info->max);
+					this->clicked_increase = true;
+				} else {
+					/* Decrease button clicked */
+					val -= info->step;
+					val = max(val,  info->min);
+					this->clicked_increase = false;
+				}
+				this->clicked_button = btn;
+
+				/* save value in temporary variable */
+				((GDType*)&this->opt_mod_temp.diff)[btn] = val;
+				this->RaiseWidget(GDW_LVL_EASY + this->opt_mod_temp.diff_level);
+				SetDifficultyLevel(3, &this->opt_mod_temp); // set difficulty level to custom
+				this->LowerWidget(GDW_LVL_CUSTOM);
+				this->SetDirty();
+			} break;
+
+			case GDW_LVL_EASY:
+			case GDW_LVL_MEDIUM:
+			case GDW_LVL_HARD:
+			case GDW_LVL_CUSTOM:
+				/* temporarily change difficulty level */
+				this->RaiseWidget(GDW_LVL_EASY + this->opt_mod_temp.diff_level);
+				SetDifficultyLevel(widget - GDW_LVL_EASY, &this->opt_mod_temp);
+				this->LowerWidget(GDW_LVL_EASY + this->opt_mod_temp.diff_level);
+				this->SetDirty();
+				break;
+
+			case GDW_HIGHSCORE: // Highscore Table
+				ShowHighscoreTable(this->opt_mod_temp.diff_level, -1);
+				break;
+
+			case GDW_ACCEPT: { // Save button - save changes
+				GDType btn, val;
+				for (btn = 0; btn != GAME_DIFFICULTY_NUM; btn++) {
+					val = ((GDType*)&this->opt_mod_temp.diff)[btn];
+					/* if setting has changed, change it */
+					if (val != ((GDType*)&_opt_ptr->diff)[btn])
+						DoCommandP(0, btn, val, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
+				}
+				DoCommandP(0, UINT_MAX, this->opt_mod_temp.diff_level, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
+				delete this;
+				/* If we are in the editor, we should reload the economy.
+				 * This way when you load a game, the max loan and interest rate
+				 * are loaded correctly. */
+				if (_game_mode == GM_EDITOR) StartupEconomy();
+				break;
+			}
+
+			case GDW_CANCEL: // Cancel button - close window, abandon changes
+				delete this;
+				break;
+		}
+	}
+
+	virtual void OnTick()
+	{
+		if (this->timeout != 0) {
+			this->timeout--;
+			if (this->timeout == 0) this->clicked_button = NO_SETTINGS_BUTTON;
+			this->SetDirty();
+		}
+	}
 };
 
 void ShowGameDifficulty()
 {
 	DeleteWindowById(WC_GAME_OPTIONS, 0);
-	/* Copy current settings (ingame or in intro) to temporary holding place
-	 * change that when setting stuff, copy back on clicking 'OK' */
-	_opt_mod_temp = *_opt_ptr;
-	new Window(&_game_difficulty_desc);
+	new GameDifficultyWindow();
 }
 
 static const char *_patches_ui[] = {
@@ -854,228 +814,232 @@
 	PATCHSEL_COMPETITORS
 };
 
-/** The main patches window. Shows a number of categories on top and
- * a selection of patches in that category.
- * Uses WP(w, def_d) macro - data_1, data_2, data_3 */
-static void PatchesSelectionWndProc(Window *w, WindowEvent *e)
-{
+struct PatchesSelectionWindow : Window {
 	static Patches *patches_ptr;
-	static int patches_max = 0;
-
-	switch (e->event) {
-		case WE_CREATE: {
-			static bool first_time = true;
-
-			patches_ptr = (_game_mode == GM_MENU) ? &_patches_newgame : &_patches;
-
-			/* Build up the dynamic settings-array only once per OpenTTD session */
-			if (first_time) {
-				PatchPage *page;
-				for (page = &_patches_page[0]; page != endof(_patches_page); page++) {
-					uint i;
-
-					if (patches_max < page->num) patches_max = page->num;
-
-					page->entries = MallocT<PatchEntry>(page->num);
-					for (i = 0; i != page->num; i++) {
-						uint index;
-						const SettingDesc *sd = GetPatchFromName(page->names[i], &index);
-						assert(sd != NULL);
-
-						page->entries[i].setting = sd;
-						page->entries[i].index = index;
-					}
-				}
-				first_time = false;
-			}
-
-			/* Resize the window to fit the largest patch tab */
-			ResizeWindowForWidget(w, PATCHSEL_OPTIONSPANEL, 0, patches_max * 11);
-
-			/* Recentre the window for the new size */
-			w->top = w->top - (patches_max * 11) / 2;
-
-			w->LowerWidget(4);
-		} break;
+	static int patches_max;
 
-		case WE_PAINT: {
-			int x, y;
-			const PatchPage *page = &_patches_page[WP(w, def_d).data_1];
-			uint i;
-
-			/* Set up selected category */
-			DrawWindowWidgets(w);
-
-			x = 5;
-			y = 47;
-			for (i = 0; i != page->num; i++) {
-				const SettingDesc *sd = page->entries[i].setting;
-				const SettingDescBase *sdb = &sd->desc;
-				const void *var = GetVariableAddress(patches_ptr, &sd->save);
-				bool editable = true;
-				bool disabled = false;
-
-				// We do not allow changes of some items when we are a client in a networkgame
-				if (!(sd->save.conv & SLF_NETWORK_NO) && _networking && !_network_server) editable = false;
-				if ((sdb->flags & SGF_NETWORK_ONLY) && !_networking) editable = false;
-				if ((sdb->flags & SGF_NO_NETWORK) && _networking) editable = false;
+	int page;
+	int entry;
+	int click;
 
-				if (sdb->cmd == SDT_BOOLX) {
-					static const int _bool_ctabs[2][2] = {{9, 4}, {7, 6}};
-					/* Draw checkbox for boolean-value either on/off */
-					bool on = (*(bool*)var);
-
-					DrawFrameRect(x, y, x + 19, y + 8, _bool_ctabs[!!on][!!editable], on ? FR_LOWERED : FR_NONE);
-					SetDParam(0, on ? STR_CONFIG_PATCHES_ON : STR_CONFIG_PATCHES_OFF);
-				} else {
-					int32 value;
-
-					value = (int32)ReadValue(var, sd->save.conv);
+	PatchesSelectionWindow(const WindowDesc *desc) : Window(desc)
+	{
+		static bool first_time = true;
 
-					/* Draw [<][>] boxes for settings of an integer-type */
-					DrawArrowButtons(x, y, 3, WP(w, def_d).data_2 - (i * 2), (editable && value != sdb->min), (editable && value != sdb->max));
+		patches_ptr = (_game_mode == GM_MENU) ? &_patches_newgame : &_patches;
 
-					disabled = (value == 0) && (sdb->flags & SGF_0ISDISABLED);
-					if (disabled) {
-						SetDParam(0, STR_CONFIG_PATCHES_DISABLED);
+		/* Build up the dynamic settings-array only once per OpenTTD session */
+		if (first_time) {
+			PatchPage *page;
+			for (page = &_patches_page[0]; page != endof(_patches_page); page++) {
+				uint i;
+
+				if (patches_max < page->num) patches_max = page->num;
+
+				page->entries = MallocT<PatchEntry>(page->num);
+				for (i = 0; i != page->num; i++) {
+					uint index;
+					const SettingDesc *sd = GetPatchFromName(page->names[i], &index);
+					assert(sd != NULL);
+
+					page->entries[i].setting = sd;
+					page->entries[i].index = index;
+				}
+			}
+			first_time = false;
+		}
+
+		/* Resize the window to fit the largest patch tab */
+		ResizeWindowForWidget(this, PATCHSEL_OPTIONSPANEL, 0, patches_max * 11);
+
+		/* Recentre the window for the new size */
+		this->top = this->top - (patches_max * 11) / 2;
+
+		this->LowerWidget(4);
+
+		this->FindWindowPlacementAndResize(desc);
+	}
+
+	virtual void OnPaint()
+	{
+		int x, y;
+		const PatchPage *page = &_patches_page[this->page];
+		uint i;
+
+		/* Set up selected category */
+		this->DrawWidgets();
+
+		x = 5;
+		y = 47;
+		for (i = 0; i != page->num; i++) {
+			const SettingDesc *sd = page->entries[i].setting;
+			const SettingDescBase *sdb = &sd->desc;
+			const void *var = GetVariableAddress(patches_ptr, &sd->save);
+			bool editable = true;
+			bool disabled = false;
+
+			// We do not allow changes of some items when we are a client in a networkgame
+			if (!(sd->save.conv & SLF_NETWORK_NO) && _networking && !_network_server) editable = false;
+			if ((sdb->flags & SGF_NETWORK_ONLY) && !_networking) editable = false;
+			if ((sdb->flags & SGF_NO_NETWORK) && _networking) editable = false;
+
+			if (sdb->cmd == SDT_BOOLX) {
+				static const int _bool_ctabs[2][2] = {{9, 4}, {7, 6}};
+				/* Draw checkbox for boolean-value either on/off */
+				bool on = (*(bool*)var);
+
+				DrawFrameRect(x, y, x + 19, y + 8, _bool_ctabs[!!on][!!editable], on ? FR_LOWERED : FR_NONE);
+				SetDParam(0, on ? STR_CONFIG_PATCHES_ON : STR_CONFIG_PATCHES_OFF);
+			} else {
+				int32 value;
+
+				value = (int32)ReadValue(var, sd->save.conv);
+
+				/* Draw [<][>] boxes for settings of an integer-type */
+				DrawArrowButtons(x, y, 3, this->click - (i * 2), (editable && value != sdb->min), (editable && value != sdb->max));
+
+				disabled = (value == 0) && (sdb->flags & SGF_0ISDISABLED);
+				if (disabled) {
+					SetDParam(0, STR_CONFIG_PATCHES_DISABLED);
+				} else {
+					if (sdb->flags & SGF_CURRENCY) {
+						SetDParam(0, STR_CONFIG_PATCHES_CURRENCY);
+					} else if (sdb->flags & SGF_MULTISTRING) {
+						SetDParam(0, sdb->str + value + 1);
 					} else {
-						if (sdb->flags & SGF_CURRENCY) {
-							SetDParam(0, STR_CONFIG_PATCHES_CURRENCY);
-						} else if (sdb->flags & SGF_MULTISTRING) {
-							SetDParam(0, sdb->str + value + 1);
+						SetDParam(0, (sdb->flags & SGF_NOCOMMA) ? STR_CONFIG_PATCHES_INT32 : STR_7024);
+					}
+					SetDParam(1, value);
+				}
+			}
+			DrawString(30, y, (sdb->str) + disabled, TC_FROMSTRING);
+			y += 11;
+		}
+	}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case PATCHSEL_OPTIONSPANEL: {
+				const PatchPage *page = &_patches_page[this->page];
+				const SettingDesc *sd;
+				void *var;
+				int32 value;
+				int x, y;
+				byte btn;
+
+				y = pt.y - 46 - 1;
+				if (y < 0) return;
+
+				x = pt.x - 5;
+				if (x < 0) return;
+
+				btn = y / 11;
+				if (y % 11 > 9) return;
+				if (btn >= page->num) return;
+
+				sd = page->entries[btn].setting;
+
+				/* return if action is only active in network, or only settable by server */
+				if (!(sd->save.conv & SLF_NETWORK_NO) && _networking && !_network_server) return;
+				if ((sd->desc.flags & SGF_NETWORK_ONLY) && !_networking) return;
+				if ((sd->desc.flags & SGF_NO_NETWORK) && _networking) return;
+
+				var = GetVariableAddress(patches_ptr, &sd->save);
+				value = (int32)ReadValue(var, sd->save.conv);
+
+				/* clicked on the icon on the left side. Either scroller or bool on/off */
+				if (x < 21) {
+					const SettingDescBase *sdb = &sd->desc;
+					int32 oldvalue = value;
+
+					switch (sdb->cmd) {
+					case SDT_BOOLX: value ^= 1; break;
+					case SDT_NUMX: {
+						/* Add a dynamic step-size to the scroller. In a maximum of
+							* 50-steps you should be able to get from min to max,
+							* unless specified otherwise in the 'interval' variable
+							* of the current patch. */
+						uint32 step = (sdb->interval == 0) ? ((sdb->max - sdb->min) / 50) : sdb->interval;
+						if (step == 0) step = 1;
+
+						// don't allow too fast scrolling
+						if ((this->flags4 & WF_TIMEOUT_MASK) > 2 << WF_TIMEOUT_SHL) {
+							_left_button_clicked = false;
+							return;
+						}
+
+						/* Increase or decrease the value and clamp it to extremes */
+						if (x >= 10) {
+							value += step;
+							if (value > sdb->max) value = sdb->max;
 						} else {
-							SetDParam(0, (sdb->flags & SGF_NOCOMMA) ? STR_CONFIG_PATCHES_INT32 : STR_7024);
+							value -= step;
+							if (value < sdb->min) value = (sdb->flags & SGF_0ISDISABLED) ? 0 : sdb->min;
 						}
-						SetDParam(1, value);
+
+						/* Set up scroller timeout for numeric values */
+						if (value != oldvalue && !(sd->desc.flags & SGF_MULTISTRING)) {
+							this->click = btn * 2 + 1 + ((x >= 10) ? 1 : 0);
+							this->flags4 |= 5 << WF_TIMEOUT_SHL;
+							_left_button_clicked = false;
+						}
+					} break;
+					default: NOT_REACHED();
+					}
+
+					if (value != oldvalue) {
+						SetPatchValue(page->entries[btn].index, patches_ptr, value);
+						this->SetDirty();
+					}
+				} else {
+					/* only open editbox for types that its sensible for */
+					if (sd->desc.cmd != SDT_BOOLX && !(sd->desc.flags & SGF_MULTISTRING)) {
+						/* Show the correct currency-translated value */
+						if (sd->desc.flags & SGF_CURRENCY) value *= _currency->rate;
+
+						this->entry = btn;
+						SetDParam(0, value);
+						ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_CONFIG_PATCHES_QUERY_CAPT, 10, 100, this, CS_NUMERAL);
 					}
 				}
-				DrawString(30, y, (sdb->str) + disabled, TC_FROMSTRING);
-				y += 11;
-			}
-		} break;
-
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case PATCHSEL_OPTIONSPANEL: {
-					const PatchPage *page = &_patches_page[WP(w, def_d).data_1];
-					const SettingDesc *sd;
-					void *var;
-					int32 value;
-					int x, y;
-					byte btn;
-
-					y = e->we.click.pt.y - 46 - 1;
-					if (y < 0) return;
-
-					x = e->we.click.pt.x - 5;
-					if (x < 0) return;
-
-					btn = y / 11;
-					if (y % 11 > 9) return;
-					if (btn >= page->num) return;
-
-					sd = page->entries[btn].setting;
-
-					/* return if action is only active in network, or only settable by server */
-					if (!(sd->save.conv & SLF_NETWORK_NO) && _networking && !_network_server) return;
-					if ((sd->desc.flags & SGF_NETWORK_ONLY) && !_networking) return;
-					if ((sd->desc.flags & SGF_NO_NETWORK) && _networking) return;
-
-					var = GetVariableAddress(patches_ptr, &sd->save);
-					value = (int32)ReadValue(var, sd->save.conv);
-
-					/* clicked on the icon on the left side. Either scroller or bool on/off */
-					if (x < 21) {
-						const SettingDescBase *sdb = &sd->desc;
-						int32 oldvalue = value;
-
-						switch (sdb->cmd) {
-						case SDT_BOOLX: value ^= 1; break;
-						case SDT_NUMX: {
-							/* Add a dynamic step-size to the scroller. In a maximum of
-							 * 50-steps you should be able to get from min to max,
-							 * unless specified otherwise in the 'interval' variable
-							 * of the current patch. */
-							uint32 step = (sdb->interval == 0) ? ((sdb->max - sdb->min) / 50) : sdb->interval;
-							if (step == 0) step = 1;
-
-							// don't allow too fast scrolling
-							if ((w->flags4 & WF_TIMEOUT_MASK) > 2 << WF_TIMEOUT_SHL) {
-								_left_button_clicked = false;
-								return;
-							}
+			} break;
 
-							/* Increase or decrease the value and clamp it to extremes */
-							if (x >= 10) {
-								value += step;
-								if (value > sdb->max) value = sdb->max;
-							} else {
-								value -= step;
-								if (value < sdb->min) value = (sdb->flags & SGF_0ISDISABLED) ? 0 : sdb->min;
-							}
-
-							/* Set up scroller timeout for numeric values */
-							if (value != oldvalue && !(sd->desc.flags & SGF_MULTISTRING)) {
-								WP(w, def_d).data_2 = btn * 2 + 1 + ((x >= 10) ? 1 : 0);
-								w->flags4 |= 5 << WF_TIMEOUT_SHL;
-								_left_button_clicked = false;
-							}
-						} break;
-						default: NOT_REACHED();
-						}
-
-						if (value != oldvalue) {
-							SetPatchValue(page->entries[btn].index, patches_ptr, value);
-							w->SetDirty();
-						}
-					} else {
-						/* only open editbox for types that its sensible for */
-						if (sd->desc.cmd != SDT_BOOLX && !(sd->desc.flags & SGF_MULTISTRING)) {
-							/* Show the correct currency-translated value */
-							if (sd->desc.flags & SGF_CURRENCY) value *= _currency->rate;
+			case PATCHSEL_INTERFACE: case PATCHSEL_CONSTRUCTION: case PATCHSEL_VEHICLES:
+			case PATCHSEL_STATIONS:  case PATCHSEL_ECONOMY:      case PATCHSEL_COMPETITORS:
+				this->RaiseWidget(this->page + PATCHSEL_INTERFACE);
+				this->page = widget - PATCHSEL_INTERFACE;
+				this->LowerWidget(this->page + PATCHSEL_INTERFACE);
+				DeleteWindowById(WC_QUERY_STRING, 0);
+				this->SetDirty();
+				break;
+		}
+	}
 
-							WP(w, def_d).data_3 = btn;
-							SetDParam(0, value);
-							ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_CONFIG_PATCHES_QUERY_CAPT, 10, 100, w, CS_NUMERAL);
-						}
-					}
-				} break;
-
-				case PATCHSEL_INTERFACE: case PATCHSEL_CONSTRUCTION: case PATCHSEL_VEHICLES:
-				case PATCHSEL_STATIONS:  case PATCHSEL_ECONOMY:      case PATCHSEL_COMPETITORS:
-					w->RaiseWidget(WP(w, def_d).data_1 + PATCHSEL_INTERFACE);
-					WP(w, def_d).data_1 = e->we.click.widget - PATCHSEL_INTERFACE;
-					w->LowerWidget(WP(w, def_d).data_1 + PATCHSEL_INTERFACE);
-					DeleteWindowById(WC_QUERY_STRING, 0);
-					w->SetDirty();
-					break;
-			}
-			break;
+	virtual void OnTimeout()
+	{
+		this->click = 0;
+		this->SetDirty();
+	}
 
-		case WE_TIMEOUT:
-			WP(w, def_d).data_2 = 0;
-			w->SetDirty();
-			break;
-
-		case WE_ON_EDIT_TEXT:
-			if (!StrEmpty(e->we.edittext.str)) {
-				const PatchEntry *pe = &_patches_page[WP(w, def_d).data_1].entries[WP(w, def_d).data_3];
-				const SettingDesc *sd = pe->setting;
-				int32 value = atoi(e->we.edittext.str);
+	virtual void OnQueryTextFinished(char *str)
+	{
+		if (!StrEmpty(str)) {
+			const PatchEntry *pe = &_patches_page[this->page].entries[this->entry];
+			const SettingDesc *sd = pe->setting;
+			int32 value = atoi(str);
 
-				/* Save the correct currency-translated value */
-				if (sd->desc.flags & SGF_CURRENCY) value /= _currency->rate;
+			/* Save the correct currency-translated value */
+			if (sd->desc.flags & SGF_CURRENCY) value /= _currency->rate;
 
-				SetPatchValue(pe->index, patches_ptr, value);
-				w->SetDirty();
-			}
-			break;
+			SetPatchValue(pe->index, patches_ptr, value);
+			this->SetDirty();
+		}
+	}
+};
 
-		case WE_DESTROY:
-			DeleteWindowById(WC_QUERY_STRING, 0);
-			break;
-	}
-}
+Patches *PatchesSelectionWindow::patches_ptr = NULL;
+int PatchesSelectionWindow::patches_max = 0;
 
 static const Widget _patches_selection_widgets[] = {
 {   WWT_CLOSEBOX,   RESIZE_NONE,    10,     0,    10,     0,    13, STR_00C5,                        STR_018B_CLOSE_WINDOW},
@@ -1097,13 +1061,12 @@
 	WC_GAME_OPTIONS, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 	_patches_selection_widgets,
-	PatchesSelectionWndProc,
 };
 
 void ShowPatchesSelection()
 {
 	DeleteWindowById(WC_GAME_OPTIONS, 0);
-	new Window(&_patches_selection_desc);
+	new PatchesSelectionWindow(&_patches_selection_desc);
 }
 
 
@@ -1143,176 +1106,178 @@
 	CUSTCURR_TO_EURO,
 };
 
-static char _str_separator[2];
-
-static void CustCurrencyWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			int x;
-			int y = 20;
-			int clk = WP(w, def_d).data_1;
-			DrawWindowWidgets(w);
-
-			/* exchange rate */
-			DrawArrowButtons(10, y, 3, GB(clk, 0, 2), true, true);
-			SetDParam(0, 1);
-			SetDParam(1, 1);
-			DrawString(35, y + 1, STR_CURRENCY_EXCHANGE_RATE, TC_FROMSTRING);
-			y += 12;
-
-			/* separator */
-			DrawFrameRect(10, y + 1, 29, y + 9, 0, GB(clk, 2, 2) ? FR_LOWERED : FR_NONE);
-			x = DrawString(35, y + 1, STR_CURRENCY_SEPARATOR, TC_FROMSTRING);
-			DoDrawString(_str_separator, x + 4, y + 1, TC_ORANGE);
-			y += 12;
-
-			/* prefix */
-			DrawFrameRect(10, y + 1, 29, y + 9, 0, GB(clk, 4, 2) ? FR_LOWERED : FR_NONE);
-			x = DrawString(35, y + 1, STR_CURRENCY_PREFIX, TC_FROMSTRING);
-			DoDrawString(_custom_currency.prefix, x + 4, y + 1, TC_ORANGE);
-			y += 12;
-
-			/* suffix */
-			DrawFrameRect(10, y + 1, 29, y + 9, 0, GB(clk, 6, 2) ? FR_LOWERED : FR_NONE);
-			x = DrawString(35, y + 1, STR_CURRENCY_SUFFIX, TC_FROMSTRING);
-			DoDrawString(_custom_currency.suffix, x + 4, y + 1, TC_ORANGE);
-			y += 12;
-
-			/* switch to euro */
-			DrawArrowButtons(10, y, 3, GB(clk, 8, 2), true, true);
-			SetDParam(0, _custom_currency.to_euro);
-			DrawString(35, y + 1, (_custom_currency.to_euro != CF_NOEURO) ? STR_CURRENCY_SWITCH_TO_EURO : STR_CURRENCY_SWITCH_TO_EURO_NEVER, TC_FROMSTRING);
-			y += 12;
+struct CustomCurrencyWindow : Window {
+	char separator[2];
+	int click;
+	int query_widget;
 
-			/* Preview */
-			y += 12;
-			SetDParam(0, 10000);
-			DrawString(35, y + 1, STR_CURRENCY_PREVIEW, TC_FROMSTRING);
-		} break;
-
-		case WE_CLICK: {
-			int line = (e->we.click.pt.y - 20) / 12;
-			int len = 0;
-			int x = e->we.click.pt.x;
-			StringID str = 0;
-			CharSetFilter afilter = CS_ALPHANUMERAL;
+	CustomCurrencyWindow(const WindowDesc *desc) : Window(desc)
+	{
+		this->separator[0] = _custom_currency.separator;
+		this->separator[1] = '\0';
+		this->FindWindowPlacementAndResize(desc);
+	}
 
-			switch (line) {
-				case CUSTCURR_EXCHANGERATE:
-					if (IsInsideMM(x, 10, 30)) { // clicked buttons
-						if (x < 20) {
-							if (_custom_currency.rate > 1) _custom_currency.rate--;
-							WP(w, def_d).data_1 = 1 << (line * 2 + 0);
-						} else {
-							if (_custom_currency.rate < 5000) _custom_currency.rate++;
-							WP(w, def_d).data_1 = 1 << (line * 2 + 1);
-						}
-					} else { // enter text
-						SetDParam(0, _custom_currency.rate);
-						str = STR_CONFIG_PATCHES_INT32;
-						len = 4;
-						afilter = CS_NUMERAL;
-					}
-					break;
+	virtual void OnPaint()
+	{
+		int x;
+		int y = 20;
+		this->DrawWidgets();
 
-				case CUSTCURR_SEPARATOR:
-					if (IsInsideMM(x, 10, 30)) { // clicked button
-						WP(w, def_d).data_1 = 1 << (line * 2 + 1);
-					}
-					str = BindCString(_str_separator);
-					len = 1;
-					break;
+		/* exchange rate */
+		DrawArrowButtons(10, y, 3, GB(this->click, 0, 2), true, true);
+		SetDParam(0, 1);
+		SetDParam(1, 1);
+		DrawString(35, y + 1, STR_CURRENCY_EXCHANGE_RATE, TC_FROMSTRING);
+		y += 12;
 
-				case CUSTCURR_PREFIX:
-					if (IsInsideMM(x, 10, 30)) { // clicked button
-						WP(w, def_d).data_1 = 1 << (line * 2 + 1);
+		/* separator */
+		DrawFrameRect(10, y + 1, 29, y + 9, 0, GB(this->click, 2, 2) ? FR_LOWERED : FR_NONE);
+		x = DrawString(35, y + 1, STR_CURRENCY_SEPARATOR, TC_FROMSTRING);
+		DoDrawString(this->separator, x + 4, y + 1, TC_ORANGE);
+		y += 12;
+
+		/* prefix */
+		DrawFrameRect(10, y + 1, 29, y + 9, 0, GB(this->click, 4, 2) ? FR_LOWERED : FR_NONE);
+		x = DrawString(35, y + 1, STR_CURRENCY_PREFIX, TC_FROMSTRING);
+		DoDrawString(_custom_currency.prefix, x + 4, y + 1, TC_ORANGE);
+		y += 12;
+
+		/* suffix */
+		DrawFrameRect(10, y + 1, 29, y + 9, 0, GB(this->click, 6, 2) ? FR_LOWERED : FR_NONE);
+		x = DrawString(35, y + 1, STR_CURRENCY_SUFFIX, TC_FROMSTRING);
+		DoDrawString(_custom_currency.suffix, x + 4, y + 1, TC_ORANGE);
+		y += 12;
+
+		/* switch to euro */
+		DrawArrowButtons(10, y, 3, GB(this->click, 8, 2), true, true);
+		SetDParam(0, _custom_currency.to_euro);
+		DrawString(35, y + 1, (_custom_currency.to_euro != CF_NOEURO) ? STR_CURRENCY_SWITCH_TO_EURO : STR_CURRENCY_SWITCH_TO_EURO_NEVER, TC_FROMSTRING);
+		y += 12;
+
+		/* Preview */
+		y += 12;
+		SetDParam(0, 10000);
+		DrawString(35, y + 1, STR_CURRENCY_PREVIEW, TC_FROMSTRING);
+	}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		int line = (pt.y - 20) / 12;
+		int len = 0;
+		int x = pt.x;
+		StringID str = 0;
+		CharSetFilter afilter = CS_ALPHANUMERAL;
+
+		switch (line) {
+			case CUSTCURR_EXCHANGERATE:
+				if (IsInsideMM(x, 10, 30)) { // clicked buttons
+					if (x < 20) {
+						if (_custom_currency.rate > 1) _custom_currency.rate--;
+						this->click = 1 << (line * 2 + 0);
+					} else {
+						if (_custom_currency.rate < 5000) _custom_currency.rate++;
+						this->click = 1 << (line * 2 + 1);
 					}
-					str = BindCString(_custom_currency.prefix);
-					len = 12;
-					break;
-
-				case CUSTCURR_SUFFIX:
-					if (IsInsideMM(x, 10, 30)) { // clicked button
-						WP(w, def_d).data_1 = 1 << (line * 2 + 1);
-					}
-					str = BindCString(_custom_currency.suffix);
-					len = 12;
-					break;
-
-				case CUSTCURR_TO_EURO:
-					if (IsInsideMM(x, 10, 30)) { // clicked buttons
-						if (x < 20) {
-							_custom_currency.to_euro = (_custom_currency.to_euro <= 2000) ?
-								CF_NOEURO : _custom_currency.to_euro - 1;
-							WP(w, def_d).data_1 = 1 << (line * 2 + 0);
-						} else {
-							_custom_currency.to_euro =
-								Clamp(_custom_currency.to_euro + 1, 2000, MAX_YEAR);
-							WP(w, def_d).data_1 = 1 << (line * 2 + 1);
-						}
-					} else { // enter text
-						SetDParam(0, _custom_currency.to_euro);
-						str = STR_CONFIG_PATCHES_INT32;
-						len = 4;
-						afilter = CS_NUMERAL;
-					}
-					break;
-			}
-
-			if (len != 0) {
-				WP(w, def_d).data_2 = line;
-				ShowQueryString(str, STR_CURRENCY_CHANGE_PARAMETER, len + 1, 250, w, afilter);
-			}
-
-			w->flags4 |= 5 << WF_TIMEOUT_SHL;
-			w->SetDirty();
-		} break;
+				} else { // enter text
+					SetDParam(0, _custom_currency.rate);
+					str = STR_CONFIG_PATCHES_INT32;
+					len = 4;
+					afilter = CS_NUMERAL;
+				}
+				break;
 
-		case WE_ON_EDIT_TEXT: {
-			if (e->we.edittext.str == NULL) break;
-
-			const char *b = e->we.edittext.str;
-
-			switch (WP(w, def_d).data_2) {
-				case CUSTCURR_EXCHANGERATE:
-					_custom_currency.rate = Clamp(atoi(b), 1, 5000);
-					break;
-
-				case CUSTCURR_SEPARATOR: /* Thousands seperator */
-					_custom_currency.separator = StrEmpty(b) ? ' ' : b[0];
-					ttd_strlcpy(_str_separator, b, lengthof(_str_separator));
-					break;
-
-				case CUSTCURR_PREFIX:
-					ttd_strlcpy(_custom_currency.prefix, b, lengthof(_custom_currency.prefix));
-					break;
+			case CUSTCURR_SEPARATOR:
+				if (IsInsideMM(x, 10, 30)) { // clicked button
+					this->click = 1 << (line * 2 + 1);
+				}
+				str = BindCString(this->separator);
+				len = 1;
+				break;
 
-				case CUSTCURR_SUFFIX:
-					ttd_strlcpy(_custom_currency.suffix, b, lengthof(_custom_currency.suffix));
-					break;
+			case CUSTCURR_PREFIX:
+				if (IsInsideMM(x, 10, 30)) { // clicked button
+					this->click = 1 << (line * 2 + 1);
+				}
+				str = BindCString(_custom_currency.prefix);
+				len = 12;
+				break;
 
-				case CUSTCURR_TO_EURO: { /* Year to switch to euro */
-					int val = atoi(b);
+			case CUSTCURR_SUFFIX:
+				if (IsInsideMM(x, 10, 30)) { // clicked button
+					this->click = 1 << (line * 2 + 1);
+				}
+				str = BindCString(_custom_currency.suffix);
+				len = 12;
+				break;
 
-					_custom_currency.to_euro = (val < 2000 ? CF_NOEURO : min(val, MAX_YEAR));
-					break;
+			case CUSTCURR_TO_EURO:
+				if (IsInsideMM(x, 10, 30)) { // clicked buttons
+					if (x < 20) {
+						_custom_currency.to_euro = (_custom_currency.to_euro <= 2000) ?
+							CF_NOEURO : _custom_currency.to_euro - 1;
+						this->click = 1 << (line * 2 + 0);
+					} else {
+						_custom_currency.to_euro =
+							Clamp(_custom_currency.to_euro + 1, 2000, MAX_YEAR);
+						this->click = 1 << (line * 2 + 1);
+					}
+				} else { // enter text
+					SetDParam(0, _custom_currency.to_euro);
+					str = STR_CONFIG_PATCHES_INT32;
+					len = 4;
+					afilter = CS_NUMERAL;
 				}
+				break;
+		}
+
+		if (len != 0) {
+			this->query_widget = line;
+			ShowQueryString(str, STR_CURRENCY_CHANGE_PARAMETER, len + 1, 250, this, afilter);
+		}
+
+		this->flags4 |= 5 << WF_TIMEOUT_SHL;
+		this->SetDirty();
+	}
+
+	virtual void OnQueryTextFinished(char *str)
+	{
+		if (str == NULL) return;
+
+		switch (this->query_widget) {
+			case CUSTCURR_EXCHANGERATE:
+				_custom_currency.rate = Clamp(atoi(str), 1, 5000);
+				break;
+
+			case CUSTCURR_SEPARATOR: /* Thousands seperator */
+				_custom_currency.separator = StrEmpty(str) ? ' ' : str[0];
+				ttd_strlcpy(this->separator, str, lengthof(this->separator));
+				break;
+
+			case CUSTCURR_PREFIX:
+				ttd_strlcpy(_custom_currency.prefix, str, lengthof(_custom_currency.prefix));
+				break;
+
+			case CUSTCURR_SUFFIX:
+				ttd_strlcpy(_custom_currency.suffix, str, lengthof(_custom_currency.suffix));
+				break;
+
+			case CUSTCURR_TO_EURO: { /* Year to switch to euro */
+				int val = atoi(str);
+
+				_custom_currency.to_euro = (val < 2000 ? CF_NOEURO : min(val, MAX_YEAR));
+				break;
 			}
-			MarkWholeScreenDirty();
-		} break;
+		}
+		MarkWholeScreenDirty();
+	}
 
-		case WE_TIMEOUT:
-			WP(w, def_d).data_1 = 0;
-			w->SetDirty();
-			break;
-
-		case WE_DESTROY:
-			DeleteWindowById(WC_QUERY_STRING, 0);
-			MarkWholeScreenDirty();
-			break;
+	virtual void OnTimeout()
+	{
+		this->click = 0;
+		this->SetDirty();
 	}
-}
+};
 
 static const Widget _cust_currency_widgets[] = {
 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,            STR_018B_CLOSE_WINDOW},
@@ -1326,14 +1291,10 @@
 	WC_CUSTOM_CURRENCY, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
 	_cust_currency_widgets,
-	CustCurrencyWndProc,
 };
 
 static void ShowCustCurrency()
 {
-	_str_separator[0] = _custom_currency.separator;
-	_str_separator[1] = '\0';
-
 	DeleteWindowById(WC_CUSTOM_CURRENCY, 0);
-	new Window(&_cust_currency_desc);
+	new CustomCurrencyWindow(&_cust_currency_desc);
 }
--- a/src/ship_cmd.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/ship_cmd.cpp	Mon May 19 15:13:58 2008 +0000
@@ -350,7 +350,7 @@
 		SetDParam(0, st->index);
 		AddNewsItem(
 			STR_9833_CITIZENS_CELEBRATE_FIRST,
-			NM_THIN, NF_VIEWPORT | NF_VEHICLE, (v->owner == _local_player) ? NT_ARRIVAL_PLAYER : NT_ARRIVAL_OTHER, DNC_NONE,
+			(v->owner == _local_player) ? NS_ARRIVAL_PLAYER : NS_ARRIVAL_OTHER,
 			v->index,
 			0);
 	}
@@ -818,7 +818,7 @@
 		VehiclePositionChanged(v);
 
 		InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
-		RebuildVehicleLists();
+		InvalidateWindowClassesData(WC_SHIPS_LIST, 0);
 		InvalidateWindow(WC_COMPANY, v->owner);
 		if (IsLocalPlayer())
 			InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the replace Ship window
@@ -855,7 +855,7 @@
 
 	if (flags & DC_EXEC) {
 		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
-		RebuildVehicleLists();
+		InvalidateWindowClassesData(WC_SHIPS_LIST, 0);
 		InvalidateWindow(WC_COMPANY, v->owner);
 		DeleteWindowById(WC_VEHICLE_VIEW, v->index);
 		DeleteDepotHighlightOfVehicle(v);
@@ -1001,7 +1001,7 @@
 		v->cargo_subtype = new_subtype;
 		InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
 		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
-		RebuildVehicleLists();
+		InvalidateWindowClassesData(WC_SHIPS_LIST, 0);
 	}
 
 	return cost;
--- a/src/signal.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/signal.cpp	Mon May 19 15:13:58 2008 +0000
@@ -468,12 +468,12 @@
  * @return false iff presignal entry would be green (needed for trains leaving depot)
  * @pre IsValidPlayer(owner)
  */
-static bool UpdateSignalsInBuffer(Owner owner)
+static SigSegState UpdateSignalsInBuffer(Owner owner)
 {
 	assert(IsValidPlayer(owner));
 
 	bool first = true;  // first block?
-	bool state = false; // value to return
+	SigSegState state = SIGSEG_FREE; // value to return
 
 	TileIndex tile;
 	DiagDirection dir;
@@ -532,7 +532,10 @@
 
 		if (first) {
 			first = false;
-			state = (flags & SF_TRAIN) || (flags & SF_EXIT && !(flags & SF_GREEN)) || (flags & SF_FULL); // true iff train CAN'T leave the depot
+			if ((flags & SF_TRAIN) || (flags & SF_EXIT && !(flags & SF_GREEN)) || (flags & SF_FULL)) {
+				/* SIGSEG_FREE is set by default */
+				state = SIGSEG_FULL;
+			}
 		}
 
 		/* do not do anything when some buffer was full */
@@ -629,7 +632,7 @@
  * @param owner owner whose signals we will update
  * @return false iff train can leave depot
  */
-bool UpdateSignalsOnSegment(TileIndex tile, DiagDirection side, Owner owner)
+SigSegState UpdateSignalsOnSegment(TileIndex tile, DiagDirection side, Owner owner)
 {
 	assert(_globset.IsEmpty());
 	_globset.Add(tile, side);
--- a/src/signal_func.h	Mon May 19 14:14:33 2008 +0000
+++ b/src/signal_func.h	Mon May 19 15:13:58 2008 +0000
@@ -41,7 +41,13 @@
 	return _signal_on_track[track];
 }
 
-bool UpdateSignalsOnSegment(TileIndex tile, DiagDirection side, Owner owner);
+/** State of the signal segment */
+enum SigSegState {
+	SIGSEG_FREE,    ///< Free and has no pre-signal exits or at least one green exit
+	SIGSEG_FULL,    ///< Occupied by a train
+};
+
+SigSegState UpdateSignalsOnSegment(TileIndex tile, DiagDirection side, Owner owner);
 void SetSignalsOnBothDir(TileIndex tile, Track track, Owner owner);
 void AddTrackToSignalBuffer(TileIndex tile, Track track, Owner owner);
 void AddSideToSignalBuffer(TileIndex tile, DiagDirection side, Owner owner);
--- a/src/signs_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/signs_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -66,54 +66,63 @@
 	DEBUG(misc, 3, "Resorting global signs list");
 }
 
-static void SignListWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			if (_sign_sort_dirty) GlobalSortSignList();
-
-			SetVScrollCount(w, _num_sign_sort);
-
-			SetDParam(0, w->vscroll.count);
-			DrawWindowWidgets(w);
-
-			/* No signs? */
-			int y = 16; // offset from top of widget
-			if (w->vscroll.count == 0) {
-				DrawString(2, y, STR_304A_NONE, TC_FROMSTRING);
-				return;
-			}
-
-			/* Start drawing the signs */
-			for (uint16 i = w->vscroll.pos; i < w->vscroll.cap + w->vscroll.pos && i < w->vscroll.count; i++) {
-				const Sign *si = _sign_sort[i];
-
-				if (si->owner != OWNER_NONE) DrawPlayerIcon(si->owner, 4, y + 1);
+struct SignListWindow : Window {
+	SignListWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+	{
+		this->vscroll.cap = 12;
+		this->resize.step_height = 10;
+		this->resize.height = this->height - 10 * 7; // minimum if 5 in the list
 
-				SetDParam(0, si->index);
-				DrawString(22, y, STR_SIGN_NAME, TC_YELLOW);
-				y += 10;
-			}
-		} break;
-
-		case WE_CLICK:
-			if (e->we.click.widget == 3) {
-				uint32 id_v = (e->we.click.pt.y - 15) / 10;
+		this->FindWindowPlacementAndResize(desc);
+	}
 
-				if (id_v >= w->vscroll.cap) return;
-				id_v += w->vscroll.pos;
-				if (id_v >= w->vscroll.count) return;
+	virtual void OnPaint()
+	{
+		if (_sign_sort_dirty) GlobalSortSignList();
 
-				const Sign *si = _sign_sort[id_v];
-				ScrollMainWindowToTile(TileVirtXY(si->x, si->y));
-			}
-			break;
+		SetVScrollCount(this, _num_sign_sort);
 
-		case WE_RESIZE:
-			w->vscroll.cap += e->we.sizing.diff.y / 10;
-			break;
+		SetDParam(0, this->vscroll.count);
+		this->DrawWidgets();
+
+		/* No signs? */
+		int y = 16; // offset from top of widget
+		if (this->vscroll.count == 0) {
+			DrawString(2, y, STR_304A_NONE, TC_FROMSTRING);
+			return;
+		}
+
+		/* Start drawing the signs */
+		for (uint16 i = this->vscroll.pos; i < this->vscroll.cap + this->vscroll.pos && i < this->vscroll.count; i++) {
+			const Sign *si = _sign_sort[i];
+
+			if (si->owner != OWNER_NONE) DrawPlayerIcon(si->owner, 4, y + 1);
+
+			SetDParam(0, si->index);
+			DrawString(22, y, STR_SIGN_NAME, TC_YELLOW);
+			y += 10;
+		}
 	}
-}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		if (widget == 3) {
+			uint32 id_v = (pt.y - 15) / 10;
+
+			if (id_v >= this->vscroll.cap) return;
+			id_v += this->vscroll.pos;
+			if (id_v >= this->vscroll.count) return;
+
+			const Sign *si = _sign_sort[id_v];
+			ScrollMainWindowToTile(TileVirtXY(si->x, si->y));
+		}
+	}
+
+	virtual void OnResize(Point new_size, Point delta)
+	{
+		this->vscroll.cap += delta.y / 10;
+	}
+};
 
 static const Widget _sign_list_widget[] = {
 {   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},
@@ -130,18 +139,12 @@
 	WC_SIGN_LIST, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON | WDF_RESIZABLE,
 	_sign_list_widget,
-	SignListWndProc
 };
 
 
 void ShowSignList()
 {
-	Window *w = AllocateWindowDescFront<Window>(&_sign_list_desc, 0);
-	if (w != NULL) {
-		w->vscroll.cap = 12;
-		w->resize.step_height = 10;
-		w->resize.height = w->height - 10 * 7; // minimum if 5 in the list
-	}
+	AllocateWindowDescFront<SignListWindow>(&_sign_list_desc, 0);
 }
 
 static void RenameSign(SignID index, const char *text)
@@ -170,6 +173,7 @@
 		this->LowerWidget(QUERY_EDIT_SIGN_WIDGET_TEXT);
 
 		UpdateSignEditWindow(si);
+		this->FindWindowPlacementAndResize(desc);
 	}
 
 	~SignWindow()
@@ -197,7 +201,7 @@
 	virtual void OnPaint()
 	{
 		SetDParam(0, this->caption);
-		DrawWindowWidgets(this);
+		this->DrawWidgets();
 		this->DrawEditBox(QUERY_EDIT_SIGN_WIDGET_TEXT);
 	}
 
@@ -255,10 +259,10 @@
 		}
 	}
 
-	virtual bool OnKeyPress(uint16 key, uint16 keycode)
+	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
 	{
-		bool cont = true;
-		switch (this->HandleEditBoxKey(QUERY_EDIT_SIGN_WIDGET_TEXT, key, keycode, cont)) {
+		EventState state = ES_NOT_HANDLED;
+		switch (this->HandleEditBoxKey(QUERY_EDIT_SIGN_WIDGET_TEXT, key, keycode, state)) {
 			case 1: // Enter pressed, confirms change
 				RenameSign(this->cur_sign, this->text.buf);
 				/* FALL THROUGH */
@@ -267,7 +271,7 @@
 				delete this;
 				break;
 		}
-		return cont;
+		return state;
 	}
 
 	virtual void OnMouseLoop()
@@ -295,7 +299,6 @@
 	WC_QUERY_STRING, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
 	_query_sign_edit_widgets,
-	NULL
 };
 
 void ShowRenameSignWindow(const Sign *si)
--- a/src/smallmap_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/smallmap_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -800,7 +800,7 @@
 		this->SetDirty();
 	}
 
-	SmallMapWindow(const WindowDesc *desc, void *data, int window_number) : Window(desc, data, window_number)
+	SmallMapWindow(const WindowDesc *desc, int window_number) : Window(desc, window_number)
 	{
 		/* Resize the window to fit industries list */
 		if (_industries_per_column > BASE_NB_PER_COLUMN) {
@@ -847,7 +847,7 @@
 
 		/* draw the window */
 		SetDParam(0, STR_00E5_CONTOURS + _smallmap_type);
-		DrawWindowWidgets(this);
+		this->DrawWidgets();
 
 		tbl = _legend_table[_smallmap_type];
 
@@ -1078,7 +1078,6 @@
 	WC_SMALLMAP, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON | WDF_RESIZABLE,
 	_smallmap_widgets,
-	NULL
 };
 
 void ShowSmallMap()
@@ -1103,88 +1102,127 @@
 {   WIDGETS_END},
 };
 
-static void ExtraViewPortWndProc(Window *w, WindowEvent *e)
+class ExtraViewportWindow : public Window
 {
-	switch (e->event) {
-	case WE_CREATE: // Disable zoom in button
-		/* New viewport start at (zero,zero) */
-		InitializeWindowViewport(w, 3, 17, w->widget[4].right - w->widget[4].left - 1, w->widget[4].bottom - w->widget[4].top - 1, 0, ZOOM_LVL_VIEWPORT);
-
-		w->DisableWidget(5);
-		break;
-
-	case WE_PAINT:
-		/* set the number in the title bar */
-		SetDParam(0, w->window_number + 1);
-
-		DrawWindowWidgets(w);
-		DrawWindowViewport(w);
-		break;
-
-	case WE_CLICK:
-		switch (e->we.click.widget) {
-			case 5: DoZoomInOutWindow(ZOOM_IN,  w); break;
-			case 6: DoZoomInOutWindow(ZOOM_OUT, w); break;
-
-		case 7: { // location button (move main view to same spot as this view) 'Paste Location'
-			Window *w2 = FindWindowById(WC_MAIN_WINDOW, 0);
-			int x = w->viewport->scrollpos_x; // Where is the main looking at
-			int y = w->viewport->scrollpos_y;
-
-			/* set this view to same location. Based on the center, adjusting for zoom */
-			w2->viewport->dest_scrollpos_x =  x - (w2->viewport->virtual_width -  w->viewport->virtual_width) / 2;
-			w2->viewport->dest_scrollpos_y =  y - (w2->viewport->virtual_height - w->viewport->virtual_height) / 2;
-		} break;
+	enum ExtraViewportWindowWidgets {
+		EVW_CLOSE,
+		EVW_CAPTION,
+		EVW_STICKY,
+		EVW_BACKGROUND,
+		EVW_VIEWPORT,
+		EVW_ZOOMIN,
+		EVW_ZOOMOUT,
+		EVW_MAIN_TO_VIEW,
+		EVW_VIEW_TO_MAIN,
+		EVW_SPACER1,
+		EVW_SPACER2,
+		EVW_RESIZE,
+	};
 
-		case 8: { // inverse location button (move this view to same spot as main view) 'Copy Location'
-			const Window *w2 = FindWindowById(WC_MAIN_WINDOW, 0);
-			int x = w2->viewport->scrollpos_x;
-			int y = w2->viewport->scrollpos_y;
-
-			w->viewport->dest_scrollpos_x =  x + (w2->viewport->virtual_width -  w->viewport->virtual_width) / 2;
-			w->viewport->dest_scrollpos_y =  y + (w2->viewport->virtual_height - w->viewport->virtual_height) / 2;
-		} break;
-		}
-		break;
-
-	case WE_RESIZE:
-		w->viewport->width          += e->we.sizing.diff.x;
-		w->viewport->height         += e->we.sizing.diff.y;
-		w->viewport->virtual_width  += e->we.sizing.diff.x;
-		w->viewport->virtual_height += e->we.sizing.diff.y;
-		break;
-
-		case WE_SCROLL: {
-			ViewPort *vp = IsPtInWindowViewport(w, _cursor.pos.x, _cursor.pos.y);
+public:
+	ExtraViewportWindow(const WindowDesc *desc, int window_number, TileIndex tile) : Window(desc, window_number)
+	{
+		/* New viewport start at (zero,zero) */
+		InitializeWindowViewport(this, 3, 17, this->widget[EVW_VIEWPORT].right - this->widget[EVW_VIEWPORT].left - 1, this->widget[EVW_VIEWPORT].bottom - this->widget[EVW_VIEWPORT].top - 1, 0, ZOOM_LVL_VIEWPORT);
 
-			if (vp == NULL) {
-				_cursor.fix_at = false;
-				_scrolling_viewport = false;
-			}
+		this->DisableWidget(EVW_ZOOMIN);
+		this->FindWindowPlacementAndResize(desc);
 
-			w->viewport->scrollpos_x += ScaleByZoom(e->we.scroll.delta.x, vp->zoom);
-			w->viewport->scrollpos_y += ScaleByZoom(e->we.scroll.delta.y, vp->zoom);
-			w->viewport->dest_scrollpos_x = w->viewport->scrollpos_x;
-			w->viewport->dest_scrollpos_y = w->viewport->scrollpos_y;
-		} break;
+		Point pt;
+		if (tile == INVALID_TILE) {
+			/* the main window with the main view */
+			const Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
 
-		case WE_MOUSEWHEEL:
-			ZoomInOrOutToCursorWindow(e->we.wheel.wheel < 0, w);
-			break;
+			/* center on same place as main window (zoom is maximum, no adjustment needed) */
+			pt.x = w->viewport->scrollpos_x + w->viewport->virtual_height / 2;
+			pt.y = w->viewport->scrollpos_y + w->viewport->virtual_height / 2;
+		} else {
+			pt = RemapCoords(TileX(tile) * TILE_SIZE + TILE_SIZE / 2, TileY(tile) * TILE_SIZE + TILE_SIZE / 2, TileHeight(tile));
+		}
 
-		case WE_INVALIDATE_DATA:
-			/* Only handle zoom message if intended for us (msg ZOOM_IN/ZOOM_OUT) */
-			HandleZoomMessage(w, w->viewport, 5, 6);
-			break;
+		this->viewport->scrollpos_x = pt.x - ((this->widget[EVW_VIEWPORT].right - this->widget[EVW_VIEWPORT].left) - 1) / 2;
+		this->viewport->scrollpos_y = pt.y - ((this->widget[EVW_VIEWPORT].bottom - this->widget[EVW_VIEWPORT].top) - 1) / 2;
+		this->viewport->dest_scrollpos_x = this->viewport->scrollpos_x;
+		this->viewport->dest_scrollpos_y = this->viewport->scrollpos_y;
+
 	}
-}
+
+	virtual void OnPaint()
+	{
+		/* set the number in the title bar */
+		SetDParam(0, this->window_number + 1);
+
+		this->DrawWidgets();
+		this->DrawViewport();
+	}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case EVW_ZOOMIN: DoZoomInOutWindow(ZOOM_IN,  this); break;
+			case EVW_ZOOMOUT: DoZoomInOutWindow(ZOOM_OUT, this); break;
+
+			case EVW_MAIN_TO_VIEW: { // location button (move main view to same spot as this view) 'Paste Location'
+				Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
+				int x = this->viewport->scrollpos_x; // Where is the main looking at
+				int y = this->viewport->scrollpos_y;
+
+				/* set this view to same location. Based on the center, adjusting for zoom */
+				w->viewport->dest_scrollpos_x =  x - (w->viewport->virtual_width -  this->viewport->virtual_width) / 2;
+				w->viewport->dest_scrollpos_y =  y - (w->viewport->virtual_height - this->viewport->virtual_height) / 2;
+			} break;
+
+			case EVW_VIEW_TO_MAIN: { // inverse location button (move this view to same spot as main view) 'Copy Location'
+				const Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
+				int x = w->viewport->scrollpos_x;
+				int y = w->viewport->scrollpos_y;
+
+				this->viewport->dest_scrollpos_x =  x + (w->viewport->virtual_width -  this->viewport->virtual_width) / 2;
+				this->viewport->dest_scrollpos_y =  y + (w->viewport->virtual_height - this->viewport->virtual_height) / 2;
+			} break;
+		}
+	}
+
+	virtual void OnResize(Point new_size, Point delta)
+	{
+		this->viewport->width          += delta.x;
+		this->viewport->height         += delta.y;
+		this->viewport->virtual_width  += delta.x;
+		this->viewport->virtual_height += delta.y;
+	}
+
+	virtual void OnScroll(Point delta)
+	{
+		ViewPort *vp = IsPtInWindowViewport(this, _cursor.pos.x, _cursor.pos.y);
+
+		if (vp == NULL) {
+			_cursor.fix_at = false;
+			_scrolling_viewport = false;
+		}
+
+		this->viewport->scrollpos_x += ScaleByZoom(delta.x, vp->zoom);
+		this->viewport->scrollpos_y += ScaleByZoom(delta.y, vp->zoom);
+		this->viewport->dest_scrollpos_x = this->viewport->scrollpos_x;
+		this->viewport->dest_scrollpos_y = this->viewport->scrollpos_y;
+	}
+
+	virtual void OnMouseWheel(int wheel)
+	{
+		ZoomInOrOutToCursorWindow(wheel < 0, this);
+	}
+
+	virtual void OnInvalidateData(int data = 0)
+	{
+		/* Only handle zoom message if intended for us (msg ZOOM_IN/ZOOM_OUT) */
+		HandleZoomMessage(this, this->viewport, EVW_ZOOMIN, EVW_ZOOMOUT);
+	}
+};
 
 static const WindowDesc _extra_view_port_desc = {
 	WDP_AUTO, WDP_AUTO, 300, 68, 300, 268,
 	WC_EXTRA_VIEW_PORT, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
 	_extra_view_port_widgets,
-	ExtraViewPortWndProc
 };
 
 void ShowExtraViewPortWindow(TileIndex tile)
@@ -1194,26 +1232,7 @@
 	/* find next free window number for extra viewport */
 	while (FindWindowById(WC_EXTRA_VIEW_PORT, i) != NULL) i++;
 
-	Window *w = AllocateWindowDescFront<Window>(&_extra_view_port_desc, i);
-	if (w != NULL) {
-		Point pt;
-
-		if (tile == INVALID_TILE) {
-			/* the main window with the main view */
-			const Window *v = FindWindowById(WC_MAIN_WINDOW, 0);
-
-			/* center on same place as main window (zoom is maximum, no adjustment needed) */
-			pt.x = v->viewport->scrollpos_x + v->viewport->virtual_height / 2;
-			pt.y = v->viewport->scrollpos_y + v->viewport->virtual_height / 2;
-		} else {
-			pt = RemapCoords(TileX(tile) * TILE_SIZE + TILE_SIZE / 2, TileY(tile) * TILE_SIZE + TILE_SIZE / 2, TileHeight(tile));
-		}
-
-		w->viewport->scrollpos_x = pt.x - ((w->widget[4].right - w->widget[4].left) - 1) / 2;
-		w->viewport->scrollpos_y = pt.y - ((w->widget[4].bottom - w->widget[4].top) - 1) / 2;
-		w->viewport->dest_scrollpos_x = w->viewport->scrollpos_x;
-		w->viewport->dest_scrollpos_y = w->viewport->scrollpos_y;
-	}
+	new ExtraViewportWindow(&_extra_view_port_desc, i, tile);
 }
 
 bool ScrollMainWindowTo(int x, int y, bool instant)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sortlist_type.h	Mon May 19 15:13:58 2008 +0000
@@ -0,0 +1,31 @@
+/* $Id$ */
+
+/** @file sortlist_type.h Base types for having sorted lists in GUIs. */
+
+#ifndef SORTLIST_TYPE_H
+#define SORTLIST_TYPE_H
+
+enum SortListFlags {
+	VL_NONE    = 0,      ///< no sort
+	VL_DESC    = 1 << 0, ///< sort descending or ascending
+	VL_RESORT  = 1 << 1, ///< instruct the code to resort the list in the next loop
+	VL_REBUILD = 1 << 2, ///< create sort-listing to use for qsort and friends
+	VL_END     = 1 << 3,
+};
+DECLARE_ENUM_AS_BIT_SET(SortListFlags);
+
+struct Listing {
+	bool order;    ///< Ascending/descending
+	byte criteria; ///< Sorting criteria
+};
+
+template <typename T>
+struct GUIList {
+	T* sort_list;        ///< The items to sort.
+	SortListFlags flags; ///< used to control sorting/resorting/etc.
+	uint16 list_length;  ///< length of the list being sorted
+	uint16 resort_timer; ///< resort list after a given amount of ticks if set
+	byte sort_type;      ///< what criteria to sort on
+};
+
+#endif /* SORTLIST_TYPE_H */
--- a/src/station.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/station.cpp	Mon May 19 15:13:58 2008 +0000
@@ -74,8 +74,7 @@
 	}
 
 	MarkDirty();
-	RebuildStationLists();
-	InvalidateWindowClasses(WC_STATION_LIST);
+	InvalidateWindowData(WC_STATION_LIST, this->owner, 0);
 
 	DeleteWindowById(WC_STATION_VIEW, index);
 
--- a/src/station_cmd.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/station_cmd.cpp	Mon May 19 15:13:58 2008 +0000
@@ -409,7 +409,7 @@
 	}
 
 	SetDParam(0, st->index);
-	AddNewsItem(msg, NM_SMALL, NF_VIEWPORT | NF_TILE, NT_ACCEPTANCE, DNC_NONE, st->xy, 0);
+	AddNewsItem(msg, NS_ACCEPTANCE, st->xy, 0);
 }
 
 /**
@@ -650,8 +650,7 @@
 {
 	if (st->facilities == 0) {
 		st->delete_ctr = 0;
-		RebuildStationLists();
-		InvalidateWindow(WC_STATION_LIST, st->owner);
+		InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
 	}
 	/* station remains but it probably lost some parts - station sign should stay in the station boundaries */
 	UpdateStationSignCoord(st);
@@ -1051,8 +1050,7 @@
 		st->MarkTilesDirty(false);
 		UpdateStationVirtCoordDirty(st);
 		UpdateStationAcceptance(st, false);
-		RebuildStationLists();
-		InvalidateWindow(WC_STATION_LIST, st->owner);
+		InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
 		InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_TRAINS);
 	}
 
@@ -1410,8 +1408,7 @@
 
 		UpdateStationVirtCoordDirty(st);
 		UpdateStationAcceptance(st, false);
-		RebuildStationLists();
-		InvalidateWindow(WC_STATION_LIST, st->owner);
+		InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
 		InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_ROADVEHS);
 	}
 	return cost;
@@ -1723,8 +1720,7 @@
 
 		UpdateStationVirtCoordDirty(st);
 		UpdateStationAcceptance(st, false);
-		RebuildStationLists();
-		InvalidateWindow(WC_STATION_LIST, st->owner);
+		InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
 		InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_PLANES);
 	}
 
@@ -1820,8 +1816,7 @@
 
 		UpdateStationVirtCoordDirty(st);
 		UpdateStationAcceptance(st, false);
-		RebuildStationLists();
-		InvalidateWindow(WC_STATION_LIST, st->owner);
+		InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
 		InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_SHIPS);
 	}
 
@@ -1979,8 +1974,7 @@
 
 		UpdateStationVirtCoordDirty(st);
 		UpdateStationAcceptance(st, false);
-		RebuildStationLists();
-		InvalidateWindow(WC_STATION_LIST, st->owner);
+		InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
 		InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_SHIPS);
 	}
 
@@ -2637,7 +2631,7 @@
 		st->name = strdup(_cmd_text);
 
 		UpdateStationVirtCoord(st);
-		ResortStationLists();
+		InvalidateWindowData(WC_STATION_LIST, st->owner, 1);
 		MarkWholeScreenDirty();
 	}
 
@@ -2858,8 +2852,7 @@
 
 		SetTileOwner(tile, new_player);
 		if (!IsBuoy(tile)) st->owner = new_player; // do not set st->owner for buoys
-		RebuildStationLists();
-		InvalidateWindowClasses(WC_STATION_LIST);
+		InvalidateWindowClassesData(WC_STATION_LIST, 0);
 	} else {
 		if (IsDriveThroughStopTile(tile)) {
 			/* Remove the drive-through road stop */
--- a/src/station_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/station_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -168,39 +168,6 @@
 typedef GUIList<const Station*> GUIStationList;
 
 /**
- * Set the station sort flag for all station-list windows.
- * @param sl_flag Sort list flag to set for all station-list windows
- */
-static void SetStationListsFlag(SortListFlags sl_flag)
-{
-	Window *const *wz;
-
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
-		if (w->window_class == WC_STATION_LIST) {
-			dynamic_cast<GUIStationList*>(w)->flags |= sl_flag;
-			w->SetDirty();
-		}
-	}
-}
-
-/**
- * Set the 'VL_REBUILD' flag for all station lists
- */
-void RebuildStationLists()
-{
-	SetStationListsFlag(VL_REBUILD);
-}
-
-/**
- * Set the 'VL_RESORT' flag for all station lists
- */
-void ResortStationLists()
-{
-	SetStationListsFlag(VL_RESORT);
-}
-
-/**
  * Rebuild station list if the VL_REBUILD flag is set
  *
  * @param sl pointer to plstations_d (station list and flags)
@@ -287,7 +254,7 @@
 	static byte facilities;
 	static bool include_empty;
 
-	PlayerStationsWindow(const WindowDesc *desc, void *data, WindowNumber window_number) : Window(desc, data, window_number)
+	PlayerStationsWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
 	{
 		this->caption_color = (byte)this->window_number;
 		this->vscroll.cap = 12;
@@ -369,10 +336,10 @@
 		/* Set text of sort by dropdown */
 		this->widget[SLW_SORTDROPBTN].data = _station_sort_listing[this->sort_type];
 
-		DrawWindowWidgets(this);
+		this->DrawWidgets();
 
 		/* draw arrow pointing up/down for ascending/descending sorting */
-		DrawSortButtonState(this, SLW_SORTBY, this->flags & VL_DESC ? SBS_DOWN : SBS_UP);
+		this->DrawSortButtonState(SLW_SORTBY, this->flags & VL_DESC ? SBS_DOWN : SBS_UP);
 
 		int cg_ofst;
 		int x = 89;
@@ -436,8 +403,6 @@
 
 	virtual void OnClick(Point pt, int widget)
 	{
-		PlayerID owner = (PlayerID)this->window_number;
-
 		switch (widget) {
 			case SLW_LIST: {
 				uint32 id_v = (pt.y - 41) / 10;
@@ -450,7 +415,7 @@
 
 				const Station *st = this->sort_list[id_v];
 				/* do not check HasStationInUse - it is slow and may be invalid */
-				assert(st->owner == owner || (st->owner == OWNER_NONE && !st->IsBuoy()));
+				assert(st->owner == (PlayerID)this->window_number || (st->owner == OWNER_NONE && !st->IsBuoy()));
 
 				if (_ctrl_pressed) {
 					ShowExtraViewPortWindow(st->xy);
@@ -607,6 +572,11 @@
 	{
 		this->vscroll.cap += delta.y / 10;
 	}
+
+	virtual void OnInvalidateData(int data)
+	{
+		this->flags |= (data == 0 ? VL_REBUILD : VL_RESORT);
+	}
 };
 
 Listing PlayerStationsWindow::station_sort = {0, 0};
@@ -645,7 +615,6 @@
 	WC_STATION_LIST, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON | WDF_RESIZABLE,
 	_player_stations_widgets,
-	NULL
 };
 
 /**
@@ -737,7 +706,7 @@
 	uint32 cargo;                 ///< Bitmask of cargo types to expand
 	uint16 cargo_rows[NUM_CARGO]; ///< Header row for each cargo type
 
-	StationViewWindow(const WindowDesc *desc, void *data, WindowNumber window_number) : Window(desc, data, window_number)
+	StationViewWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
 	{
 		PlayerID owner = GetStation(window_number)->owner;
 		if (owner != OWNER_NONE) this->caption_color = owner;
@@ -815,7 +784,7 @@
 
 		SetDParam(0, st->index);
 		SetDParam(1, st->facilities);
-		DrawWindowWidgets(this);
+		this->DrawWidgets();
 
 		int x = 2;  ///< coordinates used for printing waiting/accepted/rating of cargo
 		int y = 15;
@@ -1017,7 +986,6 @@
 	WC_STATION_VIEW, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
 	_station_view_widgets,
-	NULL
 };
 
 /**
--- a/src/station_gui.h	Mon May 19 14:14:33 2008 +0000
+++ b/src/station_gui.h	Mon May 19 15:13:58 2008 +0000
@@ -48,10 +48,6 @@
 	SVW_RESIZE,          ///< Resize button
 };
 
-/* sorter stuff */
-void RebuildStationLists();
-void ResortStationLists();
-
 enum StationCoverageType {
 	SCT_PASSENGERS_ONLY,
 	SCT_NON_PASSENGERS_ONLY,
--- a/src/statusbar_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/statusbar_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -18,21 +18,15 @@
 #include "window_gui.h"
 #include "variables.h"
 #include "window_func.h"
+#include "statusbar_gui.h"
 
 #include "table/strings.h"
 #include "table/sprites.h"
 
-extern GetNewsStringCallbackProc * const _get_news_string_callback[];
-
 static bool DrawScrollingStatusText(const NewsItem *ni, int pos, int width)
 {
-	StringID str;
-	if (ni->display_mode == NM_CALLBACK) {
-		str = _get_news_string_callback[ni->callback](ni);
-	} else {
-		CopyInDParam(0, ni->params, lengthof(ni->params));
-		str = ni->string_id;
-	}
+	CopyInDParam(0, ni->params, lengthof(ni->params));
+	StringID str = ni->string_id;
 
 	char buf[512];
 	GetString(buf, str, lastof(buf));
@@ -69,80 +63,98 @@
 	return x > 0;
 }
 
-static void StatusBarWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			const Player *p = (_local_player == PLAYER_SPECTATOR) ? NULL : GetPlayer(_local_player);
-
-			DrawWindowWidgets(w);
-			SetDParam(0, _date);
-			DrawStringCentered(70, 1, (_pause_game || _patches.status_long_date) ? STR_00AF : STR_00AE, TC_FROMSTRING);
-
-			if (p != NULL) {
-				/* Draw player money */
-				SetDParam(0, p->player_money);
-				DrawStringCentered(w->widget[2].left + 70, 1, STR_0004, TC_FROMSTRING);
-			}
+struct StatusBarWindow : Window {
+	bool saving;
+	int ticker_scroll;
+	int reminder_timeout;
 
-			/* Draw status bar */
-			if (WP(w, def_d).data_3) { // true when saving is active
-				DrawStringCenteredTruncated(w->widget[1].left + 1, w->widget[1].right - 1, 1, STR_SAVING_GAME, TC_FROMSTRING);
-			} else if (_do_autosave) {
-				DrawStringCenteredTruncated(w->widget[1].left + 1, w->widget[1].right - 1, 1, STR_032F_AUTOSAVE, TC_FROMSTRING);
-			} else if (_pause_game) {
-				DrawStringCenteredTruncated(w->widget[1].left + 1, w->widget[1].right - 1, 1, STR_0319_PAUSED, TC_FROMSTRING);
-			} else if (WP(w, def_d).data_1 > -1280 && FindWindowById(WC_NEWS_WINDOW,0) == NULL && _statusbar_news_item.string_id != 0) {
-				/* Draw the scrolling news text */
-				if (!DrawScrollingStatusText(&_statusbar_news_item, WP(w, def_d).data_1, w->widget[1].right - w->widget[1].left - 2)) {
-					WP(w, def_d).data_1 = -1280;
-					if (p != NULL) {
-						/* This is the default text */
-						SetDParam(0, p->index);
-						DrawStringCenteredTruncated(w->widget[1].left + 1, w->widget[1].right - 1, 1, STR_02BA, TC_FROMSTRING);
-					}
-				}
-			} else {
+	StatusBarWindow(const WindowDesc *desc) : Window(desc)
+	{
+		CLRBITS(this->flags4, WF_WHITE_BORDER_MASK);
+		this->ticker_scroll = -1280;
+
+		this->FindWindowPlacementAndResize(desc);
+	}
+
+	virtual void OnPaint()
+	{
+		const Player *p = (_local_player == PLAYER_SPECTATOR) ? NULL : GetPlayer(_local_player);
+
+		this->DrawWidgets();
+		SetDParam(0, _date);
+		DrawStringCentered(70, 1, (_pause_game || _patches.status_long_date) ? STR_00AF : STR_00AE, TC_FROMSTRING);
+
+		if (p != NULL) {
+			/* Draw player money */
+			SetDParam(0, p->player_money);
+			DrawStringCentered(this->widget[2].left + 70, 1, STR_0004, TC_FROMSTRING);
+		}
+
+		/* Draw status bar */
+		if (this->saving) { // true when saving is active
+			DrawStringCenteredTruncated(this->widget[1].left + 1, this->widget[1].right - 1, 1, STR_SAVING_GAME, TC_FROMSTRING);
+		} else if (_do_autosave) {
+			DrawStringCenteredTruncated(this->widget[1].left + 1, this->widget[1].right - 1, 1, STR_032F_AUTOSAVE, TC_FROMSTRING);
+		} else if (_pause_game) {
+			DrawStringCenteredTruncated(this->widget[1].left + 1, this->widget[1].right - 1, 1, STR_0319_PAUSED, TC_FROMSTRING);
+		} else if (this->ticker_scroll > -1280 && FindWindowById(WC_NEWS_WINDOW, 0) == NULL && _statusbar_news_item.string_id != 0) {
+			/* Draw the scrolling news text */
+			if (!DrawScrollingStatusText(&_statusbar_news_item, this->ticker_scroll, this->widget[1].right - this->widget[1].left - 2)) {
+				this->ticker_scroll = -1280;
 				if (p != NULL) {
 					/* This is the default text */
 					SetDParam(0, p->index);
-					DrawStringCenteredTruncated(w->widget[1].left + 1, w->widget[1].right - 1, 1, STR_02BA, TC_FROMSTRING);
+					DrawStringCenteredTruncated(this->widget[1].left + 1, this->widget[1].right - 1, 1, STR_02BA, TC_FROMSTRING);
 				}
 			}
-
-			if (WP(w, def_d).data_2 > 0) DrawSprite(SPR_BLOT, PALETTE_TO_RED, w->widget[1].right - 11, 2);
-		} break;
-
-		case WE_INVALIDATE_DATA:
-			WP(w, def_d).data_3 = e->we.invalidate.data;
-			break;
-
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case 1: ShowLastNewsMessage(); break;
-				case 2: if (_local_player != PLAYER_SPECTATOR) ShowPlayerFinances(_local_player); break;
-				default: ResetObjectToPlace();
+		} else {
+			if (p != NULL) {
+				/* This is the default text */
+				SetDParam(0, p->index);
+				DrawStringCenteredTruncated(this->widget[1].left + 1, this->widget[1].right - 1, 1, STR_02BA, TC_FROMSTRING);
 			}
-			break;
+		}
 
-		case WE_TICK: {
-			if (_pause_game) return;
-
-			if (WP(w, def_d).data_1 > -1280) { // Scrolling text
-				WP(w, def_d).data_1 -= 2;
-				w->InvalidateWidget(1);
-			}
+		if (this->reminder_timeout > 0) DrawSprite(SPR_BLOT, PALETTE_TO_RED, this->widget[1].right - 11, 2);
+	}
 
-			if (WP(w, def_d).data_2 > 0) { // Red blot to show there are new unread newsmessages
-				WP(w, def_d).data_2 -= 2;
-			} else if (WP(w, def_d).data_2 < 0) {
-				WP(w, def_d).data_2 = 0;
-				w->InvalidateWidget(1);
-			}
+	virtual void OnInvalidateData(int data)
+	{
+		switch (data) {
+			default: NOT_REACHED();
+			case SBI_SAVELOAD_START:  this->saving = true;  break;
+			case SBI_SAVELOAD_FINISH: this->saving = false; break;
+			case SBI_SHOW_TICKER:     this->ticker_scroll    = 360; break;
+			case SBI_SHOW_REMINDER:   this->reminder_timeout =  91; break;
+		}
+	}
 
-		} break;
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case 1: ShowLastNewsMessage(); break;
+			case 2: if (_local_player != PLAYER_SPECTATOR) ShowPlayerFinances(_local_player); break;
+			default: ResetObjectToPlace();
+		}
 	}
-}
+
+	virtual void OnTick()
+	{
+		if (_pause_game) return;
+
+		if (this->ticker_scroll > -1280) { // Scrolling text
+			this->ticker_scroll -= 2;
+			this->InvalidateWidget(1);
+		}
+
+		if (this->reminder_timeout > 0) { // Red blot to show there are new unread newsmessages
+			this->reminder_timeout -= 2;
+		} else if (this->reminder_timeout < 0) {
+			this->reminder_timeout = 0;
+			this->InvalidateWidget(1);
+		}
+	}
+};
 
 static const Widget _main_status_widgets[] = {
 {      WWT_PANEL,   RESIZE_NONE,    14,     0,   139,     0,    11, 0x0, STR_NULL},
@@ -156,15 +168,19 @@
 	WC_STATUS_BAR, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
 	_main_status_widgets,
-	StatusBarWndProc
 };
 
+/**
+ * Checks whether the news ticker is currently being used.
+ */
+bool IsNewsTickerShown()
+{
+	const StatusBarWindow *w = dynamic_cast<StatusBarWindow*>(FindWindowById(WC_STATUS_BAR, 0));
+	return w != NULL && w->ticker_scroll > -1280;
+}
+
 void ShowStatusBar()
 {
 	_main_status_desc.top = _screen.height - 12;
-	Window *w = new Window(&_main_status_desc);
-	if (w != NULL) {
-		CLRBITS(w->flags4, WF_WHITE_BORDER_MASK);
-		WP(w, def_d).data_1 = -1280;
-	}
+	new StatusBarWindow(&_main_status_desc);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/statusbar_gui.h	Mon May 19 15:13:58 2008 +0000
@@ -0,0 +1,20 @@
+/* $Id$ */
+
+/** @file statusbar_gui.h Functions, definitions and such used only by the GUI. */
+
+#ifndef STATUSBAR_GUI_H
+#define STATUSBAR_GUI_H
+
+enum StatusBarInvalidate
+{
+	SBI_SAVELOAD_START,
+	SBI_SAVELOAD_FINISH,
+	SBI_SHOW_TICKER,
+	SBI_SHOW_REMINDER,
+	SBI_END
+};
+
+bool IsNewsTickerShown();
+void ShowStatusBar();
+
+#endif /* STATUSBAR_GUI_H */
--- a/src/stdafx.h	Mon May 19 14:14:33 2008 +0000
+++ b/src/stdafx.h	Mon May 19 15:13:58 2008 +0000
@@ -145,6 +145,10 @@
 	#include <malloc.h> // alloca()
 #endif
 
+#if defined(WIN32)
+	#define WIN32_LEAN_AND_MEAN     // Exclude rarely-used stuff from Windows headers
+#endif
+
 /* Stuff for MSVC */
 #if defined(_MSC_VER)
 	#pragma once
@@ -158,7 +162,6 @@
 	#endif
 	#define _WIN32_IE_ 0x0401         // 4.01 (win98 and NT4SP5+)
 
-	#define WIN32_LEAN_AND_MEAN     // Exclude rarely-used stuff from Windows headers
 	#pragma warning(disable: 4244)  // 'conversion' conversion from 'type1' to 'type2', possible loss of data
 	#pragma warning(disable: 4761)  // integral size mismatch in argument : conversion supplied
 	#pragma warning(disable: 4200)  // nonstandard extension used : zero-sized array in struct/union
--- a/src/subsidy_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/subsidy_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -19,161 +19,149 @@
 
 #include "table/strings.h"
 
-static void HandleSubsidyClick(int y)
-{
-	const Subsidy *s;
-	uint num;
-	int offs;
-	TileIndex xy;
+struct SubsidyListWindow : Window {
+	SubsidyListWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+	{
+	}
 
-	if (y < 0) return;
+	virtual void OnClick(Point pt, int widget)
+	{
+		if (widget != 3) return;
 
-	num = 0;
-	for (s = _subsidies; s != endof(_subsidies); s++) {
-		if (s->cargo_type != CT_INVALID && s->age < 12) {
+		int y = pt.y - 25;
+
+		if (y < 0) return;
+
+		uint num = 0;
+		for (const Subsidy *s = _subsidies; s != endof(_subsidies); s++) {
+			if (s->cargo_type != CT_INVALID && s->age < 12) {
+				y -= 10;
+				if (y < 0) this->HandleClick(s);
+				num++;
+			}
+		}
+
+		if (num == 0) {
 			y -= 10;
-			if (y < 0) goto handle_click;
-			num++;
+			if (y < 0) return;
+		}
+
+		y -= 11;
+		if (y < 0) return;
+
+		for (const Subsidy *s = _subsidies; s != endof(_subsidies); s++) {
+			if (s->cargo_type != CT_INVALID && s->age >= 12) {
+				y -= 10;
+				if (y < 0) this->HandleClick(s);
+			}
 		}
 	}
 
-	if (num == 0) {
-		y -= 10;
-		if (y < 0) return;
-	}
-
-	y -= 11;
-	if (y < 0) return;
-
-	for (s = _subsidies; s != endof(_subsidies); s++) {
-		if (s->cargo_type != CT_INVALID && s->age >= 12) {
-			y -= 10;
-			if (y < 0) goto handle_click;
-		}
-	}
-	return;
+	void HandleClick(const Subsidy *s)
+	{
+		TownEffect te = GetCargo(s->cargo_type)->town_effect;
+		TileIndex xy;
 
-handle_click:
-
-	TownEffect te = GetCargo(s->cargo_type)->town_effect;
-
-	/* determine from coordinate for subsidy and try to scroll to it */
-	offs = s->from;
-	if (s->age >= 12) {
-		xy = GetStation(offs)->xy;
-	} else if (te == TE_PASSENGERS || te == TE_MAIL) {
-		xy = GetTown(offs)->xy;
-	} else {
-		xy = GetIndustry(offs)->xy;
-	}
-
-	if (_ctrl_pressed || !ScrollMainWindowToTile(xy)) {
-		if (_ctrl_pressed) ShowExtraViewPortWindow(xy);
-
-		/* otherwise determine to coordinate for subsidy and scroll to it */
-		offs = s->to;
+		/* determine from coordinate for subsidy and try to scroll to it */
+		uint offs = s->from;
 		if (s->age >= 12) {
 			xy = GetStation(offs)->xy;
-		} else if (te == TE_PASSENGERS || te == TE_MAIL || te == TE_GOODS || te == TE_FOOD) {
+		} else if (te == TE_PASSENGERS || te == TE_MAIL) {
 			xy = GetTown(offs)->xy;
 		} else {
 			xy = GetIndustry(offs)->xy;
 		}
 
-		if (_ctrl_pressed) {
-			ShowExtraViewPortWindow(xy);
-		} else {
-			ScrollMainWindowToTile(xy);
-		}
-	}
-}
-
-static void DrawSubsidiesWindow(const Window *w)
-{
-	YearMonthDay ymd;
-	const Subsidy *s;
-	uint num;
-	int x;
-	int y;
-
-	DrawWindowWidgets(w);
-
-	ConvertDateToYMD(_date, &ymd);
+		if (_ctrl_pressed || !ScrollMainWindowToTile(xy)) {
+			if (_ctrl_pressed) ShowExtraViewPortWindow(xy);
 
-	int width = w->width - 13;  // scroll bar = 11 + pixel each side
-	y = 15;
-	x = 1;
-
-	/* Section for drawing the offered subisidies */
-	DrawStringTruncated(x, y, STR_2026_SUBSIDIES_ON_OFFER_FOR, TC_FROMSTRING, width);
-	y += 10;
-	num = 0;
+			/* otherwise determine to coordinate for subsidy and scroll to it */
+			offs = s->to;
+			if (s->age >= 12) {
+				xy = GetStation(offs)->xy;
+			} else if (te == TE_PASSENGERS || te == TE_MAIL || te == TE_GOODS || te == TE_FOOD) {
+				xy = GetTown(offs)->xy;
+			} else {
+				xy = GetIndustry(offs)->xy;
+			}
 
-	for (s = _subsidies; s != endof(_subsidies); s++) {
-		if (s->cargo_type != CT_INVALID && s->age < 12) {
-			int x2;
-
-			/* Displays the two offered towns */
-			SetupSubsidyDecodeParam(s, 1);
-			x2 = DrawStringTruncated(x + 2, y, STR_2027_FROM_TO, TC_FROMSTRING, width);
-
-			/* Displays the deadline before voiding the proposal */
-			SetDParam(0, _date - ymd.day + 384 - s->age * 32);
-			DrawStringTruncated(x2, y, STR_2028_BY, TC_FROMSTRING, width - x2);
-			y += 10;
-			num++;
+			if (_ctrl_pressed) {
+				ShowExtraViewPortWindow(xy);
+			} else {
+				ScrollMainWindowToTile(xy);
+			}
 		}
 	}
 
-	if (num == 0) {
-		DrawStringTruncated(x + 2, y, STR_202A_NONE, TC_FROMSTRING, width - 2);
-		y += 10;
-	}
-
-	/* Section for drawing the already granted subisidies */
-	DrawStringTruncated(x, y + 1, STR_202B_SERVICES_ALREADY_SUBSIDISED, TC_FROMSTRING, width);
-	y += 10;
-	num = 0;
-
-	for (s = _subsidies; s != endof(_subsidies); s++) {
-		if (s->cargo_type != CT_INVALID && s->age >= 12) {
-			int xt;
-
-			SetupSubsidyDecodeParam(s, 1);
-
-			PlayerID player = GetStation(s->to)->owner;
-			SetDParam(3, player);
-
-			/* Displays the two connected stations */
-			xt = DrawStringTruncated(x + 2, y, STR_202C_FROM_TO, TC_FROMSTRING, width - 2);
+	virtual void OnPaint()
+	{
+		YearMonthDay ymd;
+		const Subsidy *s;
 
-			/* Displays the date where the granted subsidy will end */
-			if ((xt > 3) && (width - xt) > 9 ) { // do not draw if previous drawing failed or if it will overlap on scrollbar
-				SetDParam(0, _date - ymd.day + 768 - s->age * 32);
-				DrawStringTruncated(xt, y, STR_202D_UNTIL, TC_FROMSTRING, width - xt);
-			}
-			y += 10;
-			num++;
-		}
-	}
-
-	if (num == 0) DrawStringTruncated(x + 2, y, STR_202A_NONE, TC_FROMSTRING, width - 2);
-}
+		this->DrawWidgets();
 
-static void SubsidiesListWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: DrawSubsidiesWindow(w); break;
+		ConvertDateToYMD(_date, &ymd);
 
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case 3:
-					HandleSubsidyClick(e->we.click.pt.y - 25);
-					break;
+		int width = this->width - 13;  // scroll bar = 11 + pixel each side
+		int y = 15;
+		int x = 1;
+
+		/* Section for drawing the offered subisidies */
+		DrawStringTruncated(x, y, STR_2026_SUBSIDIES_ON_OFFER_FOR, TC_FROMSTRING, width);
+		y += 10;
+		uint num = 0;
+
+		for (s = _subsidies; s != endof(_subsidies); s++) {
+			if (s->cargo_type != CT_INVALID && s->age < 12) {
+				int x2;
+
+				/* Displays the two offered towns */
+				SetupSubsidyDecodeParam(s, 1);
+				x2 = DrawStringTruncated(x + 2, y, STR_2027_FROM_TO, TC_FROMSTRING, width);
+
+				/* Displays the deadline before voiding the proposal */
+				SetDParam(0, _date - ymd.day + 384 - s->age * 32);
+				DrawStringTruncated(x2, y, STR_2028_BY, TC_FROMSTRING, width - x2);
+				y += 10;
+				num++;
 			}
-		break;
+		}
+
+		if (num == 0) {
+			DrawStringTruncated(x + 2, y, STR_202A_NONE, TC_FROMSTRING, width - 2);
+			y += 10;
+		}
+
+		/* Section for drawing the already granted subisidies */
+		DrawStringTruncated(x, y + 1, STR_202B_SERVICES_ALREADY_SUBSIDISED, TC_FROMSTRING, width);
+		y += 10;
+		num = 0;
+
+		for (s = _subsidies; s != endof(_subsidies); s++) {
+			if (s->cargo_type != CT_INVALID && s->age >= 12) {
+				int xt;
+
+				SetupSubsidyDecodeParam(s, 1);
+
+				PlayerID player = GetStation(s->to)->owner;
+				SetDParam(3, player);
+
+				/* Displays the two connected stations */
+				xt = DrawStringTruncated(x + 2, y, STR_202C_FROM_TO, TC_FROMSTRING, width - 2);
+
+				/* Displays the date where the granted subsidy will end */
+				if ((xt > 3) && (width - xt) > 9 ) { // do not draw if previous drawing failed or if it will overlap on scrollbar
+					SetDParam(0, _date - ymd.day + 768 - s->age * 32);
+					DrawStringTruncated(xt, y, STR_202D_UNTIL, TC_FROMSTRING, width - xt);
+				}
+				y += 10;
+				num++;
+			}
+		}
+
+		if (num == 0) DrawStringTruncated(x + 2, y, STR_202A_NONE, TC_FROMSTRING, width - 2);
 	}
-}
+};
 
 static const Widget _subsidies_list_widgets[] = {
 {   WWT_CLOSEBOX, RESIZE_NONE,   13,   0,  10,   0,  13, STR_00C5,           STR_018B_CLOSE_WINDOW},
@@ -191,11 +179,10 @@
 	WC_SUBSIDIES_LIST, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON | WDF_RESIZABLE,
 	_subsidies_list_widgets,
-	SubsidiesListWndProc
 };
 
 
 void ShowSubsidiesList()
 {
-	AllocateWindowDescFront<Window>(&_subsidies_list_desc, 0);
+	AllocateWindowDescFront<SubsidyListWindow>(&_subsidies_list_desc, 0);
 }
--- a/src/table/engines.h	Mon May 19 14:14:33 2008 +0000
+++ b/src/table/engines.h	Mon May 19 15:13:58 2008 +0000
@@ -387,8 +387,8 @@
 	RVI( 0, G,  13, 112,    1000, 131,   120, RC_S,  0, 0              , 20, R, S), //   8
 	RVI( 1, G,  19, 128,    1200, 162,   140, RC_S,  0, 0              , 21, R, S), //   9
 	RVI( 0, G,  22, 144,    1600, 170,   130, RC_S,  0, 0              , 22, R, S), //  10
-	RVI( 8, M,  11, 112,   600/2,  32,  85/2, RC_D, 38, CT_PASSENGERS  , 10, R, D), //  11
-	RVI(10, M,  14, 120,   700/2,  38,  70/2, RC_D, 40, CT_PASSENGERS  , 11, R, D), //  12
+	RVI( 8, M,  11, 112,     600,  32,    85, RC_D, 38, CT_PASSENGERS  , 10, R, D), //  11
+	RVI(10, M,  14, 120,     700,  38,    70, RC_D, 40, CT_PASSENGERS  , 11, R, D), //  12
 	RVI( 4, G,  15, 128,    1250,  72,    95, RC_D,  0, 0              , 30, R, D), //  13
 	RVI( 5, G,  17, 144,    1750, 101,   120, RC_D,  0, 0              , 31, R, D), //  14
 	RVI( 4, G,  18, 160,    2580, 112,   140, RC_D,  0, 0              , 32, R, D), //  15
@@ -396,13 +396,13 @@
 	RVI(12, G,  16, 112,    2400, 120,   105, RC_D,  0, 0              , 34, R, D), //  17
 	RVI(13, G,  30, 112,    6600, 207,   155, RC_D,  0, 0              , 35, R, D), //  18
 	RVI(15, G,  18, 104,    1500, 110,   105, RC_D,  0, 0              , 29, R, D), //  19
-	RVI(16, M,  35, 160,  3500/2,  95, 205/2, RC_D,  0, 0              , 45, R, D), //  20
+	RVI(16, M,  35, 160,    3500,  95,   205, RC_D,  0, 0              , 45, R, D), //  20
 	RVI(18, G,  21, 104,    2200, 120,   145, RC_D,  0, 0              , 32, R, D), //  21
-	RVI( 6, M,  20, 200,  4500/2,  70, 190/2, RC_D,  4, CT_MAIL        , 50, R, D), //  22
+	RVI( 6, M,  20, 200,    4500,  70,   190, RC_D,  4, CT_MAIL        , 50, R, D), //  22
 	RVI(20, G,  26, 160,    3600,  84,   180, RC_E,  0, 0              , 40, C, E), //  23
 	RVI(20, G,  30, 176,    5000,  82,   205, RC_E,  0, 0              , 41, C, E), //  24
-	RVI(21, M,  40, 240,  7000/2,  90, 240/2, RC_E,  0, 0              , 51, C, E), //  25
-	RVI(23, M,  43, 264,  8000/2,  95, 250/2, RC_E,  0, 0              , 52, C, E), //  26
+	RVI(21, M,  40, 240,    7000,  90,   240, RC_E,  0, 0              , 51, C, E), //  25
+	RVI(23, M,  43, 264,    8000,  95,   250, RC_E,  0, 0              , 52, C, E), //  26
 	RVI(33, W, 247,   0,       0,  25,     0, RC_W, 40, CT_PASSENGERS  ,  0, R, A), //  27
 	RVI(35, W, 228,   0,       0,  21,     0, RC_W, 30, CT_MAIL        ,  0, R, A), //  28
 	RVI(34, W, 176,   0,       0,  18,     0, RC_W, 30, CT_COAL        ,  0, R, A), //  29
@@ -431,7 +431,7 @@
 	RVI(58, W, 193,   0,       0,  18,     0, RC_W, 25, CT_FIZZY_DRINKS,  0, R, A), //  52
 	RVI(59, W, 191,   0,       0,  18,     0, RC_W, 30, CT_PLASTIC     ,  0, R, A), //  53
 	RVI(25, G,  52, 304,    9000,  95,   230, RC_E,  0, 0              , 60, O, N), //  54
-	RVI(26, M,  60, 336, 10000/2,  85, 240/2, RC_E, 25, CT_PASSENGERS  , 62, O, N), //  55
+	RVI(26, M,  60, 336,   10000,  85,   240, RC_E, 25, CT_PASSENGERS  , 62, O, N), //  55
 	RVI(26, G,  53, 320,    5000,  95,   230, RC_E,  0, 0              , 63, O, N), //  56
 	RVI(60, W, 247,   0,       0,  25,     0, RC_W, 45, CT_PASSENGERS  ,  0, O, A), //  57
 	RVI(62, W, 228,   0,       0,  21,     0, RC_W, 35, CT_MAIL        ,  0, O, A), //  58
@@ -463,7 +463,7 @@
 	RVI(28, G,  70, 400,   10000, 105,   250, RC_E,  0, 0              , 70, L, V), //  84
 	RVI(29, G,  74, 448,   12000, 120,   253, RC_E,  0, 0              , 71, L, V), //  85
 	RVI(30, G,  82, 480,   15000, 130,   254, RC_E,  0, 0              , 72, L, V), //  86
-	RVI(31, M,  95, 640, 20000/2, 150, 255/2, RC_E,  0, 0              , 73, L, V), //  87
+	RVI(31, M,  95, 640,   20000, 150,   255, RC_E,  0, 0              , 73, L, V), //  87
 	RVI(28, G,  70, 480,   10000, 120,   250, RC_E,  0, 0              , 74, L, V), //  88
 	RVI(60, W, 247,   0,       0,  25,     0, RC_W, 47, CT_PASSENGERS  ,  0, L, A), //  89
 	RVI(62, W, 228,   0,       0,  21,     0, RC_W, 37, CT_MAIL        ,  0, L, A), //  90
--- a/src/terraform_cmd.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/terraform_cmd.cpp	Mon May 19 15:13:58 2008 +0000
@@ -301,7 +301,10 @@
 				return_cmd_error(STR_1002_EXCAVATION_WOULD_DAMAGE);
 			}
 			/* Check tiletype-specific things, and add extra-cost */
+			const bool curr_gen = _generating_world;
+			if (_game_mode == GM_EDITOR) _generating_world = true; // used to create green terraformed land
 			CommandCost cost = _tile_type_procs[GetTileType(tile)]->terraform_tile_proc(tile, flags | DC_AUTO, z_min * TILE_HEIGHT, tileh);
+			_generating_world = curr_gen;
 			if (CmdFailed(cost)) {
 				_terraform_err_tile = tile;
 				return cost;
--- a/src/terraform_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/terraform_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -110,12 +110,9 @@
  * allows for additional implements that are more local. For example X_Y drag
  * of convertrail which belongs in rail_gui.cpp and not terraform_gui.cpp
  **/
-bool GUIPlaceProcDragXY(const WindowEvent *e)
+bool GUIPlaceProcDragXY(ViewportDragDropSelectionProcess proc, TileIndex start_tile, TileIndex end_tile)
 {
-	TileIndex start_tile = e->we.place.starttile;
-	TileIndex end_tile = e->we.place.tile;
-
-	switch (e->we.place.select_proc) {
+	switch (proc) {
 		case DDSP_DEMOLISH_AREA:
 			DoCommandP(end_tile, start_tile, 0, CcPlaySound10, CMD_CLEAR_AREA | CMD_MSG(STR_00B5_CAN_T_CLEAR_THIS_AREA));
 			break;
@@ -232,56 +229,67 @@
 	TerraformClick_PlaceSign,
 };
 
-static void TerraformToolbWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-	case WE_PAINT:
-		DrawWindowWidgets(w);
-		break;
+struct TerraformToolbarWindow : Window {
+	TerraformToolbarWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+	{
+		this->FindWindowPlacementAndResize(desc);
+	}
 
-	case WE_CLICK:
-		if (e->we.click.widget >= 4) _terraform_button_proc[e->we.click.widget - 4](w);
-		break;
+	~TerraformToolbarWindow()
+	{
+	}
 
-	case WE_KEYPRESS: {
-		uint i;
+	virtual void OnPaint()
+	{
+		this->DrawWidgets();
+	}
 
-		for (i = 0; i != lengthof(_terraform_keycodes); i++) {
-			if (e->we.keypress.keycode == _terraform_keycodes[i]) {
-				e->we.keypress.cont = false;
-				_terraform_button_proc[i](w);
-				break;
+	virtual void OnClick(Point pt, int widget)
+	{
+		if (widget >= 4) _terraform_button_proc[widget - 4](this);
+	}
+
+	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+	{
+		for (uint i = 0; i != lengthof(_terraform_keycodes); i++) {
+			if (keycode == _terraform_keycodes[i]) {
+				_terraform_button_proc[i](this);
+				return ES_HANDLED;
 			}
 		}
-		break;
+		return ES_NOT_HANDLED;
 	}
 
-	case WE_PLACE_OBJ:
-		_place_proc(e->we.place.tile);
-		return;
+	virtual void OnPlaceObject(Point pt, TileIndex tile)
+	{
+		_place_proc(tile);
+	}
 
-	case WE_PLACE_DRAG:
-		VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.select_method);
-		break;
+	virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
+	{
+		VpSelectTilesWithMethod(pt.x, pt.y, select_method);
+	}
 
-	case WE_PLACE_MOUSEUP:
-		if (e->we.place.pt.x != -1) {
-			switch (e->we.place.select_proc) {
+	virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
+	{
+		if (pt.x != -1) {
+			switch (select_proc) {
+				default: NOT_REACHED();
 				case DDSP_DEMOLISH_AREA:
 				case DDSP_RAISE_AND_LEVEL_AREA:
 				case DDSP_LOWER_AND_LEVEL_AREA:
 				case DDSP_LEVEL_AREA:
-					GUIPlaceProcDragXY(e);
+					GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
 					break;
 			}
 		}
-		break;
+	}
 
-	case WE_ABORT_PLACE_OBJ:
-		w->RaiseButtons();
-		break;
+	virtual void OnPlaceObjectAbort()
+	{
+		this->RaiseButtons();
 	}
-}
+};
 
 static const Widget _terraform_widgets[] = {
 { WWT_CLOSEBOX,   RESIZE_NONE,     7,   0,  10,   0,  13, STR_00C5,                STR_018B_CLOSE_WINDOW},
@@ -305,13 +313,12 @@
 	WC_SCEN_LAND_GEN, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
 	_terraform_widgets,
-	TerraformToolbWndProc
 };
 
 void ShowTerraformToolbar(Window *link)
 {
 	if (!IsValidPlayer(_current_player)) return;
-	Window *w = AllocateWindowDescFront<Window>(&_terraform_desc, 0);
+	Window *w = AllocateWindowDescFront<TerraformToolbarWindow>(&_terraform_desc, 0);
 	if (w != NULL && link != NULL) {
 		/* Align the terraform toolbar under the main toolbar and put the linked
 		 * toolbar to left of it
@@ -339,8 +346,6 @@
 	int sizex, sizey;
 	uint h;
 
-	_generating_world = true; // used to create green terraformed land
-
 	if (_terraform_size == 1) {
 		StringID msg =
 			mode ? STR_0808_CAN_T_RAISE_LAND_HERE : STR_0809_CAN_T_LOWER_LAND_HERE;
@@ -376,8 +381,6 @@
 			}
 		} END_TILE_LOOP(tile2, sizex, sizey, tile)
 	}
-
-	_generating_world = false;
 }
 
 static void PlaceProc_RaiseBigLand(TileIndex tile)
@@ -569,122 +572,128 @@
 	}
 }
 
-static void ScenEditLandGenWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_CREATE:
-			/* XXX - lighthouse button is widget 11!! Don't forget when changing */
-			w->widget[11].tooltips = (_opt.landscape == LT_TROPIC) ? STR_028F_DEFINE_DESERT_AREA : STR_028D_PLACE_LIGHTHOUSE;
-			break;
-
-		case WE_PAINT: {
-			DrawWindowWidgets(w);
-
-			int n = _terraform_size * _terraform_size;
-			const int8 *coords = &_multi_terraform_coords[0][0];
-
-			assert(n != 0);
-			do {
-				DrawSprite(SPR_WHITE_POINT, PAL_NONE, 88 + coords[0], 55 + coords[1]);
-				coords += 2;
-			} while (--n);
-
-			if (w->IsWidgetLowered(5) || w->IsWidgetLowered(6)) // change area-size if raise/lower corner is selected
-				SetTileSelectSize(_terraform_size, _terraform_size);
-
-		} break;
+struct ScenarioEditorLandscapeGenerationWindow : Window {
+	ScenarioEditorLandscapeGenerationWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+	{
+		/* XXX - lighthouse button is widget 11!! Don't forget when changing */
+		this->widget[11].tooltips = (_opt.landscape == LT_TROPIC) ? STR_028F_DEFINE_DESERT_AREA : STR_028D_PLACE_LIGHTHOUSE;
+		this->FindWindowPlacementAndResize(desc);
+	}
 
-		case WE_KEYPRESS:
-			for (uint i = 0; i != lengthof(_editor_terraform_keycodes); i++) {
-				if (e->we.keypress.keycode == _editor_terraform_keycodes[i]) {
-					e->we.keypress.cont = false;
-					_editor_terraform_button_proc[i](w);
-					break;
-				}
-			}
-			break;
+	virtual void OnPaint() {
+		this->DrawWidgets();
 
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12:
-					_editor_terraform_button_proc[e->we.click.widget - 4](w);
-					break;
-				case 13: case 14: { // Increase/Decrease terraform size
-					int size = (e->we.click.widget == 13) ? 1 : -1;
-					w->HandleButtonClick(e->we.click.widget);
-					size += _terraform_size;
-
-					if (!IsInsideMM(size, 1, 8 + 1)) return;
-					_terraform_size = size;
+		int n = _terraform_size * _terraform_size;
+		const int8 *coords = &_multi_terraform_coords[0][0];
 
-					SndPlayFx(SND_15_BEEP);
-					w->SetDirty();
-				} break;
-				case 15: // gen random land
-					w->HandleButtonClick(15);
-					ShowCreateScenario();
-					break;
-				case 16: // Reset landscape
-					ShowQuery(
-						STR_022C_RESET_LANDSCAPE,
-						STR_RESET_LANDSCAPE_CONFIRMATION_TEXT,
-						NULL,
-						ResetLandscapeConfirmationCallback);
+		assert(n != 0);
+		do {
+			DrawSprite(SPR_WHITE_POINT, PAL_NONE, 88 + coords[0], 55 + coords[1]);
+			coords += 2;
+		} while (--n);
+
+		if (this->IsWidgetLowered(5) || this->IsWidgetLowered(6)) { // change area-size if raise/lower corner is selected
+			SetTileSelectSize(_terraform_size, _terraform_size);
+		}
+	}
+
+	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+	{
+		for (uint i = 0; i != lengthof(_editor_terraform_keycodes); i++) {
+			if (keycode == _editor_terraform_keycodes[i]) {
+				_editor_terraform_button_proc[i](this);
+				return ES_HANDLED;
+			}
+		}
+		return ES_NOT_HANDLED;
+	}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12:
+				_editor_terraform_button_proc[widget - 4](this);
+				break;
+			case 13: case 14: { // Increase/Decrease terraform size
+				int size = (widget == 13) ? 1 : -1;
+				this->HandleButtonClick(widget);
+				size += _terraform_size;
+
+				if (!IsInsideMM(size, 1, 8 + 1)) return;
+				_terraform_size = size;
+
+				SndPlayFx(SND_15_BEEP);
+				this->SetDirty();
+			} break;
+			case 15: // gen random land
+				this->HandleButtonClick(15);
+				ShowCreateScenario();
+				break;
+			case 16: // Reset landscape
+				ShowQuery(
+					STR_022C_RESET_LANDSCAPE,
+					STR_RESET_LANDSCAPE_CONFIRMATION_TEXT,
+					NULL,
+					ResetLandscapeConfirmationCallback);
+				break;
+		}
+	}
+
+	virtual void OnTimeout()
+	{
+		for (uint i = 0; i < this->widget_count; i++) {
+			if (this->IsWidgetLowered(i)) {
+				this->RaiseWidget(i);
+				this->InvalidateWidget(i);
+			}
+			if (i == 3) i = 12;
+		}
+	}
+
+	virtual void OnPlaceObject(Point pt, TileIndex tile)
+	{
+		_place_proc(tile);
+	}
+
+	virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
+	{
+		VpSelectTilesWithMethod(pt.x, pt.y, select_method);
+	}
+
+	virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
+	{
+		if (pt.x != -1) {
+			switch (select_proc) {
+				default: NOT_REACHED();
+				case DDSP_CREATE_ROCKS:
+				case DDSP_CREATE_DESERT:
+				case DDSP_CREATE_WATER:
+				case DDSP_CREATE_RIVER:
+				case DDSP_RAISE_AND_LEVEL_AREA:
+				case DDSP_LOWER_AND_LEVEL_AREA:
+				case DDSP_LEVEL_AREA:
+				case DDSP_DEMOLISH_AREA:
+					GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
 					break;
 			}
-			break;
-
-		case WE_TIMEOUT:
-			for (uint i = 0; i < w->widget_count; i++) {
-				if (w->IsWidgetLowered(i)) {
-					w->RaiseWidget(i);
-					w->InvalidateWidget(i);
-				}
-				if (i == 3) i = 12;
-			}
-			break;
-
-		case WE_PLACE_OBJ:
-			_place_proc(e->we.place.tile);
-			break;
-
-		case WE_PLACE_DRAG:
-			VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.select_method);
-			break;
+		}
+	}
 
-		case WE_PLACE_MOUSEUP:
-			if (e->we.place.pt.x != -1) {
-				switch (e->we.place.select_proc) {
-					case DDSP_CREATE_ROCKS:
-					case DDSP_CREATE_DESERT:
-					case DDSP_CREATE_WATER:
-					case DDSP_CREATE_RIVER:
-					case DDSP_RAISE_AND_LEVEL_AREA:
-					case DDSP_LOWER_AND_LEVEL_AREA:
-					case DDSP_LEVEL_AREA:
-					case DDSP_DEMOLISH_AREA:
-						GUIPlaceProcDragXY(e);
-						break;
-				}
-			}
-			break;
-
-		case WE_ABORT_PLACE_OBJ:
-			w->RaiseButtons();
-			w->SetDirty();
-			break;
+	virtual void OnPlaceObjectAbort()
+	{
+		this->RaiseButtons();
+		this->SetDirty();
 	}
-}
+};
 
 static const WindowDesc _scen_edit_land_gen_desc = {
 	WDP_AUTO, WDP_AUTO, 204, 103, 204, 103,
 	WC_SCEN_LAND_GEN, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
 	_scen_edit_land_gen_widgets,
-	ScenEditLandGenWndProc,
 };
 
 void ShowEditorTerraformToolbar()
 {
-	AllocateWindowDescFront<Window>(&_scen_edit_land_gen_desc, 0);
+	AllocateWindowDescFront<ScenarioEditorLandscapeGenerationWindow>(&_scen_edit_land_gen_desc, 0);
 }
--- a/src/tilehighlight_func.h	Mon May 19 14:14:33 2008 +0000
+++ b/src/tilehighlight_func.h	Mon May 19 15:13:58 2008 +0000
@@ -12,7 +12,7 @@
 
 typedef void PlaceProc(TileIndex tile);
 void PlaceProc_DemolishArea(TileIndex tile);
-bool GUIPlaceProcDragXY(const WindowEvent *e);
+bool GUIPlaceProcDragXY(ViewportDragDropSelectionProcess proc, TileIndex start_tile, TileIndex end_tile);
 
 bool HandlePlacePushButton(Window *w, int widget, CursorID cursor, ViewportHighlightMode mode, PlaceProc *placeproc);
 void SetObjectToPlaceWnd(CursorID icon, SpriteID pal, ViewportHighlightMode mode, Window *w);
--- a/src/timetable_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/timetable_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -36,27 +36,6 @@
 	TTV_RESIZE,
 };
 
-struct timetable_d {
-	int sel;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(timetable_d));
-
-static int GetOrderFromTimetableWndPt(Window *w, int y, const Vehicle *v)
-{
-	/*
-	 * Calculation description:
-	 * 15 = 14 (w->widget[TTV_ORDER_VIEW].top) + 1 (frame-line)
-	 * 10 = order text hight
-	 */
-	int sel = (y - 15) / 10;
-
-	if ((uint)sel >= w->vscroll.cap) return INVALID_ORDER;
-
-	sel += w->vscroll.pos;
-
-	return (sel <= v->num_orders * 2 && sel >= 0) ? sel : INVALID_ORDER;
-}
-
 void SetTimetableParams(int param1, int param2, uint32 time)
 {
 	if (_patches.timetable_in_ticks) {
@@ -68,208 +47,229 @@
 	}
 }
 
-static void DrawTimetableWindow(Window *w)
-{
-	const Vehicle *v = GetVehicle(w->window_number);
-	int selected = WP(w, timetable_d).sel;
-
-	SetVScrollCount(w, v->num_orders * 2);
+struct TimetableWindow : Window {
+	int sel_index;
 
-	if (v->owner == _local_player) {
-		if (selected == -1) {
-			w->DisableWidget(TTV_CHANGE_TIME);
-			w->DisableWidget(TTV_CLEAR_TIME);
-		} else if (selected % 2 == 1) {
-			w->EnableWidget(TTV_CHANGE_TIME);
-			w->EnableWidget(TTV_CLEAR_TIME);
-		} else {
-			const Order *order = GetVehicleOrder(v, (selected + 1) / 2);
-			bool disable = order == NULL || !order->IsType(OT_GOTO_STATION) || (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION);
-
-			w->SetWidgetDisabledState(TTV_CHANGE_TIME, disable);
-			w->SetWidgetDisabledState(TTV_CLEAR_TIME, disable);
-		}
-
-		w->EnableWidget(TTV_RESET_LATENESS);
-		w->EnableWidget(TTV_AUTOFILL);
-	} else {
-		w->DisableWidget(TTV_CHANGE_TIME);
-		w->DisableWidget(TTV_CLEAR_TIME);
-		w->DisableWidget(TTV_RESET_LATENESS);
-		w->DisableWidget(TTV_AUTOFILL);
+	TimetableWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+	{
+		this->caption_color = GetVehicle(window_number)->owner;
+		this->vscroll.cap = 8;
+		this->resize.step_height = 10;
+		this->sel_index = -1;
 	}
 
-	w->SetWidgetLoweredState(TTV_AUTOFILL, HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE));
-
-	SetDParam(0, v->index);
-	DrawWindowWidgets(w);
-
-	int y = 15;
-	int i = w->vscroll.pos;
-	VehicleOrderID order_id = (i + 1) / 2;
-	bool final_order = false;
-
-	const Order *order = GetVehicleOrder(v, order_id);
-
-	while (order != NULL) {
-		/* Don't draw anything if it extends past the end of the window. */
-		if (i - w->vscroll.pos >= w->vscroll.cap) break;
+	int GetOrderFromTimetableWndPt(int y, const Vehicle *v)
+	{
+		/*
+		 * Calculation description:
+		 * 15 = 14 (this->widget[TTV_ORDER_VIEW].top) + 1 (frame-line)
+		 * 10 = order text hight
+		 */
+		int sel = (y - 15) / 10;
 
-		if (i % 2 == 0) {
-			DrawOrderString(v, order, order_id, y, i == selected, true);
+		if ((uint)sel >= this->vscroll.cap) return INVALID_ORDER;
 
-			order_id++;
+		sel += this->vscroll.pos;
 
-			if (order_id >= v->num_orders) {
-				order = GetVehicleOrder(v, 0);
-				final_order = true;
+		return (sel <= v->num_orders * 2 && sel >= 0) ? sel : INVALID_ORDER;
+	}
+
+	void OnPaint()
+	{
+		const Vehicle *v = GetVehicle(this->window_number);
+		int selected = this->sel_index;
+
+		SetVScrollCount(this, v->num_orders * 2);
+
+		if (v->owner == _local_player) {
+			if (selected == -1) {
+				this->DisableWidget(TTV_CHANGE_TIME);
+				this->DisableWidget(TTV_CLEAR_TIME);
+			} else if (selected % 2 == 1) {
+				this->EnableWidget(TTV_CHANGE_TIME);
+				this->EnableWidget(TTV_CLEAR_TIME);
 			} else {
-				order = order->next;
-			}
-		} else {
-			StringID string;
+				const Order *order = GetVehicleOrder(v, (selected + 1) / 2);
+				bool disable = order == NULL || !order->IsType(OT_GOTO_STATION) || (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION);
 
-			if (order->travel_time == 0) {
-				string = STR_TIMETABLE_TRAVEL_NOT_TIMETABLED;
-			} else {
-				SetTimetableParams(0, 1, order->travel_time);
-				string = STR_TIMETABLE_TRAVEL_FOR;
+				this->SetWidgetDisabledState(TTV_CHANGE_TIME, disable);
+				this->SetWidgetDisabledState(TTV_CLEAR_TIME, disable);
 			}
 
-			DrawString(22, y, string, (i == selected) ? TC_WHITE : TC_BLACK);
-
-			if (final_order) break;
+			this->EnableWidget(TTV_RESET_LATENESS);
+			this->EnableWidget(TTV_AUTOFILL);
+		} else {
+			this->DisableWidget(TTV_CHANGE_TIME);
+			this->DisableWidget(TTV_CLEAR_TIME);
+			this->DisableWidget(TTV_RESET_LATENESS);
+			this->DisableWidget(TTV_AUTOFILL);
 		}
 
-		i++;
-		y += 10;
-	}
-
-	y = w->widget[TTV_SUMMARY_PANEL].top + 1;
+		this->SetWidgetLoweredState(TTV_AUTOFILL, HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE));
 
-	{
-		uint total_time = 0;
-		bool complete = true;
+		SetDParam(0, v->index);
+		this->DrawWidgets();
 
-		for (const Order *order = GetVehicleOrder(v, 0); order != NULL; order = order->next) {
-			total_time += order->travel_time + order->wait_time;
-			if (order->travel_time == 0) complete = false;
-			if (order->wait_time == 0 && order->IsType(OT_GOTO_STATION) && !(order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION)) complete = false;
+		int y = 15;
+		int i = this->vscroll.pos;
+		VehicleOrderID order_id = (i + 1) / 2;
+		bool final_order = false;
+
+		const Order *order = GetVehicleOrder(v, order_id);
+
+		while (order != NULL) {
+			/* Don't draw anything if it extends past the end of the window. */
+			if (i - this->vscroll.pos >= this->vscroll.cap) break;
+
+			if (i % 2 == 0) {
+				DrawOrderString(v, order, order_id, y, i == selected, true);
+
+				order_id++;
+
+				if (order_id >= v->num_orders) {
+					order = GetVehicleOrder(v, 0);
+					final_order = true;
+				} else {
+					order = order->next;
+				}
+			} else {
+				StringID string;
+
+				if (order->travel_time == 0) {
+					string = STR_TIMETABLE_TRAVEL_NOT_TIMETABLED;
+				} else {
+					SetTimetableParams(0, 1, order->travel_time);
+					string = STR_TIMETABLE_TRAVEL_FOR;
+				}
+
+				DrawString(22, y, string, (i == selected) ? TC_WHITE : TC_BLACK);
+
+				if (final_order) break;
+			}
+
+			i++;
+			y += 10;
 		}
 
-		if (total_time != 0) {
-			SetTimetableParams(0, 1, total_time);
-			DrawString(2, y, complete ? STR_TIMETABLE_TOTAL_TIME : STR_TIMETABLE_TOTAL_TIME_INCOMPLETE, TC_BLACK);
+		y = this->widget[TTV_SUMMARY_PANEL].top + 1;
+
+		{
+			uint total_time = 0;
+			bool complete = true;
+
+			for (const Order *order = GetVehicleOrder(v, 0); order != NULL; order = order->next) {
+				total_time += order->travel_time + order->wait_time;
+				if (order->travel_time == 0) complete = false;
+				if (order->wait_time == 0 && order->IsType(OT_GOTO_STATION) && !(order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION)) complete = false;
+			}
+
+			if (total_time != 0) {
+				SetTimetableParams(0, 1, total_time);
+				DrawString(2, y, complete ? STR_TIMETABLE_TOTAL_TIME : STR_TIMETABLE_TOTAL_TIME_INCOMPLETE, TC_BLACK);
+			}
+		}
+		y += 10;
+
+		if (v->lateness_counter == 0 || (!_patches.timetable_in_ticks && v->lateness_counter / DAY_TICKS == 0)) {
+			DrawString(2, y, STR_TIMETABLE_STATUS_ON_TIME, TC_BLACK);
+		} else {
+			SetTimetableParams(0, 1, abs(v->lateness_counter));
+			DrawString(2, y, v->lateness_counter < 0 ? STR_TIMETABLE_STATUS_EARLY : STR_TIMETABLE_STATUS_LATE, TC_BLACK);
 		}
 	}
-	y += 10;
-
-	if (v->lateness_counter == 0 || (!_patches.timetable_in_ticks && v->lateness_counter / DAY_TICKS == 0)) {
-		DrawString(2, y, STR_TIMETABLE_STATUS_ON_TIME, TC_BLACK);
-	} else {
-		SetTimetableParams(0, 1, abs(v->lateness_counter));
-		DrawString(2, y, v->lateness_counter < 0 ? STR_TIMETABLE_STATUS_EARLY : STR_TIMETABLE_STATUS_LATE, TC_BLACK);
-	}
-}
-
-static inline uint32 PackTimetableArgs(const Vehicle *v, uint selected)
-{
-	uint order_number = (selected + 1) / 2;
-	uint is_journey   = (selected % 2 == 1) ? 1 : 0;
-
-	if (order_number >= v->num_orders) order_number = 0;
-
-	return v->index | (order_number << 16) | (is_journey << 24);
-}
-
-static void TimetableWndProc(Window *w, WindowEvent *we)
-{
-	switch (we->event) {
-		case WE_PAINT:
-			DrawTimetableWindow(w);
-			break;
-
-		case WE_CLICK: {
-			const Vehicle *v = GetVehicle(w->window_number);
-
-			switch (we->we.click.widget) {
-				case TTV_ORDER_VIEW: /* Order view button */
-					ShowOrdersWindow(v);
-					break;
-
-				case TTV_TIMETABLE_PANEL: { /* Main panel. */
-					int selected = GetOrderFromTimetableWndPt(w, we->we.click.pt.y, v);
-
-					if (selected == INVALID_ORDER || selected == WP(w, timetable_d).sel) {
-						/* Deselect clicked order */
-						WP(w, timetable_d).sel = -1;
-					} else {
-						/* Select clicked order */
-						WP(w, timetable_d).sel = selected;
-					}
-				} break;
-
-				case TTV_CHANGE_TIME: { /* "Wait For" button. */
-					int selected = WP(w, timetable_d).sel;
-					VehicleOrderID real = (selected + 1) / 2;
-
-					if (real >= v->num_orders) real = 0;
 
-					const Order *order = GetVehicleOrder(v, real);
-					StringID current = STR_EMPTY;
-
-					if (order != NULL) {
-						uint time = (selected % 2 == 1) ? order->travel_time : order->wait_time;
-						if (!_patches.timetable_in_ticks) time /= DAY_TICKS;
-
-						if (time != 0) {
-							SetDParam(0, time);
-							current = STR_CONFIG_PATCHES_INT32;
-						}
-					}
-
-					ShowQueryString(current, STR_TIMETABLE_CHANGE_TIME, 31, 150, w, CS_NUMERAL);
-				} break;
-
-				case TTV_CLEAR_TIME: { /* Clear waiting time button. */
-					uint32 p1 = PackTimetableArgs(v, WP(w, timetable_d).sel);
-					DoCommandP(0, p1, 0, NULL, CMD_CHANGE_TIMETABLE | CMD_MSG(STR_CAN_T_TIMETABLE_VEHICLE));
-				} break;
-
-				case TTV_RESET_LATENESS: /* Reset the vehicle's late counter. */
-					DoCommandP(0, v->index, 0, NULL, CMD_SET_VEHICLE_ON_TIME | CMD_MSG(STR_CAN_T_TIMETABLE_VEHICLE));
-					break;
+	static inline uint32 PackTimetableArgs(const Vehicle *v, uint selected)
+	{
+		uint order_number = (selected + 1) / 2;
+		uint is_journey   = (selected % 2 == 1) ? 1 : 0;
 
-				case TTV_AUTOFILL: /* Autofill the timetable. */
-					DoCommandP(0, v->index, HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE) ? 0 : 1, NULL, CMD_AUTOFILL_TIMETABLE | CMD_MSG(STR_CAN_T_TIMETABLE_VEHICLE));
-					break;
-			}
-
-			w->SetDirty();
-		} break;
-
-		case WE_ON_EDIT_TEXT: {
-			if (we->we.edittext.str == NULL) break;
-
-			const Vehicle *v = GetVehicle(w->window_number);
-
-			uint32 p1 = PackTimetableArgs(v, WP(w, timetable_d).sel);
+		if (order_number >= v->num_orders) order_number = 0;
 
-			uint64 time = StrEmpty(we->we.edittext.str) ? 0 : strtoul(we->we.edittext.str, NULL, 10);
-			if (!_patches.timetable_in_ticks) time *= DAY_TICKS;
-
-			uint32 p2 = minu(time, MAX_UVALUE(uint16));
+		return v->index | (order_number << 16) | (is_journey << 24);
+	}
 
-			DoCommandP(0, p1, p2, NULL, CMD_CHANGE_TIMETABLE | CMD_MSG(STR_CAN_T_TIMETABLE_VEHICLE));
-		} break;
+	virtual void OnClick(Point pt, int widget)
+	{
+		const Vehicle *v = GetVehicle(this->window_number);
 
-		case WE_RESIZE:
-			/* Update the scroll + matrix */
-			w->vscroll.cap = (w->widget[TTV_TIMETABLE_PANEL].bottom - w->widget[TTV_TIMETABLE_PANEL].top) / 10;
-			break;
+		switch (widget) {
+			case TTV_ORDER_VIEW: /* Order view button */
+				ShowOrdersWindow(v);
+				break;
 
+			case TTV_TIMETABLE_PANEL: { /* Main panel. */
+				int selected = GetOrderFromTimetableWndPt(pt.y, v);
+
+				if (selected == INVALID_ORDER || selected == this->sel_index) {
+					/* Deselect clicked order */
+					this->sel_index = -1;
+				} else {
+					/* Select clicked order */
+					this->sel_index = selected;
+				}
+			} break;
+
+			case TTV_CHANGE_TIME: { /* "Wait For" button. */
+				int selected = this->sel_index;
+				VehicleOrderID real = (selected + 1) / 2;
+
+				if (real >= v->num_orders) real = 0;
+
+				const Order *order = GetVehicleOrder(v, real);
+				StringID current = STR_EMPTY;
+
+				if (order != NULL) {
+					uint time = (selected % 2 == 1) ? order->travel_time : order->wait_time;
+					if (!_patches.timetable_in_ticks) time /= DAY_TICKS;
+
+					if (time != 0) {
+						SetDParam(0, time);
+						current = STR_CONFIG_PATCHES_INT32;
+					}
+				}
+
+				ShowQueryString(current, STR_TIMETABLE_CHANGE_TIME, 31, 150, this, CS_NUMERAL);
+			} break;
+
+			case TTV_CLEAR_TIME: { /* Clear waiting time button. */
+				uint32 p1 = PackTimetableArgs(v, this->sel_index);
+				DoCommandP(0, p1, 0, NULL, CMD_CHANGE_TIMETABLE | CMD_MSG(STR_CAN_T_TIMETABLE_VEHICLE));
+			} break;
+
+			case TTV_RESET_LATENESS: /* Reset the vehicle's late counter. */
+				DoCommandP(0, v->index, 0, NULL, CMD_SET_VEHICLE_ON_TIME | CMD_MSG(STR_CAN_T_TIMETABLE_VEHICLE));
+				break;
+
+			case TTV_AUTOFILL: /* Autofill the timetable. */
+				DoCommandP(0, v->index, HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE) ? 0 : 1, NULL, CMD_AUTOFILL_TIMETABLE | CMD_MSG(STR_CAN_T_TIMETABLE_VEHICLE));
+				break;
+		}
+
+		this->SetDirty();
 	}
-}
+
+	virtual void OnQueryTextFinished(char *str)
+	{
+		if (str == NULL) return;
+
+		const Vehicle *v = GetVehicle(this->window_number);
+
+		uint32 p1 = PackTimetableArgs(v, this->sel_index);
+
+		uint64 time = StrEmpty(str) ? 0 : strtoul(str, NULL, 10);
+		if (!_patches.timetable_in_ticks) time *= DAY_TICKS;
+
+		uint32 p2 = minu(time, MAX_UVALUE(uint16));
+
+		DoCommandP(0, p1, p2, NULL, CMD_CHANGE_TIMETABLE | CMD_MSG(STR_CAN_T_TIMETABLE_VEHICLE));
+	}
+
+	virtual void OnResize(Point new_size, Point delta)
+	{
+		/* Update the scroll + matrix */
+		this->vscroll.cap = (this->widget[TTV_TIMETABLE_PANEL].bottom - this->widget[TTV_TIMETABLE_PANEL].top) / 10;
+	}
+};
 
 static const Widget _timetable_widgets[] = {
 	{   WWT_CLOSEBOX,   RESIZE_NONE,    14,     0,    10,     0,    13, STR_00C5,                   STR_018B_CLOSE_WINDOW},                // TTV_WIDGET_CLOSEBOX
@@ -298,17 +298,9 @@
 	WC_VEHICLE_TIMETABLE, WC_VEHICLE_VIEW,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
 	_timetable_widgets,
-	TimetableWndProc
 };
 
 void ShowTimetableWindow(const Vehicle *v)
 {
-	Window *w = AllocateWindowDescFront<Window>(&_timetable_desc, v->index);
-
-	if (w != NULL) {
-		w->caption_color = v->owner;
-		w->vscroll.cap = 8;
-		w->resize.step_height = 10;
-		WP(w, timetable_d).sel = -1;
-	}
+	AllocateWindowDescFront<TimetableWindow>(&_timetable_desc, v->index);
 }
--- a/src/toolbar_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/toolbar_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -46,8 +46,8 @@
 #include "table/strings.h"
 #include "table/sprites.h"
 
-static Window *PopupMainToolbMenu(Window *w, uint16 parent_button, StringID base_string, byte item_count, byte disabled_mask);
-static Window *PopupMainPlayerToolbMenu(Window *w, int main_button, int gray);
+static void PopupMainToolbMenu(Window *parent, uint16 parent_button, StringID base_string, byte item_count, byte disabled_mask = 0, int sel_index = 0, int checked_items = 0);
+static void PopupMainPlayerToolbMenu(Window *parent, int main_button, int gray);
 
 RailType _last_built_railtype;
 RoadType _last_built_roadtype;
@@ -79,13 +79,13 @@
 }
 
 /**
- * In a window with menu_d custom extension, retrieve the menu item number from a position
+ * Retrieve the menu item number from a position
  * @param w Window holding the menu items
  * @param x X coordinate of the position
  * @param y Y coordinate of the position
  * @return Index number of the menu item, or \c -1 if no valid selection under position
  */
-static int GetMenuItemIndex(const Window *w)
+static int GetMenuItemIndex(const Window *w, int item_count, int disabled_items)
 {
 	int x = _cursor.pos.x;
 	int y = _cursor.pos.y;
@@ -93,8 +93,8 @@
 	if ((x -= w->left) >= 0 && x < w->width && (y -= w->top + 1) >= 0) {
 		y /= 10;
 
-		if (y < WP(w, const menu_d).item_count &&
-				!HasBit(WP(w, const menu_d).disabled_items, y)) {
+		if (y < item_count &&
+				!HasBit(disabled_items, y)) {
 			return y;
 		}
 	}
@@ -123,9 +123,6 @@
 static void ToolbarOptionsClick(Window *w)
 {
 	uint16 x = 0;
-
-	w = PopupMainToolbMenu(w, 2, STR_02C4_GAME_OPTIONS, 14, 0);
-
 	if (HasBit(_display_opt, DO_SHOW_TOWN_NAMES))    SetBit(x,  6);
 	if (HasBit(_display_opt, DO_SHOW_STATION_NAMES)) SetBit(x,  7);
 	if (HasBit(_display_opt, DO_SHOW_SIGNS))         SetBit(x,  8);
@@ -134,7 +131,8 @@
 	if (HasBit(_display_opt, DO_FULL_DETAIL))        SetBit(x, 11);
 	if (IsTransparencySet(TO_HOUSES))                SetBit(x, 12);
 	if (IsTransparencySet(TO_SIGNS))                 SetBit(x, 13);
-	WP(w, menu_d).checked_items = x;
+
+	PopupMainToolbMenu(w, 2, STR_02C4_GAME_OPTIONS, 14, 0, 0, x);
 }
 
 static void MenuClickSettings(int index)
@@ -162,12 +160,12 @@
 
 static void ToolbarSaveClick(Window *w)
 {
-	PopupMainToolbMenu(w, 3, STR_015C_SAVE_GAME, 4, 0);
+	PopupMainToolbMenu(w, 3, STR_015C_SAVE_GAME, 4);
 }
 
 static void ToolbarScenSaveOrLoad(Window *w)
 {
-	PopupMainToolbMenu(w, 3, STR_0292_SAVE_SCENARIO, 6, 0);
+	PopupMainToolbMenu(w, 3, STR_0292_SAVE_SCENARIO, 6);
 }
 
 static void MenuClickSaveLoad(int index)
@@ -194,7 +192,7 @@
 
 static void ToolbarMapClick(Window *w)
 {
-	PopupMainToolbMenu(w, 4, STR_02DE_MAP_OF_WORLD, 3, 0);
+	PopupMainToolbMenu(w, 4, STR_02DE_MAP_OF_WORLD, 3);
 }
 
 static void MenuClickMap(int index)
@@ -220,7 +218,7 @@
 
 static void ToolbarTownClick(Window *w)
 {
-	PopupMainToolbMenu(w, 5, STR_02BB_TOWN_DIRECTORY, 1, 0);
+	PopupMainToolbMenu(w, 5, STR_02BB_TOWN_DIRECTORY, 1);
 }
 
 static void MenuClickTown(int index)
@@ -232,7 +230,7 @@
 
 static void ToolbarSubsidiesClick(Window *w)
 {
-	PopupMainToolbMenu(w, 6, STR_02DD_SUBSIDIES, 1, 0);
+	PopupMainToolbMenu(w, 6, STR_02DD_SUBSIDIES, 1);
 }
 
 static void MenuClickSubsidies(int index)
@@ -285,7 +283,7 @@
 
 static void ToolbarGraphsClick(Window *w)
 {
-	PopupMainToolbMenu(w, 10, STR_0154_OPERATING_PROFIT_GRAPH, 6, 0);
+	PopupMainToolbMenu(w, 10, STR_0154_OPERATING_PROFIT_GRAPH, 6);
 }
 
 static void MenuClickGraphs(int index)
@@ -304,7 +302,7 @@
 
 static void ToolbarLeagueClick(Window *w)
 {
-	PopupMainToolbMenu(w, 11, STR_015A_COMPANY_LEAGUE_TABLE, 2, 0);
+	PopupMainToolbMenu(w, 11, STR_015A_COMPANY_LEAGUE_TABLE, 2);
 }
 
 static void MenuClickLeague(int index)
@@ -416,8 +414,7 @@
 static void ToolbarBuildRailClick(Window *w)
 {
 	const Player *p = GetPlayer(_local_player);
-	Window *w2 = PopupMainToolbMenu(w, 19, STR_1015_RAILROAD_CONSTRUCTION, RAILTYPE_END, ~p->avail_railtypes);
-	WP(w2, menu_d).sel_index = _last_built_railtype;
+	PopupMainToolbMenu(w, 19, STR_1015_RAILROAD_CONSTRUCTION, RAILTYPE_END, ~p->avail_railtypes, _last_built_railtype);
 }
 
 static void MenuClickBuildRail(int index)
@@ -432,8 +429,7 @@
 {
 	const Player *p = GetPlayer(_local_player);
 	/* The standard road button is *always* available */
-	Window *w2 = PopupMainToolbMenu(w, 20, STR_180A_ROAD_CONSTRUCTION, 2, ~(p->avail_roadtypes | ROADTYPES_ROAD));
-	WP(w2, menu_d).sel_index = _last_built_roadtype;
+	PopupMainToolbMenu(w, 20, STR_180A_ROAD_CONSTRUCTION, 2, ~(p->avail_roadtypes | ROADTYPES_ROAD), _last_built_roadtype);
 }
 
 static void MenuClickBuildRoad(int index)
@@ -446,7 +442,7 @@
 
 static void ToolbarBuildWaterClick(Window *w)
 {
-	PopupMainToolbMenu(w, 21, STR_9800_DOCK_CONSTRUCTION, 1, 0);
+	PopupMainToolbMenu(w, 21, STR_9800_DOCK_CONSTRUCTION, 1);
 }
 
 static void MenuClickBuildWater(int index)
@@ -458,7 +454,7 @@
 
 static void ToolbarBuildAirClick(Window *w)
 {
-	PopupMainToolbMenu(w, 22, STR_A01D_AIRPORT_CONSTRUCTION, 1, 0);
+	PopupMainToolbMenu(w, 22, STR_A01D_AIRPORT_CONSTRUCTION, 1);
 }
 
 static void MenuClickBuildAir(int index)
@@ -470,7 +466,7 @@
 
 static void ToolbarForestClick(Window *w)
 {
-	PopupMainToolbMenu(w, 23, STR_LANDSCAPING, 3, 0);
+	PopupMainToolbMenu(w, 23, STR_LANDSCAPING, 3);
 }
 
 static void MenuClickForest(int index)
@@ -486,7 +482,7 @@
 
 static void ToolbarMusicClick(Window *w)
 {
-	PopupMainToolbMenu(w, 24, STR_01D3_SOUND_MUSIC, 1, 0);
+	PopupMainToolbMenu(w, 24, STR_01D3_SOUND_MUSIC, 1);
 }
 
 static void MenuClickMusicWindow(int index)
@@ -498,7 +494,7 @@
 
 static void ToolbarNewspaperClick(Window *w)
 {
-	PopupMainToolbMenu(w, 25, STR_0200_LAST_MESSAGE_NEWS_REPORT, 3, 0);
+	PopupMainToolbMenu(w, 25, STR_0200_LAST_MESSAGE_NEWS_REPORT, 3);
 }
 
 static void MenuClickNewspaper(int index)
@@ -514,7 +510,7 @@
 
 static void ToolbarHelpClick(Window *w)
 {
-	PopupMainToolbMenu(w, 26, STR_02D5_LAND_BLOCK_INFO, 7, 0);
+	PopupMainToolbMenu(w, 26, STR_02D5_LAND_BLOCK_INFO, 7);
 }
 
 static void MenuClickSmallScreenshot()
@@ -570,7 +566,7 @@
 static void ToolbarScenMapTownDir(Window *w)
 {
 	/* Scenario editor button, *hack*hack* use different button to activate */
-	PopupMainToolbMenu(w, 8 | (17 << 8), STR_02DE_MAP_OF_WORLD, 4, 0);
+	PopupMainToolbMenu(w, 8 | (17 << 8), STR_02DE_MAP_OF_WORLD, 4);
 }
 
 static void ToolbarScenZoomIn(Window *w)
@@ -623,7 +619,7 @@
 {
 	w->HandleButtonClick(15);
 	SndPlayFx(SND_15_BEEP);
-	ShowBuildTreesScenToolbar();
+	ShowBuildTreesToolbar();
 }
 
 static void ToolbarScenPlaceSign(Window *w)
@@ -672,137 +668,155 @@
 	ToolbarHelpClick,
 };
 
-static void MainToolbarWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT:
-			/* Draw brown-red toolbar bg. */
-			GfxFillRect(0, 0, w->width - 1, w->height - 1, 0xB2);
-			GfxFillRect(0, 0, w->width - 1, w->height - 1, 0xB4 | (1 << PALETTE_MODIFIER_GREYOUT));
-
-			/* If spectator, disable all construction buttons
-			* ie : Build road, rail, ships, airports and landscaping
-			* Since enabled state is the default, just disable when needed */
-			w->SetWidgetsDisabledState(_current_player == PLAYER_SPECTATOR, 19, 20, 21, 22, 23, WIDGET_LIST_END);
-			/* disable company list drop downs, if there are no companies */
-			w->SetWidgetsDisabledState(ActivePlayerCount() == 0, 7, 8, 13, 14, 15, 16, WIDGET_LIST_END);
-
-			w->SetWidgetDisabledState(19, !CanBuildVehicleInfrastructure(VEH_TRAIN));
-			w->SetWidgetDisabledState(22, !CanBuildVehicleInfrastructure(VEH_AIRCRAFT));
-
-			DrawWindowWidgets(w);
-			break;
-
-		case WE_CLICK:
-			if (_game_mode != GM_MENU && !w->IsWidgetDisabled(e->we.click.widget)) _toolbar_button_procs[e->we.click.widget](w);
-			break;
+struct MainToolbarWindow : Window {
+	MainToolbarWindow(const WindowDesc *desc) : Window(desc)
+	{
+		this->SetWidgetDisabledState(0, _networking && !_network_server); // if not server, disable pause button
+		this->SetWidgetDisabledState(1, _networking); // if networking, disable fast-forward button
 
-		case WE_KEYPRESS:
-			switch (e->we.keypress.keycode) {
-				case WKC_F1: case WKC_PAUSE: ToolbarPauseClick(w); break;
-				case WKC_F2: ShowGameOptions(); break;
-				case WKC_F3: MenuClickSaveLoad(0); break;
-				case WKC_F4: ShowSmallMap(); break;
-				case WKC_F5: ShowTownDirectory(); break;
-				case WKC_F6: ShowSubsidiesList(); break;
-				case WKC_F7: ShowPlayerStations(_local_player); break;
-				case WKC_F8: ShowPlayerFinances(_local_player); break;
-				case WKC_F9: ShowPlayerCompany(_local_player); break;
-				case WKC_F10: ShowOperatingProfitGraph(); break;
-				case WKC_F11: ShowCompanyLeagueTable(); break;
-				case WKC_F12: ShowBuildIndustryWindow(); break;
-				case WKC_SHIFT | WKC_F1: ShowVehicleListWindow(_local_player, VEH_TRAIN); break;
-				case WKC_SHIFT | WKC_F2: ShowVehicleListWindow(_local_player, VEH_ROAD); break;
-				case WKC_SHIFT | WKC_F3: ShowVehicleListWindow(_local_player, VEH_SHIP); break;
-				case WKC_SHIFT | WKC_F4: ShowVehicleListWindow(_local_player, VEH_AIRCRAFT); break;
-				case WKC_NUM_PLUS: // Fall through
-				case WKC_EQUALS: // Fall through
-				case WKC_SHIFT | WKC_EQUALS: // Fall through
-				case WKC_SHIFT | WKC_F5: ToolbarZoomInClick(w); break;
-				case WKC_NUM_MINUS: // Fall through
-				case WKC_MINUS: // Fall through
-				case WKC_SHIFT | WKC_MINUS: // Fall through
-				case WKC_SHIFT | WKC_F6: ToolbarZoomOutClick(w); break;
-				case WKC_SHIFT | WKC_F7: if (CanBuildVehicleInfrastructure(VEH_TRAIN)) ShowBuildRailToolbar(_last_built_railtype, -1); break;
-				case WKC_SHIFT | WKC_F8: ShowBuildRoadToolbar(_last_built_roadtype); break;
-				case WKC_SHIFT | WKC_F9: ShowBuildDocksToolbar(); break;
-				case WKC_SHIFT | WKC_F10: if (CanBuildVehicleInfrastructure(VEH_AIRCRAFT)) ShowBuildAirToolbar(); break;
-				case WKC_SHIFT | WKC_F11: ShowBuildTreesToolbar(); break;
-				case WKC_SHIFT | WKC_F12: ShowMusicWindow(); break;
-				case WKC_CTRL  | 'S': MenuClickSmallScreenshot(); break;
-				case WKC_CTRL  | 'G': MenuClickWorldScreenshot(); break;
-				case WKC_CTRL | WKC_ALT | 'C': if (!_networking) ShowCheatWindow(); break;
-				case 'A': if (CanBuildVehicleInfrastructure(VEH_TRAIN)) ShowBuildRailToolbar(_last_built_railtype, 4); break; // Invoke Autorail
-				case 'L': ShowTerraformToolbar(); break;
-				case 'M': ShowSmallMap(); break;
-				case 'V': ShowExtraViewPortWindow(); break;
-				default: return;
-			}
-			e->we.keypress.cont = false;
-			break;
+		CLRBITS(this->flags4, WF_WHITE_BORDER_MASK);
 
-		case WE_PLACE_OBJ:
-			_place_proc(e->we.place.tile);
-			break;
+		this->FindWindowPlacementAndResize(desc);
+		PositionMainToolbar(this);
+		DoZoomInOutWindow(ZOOM_NONE, this);
+	}
 
-		case WE_ABORT_PLACE_OBJ:
-			w->RaiseWidget(25);
-			w->SetDirty();
-			break;
+	virtual void OnPaint()
+	{
+		/* Draw brown-red toolbar bg. */
+		GfxFillRect(0, 0, this->width - 1, this->height - 1, 0xB2);
+		GfxFillRect(0, 0, this->width - 1, this->height - 1, 0xB4 | (1 << PALETTE_MODIFIER_GREYOUT));
 
-		case WE_TICK:
-			if (w->IsWidgetLowered(0) != !!_pause_game) {
-				w->ToggleWidgetLoweredState(0);
-				w->InvalidateWidget(0);
+		/* If spectator, disable all construction buttons
+		* ie : Build road, rail, ships, airports and landscaping
+		* Since enabled state is the default, just disable when needed */
+		this->SetWidgetsDisabledState(_current_player == PLAYER_SPECTATOR, 19, 20, 21, 22, 23, WIDGET_LIST_END);
+		/* disable company list drop downs, if there are no companies */
+		this->SetWidgetsDisabledState(ActivePlayerCount() == 0, 7, 8, 13, 14, 15, 16, WIDGET_LIST_END);
+
+		this->SetWidgetDisabledState(19, !CanBuildVehicleInfrastructure(VEH_TRAIN));
+		this->SetWidgetDisabledState(22, !CanBuildVehicleInfrastructure(VEH_AIRCRAFT));
+
+		this->DrawWidgets();
+	}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		if (_game_mode != GM_MENU && !this->IsWidgetDisabled(widget)) _toolbar_button_procs[widget](this);
+	}
+
+	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+	{
+		switch (keycode) {
+			case WKC_F1: case WKC_PAUSE: ToolbarPauseClick(this); break;
+			case WKC_F2: ShowGameOptions(); break;
+			case WKC_F3: MenuClickSaveLoad(0); break;
+			case WKC_F4: ShowSmallMap(); break;
+			case WKC_F5: ShowTownDirectory(); break;
+			case WKC_F6: ShowSubsidiesList(); break;
+			case WKC_F7: ShowPlayerStations(_local_player); break;
+			case WKC_F8: ShowPlayerFinances(_local_player); break;
+			case WKC_F9: ShowPlayerCompany(_local_player); break;
+			case WKC_F10: ShowOperatingProfitGraph(); break;
+			case WKC_F11: ShowCompanyLeagueTable(); break;
+			case WKC_F12: ShowBuildIndustryWindow(); break;
+			case WKC_SHIFT | WKC_F1: ShowVehicleListWindow(_local_player, VEH_TRAIN); break;
+			case WKC_SHIFT | WKC_F2: ShowVehicleListWindow(_local_player, VEH_ROAD); break;
+			case WKC_SHIFT | WKC_F3: ShowVehicleListWindow(_local_player, VEH_SHIP); break;
+			case WKC_SHIFT | WKC_F4: ShowVehicleListWindow(_local_player, VEH_AIRCRAFT); break;
+			case WKC_NUM_PLUS: // Fall through
+			case WKC_EQUALS: // Fall through
+			case WKC_SHIFT | WKC_EQUALS: // Fall through
+			case WKC_SHIFT | WKC_F5: ToolbarZoomInClick(this); break;
+			case WKC_NUM_MINUS: // Fall through
+			case WKC_MINUS: // Fall through
+			case WKC_SHIFT | WKC_MINUS: // Fall through
+			case WKC_SHIFT | WKC_F6: ToolbarZoomOutClick(this); break;
+			case WKC_SHIFT | WKC_F7: if (CanBuildVehicleInfrastructure(VEH_TRAIN)) ShowBuildRailToolbar(_last_built_railtype, -1); break;
+			case WKC_SHIFT | WKC_F8: ShowBuildRoadToolbar(_last_built_roadtype); break;
+			case WKC_SHIFT | WKC_F9: ShowBuildDocksToolbar(); break;
+			case WKC_SHIFT | WKC_F10: if (CanBuildVehicleInfrastructure(VEH_AIRCRAFT)) ShowBuildAirToolbar(); break;
+			case WKC_SHIFT | WKC_F11: ShowBuildTreesToolbar(); break;
+			case WKC_SHIFT | WKC_F12: ShowMusicWindow(); break;
+			case WKC_CTRL  | 'S': MenuClickSmallScreenshot(); break;
+			case WKC_CTRL  | 'G': MenuClickWorldScreenshot(); break;
+			case WKC_CTRL | WKC_ALT | 'C': if (!_networking) ShowCheatWindow(); break;
+			case 'A': if (CanBuildVehicleInfrastructure(VEH_TRAIN)) ShowBuildRailToolbar(_last_built_railtype, 4); break; // Invoke Autorail
+			case 'L': ShowTerraformToolbar(); break;
+			case 'M': ShowSmallMap(); break;
+			case 'V': ShowExtraViewPortWindow(); break;
+			default: return ES_NOT_HANDLED;
+		}
+		return ES_HANDLED;
+	}
+
+	virtual void OnPlaceObject(Point pt, TileIndex tile)
+	{
+		_place_proc(tile);
+	}
+
+	virtual void OnPlaceObjectAbort()
+	{
+		this->RaiseWidget(25);
+		this->SetDirty();
+	}
+
+	virtual void OnTick()
+	{
+		if (this->IsWidgetLowered(0) != !!_pause_game) {
+			this->ToggleWidgetLoweredState(0);
+			this->InvalidateWidget(0);
+		}
+
+		if (this->IsWidgetLowered(1) != !!_fast_forward) {
+			this->ToggleWidgetLoweredState(1);
+			this->InvalidateWidget(1);
+		}
+	}
+
+	virtual void OnResize(Point new_size, Point delta)
+	{
+		/* There are 27 buttons plus some spacings if the space allows it */
+		uint button_width;
+		uint spacing;
+		if (this->width >= 27 * 22) {
+			button_width = 22;
+			spacing = this->width - (27 * button_width);
+		} else {
+			button_width = this->width / 27;
+			spacing = 0;
+		}
+		uint extra_spacing_at[] = { 4, 8, 13, 17, 19, 24, 0 };
+
+		for (uint i = 0, x = 0, j = 0; i < 27; i++) {
+			if (extra_spacing_at[j] == i) {
+				j++;
+				uint add = spacing / (lengthof(extra_spacing_at) - j);
+				spacing -= add;
+				x += add;
 			}
 
-			if (w->IsWidgetLowered(1) != !!_fast_forward) {
-				w->ToggleWidgetLoweredState(1);
-				w->InvalidateWidget(1);
-			}
-			break;
-
-		case WE_RESIZE: {
-			/* There are 27 buttons plus some spacings if the space allows it */
-			uint button_width;
-			uint spacing;
-			if (w->width >= 27 * 22) {
-				button_width = 22;
-				spacing = w->width - (27 * button_width);
-			} else {
-				button_width = w->width / 27;
-				spacing = 0;
-			}
-			uint extra_spacing_at[] = { 4, 8, 13, 17, 19, 24, 0 };
+			this->widget[i].left = x;
+			x += (spacing != 0) ? button_width : (this->width - x) / (27 - i);
+			this->widget[i].right = x - 1;
+		}
+	}
 
-			for (uint i = 0, x = 0, j = 0; i < 27; i++) {
-				if (extra_spacing_at[j] == i) {
-					j++;
-					uint add = spacing / (lengthof(extra_spacing_at) - j);
-					spacing -= add;
-					x += add;
-				}
-
-				w->widget[i].left = x;
-				x += (spacing != 0) ? button_width : (w->width - x) / (27 - i);
-				w->widget[i].right = x - 1;
+	virtual void OnTimeout()
+	{
+		for (uint i = 2; i < this->widget_count; i++) {
+			if (this->IsWidgetLowered(i)) {
+				this->RaiseWidget(i);
+				this->InvalidateWidget(i);
 			}
-		} break;
+		}
+	}
 
-		case WE_TIMEOUT:
-			for (uint i = 2; i < w->widget_count; i++) {
-				if (w->IsWidgetLowered(i)) {
-					w->RaiseWidget(i);
-					w->InvalidateWidget(i);
-				}
-			}
-			break;
-
-		case WE_INVALIDATE_DATA:
-			if (FindWindowById(WC_MAIN_WINDOW, 0) != NULL) HandleZoomMessage(w, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, 17, 18);
-			break;
+	virtual void OnInvalidateData(int data)
+	{
+		if (FindWindowById(WC_MAIN_WINDOW, 0) != NULL) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, 17, 18);
 	}
-}
+};
 
 static const Widget _toolb_normal_widgets[] = {
 {     WWT_IMGBTN,   RESIZE_LEFT,    14,     0,     0,     0,    21, SPR_IMG_PAUSE,           STR_0171_PAUSE_GAME},
@@ -846,7 +860,6 @@
 	WC_MAIN_TOOLBAR, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET,
 	_toolb_normal_widgets,
-	MainToolbarWndProc
 };
 
 
@@ -882,163 +895,176 @@
 	ToolbarHelpClick,
 };
 
-static void ScenEditToolbarWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT:
-			w->SetWidgetDisabledState(6, _patches_newgame.starting_year <= MIN_YEAR);
-			w->SetWidgetDisabledState(7, _patches_newgame.starting_year >= MAX_YEAR);
+struct ScenarioEditorToolbarWindow : Window {
+	ScenarioEditorToolbarWindow(const WindowDesc *desc) : Window(desc)
+	{
+		CLRBITS(this->flags4, WF_WHITE_BORDER_MASK);
 
-			/* Draw brown-red toolbar bg. */
-			GfxFillRect(0, 0, w->width - 1, w->height - 1, 0xB2);
-			GfxFillRect(0, 0, w->width - 1, w->height - 1, 0xB4 | (1 << PALETTE_MODIFIER_GREYOUT));
-
-			DrawWindowWidgets(w);
+		this->FindWindowPlacementAndResize(desc);
+		PositionMainToolbar(this);
+		DoZoomInOutWindow(ZOOM_NONE, this);
+	}
 
-			SetDParam(0, ConvertYMDToDate(_patches_newgame.starting_year, 0, 1));
-			DrawStringCenteredTruncated(w->widget[6].right, w->widget[7].left, 6, STR_00AF, TC_FROMSTRING);
+	virtual void OnPaint()
+	{
+		this->SetWidgetDisabledState(6, _patches_newgame.starting_year <= MIN_YEAR);
+		this->SetWidgetDisabledState(7, _patches_newgame.starting_year >= MAX_YEAR);
 
-			/* We hide this panel when the toolbar space gets too small */
-			if (w->widget[4].left != w->widget[4].right) {
-				DrawStringCenteredTruncated(w->widget[4].left + 1, w->widget[4].right - 1,  1, STR_0221_OPENTTD, TC_FROMSTRING);
-				DrawStringCenteredTruncated(w->widget[4].left + 1, w->widget[4].right - 1, 11, STR_0222_SCENARIO_EDITOR, TC_FROMSTRING);
+		/* Draw brown-red toolbar bg. */
+		GfxFillRect(0, 0, this->width - 1, this->height - 1, 0xB2);
+		GfxFillRect(0, 0, this->width - 1, this->height - 1, 0xB4 | (1 << PALETTE_MODIFIER_GREYOUT));
+
+		this->DrawWidgets();
+
+		SetDParam(0, ConvertYMDToDate(_patches_newgame.starting_year, 0, 1));
+		DrawStringCenteredTruncated(this->widget[6].right, this->widget[7].left, 6, STR_00AF, TC_FROMSTRING);
+
+		/* We hide this panel when the toolbar space gets too small */
+		if (this->widget[4].left != this->widget[4].right) {
+			DrawStringCenteredTruncated(this->widget[4].left + 1, this->widget[4].right - 1,  1, STR_0221_OPENTTD, TC_FROMSTRING);
+			DrawStringCenteredTruncated(this->widget[4].left + 1, this->widget[4].right - 1, 11, STR_0222_SCENARIO_EDITOR, TC_FROMSTRING);
+		}
+	}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		if (_game_mode == GM_MENU) return;
+		_scen_toolbar_button_procs[widget](this);
+	}
+
+	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+	{
+		switch (keycode) {
+			case WKC_F1: case WKC_PAUSE: ToolbarPauseClick(this); break;
+			case WKC_F2: ShowGameOptions(); break;
+			case WKC_F3: MenuClickSaveLoad(0); break;
+			case WKC_F4: ToolbarScenGenLand(this); break;
+			case WKC_F5: ToolbarScenGenTown(this); break;
+			case WKC_F6: ToolbarScenGenIndustry(this); break;
+			case WKC_F7: ToolbarScenBuildRoad(this); break;
+			case WKC_F8: ToolbarScenPlantTrees(this); break;
+			case WKC_F9: ToolbarScenPlaceSign(this); break;
+			case WKC_F10: ShowMusicWindow(); break;
+			case WKC_F11: PlaceLandBlockInfo(); break;
+			case WKC_CTRL | 'S': MenuClickSmallScreenshot(); break;
+			case WKC_CTRL | 'G': MenuClickWorldScreenshot(); break;
+
+			/* those following are all fall through */
+			case WKC_NUM_PLUS:
+			case WKC_EQUALS:
+			case WKC_SHIFT | WKC_EQUALS:
+			case WKC_SHIFT | WKC_F5: ToolbarZoomInClick(this); break;
+
+			/* those following are all fall through */
+			case WKC_NUM_MINUS:
+			case WKC_MINUS:
+			case WKC_SHIFT | WKC_MINUS:
+			case WKC_SHIFT | WKC_F6: ToolbarZoomOutClick(this); break;
+
+			case 'L': ShowEditorTerraformToolbar(); break;
+			case 'M': ShowSmallMap(); break;
+			case 'V': ShowExtraViewPortWindow(); break;
+			default: return ES_NOT_HANDLED;
+		}
+		return ES_HANDLED;
+	}
+
+	virtual void OnPlaceObject(Point pt, TileIndex tile)
+	{
+		_place_proc(tile);
+	}
+
+	virtual void OnPlaceObjectAbort()
+	{
+		this->RaiseWidget(25);
+		this->SetDirty();
+	}
+
+	virtual void OnResize(Point new_size, Point delta)
+	{
+		/* There are 15 buttons plus some spacings if the space allows it.
+		 * Furthermore there are two panels of which one is non - essential
+		 * and that one can be removed is the space is too small. */
+		uint buttons_width;
+		uint spacing;
+
+		static int normal_min_width = (15 * 22) + (2 * 130);
+		static int one_less_panel_min_width = (15 * 22) + 130;
+
+		if (this->width >= one_less_panel_min_width) {
+			buttons_width = 15 * 22;
+			spacing = this->width - ((this->width >= normal_min_width) ? normal_min_width : one_less_panel_min_width);
+		} else {
+			buttons_width = this->width - 130;
+			spacing = 0;
+		}
+		uint extra_spacing_at[] = { 3, 4, 7, 8, 10, 16, 0 };
+
+		/* Yes, it defines about 27 widgets for this toolbar */
+		for (uint i = 0, x = 0, j = 0, b = 0; i < 27; i++) {
+			switch (i) {
+				case 4:
+					this->widget[i].left = x;
+					if (this->width < normal_min_width) {
+						this->widget[i].right = x;
+						j++;
+						continue;
+					}
+
+					x += 130;
+					this->widget[i].right = x - 1;
+					break;
+
+				case 5: {
+					int offset = x - this->widget[i].left;
+					this->widget[i + 1].left  += offset;
+					this->widget[i + 1].right += offset;
+					this->widget[i + 2].left  += offset;
+					this->widget[i + 2].right += offset;
+					this->widget[i].left = x;
+					x += 130;
+					this->widget[i].right = x - 1;
+					i += 2;
+				} break;
+
+				default:
+					if (this->widget[i].bottom == 0) continue;
+
+					this->widget[i].left = x;
+					x += buttons_width / (15 - b);
+					this->widget[i].right = x - 1;
+					buttons_width -= buttons_width / (15 - b);
+					b++;
+					break;
 			}
 
-			break;
-
-		case WE_CLICK:
-			if (_game_mode == GM_MENU) return;
-			_scen_toolbar_button_procs[e->we.click.widget](w);
-			break;
-
-		case WE_KEYPRESS:
-			switch (e->we.keypress.keycode) {
-				case WKC_F1: case WKC_PAUSE: ToolbarPauseClick(w); break;
-				case WKC_F2: ShowGameOptions(); break;
-				case WKC_F3: MenuClickSaveLoad(0); break;
-				case WKC_F4: ToolbarScenGenLand(w); break;
-				case WKC_F5: ToolbarScenGenTown(w); break;
-				case WKC_F6: ToolbarScenGenIndustry(w); break;
-				case WKC_F7: ToolbarScenBuildRoad(w); break;
-				case WKC_F8: ToolbarScenPlantTrees(w); break;
-				case WKC_F9: ToolbarScenPlaceSign(w); break;
-				case WKC_F10: ShowMusicWindow(); break;
-				case WKC_F11: PlaceLandBlockInfo(); break;
-				case WKC_CTRL | 'S': MenuClickSmallScreenshot(); break;
-				case WKC_CTRL | 'G': MenuClickWorldScreenshot(); break;
-
-				/* those following are all fall through */
-				case WKC_NUM_PLUS:
-				case WKC_EQUALS:
-				case WKC_SHIFT | WKC_EQUALS:
-				case WKC_SHIFT | WKC_F5: ToolbarZoomInClick(w); break;
-
-				/* those following are all fall through */
-				case WKC_NUM_MINUS:
-				case WKC_MINUS:
-				case WKC_SHIFT | WKC_MINUS:
-				case WKC_SHIFT | WKC_F6: ToolbarZoomOutClick(w); break;
-
-				case 'L': ShowEditorTerraformToolbar(); break;
-				case 'M': ShowSmallMap(); break;
-				case 'V': ShowExtraViewPortWindow(); break;
-				default: return;
+			if (extra_spacing_at[j] == i) {
+				j++;
+				uint add = spacing / (lengthof(extra_spacing_at) - j);
+				spacing -= add;
+				x += add;
 			}
-			e->we.keypress.cont = false;
-			break;
-
-		case WE_PLACE_OBJ:
-			_place_proc(e->we.place.tile);
-			break;
-
-		case WE_ABORT_PLACE_OBJ:
-			w->RaiseWidget(25);
-			w->SetDirty();
-			break;
-
-		case WE_RESIZE: {
-			/* There are 15 buttons plus some spacings if the space allows it.
-			* Furthermore there are two panels of which one is non - essential
-			* and that one can be removed is the space is too small. */
-			uint buttons_width;
-			uint spacing;
-
-			static int normal_min_width = (15 * 22) + (2 * 130);
-			static int one_less_panel_min_width = (15 * 22) + 130;
+		}
+	}
 
-			if (w->width >= one_less_panel_min_width) {
-				buttons_width = 15 * 22;
-				spacing = w->width - ((w->width >= normal_min_width) ? normal_min_width : one_less_panel_min_width);
-			} else {
-				buttons_width = w->width - 130;
-				spacing = 0;
-			}
-			uint extra_spacing_at[] = { 3, 4, 7, 8, 10, 16, 0 };
-
-			/* Yes, it defines about 27 widgets for this toolbar */
-			for (uint i = 0, x = 0, j = 0, b = 0; i < 27; i++) {
-				switch (i) {
-					case 4:
-						w->widget[i].left = x;
-						if (w->width < normal_min_width) {
-							w->widget[i].right = x;
-							j++;
-							continue;
-						}
-
-						x += 130;
-						w->widget[i].right = x - 1;
-						break;
-
-					case 5: {
-						int offset = x - w->widget[i].left;
-						w->widget[i + 1].left  += offset;
-						w->widget[i + 1].right += offset;
-						w->widget[i + 2].left  += offset;
-						w->widget[i + 2].right += offset;
-						w->widget[i].left = x;
-						x += 130;
-						w->widget[i].right = x - 1;
-						i += 2;
-					} break;
+	virtual void OnTick()
+	{
+		if (this->IsWidgetLowered(0) != !!_pause_game) {
+			this->ToggleWidgetLoweredState(0);
+			this->SetDirty();
+		}
 
-					default:
-						if (w->widget[i].bottom == 0) continue;
-
-						w->widget[i].left = x;
-						x += buttons_width / (15 - b);
-						w->widget[i].right = x - 1;
-						buttons_width -= buttons_width / (15 - b);
-						b++;
-						break;
-				}
+		if (this->IsWidgetLowered(1) != !!_fast_forward) {
+			this->ToggleWidgetLoweredState(1);
+			this->SetDirty();
+		}
+	}
 
-				if (extra_spacing_at[j] == i) {
-					j++;
-					uint add = spacing / (lengthof(extra_spacing_at) - j);
-					spacing -= add;
-					x += add;
-				}
-			}
-		} break;
-
-		case WE_TICK:
-			if (w->IsWidgetLowered(0) != !!_pause_game) {
-				w->ToggleWidgetLoweredState(0);
-				w->SetDirty();
-			}
-
-			if (w->IsWidgetLowered(1) != !!_fast_forward) {
-				w->ToggleWidgetLoweredState(1);
-				w->SetDirty();
-			}
-			break;
-
-		case WE_INVALIDATE_DATA:
-			HandleZoomMessage(w, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, 9, 10);
-			break;
+	virtual void OnInvalidateData(int data)
+	{
+		if (FindWindowById(WC_MAIN_WINDOW, 0) != NULL) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, 17, 18);
 	}
-}
+};
 
 static const Widget _toolb_scen_widgets[] = {
 {  WWT_IMGBTN, RESIZE_LEFT, 14,   0,   0,  0, 21, SPR_IMG_PAUSE,       STR_0171_PAUSE_GAME},
@@ -1082,7 +1108,6 @@
 	WC_MAIN_TOOLBAR, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
 	_toolb_scen_widgets,
-	ScenEditToolbarWndProc
 };
 
 /* --- Rendering/handling the drop down menus --- */
@@ -1119,71 +1144,77 @@
 	MenuClickHelp,        /* 26 */
 };
 
-static void MenuWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_CREATE:
-			w->widget[0].right = w->width - 1;
-			break;
-
-		case WE_PAINT: {
-			byte count = WP(w, menu_d).item_count;
-			byte sel = WP(w, menu_d).sel_index;
-			uint16 chk = WP(w, menu_d).checked_items;
-			StringID string = WP(w, menu_d).string_id;
-			byte dis = WP(w, menu_d).disabled_items;
-
-			DrawWindowWidgets(w);
+struct ToolbarMenuWindow : Window {
+	int item_count;
+	int sel_index;
+	int main_button;
+	int action_id;
+	int checked_items;
+	int disabled_items;
+	StringID base_string;
 
-			int x = 1;
-			int y = 1;
-
-			for (; count != 0; count--, string++, sel--) {
-				TextColour color = HasBit(dis, 0) ? TC_GREY : (sel == 0) ? TC_WHITE : TC_BLACK;
-				if (sel == 0) GfxFillRect(x, y, x + w->width - 3, y + 9, 0);
-
-				if (HasBit(chk, 0)) DrawString(x + 2, y, STR_CHECKMARK, color);
-				DrawString(x + 2, y, string, color);
+	ToolbarMenuWindow(int x, int y, int width, int height, const Widget *widgets, int item_count,
+										int sel_index, int parent_button, StringID base_string, int checked_items,
+										int disabled_mask) :
+			Window(x, y, width, height, WC_TOOLBAR_MENU, widgets),
+			item_count(item_count), sel_index(sel_index), main_button(GB(parent_button, 0, 8)),
+			action_id((GB(parent_button, 8, 8) != 0) ? GB(parent_button, 8, 8) : parent_button),
+			checked_items(checked_items), disabled_items(disabled_items), base_string(base_string)
+	{
+		this->widget[0].bottom = item_count * 10 + 1;
+		this->widget[0].right = this->width - 1;
+		this->flags4 &= ~WF_WHITE_BORDER_MASK;
 
-				y += 10;
-				chk >>= 1;
-				dis >>= 1;
-			}
-		} break;
+		this->FindWindowPlacementAndResize(width, height);
+	}
 
-		case WE_DESTROY: {
-				Window *v = FindWindowById(WC_MAIN_TOOLBAR, 0);
-				v->RaiseWidget(WP(w, menu_d).main_button);
-				v->SetDirty();
-				return;
+	~ToolbarMenuWindow()
+	{
+		Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0);
+		w->RaiseWidget(this->main_button);
+		w->SetDirty();
+	}
+
+	virtual void OnPaint()
+	{
+		this->DrawWidgets();
+
+		for (int i = 0, x = 1, y = 1; i != this->item_count; i++, y += 10) {
+			TextColour color = HasBit(this->disabled_items, i) ? TC_GREY : (this->sel_index == i) ? TC_WHITE : TC_BLACK;
+			if (this->sel_index == i) GfxFillRect(x, y, x + this->width - 3, y + 9, 0);
+
+			if (HasBit(this->checked_items, i)) DrawString(x + 2, y, STR_CHECKMARK, color);
+			DrawString(x + 2, y, this->base_string + i, color);
+		}
+	}
+
+	virtual void OnMouseLoop()
+	{
+		int index = GetMenuItemIndex(this, this->item_count, this->disabled_items);
+
+		if (_left_button_down) {
+			if (index == -1 || index == this->sel_index) return;
+
+			this->sel_index = index;
+			this->SetDirty();
+		} else {
+			if (index < 0) {
+				Window *w = FindWindowById(WC_MAIN_TOOLBAR,0);
+				if (GetWidgetFromPos(w, _cursor.pos.x - w->left, _cursor.pos.y - w->top) == this->main_button) {
+					index = this->sel_index;
+				}
 			}
 
-		case WE_MOUSELOOP: {
-			int index = GetMenuItemIndex(w);
-
-			if (_left_button_down) {
-				if (index == -1 || index == WP(w, menu_d).sel_index) return;
+			int action_id = this->action_id;
+			delete this;
 
-				WP(w, menu_d).sel_index = index;
-				w->SetDirty();
-			} else {
-				if (index < 0) {
-					Window *w2 = FindWindowById(WC_MAIN_TOOLBAR,0);
-					if (GetWidgetFromPos(w2, _cursor.pos.x - w2->left, _cursor.pos.y - w2->top) == WP(w, menu_d).main_button)
-						index = WP(w, menu_d).sel_index;
-				}
-
-				int action_id = WP(w, menu_d).action_id;
-				delete w;
-
-				if (index >= 0) {
-					assert((uint)index <= lengthof(_menu_clicked_procs));
-					_menu_clicked_procs[action_id](index);
-				}
+			if (index >= 0) {
+				assert((uint)index <= lengthof(_menu_clicked_procs));
+				_menu_clicked_procs[action_id](index);
 			}
-		} break;
+		}
 	}
-}
+};
 
 /* Dynamic widget length determined by toolbar-string length.
  * See PopupMainToolbMenu en MenuWndProc */
@@ -1222,7 +1253,7 @@
  * aligned with the toolbar's right side.
  * Since the disable-mask is only 8 bits right now, these dropdowns are
  * restricted to 8 items max if any bits of disabled_mask are active.
- * @param w Pointer to a window this dropdown menu belongs to. Has no effect
+ * @param parent Pointer to a window this dropdown menu belongs to. Has no effect
  * whatsoever, only graphically for positioning.
  * @param parent_button The widget identifier of the button that was clicked for
  * this dropdown. The created dropdown then knows what button to raise (button) on
@@ -1236,12 +1267,15 @@
  * consecutive indeces from the language file. XXX - fix? Use ingame-string tables?
  * @param item_count Number of strings in the list, see previous parameter
  * @param disabled_mask Bitmask of disabled strings in the list
- * @return Return a pointer to the newly created dropdown window */
-static Window *PopupMainToolbMenu(Window *w, uint16 parent_button, StringID base_string, byte item_count, byte disabled_mask)
+ * @param sel_index The selected toolbar item
+ * @param check_items The items to have a checked mark in front of them.
+ * @return Return a pointer to the newly created dropdown window
+ */
+static void PopupMainToolbMenu(Window *parent, uint16 parent_button, StringID base_string, byte item_count, byte disabled_mask, int sel_index, int checked_items)
 {
 	assert(disabled_mask == 0 || item_count <= 8);
-	w->LowerWidget(parent_button);
-	w->InvalidateWidget(parent_button);
+	parent->LowerWidget(parent_button);
+	parent->InvalidateWidget(parent_button);
 
 	DeleteWindowById(WC_TOOLBAR_MENU, 0);
 
@@ -1251,20 +1285,9 @@
 
 	Point pos = GetToolbarDropdownPos(parent_button, width, height);
 
-	w = new Window(pos.x, pos.y, width, height, MenuWndProc, WC_TOOLBAR_MENU, _menu_widgets);
-	w->widget[0].bottom = item_count * 10 + 1;
-	w->flags4 &= ~WF_WHITE_BORDER_MASK;
-
-	WP(w, menu_d).item_count = item_count;
-	WP(w, menu_d).sel_index = 0;
-	WP(w, menu_d).main_button = GB(parent_button, 0, 8);
-	WP(w, menu_d).action_id = (GB(parent_button, 8, 8) != 0) ? GB(parent_button, 8, 8) : parent_button;
-	WP(w, menu_d).string_id = base_string;
-	WP(w, menu_d).checked_items = 0;
-	WP(w, menu_d).disabled_items = disabled_mask;
+	new ToolbarMenuWindow(pos.x, pos.y, width, height, _menu_widgets, item_count, sel_index, parent_button, base_string, checked_items, disabled_mask);
 
 	SndPlayFx(SND_15_BEEP);
-	return w;
 }
 
 /* --- Rendering/drawing the player menu --- */
@@ -1280,170 +1303,169 @@
 	return -1;
 }
 
-static void UpdatePlayerMenuHeight(Window *w)
-{
-	byte num = ActivePlayerCount();
-
-	/* Increase one to fit in PlayerList in the menu when in network */
-	if (_networking && WP(w, menu_d).main_button == 9) num++;
+struct ToolbarPlayerMenuWindow : Window {
+	int item_count;
+	int sel_index;
+	int main_button;
+	int action_id;
+	int gray_items;
 
-	if (WP(w, menu_d).item_count != num) {
-		WP(w, menu_d).item_count = num;
-		w->SetDirty();
-		num = num * 10 + 2;
-		w->height = num;
-		w->widget[0].bottom = w->widget[0].top + num - 1;
-		w->top = GetToolbarDropdownPos(0, w->width, w->height).y;
+	ToolbarPlayerMenuWindow(int x, int y, int width, int height, const Widget *widgets, int main_button, int gray) :
+			Window(x, y, width, height, WC_TOOLBAR_MENU, widgets),
+			item_count(0), main_button(main_button), action_id(main_button), gray_items(gray)
+	{
+		this->flags4 &= ~WF_WHITE_BORDER_MASK;
+		this->sel_index = (_local_player != PLAYER_SPECTATOR) ? _local_player : GetPlayerIndexFromMenu(0);
+		if (_networking && main_button == 9) {
+			if (_local_player != PLAYER_SPECTATOR) {
+				this->sel_index++;
+			} else {
+				/* Select client list by default for spectators */
+				this->sel_index = 0;
+			}
+		}
+	}
+
+	~ToolbarPlayerMenuWindow()
+	{
+		Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0);
+		w->RaiseWidget(this->main_button);
 		w->SetDirty();
 	}
-}
 
-static void PlayerMenuWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			UpdatePlayerMenuHeight(w);
-			DrawWindowWidgets(w);
+	void UpdatePlayerMenuHeight()
+	{
+		byte num = ActivePlayerCount();
 
-			int x = 1;
-			int y = 1;
-			int sel = WP(w, menu_d).sel_index;
-			int chk = WP(w, menu_d).checked_items; // let this mean gray items.
+		/* Increase one to fit in PlayerList in the menu when in network */
+		if (_networking && this->main_button == 9) num++;
 
-			/* 9 = playerlist */
-			if (_networking && WP(w, menu_d).main_button == 9) {
-				if (sel == 0) {
+		if (this->item_count != num) {
+			this->item_count = num;
+			this->SetDirty();
+			num = num * 10 + 2;
+			this->height = num;
+			this->widget[0].bottom = this->widget[0].top + num - 1;
+			this->top = GetToolbarDropdownPos(0, this->width, this->height).y;
+			this->SetDirty();
+		}
+	}
+
+	virtual void OnPaint()
+	{
+		this->UpdatePlayerMenuHeight();
+		this->DrawWidgets();
+
+		int x = 1;
+		int y = 1;
+		int sel = this->sel_index;
+		int gray = this->gray_items;
+
+		/* 9 = playerlist */
+		if (_networking && this->main_button == 9) {
+			if (sel == 0) {
+				GfxFillRect(x, y, x + 238, y + 9, 0);
+			}
+			DrawString(x + 19, y, STR_NETWORK_CLIENT_LIST, TC_FROMSTRING);
+			y += 10;
+			sel--;
+		}
+
+		const Player *p;
+		FOR_ALL_PLAYERS(p) {
+			if (p->is_active) {
+				if (p->index == sel) {
 					GfxFillRect(x, y, x + 238, y + 9, 0);
 				}
-				DrawString(x + 19, y, STR_NETWORK_CLIENT_LIST, TC_FROMSTRING);
+
+				DrawPlayerIcon(p->index, x + 2, y + 1);
+
+				SetDParam(0, p->index);
+				SetDParam(1, p->index);
+
+				TextColour color = (p->index == sel) ? TC_WHITE : TC_BLACK;
+				if (gray & 1) color = TC_GREY;
+				DrawString(x + 19, y, STR_7021, color);
+
 				y += 10;
-				sel--;
+			}
+			gray >>= 1;
+		}
+	}
+
+	virtual void OnMouseLoop()
+	{
+		int index = GetMenuItemIndex(this, this->item_count, 0);
+
+		if (_left_button_down) {
+			this->UpdatePlayerMenuHeight();
+			/* We have a new entry at the top of the list of menu 9 when networking
+				* so keep that in count */
+			if (_networking && this->main_button == 9) {
+				if (index > 0) index = GetPlayerIndexFromMenu(index - 1) + 1;
+			} else {
+				index = GetPlayerIndexFromMenu(index);
 			}
 
-			const Player *p;
-			FOR_ALL_PLAYERS(p) {
-				if (p->is_active) {
-					if (p->index == sel) {
-						GfxFillRect(x, y, x + 238, y + 9, 0);
-					}
-
-					DrawPlayerIcon(p->index, x + 2, y + 1);
-
-					SetDParam(0, p->index);
-					SetDParam(1, p->index);
-
-					TextColour color = (p->index == sel) ? TC_WHITE : TC_BLACK;
-					if (chk & 1) color = TC_GREY;
-					DrawString(x + 19, y, STR_7021, color);
-
-					y += 10;
-				}
-				chk >>= 1;
-			}
-		 } break;
-
-		case WE_DESTROY: {
-			Window *v = FindWindowById(WC_MAIN_TOOLBAR, 0);
-			v->RaiseWidget(WP(w, menu_d).main_button);
-			v->SetDirty();
-			return;
-		}
-
-		case WE_MOUSELOOP: {
-			int index = GetMenuItemIndex(w);
+			if (index == -1 || index == this->sel_index) return;
 
-			if (_left_button_down) {
-				UpdatePlayerMenuHeight(w);
-				/* We have a new entry at the top of the list of menu 9 when networking
-				 * so keep that in count */
-				if (_networking && WP(w, menu_d).main_button == 9) {
-					if (index > 0) index = GetPlayerIndexFromMenu(index - 1) + 1;
-				} else {
-					index = GetPlayerIndexFromMenu(index);
-				}
-
-				if (index == -1 || index == WP(w, menu_d).sel_index) return;
-
-				WP(w, menu_d).sel_index = index;
-				w->SetDirty();
-			} else {
-				int action_id = WP(w, menu_d).action_id;
+			this->sel_index = index;
+			this->SetDirty();
+		} else {
+			int action_id = this->action_id;
 
-				/* We have a new entry at the top of the list of menu 9 when networking
-				 * so keep that in count */
-				if (_networking && WP(w, menu_d).main_button == 9) {
-					if (index > 0) index = GetPlayerIndexFromMenu(index - 1) + 1;
-				} else {
-					index = GetPlayerIndexFromMenu(index);
-				}
+			/* We have a new entry at the top of the list of menu 9 when networking
+				* so keep that in count */
+			if (_networking && this->main_button == 9) {
+				if (index > 0) index = GetPlayerIndexFromMenu(index - 1) + 1;
+			} else {
+				index = GetPlayerIndexFromMenu(index);
+			}
 
-				if (index < 0) {
-					Window *w2 = FindWindowById(WC_MAIN_TOOLBAR,0);
-					if (GetWidgetFromPos(w2, _cursor.pos.x - w2->left, _cursor.pos.y - w2->top) == WP(w, menu_d).main_button)
-						index = WP(w, menu_d).sel_index;
-				}
-
-				delete w;
-
-				if (index >= 0) {
-					assert(index >= 0 && index < 30);
-					_menu_clicked_procs[action_id](index);
+			if (index < 0) {
+				Window *w = FindWindowById(WC_MAIN_TOOLBAR,0);
+				if (GetWidgetFromPos(w, _cursor.pos.x - w->left, _cursor.pos.y - w->top) == this->main_button) {
+					index = this->sel_index;
 				}
 			}
-		} break;
+
+			delete this;
+
+			if (index >= 0) {
+				assert(index >= 0 && index < 30);
+				_menu_clicked_procs[action_id](index);
+			}
+		}
 	}
-}
+};
 
 static const Widget _player_menu_widgets[] = {
 {    WWT_PANEL, RESIZE_NONE, 14, 0, 240, 0, 81, 0x0, STR_NULL},
 { WIDGETS_END},
 };
 
-static Window *PopupMainPlayerToolbMenu(Window *w, int main_button, int gray)
+static void PopupMainPlayerToolbMenu(Window *parent, int main_button, int gray)
 {
-	w->LowerWidget(main_button);
-	w->InvalidateWidget(main_button);
+	parent->LowerWidget(main_button);
+	parent->InvalidateWidget(main_button);
 
 	DeleteWindowById(WC_TOOLBAR_MENU, 0);
 	Point pos = GetToolbarDropdownPos(main_button, 241, 82);
-	w = new Window(pos.x, pos.y, 241, 82, PlayerMenuWndProc, WC_TOOLBAR_MENU, _player_menu_widgets);
-	w->flags4 &= ~WF_WHITE_BORDER_MASK;
-	WP(w, menu_d).item_count = 0;
-	WP(w, menu_d).sel_index = (_local_player != PLAYER_SPECTATOR) ? _local_player : GetPlayerIndexFromMenu(0);
-	if (_networking && main_button == 9) {
-		if (_local_player != PLAYER_SPECTATOR) {
-			WP(w, menu_d).sel_index++;
-		} else {
-			/* Select client list by default for spectators */
-			WP(w, menu_d).sel_index = 0;
-		}
-	}
-	WP(w, menu_d).action_id = main_button;
-	WP(w, menu_d).main_button = main_button;
-	WP(w, menu_d).checked_items = gray;
-	WP(w, menu_d).disabled_items = 0;
+	new ToolbarPlayerMenuWindow(pos.x, pos.y, 241, 82, _player_menu_widgets, main_button, gray);
 
 	SndPlayFx(SND_15_BEEP);
-	return w;
 }
 
 /* --- Allocating the toolbar --- */
 
-Window *AllocateToolbar()
+void AllocateToolbar()
 {
 	/* Clean old GUI values; railtype is (re)set by rail_gui.cpp */
 	_last_built_roadtype = ROADTYPE_ROAD;
 
-	Window *w = new Window((_game_mode != GM_EDITOR) ? &_toolb_normal_desc : &_toolb_scen_desc);
-	if (w == NULL) return NULL;
-
-	CLRBITS(w->flags4, WF_WHITE_BORDER_MASK);
-
-	w->SetWidgetDisabledState(0, _networking && !_network_server); // if not server, disable pause button
-	w->SetWidgetDisabledState(1, _networking); // if networking, disable fast-forward button
-
-	/* 'w' is for sure a WC_MAIN_TOOLBAR */
-	PositionMainToolbar(w);
-
-	return w;
+	if (_game_mode == GM_EDITOR) {
+		new ScenarioEditorToolbarWindow(&_toolb_scen_desc);;
+	} else {
+		new MainToolbarWindow(&_toolb_normal_desc);
+	}
 }
--- a/src/toolbar_gui.h	Mon May 19 14:14:33 2008 +0000
+++ b/src/toolbar_gui.h	Mon May 19 15:13:58 2008 +0000
@@ -5,8 +5,6 @@
 #ifndef TOOLBAR_GUI_H
 #define TOOLBAR_GUI_H
 
-#include "window_type.h"
-
-Window *AllocateToolbar();
+void AllocateToolbar();
 
 #endif /*TOOLBAR_GUI_H*/
--- a/src/town_cmd.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/town_cmd.cpp	Mon May 19 15:13:58 2008 +0000
@@ -2152,7 +2152,7 @@
 	SetDParam(1, _current_player);
 
 	AddNewsItem(STR_2055_TRAFFIC_CHAOS_IN_ROAD_REBUILDING,
-		NM_NORMAL, NF_TILE, NT_GENERAL, DNC_NONE, t->xy, 0);
+		NS_GENERAL, t->xy, 0);
 }
 
 static bool DoBuildStatueOfCompany(TileIndex tile, TownID town_id)
--- a/src/town_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/town_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -141,140 +141,134 @@
 	return -1;
 }
 
-static void TownAuthorityWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			const Town *t = GetTown(w->window_number);
-			int numact;
-			uint buttons = GetMaskOfTownActions(&numact, _local_player, t);
-
-			SetVScrollCount(w, numact + 1);
-
-			if (WP(w, def_d).data_1 != -1 && !HasBit(buttons, WP(w, def_d).data_1))
-				WP(w, def_d).data_1 = -1;
-
-			w->SetWidgetDisabledState(6, WP(w, def_d).data_1 == -1);
-
-			{
-				int y;
-				const Player *p;
-				int r;
-				StringID str;
-
-				SetDParam(0, w->window_number);
-				DrawWindowWidgets(w);
-
-				DrawString(2, 15, STR_2023_TRANSPORT_COMPANY_RATINGS, TC_FROMSTRING);
+struct TownAuthorityWindow : Window {
+	int sel_index;
 
-				/* Draw list of players */
-				y = 25;
-				FOR_ALL_PLAYERS(p) {
-					if (p->is_active && (HasBit(t->have_ratings, p->index) || t->exclusivity == p->index)) {
-						DrawPlayerIcon(p->index, 2, y);
-
-						SetDParam(0, p->index);
-						SetDParam(1, p->index);
+	TownAuthorityWindow(const WindowDesc *desc, WindowNumber window_number) :
+			Window(desc, window_number), sel_index(-1)
+	{
+		this->vscroll.cap = 5;
 
-						r = t->ratings[p->index];
-						(str = STR_3035_APPALLING, r <= RATING_APPALLING) || // Apalling
-						(str++,                    r <= RATING_VERYPOOR)  || // Very Poor
-						(str++,                    r <= RATING_POOR)      || // Poor
-						(str++,                    r <= RATING_MEDIOCRE)  || // Mediocore
-						(str++,                    r <= RATING_GOOD)      || // Good
-						(str++,                    r <= RATING_VERYGOOD)  || // Very Good
-						(str++,                    r <= RATING_EXCELLENT) || // Excellent
-						(str++,                    true);                    // Outstanding
+		this->FindWindowPlacementAndResize(desc);
+	}
 
-						SetDParam(2, str);
-						if (t->exclusivity == p->index) { // red icon for player with exclusive rights
-							DrawSprite(SPR_BLOT, PALETTE_TO_RED, 18, y);
-						}
+	virtual void OnPaint()
+	{
+		const Town *t = GetTown(this->window_number);
+		int numact;
+		uint buttons = GetMaskOfTownActions(&numact, _local_player, t);
 
-						DrawString(28, y, STR_2024, TC_FROMSTRING);
-						y += 10;
-					}
+		SetVScrollCount(this, numact + 1);
+
+		if (this->sel_index != -1 && !HasBit(buttons, this->sel_index)) {
+			this->sel_index = -1;
+		}
+
+		this->SetWidgetDisabledState(6, this->sel_index == -1);
+
+		SetDParam(0, this->window_number);
+		this->DrawWidgets();
+
+		DrawString(2, 15, STR_2023_TRANSPORT_COMPANY_RATINGS, TC_FROMSTRING);
+
+		/* Draw list of players */
+		int y = 25;
+
+		const Player *p;
+		FOR_ALL_PLAYERS(p) {
+			if (p->is_active && (HasBit(t->have_ratings, p->index) || t->exclusivity == p->index)) {
+				DrawPlayerIcon(p->index, 2, y);
+
+				SetDParam(0, p->index);
+				SetDParam(1, p->index);
+
+				int r = t->ratings[p->index];
+				StringID str;
+				(str = STR_3035_APPALLING, r <= RATING_APPALLING) || // Apalling
+				(str++,                    r <= RATING_VERYPOOR)  || // Very Poor
+				(str++,                    r <= RATING_POOR)      || // Poor
+				(str++,                    r <= RATING_MEDIOCRE)  || // Mediocore
+				(str++,                    r <= RATING_GOOD)      || // Good
+				(str++,                    r <= RATING_VERYGOOD)  || // Very Good
+				(str++,                    r <= RATING_EXCELLENT) || // Excellent
+				(str++,                    true);                    // Outstanding
+
+				SetDParam(2, str);
+				if (t->exclusivity == p->index) { // red icon for player with exclusive rights
+					DrawSprite(SPR_BLOT, PALETTE_TO_RED, 18, y);
 				}
+
+				DrawString(28, y, STR_2024, TC_FROMSTRING);
+				y += 10;
+			}
+		}
+		y = 107;
+		int pos = this->vscroll.pos;
+
+		if (--pos < 0) {
+			DrawString(2, y, STR_2045_ACTIONS_AVAILABLE, TC_FROMSTRING);
+			y += 10;
+		}
+
+		for (int i = 0; buttons; i++, buttons >>= 1) {
+			if (pos <= -5) break; ///< Draw only the 5 fitting lines
+
+			if ((buttons & 1) && --pos < 0) {
+				DrawString(3, y, STR_2046_SMALL_ADVERTISING_CAMPAIGN + i, TC_ORANGE);
+				y += 10;
+			}
+		}
+
+		if (this->sel_index != -1) {
+			SetDParam(1, (_price.build_industry >> 8) * _town_action_costs[this->sel_index]);
+			SetDParam(0, STR_2046_SMALL_ADVERTISING_CAMPAIGN + this->sel_index);
+			DrawStringMultiLine(2, 159, STR_204D_INITIATE_A_SMALL_LOCAL + this->sel_index, 313);
+		}
+	}
+
+	virtual void OnDoubleClick(Point pt, int widget) { HandleClick(pt, widget, true); }
+	virtual void OnClick(Point pt, int widget) { HandleClick(pt, widget, false); }
+
+	void HandleClick(Point pt, int widget, bool double_click)
+	{
+		switch (widget) {
+			case TWA_COMMAND_LIST: {
+				const Town *t = GetTown(this->window_number);
+				int y = (pt.y - 0x6B) / 10;
+
+				if (!IsInsideMM(y, 0, 5)) return;
+
+				y = GetNthSetBit(GetMaskOfTownActions(NULL, _local_player, t), y + this->vscroll.pos - 1);
+				if (y >= 0) {
+					this->sel_index = y;
+					this->SetDirty();
+				}
+				/* Fall through to clicking in case we are double-clicked */
+				if (!double_click || y < 0) break;
 			}
 
-			/* Draw actions list */
-			{
-				int y = 107, i;
-				int pos = w->vscroll.pos;
-
-				if (--pos < 0) {
-					DrawString(2, y, STR_2045_ACTIONS_AVAILABLE, TC_FROMSTRING);
-					y += 10;
-				}
-
-				for (i = 0; buttons; i++, buttons >>= 1) {
-					if (pos <= -5) break; ///< Draw only the 5 fitting lines
-
-					if ((buttons & 1) && --pos < 0) {
-						DrawString(3, y, STR_2046_SMALL_ADVERTISING_CAMPAIGN + i, TC_ORANGE);
-						y += 10;
-					}
-				}
-			}
-
-			{
-				int i = WP(w, def_d).data_1;
-
-				if (i != -1) {
-					SetDParam(1, (_price.build_industry >> 8) * _town_action_costs[i]);
-					SetDParam(0, STR_2046_SMALL_ADVERTISING_CAMPAIGN + i);
-					DrawStringMultiLine(2, 159, STR_204D_INITIATE_A_SMALL_LOCAL + i, 313);
-				}
-			}
+			case TWA_EXECUTE:
+				DoCommandP(GetTown(this->window_number)->xy, this->window_number, this->sel_index, NULL, CMD_DO_TOWN_ACTION | CMD_MSG(STR_00B4_CAN_T_DO_THIS));
+				break;
+		}
+	}
 
-		} break;
-
-		case WE_DOUBLE_CLICK:
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case TWA_COMMAND_LIST: {
-					const Town *t = GetTown(w->window_number);
-					int y = (e->we.click.pt.y - 0x6B) / 10;
-
-					if (!IsInsideMM(y, 0, 5)) return;
-
-					y = GetNthSetBit(GetMaskOfTownActions(NULL, _local_player, t), y + w->vscroll.pos - 1);
-					if (y >= 0) {
-						WP(w, def_d).data_1 = y;
-						w->SetDirty();
-					}
-					/* Fall through to clicking in case we are double-clicked */
-					if (e->event != WE_DOUBLE_CLICK || y < 0) break;
-				}
-
-				case TWA_EXECUTE:
-					DoCommandP(GetTown(w->window_number)->xy, w->window_number, WP(w, def_d).data_1, NULL, CMD_DO_TOWN_ACTION | CMD_MSG(STR_00B4_CAN_T_DO_THIS));
-					break;
-			}
-			break;
-
-		case WE_100_TICKS:
-			w->SetDirty();
-			break;
+	virtual void OnHundredthTick()
+	{
+		this->SetDirty();
 	}
-}
+};
 
 static const WindowDesc _town_authority_desc = {
 	WDP_AUTO, WDP_AUTO, 317, 222, 317, 222,
 	WC_TOWN_AUTHORITY, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
 	_town_authority_widgets,
-	TownAuthorityWndProc
 };
 
 static void ShowTownAuthorityWindow(uint town)
 {
-	Window *w = AllocateWindowDescFront<Window>(&_town_authority_desc, town);
-
-	if (w != NULL) {
-		w->vscroll.cap = 5;
-		WP(w, def_d).data_1 = -1;
-	}
+	AllocateWindowDescFront<TownAuthorityWindow>(&_town_authority_desc, town);
 }
 
 
@@ -288,87 +282,98 @@
 	TVW_DELETE,
 };
 
-static void TownViewWndProc(Window *w, WindowEvent *e)
-{
-	Town *t = GetTown(w->window_number);
-
-	switch (e->event) {
-		case WE_CREATE: {
-			bool ingame = _game_mode != GM_EDITOR;
-			if (t->larger_town) w->widget[TVW_CAPTION].data = STR_CITY;
-			w->SetWidgetHiddenState(TVW_DELETE, ingame);  // hide delete button on game mode
-			w->SetWidgetHiddenState(TVW_EXPAND, ingame);  // hide expand button on game mode
-			w->SetWidgetHiddenState(TVW_SHOWAUTORITY, !ingame); // hide autority button on editor mode
-
-			if (ingame) {
-				/* resize caption bar */
-				w->widget[TVW_CAPTION].right = w->widget[TVW_STICKY].left -1;
-				/* move the rename from top on scenario to bottom in game */
-				w->widget[TVW_CHANGENAME].top = w->widget[TVW_EXPAND].top;
-				w->widget[TVW_CHANGENAME].bottom = w->widget[TVW_EXPAND].bottom;
-				w->widget[TVW_CHANGENAME].right = w->widget[TVW_STICKY].right;
-			}
-		} break;
-
-		case WE_PAINT:
-			/* disable renaming town in network games if you are not the server */
-			w->SetWidgetDisabledState(TVW_CHANGENAME, _networking && !_network_server);
-
-			SetDParam(0, t->index);
-			DrawWindowWidgets(w);
-
-			SetDParam(0, t->population);
-			SetDParam(1, t->num_houses);
-			DrawString(2, 107, STR_2006_POPULATION, TC_FROMSTRING);
-
-			SetDParam(0, t->act_pass);
-			SetDParam(1, t->max_pass);
-			DrawString(2, 117, STR_200D_PASSENGERS_LAST_MONTH_MAX, TC_FROMSTRING);
+struct TownViewWindow : Window {
+	TownViewWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+	{
+		const Town *t = GetTown(this->window_number);
 
-			SetDParam(0, t->act_mail);
-			SetDParam(1, t->max_mail);
-			DrawString(2, 127, STR_200E_MAIL_LAST_MONTH_MAX, TC_FROMSTRING);
-
-			DrawWindowViewport(w);
-			break;
-
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case TVW_CENTERVIEW: /* scroll to location */
-					if (_ctrl_pressed) {
-						ShowExtraViewPortWindow(t->xy);
-					} else {
-						ScrollMainWindowToTile(t->xy);
-					}
-					break;
-
-				case TVW_SHOWAUTORITY: /* town authority */
-					ShowTownAuthorityWindow(w->window_number);
-					break;
+		this->flags4 |= WF_DISABLE_VP_SCROLL;
+		InitializeWindowViewport(this, 3, 17, 254, 86, t->xy, ZOOM_LVL_TOWN);
 
-				case TVW_CHANGENAME: /* rename */
-					SetDParam(0, w->window_number);
-					ShowQueryString(STR_TOWN, STR_2007_RENAME_TOWN, 31, 130, w, CS_ALPHANUMERAL);
-					break;
-
-				case TVW_EXPAND: /* expand town - only available on Scenario editor */
-					ExpandTown(t);
-					break;
+		bool ingame = _game_mode != GM_EDITOR;
+		if (t->larger_town) this->widget[TVW_CAPTION].data = STR_CITY;
+		this->SetWidgetHiddenState(TVW_DELETE, ingame);  // hide delete button on game mode
+		this->SetWidgetHiddenState(TVW_EXPAND, ingame);  // hide expand button on game mode
+		this->SetWidgetHiddenState(TVW_SHOWAUTORITY, !ingame); // hide autority button on editor mode
 
-				case TVW_DELETE: /* delete town - only available on Scenario editor */
-					delete t;
-					break;
-			} break;
+		if (ingame) {
+			/* resize caption bar */
+			this->widget[TVW_CAPTION].right = this->widget[TVW_STICKY].left -1;
+			/* move the rename from top on scenario to bottom in game */
+			this->widget[TVW_CHANGENAME].top = this->widget[TVW_EXPAND].top;
+			this->widget[TVW_CHANGENAME].bottom = this->widget[TVW_EXPAND].bottom;
+			this->widget[TVW_CHANGENAME].right = this->widget[TVW_STICKY].right;
+		}
 
-		case WE_ON_EDIT_TEXT:
-			if (!StrEmpty(e->we.edittext.str)) {
-				_cmd_text = e->we.edittext.str;
-				DoCommandP(0, w->window_number, 0, NULL,
-					CMD_RENAME_TOWN | CMD_MSG(STR_2008_CAN_T_RENAME_TOWN));
-			}
-			break;
+		this->FindWindowPlacementAndResize(desc);
 	}
-}
+
+	virtual void OnPaint()
+	{
+		const Town *t = GetTown(this->window_number);
+
+		/* disable renaming town in network games if you are not the server */
+		this->SetWidgetDisabledState(TVW_CHANGENAME, _networking && !_network_server);
+
+		SetDParam(0, t->index);
+		this->DrawWidgets();
+
+		SetDParam(0, t->population);
+		SetDParam(1, t->num_houses);
+		DrawString(2, 107, STR_2006_POPULATION, TC_FROMSTRING);
+
+		SetDParam(0, t->act_pass);
+		SetDParam(1, t->max_pass);
+		DrawString(2, 117, STR_200D_PASSENGERS_LAST_MONTH_MAX, TC_FROMSTRING);
+
+		SetDParam(0, t->act_mail);
+		SetDParam(1, t->max_mail);
+		DrawString(2, 127, STR_200E_MAIL_LAST_MONTH_MAX, TC_FROMSTRING);
+
+		this->DrawViewport();
+	}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		Town *t = GetTown(this->window_number);
+
+		switch (widget) {
+			case TVW_CENTERVIEW: /* scroll to location */
+				if (_ctrl_pressed) {
+					ShowExtraViewPortWindow(t->xy);
+				} else {
+					ScrollMainWindowToTile(t->xy);
+				}
+				break;
+
+			case TVW_SHOWAUTORITY: /* town authority */
+				ShowTownAuthorityWindow(this->window_number);
+				break;
+
+			case TVW_CHANGENAME: /* rename */
+				SetDParam(0, this->window_number);
+				ShowQueryString(STR_TOWN, STR_2007_RENAME_TOWN, 31, 130, this, CS_ALPHANUMERAL);
+				break;
+
+			case TVW_EXPAND: /* expand town - only available on Scenario editor */
+				ExpandTown(t);
+				break;
+
+			case TVW_DELETE: /* delete town - only available on Scenario editor */
+				delete t;
+				break;
+		}
+	}
+
+	virtual void OnQueryTextFinished(char *str)
+	{
+		if (!StrEmpty(str)) {
+			_cmd_text = str;
+			DoCommandP(0, this->window_number, 0, NULL,
+				CMD_RENAME_TOWN | CMD_MSG(STR_2008_CAN_T_RENAME_TOWN));
+		}
+	}
+};
 
 
 static const Widget _town_view_widgets[] = {
@@ -391,26 +396,13 @@
 	WC_TOWN_VIEW, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
 	_town_view_widgets,
-	TownViewWndProc
 };
 
 void ShowTownViewWindow(TownID town)
 {
-	Window *w;
-
-	w = AllocateWindowDescFront<Window>(&_town_view_desc, town);
-
-	if (w != NULL) {
-		w->flags4 |= WF_DISABLE_VP_SCROLL;
-		InitializeWindowViewport(w, 3, 17, 254, 86, GetTown(town)->xy, ZOOM_LVL_TOWN);
-	}
+	AllocateWindowDescFront<TownViewWindow>(&_town_view_desc, town);
 }
 
-enum TownDirectoryWidget {
-	TDW_SORTNAME = 3,
-	TDW_SORTPOPULATION,
-	TDW_CENTERTOWN,
-};
 static const Widget _town_directory_widgets[] = {
 {   WWT_CLOSEBOX,   RESIZE_NONE,    13,     0,    10,     0,    13, STR_00C5,               STR_018B_CLOSE_WINDOW},
 {    WWT_CAPTION,   RESIZE_NONE,    13,    11,   195,     0,    13, STR_2000_TOWNS,         STR_018C_WINDOW_TITLE_DRAG_THIS},
@@ -483,107 +475,117 @@
 }
 
 
-static void TownDirectoryWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			if (_town_sort_dirty) {
-				_town_sort_dirty = false;
-				MakeSortedTownList();
+struct TownDirectoryWindow : public Window {
+	enum TownDirectoryWidget {
+		TDW_SORTNAME = 3,
+		TDW_SORTPOPULATION,
+		TDW_CENTERTOWN,
+	};
+
+	TownDirectoryWindow(const WindowDesc *desc) : Window(desc, 0)
+	{
+		this->vscroll.cap = 16;
+		this->resize.step_height = 10;
+		this->resize.height = this->height - 10 * 6; // minimum of 10 items in the list, each item 10 high
+
+		this->FindWindowPlacementAndResize(desc);
+	}
+
+	virtual void OnPaint()
+	{
+		if (_town_sort_dirty) {
+			_town_sort_dirty = false;
+			MakeSortedTownList();
+		}
+
+		SetVScrollCount(this, _num_town_sort);
+
+		this->DrawWidgets();
+		this->DrawSortButtonState((_town_sort_order <= 1) ? TDW_SORTNAME : TDW_SORTPOPULATION, _town_sort_order & 1 ? SBS_DOWN : SBS_UP);
+
+		{
+			int n = 0;
+			uint16 i = this->vscroll.pos;
+			int y = 28;
+
+			while (i < _num_town_sort) {
+				const Town* t = _town_sort[i];
+
+				assert(t->xy);
+
+				SetDParam(0, t->index);
+				SetDParam(1, t->population);
+				DrawString(2, y, STR_2057, TC_FROMSTRING);
+
+				y += 10;
+				i++;
+				if (++n == this->vscroll.cap) break; // max number of towns in 1 window
 			}
 
-			SetVScrollCount(w, _num_town_sort);
-
-			DrawWindowWidgets(w);
-			DrawSortButtonState(w, (_town_sort_order <= 1) ? TDW_SORTNAME : TDW_SORTPOPULATION, _town_sort_order & 1 ? SBS_DOWN : SBS_UP);
-
-			{
-				int n = 0;
-				uint16 i = w->vscroll.pos;
-				int y = 28;
-
-				while (i < _num_town_sort) {
-					const Town* t = _town_sort[i];
-
-					assert(t->xy);
-
-					SetDParam(0, t->index);
-					SetDParam(1, t->population);
-					DrawString(2, y, STR_2057, TC_FROMSTRING);
-
-					y += 10;
-					i++;
-					if (++n == w->vscroll.cap) break; // max number of towns in 1 window
-				}
-				SetDParam(0, GetWorldPopulation());
-				DrawString(3, w->height - 12 + 2, STR_TOWN_POPULATION, TC_FROMSTRING);
-			}
-		} break;
-
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case TDW_SORTNAME: /* Sort by Name ascending/descending */
-					_town_sort_order = (_town_sort_order == 0) ? 1 : 0;
-					_town_sort_dirty = true;
-					w->SetDirty();
-					break;
+			SetDParam(0, GetWorldPopulation());
+			DrawString(3, this->height - 12 + 2, STR_TOWN_POPULATION, TC_FROMSTRING);
+		}
+	}
 
-				case TDW_SORTPOPULATION: /* Sort by Population ascending/descending */
-					_town_sort_order = (_town_sort_order == 2) ? 3 : 2;
-					_town_sort_dirty = true;
-					w->SetDirty();
-					break;
-
-				case TDW_CENTERTOWN: { /* Click on Town Matrix */
-					const Town* t;
-
-					uint16 id_v = (e->we.click.pt.y - 28) / 10;
-
-					if (id_v >= w->vscroll.cap) return; // click out of bounds
-
-					id_v += w->vscroll.pos;
-
-					if (id_v >= _num_town_sort) return; // click out of town bounds
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case TDW_SORTNAME: /* Sort by Name ascending/descending */
+				_town_sort_order = (_town_sort_order == 0) ? 1 : 0;
+				_town_sort_dirty = true;
+				this->SetDirty();
+				break;
 
-					t = _town_sort[id_v];
-					assert(t->xy);
-					if (_ctrl_pressed) {
-						ShowExtraViewPortWindow(t->xy);
-					} else {
-						ScrollMainWindowToTile(t->xy);
-					}
-				} break;
+			case TDW_SORTPOPULATION: /* Sort by Population ascending/descending */
+				_town_sort_order = (_town_sort_order == 2) ? 3 : 2;
+				_town_sort_dirty = true;
+				this->SetDirty();
+				break;
+
+			case TDW_CENTERTOWN: { /* Click on Town Matrix */
+				const Town* t;
+
+				uint16 id_v = (pt.y - 28) / 10;
+
+				if (id_v >= this->vscroll.cap) return; // click out of bounds
+
+				id_v += this->vscroll.pos;
+
+				if (id_v >= _num_town_sort) return; // click out of town bounds
+
+				t = _town_sort[id_v];
+				assert(t->xy);
+				if (_ctrl_pressed) {
+					ShowExtraViewPortWindow(t->xy);
+				} else {
+					ScrollMainWindowToTile(t->xy);
+				}
+				break;
 			}
-			break;
+		}
+	}
 
-		case WE_100_TICKS:
-			w->SetDirty();
-			break;
+	virtual void OnHundredthTick()
+	{
+		this->SetDirty();
+	}
 
-		case WE_RESIZE:
-			w->vscroll.cap += e->we.sizing.diff.y / 10;
-			break;
+	virtual void OnResize(Point new_size, Point delta)
+	{
+		this->vscroll.cap += delta.y / 10;
 	}
-}
+};
 
 static const WindowDesc _town_directory_desc = {
 	WDP_AUTO, WDP_AUTO, 208, 202, 208, 202,
 	WC_TOWN_DIRECTORY, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
 	_town_directory_widgets,
-	TownDirectoryWndProc
 };
 
-
 void ShowTownDirectory()
 {
-	Window *w = AllocateWindowDescFront<Window>(&_town_directory_desc, 0);
-
-	if (w != NULL) {
-		w->vscroll.cap = 16;
-		w->resize.step_height = 10;
-		w->resize.height = w->height - 10 * 6; // minimum of 10 items in the list, each item 10 high
-	}
+	new TownDirectoryWindow(&_town_directory_desc);
 }
 
 void CcBuildTown(bool success, TileIndex tile, uint32 p1, uint32 p2)
@@ -627,85 +629,89 @@
 {   WIDGETS_END},
 };
 
-static void ScenEditTownGenWndProc(Window *w, WindowEvent *e)
+struct ScenarioEditorTownGenerationWindow : Window
 {
-	switch (e->event) {
-		case WE_PAINT:
-			DrawWindowWidgets(w);
-			break;
-
-		case WE_CREATE:
-			w->LowerWidget(_scengen_town_size + TSEW_SMALLTOWN);
-			break;
-
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case TSEW_NEWTOWN:
-					HandlePlacePushButton(w, TSEW_NEWTOWN, SPR_CURSOR_TOWN, VHM_RECT, PlaceProc_Town);
-					break;
-
-				case TSEW_RANDOMTOWN: {
-					Town *t;
-					uint size = min(_scengen_town_size, (int)TSM_CITY);
-					TownSizeMode mode = _scengen_town_size > TSM_CITY ? TSM_CITY : TSM_FIXED;
+	ScenarioEditorTownGenerationWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+	{
+		this->LowerWidget(_scengen_town_size + TSEW_SMALLTOWN);
+	}
 
-					w->HandleButtonClick(TSEW_RANDOMTOWN);
-					_generating_world = true;
-					t = CreateRandomTown(20, mode, size);
-					_generating_world = false;
-
-					if (t == NULL) {
-						ShowErrorMessage(STR_NO_SPACE_FOR_TOWN, STR_CANNOT_GENERATE_TOWN, 0, 0);
-					} else {
-						ScrollMainWindowToTile(t->xy);
-					}
-				} break;
+	virtual void OnPaint()
+	{
+		this->DrawWidgets();
+	}
 
-				case TSEW_MANYRANDOMTOWNS:
-					w->HandleButtonClick(TSEW_MANYRANDOMTOWNS);
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case TSEW_NEWTOWN:
+				HandlePlacePushButton(this, TSEW_NEWTOWN, SPR_CURSOR_TOWN, VHM_RECT, PlaceProc_Town);
+				break;
 
-					_generating_world = true;
-					if (!GenerateTowns()) ShowErrorMessage(STR_NO_SPACE_FOR_TOWN, STR_CANNOT_GENERATE_TOWN, 0, 0);
-					_generating_world = false;
-					break;
+			case TSEW_RANDOMTOWN: {
+				Town *t;
+				uint size = min(_scengen_town_size, (int)TSM_CITY);
+				TownSizeMode mode = _scengen_town_size > TSM_CITY ? TSM_CITY : TSM_FIXED;
 
-				case TSEW_SMALLTOWN: case TSEW_MEDIUMTOWN: case TSEW_LARGETOWN: case TSEW_CITY:
-					w->RaiseWidget(_scengen_town_size + TSEW_SMALLTOWN);
-					_scengen_town_size = e->we.click.widget - TSEW_SMALLTOWN;
-					w->LowerWidget(_scengen_town_size + TSEW_SMALLTOWN);
-					w->SetDirty();
-					break;
+				this->HandleButtonClick(TSEW_RANDOMTOWN);
+				_generating_world = true;
+				t = CreateRandomTown(20, mode, size);
+				_generating_world = false;
+
+				if (t == NULL) {
+					ShowErrorMessage(STR_NO_SPACE_FOR_TOWN, STR_CANNOT_GENERATE_TOWN, 0, 0);
+				} else {
+					ScrollMainWindowToTile(t->xy);
+				}
 			} break;
 
-		case WE_TIMEOUT:
-			w->RaiseWidget(TSEW_RANDOMTOWN);
-			w->RaiseWidget(TSEW_MANYRANDOMTOWNS);
-			w->SetDirty();
-			break;
+			case TSEW_MANYRANDOMTOWNS:
+				this->HandleButtonClick(TSEW_MANYRANDOMTOWNS);
 
-		case WE_PLACE_OBJ:
-			_place_proc(e->we.place.tile);
-			break;
+				_generating_world = true;
+				if (!GenerateTowns()) ShowErrorMessage(STR_NO_SPACE_FOR_TOWN, STR_CANNOT_GENERATE_TOWN, 0, 0);
+				_generating_world = false;
+				break;
 
-		case WE_ABORT_PLACE_OBJ:
-			w->RaiseButtons();
-			w->LowerWidget(_scengen_town_size + TSEW_SMALLTOWN);
-			w->SetDirty();
-			break;
+			case TSEW_SMALLTOWN: case TSEW_MEDIUMTOWN: case TSEW_LARGETOWN: case TSEW_CITY:
+				this->RaiseWidget(_scengen_town_size + TSEW_SMALLTOWN);
+				_scengen_town_size = widget - TSEW_SMALLTOWN;
+				this->LowerWidget(_scengen_town_size + TSEW_SMALLTOWN);
+				this->SetDirty();
+				break;
+		}
 	}
-}
+
+	virtual void OnTimeout()
+	{
+		this->RaiseWidget(TSEW_RANDOMTOWN);
+		this->RaiseWidget(TSEW_MANYRANDOMTOWNS);
+		this->SetDirty();
+	}
+
+	virtual void OnPlaceObject(Point pt, TileIndex tile)
+	{
+		_place_proc(tile);
+	}
+
+	virtual void OnPlaceObjectAbort()
+	{
+		this->RaiseButtons();
+		this->LowerWidget(_scengen_town_size + TSEW_SMALLTOWN);
+		this->SetDirty();
+	}
+};
 
 static const WindowDesc _scen_edit_town_gen_desc = {
 	WDP_AUTO, WDP_AUTO, 160, 95, 160, 95,
 	WC_SCEN_TOWN_GEN, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
 	_scen_edit_town_gen_widgets,
-	ScenEditTownGenWndProc,
 };
 
 void ShowBuildTownWindow()
 {
 	if (_game_mode != GM_EDITOR && !IsValidPlayer(_current_player)) return;
-	AllocateWindowDescFront<Window>(&_scen_edit_town_gen_desc, 0);
+	AllocateWindowDescFront<ScenarioEditorTownGenerationWindow>(&_scen_edit_town_gen_desc, 0);
 }
 
--- a/src/track_func.h	Mon May 19 14:14:33 2008 +0000
+++ b/src/track_func.h	Mon May 19 15:13:58 2008 +0000
@@ -24,8 +24,6 @@
 	return (Track)a;
 }
 
-
-
 /**
  * Maps a Track to the corresponding TrackBits value
  * @param track the track to convert
@@ -277,7 +275,7 @@
  * Converts TrackBits to TrackdirBits while allowing both directions.
  *
  * @param bits The TrackBits
- * @return The TrackDirBits containing of bits in both directions.
+ * @return The TrackdirBits containing of bits in both directions.
  */
 static inline TrackdirBits TrackBitsToTrackdirBits(TrackBits bits)
 {
@@ -436,13 +434,35 @@
 }
 
 /**
+ * Maps a (4-way) direction to the diagonal track incidating with that diagdir
+ *
+ * @param diagdir The direction
+ * @return The resulting Track
+ */
+static inline Track DiagDirToDiagTrack(DiagDirection diagdir)
+{
+	return (Track)(diagdir & 1);
+}
+
+/**
+ * Maps a (4-way) direction to the diagonal track bits incidating with that diagdir
+ *
+ * @param diagdir The direction
+ * @return The resulting TrackBits
+ */
+static inline TrackBits DiagDirToDiagTrackBits(DiagDirection diagdir)
+{
+	return TrackToTrackBits(DiagDirToDiagTrack(diagdir));
+}
+
+/**
  * Maps a (4-way) direction to the diagonal trackdir that runs in that
  * direction.
  *
  * @param diagdir The direction
  * @return The resulting Trackdir direction
  */
-static inline Trackdir DiagdirToDiagTrackdir(DiagDirection diagdir)
+static inline Trackdir DiagDirToDiagTrackdir(DiagDirection diagdir)
 {
 	extern const Trackdir _dir_to_diag_trackdir[DIAGDIR_END];
 	return _dir_to_diag_trackdir[diagdir];
--- a/src/train_cmd.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/train_cmd.cpp	Mon May 19 15:13:58 2008 +0000
@@ -119,6 +119,9 @@
 		if (engine_has_power) {
 			uint16 power = GetVehicleProperty(u, 0x0B, rvi_u->power);
 			if (power != 0) {
+				/* Halve power for multiheaded parts */
+				if (IsMultiheaded(u)) power /= 2;
+
 				total_power += power;
 				/* Tractive effort in (tonnes * 1000 * 10 =) N */
 				max_te += (u->u.rail.cached_veh_weight * 10000 * GetVehicleProperty(u, 0x1F, rvi_u->tractive_effort)) / 256;
@@ -801,7 +804,7 @@
 			}
 
 			InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
-			RebuildVehicleLists();
+			InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
 			InvalidateWindow(WC_COMPANY, v->owner);
 			if (IsLocalPlayer()) {
 				InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the replace Train window
@@ -1270,7 +1273,7 @@
 			InvalidateWindow(WC_VEHICLE_DEPOT, dst_head->tile);
 		}
 
-		RebuildVehicleLists();
+		InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
 	}
 
 	return CommandCost();
@@ -1348,10 +1351,10 @@
 
 	if (flags & DC_EXEC) {
 		if (v == first && IsFrontEngine(first)) {
-			delete FindWindowById(WC_VEHICLE_VIEW, first->index);
+			DeleteWindowById(WC_VEHICLE_VIEW, first->index);
 		}
 		InvalidateWindow(WC_VEHICLE_DEPOT, first->tile);
-		RebuildVehicleLists();
+		InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
 	}
 
 	CommandCost cost(EXPENSES_NEW_VEHICLES);
@@ -1762,7 +1765,7 @@
 
 		if (d <= 0) {
 			leave->vehstatus &= ~VS_HIDDEN; // move it out of the depot
-			leave->u.rail.track = AxisToTrackBits(DiagDirToAxis(GetRailDepotDirection(leave->tile)));
+			leave->u.rail.track = TrackToTrackBits(GetRailDepotTrack(leave->tile));
 			for (int i = 0; i >= d; i--) TrainController(leave, NULL, false); // maybe move it, and maybe let another wagon leave
 		}
 	} else {
@@ -1999,7 +2002,7 @@
 					v->cargo_subtype = new_subtype;
 					InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
 					InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
-					RebuildVehicleLists();
+					InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
 				}
 			}
 		}
@@ -2260,7 +2263,7 @@
 
 		v->load_unload_time_rem = 0;
 
-		if (UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR, v->owner)) {
+		if (UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR, v->owner) == SIGSEG_FULL) {
 			InvalidateWindowClasses(WC_TRAINS_LIST);
 			return true;
 		}
@@ -2448,7 +2451,7 @@
 				SetDParam(0, v->unitnumber);
 				AddNewsItem(
 					STR_TRAIN_IS_LOST,
-					NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, DNC_NONE,
+					NS_ADVICE,
 					v->index,
 					0);
 			}
@@ -2646,7 +2649,7 @@
 		SetDParam(0, st->index);
 		AddNewsItem(
 			STR_8801_CITIZENS_CELEBRATE_FIRST,
-			NM_THIN, NF_VIEWPORT | NF_VEHICLE, v->owner == _local_player ? NT_ARRIVAL_PLAYER : NT_ARRIVAL_OTHER, DNC_NONE,
+			v->owner == _local_player ? NS_ARRIVAL_PLAYER : NS_ARRIVAL_OTHER,
 			v->index,
 			0
 		);
@@ -2804,7 +2807,7 @@
 		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
 	}
 
-	RebuildVehicleLists();
+	InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
 
 	BEGIN_ENUM_WAGONS(v)
 		v->vehstatus |= VS_CRASHED;
@@ -2893,7 +2896,7 @@
 	AI_Event(v->owner, new AIEventVehicleCrash(v->index, v->tile));
 	SetDParam(0, tcc.num);
 	AddNewsItem(STR_8868_TRAIN_CRASH_DIE_IN_FIREBALL,
-		NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ACCIDENT, DNC_NONE,
+		NS_ACCIDENT_VEHICLE,
 		v->index,
 		0
 	);
@@ -3152,7 +3155,7 @@
 		}
 	}
 
-	RebuildVehicleLists();
+	InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
 
 	MarkSingleVehicleDirty(v);
 
@@ -3502,6 +3505,9 @@
 		byte cost_factor = GetVehicleProperty(v, 0x0D, rvi->running_cost);
 		if (cost_factor == 0) continue;
 
+		/* Halve running cost for multiheaded parts */
+		if (IsMultiheaded(v)) cost_factor /= 2;
+
 		cost += cost_factor * GetPriceByIndex(rvi->running_cost_class);
 	} while ((v = GetNextVehicle(v)) != NULL);
 
@@ -3615,7 +3621,7 @@
 					SetDParam(0, v->unitnumber);
 					AddNewsItem(
 						STR_TRAIN_IS_UNPROFITABLE,
-						NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, DNC_NONE,
+						NS_ADVICE,
 						v->index,
 						0);
 				}
--- a/src/train_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/train_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -18,6 +18,7 @@
 #include "order_func.h"
 #include "engine_func.h"
 #include "engine_base.h"
+#include "window_func.h"
 
 #include "table/sprites.h"
 #include "table/strings.h"
@@ -43,7 +44,7 @@
 		found = GetLastVehicleInChain(found);
 		/* put the new wagon at the end of the loco. */
 		DoCommandP(0, _new_vehicle_id | (found->index << 16), 0, NULL, CMD_MOVE_RAIL_VEHICLE);
-		RebuildVehicleLists();
+		InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
 	}
 }
 
--- a/src/transparency_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/transparency_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -17,82 +17,86 @@
 TransparencyOptionBits _transparency_lock;
 TransparencyOptionBits _invisibility_opt;
 
-enum TransparencyToolbarWidgets{
-	TTW_WIDGET_SIGNS = 3,    ///< Make signs background transparent
-	TTW_WIDGET_TREES,        ///< Make trees transparent
-	TTW_WIDGET_HOUSES,       ///< Make houses transparent
-	TTW_WIDGET_INDUSTRIES,   ///< Make Industries transparent
-	TTW_WIDGET_BUILDINGS,    ///< Make player buildings and structures transparent
-	TTW_WIDGET_BRIDGES,      ///< Make bridges transparent
-	TTW_WIDGET_STRUCTURES,   ///< Make unmovable structures transparent
-	TTW_WIDGET_CATENARY,     ///< Make catenary transparent
-	TTW_WIDGET_LOADING,      ///< Make loading indicators transparent
-	TTW_WIDGET_END,          ///< End of toggle buttons
-
-	/* Panel with buttons for invisibility */
-	TTW_BUTTONS = 12,        ///< Panel with 'invisibility' buttons
-};
-
-static void TransparencyToolbWndProc(Window *w, WindowEvent *e)
+class TransparenciesWindow : public Window
 {
-	switch (e->event) {
-		case WE_PAINT:
-			/* must be sure that the widgets show the transparency variable changes
-			 * also when we use shortcuts */
-			for (uint i = TTW_WIDGET_SIGNS; i < TTW_WIDGET_END; i++) {
-				w->SetWidgetLoweredState(i, IsTransparencySet((TransparencyOption)(i - TTW_WIDGET_SIGNS)));
-			}
-
-			DrawWindowWidgets(w);
-			for (uint i = TO_SIGNS; i < TO_END; i++) {
-				if (HasBit(_transparency_lock, i)) DrawSprite(SPR_LOCK, PAL_NONE, w->widget[TTW_WIDGET_SIGNS + i].left + 1, w->widget[TTW_WIDGET_SIGNS + i].top + 1);
-			}
+	enum TransparencyToolbarWidgets{
+		TTW_WIDGET_SIGNS = 3,    ///< Make signs background transparent
+		TTW_WIDGET_TREES,        ///< Make trees transparent
+		TTW_WIDGET_HOUSES,       ///< Make houses transparent
+		TTW_WIDGET_INDUSTRIES,   ///< Make Industries transparent
+		TTW_WIDGET_BUILDINGS,    ///< Make player buildings and structures transparent
+		TTW_WIDGET_BRIDGES,      ///< Make bridges transparent
+		TTW_WIDGET_STRUCTURES,   ///< Make unmovable structures transparent
+		TTW_WIDGET_CATENARY,     ///< Make catenary transparent
+		TTW_WIDGET_LOADING,      ///< Make loading indicators transparent
+		TTW_WIDGET_END,          ///< End of toggle buttons
 
-			/* Do not draw button for invisible loading indicators */
-			for (uint i = 0; i < 8; i++) {
-				if (i < TTW_WIDGET_BRIDGES - TTW_WIDGET_SIGNS) {
-					DrawFrameRect(i * 22, 38, i * 22 + 19, 46, true, HasBit(_invisibility_opt, i) ? FR_LOWERED : FR_NONE);
-				} else if (i == TTW_WIDGET_BRIDGES - TTW_WIDGET_SIGNS) {
-					DrawFrameRect(i * 22, 38, i * 22 + 41, 46, true, HasBit(_invisibility_opt, i) ? FR_LOWERED : FR_NONE);
-				} else { // i > TTW_WIDGET_BRIDGES - TTW_WIDGET_SIGNS
-					DrawFrameRect((i + 1) * 22, 38, (i + 1) * 22 + 19, 46, true, HasBit(_invisibility_opt, i) ? FR_LOWERED : FR_NONE);
-				}
-			}
-
-			break;
+		/* Panel with buttons for invisibility */
+		TTW_BUTTONS = 12,        ///< Panel with 'invisibility' buttons
+	};
 
-		case WE_CLICK:
-			if (e->we.click.widget >= TTW_WIDGET_SIGNS && e->we.click.widget < TTW_WIDGET_END) {
-				if (_ctrl_pressed) {
-					/* toggle the bit of the transparencies lock variable */
-					ToggleTransparencyLock((TransparencyOption)(e->we.click.widget - TTW_WIDGET_SIGNS));
-					w->SetDirty();
-				} else {
-					/* toggle the bit of the transparencies variable and play a sound */
-					ToggleTransparency((TransparencyOption)(e->we.click.widget - TTW_WIDGET_SIGNS));
-					SndPlayFx(SND_15_BEEP);
-					MarkWholeScreenDirty();
-				}
-			} else if (e->we.click.widget == TTW_BUTTONS) {
-				uint x = e->we.click.pt.x / 22;
+public:
+	TransparenciesWindow(const WindowDesc *desc, int window_number) : Window(desc, window_number)
+	{
+		this->FindWindowPlacementAndResize(desc);
+	}
 
-				if (x > TTW_WIDGET_BRIDGES - TTW_WIDGET_SIGNS) x--;
-				if (x > TTW_WIDGET_CATENARY - TTW_WIDGET_SIGNS) break;
-
-				ToggleInvisibility((TransparencyOption)x);
-				SndPlayFx(SND_15_BEEP);
+	virtual void OnPaint()
+	{
+		/* must be sure that the widgets show the transparency variable changes
+		 * also when we use shortcuts */
+		for (uint i = TTW_WIDGET_SIGNS; i < TTW_WIDGET_END; i++) {
+			this->SetWidgetLoweredState(i, IsTransparencySet((TransparencyOption)(i - TTW_WIDGET_SIGNS)));
+		}
 
-				/* Redraw whole screen only if transparency is set */
-				if (IsTransparencySet((TransparencyOption)x)) {
-					MarkWholeScreenDirty();
-				} else {
-					w->InvalidateWidget(TTW_BUTTONS);
-				}
+		this->DrawWidgets();
+		for (uint i = TO_SIGNS; i < TO_END; i++) {
+			if (HasBit(_transparency_lock, i)) DrawSprite(SPR_LOCK, PAL_NONE, this->widget[TTW_WIDGET_SIGNS + i].left + 1, this->widget[TTW_WIDGET_SIGNS + i].top + 1);
+		}
+
+		/* Do not draw button for invisible loading indicators */
+		for (uint i = 0; i < 8; i++) {
+			if (i < TTW_WIDGET_BRIDGES - TTW_WIDGET_SIGNS) {
+				DrawFrameRect(i * 22, 38, i * 22 + 19, 46, true, HasBit(_invisibility_opt, i) ? FR_LOWERED : FR_NONE);
+			} else if (i == TTW_WIDGET_BRIDGES - TTW_WIDGET_SIGNS) {
+				DrawFrameRect(i * 22, 38, i * 22 + 41, 46, true, HasBit(_invisibility_opt, i) ? FR_LOWERED : FR_NONE);
+			} else { // i > TTW_WIDGET_BRIDGES - TTW_WIDGET_SIGNS
+				DrawFrameRect((i + 1) * 22, 38, (i + 1) * 22 + 19, 46, true, HasBit(_invisibility_opt, i) ? FR_LOWERED : FR_NONE);
 			}
+		}
+	}
 
-			break;
+	virtual void OnClick(Point pt, int widget)
+	{
+		if (widget >= TTW_WIDGET_SIGNS && widget < TTW_WIDGET_END) {
+			if (_ctrl_pressed) {
+				/* toggle the bit of the transparencies lock variable */
+				ToggleTransparencyLock((TransparencyOption)(widget - TTW_WIDGET_SIGNS));
+				this->SetDirty();
+			} else {
+				/* toggle the bit of the transparencies variable and play a sound */
+				ToggleTransparency((TransparencyOption)(widget - TTW_WIDGET_SIGNS));
+				SndPlayFx(SND_15_BEEP);
+				MarkWholeScreenDirty();
+			}
+		} else if (widget == TTW_BUTTONS) {
+			uint x = pt.x / 22;
+
+			if (x > TTW_WIDGET_BRIDGES - TTW_WIDGET_SIGNS) x--;
+			if (x > TTW_WIDGET_CATENARY - TTW_WIDGET_SIGNS) return;
+
+			ToggleInvisibility((TransparencyOption)x);
+			SndPlayFx(SND_15_BEEP);
+
+			/* Redraw whole screen only if transparency is set */
+			if (IsTransparencySet((TransparencyOption)x)) {
+				MarkWholeScreenDirty();
+			} else {
+				this->InvalidateWidget(TTW_BUTTONS);
+			}
+		}
 	}
-}
+};
 
 static const Widget _transparency_widgets[] = {
 { WWT_CLOSEBOX,   RESIZE_NONE,  7,   0,  10,   0,  13, STR_00C5,                 STR_018B_CLOSE_WINDOW},
@@ -121,10 +125,9 @@
 	WC_TRANSPARENCY_TOOLBAR, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
 	_transparency_widgets,
-	TransparencyToolbWndProc
 };
 
 void ShowTransparencyToolbar(void)
 {
-	AllocateWindowDescFront<Window>(&_transparency_desc, 0);
+	AllocateWindowDescFront<TransparenciesWindow>(&_transparency_desc, 0);
 }
--- a/src/tree_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/tree_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -16,178 +16,169 @@
 #include "table/strings.h"
 #include "table/tree_land.h"
 
-struct tree_d {
-	uint16 base;
-	uint16 count;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(tree_d));
-
-static int _tree_to_plant;
 void PlaceTreesRandomly();
 
-static const PalSpriteID _tree_sprites[] = {
-	{ 0x655, PAL_NONE }, { 0x663, PAL_NONE }, { 0x678, PAL_NONE }, { 0x62B, PAL_NONE },
-	{ 0x647, PAL_NONE }, { 0x639, PAL_NONE }, { 0x64E, PAL_NONE }, { 0x632, PAL_NONE },
-	{ 0x67F, PAL_NONE }, { 0x68D, PAL_NONE }, { 0x69B, PAL_NONE }, { 0x6A9, PAL_NONE },
-	{ 0x6AF, PAL_NONE }, { 0x6D2, PAL_NONE }, { 0x6D9, PAL_NONE }, { 0x6C4, PAL_NONE },
-	{ 0x6CB, PAL_NONE }, { 0x6B6, PAL_NONE }, { 0x6BD, PAL_NONE }, { 0x6E0, PAL_NONE },
-	{ 0x72E, PAL_NONE }, { 0x734, PAL_NONE }, { 0x74A, PAL_NONE }, { 0x74F, PAL_NONE },
-	{ 0x76B, PAL_NONE }, { 0x78F, PAL_NONE }, { 0x788, PAL_NONE }, { 0x77B, PAL_NONE },
-	{ 0x75F, PAL_NONE }, { 0x774, PAL_NONE }, { 0x720, PAL_NONE }, { 0x797, PAL_NONE },
-	{ 0x79E, PAL_NONE }, { 0x7A5, PALETTE_TO_GREEN }, { 0x7AC, PALETTE_TO_RED }, { 0x7B3, PAL_NONE },
-	{ 0x7BA, PAL_NONE }, { 0x7C1, PALETTE_TO_RED, }, { 0x7C8, PALETTE_TO_PALE_GREEN }, { 0x7CF, PALETTE_TO_YELLOW }, { 0x7D6, PALETTE_TO_RED }
+class BuildTreesWindow : public Window
+{
+	uint16 base;
+	uint16 count;
+	int tree_to_plant;
+
+	enum BuildTreesWidgets {
+		BTW_CLOSE,
+		BTW_CAPTION,
+		BTW_BACKGROUND,
+		BTW_TYPE_11,
+		BTW_TYPE_12,
+		BTW_TYPE_13,
+		BTW_TYPE_14,
+		BTW_TYPE_21,
+		BTW_TYPE_22,
+		BTW_TYPE_23,
+		BTW_TYPE_24,
+		BTW_TYPE_31,
+		BTW_TYPE_32,
+		BTW_TYPE_33,
+		BTW_TYPE_34,
+		BTW_TYPE_RANDOM,
+		BTW_MANY_RANDOM,
+	};
+
+public:
+	BuildTreesWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+	{
+		if (_game_mode != GM_EDITOR) {
+			this->HideWidget(BTW_MANY_RANDOM);
+			int offset = this->widget[BTW_MANY_RANDOM].bottom - this->widget[BTW_MANY_RANDOM].top;
+			this->height -= offset;
+			this->widget[BTW_BACKGROUND].bottom -= offset;
+		}
+		ResetObjectToPlace();
+		this->FindWindowPlacementAndResize(desc);
+	}
+
+	virtual void OnPaint()
+	{
+		static const PalSpriteID tree_sprites[] = {
+			{ 0x655, PAL_NONE }, { 0x663, PAL_NONE }, { 0x678, PAL_NONE }, { 0x62B, PAL_NONE },
+			{ 0x647, PAL_NONE }, { 0x639, PAL_NONE }, { 0x64E, PAL_NONE }, { 0x632, PAL_NONE },
+			{ 0x67F, PAL_NONE }, { 0x68D, PAL_NONE }, { 0x69B, PAL_NONE }, { 0x6A9, PAL_NONE },
+			{ 0x6AF, PAL_NONE }, { 0x6D2, PAL_NONE }, { 0x6D9, PAL_NONE }, { 0x6C4, PAL_NONE },
+			{ 0x6CB, PAL_NONE }, { 0x6B6, PAL_NONE }, { 0x6BD, PAL_NONE }, { 0x6E0, PAL_NONE },
+			{ 0x72E, PAL_NONE }, { 0x734, PAL_NONE }, { 0x74A, PAL_NONE }, { 0x74F, PAL_NONE },
+			{ 0x76B, PAL_NONE }, { 0x78F, PAL_NONE }, { 0x788, PAL_NONE }, { 0x77B, PAL_NONE },
+			{ 0x75F, PAL_NONE }, { 0x774, PAL_NONE }, { 0x720, PAL_NONE }, { 0x797, PAL_NONE },
+			{ 0x79E, PAL_NONE }, { 0x7A5, PALETTE_TO_GREEN }, { 0x7AC, PALETTE_TO_RED }, { 0x7B3, PAL_NONE },
+			{ 0x7BA, PAL_NONE }, { 0x7C1, PALETTE_TO_RED, }, { 0x7C8, PALETTE_TO_PALE_GREEN }, { 0x7CF, PALETTE_TO_YELLOW }, { 0x7D6, PALETTE_TO_RED }
+		};
+
+		this->DrawWidgets();
+
+		int i = this->base = _tree_base_by_landscape[_opt.landscape];
+		int count = this->count = _tree_count_by_landscape[_opt.landscape];
+
+		int x = 18;
+		int y = 54;
+		do {
+			DrawSprite(tree_sprites[i].sprite, tree_sprites[i].pal, x, y);
+			x += 35;
+			if (!(++i & 3)) {
+				x -= 35 * 4;
+				y += 47;
+			}
+		} while (--count);
+	}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case BTW_TYPE_11: case BTW_TYPE_12: case BTW_TYPE_13: case BTW_TYPE_14:
+			case BTW_TYPE_21: case BTW_TYPE_22: case BTW_TYPE_23: case BTW_TYPE_24:
+			case BTW_TYPE_31: case BTW_TYPE_32: case BTW_TYPE_33: case BTW_TYPE_34:
+				if (widget - BTW_TYPE_11 >= this->count) break;
+
+				if (HandlePlacePushButton(this, widget, SPR_CURSOR_TREE, VHM_RECT, NULL)) {
+					this->tree_to_plant = this->base + widget - BTW_TYPE_11;
+				}
+				break;
+
+			case BTW_TYPE_RANDOM: // tree of random type.
+				if (HandlePlacePushButton(this, BTW_TYPE_RANDOM, SPR_CURSOR_TREE, VHM_RECT, NULL)) {
+					this->tree_to_plant = -1;
+				}
+				break;
+
+			case BTW_MANY_RANDOM: // place trees randomly over the landscape
+				this->LowerWidget(BTW_MANY_RANDOM);
+				this->flags4 |= 5 << WF_TIMEOUT_SHL;
+				SndPlayFx(SND_15_BEEP);
+				PlaceTreesRandomly();
+				MarkWholeScreenDirty();
+				break;
+		}
+	}
+
+	virtual void OnPlaceObject(Point pt, TileIndex tile)
+	{
+		VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_PLANT_TREES);
+		VpSetPlaceSizingLimit(20);
+	}
+
+	virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
+	{
+		VpSelectTilesWithMethod(pt.x, pt.y, select_method);
+	}
+
+	virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
+	{
+		if (pt.x != -1 && select_proc == DDSP_PLANT_TREES) {
+			DoCommandP(end_tile, this->tree_to_plant, start_tile, NULL,
+				CMD_PLANT_TREE | CMD_MSG(STR_2805_CAN_T_PLANT_TREE_HERE));
+		}
+	}
+
+	virtual void OnTimeout()
+	{
+		this->RaiseWidget(BTW_MANY_RANDOM);
+		this->InvalidateWidget(BTW_MANY_RANDOM);
+	}
+
+	virtual void OnPlaceObjectAbort()
+	{
+		this->RaiseButtons();
+	}
 };
 
-static void BuildTreesWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_CREATE:
-			ResetObjectToPlace();
-			break;
-
-		case WE_PAINT: {
-			DrawWindowWidgets(w);
-
-			int i = WP(w, tree_d).base = _tree_base_by_landscape[_opt.landscape];
-			int count = WP(w, tree_d).count = _tree_count_by_landscape[_opt.landscape];
-
-			int x = 18;
-			int y = 54;
-			do {
-				DrawSprite(_tree_sprites[i].sprite, _tree_sprites[i].pal, x, y);
-				x += 35;
-				if (!(++i & 3)) {
-					x -= 35 * 4;
-					y += 47;
-				}
-			} while (--count);
-		} break;
-
-		case WE_CLICK: {
-			int wid = e->we.click.widget;
-
-			switch (wid) {
-				case 0:
-					ResetObjectToPlace();
-					break;
-
-				case 3: case 4: case 5: case 6:
-				case 7: case 8: case 9: case 10:
-				case 11:case 12: case 13: case 14:
-					if (wid - 3 >= WP(w, tree_d).count) break;
-
-					if (HandlePlacePushButton(w, wid, SPR_CURSOR_TREE, VHM_RECT, NULL)) {
-						_tree_to_plant = WP(w, tree_d).base + wid - 3;
-					}
-					break;
-
-				case 15: // tree of random type.
-					if (HandlePlacePushButton(w, 15, SPR_CURSOR_TREE, VHM_RECT, NULL)) {
-						_tree_to_plant = -1;
-					}
-					break;
-
-				case 16: // place trees randomly over the landscape
-					w->LowerWidget(16);
-					w->flags4 |= 5 << WF_TIMEOUT_SHL;
-					SndPlayFx(SND_15_BEEP);
-					PlaceTreesRandomly();
-					MarkWholeScreenDirty();
-					break;
-			}
-		} break;
-
-		case WE_PLACE_OBJ:
-			VpStartPlaceSizing(e->we.place.tile, VPM_X_AND_Y_LIMITED, DDSP_PLANT_TREES);
-			VpSetPlaceSizingLimit(20);
-			break;
-
-		case WE_PLACE_DRAG:
-			VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.select_method);
-			return;
-
-		case WE_PLACE_MOUSEUP:
-			if (e->we.place.pt.x != -1 && e->we.place.select_proc == DDSP_PLANT_TREES) {
-				DoCommandP(e->we.place.tile, _tree_to_plant, e->we.place.starttile, NULL,
-					CMD_PLANT_TREE | CMD_MSG(STR_2805_CAN_T_PLANT_TREE_HERE));
-			}
-			break;
-
-		case WE_TIMEOUT:
-			w->RaiseWidget(16);
-			break;
-
-		case WE_ABORT_PLACE_OBJ:
-			w->RaiseButtons();
-			break;
-	}
-}
-
 static const Widget _build_trees_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   142,     0,    13, STR_2802_TREES,        STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   142,    14,   170, 0x0,                   STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,     2,    35,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,    37,    70,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,    72,   105,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,   107,   140,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,     2,    35,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,    37,    70,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,    72,   105,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,   107,   140,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,     2,    35,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,    37,    70,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,    72,   105,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,   107,   140,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   140,   157,   168, STR_TREES_RANDOM_TYPE, STR_TREES_RANDOM_TYPE_TIP},
+{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},              // BTW_CLOSE
+{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   142,     0,    13, STR_2802_TREES,        STR_018C_WINDOW_TITLE_DRAG_THIS},    // BTW_CAPTION
+{      WWT_PANEL,   RESIZE_NONE,     7,     0,   142,    14,   183, 0x0,                   STR_NULL},                           // BTW_BACKGROUND
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,    35,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT}, // BTW_TYPE_11
+{      WWT_PANEL,   RESIZE_NONE,    14,    37,    70,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT}, // BTW_TYPE_12
+{      WWT_PANEL,   RESIZE_NONE,    14,    72,   105,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT}, // BTW_TYPE_13
+{      WWT_PANEL,   RESIZE_NONE,    14,   107,   140,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT}, // BTW_TYPE_14
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,    35,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT}, // BTW_TYPE_21
+{      WWT_PANEL,   RESIZE_NONE,    14,    37,    70,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT}, // BTW_TYPE_22
+{      WWT_PANEL,   RESIZE_NONE,    14,    72,   105,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT}, // BTW_TYPE_23
+{      WWT_PANEL,   RESIZE_NONE,    14,   107,   140,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT}, // BTW_TYPE_24
+{      WWT_PANEL,   RESIZE_NONE,    14,     2,    35,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT}, // BTW_TYPE_31
+{      WWT_PANEL,   RESIZE_NONE,    14,    37,    70,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT}, // BTW_TYPE_32
+{      WWT_PANEL,   RESIZE_NONE,    14,    72,   105,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT}, // BTW_TYPE_33
+{      WWT_PANEL,   RESIZE_NONE,    14,   107,   140,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT}, // BTW_TYPE_34
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   140,   157,   168, STR_TREES_RANDOM_TYPE, STR_TREES_RANDOM_TYPE_TIP},          // BTW_TYPE_RANDOM
+{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   140,   170,   181, STR_028A_RANDOM_TREES, STR_028B_PLANT_TREES_RANDOMLY_OVER}, // BTW_MANY_RANDOM
 {    WIDGETS_END},
 };
 
 static const WindowDesc _build_trees_desc = {
-	497, 22, 143, 171, 143, 171,
-	WC_BUILD_TREES, WC_SCEN_LAND_GEN,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_build_trees_widgets,
-	BuildTreesWndProc
-};
-
-static const Widget _build_trees_scen_widgets[] = {
-{   WWT_CLOSEBOX,   RESIZE_NONE,     7,     0,    10,     0,    13, STR_00C5,              STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,   RESIZE_NONE,     7,    11,   142,     0,    13, STR_2802_TREES,        STR_018C_WINDOW_TITLE_DRAG_THIS},
-{      WWT_PANEL,   RESIZE_NONE,     7,     0,   142,    14,   183, 0x0,                   STR_NULL},
-{      WWT_PANEL,   RESIZE_NONE,    14,     2,    35,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,    37,    70,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,    72,   105,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,   107,   140,    16,    61, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,     2,    35,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,    37,    70,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,    72,   105,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,   107,   140,    63,   108, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,     2,    35,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,    37,    70,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,    72,   105,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{      WWT_PANEL,   RESIZE_NONE,    14,   107,   140,   110,   155, 0x0,                   STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   140,   157,   168, STR_TREES_RANDOM_TYPE, STR_TREES_RANDOM_TYPE_TIP},
-{    WWT_TEXTBTN,   RESIZE_NONE,    14,     2,   140,   170,   181, STR_028A_RANDOM_TREES, STR_028B_PLANT_TREES_RANDOMLY_OVER},
-{    WIDGETS_END},
-};
-
-static const WindowDesc _build_trees_scen_desc = {
 	WDP_AUTO, WDP_AUTO, 143, 184, 143, 184,
 	WC_BUILD_TREES, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
-	_build_trees_scen_widgets,
-	BuildTreesWndProc
+	_build_trees_widgets,
 };
 
-
 void ShowBuildTreesToolbar()
 {
-	if (!IsValidPlayer(_current_player)) return;
-	AllocateWindowDescFront<Window>(&_build_trees_desc, 0);
+	if (_game_mode != GM_EDITOR && !IsValidPlayer(_current_player)) return;
+	AllocateWindowDescFront<BuildTreesWindow>(&_build_trees_desc, 0);
 }
-
-void ShowBuildTreesScenToolbar()
-{
-	AllocateWindowDescFront<Window>(&_build_trees_scen_desc, 0);
-}
--- a/src/tunnelbridge_cmd.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/tunnelbridge_cmd.cpp	Mon May 19 15:13:58 2008 +0000
@@ -494,7 +494,7 @@
 
 	delta = TileOffsByDiagDir(direction);
 	DiagDirection tunnel_in_way_dir;
-	if (OtherAxis(DiagDirToAxis(direction)) == AXIS_X) {
+	if (DiagDirToAxis(direction) == AXIS_Y) {
 		tunnel_in_way_dir = (TileX(start_tile) < (MapMaxX() / 2)) ? DIAGDIR_SW : DIAGDIR_NE;
 	} else {
 		tunnel_in_way_dir = (TileY(start_tile) < (MapMaxX() / 2)) ? DIAGDIR_SE : DIAGDIR_NW;
@@ -558,7 +558,7 @@
 			MakeRailTunnel(start_tile, _current_player, direction,                 (RailType)GB(p1, 0, 4));
 			MakeRailTunnel(end_tile,   _current_player, ReverseDiagDir(direction), (RailType)GB(p1, 0, 4));
 			AddSideToSignalBuffer(start_tile, INVALID_DIAGDIR, _current_player);
-			YapfNotifyTrackLayoutChange(start_tile, AxisToTrack(DiagDirToAxis(direction)));
+			YapfNotifyTrackLayoutChange(start_tile, DiagDirToDiagTrack(direction));
 		} else {
 			MakeRoadTunnel(start_tile, _current_player, direction,                 (RoadTypes)GB(p1, 0, 3));
 			MakeRoadTunnel(end_tile,   _current_player, ReverseDiagDir(direction), (RoadTypes)GB(p1, 0, 3));
@@ -623,7 +623,7 @@
 			AddSideToSignalBuffer(tile,    ReverseDiagDir(dir), owner);
 			AddSideToSignalBuffer(endtile, dir,                 owner);
 
-			Track track = AxisToTrack(DiagDirToAxis(dir));
+			Track track = DiagDirToDiagTrack(dir);
 			YapfNotifyTrackLayoutChange(tile,    track);
 			YapfNotifyTrackLayoutChange(endtile, track);
 		} else {
@@ -691,7 +691,7 @@
 			AddSideToSignalBuffer(tile,    ReverseDiagDir(direction), owner);
 			AddSideToSignalBuffer(endtile, direction,                 owner);
 
-			Track track = AxisToTrack(DiagDirToAxis(direction));
+			Track track = DiagDirToDiagTrack(direction);
 			YapfNotifyTrackLayoutChange(tile,    track);
 			YapfNotifyTrackLayoutChange(endtile, track);
 		}
@@ -1233,7 +1233,7 @@
 
 	DiagDirection dir = GetTunnelBridgeDirection(tile);
 	if (side != INVALID_DIAGDIR && side != ReverseDiagDir(dir)) return 0;
-	return CombineTrackStatus(TrackBitsToTrackdirBits(AxisToTrackBits(DiagDirToAxis(dir))), TRACKDIR_BIT_NONE);
+	return CombineTrackStatus(TrackBitsToTrackdirBits(DiagDirToDiagTrackBits(dir)), TRACKDIR_BIT_NONE);
 }
 
 static void ChangeTileOwner_TunnelBridge(TileIndex tile, PlayerID old_player, PlayerID new_player)
--- a/src/vehicle.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/vehicle.cpp	Mon May 19 15:13:58 2008 +0000
@@ -591,11 +591,8 @@
 		delete this->Next();
 	}
 
-	Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
-	if (w != NULL && w->viewport->follow_vehicle == this->index) {
-		ScrollMainWindowTo(this->x_pos, this->y_pos, true); // lock the main view on the vehicle's last position
-		w->viewport->follow_vehicle = INVALID_VEHICLE;
-	}
+	extern void StopGlobalFollowVehicle(const Vehicle *v);
+	StopGlobalFollowVehicle(this);
 }
 
 Vehicle::~Vehicle()
@@ -953,7 +950,7 @@
 
 	SetDParam(0, _vehicle_type_names[v->type]);
 	SetDParam(1, v->unitnumber);
-	AddNewsItem(msg, NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, DNC_NONE, v->index, 0);
+	AddNewsItem(msg, NS_ADVICE, v->index, 0);
 }
 
 void AgeVehicle(Vehicle *v)
@@ -1553,7 +1550,7 @@
  * @param color The string to show depending on if we are unloading or loading
  * @return A percentage of how full the Vehicle is.
  */
-uint8 CalcPercentVehicleFilled(Vehicle *v, StringID *color)
+uint8 CalcPercentVehicleFilled(const Vehicle *v, StringID *color)
 {
 	int count = 0;
 	int max = 0;
@@ -1652,7 +1649,7 @@
 					/* Notify the user that we stopped the vehicle */
 					SetDParam(0, _vehicle_type_names[v->type]);
 					SetDParam(1, v->unitnumber);
-					AddNewsItem(STR_ORDER_REFIT_FAILED, NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, DNC_NONE, v->index, 0);
+					AddNewsItem(STR_ORDER_REFIT_FAILED, NS_ADVICE, v->index, 0);
 				}
 			} else if (v->owner == _local_player && cost.GetCost() != 0) {
 				ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
@@ -1678,7 +1675,7 @@
 				}
 
 				SetDParam(0, v->unitnumber);
-				AddNewsItem(string, NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, DNC_NONE, v->index, 0);
+				AddNewsItem(string, NS_ADVICE, v->index, 0);
 			}
 			AI_Event(v->owner, new AIEventVehicleWaitingInDepot(v->index));
 		}
@@ -1738,7 +1735,7 @@
 	if (flags & DC_EXEC) {
 		free(v->name);
 		v->name = strdup(_cmd_text);
-		ResortVehicleLists();
+		InvalidateWindowClassesData(WC_TRAINS_LIST, 1);
 		MarkWholeScreenDirty();
 	}
 
@@ -1869,34 +1866,34 @@
 	switch (v->type) {
 		case VEH_TRAIN:
 			if (v->u.rail.track == TRACK_BIT_DEPOT) // We'll assume the train is facing outwards
-				return DiagdirToDiagTrackdir(GetRailDepotDirection(v->tile)); // Train in depot
+				return DiagDirToDiagTrackdir(GetRailDepotDirection(v->tile)); // Train in depot
 
 			if (v->u.rail.track == TRACK_BIT_WORMHOLE) // train in tunnel, so just use his direction and assume a diagonal track
-				return DiagdirToDiagTrackdir(DirToDiagDir(v->direction));
+				return DiagDirToDiagTrackdir(DirToDiagDir(v->direction));
 
 			return TrackDirectionToTrackdir(FindFirstTrack(v->u.rail.track), v->direction);
 
 		case VEH_SHIP:
 			if (v->IsInDepot())
 				// We'll assume the ship is facing outwards
-				return DiagdirToDiagTrackdir(GetShipDepotDirection(v->tile));
+				return DiagDirToDiagTrackdir(GetShipDepotDirection(v->tile));
 
 			return TrackDirectionToTrackdir(FindFirstTrack(v->u.ship.state), v->direction);
 
 		case VEH_ROAD:
 			if (v->IsInDepot()) // We'll assume the road vehicle is facing outwards
-				return DiagdirToDiagTrackdir(GetRoadDepotDirection(v->tile));
+				return DiagDirToDiagTrackdir(GetRoadDepotDirection(v->tile));
 
 			if (IsStandardRoadStopTile(v->tile)) // We'll assume the road vehicle is facing outwards
-				return DiagdirToDiagTrackdir(GetRoadStopDir(v->tile)); // Road vehicle in a station
-
-			if (IsDriveThroughStopTile(v->tile)) return DiagdirToDiagTrackdir(DirToDiagDir(v->direction));
+				return DiagDirToDiagTrackdir(GetRoadStopDir(v->tile)); // Road vehicle in a station
+
+			if (IsDriveThroughStopTile(v->tile)) return DiagDirToDiagTrackdir(DirToDiagDir(v->direction));
 
 			/* If vehicle's state is a valid track direction (vehicle is not turning around) return it */
 			if (!IsReversingRoadTrackdir((Trackdir)v->u.road.state)) return (Trackdir)v->u.road.state;
 
 			/* Vehicle is turning around, get the direction from vehicle's direction */
-			return DiagdirToDiagTrackdir(DirToDiagDir(v->direction));
+			return DiagDirToDiagTrackdir(DirToDiagDir(v->direction));
 
 		/* case VEH_AIRCRAFT: case VEH_EFFECT: case VEH_DISASTER: */
 		default: return INVALID_TRACKDIR;
@@ -2759,7 +2756,11 @@
 		memcpy(dest, backup, sizeof(Vehicle));
 
 		/* We decreased the engine count when we sold the engines so we will increase it again. */
-		if (IsEngineCountable(backup)) p->num_engines[backup->engine_type]++;
+		if (IsEngineCountable(backup)) {
+			p->num_engines[backup->engine_type]++;
+			if (IsValidGroupID(backup->group_id)) GetGroup(backup->group_id)->num_engines[backup->engine_type]++;
+			if (backup->IsPrimaryVehicle()) IncreaseGroupNumVehicle(backup->group_id);
+		}
 
 		/* Update hash. */
 		Vehicle *dummy = dest;
@@ -2806,11 +2807,11 @@
 {
 	if (!ContainsBackup()) return v;
 	if (v != NULL) {
-		ChangeVehicleViewWindow(v, INVALID_VEHICLE);
+		ChangeVehicleViewWindow(v->index, INVALID_VEHICLE);
 		DoCommand(0, v->index, 1, DC_EXEC, GetCmdSellVeh(v));
 	}
 	v = RestoreBackupVehicle(this->vehicles, p);
-	ChangeVehicleViewWindow(INVALID_VEHICLE, v);
+	ChangeVehicleViewWindow(INVALID_VEHICLE, v->index);
 	if (orders != NULL) RestoreVehicleOrdersBruteForce(v, orders);
 	if (economy != NULL) economy->Restore();
 	/* If we stored cargo as well then we should restore it. */
--- a/src/vehicle_func.h	Mon May 19 14:14:33 2008 +0000
+++ b/src/vehicle_func.h	Mon May 19 15:13:58 2008 +0000
@@ -32,7 +32,7 @@
 void *VehicleFromPosXY(int x, int y, void *data, VehicleFromPosProc *proc);
 void CallVehicleTicks();
 Vehicle *FindVehicleOnTileZ(TileIndex tile, byte z);
-uint8 CalcPercentVehicleFilled(Vehicle *v, StringID *color);
+uint8 CalcPercentVehicleFilled(const Vehicle *v, StringID *color);
 
 void InitializeTrains();
 byte VehicleRandomBits();
--- a/src/vehicle_gui.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/vehicle_gui.cpp	Mon May 19 15:13:58 2008 +0000
@@ -40,20 +40,6 @@
 #include "table/sprites.h"
 #include "table/strings.h"
 
-struct vehicledetails_d {
-	byte tab;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(vehicledetails_d));
-
-struct refit_d {
-	int sel;
-	struct RefitOption *cargo;
-	struct RefitList *list;
-	uint length;
-	VehicleOrderID order;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(refit_d));
-
 Sorting _sorting;
 static bool   _internal_sort_order;     // descending/ascending
 
@@ -100,47 +86,6 @@
 	INVALID_STRING_ID
 };
 
-/**
- * Set sort list flag for all vehicle list windows
- * @param sl_flag Sort list flag to set
- */
-static void SetVehicleListsFlag(SortListFlags sl_flag)
-{
-	Window* const *wz;
-
-	FOR_ALL_WINDOWS(wz) {
-		Window *w = *wz;
-
-		switch (w->window_class) {
-			case WC_TRAINS_LIST:
-			case WC_ROADVEH_LIST:
-			case WC_SHIPS_LIST:
-			case WC_AIRCRAFT_LIST:
-				dynamic_cast<VehicleListBase*>(w)->vehicles.flags |= sl_flag;
-				w->SetDirty();
-				break;
-
-			default: break;
-		}
-	}
-}
-
-/**
- * Rebuild all vehicle list windows
- */
-void RebuildVehicleLists()
-{
-	SetVehicleListsFlag(VL_REBUILD);
-}
-
-/**
- * Resort all vehicle list windows
- */
-void ResortVehicleLists()
-{
-	SetVehicleListsFlag(VL_RESORT);
-}
-
 void BuildVehicleList(VehicleListBase *vl, PlayerID owner, uint16 index, uint16 window_type)
 {
 	if (!(vl->vehicles.flags & VL_REBUILD)) return;
@@ -333,89 +278,141 @@
 	return selected;
 }
 
-static void VehicleRefitWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_PAINT: {
-			Vehicle *v = GetVehicle(w->window_number);
+struct RefitWindow : public Window {
+	int sel;
+	RefitOption *cargo;
+	RefitList *list;
+	uint length;
+	VehicleOrderID order;
 
-			if (v->type == VEH_TRAIN) {
-				uint length = CountVehiclesInChain(v);
+	RefitWindow(const WindowDesc *desc, const Vehicle *v, VehicleOrderID order) : Window(desc, v->index)
+	{
+		this->caption_color = v->owner;
+		this->vscroll.cap = 8;
+		this->resize.step_height = 14;
 
-				if (length != WP(w, refit_d).length) {
-					/* Consist length has changed, so rebuild the refit list */
-					free(WP(w, refit_d).list->items);
-					free(WP(w, refit_d).list);
-					WP(w, refit_d).list = BuildRefitList(v);
-					WP(w, refit_d).length = length;
+		this->order = order;
+		this->sel  = -1;
+		this->list = BuildRefitList(v);
+		if (v->type == VEH_TRAIN) this->length = CountVehiclesInChain(v);
+		SetVScrollCount(this, this->list->num_lines);
+
+		switch (v->type) {
+			case VEH_TRAIN:
+				this->widget[3].tooltips = STR_RAIL_SELECT_TYPE_OF_CARGO_FOR;
+				this->widget[6].data     = STR_RAIL_REFIT_VEHICLE;
+				this->widget[6].tooltips = STR_RAIL_REFIT_TO_CARRY_HIGHLIGHTED;
+				break;
+
+			case VEH_ROAD:
+				this->widget[3].tooltips = STR_ROAD_SELECT_TYPE_OF_CARGO_FOR;
+				this->widget[6].data     = STR_REFIT_ROAD_VEHICLE;
+				this->widget[6].tooltips = STR_REFIT_ROAD_VEHICLE_TO_CARRY_HIGHLIGHTED;
+				break;
+
+			case VEH_SHIP:
+				this->widget[3].tooltips = STR_983D_SELECT_TYPE_OF_CARGO_FOR;
+				this->widget[6].data     = STR_983C_REFIT_SHIP;
+				this->widget[6].tooltips = STR_983E_REFIT_SHIP_TO_CARRY_HIGHLIGHTED;
+				break;
+
+			case VEH_AIRCRAFT:
+				this->widget[3].tooltips = STR_A03E_SELECT_TYPE_OF_CARGO_FOR;
+				this->widget[6].data     = STR_A03D_REFIT_AIRCRAFT;
+				this->widget[6].tooltips = STR_A03F_REFIT_AIRCRAFT_TO_CARRY;
+				break;
+
+			default: NOT_REACHED();
+		}
+
+		this->FindWindowPlacementAndResize(desc);
+	}
+
+	~RefitWindow()
+	{
+		free(this->list->items);
+		free(this->list);
+	}
+
+	virtual void OnPaint()
+	{
+		Vehicle *v = GetVehicle(this->window_number);
+
+		if (v->type == VEH_TRAIN) {
+			uint length = CountVehiclesInChain(v);
+
+			if (length != this->length) {
+				/* Consist length has changed, so rebuild the refit list */
+				free(this->list->items);
+				free(this->list);
+				this->list = BuildRefitList(v);
+				this->length = length;
+			}
+		}
+
+		SetVScrollCount(this, this->list->num_lines);
+
+		SetDParam(0, v->index);
+		this->DrawWidgets();
+
+		this->cargo = DrawVehicleRefitWindow(this->list, this->sel, this->vscroll.pos, this->vscroll.cap, this->resize.step_height);
+
+		if (this->cargo != NULL) {
+			CommandCost cost;
+
+			cost = DoCommand(v->tile, v->index, this->cargo->cargo | this->cargo->subtype << 8,
+							 DC_QUERY_COST, GetCmdRefitVeh(v->type));
+
+			if (CmdSucceeded(cost)) {
+				SetDParam(0, this->cargo->cargo);
+				SetDParam(1, _returned_refit_capacity);
+				SetDParam(2, cost.GetCost());
+				DrawString(2, this->widget[5].top + 1, STR_9840_NEW_CAPACITY_COST_OF_REFIT, TC_FROMSTRING);
+			}
+		}
+	}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		switch (widget) {
+			case 3: { // listbox
+				int y = pt.y - this->widget[3].top;
+				if (y >= 0) {
+					this->sel = (y / (int)this->resize.step_height) + this->vscroll.pos;
+					this->SetDirty();
 				}
+				break;
 			}
 
-			SetVScrollCount(w, WP(w, refit_d).list->num_lines);
-
-			SetDParam(0, v->index);
-			DrawWindowWidgets(w);
-
-			WP(w, refit_d).cargo = DrawVehicleRefitWindow(WP(w, refit_d).list, WP(w, refit_d).sel, w->vscroll.pos, w->vscroll.cap, w->resize.step_height);
-
-			if (WP(w, refit_d).cargo != NULL) {
-				CommandCost cost;
-
-				cost = DoCommand(v->tile, v->index, WP(w, refit_d).cargo->cargo | WP(w, refit_d).cargo->subtype << 8,
-								 DC_QUERY_COST, GetCmdRefitVeh(GetVehicle(w->window_number)->type));
+			case 6: // refit button
+				if (this->cargo != NULL) {
+					const Vehicle *v = GetVehicle(this->window_number);
 
-				if (CmdSucceeded(cost)) {
-					SetDParam(0, WP(w, refit_d).cargo->cargo);
-					SetDParam(1, _returned_refit_capacity);
-					SetDParam(2, cost.GetCost());
-					DrawString(2, w->widget[5].top + 1, STR_9840_NEW_CAPACITY_COST_OF_REFIT, TC_FROMSTRING);
-				}
-			}
-		} break;
+					if (this->order == INVALID_VEH_ORDER_ID) {
+						int command = 0;
 
-		case WE_CLICK:
-			switch (e->we.click.widget) {
-				case 3: { // listbox
-					int y = e->we.click.pt.y - w->widget[3].top;
-					if (y >= 0) {
-						WP(w, refit_d).sel = (y / (int)w->resize.step_height) + w->vscroll.pos;
-						w->SetDirty();
+						switch (v->type) {
+							default: NOT_REACHED();
+							case VEH_TRAIN:    command = CMD_REFIT_RAIL_VEHICLE | CMD_MSG(STR_RAIL_CAN_T_REFIT_VEHICLE);  break;
+							case VEH_ROAD:     command = CMD_REFIT_ROAD_VEH     | CMD_MSG(STR_REFIT_ROAD_VEHICLE_CAN_T);  break;
+							case VEH_SHIP:     command = CMD_REFIT_SHIP         | CMD_MSG(STR_9841_CAN_T_REFIT_SHIP);     break;
+							case VEH_AIRCRAFT: command = CMD_REFIT_AIRCRAFT     | CMD_MSG(STR_A042_CAN_T_REFIT_AIRCRAFT); break;
+						}
+						if (DoCommandP(v->tile, v->index, this->cargo->cargo | this->cargo->subtype << 8, NULL, command)) delete this;
+					} else {
+						if (DoCommandP(v->tile, v->index, this->cargo->cargo | this->cargo->subtype << 8 | this->order << 16, NULL, CMD_ORDER_REFIT)) delete this;
 					}
-				} break;
-				case 6: // refit button
-					if (WP(w, refit_d).cargo != NULL) {
-						const Vehicle *v = GetVehicle(w->window_number);
-
-						if (WP(w, refit_d).order == INVALID_VEH_ORDER_ID) {
-							int command = 0;
+				}
+				break;
+		}
+	}
 
-							switch (v->type) {
-								default: NOT_REACHED();
-								case VEH_TRAIN:    command = CMD_REFIT_RAIL_VEHICLE | CMD_MSG(STR_RAIL_CAN_T_REFIT_VEHICLE);  break;
-								case VEH_ROAD:     command = CMD_REFIT_ROAD_VEH     | CMD_MSG(STR_REFIT_ROAD_VEHICLE_CAN_T);  break;
-								case VEH_SHIP:     command = CMD_REFIT_SHIP         | CMD_MSG(STR_9841_CAN_T_REFIT_SHIP);     break;
-								case VEH_AIRCRAFT: command = CMD_REFIT_AIRCRAFT     | CMD_MSG(STR_A042_CAN_T_REFIT_AIRCRAFT); break;
-							}
-							if (DoCommandP(v->tile, v->index, WP(w, refit_d).cargo->cargo | WP(w, refit_d).cargo->subtype << 8, NULL, command)) delete w;
-						} else {
-							if (DoCommandP(v->tile, v->index, WP(w, refit_d).cargo->cargo | WP(w, refit_d).cargo->subtype << 8 | WP(w, refit_d).order << 16, NULL, CMD_ORDER_REFIT)) delete w;
-						}
-					}
-					break;
-			}
-			break;
-
-		case WE_RESIZE:
-			w->vscroll.cap += e->we.sizing.diff.y / (int)w->resize.step_height;
-			w->widget[3].data = (w->vscroll.cap << 8) + 1;
-			break;
-
-		case WE_DESTROY:
-			free(WP(w, refit_d).list->items);
-			free(WP(w, refit_d).list);
-			break;
+	virtual void OnResize(Point new_size, Point delta)
+	{
+		this->vscroll.cap += delta.y / (int)this->resize.step_height;
+		this->widget[3].data = (this->vscroll.cap << 8) + 1;
 	}
-}
+};
 
 
 static const Widget _vehicle_refit_widgets[] = {
@@ -435,7 +432,6 @@
 	WC_VEHICLE_REFIT, WC_VEHICLE_VIEW,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
 	_vehicle_refit_widgets,
-	VehicleRefitWndProc,
 };
 
 /** Show the refit window for a vehicle
@@ -444,46 +440,8 @@
 */
 void ShowVehicleRefitWindow(const Vehicle *v, VehicleOrderID order)
 {
-	Window *w;
-
 	DeleteWindowById(WC_VEHICLE_REFIT, v->index);
-
-	w = AllocateWindowDescFront<Window>(&_vehicle_refit_desc, v->index);
-	WP(w, refit_d).order = order;
-
-	if (w != NULL) {
-		w->caption_color = v->owner;
-		w->vscroll.cap = 8;
-		w->resize.step_height = 14;
-		WP(w, refit_d).sel  = -1;
-		WP(w, refit_d).list = BuildRefitList(v);
-		if (v->type == VEH_TRAIN) WP(w, refit_d).length = CountVehiclesInChain(v);
-		SetVScrollCount(w, WP(w, refit_d).list->num_lines);
-
-		switch (v->type) {
-			case VEH_TRAIN:
-				w->widget[3].tooltips = STR_RAIL_SELECT_TYPE_OF_CARGO_FOR;
-				w->widget[6].data     = STR_RAIL_REFIT_VEHICLE;
-				w->widget[6].tooltips = STR_RAIL_REFIT_TO_CARRY_HIGHLIGHTED;
-				break;
-			case VEH_ROAD:
-				w->widget[3].tooltips = STR_ROAD_SELECT_TYPE_OF_CARGO_FOR;
-				w->widget[6].data     = STR_REFIT_ROAD_VEHICLE;
-				w->widget[6].tooltips = STR_REFIT_ROAD_VEHICLE_TO_CARRY_HIGHLIGHTED;
-				break;
-			case VEH_SHIP:
-				w->widget[3].tooltips = STR_983D_SELECT_TYPE_OF_CARGO_FOR;
-				w->widget[6].data     = STR_983C_REFIT_SHIP;
-				w->widget[6].tooltips = STR_983E_REFIT_SHIP_TO_CARRY_HIGHLIGHTED;
-				break;
-			case VEH_AIRCRAFT:
-				w->widget[3].tooltips = STR_A03E_SELECT_TYPE_OF_CARGO_FOR;
-				w->widget[6].data     = STR_A03D_REFIT_AIRCRAFT;
-				w->widget[6].tooltips = STR_A03F_REFIT_AIRCRAFT_TO_CARRY;
-				break;
-			default: NOT_REACHED();
-		}
-	}
+	new RefitWindow(&_vehicle_refit_desc, v, order);
 }
 
 /** Display additional text from NewGRF in the purchase information window */
@@ -841,7 +799,7 @@
  */
 struct VehicleListWindow : public Window, public VehicleListBase {
 
-	VehicleListWindow(const WindowDesc *desc, void *data, WindowNumber window_number) : Window(desc, data, window_number)
+	VehicleListWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
 	{
 		uint16 window_type = this->window_number & VLW_MASK;
 		PlayerID player = (PlayerID)GB(this->window_number, 0, 8);
@@ -1028,12 +986,12 @@
 			VLW_WIDGET_START_ALL,
 			WIDGET_LIST_END);
 
-		DrawWindowWidgets(this);
+		this->DrawWidgets();
 
 		/* draw sorting criteria string */
 		DrawString(85, 15, _vehicle_sort_listing[this->vehicles.sort_type], TC_BLACK);
 		/* draw arrow pointing up/down for ascending/descending sorting */
-		DrawSortButtonState(this, VLW_WIDGET_SORT_ORDER, this->vehicles.flags & VL_DESC ? SBS_DOWN : SBS_UP);
+		this->DrawSortButtonState(VLW_WIDGET_SORT_ORDER, this->vehicles.flags & VL_DESC ? SBS_DOWN : SBS_UP);
 
 		max = min(this->vscroll.pos + this->vscroll.cap, this->vehicles.list_length);
 		for (i = this->vscroll.pos; i < max; ++i) {
@@ -1187,6 +1145,11 @@
 		this->vscroll.cap += delta.y / (int)this->resize.step_height;
 		this->widget[VLW_WIDGET_LIST].data = (this->vscroll.cap << 8) + 1;
 	}
+
+	virtual void OnInvalidateData(int data)
+	{
+		this->vehicles.flags |= (data == 0 ? VL_REBUILD : VL_RESORT);
+	}
 };
 
 static const WindowDesc _player_vehicle_list_train_desc = {
@@ -1194,7 +1157,6 @@
 	WC_TRAINS_LIST, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
 	_vehicle_list_widgets,
-	NULL
 };
 
 static const WindowDesc _player_vehicle_list_road_veh_desc = {
@@ -1202,7 +1164,6 @@
 	WC_ROADVEH_LIST, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
 	_vehicle_list_widgets,
-	NULL
 };
 
 static const WindowDesc _player_vehicle_list_ship_desc = {
@@ -1210,7 +1171,6 @@
 	WC_SHIPS_LIST, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
 	_vehicle_list_widgets,
-	NULL
 };
 
 static const WindowDesc _player_vehicle_list_aircraft_desc = {
@@ -1218,7 +1178,6 @@
 	WC_AIRCRAFT_LIST, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
 	_vehicle_list_widgets,
-	NULL
 };
 
 static void ShowVehicleListWindowLocal(PlayerID player, uint16 VLW_flag, VehicleType vehicle_type, uint16 unique_number)
@@ -1374,78 +1333,6 @@
 	},
 };
 
-/** Initialize a newly created vehicle details window */
-void CreateVehicleDetailsWindow(Window *w)
-{
-	const Vehicle *v = GetVehicle(w->window_number);
-
-	switch (v->type) {
-		case VEH_TRAIN:
-			ResizeWindow(w, 0, 39);
-
-			w->vscroll.cap = 6;
-			w->height += 12;
-			w->resize.step_height = 14;
-			w->resize.height = w->height - 14 * 2; // Minimum of 4 wagons in the display
-
-			w->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_8867_NAME_TRAIN;
-			w->widget[VLD_WIDGET_CAPTION].data = STR_8802_DETAILS;
-			break;
-
-		case VEH_ROAD: {
-			w->widget[VLD_WIDGET_CAPTION].data = STR_900C_DETAILS;
-			w->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_902E_NAME_ROAD_VEHICLE;
-
-			if (!RoadVehHasArticPart(v)) break;
-
-			/* Draw the text under the vehicle instead of next to it, minus the
-			* height already allocated for the cargo of the first vehicle. */
-			uint height_extension = 15 - 11;
-
-			/* Add space for the cargo amount for each part. */
-			for (const Vehicle *u = v; u != NULL; u = u->Next()) {
-				height_extension += 11;
-			}
-
-			ResizeWindow(w, 0, height_extension);
-		} break;
-
-		case VEH_SHIP:
-			w->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_982F_NAME_SHIP;
-			w->widget[VLD_WIDGET_CAPTION].data = STR_9811_DETAILS;
-			break;
-
-		case VEH_AIRCRAFT:
-			ResizeWindow(w, 0, 11);
-			w->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_A032_NAME_AIRCRAFT;
-			w->widget[VLD_WIDGET_CAPTION].data = STR_A00C_DETAILS;
-			break;
-		default: NOT_REACHED();
-	}
-
-	if (v->type != VEH_TRAIN) {
-		w->vscroll.cap = 1;
-		w->widget[VLD_WIDGET_MIDDLE_DETAILS].right += 12;
-	}
-
-	w->widget[VLD_WIDGET_MIDDLE_DETAILS].data = (w->vscroll.cap << 8) + 1;
-	w->caption_color = v->owner;
-
-	WP(w, vehicledetails_d).tab = 0;
-}
-
-/** Checks whether service interval is enabled for the vehicle. */
-static inline bool IsVehicleServiceIntervalEnabled(const VehicleType vehicle_type)
-{
-	switch (vehicle_type) {
-		default: NOT_REACHED();
-		case VEH_TRAIN:    return _patches.servint_trains   != 0; break;
-		case VEH_ROAD:     return _patches.servint_roadveh  != 0; break;
-		case VEH_SHIP:     return _patches.servint_ships    != 0; break;
-		case VEH_AIRCRAFT: return _patches.servint_aircraft != 0; break;
-	}
-	return false; // kill a compiler warning
-}
 
 extern int GetTrainDetailsWndVScroll(VehicleID veh_id, byte det_tab);
 extern void DrawTrainDetails(const Vehicle *v, int x, int y, int vscroll_pos, uint16 vscroll_cap, byte det_tab);
@@ -1453,201 +1340,267 @@
 extern void DrawShipDetails(const Vehicle *v, int x, int y);
 extern void DrawAircraftDetails(const Vehicle *v, int x, int y);
 
-/**
-* Draw the details for the given vehicle at the position (x, y) of the Details windows
-*
-* @param v current vehicle
-* @param x The x coordinate
-* @param y The y coordinate
-* @param vscroll_pos (train only)
-* @param vscroll_cap (train only)
-* @param det_tab (train only)
-*/
-static inline void DrawVehicleDetails(const Vehicle *v, int x, int y, int vscroll_pos, uint vscroll_cap, byte det_tab)
-{
-	switch (v->type) {
-		case VEH_TRAIN:    DrawTrainDetails(v, x, y, vscroll_pos, vscroll_cap, det_tab);  break;
-		case VEH_ROAD:     DrawRoadVehDetails(v, x, y);  break;
-		case VEH_SHIP:     DrawShipDetails(v, x, y);     break;
-		case VEH_AIRCRAFT: DrawAircraftDetails(v, x, y); break;
-		default: NOT_REACHED();
-	}
-}
-
-/** Repaint vehicle details window. */
-static void DrawVehicleDetailsWindow(Window *w)
-{
-	const Vehicle *v = GetVehicle(w->window_number);
-	byte det_tab = WP(w, vehicledetails_d).tab;
-
-	w->SetWidgetDisabledState(VLD_WIDGET_RENAME_VEHICLE, v->owner != _local_player);
-
-	if (v->type == VEH_TRAIN) {
-		w->DisableWidget(det_tab + VLD_WIDGET_DETAILS_CARGO_CARRIED);
-		SetVScrollCount(w, GetTrainDetailsWndVScroll(v->index, det_tab));
-	}
+struct VehicleDetailsWindow : Window {
+	int tab;
 
-	w->SetWidgetsHiddenState(v->type != VEH_TRAIN,
-		VLD_WIDGET_SCROLLBAR,
-		VLD_WIDGET_DETAILS_CARGO_CARRIED,
-		VLD_WIDGET_DETAILS_TRAIN_VEHICLES,
-		VLD_WIDGET_DETAILS_CAPACITY_OF_EACH,
-		VLD_WIDGET_DETAILS_TOTAL_CARGO,
-		VLD_WIDGET_RESIZE,
-		WIDGET_LIST_END);
-
-	/* Disable service-scroller when interval is set to disabled */
-	w->SetWidgetsDisabledState(!IsVehicleServiceIntervalEnabled(v->type),
-		VLD_WIDGET_INCREASE_SERVICING_INTERVAL,
-		VLD_WIDGET_DECREASE_SERVICING_INTERVAL,
-		WIDGET_LIST_END);
-
-
-	SetDParam(0, v->index);
-	DrawWindowWidgets(w);
+	/** Initialize a newly created vehicle details window */
+	VehicleDetailsWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+	{
+		const Vehicle *v = GetVehicle(this->window_number);
 
-	/* Draw running cost */
-	SetDParam(1, v->age / 366);
-	SetDParam(0, (v->age + 365 < v->max_age) ? STR_AGE : STR_AGE_RED);
-	SetDParam(2, v->max_age / 366);
-	SetDParam(3, v->GetDisplayRunningCost());
-	DrawString(2, 15, _vehicle_translation_table[VST_VEHICLE_AGE_RUNNING_COST_YR][v->type], TC_FROMSTRING);
+		switch (v->type) {
+			case VEH_TRAIN:
+				ResizeWindow(this, 0, 39);
 
-	/* Draw max speed */
-	switch (v->type) {
-		case VEH_TRAIN:
-			SetDParam(2, v->GetDisplayMaxSpeed());
-			SetDParam(1, v->u.rail.cached_power);
-			SetDParam(0, v->u.rail.cached_weight);
-			SetDParam(3, v->u.rail.cached_max_te / 1000);
-			DrawString(2, 25, (_patches.realistic_acceleration && v->u.rail.railtype != RAILTYPE_MAGLEV) ?
-				STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :
-				STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED, TC_FROMSTRING);
-			break;
+				this->vscroll.cap = 6;
+				this->height += 12;
+				this->resize.step_height = 14;
+				this->resize.height = this->height - 14 * 2; // Minimum of 4 wagons in the display
 
-		case VEH_ROAD:
-		case VEH_SHIP:
-		case VEH_AIRCRAFT:
-			SetDParam(0, v->GetDisplayMaxSpeed());
-			DrawString(2, 25, _vehicle_translation_table[VST_VEHICLE_MAX_SPEED][v->type], TC_FROMSTRING);
-			break;
+				this->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_8867_NAME_TRAIN;
+				this->widget[VLD_WIDGET_CAPTION].data = STR_8802_DETAILS;
+				break;
 
-		default: NOT_REACHED();
+			case VEH_ROAD: {
+				this->widget[VLD_WIDGET_CAPTION].data = STR_900C_DETAILS;
+				this->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_902E_NAME_ROAD_VEHICLE;
+
+				if (!RoadVehHasArticPart(v)) break;
+
+				/* Draw the text under the vehicle instead of next to it, minus the
+				 * height already allocated for the cargo of the first vehicle. */
+				uint height_extension = 15 - 11;
+
+				/* Add space for the cargo amount for each part. */
+				for (const Vehicle *u = v; u != NULL; u = u->Next()) {
+					height_extension += 11;
+				}
+
+				ResizeWindow(this, 0, height_extension);
+			} break;
+
+			case VEH_SHIP:
+				this->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_982F_NAME_SHIP;
+				this->widget[VLD_WIDGET_CAPTION].data = STR_9811_DETAILS;
+				break;
+
+			case VEH_AIRCRAFT:
+				ResizeWindow(this, 0, 11);
+				this->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_A032_NAME_AIRCRAFT;
+				this->widget[VLD_WIDGET_CAPTION].data = STR_A00C_DETAILS;
+				break;
+			default: NOT_REACHED();
+		}
+
+		if (v->type != VEH_TRAIN) {
+			this->vscroll.cap = 1;
+			this->widget[VLD_WIDGET_MIDDLE_DETAILS].right += 12;
+		}
+
+		this->widget[VLD_WIDGET_MIDDLE_DETAILS].data = (this->vscroll.cap << 8) + 1;
+		this->caption_color = v->owner;
+
+		this->tab = 0;
 	}
 
-	/* Draw profit */
-	SetDParam(0, v->GetDisplayProfitThisYear());
-	SetDParam(1, v->GetDisplayProfitLastYear());
-	DrawString(2, 35, _vehicle_translation_table[VST_VEHICLE_PROFIT_THIS_YEAR_LAST_YEAR][v->type], TC_FROMSTRING);
-
-	/* Draw breakdown & reliability */
-	SetDParam(0, v->reliability * 100 >> 16);
-	SetDParam(1, v->breakdowns_since_last_service);
-	DrawString(2, 45, _vehicle_translation_table[VST_VEHICLE_RELIABILITY_BREAKDOWNS][v->type], TC_FROMSTRING);
-
-	/* Draw service interval text */
-	SetDParam(0, v->service_interval);
-	SetDParam(1, v->date_of_last_service);
-	DrawString(13, w->height - (v->type != VEH_TRAIN ? 11 : 23), _patches.servint_ispercent ? STR_SERVICING_INTERVAL_PERCENT : STR_883C_SERVICING_INTERVAL_DAYS, TC_FROMSTRING);
-
-	switch (v->type) {
-		case VEH_TRAIN:
-			DrawVehicleDetails(v, 2, 57, w->vscroll.pos, w->vscroll.cap, det_tab);
-			break;
-
-		case VEH_ROAD:
-		case VEH_SHIP:
-		case VEH_AIRCRAFT:
-			DrawVehicleImage(v, 3, 57, INVALID_VEHICLE, 0, 0);
-			DrawVehicleDetails(v, 75, 57, w->vscroll.pos, w->vscroll.cap, det_tab);
-			break;
-
-		default: NOT_REACHED();
+	/** Checks whether service interval is enabled for the vehicle. */
+	static bool IsVehicleServiceIntervalEnabled(const VehicleType vehicle_type)
+	{
+		switch (vehicle_type) {
+			default: NOT_REACHED();
+			case VEH_TRAIN:    return _patches.servint_trains   != 0; break;
+			case VEH_ROAD:     return _patches.servint_roadveh  != 0; break;
+			case VEH_SHIP:     return _patches.servint_ships    != 0; break;
+			case VEH_AIRCRAFT: return _patches.servint_aircraft != 0; break;
+		}
+		return false; // kill a compiler warning
 	}
-}
-
-/** Message strings for renaming vehicles indexed by vehicle type. */
-static const StringID _name_vehicle_title[] = {
-	STR_8865_NAME_TRAIN,
-	STR_902C_NAME_ROAD_VEHICLE,
-	STR_9831_NAME_SHIP,
-	STR_A030_NAME_AIRCRAFT
-};
-
-/** Message strings for error while renaming indexed by vehicle type. */
-static const StringID _name_vehicle_error[] = {
-	STR_8866_CAN_T_NAME_TRAIN,
-	STR_902D_CAN_T_NAME_ROAD_VEHICLE,
-	STR_9832_CAN_T_NAME_SHIP,
-	STR_A031_CAN_T_NAME_AIRCRAFT
-};
-
-/** Window event hook for vehicle details. */
-static void VehicleDetailsWndProc(Window *w, WindowEvent *e)
-{
-	switch (e->event) {
-		case WE_CREATE:
-			CreateVehicleDetailsWindow(w);
-			break;
 
-		case WE_PAINT:
-			DrawVehicleDetailsWindow(w);
-			break;
-
-		case WE_CLICK: {
-			switch (e->we.click.widget) {
-				case VLD_WIDGET_RENAME_VEHICLE: {// rename
-					const Vehicle *v = GetVehicle(w->window_number);
-					SetDParam(0, v->index);
-					ShowQueryString(STR_VEHICLE_NAME, _name_vehicle_title[v->type], 31, 150, w, CS_ALPHANUMERAL);
-				} break;
-
-				case VLD_WIDGET_INCREASE_SERVICING_INTERVAL:   // increase int
-				case VLD_WIDGET_DECREASE_SERVICING_INTERVAL: { // decrease int
-					int mod = _ctrl_pressed ? 5 : 10;
-					const Vehicle *v = GetVehicle(w->window_number);
-
-					mod = (e->we.click.widget == VLD_WIDGET_DECREASE_SERVICING_INTERVAL) ? -mod : mod;
-					mod = GetServiceIntervalClamped(mod + v->service_interval);
-					if (mod == v->service_interval) return;
-
-					DoCommandP(v->tile, v->index, mod, NULL, CMD_CHANGE_SERVICE_INT | CMD_MSG(STR_018A_CAN_T_CHANGE_SERVICING));
-				} break;
+	/**
+	 * Draw the details for the given vehicle at the position (x, y) of the Details windows
+	 *
+	 * @param v current vehicle
+	 * @param x The x coordinate
+	 * @param y The y coordinate
+	 * @param vscroll_pos (train only)
+	 * @param vscroll_cap (train only)
+	 * @param det_tab (train only)
+	 */
+	static void DrawVehicleDetails(const Vehicle *v, int x, int y, int vscroll_pos, uint vscroll_cap, byte det_tab)
+	{
+		switch (v->type) {
+			case VEH_TRAIN:    DrawTrainDetails(v, x, y, vscroll_pos, vscroll_cap, det_tab);  break;
+			case VEH_ROAD:     DrawRoadVehDetails(v, x, y);  break;
+			case VEH_SHIP:     DrawShipDetails(v, x, y);     break;
+			case VEH_AIRCRAFT: DrawAircraftDetails(v, x, y); break;
+			default: NOT_REACHED();
+		}
+	}
 
-				case VLD_WIDGET_DETAILS_CARGO_CARRIED:
-				case VLD_WIDGET_DETAILS_TRAIN_VEHICLES:
-				case VLD_WIDGET_DETAILS_CAPACITY_OF_EACH:
-				case VLD_WIDGET_DETAILS_TOTAL_CARGO:
-					w->SetWidgetsDisabledState(false,
-						VLD_WIDGET_DETAILS_CARGO_CARRIED,
-						VLD_WIDGET_DETAILS_TRAIN_VEHICLES,
-						VLD_WIDGET_DETAILS_CAPACITY_OF_EACH,
-						VLD_WIDGET_DETAILS_TOTAL_CARGO,
-						e->we.click.widget,
-						WIDGET_LIST_END);
+	/** Repaint vehicle details window. */
+	virtual void OnPaint()
+	{
+		const Vehicle *v = GetVehicle(this->window_number);
+		byte det_tab = this->tab;
 
-					WP(w, vehicledetails_d).tab = e->we.click.widget - VLD_WIDGET_DETAILS_CARGO_CARRIED;
-					w->SetDirty();
-					break;
-			}
-		} break;
+		this->SetWidgetDisabledState(VLD_WIDGET_RENAME_VEHICLE, v->owner != _local_player);
 
-		case WE_ON_EDIT_TEXT:
-			if (!StrEmpty(e->we.edittext.str)) {
-				_cmd_text = e->we.edittext.str;
-				DoCommandP(0, w->window_number, 0, NULL, CMD_NAME_VEHICLE | CMD_MSG(_name_vehicle_error[GetVehicle(w->window_number)->type]));
-			}
-			break;
+		if (v->type == VEH_TRAIN) {
+			this->DisableWidget(det_tab + VLD_WIDGET_DETAILS_CARGO_CARRIED);
+			SetVScrollCount(this, GetTrainDetailsWndVScroll(v->index, det_tab));
+		}
 
-		case WE_RESIZE:
-			if (e->we.sizing.diff.x != 0) ResizeButtons(w, VLD_WIDGET_DETAILS_CARGO_CARRIED, VLD_WIDGET_DETAILS_TOTAL_CARGO);
-			if (e->we.sizing.diff.y == 0) break;
+		this->SetWidgetsHiddenState(v->type != VEH_TRAIN,
+			VLD_WIDGET_SCROLLBAR,
+			VLD_WIDGET_DETAILS_CARGO_CARRIED,
+			VLD_WIDGET_DETAILS_TRAIN_VEHICLES,
+			VLD_WIDGET_DETAILS_CAPACITY_OF_EACH,
+			VLD_WIDGET_DETAILS_TOTAL_CARGO,
+			VLD_WIDGET_RESIZE,
+			WIDGET_LIST_END);
 
-			w->vscroll.cap += e->we.sizing.diff.y / 14;
-			w->widget[VLD_WIDGET_MIDDLE_DETAILS].data = (w->vscroll.cap << 8) + 1;
-			break;
+		/* Disable service-scroller when interval is set to disabled */
+		this->SetWidgetsDisabledState(!IsVehicleServiceIntervalEnabled(v->type),
+			VLD_WIDGET_INCREASE_SERVICING_INTERVAL,
+			VLD_WIDGET_DECREASE_SERVICING_INTERVAL,
+			WIDGET_LIST_END);
+
+
+		SetDParam(0, v->index);
+		this->DrawWidgets();
+
+		/* Draw running cost */
+		SetDParam(1, v->age / 366);
+		SetDParam(0, (v->age + 365 < v->max_age) ? STR_AGE : STR_AGE_RED);
+		SetDParam(2, v->max_age / 366);
+		SetDParam(3, v->GetDisplayRunningCost());
+		DrawString(2, 15, _vehicle_translation_table[VST_VEHICLE_AGE_RUNNING_COST_YR][v->type], TC_FROMSTRING);
+
+		/* Draw max speed */
+		switch (v->type) {
+			case VEH_TRAIN:
+				SetDParam(2, v->GetDisplayMaxSpeed());
+				SetDParam(1, v->u.rail.cached_power);
+				SetDParam(0, v->u.rail.cached_weight);
+				SetDParam(3, v->u.rail.cached_max_te / 1000);
+				DrawString(2, 25, (_patches.realistic_acceleration && v->u.rail.railtype != RAILTYPE_MAGLEV) ?
+					STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :
+					STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED, TC_FROMSTRING);
+				break;
+
+			case VEH_ROAD:
+			case VEH_SHIP:
+			case VEH_AIRCRAFT:
+				SetDParam(0, v->GetDisplayMaxSpeed());
+				DrawString(2, 25, _vehicle_translation_table[VST_VEHICLE_MAX_SPEED][v->type], TC_FROMSTRING);
+				break;
+
+			default: NOT_REACHED();
+		}
+
+		/* Draw profit */
+		SetDParam(0, v->GetDisplayProfitThisYear());
+		SetDParam(1, v->GetDisplayProfitLastYear());
+		DrawString(2, 35, _vehicle_translation_table[VST_VEHICLE_PROFIT_THIS_YEAR_LAST_YEAR][v->type], TC_FROMSTRING);
+
+		/* Draw breakdown & reliability */
+		SetDParam(0, v->reliability * 100 >> 16);
+		SetDParam(1, v->breakdowns_since_last_service);
+		DrawString(2, 45, _vehicle_translation_table[VST_VEHICLE_RELIABILITY_BREAKDOWNS][v->type], TC_FROMSTRING);
+
+		/* Draw service interval text */
+		SetDParam(0, v->service_interval);
+		SetDParam(1, v->date_of_last_service);
+		DrawString(13, this->height - (v->type != VEH_TRAIN ? 11 : 23), _patches.servint_ispercent ? STR_SERVICING_INTERVAL_PERCENT : STR_883C_SERVICING_INTERVAL_DAYS, TC_FROMSTRING);
+
+		switch (v->type) {
+			case VEH_TRAIN:
+				DrawVehicleDetails(v, 2, 57, this->vscroll.pos, this->vscroll.cap, det_tab);
+				break;
+
+			case VEH_ROAD:
+			case VEH_SHIP:
+			case VEH_AIRCRAFT:
+				DrawVehicleImage(v, 3, 57, INVALID_VEHICLE, 0, 0);
+				DrawVehicleDetails(v, 75, 57, this->vscroll.pos, this->vscroll.cap, det_tab);
+				break;
+
+			default: NOT_REACHED();
+		}
 	}
-}
+
+	virtual void OnClick(Point pt, int widget)
+	{
+		/** Message strings for renaming vehicles indexed by vehicle type. */
+		static const StringID _name_vehicle_title[] = {
+			STR_8865_NAME_TRAIN,
+			STR_902C_NAME_ROAD_VEHICLE,
+			STR_9831_NAME_SHIP,
+			STR_A030_NAME_AIRCRAFT
+		};
+
+		switch (widget) {
+			case VLD_WIDGET_RENAME_VEHICLE: {// rename
+				const Vehicle *v = GetVehicle(this->window_number);
+				SetDParam(0, v->index);
+				ShowQueryString(STR_VEHICLE_NAME, _name_vehicle_title[v->type], 31, 150, this, CS_ALPHANUMERAL);
+			} break;
+
+			case VLD_WIDGET_INCREASE_SERVICING_INTERVAL:   // increase int
+			case VLD_WIDGET_DECREASE_SERVICING_INTERVAL: { // decrease int
+				int mod = _ctrl_pressed ? 5 : 10;
+				const Vehicle *v = GetVehicle(this->window_number);
+
+				mod = (widget == VLD_WIDGET_DECREASE_SERVICING_INTERVAL) ? -mod : mod;
+				mod = GetServiceIntervalClamped(mod + v->service_interval);
+				if (mod == v->service_interval) return;
+
+				DoCommandP(v->tile, v->index, mod, NULL, CMD_CHANGE_SERVICE_INT | CMD_MSG(STR_018A_CAN_T_CHANGE_SERVICING));
+			} break;
+
+			case VLD_WIDGET_DETAILS_CARGO_CARRIED:
+			case VLD_WIDGET_DETAILS_TRAIN_VEHICLES:
+			case VLD_WIDGET_DETAILS_CAPACITY_OF_EACH:
+			case VLD_WIDGET_DETAILS_TOTAL_CARGO:
+				this->SetWidgetsDisabledState(false,
+					VLD_WIDGET_DETAILS_CARGO_CARRIED,
+					VLD_WIDGET_DETAILS_TRAIN_VEHICLES,
+					VLD_WIDGET_DETAILS_CAPACITY_OF_EACH,
+					VLD_WIDGET_DETAILS_TOTAL_CARGO,
+					widget,
+					WIDGET_LIST_END);
+
+				this->tab = widget - VLD_WIDGET_DETAILS_CARGO_CARRIED;
+				this->SetDirty();
+				break;
+		}
+	}
+
+	virtual void OnQueryTextFinished(char *str)
+	{
+		/** Message strings for error while renaming indexed by vehicle type. */
+		static const StringID _name_vehicle_error[] = {
+			STR_8866_CAN_T_NAME_TRAIN,
+			STR_902D_CAN_T_NAME_ROAD_VEHICLE,
+			STR_9832_CAN_T_NAME_SHIP,
+			STR_A031_CAN_T_NAME_AIRCRAFT
+		};
+
+		if (!StrEmpty(str)) {
+			_cmd_text = str;
+			DoCommandP(0, this->window_number, 0, NULL, CMD_NAME_VEHICLE | CMD_MSG(_name_vehicle_error[GetVehicle(this->window_number)->type]));
+		}
+	}
+
+	virtual void OnResize(Point new_size, Point delta)
+	{
+		if (delta.x != 0) ResizeButtons(this, VLD_WIDGET_DETAILS_CARGO_CARRIED, VLD_WIDGET_DETAILS_TOTAL_CARGO);
+		if (delta.y == 0) return;
+
+		this->vscroll.cap += delta.y / 14;
+		this->widget[VLD_WIDGET_MIDDLE_DETAILS].data = (this->vscroll.cap << 8) + 1;
+	}
+};
 
 /** Vehicle details window descriptor. */
 static const WindowDesc _vehicle_details_desc = {
@@ -1655,7 +1608,6 @@
 	WC_VEHICLE_DETAILS, WC_VEHICLE_VIEW,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
 	_vehicle_details_widgets,
-	VehicleDetailsWndProc
 };
 
 /** Shows the vehicle details window of the given vehicle. */
@@ -1663,7 +1615,7 @@
 {
 	DeleteWindowById(WC_VEHICLE_ORDERS, v->index);
 	DeleteWindowById(WC_VEHICLE_DETAILS, v->index);
-	AllocateWindowDescFront<Window>(&_vehicle_details_desc, v->index);
+	AllocateWindowDescFront<VehicleDetailsWindow>(&_vehicle_details_desc, v->index);
 }
 
 
@@ -1691,15 +1643,12 @@
 };
 
 
-static void VehicleViewWndProc(Window *w, WindowEvent *e);
-
 /** Vehicle view window descriptor for all vehicles but trains. */
 static const WindowDesc _vehicle_view_desc = {
 	WDP_AUTO, WDP_AUTO, 250, 116, 250, 116,
 	WC_VEHICLE_VIEW, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
 	_vehicle_view_widgets,
-	VehicleViewWndProc
 };
 
 /** Vehicle view window descriptor for trains. Only minimum_height and
@@ -1710,7 +1659,6 @@
 	WC_VEHICLE_VIEW, WC_NONE,
 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
 	_vehicle_view_widgets,
-	VehicleViewWndProc
 };
 
 
@@ -1736,300 +1684,6 @@
 static const int VV_INITIAL_VIEWPORT_HEIGHT = 84;
 static const int VV_INITIAL_VIEWPORT_HEIGHT_TRAIN = 102;
 
-/** Shows the vehicle view window of the given vehicle. */
-void ShowVehicleViewWindow(const Vehicle *v)
-{
-	Window *w = AllocateWindowDescFront<Window>((v->type == VEH_TRAIN) ? &_train_view_desc : &_vehicle_view_desc, v->index);
-
-	if (w != NULL) {
-		w->caption_color = v->owner;
-		InitializeWindowViewport(w, VV_VIEWPORT_X, VV_VIEWPORT_Y, VV_INITIAL_VIEWPORT_WIDTH,
-												 (v->type == VEH_TRAIN) ? VV_INITIAL_VIEWPORT_HEIGHT_TRAIN : VV_INITIAL_VIEWPORT_HEIGHT,
-												 w->window_number | (1 << 31), _vehicle_view_zoom_levels[v->type]);
-	}
-}
-
-/** Initialize a newly created vehicle view window */
-static void CreateVehicleViewWindow(Window *w)
-{
-	const Vehicle *v = GetVehicle(w->window_number);
-
-	/*
-	 * fill in data and tooltip codes for the widgets and
-	 * move some of the buttons for trains
-	 */
-	switch (v->type) {
-		case VEH_TRAIN:
-			w->widget[VVW_WIDGET_CAPTION].data = STR_882E;
-
-			w->widget[VVW_WIDGET_START_STOP_VEH].tooltips = STR_8846_CURRENT_TRAIN_ACTION_CLICK;
-
-			w->widget[VVW_WIDGET_CENTER_MAIN_VIEH].tooltips = STR_8848_CENTER_MAIN_VIEW_ON_TRAIN;
-
-			w->widget[VVW_WIDGET_GOTO_DEPOT].data = SPR_SEND_TRAIN_TODEPOT;
-			w->widget[VVW_WIDGET_GOTO_DEPOT].tooltips = STR_8849_SEND_TRAIN_TO_DEPOT;
-
-			w->widget[VVW_WIDGET_REFIT_VEH].tooltips = STR_RAIL_REFIT_VEHICLE_TO_CARRY;
-
-			w->widget[VVW_WIDGET_SHOW_ORDERS].tooltips = STR_8847_SHOW_TRAIN_S_ORDERS;
-
-			w->widget[VVW_WIDGET_SHOW_DETAILS].tooltips = STR_884C_SHOW_TRAIN_DETAILS;
-
-			w->widget[VVW_WIDGET_CLONE_VEH].data = SPR_CLONE_TRAIN;
-			w->widget[VVW_WIDGET_CLONE_VEH].tooltips = STR_CLONE_TRAIN_INFO;
-
-			w->widget[VVW_WIDGET_TURN_AROUND].tooltips = STR_884B_REVERSE_DIRECTION_OF_TRAIN;
-
-
-			/* due to more buttons we must modify the layout a bit for trains */
-			w->widget[VVW_WIDGET_PANEL].bottom = 121;
-			w->widget[VVW_WIDGET_VIEWPORT].bottom = 119;
-
-			w->widget[VVW_WIDGET_START_STOP_VEH].top = 122;
-			w->widget[VVW_WIDGET_START_STOP_VEH].bottom = 133;
-
-			w->widget[VVW_WIDGET_REFIT_VEH].top = 68;
-			w->widget[VVW_WIDGET_REFIT_VEH].bottom = 85;
-
-			w->widget[VVW_WIDGET_SHOW_ORDERS].top = 86;
-			w->widget[VVW_WIDGET_SHOW_ORDERS].bottom = 103;
-
-			w->widget[VVW_WIDGET_SHOW_DETAILS].top = 104;
-			w->widget[VVW_WIDGET_SHOW_DETAILS].bottom = 121;
-
-			w->widget[VVW_WIDGET_EMPTY_BOTTOM_RIGHT].top = 122;
-			w->widget[VVW_WIDGET_EMPTY_BOTTOM_RIGHT].bottom = 121;
-
-			w->widget[VVW_WIDGET_RESIZE].top = 122;
-			w->widget[VVW_WIDGET_RESIZE].bottom = 133;
-
-			w->widget[VVW_WIDGET_TURN_AROUND].top = 68;
-			w->widget[VVW_WIDGET_TURN_AROUND].bottom = 85;
-			break;
-
-		case VEH_ROAD:
-			w->widget[VVW_WIDGET_CAPTION].data = STR_9002;
-
-			w->widget[VVW_WIDGET_START_STOP_VEH].tooltips = STR_901C_CURRENT_VEHICLE_ACTION;
-
-			w->widget[VVW_WIDGET_CENTER_MAIN_VIEH].tooltips = STR_901E_CENTER_MAIN_VIEW_ON_VEHICLE;
-
-			w->widget[VVW_WIDGET_GOTO_DEPOT].data = SPR_SEND_ROADVEH_TODEPOT;
-			w->widget[VVW_WIDGET_GOTO_DEPOT].tooltips = STR_901F_SEND_VEHICLE_TO_DEPOT;
-
-			w->widget[VVW_WIDGET_REFIT_VEH].tooltips = STR_REFIT_ROAD_VEHICLE_TO_CARRY;
-
-			w->widget[VVW_WIDGET_SHOW_ORDERS].tooltips = STR_901D_SHOW_VEHICLE_S_ORDERS;
-
-			w->widget[VVW_WIDGET_SHOW_DETAILS].tooltips = STR_9021_SHOW_ROAD_VEHICLE_DETAILS;
-
-			w->widget[VVW_WIDGET_CLONE_VEH].data = SPR_CLONE_ROADVEH;
-			w->widget[VVW_WIDGET_CLONE_VEH].tooltips = STR_CLONE_ROAD_VEHICLE_INFO;
-
-			w->SetWidgetHiddenState(VVW_WIDGET_FORCE_PROCEED, true);
-			break;
-
-		case VEH_SHIP:
-			w->widget[VVW_WIDGET_CAPTION].data = STR_980F;
-
-			w->widget[VVW_WIDGET_START_STOP_VEH].tooltips = STR_9827_CURRENT_SHIP_ACTION_CLICK;
-
-			w->widget[VVW_WIDGET_CENTER_MAIN_VIEH].tooltips = STR_9829_CENTER_MAIN_VIEW_ON_SHIP;
-
-			w->widget[VVW_WIDGET_GOTO_DEPOT].data = SPR_SEND_SHIP_TODEPOT;
-			w->widget[VVW_WIDGET_GOTO_DEPOT].tooltips = STR_982A_SEND_SHIP_TO_DEPOT;
-
-			w->widget[VVW_WIDGET_REFIT_VEH].tooltips = STR_983A_REFIT_CARGO_SHIP_TO_CARRY;
-
-			w->widget[VVW_WIDGET_SHOW_ORDERS].tooltips = STR_9828_SHOW_SHIP_S_ORDERS;
-
-			w->widget[VVW_WIDGET_SHOW_DETAILS].tooltips = STR_982B_SHOW_SHIP_DETAILS;
-
-			w->widget[VVW_WIDGET_CLONE_VEH].data = SPR_CLONE_SHIP;
-			w->widget[VVW_WIDGET_CLONE_VEH].tooltips = STR_CLONE_SHIP_INFO;
-
-			w->SetWidgetsHiddenState(true,
-																	VVW_WIDGET_TURN_AROUND,
-																	VVW_WIDGET_FORCE_PROCEED,
-																	WIDGET_LIST_END);
-			break;
-
-		case VEH_AIRCRAFT:
-			w->widget[VVW_WIDGET_CAPTION].data = STR_A00A;
-
-			w->widget[VVW_WIDGET_START_STOP_VEH].tooltips = STR_A027_CURRENT_AIRCRAFT_ACTION;
-
-			w->widget[VVW_WIDGET_CENTER_MAIN_VIEH].tooltips = STR_A029_CENTER_MAIN_VIEW_ON_AIRCRAFT;
-
-			w->widget[VVW_WIDGET_GOTO_DEPOT].data = SPR_SEND_AIRCRAFT_TODEPOT;
-			w->widget[VVW_WIDGET_GOTO_DEPOT].tooltips = STR_A02A_SEND_AIRCRAFT_TO_HANGAR;
-
-			w->widget[VVW_WIDGET_REFIT_VEH].tooltips = STR_A03B_REFIT_AIRCRAFT_TO_CARRY;
-
-			w->widget[VVW_WIDGET_SHOW_ORDERS].tooltips = STR_A028_SHOW_AIRCRAFT_S_ORDERS;
-
-			w->widget[VVW_WIDGET_SHOW_DETAILS].tooltips = STR_A02B_SHOW_AIRCRAFT_DETAILS;
-
-			w->widget[VVW_WIDGET_CLONE_VEH].data = SPR_CLONE_AIRCRAFT;
-			w->widget[VVW_WIDGET_CLONE_VEH].tooltips = STR_CLONE_AIRCRAFT_INFO;
-
-			w->SetWidgetsHiddenState(true,
-																	VVW_WIDGET_TURN_AROUND,
-																	VVW_WIDGET_FORCE_PROCEED,
-																	WIDGET_LIST_END);
-			break;
-
-			default: NOT_REACHED();
-	}
-}
-
-/** Checks whether the vehicle may be refitted at the moment.*/
-static bool IsVehicleRefitable(const Vehicle *v)
-{
-	/* Why is this so different for different vehicles?
-	 * Does maybe work one solution for all?
-	 */
-	switch (v->type) {
-		case VEH_TRAIN:    return false;
-		case VEH_ROAD:     return EngInfo(v->engine_type)->refit_mask != 0 && v->IsStoppedInDepot();
-		case VEH_SHIP:     return ShipVehInfo(v->engine_type)->refittable && v->IsStoppedInDepot();
-		case VEH_AIRCRAFT: return v->IsStoppedInDepot();
-		default: NOT_REACHED();
-	}
-}
-
-/** Message strings for heading to depot indexed by vehicle type. */
-static const StringID _heading_for_depot_strings[] = {
-	STR_HEADING_FOR_TRAIN_DEPOT,
-	STR_HEADING_FOR_ROAD_DEPOT,
-	STR_HEADING_FOR_SHIP_DEPOT,
-	STR_HEADING_FOR_HANGAR,
-};
-
-/** Message strings for heading to depot and servicing indexed by vehicle type. */
-static const StringID _heading_for_depot_service_strings[] = {
-	STR_HEADING_FOR_TRAIN_DEPOT_SERVICE,
-	STR_HEADING_FOR_ROAD_DEPOT_SERVICE,
-	STR_HEADING_FOR_SHIP_DEPOT_SERVICE,
-	STR_HEADING_FOR_HANGAR_SERVICE,
-};
-
-/** Repaint vehicle view window. */
-static void DrawVehicleViewWindow(Window *w)
-{
-	const Vehicle *v = GetVehicle(w->window_number);
-	StringID str;
-	bool is_localplayer = v->owner == _local_player;
-	bool refitable_and_stopped_in_depot = IsVehicleRefitable(v);
-
-	w->SetWidgetDisabledState(VVW_WIDGET_GOTO_DEPOT, !is_localplayer);
-	w->SetWidgetDisabledState(VVW_WIDGET_REFIT_VEH,
-															 !refitable_and_stopped_in_depot || !is_localplayer);
-	w->SetWidgetDisabledState(VVW_WIDGET_CLONE_VEH, !is_localplayer);
-
-	if (v->type == VEH_TRAIN) {
-		w->SetWidgetDisabledState(VVW_WIDGET_FORCE_PROCEED, !is_localplayer);
-		w->SetWidgetDisabledState(VVW_WIDGET_TURN_AROUND, !is_localplayer);
-
-		/* Cargo refit button is disabled, until we know we can enable it below. */
-
-		if (is_localplayer) {
-			/* See if any vehicle can be refitted */
-			for (const Vehicle *u = v; u != NULL; u = u->Next()) {
-				if (EngInfo(u->engine_type)->refit_mask != 0 ||
-						(RailVehInfo(v->engine_type)->railveh_type != RAILVEH_WAGON && v->cargo_cap != 0)) {
-					w->EnableWidget(VVW_WIDGET_REFIT_VEH);
-					/* We have a refittable carriage, bail out */
-					break;
-				}
-			}
-		}
-	}
-
-	/* draw widgets & caption */
-	SetDParam(0, v->index);
-	DrawWindowWidgets(w);
-
-	if (v->vehstatus & VS_CRASHED) {
-		str = STR_8863_CRASHED;
-	} else if (v->type != VEH_AIRCRAFT && v->breakdown_ctr == 1) { // check for aircraft necessary?
-		str = STR_885C_BROKEN_DOWN;
-	} else if (v->vehstatus & VS_STOPPED) {
-		if (v->type == VEH_TRAIN) {
-			if (v->cur_speed == 0) {
-				if (v->u.rail.cached_power == 0) {
-					str = STR_TRAIN_NO_POWER;
-				} else {
-					str = STR_8861_STOPPED;
-				}
-			} else {
-				SetDParam(0, v->GetDisplaySpeed());
-				str = STR_TRAIN_STOPPING + _patches.vehicle_speed;
-			}
-		} else { // no train
-			str = STR_8861_STOPPED;
-		}
-	} else { // vehicle is in a "normal" state, show current order
-		switch (v->current_order.GetType()) {
-			case OT_GOTO_STATION: {
-				SetDParam(0, v->current_order.GetDestination());
-				SetDParam(1, v->GetDisplaySpeed());
-				str = STR_HEADING_FOR_STATION + _patches.vehicle_speed;
-			} break;
-
-			case OT_GOTO_DEPOT: {
-				if (v->type == VEH_AIRCRAFT) {
-					/* Aircrafts always go to a station, even if you say depot */
-					SetDParam(0, v->current_order.GetDestination());
-					SetDParam(1, v->GetDisplaySpeed());
-				} else {
-					Depot *depot = GetDepot(v->current_order.GetDestination());
-					SetDParam(0, depot->town_index);
-					SetDParam(1, v->GetDisplaySpeed());
-				}
-				if ((v->current_order.GetDepotActionType() & ODATFB_HALT) && !(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) {
-					str = _heading_for_depot_strings[v->type] + _patches.vehicle_speed;
-				} else {
-					str = _heading_for_depot_service_strings[v->type] + _patches.vehicle_speed;
-				}
-			} break;
-
-			case OT_LOADING:
-				str = STR_882F_LOADING_UNLOADING;
-				break;
-
-			case OT_GOTO_WAYPOINT: {
-				assert(v->type == VEH_TRAIN);
-				SetDParam(0, v->current_order.GetDestination());
-				str = STR_HEADING_FOR_WAYPOINT + _patches.vehicle_speed;
-				SetDParam(1, v->GetDisplaySpeed());
-				break;
-			}
-
-			case OT_LEAVESTATION:
-				if (v->type != VEH_AIRCRAFT) {
-					str = STR_LEAVING;
-					break;
-				}
-				/* fall-through if aircraft. Does this even happen? */
-
-			default:
-				if (v->num_orders == 0) {
-					str = STR_NO_ORDERS + _patches.vehicle_speed;
-					SetDParam(0, v->GetDisplaySpeed());
-				} else {
-					str = STR_EMPTY;
-				}
-				break;
-		}
-	}
-
-	/* draw the flag plus orders */
-	DrawSprite(v->vehstatus & VS_STOPPED ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, PAL_NONE, 2, w->widget[VVW_WIDGET_START_STOP_VEH].top + 1);
-	DrawStringCenteredTruncated(w->widget[VVW_WIDGET_START_STOP_VEH].left + 8, w->widget[VVW_WIDGET_START_STOP_VEH].right, w->widget[VVW_WIDGET_START_STOP_VEH].top + 1, str, TC_FROMSTRING);
-	DrawWindowViewport(w);
-}
-
 /** Command indices for the _vehicle_command_translation_table. */
 enum VehicleCommandTranslation {
 	VCT_CMD_START_STOP = 0,
@@ -2067,104 +1721,387 @@
 	},
 };
 
-/** Window event hook for vehicle view. */
-static void VehicleViewWndProc(Window *w, WindowEvent *e)
+/** Checks whether the vehicle may be refitted at the moment.*/
+static bool IsVehicleRefitable(const Vehicle *v)
 {
-	switch (e->event) {
-		case WE_CREATE:
-			CreateVehicleViewWindow(w);
-			break;
-
-		case WE_PAINT:
-			DrawVehicleViewWindow(w);
-			break;
+	/* Why is this so different for different vehicles?
+	 * Does maybe work one solution for all?
+	 */
+	switch (v->type) {
+		case VEH_TRAIN:    return false;
+		case VEH_ROAD:     return EngInfo(v->engine_type)->refit_mask != 0 && v->IsStoppedInDepot();
+		case VEH_SHIP:     return ShipVehInfo(v->engine_type)->refittable && v->IsStoppedInDepot();
+		case VEH_AIRCRAFT: return v->IsStoppedInDepot();
+		default: NOT_REACHED();
+	}
+}
 
-		case WE_CLICK: {
-			const Vehicle *v = GetVehicle(w->window_number);
+struct VehicleViewWindow : Window {
+	VehicleViewWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+	{
+		const Vehicle *v = GetVehicle(this->window_number);
 
-			switch (e->we.click.widget) {
-				case VVW_WIDGET_START_STOP_VEH: /* start stop */
-					DoCommandP(v->tile, v->index, 0, NULL,
-										 _vehicle_command_translation_table[VCT_CMD_START_STOP][v->type]);
-					break;
-				case VVW_WIDGET_CENTER_MAIN_VIEH: {/* center main view */
-					const Window *mainwindow = FindWindowById(WC_MAIN_WINDOW, 0);
-					/* code to allow the main window to 'follow' the vehicle if the ctrl key is pressed */
-					if (_ctrl_pressed && mainwindow->viewport->zoom == ZOOM_LVL_NORMAL) {
-						mainwindow->viewport->follow_vehicle = v->index;
+		this->caption_color = v->owner;
+		InitializeWindowViewport(this, VV_VIEWPORT_X, VV_VIEWPORT_Y, VV_INITIAL_VIEWPORT_WIDTH,
+												 (v->type == VEH_TRAIN) ? VV_INITIAL_VIEWPORT_HEIGHT_TRAIN : VV_INITIAL_VIEWPORT_HEIGHT,
+												 this->window_number | (1 << 31), _vehicle_view_zoom_levels[v->type]);
+
+		/*
+		 * fill in data and tooltip codes for the widgets and
+		 * move some of the buttons for trains
+		 */
+		switch (v->type) {
+			case VEH_TRAIN:
+				this->widget[VVW_WIDGET_CAPTION].data = STR_882E;
+
+				this->widget[VVW_WIDGET_START_STOP_VEH].tooltips = STR_8846_CURRENT_TRAIN_ACTION_CLICK;
+
+				this->widget[VVW_WIDGET_CENTER_MAIN_VIEH].tooltips = STR_8848_CENTER_MAIN_VIEW_ON_TRAIN;
+
+				this->widget[VVW_WIDGET_GOTO_DEPOT].data = SPR_SEND_TRAIN_TODEPOT;
+				this->widget[VVW_WIDGET_GOTO_DEPOT].tooltips = STR_8849_SEND_TRAIN_TO_DEPOT;
+
+				this->widget[VVW_WIDGET_REFIT_VEH].tooltips = STR_RAIL_REFIT_VEHICLE_TO_CARRY;
+
+				this->widget[VVW_WIDGET_SHOW_ORDERS].tooltips = STR_8847_SHOW_TRAIN_S_ORDERS;
+
+				this->widget[VVW_WIDGET_SHOW_DETAILS].tooltips = STR_884C_SHOW_TRAIN_DETAILS;
+
+				this->widget[VVW_WIDGET_CLONE_VEH].data = SPR_CLONE_TRAIN;
+				this->widget[VVW_WIDGET_CLONE_VEH].tooltips = STR_CLONE_TRAIN_INFO;
+
+				this->widget[VVW_WIDGET_TURN_AROUND].tooltips = STR_884B_REVERSE_DIRECTION_OF_TRAIN;
+
+
+				/* due to more buttons we must modify the layout a bit for trains */
+				this->widget[VVW_WIDGET_PANEL].bottom = 121;
+				this->widget[VVW_WIDGET_VIEWPORT].bottom = 119;
+
+				this->widget[VVW_WIDGET_START_STOP_VEH].top = 122;
+				this->widget[VVW_WIDGET_START_STOP_VEH].bottom = 133;
+
+				this->widget[VVW_WIDGET_REFIT_VEH].top = 68;
+				this->widget[VVW_WIDGET_REFIT_VEH].bottom = 85;
+
+				this->widget[VVW_WIDGET_SHOW_ORDERS].top = 86;
+				this->widget[VVW_WIDGET_SHOW_ORDERS].bottom = 103;
+
+				this->widget[VVW_WIDGET_SHOW_DETAILS].top = 104;
+				this->widget[VVW_WIDGET_SHOW_DETAILS].bottom = 121;
+
+				this->widget[VVW_WIDGET_EMPTY_BOTTOM_RIGHT].top = 122;
+				this->widget[VVW_WIDGET_EMPTY_BOTTOM_RIGHT].bottom = 121;
+
+				this->widget[VVW_WIDGET_RESIZE].top = 122;
+				this->widget[VVW_WIDGET_RESIZE].bottom = 133;
+
+				this->widget[VVW_WIDGET_TURN_AROUND].top = 68;
+				this->widget[VVW_WIDGET_TURN_AROUND].bottom = 85;
+				break;
+
+			case VEH_ROAD:
+				this->widget[VVW_WIDGET_CAPTION].data = STR_9002;
+
+				this->widget[VVW_WIDGET_START_STOP_VEH].tooltips = STR_901C_CURRENT_VEHICLE_ACTION;
+
+				this->widget[VVW_WIDGET_CENTER_MAIN_VIEH].tooltips = STR_901E_CENTER_MAIN_VIEW_ON_VEHICLE;
+
+				this->widget[VVW_WIDGET_GOTO_DEPOT].data = SPR_SEND_ROADVEH_TODEPOT;
+				this->widget[VVW_WIDGET_GOTO_DEPOT].tooltips = STR_901F_SEND_VEHICLE_TO_DEPOT;
+
+				this->widget[VVW_WIDGET_REFIT_VEH].tooltips = STR_REFIT_ROAD_VEHICLE_TO_CARRY;
+
+				this->widget[VVW_WIDGET_SHOW_ORDERS].tooltips = STR_901D_SHOW_VEHICLE_S_ORDERS;
+
+				this->widget[VVW_WIDGET_SHOW_DETAILS].tooltips = STR_9021_SHOW_ROAD_VEHICLE_DETAILS;
+
+				this->widget[VVW_WIDGET_CLONE_VEH].data = SPR_CLONE_ROADVEH;
+				this->widget[VVW_WIDGET_CLONE_VEH].tooltips = STR_CLONE_ROAD_VEHICLE_INFO;
+
+				this->SetWidgetHiddenState(VVW_WIDGET_FORCE_PROCEED, true);
+				break;
+
+			case VEH_SHIP:
+				this->widget[VVW_WIDGET_CAPTION].data = STR_980F;
+
+				this->widget[VVW_WIDGET_START_STOP_VEH].tooltips = STR_9827_CURRENT_SHIP_ACTION_CLICK;
+
+				this->widget[VVW_WIDGET_CENTER_MAIN_VIEH].tooltips = STR_9829_CENTER_MAIN_VIEW_ON_SHIP;
+
+				this->widget[VVW_WIDGET_GOTO_DEPOT].data = SPR_SEND_SHIP_TODEPOT;
+				this->widget[VVW_WIDGET_GOTO_DEPOT].tooltips = STR_982A_SEND_SHIP_TO_DEPOT;
+
+				this->widget[VVW_WIDGET_REFIT_VEH].tooltips = STR_983A_REFIT_CARGO_SHIP_TO_CARRY;
+
+				this->widget[VVW_WIDGET_SHOW_ORDERS].tooltips = STR_9828_SHOW_SHIP_S_ORDERS;
+
+				this->widget[VVW_WIDGET_SHOW_DETAILS].tooltips = STR_982B_SHOW_SHIP_DETAILS;
+
+				this->widget[VVW_WIDGET_CLONE_VEH].data = SPR_CLONE_SHIP;
+				this->widget[VVW_WIDGET_CLONE_VEH].tooltips = STR_CLONE_SHIP_INFO;
+
+				this->SetWidgetsHiddenState(true,
+																		VVW_WIDGET_TURN_AROUND,
+																		VVW_WIDGET_FORCE_PROCEED,
+																		WIDGET_LIST_END);
+				break;
+
+			case VEH_AIRCRAFT:
+				this->widget[VVW_WIDGET_CAPTION].data = STR_A00A;
+
+				this->widget[VVW_WIDGET_START_STOP_VEH].tooltips = STR_A027_CURRENT_AIRCRAFT_ACTION;
+
+				this->widget[VVW_WIDGET_CENTER_MAIN_VIEH].tooltips = STR_A029_CENTER_MAIN_VIEW_ON_AIRCRAFT;
+
+				this->widget[VVW_WIDGET_GOTO_DEPOT].data = SPR_SEND_AIRCRAFT_TODEPOT;
+				this->widget[VVW_WIDGET_GOTO_DEPOT].tooltips = STR_A02A_SEND_AIRCRAFT_TO_HANGAR;
+
+				this->widget[VVW_WIDGET_REFIT_VEH].tooltips = STR_A03B_REFIT_AIRCRAFT_TO_CARRY;
+
+				this->widget[VVW_WIDGET_SHOW_ORDERS].tooltips = STR_A028_SHOW_AIRCRAFT_S_ORDERS;
+
+				this->widget[VVW_WIDGET_SHOW_DETAILS].tooltips = STR_A02B_SHOW_AIRCRAFT_DETAILS;
+
+				this->widget[VVW_WIDGET_CLONE_VEH].data = SPR_CLONE_AIRCRAFT;
+				this->widget[VVW_WIDGET_CLONE_VEH].tooltips = STR_CLONE_AIRCRAFT_INFO;
+
+				this->SetWidgetsHiddenState(true,
+																		VVW_WIDGET_TURN_AROUND,
+																		VVW_WIDGET_FORCE_PROCEED,
+																		WIDGET_LIST_END);
+				break;
+
+				default: NOT_REACHED();
+		}
+	}
+
+	~VehicleViewWindow()
+	{
+		DeleteWindowById(WC_VEHICLE_ORDERS, this->window_number);
+		DeleteWindowById(WC_VEHICLE_REFIT, this->window_number);
+		DeleteWindowById(WC_VEHICLE_DETAILS, this->window_number);
+		DeleteWindowById(WC_VEHICLE_TIMETABLE, this->window_number);
+	}
+
+	virtual void OnPaint()
+	{
+		/** Message strings for heading to depot indexed by vehicle type. */
+		static const StringID _heading_for_depot_strings[] = {
+			STR_HEADING_FOR_TRAIN_DEPOT,
+			STR_HEADING_FOR_ROAD_DEPOT,
+			STR_HEADING_FOR_SHIP_DEPOT,
+			STR_HEADING_FOR_HANGAR,
+		};
+
+		/** Message strings for heading to depot and servicing indexed by vehicle type. */
+		static const StringID _heading_for_depot_service_strings[] = {
+			STR_HEADING_FOR_TRAIN_DEPOT_SERVICE,
+			STR_HEADING_FOR_ROAD_DEPOT_SERVICE,
+			STR_HEADING_FOR_SHIP_DEPOT_SERVICE,
+			STR_HEADING_FOR_HANGAR_SERVICE,
+		};
+
+		const Vehicle *v = GetVehicle(this->window_number);
+		StringID str;
+		bool is_localplayer = v->owner == _local_player;
+		bool refitable_and_stopped_in_depot = IsVehicleRefitable(v);
+
+		this->SetWidgetDisabledState(VVW_WIDGET_GOTO_DEPOT, !is_localplayer);
+		this->SetWidgetDisabledState(VVW_WIDGET_REFIT_VEH,
+																!refitable_and_stopped_in_depot || !is_localplayer);
+		this->SetWidgetDisabledState(VVW_WIDGET_CLONE_VEH, !is_localplayer);
+
+		if (v->type == VEH_TRAIN) {
+			this->SetWidgetDisabledState(VVW_WIDGET_FORCE_PROCEED, !is_localplayer);
+			this->SetWidgetDisabledState(VVW_WIDGET_TURN_AROUND, !is_localplayer);
+
+			/* Cargo refit button is disabled, until we know we can enable it below. */
+
+			if (is_localplayer) {
+				/* See if any vehicle can be refitted */
+				for (const Vehicle *u = v; u != NULL; u = u->Next()) {
+					if (EngInfo(u->engine_type)->refit_mask != 0 ||
+							(RailVehInfo(v->engine_type)->railveh_type != RAILVEH_WAGON && v->cargo_cap != 0)) {
+						this->EnableWidget(VVW_WIDGET_REFIT_VEH);
+						/* We have a refittable carriage, bail out */
+						break;
+					}
+				}
+			}
+		}
+
+		/* draw widgets & caption */
+		SetDParam(0, v->index);
+		this->DrawWidgets();
+
+		if (v->vehstatus & VS_CRASHED) {
+			str = STR_8863_CRASHED;
+		} else if (v->type != VEH_AIRCRAFT && v->breakdown_ctr == 1) { // check for aircraft necessary?
+			str = STR_885C_BROKEN_DOWN;
+		} else if (v->vehstatus & VS_STOPPED) {
+			if (v->type == VEH_TRAIN) {
+				if (v->cur_speed == 0) {
+					if (v->u.rail.cached_power == 0) {
+						str = STR_TRAIN_NO_POWER;
 					} else {
-						ScrollMainWindowTo(v->x_pos, v->y_pos);
+						str = STR_8861_STOPPED;
+					}
+				} else {
+					SetDParam(0, v->GetDisplaySpeed());
+					str = STR_TRAIN_STOPPING + _patches.vehicle_speed;
+				}
+			} else { // no train
+				str = STR_8861_STOPPED;
+			}
+		} else { // vehicle is in a "normal" state, show current order
+			switch (v->current_order.GetType()) {
+				case OT_GOTO_STATION: {
+					SetDParam(0, v->current_order.GetDestination());
+					SetDParam(1, v->GetDisplaySpeed());
+					str = STR_HEADING_FOR_STATION + _patches.vehicle_speed;
+				} break;
+
+				case OT_GOTO_DEPOT: {
+					if (v->type == VEH_AIRCRAFT) {
+						/* Aircrafts always go to a station, even if you say depot */
+						SetDParam(0, v->current_order.GetDestination());
+						SetDParam(1, v->GetDisplaySpeed());
+					} else {
+						Depot *depot = GetDepot(v->current_order.GetDestination());
+						SetDParam(0, depot->town_index);
+						SetDParam(1, v->GetDisplaySpeed());
+					}
+					if ((v->current_order.GetDepotActionType() & ODATFB_HALT) && !(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) {
+						str = _heading_for_depot_strings[v->type] + _patches.vehicle_speed;
+					} else {
+						str = _heading_for_depot_service_strings[v->type] + _patches.vehicle_speed;
 					}
 				} break;
 
-				case VVW_WIDGET_GOTO_DEPOT: /* goto hangar */
-					DoCommandP(v->tile, v->index, _ctrl_pressed ? DEPOT_SERVICE : 0, NULL,
-						_vehicle_command_translation_table[VCT_CMD_GOTO_DEPOT][v->type]);
-					break;
-				case VVW_WIDGET_REFIT_VEH: /* refit */
-					ShowVehicleRefitWindow(v, INVALID_VEH_ORDER_ID);
-					break;
-				case VVW_WIDGET_SHOW_ORDERS: /* show orders */
-					if (_ctrl_pressed) {
-						ShowTimetableWindow(v);
-					} else {
-						ShowOrdersWindow(v);
-					}
+				case OT_LOADING:
+					str = STR_882F_LOADING_UNLOADING;
 					break;
-				case VVW_WIDGET_SHOW_DETAILS: /* show details */
-					ShowVehicleDetailsWindow(v);
-					break;
-				case VVW_WIDGET_CLONE_VEH: /* clone vehicle */
-					DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0, CcCloneVehicle,
-										 _vehicle_command_translation_table[VCT_CMD_CLONE_VEH][v->type]);
+
+				case OT_GOTO_WAYPOINT: {
+					assert(v->type == VEH_TRAIN);
+					SetDParam(0, v->current_order.GetDestination());
+					str = STR_HEADING_FOR_WAYPOINT + _patches.vehicle_speed;
+					SetDParam(1, v->GetDisplaySpeed());
 					break;
-				case VVW_WIDGET_TURN_AROUND: /* turn around */
-					assert(v->type == VEH_TRAIN || v->type == VEH_ROAD);
-					DoCommandP(v->tile, v->index, 0, NULL,
-										 _vehicle_command_translation_table[VCT_CMD_TURN_AROUND][v->type]);
-					break;
-				case VVW_WIDGET_FORCE_PROCEED: /* force proceed */
-					assert(v->type == VEH_TRAIN);
-					DoCommandP(v->tile, v->index, 0, NULL, CMD_FORCE_TRAIN_PROCEED | CMD_MSG(STR_8862_CAN_T_MAKE_TRAIN_PASS_SIGNAL));
+				}
+
+				case OT_LEAVESTATION:
+					if (v->type != VEH_AIRCRAFT) {
+						str = STR_LEAVING;
+						break;
+					}
+					/* fall-through if aircraft. Does this even happen? */
+
+				default:
+					if (v->num_orders == 0) {
+						str = STR_NO_ORDERS + _patches.vehicle_speed;
+						SetDParam(0, v->GetDisplaySpeed());
+					} else {
+						str = STR_EMPTY;
+					}
 					break;
 			}
-		} break;
-
-		case WE_RESIZE:
-			w->viewport->width          += e->we.sizing.diff.x;
-			w->viewport->height         += e->we.sizing.diff.y;
-			w->viewport->virtual_width  += e->we.sizing.diff.x;
-			w->viewport->virtual_height += e->we.sizing.diff.y;
-			break;
-
-		case WE_DESTROY:
-			DeleteWindowById(WC_VEHICLE_ORDERS, w->window_number);
-			DeleteWindowById(WC_VEHICLE_REFIT, w->window_number);
-			DeleteWindowById(WC_VEHICLE_DETAILS, w->window_number);
-			DeleteWindowById(WC_VEHICLE_TIMETABLE, w->window_number);
-			break;
+		}
 
-		case WE_TICK: {
-			const Vehicle *v = GetVehicle(w->window_number);
-			bool veh_stopped = v->IsStoppedInDepot();
+		/* draw the flag plus orders */
+		DrawSprite(v->vehstatus & VS_STOPPED ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, PAL_NONE, 2, this->widget[VVW_WIDGET_START_STOP_VEH].top + 1);
+		DrawStringCenteredTruncated(this->widget[VVW_WIDGET_START_STOP_VEH].left + 8, this->widget[VVW_WIDGET_START_STOP_VEH].right, this->widget[VVW_WIDGET_START_STOP_VEH].top + 1, str, TC_FROMSTRING);
+		this->DrawViewport();
+	}
 
-			/* Widget VVW_WIDGET_GOTO_DEPOT must be hidden if the vehicle is already
-			 * stopped in depot.
-			 * Widget VVW_WIDGET_CLONE_VEH should then be shown, since cloning is
-			 * allowed only while in depot and stopped.
-			 * This sytem allows to have two buttons, on top of each other.
-			 * The same system applies to widget VVW_WIDGET_REFIT_VEH and VVW_WIDGET_TURN_AROUND.*/
-			if (veh_stopped != w->IsWidgetHidden(VVW_WIDGET_GOTO_DEPOT) || veh_stopped == w->IsWidgetHidden(VVW_WIDGET_CLONE_VEH)) {
-				w->SetWidgetHiddenState( VVW_WIDGET_GOTO_DEPOT, veh_stopped);  // send to depot
-				w->SetWidgetHiddenState(VVW_WIDGET_CLONE_VEH, !veh_stopped); // clone
-				if (v->type == VEH_ROAD || v->type == VEH_TRAIN) {
-					w->SetWidgetHiddenState( VVW_WIDGET_REFIT_VEH, !veh_stopped); // refit
-					w->SetWidgetHiddenState(VVW_WIDGET_TURN_AROUND, veh_stopped);  // force turn around
+	virtual void OnClick(Point pt, int widget)
+	{
+		const Vehicle *v = GetVehicle(this->window_number);
+
+		switch (widget) {
+			case VVW_WIDGET_START_STOP_VEH: // start stop
+				DoCommandP(v->tile, v->index, 0, NULL,
+										_vehicle_command_translation_table[VCT_CMD_START_STOP][v->type]);
+				break;
+			case VVW_WIDGET_CENTER_MAIN_VIEH: {/* center main view */
+				const Window *mainwindow = FindWindowById(WC_MAIN_WINDOW, 0);
+				/* code to allow the main window to 'follow' the vehicle if the ctrl key is pressed */
+				if (_ctrl_pressed && mainwindow->viewport->zoom == ZOOM_LVL_NORMAL) {
+					mainwindow->viewport->follow_vehicle = v->index;
+				} else {
+					ScrollMainWindowTo(v->x_pos, v->y_pos);
 				}
-				w->SetDirty();
+			} break;
+
+			case VVW_WIDGET_GOTO_DEPOT: // goto hangar
+				DoCommandP(v->tile, v->index, _ctrl_pressed ? DEPOT_SERVICE : 0, NULL,
+					_vehicle_command_translation_table[VCT_CMD_GOTO_DEPOT][v->type]);
+				break;
+			case VVW_WIDGET_REFIT_VEH: // refit
+				ShowVehicleRefitWindow(v, INVALID_VEH_ORDER_ID);
+				break;
+			case VVW_WIDGET_SHOW_ORDERS: // show orders
+				if (_ctrl_pressed) {
+					ShowTimetableWindow(v);
+				} else {
+					ShowOrdersWindow(v);
+				}
+				break;
+			case VVW_WIDGET_SHOW_DETAILS: // show details
+				ShowVehicleDetailsWindow(v);
+				break;
+			case VVW_WIDGET_CLONE_VEH: // clone vehicle
+				DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0, CcCloneVehicle,
+										_vehicle_command_translation_table[VCT_CMD_CLONE_VEH][v->type]);
+				break;
+			case VVW_WIDGET_TURN_AROUND: // turn around
+				assert(v->type == VEH_TRAIN || v->type == VEH_ROAD);
+				DoCommandP(v->tile, v->index, 0, NULL,
+										_vehicle_command_translation_table[VCT_CMD_TURN_AROUND][v->type]);
+				break;
+			case VVW_WIDGET_FORCE_PROCEED: // force proceed
+				assert(v->type == VEH_TRAIN);
+				DoCommandP(v->tile, v->index, 0, NULL, CMD_FORCE_TRAIN_PROCEED | CMD_MSG(STR_8862_CAN_T_MAKE_TRAIN_PASS_SIGNAL));
+				break;
+		}
+	}
+
+	virtual void OnResize(Point new_size, Point delta)
+	{
+		this->viewport->width          += delta.x;
+		this->viewport->height         += delta.y;
+		this->viewport->virtual_width  += delta.x;
+		this->viewport->virtual_height += delta.y;
+	}
+
+	virtual void OnTick()
+	{
+		const Vehicle *v = GetVehicle(this->window_number);
+		bool veh_stopped = v->IsStoppedInDepot();
+
+		/* Widget VVW_WIDGET_GOTO_DEPOT must be hidden if the vehicle is already
+		 * stopped in depot.
+		 * Widget VVW_WIDGET_CLONE_VEH should then be shown, since cloning is
+		 * allowed only while in depot and stopped.
+		 * This sytem allows to have two buttons, on top of each other.
+		 * The same system applies to widget VVW_WIDGET_REFIT_VEH and VVW_WIDGET_TURN_AROUND.*/
+		if (veh_stopped != this->IsWidgetHidden(VVW_WIDGET_GOTO_DEPOT) || veh_stopped == this->IsWidgetHidden(VVW_WIDGET_CLONE_VEH)) {
+			this->SetWidgetHiddenState( VVW_WIDGET_GOTO_DEPOT, veh_stopped);  // send to depot
+			this->SetWidgetHiddenState(VVW_WIDGET_CLONE_VEH, !veh_stopped); // clone
+			if (v->type == VEH_ROAD || v->type == VEH_TRAIN) {
+				this->SetWidgetHiddenState( VVW_WIDGET_REFIT_VEH, !veh_stopped); // refit
+				this->SetWidgetHiddenState(VVW_WIDGET_TURN_AROUND, veh_stopped);  // force turn around
 			}
-		} break;
+			this->SetDirty();
+		}
 	}
+};
+
+
+/** Shows the vehicle view window of the given vehicle. */
+void ShowVehicleViewWindow(const Vehicle *v)
+{
+	AllocateWindowDescFront<VehicleViewWindow>((v->type == VEH_TRAIN) ? &_train_view_desc : &_vehicle_view_desc, v->index);
 }
 
 void DrawVehicleImage(const Vehicle *v, int x, int y, VehicleID selection, int count, int skip)
@@ -2177,3 +2114,12 @@
 		default: NOT_REACHED();
 	}
 }
+
+void StopGlobalFollowVehicle(const Vehicle *v)
+{
+	Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
+	if (w != NULL && w->viewport->follow_vehicle == v->index) {
+		ScrollMainWindowTo(v->x_pos, v->y_pos, true); // lock the main view on the vehicle's last position
+		w->viewport->follow_vehicle = INVALID_VEHICLE;
+	}
+}
--- a/src/vehicle_gui.h	Mon May 19 14:14:33 2008 +0000
+++ b/src/vehicle_gui.h	Mon May 19 15:13:58 2008 +0000
@@ -5,12 +5,12 @@
 #ifndef VEHICLE_GUI_H
 #define VEHICLE_GUI_H
 
-#include "window_gui.h"
+#include "sortlist_type.h"
+#include "window_type.h"
 #include "vehicle_type.h"
 #include "order_type.h"
 #include "station_type.h"
 #include "engine_type.h"
-#include "vehicle_base.h"
 
 void DrawVehicleProfitButton(const Vehicle *v, int x, int y);
 void ShowVehicleRefitWindow(const Vehicle *v, VehicleOrderID order);
@@ -89,21 +89,6 @@
  * For ease of use it can be called with both Vehicle pointers and VehicleIDs. */
 void ChangeVehicleViewWindow(VehicleID from_index, VehicleID to_index);
 
-static inline void ChangeVehicleViewWindow(const Vehicle *from_v, VehicleID to_index)
-{
-	ChangeVehicleViewWindow(from_v->index, to_index);
-}
-
-static inline void ChangeVehicleViewWindow(VehicleID from_index, const Vehicle *to_v)
-{
-	ChangeVehicleViewWindow(from_index, to_v->index);
-}
-
-static inline void ChangeVehicleViewWindow(const Vehicle *from_v, const Vehicle *to_v)
-{
-	ChangeVehicleViewWindow(from_v->index, to_v->index);
-}
-
 static inline uint GetVehicleListHeight(VehicleType type)
 {
 	return (type == VEH_TRAIN || type == VEH_ROAD) ? 14 : 24;
@@ -148,8 +133,6 @@
 extern Sorting _sorting;
 
 /* sorter stuff */
-void RebuildVehicleLists();
-void ResortVehicleLists();
 void SortVehicleList(VehicleListBase *vl);
 void BuildVehicleList(VehicleListBase *vl, PlayerID owner, uint16 index, uint16 window_type);
 
--- a/src/viewport.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/viewport.cpp	Mon May 19 15:13:58 2008 +0000
@@ -47,6 +47,7 @@
 #include "misc/smallvec.h"
 #include "window_func.h"
 #include "tilehighlight_func.h"
+#include "window_gui.h"
 
 #include "table/sprites.h"
 #include "table/strings.h"
@@ -1536,17 +1537,17 @@
 	ViewportDrawChk(vp, left, top, right, bottom);
 }
 
-void DrawWindowViewport(const Window *w)
+void Window::DrawViewport() const
 {
 	DrawPixelInfo *dpi = _cur_dpi;
 
-	dpi->left += w->left;
-	dpi->top += w->top;
-
-	ViewportDraw(w->viewport, dpi->left, dpi->top, dpi->left + dpi->width, dpi->top + dpi->height);
-
-	dpi->left -= w->left;
-	dpi->top -= w->top;
+	dpi->left += this->left;
+	dpi->top += this->top;
+
+	ViewportDraw(this->viewport, dpi->left, dpi->top, dpi->left + dpi->width, dpi->top + dpi->height);
+
+	dpi->left -= this->left;
+	dpi->top -= this->top;
 }
 
 static inline void ClampViewportToMap(const ViewPort *vp, int &x, int &y)
@@ -2660,7 +2661,10 @@
 	_thd.selend.y = y;
 }
 
-/** while dragging */
+/**
+ * Handle the mouse while dragging for placement/resizing.
+ * @return Boolean whether search for a handler should continue
+ */
 bool VpHandlePlaceSizingDrag()
 {
 	if (_special_mouse_mode != WSM_SIZING) return true;
@@ -2708,12 +2712,18 @@
 
 void SetObjectToPlace(CursorID icon, SpriteID pal, ViewportHighlightMode mode, WindowClass window_class, WindowNumber window_num)
 {
-	Window *w;
-
 	/* undo clicking on button and drag & drop */
 	if (_thd.place_mode != VHM_NONE || _special_mouse_mode == WSM_DRAGDROP) {
-		w = FindWindowById(_thd.window_class, _thd.window_number);
-		if (w != NULL) w->OnPlaceObjectAbort();
+		Window *w = FindWindowById(_thd.window_class, _thd.window_number);
+		if (w != NULL) {
+			/* Call the abort function, but set the window class to something
+			 * that will never be used to avoid infinite loops. Setting it to
+			 * the 'next' window class must not be done because recursion into
+			 * this function might in some cases reset the newly set object to
+			 * place or not properly reset the original selection. */
+			_thd.window_class = WC_INVALID;
+			w->OnPlaceObjectAbort();
+		}
 	}
 
 	SetTileSelectSize(1, 1);
@@ -2734,10 +2744,12 @@
 	if (mode == VHM_SPECIAL) // special tools, like tunnels or docks start with presizing mode
 		VpStartPreSizing();
 
-	if ( (int)icon < 0)
+	if ((int)icon < 0) {
 		SetAnimatedMouseCursor(_animcursors[~icon]);
-	else
+	} else {
 		SetMouseCursor(icon, pal);
+	}
+
 }
 
 void ResetObjectToPlace()
--- a/src/water_cmd.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/water_cmd.cpp	Mon May 19 15:13:58 2008 +0000
@@ -838,20 +838,21 @@
 				case VEH_TRAIN:
 					if (IsFrontEngine(v)) pass += 4; // driver
 					v->u.rail.crash_anim_pos = 4000; // max 4440, disappear pretty fast
+					InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
 					break;
 
 				case VEH_ROAD:
 					if (IsRoadVehFront(v)) pass += 1; // driver
 					v->u.road.crashed_ctr = 2000; // max 2220, disappear pretty fast
+					InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
 					break;
 
 				case VEH_AIRCRAFT:
 					pass += 2; // driver
 					v->u.air.crashed_counter = 9000; // max 10000, disappear pretty fast
+					InvalidateWindowClassesData(WC_AIRCRAFT_LIST, 0);
 					break;
 			}
-
-			RebuildVehicleLists();
 		} else {
 			return;
 		}
@@ -861,7 +862,7 @@
 
 		SetDParam(0, pass);
 		AddNewsItem(STR_B006_FLOOD_VEHICLE_DESTROYED,
-			NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ACCIDENT, DNC_NONE,
+			NS_ACCIDENT_VEHICLE,
 			v->index,
 			0);
 		CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
@@ -1123,7 +1124,7 @@
 	switch (GetWaterTileType(tile)) {
 		case WATER_TILE_CLEAR: ts = (GetTileSlope(tile, NULL) == SLOPE_FLAT) ? TRACK_BIT_ALL : TRACK_BIT_NONE; break;
 		case WATER_TILE_COAST: ts = (TrackBits)coast_tracks[GetTileSlope(tile, NULL) & 0xF]; break;
-		case WATER_TILE_LOCK:  ts = AxisToTrackBits(DiagDirToAxis(GetLockDirection(tile))); break;
+		case WATER_TILE_LOCK:  ts = DiagDirToDiagTrackBits(GetLockDirection(tile)); break;
 		case WATER_TILE_DEPOT: ts = AxisToTrackBits(GetShipDepotAxis(tile)); break;
 		default: return 0;
 	}
--- a/src/widget.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/widget.cpp	Mon May 19 15:13:58 2008 +0000
@@ -190,20 +190,20 @@
  * Paint all widgets of a window.
  * @param w Window
  */
-void DrawWindowWidgets(const Window *w)
+void Window::DrawWidgets() const
 {
 	const DrawPixelInfo* dpi = _cur_dpi;
 
-	for (uint i = 0; i < w->widget_count; i++) {
-		const Widget *wi = &w->widget[i];
-		bool clicked = w->IsWidgetLowered(i);
+	for (uint i = 0; i < this->widget_count; i++) {
+		const Widget *wi = &this->widget[i];
+		bool clicked = this->IsWidgetLowered(i);
 		Rect r;
 
 		if (dpi->left > (r.right = wi->right) ||
 				dpi->left + dpi->width <= (r.left = wi->left) ||
 				dpi->top > (r.bottom = wi->bottom) ||
 				dpi->top + dpi->height <= (r.top = wi->top) ||
-				w->IsWidgetHidden(i)) {
+				this->IsWidgetHidden(i)) {
 			continue;
 		}
 
@@ -304,11 +304,11 @@
 			assert(r.right - r.left == 11); // To ensure the same sizes are used everywhere!
 
 			/* draw up/down buttons */
-			clicked = ((w->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_UP);
+			clicked = ((this->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_UP);
 			DrawFrameRect(r.left, r.top, r.right, r.top + 9, wi->color, (clicked) ? FR_LOWERED : FR_NONE);
 			DoDrawString(UPARROW, r.left + 2 + clicked, r.top + clicked, TC_BLACK);
 
-			clicked = (((w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_DOWN));
+			clicked = (((this->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_DOWN));
 			DrawFrameRect(r.left, r.bottom - 9, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : FR_NONE);
 			DoDrawString(DOWNARROW, r.left + 2 + clicked, r.bottom - 9 + clicked, TC_BLACK);
 
@@ -325,8 +325,8 @@
 			GfxFillRect(r.left + 7, r.top + 10, r.left + 7, r.bottom - 10, c1);
 			GfxFillRect(r.left + 8, r.top + 10, r.left + 8, r.bottom - 10, c2);
 
-			Point pt = HandleScrollbarHittest(&w->vscroll, r.top, r.bottom);
-			DrawFrameRect(r.left, pt.x, r.right, pt.y, wi->color, (w->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_MIDDLE ? FR_LOWERED : FR_NONE);
+			Point pt = HandleScrollbarHittest(&this->vscroll, r.top, r.bottom);
+			DrawFrameRect(r.left, pt.x, r.right, pt.y, wi->color, (this->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_MIDDLE ? FR_LOWERED : FR_NONE);
 			break;
 		}
 
@@ -335,11 +335,11 @@
 			assert(r.right - r.left == 11); // To ensure the same sizes are used everywhere!
 
 			/* draw up/down buttons */
-			clicked = ((w->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_UP | WF_SCROLL2));
+			clicked = ((this->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_UP | WF_SCROLL2));
 			DrawFrameRect(r.left, r.top, r.right, r.top + 9, wi->color,  (clicked) ? FR_LOWERED : FR_NONE);
 			DoDrawString(UPARROW, r.left + 2 + clicked, r.top + clicked, TC_BLACK);
 
-			clicked = ((w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_DOWN | WF_SCROLL2));
+			clicked = ((this->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_DOWN | WF_SCROLL2));
 			DrawFrameRect(r.left, r.bottom - 9, r.right, r.bottom, wi->color,  (clicked) ? FR_LOWERED : FR_NONE);
 			DoDrawString(DOWNARROW, r.left + 2 + clicked, r.bottom - 9 + clicked, TC_BLACK);
 
@@ -356,8 +356,8 @@
 			GfxFillRect(r.left + 7, r.top + 10, r.left + 7, r.bottom - 10, c1);
 			GfxFillRect(r.left + 8, r.top + 10, r.left + 8, r.bottom - 10, c2);
 
-			Point pt = HandleScrollbarHittest(&w->vscroll2, r.top, r.bottom);
-			DrawFrameRect(r.left, pt.x, r.right, pt.y, wi->color, (w->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_MIDDLE | WF_SCROLL2) ? FR_LOWERED : FR_NONE);
+			Point pt = HandleScrollbarHittest(&this->vscroll2, r.top, r.bottom);
+			DrawFrameRect(r.left, pt.x, r.right, pt.y, wi->color, (this->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_MIDDLE | WF_SCROLL2) ? FR_LOWERED : FR_NONE);
 			break;
 		}
 
@@ -366,11 +366,11 @@
 			assert(wi->data == 0);
 			assert(r.bottom - r.top == 11); // To ensure the same sizes are used everywhere!
 
-			clicked = ((w->flags4 & (WF_SCROLL_UP | WF_HSCROLL)) == (WF_SCROLL_UP | WF_HSCROLL));
+			clicked = ((this->flags4 & (WF_SCROLL_UP | WF_HSCROLL)) == (WF_SCROLL_UP | WF_HSCROLL));
 			DrawFrameRect(r.left, r.top, r.left + 9, r.bottom, wi->color, (clicked) ? FR_LOWERED : FR_NONE);
 			DrawSprite(SPR_ARROW_LEFT, PAL_NONE, r.left + 1 + clicked, r.top + 1 + clicked);
 
-			clicked = ((w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL)) == (WF_SCROLL_DOWN | WF_HSCROLL));
+			clicked = ((this->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL)) == (WF_SCROLL_DOWN | WF_HSCROLL));
 			DrawFrameRect(r.right - 9, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : FR_NONE);
 			DrawSprite(SPR_ARROW_RIGHT, PAL_NONE, r.right - 8 + clicked, r.top + 1 + clicked);
 
@@ -388,8 +388,8 @@
 			GfxFillRect(r.left + 10, r.top + 8, r.right - 10, r.top + 8, c2);
 
 			/* draw actual scrollbar */
-			Point pt = HandleScrollbarHittest(&w->hscroll, r.left, r.right);
-			DrawFrameRect(pt.x, r.top, pt.y, r.bottom, wi->color, (w->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL)) == (WF_SCROLL_MIDDLE | WF_HSCROLL) ? FR_LOWERED : FR_NONE);
+			Point pt = HandleScrollbarHittest(&this->hscroll, r.left, r.right);
+			DrawFrameRect(pt.x, r.top, pt.y, r.bottom, wi->color, (this->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL)) == (WF_SCROLL_MIDDLE | WF_HSCROLL) ? FR_LOWERED : FR_NONE);
 
 			break;
 		}
@@ -429,7 +429,7 @@
 			assert(wi->data == 0);
 			assert(r.right - r.left == 11); // To ensure the same sizes are used everywhere!
 
-			clicked = !!(w->flags4 & WF_STICKY);
+			clicked = !!(this->flags4 & WF_STICKY);
 			DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : FR_NONE);
 			DrawSprite((clicked) ? SPR_PIN_UP : SPR_PIN_DOWN, PAL_NONE, r.left + 2 + clicked, r.top + 3 + clicked);
 			break;
@@ -438,7 +438,7 @@
 			assert(wi->data == 0);
 			assert(r.right - r.left == 11); // To ensure the same sizes are used everywhere!
 
-			clicked = !!(w->flags4 & WF_SIZING);
+			clicked = !!(this->flags4 & WF_SIZING);
 			DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : FR_NONE);
 			DrawSprite(SPR_WINDOW_RESIZE, PAL_NONE, r.left + 3 + clicked, r.top + 3 + clicked);
 			break;
@@ -457,10 +457,10 @@
 		case WWT_CAPTION:
 			assert(r.bottom - r.top == 13); // To ensure the same sizes are used everywhere!
 			DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, FR_BORDERONLY);
-			DrawFrameRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, wi->color, (w->caption_color == 0xFF) ? FR_LOWERED | FR_DARKENED : FR_LOWERED | FR_DARKENED | FR_BORDERONLY);
+			DrawFrameRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, wi->color, (this->caption_color == 0xFF) ? FR_LOWERED | FR_DARKENED : FR_LOWERED | FR_DARKENED | FR_BORDERONLY);
 
-			if (w->caption_color != 0xFF) {
-				GfxFillRect(r.left + 2, r.top + 2, r.right - 2, r.bottom - 2, _colour_gradient[_player_colors[w->caption_color]][4]);
+			if (this->caption_color != 0xFF) {
+				GfxFillRect(r.left + 2, r.top + 2, r.right - 2, r.bottom - 2, _colour_gradient[_player_colors[this->caption_color]][4]);
 			}
 
 			DrawStringCenteredTruncated(r.left + 2, r.right - 2, r.top + 2, wi->data, 0x84);
@@ -489,14 +489,14 @@
 		}
 		}
 
-		if (w->IsWidgetDisabled(i)) {
+		if (this->IsWidgetDisabled(i)) {
 			GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, _colour_gradient[wi->color & 0xF][2] | (1 << PALETTE_MODIFIER_GREYOUT));
 		}
 	}
 
 
-	if (w->flags4 & WF_WHITE_BORDER_MASK) {
-		DrawFrameRect(0, 0, w->width - 1, w->height - 1, 0xF, FR_BORDERONLY);
+	if (this->flags4 & WF_WHITE_BORDER_MASK) {
+		DrawFrameRect(0, 0, this->width - 1, this->height - 1, 0xF, FR_BORDERONLY);
 	}
 
 }
@@ -597,10 +597,10 @@
  * @param widget Sort button widget
  * @param state State of sort button
  */
-void DrawSortButtonState(const Window *w, int widget, SortButtonState state)
+void Window::DrawSortButtonState(int widget, SortButtonState state) const
 {
 	if (state == SBS_OFF) return;
 
-	int offset = w->IsWidgetLowered(widget) ? 1 : 0;
-	DoDrawString(state == SBS_DOWN ? DOWNARROW : UPARROW, w->widget[widget].right - 11 + offset, w->widget[widget].top + 1 + offset, TC_BLACK);
+	int offset = this->IsWidgetLowered(widget) ? 1 : 0;
+	DoDrawString(state == SBS_DOWN ? DOWNARROW : UPARROW, this->widget[widget].right - 11 + offset, this->widget[widget].top + 1 + offset, TC_BLACK);
 }
--- a/src/widgets/dropdown.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/widgets/dropdown.cpp	Mon May 19 15:13:58 2008 +0000
@@ -72,7 +72,7 @@
 	bool drag_mode;
 	int scrolling;
 
-	DropdownWindow(int x, int y, int width, int height, const Widget *widget) : Window(x, y, width, height, NULL, WC_DROPDOWN_MENU, widget)
+	DropdownWindow(int x, int y, int width, int height, const Widget *widget) : Window(x, y, width, height, WC_DROPDOWN_MENU, widget)
 	{
 	}
 
@@ -87,9 +87,9 @@
 		DeleteDropDownList(this->list);
 	}
 
-	int GetDropDownItem()
+	bool GetDropDownItem(int &value)
 	{
-		if (GetWidgetFromPos(this, _cursor.pos.x - this->left, _cursor.pos.y - this->top) < 0) return -1;
+		if (GetWidgetFromPos(this, _cursor.pos.x - this->left, _cursor.pos.y - this->top) < 0) return false;
 
 		int y     = _cursor.pos.y - this->top - 2;
 		int width = this->widget[0].right - 3;
@@ -105,19 +105,20 @@
 			int item_height = item->Height(width);
 
 			if (y < item_height) {
-				if (item->masked || item->String() == STR_NULL) return -1;
-				return item->result;
+				if (item->masked || item->String() == STR_NULL) return false;
+				value = item->result;
+				return true;
 			}
 
 			y -= item_height;
 		}
 
-		return -1;
+		return false;
 	}
 
 	virtual void OnPaint()
 	{
-		DrawWindowWidgets(this);
+		this->DrawWidgets();
 
 		int x = 1;
 		int y = 2;
@@ -162,8 +163,8 @@
 	virtual void OnClick(Point pt, int widget)
 	{
 		if (widget != 0) return;
-		int item = GetDropDownItem();
-		if (item >= 0) {
+		int item;
+		if (this->GetDropDownItem(item)) {
 			this->click_delay = 4;
 			this->selected_index = item;
 			this->SetDirty();
@@ -197,11 +198,11 @@
 		}
 
 		if (this->drag_mode) {
-			int item = GetDropDownItem();
+			int item;
 
 			if (!_left_button_clicked) {
 				this->drag_mode = false;
-				if (item < 0) return;
+				if (!this->GetDropDownItem(item)) return;
 				this->click_delay = 2;
 			} else {
 				if (_cursor.pos.y <= this->top + 2) {
@@ -214,7 +215,7 @@
 					return;
 				}
 
-				if (item < 0) return;
+				if (!this->GetDropDownItem(item)) return;
 			}
 
 			this->selected_index = item;
--- a/src/win32.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/win32.cpp	Mon May 19 15:13:58 2008 +0000
@@ -61,7 +61,7 @@
 		for (;;) {
 			FARPROC p;
 
-			while (*dll++ != '\0');
+			while (*dll++ != '\0') { /* Nothing */ }
 			if (*dll == '\0') break;
 #if defined(WINCE)
 			p = GetProcAddress(lib, MB_TO_WIDE(dll));
@@ -796,7 +796,7 @@
 		fios->mtime = 0;
 		snprintf(fios->name, lengthof(fios->name),  "%c:", s[0] & 0xFF);
 		ttd_strlcpy(fios->title, fios->name, lengthof(fios->title));
-		while (*s++ != '\0');
+		while (*s++ != '\0') { /* Nothing */ }
 	}
 #endif
 }
--- a/src/window.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/window.cpp	Mon May 19 15:13:58 2008 +0000
@@ -48,221 +48,6 @@
 byte _special_mouse_mode;
 
 
-/**
- * Call the window event handler for handling event \a e.
- * This is a temporary helper functions that will be removed
- * once all windows that still rely on WindowEvent and
- * WindowEventCodes have been rewritten to use the 'OnXXX'
- * event handlers.
- * @param e Window event to handle
- */
-void Window::HandleWindowEvent(WindowEvent *e)
-{
-	if (wndproc != NULL) wndproc(this, e);
-}
-
-void Window::OnPaint()
-{
-	WindowEvent e;
-	e.event = WE_PAINT;
-	this->HandleWindowEvent(&e);
-}
-
-bool Window::OnKeyPress(uint16 key, uint16 keycode)
-{
-	WindowEvent e;
-	e.event = WE_KEYPRESS;
-	e.we.keypress.key     = key;
-	e.we.keypress.keycode = keycode;
-	e.we.keypress.cont    = true;
-	this->HandleWindowEvent(&e);
-
-	return e.we.keypress.cont;
-}
-
-bool Window::OnCTRLStateChange()
-{
-	WindowEvent e;
-	e.event = WE_CTRL_CHANGED;
-	e.we.ctrl.cont = true;
-	this->HandleWindowEvent(&e);
-
-	return e.we.ctrl.cont;
-}
-
-void Window::OnClick(Point pt, int widget)
-{
-	WindowEvent e;
-	e.event = WE_CLICK;
-	e.we.click.pt     = pt;
-	e.we.click.widget = widget;
-	this->HandleWindowEvent(&e);
-}
-
-void Window::OnDoubleClick(Point pt, int widget)
-{
-	WindowEvent e;
-	e.event = WE_DOUBLE_CLICK;
-	e.we.click.pt     = pt;
-	e.we.click.widget = widget;
-	this->HandleWindowEvent(&e);
-}
-
-void Window::OnRightClick(Point pt, int widget)
-{
-	WindowEvent e;
-	e.event = WE_RCLICK;
-	e.we.click.pt     = pt;
-	e.we.click.widget = widget;
-	this->HandleWindowEvent(&e);
-}
-
-void Window::OnDragDrop(Point pt, int widget)
-{
-	WindowEvent e;
-	e.event = WE_DRAGDROP;
-	e.we.click.pt     = pt;
-	e.we.click.widget = widget;
-	this->HandleWindowEvent(&e);
-}
-
-void Window::OnScroll(Point delta)
-{
-	WindowEvent e;
-	e.event = WE_SCROLL;
-	e.we.scroll.delta = delta;
-	this->HandleWindowEvent(&e);
-}
-
-void Window::OnMouseOver(Point pt, int widget)
-{
-	WindowEvent e;
-	e.event = WE_MOUSEOVER;
-	e.we.click.pt     = pt;
-	e.we.click.widget = widget;
-	this->HandleWindowEvent(&e);
-}
-
-void Window::OnMouseWheel(int wheel)
-{
-	WindowEvent e;
-	e.event = WE_MOUSEWHEEL;
-	e.we.wheel.wheel = wheel;
-	this->HandleWindowEvent(&e);
-}
-
-void Window::OnMouseLoop()
-{
-	WindowEvent e;
-	e.event = WE_MOUSELOOP;
-	this->HandleWindowEvent(&e);
-}
-
-void Window::OnTick()
-{
-	WindowEvent e;
-	e.event = WE_TICK;
-	this->HandleWindowEvent(&e);
-}
-
-void Window::OnHundredthTick()
-{
-	WindowEvent e;
-	e.event = WE_100_TICKS;
-	this->HandleWindowEvent(&e);
-}
-
-void Window::OnTimeout()
-{
-	WindowEvent e;
-	e.event = WE_TIMEOUT;
-	this->HandleWindowEvent(&e);
-}
-
-void Window::OnResize(Point new_size, Point delta)
-{
-	WindowEvent e;
-	e.event = WE_RESIZE;
-	e.we.sizing.size = new_size;
-	e.we.sizing.diff = delta;
-	this->HandleWindowEvent(&e);
-}
-
-void Window::OnDropdownSelect(int widget, int index)
-{
-	WindowEvent e;
-	e.event = WE_DROPDOWN_SELECT;
-	e.we.dropdown.button = widget;
-	e.we.dropdown.index  = index;
-	this->HandleWindowEvent(&e);
-}
-
-void Window::OnQueryTextFinished(char *str)
-{
-	WindowEvent e;
-	e.event = WE_ON_EDIT_TEXT;
-	e.we.edittext.str = str;
-	this->HandleWindowEvent(&e);
-}
-
-void Window::OnInvalidateData(int data)
-{
-	WindowEvent e;
-	e.event = WE_INVALIDATE_DATA;
-	e.we.invalidate.data = data;
-	this->HandleWindowEvent(&e);
-}
-
-void Window::OnPlaceObject(Point pt, TileIndex tile)
-{
-	WindowEvent e;
-	e.event = WE_PLACE_OBJ;
-	e.we.place.pt   = pt;
-	e.we.place.tile = tile;
-	this->HandleWindowEvent(&e);
-}
-
-void Window::OnPlaceObjectAbort()
-{
-	WindowEvent e;
-	e.event = WE_ABORT_PLACE_OBJ;
-	this->HandleWindowEvent(&e);
-}
-
-
-void Window::OnPlaceDrag(ViewportPlaceMethod select_method, byte select_proc, Point pt)
-{
-	WindowEvent e;
-	e.event = WE_PLACE_DRAG;
-	e.we.place.select_method = select_method;
-	e.we.place.select_proc   = select_proc;
-	e.we.place.pt            = pt;
-	this->HandleWindowEvent(&e);
-}
-
-void Window::OnPlaceMouseUp(ViewportPlaceMethod select_method, byte select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
-{
-	WindowEvent e;
-	e.event = WE_PLACE_MOUSEUP;
-	e.we.place.select_method = select_method;
-	e.we.place.select_proc   = select_proc;
-	e.we.place.pt            = pt;
-	e.we.place.tile          = end_tile;
-	e.we.place.starttile     = start_tile;
-	this->HandleWindowEvent(&e);
-}
-
-void Window::OnPlacePresize(Point pt, TileIndex tile)
-{
-	WindowEvent e;
-	e.event = WE_PLACE_PRESIZE;
-	e.we.place.pt   = pt;
-	e.we.place.tile = tile;
-	this->HandleWindowEvent(&e);
-}
-
-
-
 void CDECL Window::SetWidgetsDisabledState(bool disab_stat, int widgets, ...)
 {
 	va_list wdg_list;
@@ -626,12 +411,13 @@
 	memmove(wz, wz + 1, (byte*)_last_z_window - (byte*)wz);
 	_last_z_window--;
 
-	/* Delete any children a window might have in a head-recursive manner */
-	delete FindChildWindow(this);
+	/* Delete all children a window might have in a head-recursive manner */
+	Window *child = FindChildWindow(this);
+	while (child != NULL) {
+		delete child;
+		child = FindChildWindow(this);
+	}
 
-	WindowEvent e;
-	e.event = WE_DESTROY;
-	this->HandleWindowEvent(&e);
 	if (this->viewport != NULL) DeleteWindowViewport(this);
 
 	this->SetDirty();
@@ -844,11 +630,6 @@
 	NOT_REACHED();
 }
 
-bool IsWindowOfPrototype(const Window *w, const Widget *widget)
-{
-	return (w->original_widget == widget);
-}
-
 /**
  * Assign widgets to a new window by initialising its widget pointers, and by
  * copying the widget array \a widget to \c w->widget to allow for resizable
@@ -857,13 +638,10 @@
  * @param widget pointer of widget array to fill the window with
  *
  * @post \c w->widget points to allocated memory and contains the copied widget array except for the terminating widget,
- *       \c w->original_widget points to the original widgets,
  *       \c w->widget_count contains number of widgets in the allocated memory.
  */
 static void AssignWidgetToWindow(Window *w, const Widget *widget)
 {
-	w->original_widget = widget;
-
 	if (widget != NULL) {
 		uint index = 1;
 
@@ -887,14 +665,13 @@
  * @param y offset in pixels from the top of the screen
  * @param min_width minimum width in pixels of the window
  * @param min_height minimum height in pixels of the window
- * @param *proc see WindowProc function to call when any messages/updates happen to the window
  * @param cls see WindowClass class of the window, used for identification and grouping
  * @param *widget see Widget pointer to the window layout and various elements
  * @param window_number number being assigned to the new window
- * @param data the data to be given during the WE_CREATE message
- * @return Window pointer of the newly created window */
+ * @return Window pointer of the newly created window
+ */
 void Window::Initialize(int x, int y, int min_width, int min_height,
-				WindowProc *proc, WindowClass cls, const Widget *widget, int window_number, void *data)
+				WindowClass cls, const Widget *widget, int window_number)
 {
 	/* We have run out of windows, close one and use that as the place for our new one */
 	if (_last_z_window == endof(_z_windows)) {
@@ -911,7 +688,6 @@
 	this->top = y;
 	this->width = min_width;
 	this->height = min_height;
-	this->wndproc = proc;
 	AssignWidgetToWindow(this, widget);
 	this->resize.width = min_width;
 	this->resize.height = min_height;
@@ -940,11 +716,6 @@
 
 	*wz = this;
 	_last_z_window++;
-
-	WindowEvent e;
-	e.event = WE_CREATE;
-	e.we.create.data = data;
-	this->HandleWindowEvent(&e);
 }
 
 /**
@@ -1020,16 +791,13 @@
  * @param y offset in pixels from the top of the screen
  * @param width width in pixels of the window
  * @param height height in pixels of the window
- * @param *proc see WindowProc function to call when any messages/updates happen to the window
  * @param cls see WindowClass class of the window, used for identification and grouping
  * @param *widget see Widget pointer to the window layout and various elements
  * @return Window pointer of the newly created window
  */
-Window::Window(int x, int y, int width, int height, WindowProc *proc, WindowClass cls, const Widget *widget, void *data)
+Window::Window(int x, int y, int width, int height, WindowClass cls, const Widget *widget)
 {
-	this->Initialize(x, y, width, height, proc, cls, widget, 0, data);
-
-	if (proc != NULL) this->FindWindowPlacementAndResize(width, height);
+	this->Initialize(x, y, width, height, cls, widget, 0);
 }
 
 
@@ -1215,17 +983,14 @@
  *
  * @param *desc         The pointer to the WindowDesc to be created
  * @param window_number the window number of the new window
- * @param data          arbitrary data that is send with the WE_CREATE message
  *
  * @return Window pointer of the newly created window
  */
-Window::Window(const WindowDesc *desc, void *data, WindowNumber window_number)
+Window::Window(const WindowDesc *desc, WindowNumber window_number)
 {
 	Point pt = LocalGetWindowPlacement(desc, window_number);
-	this->Initialize(pt.x, pt.y, desc->minimum_width, desc->minimum_height, desc->proc, desc->cls, desc->widgets, window_number, data);
+	this->Initialize(pt.x, pt.y, desc->minimum_width, desc->minimum_height, desc->cls, desc->widgets, window_number);
 	this->desc_flags = desc->flags;
-
-	if (desc->proc != NULL) this->FindWindowPlacementAndResize(desc->default_width, desc->default_height);
 }
 
 /** Do a search for a window at specific coordinates. For this we start
@@ -1860,8 +1625,7 @@
 				w->window_class != WC_COMPANY_PASSWORD_WINDOW) {
 			continue;
 		}
-		;
-		if (!w->OnKeyPress(key, keycode)) return;
+		if (w->OnKeyPress(key, keycode) == Window::ES_HANDLED) return;
 	}
 
 	Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0);
@@ -1877,7 +1641,7 @@
 	/* Call the event, start with the uppermost window. */
 	for (Window* const *wz = _last_z_window; wz != _z_windows;) {
 		Window *w = *--wz;
-		if (!w->OnCTRLStateChange()) break;
+		if (w->OnCTRLStateChange() == Window::ES_HANDLED) return;
 	}
 }
 
@@ -1970,7 +1734,7 @@
 
 	if (mousewheel != 0) {
 		if (_patches.scrollwheel_scrolling == 0) {
-			/* Send WE_MOUSEWHEEL event to window */
+			/* Send mousewheel event to window */
 			w->OnMouseWheel(mousewheel);
 		}
 
@@ -2400,3 +2164,13 @@
 		w->top = top;
 	}
 }
+
+/** Destructor of the base class PickerWindowBase
+ * Main utility is to stop the base Window destructor from triggering
+ * a free while the child will already be free, in this case by the ResetObjectToPlace().
+ */
+PickerWindowBase::~PickerWindowBase()
+{
+	this->window_class = WC_INVALID; // stop the ancestor from freeing the already (to be) child
+	ResetObjectToPlace();
+}
--- a/src/window_gui.h	Mon May 19 14:14:33 2008 +0000
+++ b/src/window_gui.h	Mon May 19 15:13:58 2008 +0000
@@ -20,8 +20,6 @@
  */
 static const int MAX_NUMBER_OF_WINDOWS = 25;
 
-typedef void WindowProc(Window *w, WindowEvent *e);
-
 /* How the resize system works:
     First, you need to add a WWT_RESIZEBOX to the widgets, and you need
      to add the flag WDF_RESIZABLE to the window. Now the window is ready
@@ -106,109 +104,6 @@
 void DrawFrameRect(int left, int top, int right, int bottom, int color, FrameFlags flags);
 
 /**
- * Available window events
- */
-enum WindowEventCodes {
-	WE_CREATE,       ///< Initialize the Window
-	WE_DESTROY,      ///< Prepare for deletion of the window
-	WE_PAINT,        ///< Repaint the window contents
-	WE_KEYPRESS,     ///< Key pressed
-	WE_CLICK,        ///< Left mouse button click
-	WE_DOUBLE_CLICK, ///< Left mouse button double click
-	WE_RCLICK,       ///< Right mouse button click
-	WE_MOUSEOVER,
-	WE_MOUSEWHEEL,
-	WE_MOUSELOOP,    ///< Event for each mouse event in the game (at least once every game tick)
-	WE_TICK,         ///< Regularly occurring event (every game tick)
-	WE_100_TICKS,    ///< Regularly occurring event (every 100 game ticks, approximatelly 3 seconds)
-	WE_TIMEOUT,
-	WE_PLACE_OBJ,
-	WE_ABORT_PLACE_OBJ,
-	WE_ON_EDIT_TEXT,
-	WE_DRAGDROP,
-	WE_PLACE_DRAG,
-	WE_PLACE_MOUSEUP,
-	WE_PLACE_PRESIZE,
-	WE_DROPDOWN_SELECT,
-	WE_RESIZE,          ///< Request to resize the window, @see WindowEvent.we.resize
-	WE_SCROLL,
-	WE_INVALIDATE_DATA, ///< Notification that data displayed by the window is obsolete
-	WE_CTRL_CHANGED,    ///< CTRL key has changed state
-};
-
-/**
- * Data structures for additional data associated with a window event
- * @see WindowEventCodes
- */
-struct WindowEvent {
-	byte event;
-	union {
-		struct {
-			void *data;
-		} create;
-
-		struct {
-			Point pt;
-			int widget;
-		} click;
-
-		struct {
-			Point pt;
-			TileIndex tile;
-			TileIndex starttile;
-			ViewportPlaceMethod select_method;
-			byte select_proc;
-		} place;
-
-		struct {
-			Point pt;
-			int widget;
-		} dragdrop;
-
-		struct {
-			Point size;
-			Point diff;
-		} sizing;
-
-		struct {
-			char *str;
-		} edittext;
-
-		struct {
-			int button;
-			int index;
-		} dropdown;
-
-		struct {
-			Point pt;
-			int widget;
-		} mouseover;
-
-		struct {
-			bool cont;      ///< continue the search? (default true)
-			uint16 key;     ///< 16-bit Unicode value of the key
-			uint16 keycode; ///< untranslated key (including shift-state)
-		} keypress;
-
-		struct {
-			int data;
-		} invalidate;
-
-		struct {
-			Point delta;   ///< delta position against position of last call
-		} scroll;
-
-		struct {
-			int wheel;     ///< how much was 'wheel'd'
-		} wheel;
-
-		struct {
-			bool cont;     ///< continue the search? (default true)
-		} ctrl;
-	} we;
-};
-
-/**
  * High level window description
  */
 struct WindowDesc {
@@ -222,7 +117,6 @@
 	WindowClass parent_cls; ///< Class of the parent window, @see WindowClass
 	uint32 flags;           ///< Flags, @see WindowDefaultFlags
 	const Widget *widgets;  ///< List of widgets with their position and size for the window
-	WindowProc *proc;       ///< Window event handler function for the window
 };
 
 /**
@@ -249,8 +143,6 @@
 	WDP_ALIGN_TBL = -4, ///< Align the left side of the window with the left side of the main toolbar
 };
 
-#define WP(ptr, str) (*(str*)(ptr)->custom)
-
 /**
  * Scrollbar data structure
  */
@@ -270,6 +162,12 @@
 	uint step_height; ///< Step-size of height resize changes
 };
 
+enum SortButtonState {
+	SBS_OFF,
+	SBS_DOWN,
+	SBS_UP,
+};
+
 /**
  * Data structure for a window viewport
  */
@@ -281,23 +179,24 @@
 	int32 dest_scrollpos_y;
 };
 
-	/**
+/**
  * Data structure for an opened window
  */
 struct Window : ZeroedMemoryAllocator {
-private:
-	WindowProc *wndproc;   ///< Event handler function for the window. Do not use directly, call HandleWindowEvent() instead.
-	void HandleWindowEvent(WindowEvent *e);
+	enum EventState {
+		ES_HANDLED,
+		ES_NOT_HANDLED,
+	};
 
 protected:
 	void Initialize(int x, int y, int min_width, int min_height,
-			WindowProc *proc, WindowClass cls, const Widget *widget, int window_number, void *data);
+			WindowClass cls, const Widget *widget, int window_number);
 	void FindWindowPlacementAndResize(int def_width, int def_height);
 	void FindWindowPlacementAndResize(const WindowDesc *desc);
 
 public:
-	Window(int x, int y, int width, int height, WindowProc *proc, WindowClass cls, const Widget *widget, void *data = NULL);
-	Window(const WindowDesc *desc, void *data = NULL, WindowNumber number = 0);
+	Window(int x, int y, int width, int height, WindowClass cls, const Widget *widget);
+	Window(const WindowDesc *desc, WindowNumber number = 0);
 
 	virtual ~Window();
 
@@ -318,13 +217,11 @@
 	byte caption_color; ///< Background color of the window caption, contains PlayerID
 
 	ViewportData *viewport;      ///< Pointer to viewport data, if present
-	const Widget *original_widget; ///< Original widget layout, copied from WindowDesc
 	Widget *widget;        ///< Widgets of the window
 	uint widget_count;     ///< Number of widgets of the window
 	uint32 desc_flags;     ///< Window/widgets default flags setting, @see WindowDefaultFlag
 
 	Window *parent;        ///< Parent window
-	byte custom[WINDOW_CUSTOM_SIZE]; ///< Additional data depending on window type
 
 	void HandleButtonClick(byte widget);
 
@@ -348,6 +245,10 @@
 	void CDECL SetWidgetsLoweredState(bool lowered_stat, int widgets, ...);
 	void InvalidateWidget(byte widget_index) const;
 
+	void DrawWidgets() const;
+	void DrawViewport() const;
+	void DrawSortButtonState(int widget, SortButtonState state) const;
+
 	void SetDirty() const;
 
 	/*** Event handling ***/
@@ -355,24 +256,24 @@
 	/**
 	 * This window is currently being repainted.
 	 */
-	virtual void OnPaint();
+	virtual void OnPaint() {}
 
 
 	/**
 	 * A key has been pressed.
 	 * @param key     the Unicode value of the key.
 	 * @param keycode the untranslated key code including shift state.
-	 * @return true if the key press has been handled and no other
+	 * @return ES_HANDLED if the key press has been handled and no other
 	 *         window should receive the event.
 	 */
-	virtual bool OnKeyPress(uint16 key, uint16 keycode);
+	virtual EventState OnKeyPress(uint16 key, uint16 keycode) { return ES_NOT_HANDLED; }
 
 	/**
 	 * The state of the control key has changed
-	 * @return true if the change has been handled and no other
+	 * @return ES_HANDLED if the change has been handled and no other
 	 *         window should receive the event.
 	 */
-	virtual bool OnCTRLStateChange();
+	virtual EventState OnCTRLStateChange() { return ES_NOT_HANDLED; }
 
 
 	/**
@@ -380,34 +281,34 @@
 	 * @param pt     the point inside the window that has been clicked.
 	 * @param widget the clicked widget.
 	 */
-	virtual void OnClick(Point pt, int widget);
+	virtual void OnClick(Point pt, int widget) {}
 
 	/**
 	 * A double click with the left mouse button has been made on the window.
 	 * @param pt     the point inside the window that has been clicked.
 	 * @param widget the clicked widget.
 	 */
-	virtual void OnDoubleClick(Point pt, int widget);
+	virtual void OnDoubleClick(Point pt, int widget) {}
 
 	/**
 	 * A click with the right mouse button has been made on the window.
 	 * @param pt     the point inside the window that has been clicked.
 	 * @param widget the clicked widget.
 	 */
-	virtual void OnRightClick(Point pt, int widget);
+	virtual void OnRightClick(Point pt, int widget) {}
 
 	/**
 	 * A dragged 'object' has been released.
 	 * @param pt     the point inside the window where the release took place.
 	 * @param widget the widget where the release took place.
 	 */
-	virtual void OnDragDrop(Point pt, int widget);
+	virtual void OnDragDrop(Point pt, int widget) {}
 
 	/**
 	 * Handle the request for (viewport) scrolling.
 	 * @param delta the amount the viewport must be scrolled.
 	 */
-	virtual void OnScroll(Point delta);
+	virtual void OnScroll(Point delta) {}
 
 	/**
 	 * The mouse is currently moving over the window or has just moved outside
@@ -415,34 +316,34 @@
 	 * @param pt     the point inside the window that the mouse hovers over.
 	 * @param widget the widget the mouse hovers over.
 	 */
-	virtual void OnMouseOver(Point pt, int widget);
+	virtual void OnMouseOver(Point pt, int widget) {}
 
 	/**
 	 * The mouse wheel has been turned.
 	 * @param wheel the amount of movement of the mouse wheel.
 	 */
-	virtual void OnMouseWheel(int wheel);
+	virtual void OnMouseWheel(int wheel) {}
 
 
 	/**
 	 * Called for every mouse loop run, which is at least once per (game) tick.
 	 */
-	virtual void OnMouseLoop();
+	virtual void OnMouseLoop() {}
 
 	/**
 	 * Called once per (game) tick.
 	 */
-	virtual void OnTick();
+	virtual void OnTick() {}
 
 	/**
 	 * Called once every 100 (game) ticks.
 	 */
-	virtual void OnHundredthTick();
+	virtual void OnHundredthTick() {}
 
 	/**
 	 * Called when this window's timeout has been reached.
 	 */
-	virtual void OnTimeout();
+	virtual void OnTimeout() {}
 
 
 	/**
@@ -450,27 +351,27 @@
 	 * @param new_size the new size of the window.
 	 * @param delta    the amount of which the window size changed.
 	 */
-	virtual void OnResize(Point new_size, Point delta);
+	virtual void OnResize(Point new_size, Point delta) {}
 
 	/**
 	 * A dropdown option associated to this window has been selected.
 	 * @param widget the widget (button) that the dropdown is associated with.
 	 * @param index  the element in the dropdown that is selected.
 	 */
-	virtual void OnDropdownSelect(int widget, int index);
+	virtual void OnDropdownSelect(int widget, int index) {}
 
 	/**
 	 * The query window opened from this window has closed.
 	 * @param str the new value of the string or NULL if the window
 	 *            was cancelled.
 	 */
-	virtual void OnQueryTextFinished(char *str);
+	virtual void OnQueryTextFinished(char *str) {}
 
 	/**
 	 * Some data on this window has become invalid.
 	 * @param data information about the changed data.
 	 */
-	virtual void OnInvalidateData(int data = 0);
+	virtual void OnInvalidateData(int data = 0) {}
 
 
 	/**
@@ -479,12 +380,12 @@
 	 * @param pt   the exact point on the map that has been clicked.
 	 * @param tile the tile on the map that has been clicked.
 	 */
-	virtual void OnPlaceObject(Point pt, TileIndex tile);
+	virtual void OnPlaceObject(Point pt, TileIndex tile) {}
 
 	/**
 	 * The user cancelled a tile highlight mode that has been set.
 	 */
-	virtual void OnPlaceObjectAbort();
+	virtual void OnPlaceObjectAbort() {}
 
 
 	/**
@@ -494,7 +395,7 @@
 	 * @param select_proc   what will be created when the drag is over.
 	 * @param pt            the exact point on the map where the mouse is.
 	 */
-	virtual void OnPlaceDrag(ViewportPlaceMethod select_method, byte select_proc, Point pt);
+	virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) {}
 
 	/**
 	 * The user has dragged over the map when the tile highlight mode
@@ -505,7 +406,7 @@
 	 * @param start_tile    the begin tile of the drag.
 	 * @param end_tile      the end tile of the drag.
 	 */
-	virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, byte select_proc, Point pt, TileIndex start_tile, TileIndex end_tile);
+	virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) {}
 
 	/**
 	 * The user moves over the map when a tile highlight mode has been set
@@ -514,51 +415,20 @@
 	 * @param pt   the exact point on the map where the mouse is.
 	 * @param tile the tile on the map where the mouse is.
 	 */
-	virtual void OnPlacePresize(Point pt, TileIndex tile);
+	virtual void OnPlacePresize(Point pt, TileIndex tile) {}
 
 	/*** End of the event handling ***/
 };
 
-struct menu_d {
-	byte item_count;      ///< follow_vehicle
-	byte sel_index;       ///< scrollpos_x
-	byte main_button;     ///< scrollpos_y
-	byte action_id;
-	StringID string_id;   ///< unk30
-	uint16 checked_items; ///< unk32
-	byte disabled_items;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(menu_d));
-
-struct def_d {
-	int16 data_1, data_2, data_3;
-	int16 data_4, data_5;
-	bool close;
-	byte byte_1;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(def_d));
+/**
+ * Data structure for a window opened from a toolbar
+ */
+class PickerWindowBase : public Window {
 
-enum SortListFlags {
-	VL_NONE    = 0,      ///< no sort
-	VL_DESC    = 1 << 0, ///< sort descending or ascending
-	VL_RESORT  = 1 << 1, ///< instruct the code to resort the list in the next loop
-	VL_REBUILD = 1 << 2, ///< create sort-listing to use for qsort and friends
-	VL_END     = 1 << 3,
-};
-DECLARE_ENUM_AS_BIT_SET(SortListFlags);
+public:
+	PickerWindowBase(const WindowDesc *desc) : Window(desc) {}; // nothing special yet, just propagation
 
-struct Listing {
-	bool order;    ///< Ascending/descending
-	byte criteria; ///< Sorting criteria
-};
-
-template <typename T>
-struct GUIList {
-	T* sort_list;        ///< The items to sort.
-	SortListFlags flags; ///< used to control sorting/resorting/etc.
-	uint16 list_length;  ///< length of the list being sorted
-	uint16 resort_timer; ///< resort list after a given amount of ticks if set
-	byte sort_type;      ///< what criteria to sort on
+	virtual ~PickerWindowBase();
 };
 
 /****************** THESE ARE NOT WIDGET TYPES!!!!! *******************/
@@ -632,8 +502,6 @@
 Window *BringWindowToFrontById(WindowClass cls, WindowNumber number);
 Window *FindWindowFromPt(int x, int y);
 
-bool IsWindowOfPrototype(const Window *w, const Widget *widget);
-
 /**
  * Open a new window.
  * @param *desc The pointer to the WindowDesc to be created
@@ -642,14 +510,12 @@
  * @return see Window pointer of the newly created window
  */
 template <typename Wcls>
-Wcls *AllocateWindowDescFront(const WindowDesc *desc, int window_number, void *data = NULL)
+Wcls *AllocateWindowDescFront(const WindowDesc *desc, int window_number)
 {
 	if (BringWindowToFrontById(desc->cls, window_number)) return NULL;
-	return new Wcls(desc, data, window_number);
+	return new Wcls(desc, window_number);
 }
 
-void DrawWindowViewport(const Window *w);
-
 void RelocateAllWindows(int neww, int newh);
 
 /* misc_gui.cpp */
@@ -661,17 +527,6 @@
 
 /* widget.cpp */
 int GetWidgetFromPos(const Window *w, int x, int y);
-void DrawWindowWidgets(const Window *w);
-
-enum SortButtonState {
-	SBS_OFF,
-	SBS_DOWN,
-	SBS_UP,
-};
-
-void DrawSortButtonState(const Window *w, int widget, SortButtonState state);
-
-
 
 /* window.cpp */
 extern Window *_z_windows[];
--- a/src/window_type.h	Mon May 19 14:14:33 2008 +0000
+++ b/src/window_type.h	Mon May 19 15:13:58 2008 +0000
@@ -94,17 +94,11 @@
 	WC_BUILD_SIGNAL,
 	WC_COMPANY_PASSWORD_WINDOW,
 	WC_OSK,
+
+	WC_INVALID = 0xFFFF
 };
 
 struct Window;
-struct WindowEvent;
 typedef int32 WindowNumber;
 
-/**
- * You cannot 100% reliably calculate the biggest custom struct as
- * the number of pointers in it and alignment will have a huge impact.
- * 96 is the largest window-size for 64-bit machines currently.
- */
-#define WINDOW_CUSTOM_SIZE 96
-
 #endif /* WINDOW_TYPE_H */
--- a/src/yapf/yapf_road.cpp	Mon May 19 14:14:33 2008 +0000
+++ b/src/yapf/yapf_road.cpp	Mon May 19 15:13:58 2008 +0000
@@ -88,7 +88,7 @@
 			if (v->current_order.IsType(OT_GOTO_STATION) && tile == v->dest_tile) break;
 
 			// stop if we have just entered the depot
-			if (IsRoadDepotTile(tile) && trackdir == DiagdirToDiagTrackdir(ReverseDiagDir(GetRoadDepotDirection(tile)))) {
+			if (IsRoadDepotTile(tile) && trackdir == DiagDirToDiagTrackdir(ReverseDiagDir(GetRoadDepotDirection(tile)))) {
 				// next time we will reverse and leave the depot
 				break;
 			}
@@ -264,7 +264,7 @@
 		// handle special case - when next tile is destination tile
 		if (tile == v->dest_tile) {
 			// choose diagonal trackdir reachable from enterdir
-			return (Trackdir)DiagdirToDiagTrackdir(enterdir);
+			return DiagDirToDiagTrackdir(enterdir);
 		}
 		// our source tile will be the next vehicle tile (should be the given one)
 		TileIndex src_tile = tile;