File diff r10498:bb2b452f76fe → r10499:570896340d7a
src/rail_gui.cpp
Show inline comments
 
@@ -37,281 +37,282 @@
 
#include "rail_map.h"
 
#include "road_map.h"
 
#include "station_map.h"
 
#include "tunnel_map.h"
 
#include "tunnelbridge_map.h"
 

	
 
#include "table/sprites.h"
 
#include "table/strings.h"
 

	
 
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)
 

	
 
/* Map _patches.default_signal_type to the corresponding signal type */
 
static const SignalType _default_signal_type[] = {SIGTYPE_NORMAL, SIGTYPE_PBS, SIGTYPE_PBS_ONEWAY};
 

	
 
struct RailStationGUISettings {
 
	Axis 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;                 ///< 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 )
 
};
 
static RailStationGUISettings _railstation; ///< Settings of the station builder GUI
 

	
 

	
 
static void HandleStationPlacement(TileIndex start, TileIndex end);
 
static void ShowBuildTrainDepotPicker(Window *parent);
 
static void ShowBuildWaypointPicker(Window *parent);
 
static void ShowStationBuilder(Window *parent);
 
static void ShowSignalBuilder(Window *parent);
 

	
 
void CcPlaySound1E(bool success, TileIndex tile, uint32 p1, uint32 p2)
 
{
 
	if (success) SndPlayTileFx(SND_20_SPLAT_2, tile);
 
}
 

	
 
static void GenericPlaceRail(TileIndex tile, int cmd)
 
{
 
	DoCommandP(tile, _cur_railtype, cmd, CcPlaySound1E,
 
	DoCommandP(tile, _cur_railtype, cmd,
 
		_remove_button_clicked ?
 
		CMD_REMOVE_SINGLE_RAIL | CMD_MSG(STR_1012_CAN_T_REMOVE_RAILROAD_TRACK) | CMD_NO_WATER :
 
		CMD_BUILD_SINGLE_RAIL | CMD_MSG(STR_1011_CAN_T_BUILD_RAILROAD_TRACK) | CMD_NO_WATER
 
		CMD_BUILD_SINGLE_RAIL | CMD_MSG(STR_1011_CAN_T_BUILD_RAILROAD_TRACK) | CMD_NO_WATER,
 
		CcPlaySound1E
 
	);
 
}
 

	
 
static void PlaceRail_N(TileIndex tile)
 
{
 
	int cmd = _tile_fract_coords.x > _tile_fract_coords.y ? 4 : 5;
 
	GenericPlaceRail(tile, cmd);
 
}
 

	
 
static void PlaceRail_NE(TileIndex tile)
 
{
 
	VpStartPlaceSizing(tile, VPM_FIX_Y, DDSP_PLACE_RAIL_NE);
 
}
 

	
 
static void PlaceRail_E(TileIndex tile)
 
{
 
	int cmd = _tile_fract_coords.x + _tile_fract_coords.y <= 15 ? 2 : 3;
 
	GenericPlaceRail(tile, cmd);
 
}
 

	
 
static void PlaceRail_NW(TileIndex tile)
 
{
 
	VpStartPlaceSizing(tile, VPM_FIX_X, DDSP_PLACE_RAIL_NW);
 
}
 

	
 
static void PlaceRail_AutoRail(TileIndex tile)
 
{
 
	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;
 
	if ((GetTrackBits(tile) & GB(extra, 8, 8)) == 0) return;
 

	
 
	DoCommandP(tile, _cur_railtype, extra & 0xFF, NULL, CMD_BUILD_SINGLE_RAIL | CMD_NO_WATER);
 
	DoCommandP(tile, _cur_railtype, extra & 0xFF, 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,  // First additional track for directions 0..3
 
	0x2400, 0x2801, 0x1800, 0x1401,  // Second additional track
 
	0x2203, 0x0904, 0x0A05, 0x1103,  // Third additional track
 
};
 

	
 

	
 
void CcRailDepot(bool success, TileIndex tile, uint32 p1, uint32 p2)
 
{
 
	if (success) {
 
		DiagDirection dir = (DiagDirection)p2;
 

	
 
		SndPlayTileFx(SND_20_SPLAT_2, tile);
 
		ResetObjectToPlace();
 

	
 
		tile += TileOffsByDiagDir(dir);
 

	
 
		if (IsTileType(tile, MP_RAILWAY)) {
 
			PlaceExtraDepotRail(tile, _place_depot_extra[dir]);
 
			PlaceExtraDepotRail(tile, _place_depot_extra[dir + 4]);
 
			PlaceExtraDepotRail(tile, _place_depot_extra[dir + 8]);
 
		}
 
	}
 
}
 

	
 
static void PlaceRail_Depot(TileIndex tile)
 
{
 
	DoCommandP(tile, _cur_railtype, _build_depot_direction, CcRailDepot,
 
		CMD_BUILD_TRAIN_DEPOT | CMD_NO_WATER | CMD_MSG(STR_100E_CAN_T_BUILD_TRAIN_DEPOT));
 
	DoCommandP(tile, _cur_railtype, _build_depot_direction,
 
		CMD_BUILD_TRAIN_DEPOT | CMD_NO_WATER | CMD_MSG(STR_100E_CAN_T_BUILD_TRAIN_DEPOT),
 
		CcRailDepot);
 
}
 

	
 
static void PlaceRail_Waypoint(TileIndex tile)
 
{
 
	if (_remove_button_clicked) {
 
		DoCommandP(tile, 0, 0, CcPlaySound1E, CMD_REMOVE_TRAIN_WAYPOINT | CMD_MSG(STR_CANT_REMOVE_TRAIN_WAYPOINT));
 
		DoCommandP(tile, 0, 0, CMD_REMOVE_TRAIN_WAYPOINT | CMD_MSG(STR_CANT_REMOVE_TRAIN_WAYPOINT), CcPlaySound1E);
 
	} else {
 
		DoCommandP(tile, _cur_waypoint_type, 0, CcPlaySound1E, CMD_BUILD_TRAIN_WAYPOINT | CMD_MSG(STR_CANT_BUILD_TRAIN_WAYPOINT));
 
		DoCommandP(tile, _cur_waypoint_type, 0, CMD_BUILD_TRAIN_WAYPOINT | CMD_MSG(STR_CANT_BUILD_TRAIN_WAYPOINT), CcPlaySound1E);
 
	}
 
}
 

	
 
void CcStation(bool success, TileIndex tile, uint32 p1, uint32 p2)
 
{
 
	if (success) {
 
		SndPlayTileFx(SND_20_SPLAT_2, tile);
 
		/* Only close the station builder window if the default station is chosen. */
 
		if (_railstation.station_class == STAT_CLASS_DFLT && _railstation.station_type == 0) ResetObjectToPlace();
 
	}
 
}
 

	
 
static void PlaceRail_Station(TileIndex tile)
 
{
 
	if (_remove_button_clicked) {
 
		VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_REMOVE_STATION);
 
		VpSetPlaceSizingLimit(-1);
 
	} else if (_railstation.dragdrop) {
 
		VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_STATION);
 
		VpSetPlaceSizingLimit(_settings_game.station.station_spread);
 
	} else {
 
		DoCommandP(tile,
 
				_railstation.orientation | (_railstation.numtracks << 8) | (_railstation.platlength << 16) | (_ctrl_pressed << 24),
 
				_cur_railtype | (_railstation.station_class << 8) | (_railstation.station_type << 16), CcStation,
 
				CMD_BUILD_RAILROAD_STATION | CMD_NO_WATER | CMD_MSG(STR_100F_CAN_T_BUILD_RAILROAD_STATION));
 
				_cur_railtype | (_railstation.station_class << 8) | (_railstation.station_type << 16),
 
				CMD_BUILD_RAILROAD_STATION | CMD_NO_WATER | CMD_MSG(STR_100F_CAN_T_BUILD_RAILROAD_STATION), CcStation);
 
	}
 
}
 

	
 
/**
 
 * Build a new signal or edit/remove a present signal, use CmdBuildSingleSignal() or CmdRemoveSingleSignal() in rail_cmd.cpp
 
 *
 
 * @param tile The tile where the signal will build or edit
 
 */
 
static void GenericPlaceSignals(TileIndex tile)
 
{
 
	TrackBits trackbits = TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0));
 

	
 
	if (trackbits & TRACK_BIT_VERT) { // N-S direction
 
		trackbits = (_tile_fract_coords.x <= _tile_fract_coords.y) ? TRACK_BIT_RIGHT : TRACK_BIT_LEFT;
 
	}
 

	
 
	if (trackbits & TRACK_BIT_HORZ) { // E-W direction
 
		trackbits = (_tile_fract_coords.x + _tile_fract_coords.y <= 15) ? TRACK_BIT_UPPER : TRACK_BIT_LOWER;
 
	}
 

	
 
	Track track = FindFirstTrack(trackbits);
 

	
 
	if (_remove_button_clicked) {
 
		DoCommandP(tile, track, 0, CcPlaySound1E,
 
			CMD_REMOVE_SIGNALS | CMD_MSG(STR_1013_CAN_T_REMOVE_SIGNALS_FROM));
 
		DoCommandP(tile, track, 0, CMD_REMOVE_SIGNALS | CMD_MSG(STR_1013_CAN_T_REMOVE_SIGNALS_FROM), CcPlaySound1E);
 
	} else {
 
		const Window *w = FindWindowById(WC_BUILD_SIGNAL, 0);
 

	
 
		/* Map _patches.cycle_signal_types to the lower and upper allowed signal type. */
 
		static const uint cycle_bounds[] = {SIGTYPE_NORMAL | (SIGTYPE_LAST_NOPBS << 3), SIGTYPE_PBS | (SIGTYPE_LAST << 3), SIGTYPE_NORMAL | (SIGTYPE_LAST << 3)};
 

	
 
		/* various bitstuffed elements for CmdBuildSingleSignal() */
 
		uint32 p1 = track;
 

	
 
		if (w != NULL) {
 
			/* signal GUI is used */
 
			SB(p1, 3, 1, _ctrl_pressed);
 
			SB(p1, 4, 1, _cur_signal_variant);
 
			SB(p1, 5, 3, _cur_signal_type);
 
			SB(p1, 8, 1, _convert_signal_button);
 
			SB(p1, 9, 6, cycle_bounds[_settings_client.gui.cycle_signal_types]);
 
		} else {
 
			SB(p1, 3, 1, _ctrl_pressed);
 
			SB(p1, 4, 1, (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC));
 
			SB(p1, 5, 3, _default_signal_type[_settings_client.gui.default_signal_type]);
 
			SB(p1, 8, 1, 0);
 
			SB(p1, 9, 6, cycle_bounds[_settings_client.gui.cycle_signal_types]);
 
		}
 

	
 
		DoCommandP(tile, p1, 0, CcPlaySound1E, CMD_BUILD_SIGNALS |
 
			CMD_MSG((w != NULL && _convert_signal_button) ? STR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE : STR_1010_CAN_T_BUILD_SIGNALS_HERE));
 
		DoCommandP(tile, p1, 0, CMD_BUILD_SIGNALS |
 
			CMD_MSG((w != NULL && _convert_signal_button) ? STR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE : STR_1010_CAN_T_BUILD_SIGNALS_HERE),
 
			CcPlaySound1E);
 
	}
 
}
 

	
 
static void PlaceRail_Bridge(TileIndex tile)
 
{
 
	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) {
 
		SndPlayTileFx(SND_20_SPLAT_2, tile);
 
		ResetObjectToPlace();
 
	} else {
 
		SetRedErrorSquare(_build_tunnel_endtile);
 
	}
 
}
 

	
 
static void PlaceRail_Tunnel(TileIndex tile)
 
{
 
	DoCommandP(tile, _cur_railtype, 0, CcBuildRailTunnel,
 
		CMD_BUILD_TUNNEL | CMD_MSG(STR_5016_CAN_T_BUILD_TUNNEL_HERE));
 
	DoCommandP(tile, _cur_railtype, 0, CMD_BUILD_TUNNEL | CMD_MSG(STR_5016_CAN_T_BUILD_TUNNEL_HERE), CcBuildRailTunnel);
 
}
 

	
 
static void PlaceRail_ConvertRail(TileIndex tile)
 
{
 
	VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CONVERT_RAIL);
 
}
 

	
 
static void PlaceRail_AutoSignals(TileIndex tile)
 
{
 
	VpStartPlaceSizing(tile, VPM_SIGNALDIRS, DDSP_BUILD_SIGNALS);
 
}
 

	
 

	
 
/** Enum referring to the widgets of the build rail toolbar */
 
enum RailToolbarWidgets {
 
	RTW_CLOSEBOX = 0,
 
	RTW_CAPTION,
 
	RTW_STICKY,
 
	RTW_SPACER,
 
	RTW_BUILD_NS,
 
	RTW_BUILD_X,
 
	RTW_BUILD_EW,
 
	RTW_BUILD_Y,
 
	RTW_AUTORAIL,
 
	RTW_DEMOLISH,
 
	RTW_BUILD_DEPOT,
 
	RTW_BUILD_WAYPOINT,
 
	RTW_BUILD_STATION,
 
	RTW_BUILD_SIGNALS,
 
	RTW_BUILD_BRIDGE,
 
	RTW_BUILD_TUNNEL,
 
	RTW_REMOVE,
 
	RTW_CONVERT_RAIL,
 
};
 

	
 

	
 
/** Toggles state of the Remove button of Build rail toolbar
 
 * @param w window the button belongs to
 
 */
 
static void ToggleRailButton_Remove(Window *w)
 
{
 
	w->ToggleWidgetLoweredState(RTW_REMOVE);
 
	w->InvalidateWidget(RTW_REMOVE);
 
	_remove_button_clicked = w->IsWidgetLowered(RTW_REMOVE);
 
	SetSelectionRed(_remove_button_clicked);
 
}
 

	
 
/** Updates the Remove button because of Ctrl state change
 
@@ -469,160 +470,159 @@ static void BuildRailClick_Tunnel(Window
 
/**
 
 * 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;
 
	ToggleRailButton_Remove(w);
 
	SndPlayFx(SND_15_BEEP);
 

	
 
	/* handle station builder */
 
	if (w->IsWidgetLowered(RTW_BUILD_STATION)) {
 
		if (_remove_button_clicked) {
 
			/* starting drag & drop remove */
 
			if (!_railstation.dragdrop) {
 
				SetTileSelectSize(1, 1);
 
			} else {
 
				VpSetPlaceSizingLimit(-1);
 
			}
 
		} else {
 
			/* starting station build mode */
 
			if (!_railstation.dragdrop) {
 
				int x = _railstation.numtracks;
 
				int y = _railstation.platlength;
 
				if (_railstation.orientation == 0) Swap(x, y);
 
				SetTileSelectSize(x, y);
 
			} else {
 
				VpSetPlaceSizingLimit(_settings_game.station.station_spread);
 
			}
 
		}
 
	}
 
}
 

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

	
 

	
 
static void DoRailroadTrack(int mode)
 
{
 
	DoCommandP(TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), _cur_railtype | (mode << 4), NULL,
 
	DoCommandP(TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), _cur_railtype | (mode << 4),
 
		_remove_button_clicked ?
 
		CMD_REMOVE_RAILROAD_TRACK | CMD_NO_WATER | CMD_MSG(STR_1012_CAN_T_REMOVE_RAILROAD_TRACK) :
 
		CMD_BUILD_RAILROAD_TRACK  | CMD_NO_WATER | CMD_MSG(STR_1011_CAN_T_BUILD_RAILROAD_TRACK)
 
	);
 
}
 

	
 
static void HandleAutodirPlacement()
 
{
 
	TileHighlightData *thd = &_thd;
 
	int trackstat = thd->drawstyle & 0xF; // 0..5
 

	
 
	if (thd->drawstyle & HT_RAIL) { // one tile case
 
		GenericPlaceRail(TileVirtXY(thd->selend.x, thd->selend.y), trackstat);
 
		return;
 
	}
 

	
 
	DoRailroadTrack(trackstat);
 
}
 

	
 
/**
 
 * Build new signals or remove signals or (if only one tile marked) edit a signal.
 
 *
 
 * If one tile marked abort and use GenericPlaceSignals()
 
 * else use CmdBuildSingleSignal() or CmdRemoveSingleSignal() in rail_cmd.cpp to build many signals
 
 */
 
static void HandleAutoSignalPlacement()
 
{
 
	TileHighlightData *thd = &_thd;
 
	uint32 p2 = GB(thd->drawstyle, 0, 3); // 0..5
 

	
 
	if (thd->drawstyle == HT_RECT) { // one tile case
 
		GenericPlaceSignals(TileVirtXY(thd->selend.x, thd->selend.y));
 
		return;
 
	}
 

	
 
	const Window *w = FindWindowById(WC_BUILD_SIGNAL, 0);
 

	
 
	if (w != NULL) {
 
		/* signal GUI is used */
 
		SB(p2,  3, 1, 0);
 
		SB(p2,  4, 1, _cur_signal_variant);
 
		SB(p2,  6, 1, _ctrl_pressed);
 
		SB(p2,  7, 3, _cur_signal_type);
 
		SB(p2, 24, 8, _settings_client.gui.drag_signals_density);
 
	} else {
 
		SB(p2,  3, 1, 0);
 
		SB(p2,  4, 1, (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC));
 
		SB(p2,  6, 1, _ctrl_pressed);
 
		SB(p2,  7, 3, _default_signal_type[_settings_client.gui.default_signal_type]);
 
		SB(p2, 24, 8, _settings_client.gui.drag_signals_density);
 
	}
 

	
 
	/* _settings_client.gui.drag_signals_density is given as a parameter such that each user
 
	 * in a network game can specify his/her own signal density */
 
	DoCommandP(
 
		TileVirtXY(thd->selstart.x, thd->selstart.y),
 
		TileVirtXY(thd->selend.x, thd->selend.y),
 
		p2,
 
		CcPlaySound1E,
 
		_remove_button_clicked ?
 
			CMD_REMOVE_SIGNAL_TRACK | CMD_NO_WATER | CMD_MSG(STR_1013_CAN_T_REMOVE_SIGNALS_FROM) :
 
			CMD_BUILD_SIGNAL_TRACK  | CMD_NO_WATER | CMD_MSG(STR_1010_CAN_T_BUILD_SIGNALS_HERE)
 
	);
 
			CMD_BUILD_SIGNAL_TRACK  | CMD_NO_WATER | CMD_MSG(STR_1010_CAN_T_BUILD_SIGNALS_HERE),
 
		CcPlaySound1E);
 
}
 

	
 

	
 
typedef void OnButtonClick(Window *w);
 

	
 
/** Data associated with a push button in the build rail toolbar window */
 
struct RailBuildingGUIButtonData {
 
	uint16 keycode;            ///< Keycode associated with the button
 
	OnButtonClick *click_proc; ///< Procedure to call when button is clicked
 
};
 

	
 
/**
 
 * GUI rail-building button data constants.
 
 * Offsets match widget order, starting at RTW_BUILD_NS
 
 */
 
static const RailBuildingGUIButtonData _rail_build_button_data[] = {
 
	{'1', BuildRailClick_N          },
 
	{'2', BuildRailClick_NE         },
 
	{'3', BuildRailClick_E          },
 
	{'4', BuildRailClick_NW         },
 
	{'5', BuildRailClick_AutoRail   },
 
	{'6', BuildRailClick_Demolish   },
 
	{'7', BuildRailClick_Depot      },
 
	{'8', BuildRailClick_Waypoint   },
 
	{'9', BuildRailClick_Station    },
 
	{'S', BuildRailClick_AutoSignals},
 
	{'B', BuildRailClick_Bridge     },
 
	{'T', BuildRailClick_Tunnel     },
 
	{'R', BuildRailClick_Remove     },
 
	{'C', BuildRailClick_Convert    }
 
};
 

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

	
 
		this->FindWindowPlacementAndResize(desc);
 
		if (_settings_client.gui.link_terraform_toolbar) ShowTerraformToolbar(this);
 
	}
 

	
 
	~BuildRailToolbarWindow()
 
	{
 
@@ -682,103 +682,103 @@ struct BuildRailToolbarWindow : Window {
 
				_remove_button_clicked = false;
 
				_rail_build_button_data[i].click_proc(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
 
		return state;
 
	}
 

	
 
	virtual void OnPlaceObject(Point pt, TileIndex tile)
 
	{
 
		_place_proc(tile);
 
	}
 

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

	
 
				case DDSP_PLACE_AUTORAIL:
 
					HandleAutodirPlacement();
 
					break;
 

	
 
				case DDSP_BUILD_SIGNALS:
 
					HandleAutoSignalPlacement();
 
					break;
 

	
 
				case DDSP_DEMOLISH_AREA:
 
					GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
 
					break;
 

	
 
				case DDSP_CONVERT_RAIL:
 
					DoCommandP(end_tile, start_tile, _cur_railtype, CcPlaySound10, CMD_CONVERT_RAIL | CMD_MSG(STR_CANT_CONVERT_RAIL));
 
					DoCommandP(end_tile, start_tile, _cur_railtype, CMD_CONVERT_RAIL | CMD_MSG(STR_CANT_CONVERT_RAIL), CcPlaySound10);
 
					break;
 

	
 
				case DDSP_REMOVE_STATION:
 
				case DDSP_BUILD_STATION:
 
					if (_remove_button_clicked) {
 
						DoCommandP(end_tile, start_tile, 0, CcPlaySound1E, CMD_REMOVE_FROM_RAILROAD_STATION | CMD_MSG(STR_CANT_REMOVE_PART_OF_STATION));
 
						DoCommandP(end_tile, start_tile, 0, CMD_REMOVE_FROM_RAILROAD_STATION | CMD_MSG(STR_CANT_REMOVE_PART_OF_STATION), CcPlaySound1E);
 
						break;
 
					}
 
					HandleStationPlacement(start_tile, end_tile);
 
					break;
 

	
 
				case DDSP_PLACE_RAIL_NE:
 
				case DDSP_PLACE_RAIL_NW:
 
					DoRailroadTrack(select_proc == DDSP_PLACE_RAIL_NE ? TRACK_X : TRACK_Y);
 
					break;
 
			}
 
		}
 
	}
 

	
 
	virtual void OnPlaceObjectAbort()
 
	{
 
		this->RaiseButtons();
 
		this->DisableWidget(RTW_REMOVE);
 
		this->InvalidateWidget(RTW_REMOVE);
 

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

	
 
	virtual EventState OnCTRLStateChange()
 
	{
 
		/* do not toggle Remove button by Ctrl when placing station */
 
		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[] = {
 
{   WWT_CLOSEBOX,   RESIZE_NONE,  COLOUR_DARK_GREEN,     0,    10,     0,    13, STR_00C5,                       STR_018B_CLOSE_WINDOW},                   // RTW_CLOSEBOX
 
{    WWT_CAPTION,   RESIZE_NONE,  COLOUR_DARK_GREEN,    11,   337,     0,    13, STR_100A_RAILROAD_CONSTRUCTION, STR_018C_WINDOW_TITLE_DRAG_THIS},         // RTW_CAPTION
 
{  WWT_STICKYBOX,   RESIZE_NONE,  COLOUR_DARK_GREEN,   338,   349,     0,    13, 0x0,                            STR_STICKY_BUTTON},                       // RTW_STICKY
 

	
 
{      WWT_PANEL,   RESIZE_NONE,  COLOUR_DARK_GREEN,   110,   113,    14,    35, 0x0,                            STR_NULL},                                // RTW_SPACER
 

	
 
{     WWT_IMGBTN,   RESIZE_NONE,  COLOUR_DARK_GREEN,     0,    21,    14,    35, SPR_IMG_RAIL_NS,                STR_1018_BUILD_RAILROAD_TRACK},           // RTW_BUILD_NS
 
{     WWT_IMGBTN,   RESIZE_NONE,  COLOUR_DARK_GREEN,    22,    43,    14,    35, SPR_IMG_RAIL_NE,                STR_1018_BUILD_RAILROAD_TRACK},           // RTW_BUILD_X
 
@@ -835,98 +835,98 @@ static void SetupRailToolbar(RailType ra
 
 * 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)
 
{
 
	BuildRailToolbarWindow *w;
 

	
 
	if (!IsValidCompanyID(_current_company)) 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 = dynamic_cast<BuildRailToolbarWindow*>(FindWindowById(WC_BUILD_TOOLBAR, TRANSPORT_RAIL)))) {
 
		DeleteWindowByClass(WC_BUILD_TOOLBAR);
 
		_cur_railtype = railtype;
 
		w = AllocateWindowDescFront<BuildRailToolbarWindow>(&_build_rail_desc, TRANSPORT_RAIL);
 
		SetupRailToolbar(railtype, w);
 
	}
 

	
 
	_remove_button_clicked = false;
 
	if (w != NULL && button >= RTW_CLOSEBOX) {
 
		_rail_build_button_data[button].click_proc(w);
 
		w->UpdateRemoveWidgetStatus(button + RTW_BUILD_NS);
 
	}
 
}
 

	
 
/* TODO: For custom stations, respect their allowed platforms/lengths bitmasks!
 
 * --pasky */
 

	
 
static void HandleStationPlacement(TileIndex start, TileIndex end)
 
{
 
	uint sx = TileX(start);
 
	uint sy = TileY(start);
 
	uint ex = TileX(end);
 
	uint ey = TileY(end);
 
	uint w,h;
 

	
 
	if (sx > ex) Swap(sx, ex);
 
	if (sy > ey) Swap(sy, ey);
 
	w = ex - sx + 1;
 
	h = ey - sy + 1;
 
	if (_railstation.orientation == AXIS_X) Swap(w, h);
 

	
 
	DoCommandP(TileXY(sx, sy),
 
			_railstation.orientation | (w << 8) | (h << 16) | (_ctrl_pressed << 24),
 
			_cur_railtype | (_railstation.station_class << 8) | (_railstation.station_type << 16), CcStation,
 
			CMD_BUILD_RAILROAD_STATION | CMD_NO_WATER | CMD_MSG(STR_100F_CAN_T_BUILD_RAILROAD_STATION));
 
			_cur_railtype | (_railstation.station_class << 8) | (_railstation.station_type << 16),
 
			CMD_BUILD_RAILROAD_STATION | CMD_NO_WATER | CMD_MSG(STR_100F_CAN_T_BUILD_RAILROAD_STATION), CcStation);
 
}
 

	
 
struct BuildRailStationWindow : public PickerWindowBase {
 
private:
 
	/** 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
 
	};
 

	
 
	/**
 
	 * 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)
 
	{