# rail_gui.cpp

Go to the documentation of this file.

    00001 /* $Id: rail_gui.cpp 20261 2010-07-31 18:27:54Z rubidium $ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
    00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
    00008  */
    00009
    00012 #include "stdafx.h"
    00013 #include "gui.h"
    00014 #include "window_gui.h"
    00015 #include "station_gui.h"
    00016 #include "terraform_gui.h"
    00017 #include "viewport_func.h"
    00018 #include "command_func.h"
    00019 #include "waypoint_func.h"
    00020 #include "newgrf_station.h"
    00021 #include "company_base.h"
    00022 #include "strings_func.h"
    00023 #include "functions.h"
    00024 #include "window_func.h"
    00025 #include "date_func.h"
    00026 #include "sound_func.h"
    00027 #include "company_func.h"
    00028 #include "widgets/dropdown_type.h"
    00029 #include "tunnelbridge.h"
    00030 #include "tilehighlight_func.h"
    00031 #include "spritecache.h"
    00032 #include "core/geometry_func.hpp"
    00033
    00034 #include "station_map.h"
    00035 #include "tunnelbridge_map.h"
    00036
    00037 #include "table/sprites.h"
    00038 #include "table/strings.h"
    00039
    00040 static RailType _cur_railtype;
    00041 static bool _remove_button_clicked;
    00042 static DiagDirection _build_depot_direction;
    00043 static byte _waypoint_count = 1;
    00044 static byte _cur_waypoint_type;
    00045 static bool _convert_signal_button;
    00046 static SignalVariant _cur_signal_variant;
    00047 static SignalType _cur_signal_type;
    00048
    00049 /* Map the setting: default_signal_type to the corresponding signal type */
    00050 static const SignalType _default_signal_type[] = {SIGTYPE_NORMAL, SIGTYPE_PBS, SIGTYPE_PBS_ONEWAY};
    00051
    00052 struct RailStationGUISettings {
    00053   Axis orientation;
    00054
    00055   bool newstations;
    00056   StationClassIDByte station_class;
    00057   byte station_type;
    00058   byte station_count;
    00059 };
    00060 static RailStationGUISettings _railstation;
    00061
    00062
    00063 static void HandleStationPlacement(TileIndex start, TileIndex end);
    00064 static void ShowBuildTrainDepotPicker(Window *parent);
    00065 static void ShowBuildWaypointPicker(Window *parent);
    00066 static void ShowStationBuilder(Window *parent);
    00067 static void ShowSignalBuilder(Window *parent);
    00068
    00069 void CcPlaySound1E(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
    00070 {
    00071   if (result.Succeeded()) SndPlayTileFx(SND_20_SPLAT_2, tile);
    00072 }
    00073
    00074 static void GenericPlaceRail(TileIndex tile, int cmd)
    00075 {
    00076   DoCommandP(tile, _cur_railtype, cmd,
    00077     _remove_button_clicked ?
    00078     CMD_REMOVE_SINGLE_RAIL | CMD_MSG(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK) :
    00079     CMD_BUILD_SINGLE_RAIL | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK),
    00080     CcPlaySound1E
    00081   );
    00082 }
    00083
    00084 static void PlaceRail_N(TileIndex tile)
    00085 {
    00086   VpStartPlaceSizing(tile, VPM_FIX_VERTICAL | VPM_RAILDIRS, DDSP_PLACE_RAIL);
    00087 }
    00088
    00089 static void PlaceRail_NE(TileIndex tile)
    00090 {
    00091   VpStartPlaceSizing(tile, VPM_FIX_Y | VPM_RAILDIRS, DDSP_PLACE_RAIL);
    00092 }
    00093
    00094 static void PlaceRail_E(TileIndex tile)
    00095 {
    00096   VpStartPlaceSizing(tile, VPM_FIX_HORIZONTAL | VPM_RAILDIRS, DDSP_PLACE_RAIL);
    00097 }
    00098
    00099 static void PlaceRail_NW(TileIndex tile)
    00100 {
    00101   VpStartPlaceSizing(tile, VPM_FIX_X | VPM_RAILDIRS, DDSP_PLACE_RAIL);
    00102 }
    00103
    00104 static void PlaceRail_AutoRail(TileIndex tile)
    00105 {
    00106   VpStartPlaceSizing(tile, VPM_RAILDIRS, DDSP_PLACE_RAIL);
    00107 }
    00108
    00115 static void PlaceExtraDepotRail(TileIndex tile, uint16 extra)
    00116 {
    00117   if (GetRailTileType(tile) != RAIL_TILE_NORMAL) return;
    00118   if ((GetTrackBits(tile) & GB(extra, 8, 8)) == 0) return;
    00119
    00120   DoCommandP(tile, _cur_railtype, extra & 0xFF, CMD_BUILD_SINGLE_RAIL);
    00121 }
    00122
    00124 static const uint16 _place_depot_extra[12] = {
    00125   0x0604, 0x2102, 0x1202, 0x0505,  // First additional track for directions 0..3
    00126   0x2400, 0x2801, 0x1800, 0x1401,  // Second additional track
    00127   0x2203, 0x0904, 0x0A05, 0x1103,  // Third additional track
    00128 };
    00129
    00130
    00131 void CcRailDepot(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
    00132 {
    00133   if (result.Failed()) return;
    00134
    00135   DiagDirection dir = (DiagDirection)p2;
    00136
    00137   SndPlayTileFx(SND_20_SPLAT_2, tile);
    00138   if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
    00139
    00140   tile += TileOffsByDiagDir(dir);
    00141
    00142   if (IsTileType(tile, MP_RAILWAY)) {
    00143     PlaceExtraDepotRail(tile, _place_depot_extra[dir]);
    00144     PlaceExtraDepotRail(tile, _place_depot_extra[dir + 4]);
    00145     PlaceExtraDepotRail(tile, _place_depot_extra[dir + 8]);
    00146   }
    00147 }
    00148
    00149 static void PlaceRail_Depot(TileIndex tile)
    00150 {
    00151   DoCommandP(tile, _cur_railtype, _build_depot_direction,
    00152     CMD_BUILD_TRAIN_DEPOT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT),
    00153     CcRailDepot);
    00154 }
    00155
    00156 static void PlaceRail_Waypoint(TileIndex tile)
    00157 {
    00158   if (_remove_button_clicked) {
    00159     VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_REMOVE_STATION);
    00160     return;
    00161   }
    00162
    00163   Axis axis = GetAxisForNewWaypoint(tile);
    00164   if (IsValidAxis(axis)) {
    00165     /* Valid tile for waypoints */
    00166     VpStartPlaceSizing(tile, axis == AXIS_X ? VPM_FIX_X : VPM_FIX_Y, DDSP_BUILD_STATION);
    00167   } else {
    00168     /* Tile where we can't build rail waypoints. This is always going to fail,
    00169      * but provides the user with a proper error message. */
    00170     DoCommandP(tile, 1 << 8 | 1 << 16, STAT_CLASS_WAYP | INVALID_STATION << 16, CMD_BUILD_RAIL_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT));
    00171   }
    00172 }
    00173
    00174 void CcStation(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
    00175 {
    00176   if (result.Failed()) return;
    00177
    00178   SndPlayTileFx(SND_20_SPLAT_2, tile);
    00179   /* Only close the station builder window if the default station and non persistent building is chosen. */
    00180   if (_railstation.station_class == STAT_CLASS_DFLT && _railstation.station_type == 0 && !_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
    00181 }
    00182
    00183 static void PlaceRail_Station(TileIndex tile)
    00184 {
    00185   if (_remove_button_clicked) {
    00186     VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_REMOVE_STATION);
    00187     VpSetPlaceSizingLimit(-1);
    00188   } else if (_settings_client.gui.station_dragdrop) {
    00189     VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_STATION);
    00190     VpSetPlaceSizingLimit(_settings_game.station.station_spread);
    00191   } else {
    00192     uint32 p1 = _cur_railtype | _railstation.orientation << 4 | _settings_client.gui.station_numtracks << 8 | _settings_client.gui.station_platlength << 16 | _ctrl_pressed << 24;
    00193     uint32 p2 = _railstation.station_class | _railstation.station_type << 8 | INVALID_STATION << 16;
    00194
    00195     int w = _settings_client.gui.station_numtracks;
    00196     int h = _settings_client.gui.station_platlength;
    00197     if (!_railstation.orientation) Swap(w, h);
    00198
    00199     CommandContainer cmdcont = { tile, p1, p2, CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION), CcStation, "" };
    00200     ShowSelectStationIfNeeded(cmdcont, TileArea(tile, w, h));
    00201   }
    00202 }
    00203
    00209 static void GenericPlaceSignals(TileIndex tile)
    00210 {
    00211   TrackBits trackbits = TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0));
    00212
    00213   if (trackbits & TRACK_BIT_VERT) { // N-S direction
    00214     trackbits = (_tile_fract_coords.x <= _tile_fract_coords.y) ? TRACK_BIT_RIGHT : TRACK_BIT_LEFT;
    00215   }
    00216
    00217   if (trackbits & TRACK_BIT_HORZ) { // E-W direction
    00218     trackbits = (_tile_fract_coords.x + _tile_fract_coords.y <= 15) ? TRACK_BIT_UPPER : TRACK_BIT_LOWER;
    00219   }
    00220
    00221   Track track = FindFirstTrack(trackbits);
    00222
    00223   if (_remove_button_clicked) {
    00224     DoCommandP(tile, track, 0, CMD_REMOVE_SIGNALS | CMD_MSG(STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM), CcPlaySound1E);
    00225   } else {
    00226     const Window *w = FindWindowById(WC_BUILD_SIGNAL, 0);
    00227
    00228     /* Map the setting cycle_signal_types to the lower and upper allowed signal type. */
    00229     static const uint cycle_bounds[] = {SIGTYPE_NORMAL | (SIGTYPE_LAST_NOPBS << 3), SIGTYPE_PBS | (SIGTYPE_LAST << 3), SIGTYPE_NORMAL | (SIGTYPE_LAST << 3)};
    00230
    00231     /* various bitstuffed elements for CmdBuildSingleSignal() */
    00232     uint32 p1 = track;
    00233
    00234     if (w != NULL) {
    00235       /* signal GUI is used */
    00236       SB(p1, 3, 1, _ctrl_pressed);
    00237       SB(p1, 4, 1, _cur_signal_variant);
    00238       SB(p1, 5, 3, _cur_signal_type);
    00239       SB(p1, 8, 1, _convert_signal_button);
    00240       SB(p1, 9, 6, cycle_bounds[_settings_client.gui.cycle_signal_types]);
    00241     } else {
    00242       SB(p1, 3, 1, _ctrl_pressed);
    00243       SB(p1, 4, 1, (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC));
    00244       SB(p1, 5, 3, _default_signal_type[_settings_client.gui.default_signal_type]);
    00245       SB(p1, 8, 1, 0);
    00246       SB(p1, 9, 6, cycle_bounds[_settings_client.gui.cycle_signal_types]);
    00247     }
    00248
    00249     DoCommandP(tile, p1, 0, CMD_BUILD_SIGNALS |
    00250       CMD_MSG((w != NULL && _convert_signal_button) ? STR_ERROR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE : STR_ERROR_CAN_T_BUILD_SIGNALS_HERE),
    00251       CcPlaySound1E);
    00252   }
    00253 }
    00254
    00255 static void PlaceRail_Bridge(TileIndex tile)
    00256 {
    00257   VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_BUILD_BRIDGE);
    00258 }
    00259
    00261 void CcBuildRailTunnel(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
    00262 {
    00263   if (result.Succeeded()) {
    00264     SndPlayTileFx(SND_20_SPLAT_2, tile);
    00265     if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
    00266   } else {
    00267     SetRedErrorSquare(_build_tunnel_endtile);
    00268   }
    00269 }
    00270
    00271 static void PlaceRail_Tunnel(TileIndex tile)
    00272 {
    00273   DoCommandP(tile, _cur_railtype | (TRANSPORT_RAIL << 8), 0, CMD_BUILD_TUNNEL | CMD_MSG(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE), CcBuildRailTunnel);
    00274 }
    00275
    00276 static void PlaceRail_ConvertRail(TileIndex tile)
    00277 {
    00278   VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_CONVERT_RAIL);
    00279 }
    00280
    00281 static void PlaceRail_AutoSignals(TileIndex tile)
    00282 {
    00283   VpStartPlaceSizing(tile, VPM_SIGNALDIRS, DDSP_BUILD_SIGNALS);
    00284 }
    00285
    00286
    00288 enum RailToolbarWidgets {
    00289   RTW_CAPTION,
    00290   RTW_BUILD_NS,
    00291   RTW_BUILD_X,
    00292   RTW_BUILD_EW,
    00293   RTW_BUILD_Y,
    00294   RTW_AUTORAIL,
    00295   RTW_DEMOLISH,
    00296   RTW_BUILD_DEPOT,
    00297   RTW_BUILD_WAYPOINT,
    00298   RTW_BUILD_STATION,
    00299   RTW_BUILD_SIGNALS,
    00300   RTW_BUILD_BRIDGE,
    00301   RTW_BUILD_TUNNEL,
    00302   RTW_REMOVE,
    00303   RTW_CONVERT_RAIL,
    00304 };
    00305
    00306
    00310 static void ToggleRailButton_Remove(Window *w)
    00311 {
    00312   DeleteWindowById(WC_SELECT_STATION, 0);
    00313   w->ToggleWidgetLoweredState(RTW_REMOVE);
    00314   w->SetWidgetDirty(RTW_REMOVE);
    00315   _remove_button_clicked = w->IsWidgetLowered(RTW_REMOVE);
    00316   SetSelectionRed(_remove_button_clicked);
    00317 }
    00318
    00323 static bool RailToolbar_CtrlChanged(Window *w)
    00324 {
    00325   if (w->IsWidgetDisabled(RTW_REMOVE)) return false;
    00326
    00327   /* allow ctrl to switch remove mode only for these widgets */
    00328   for (uint i = RTW_BUILD_NS; i <= RTW_BUILD_STATION; i++) {
    00329     if ((i <= RTW_AUTORAIL || i >= RTW_BUILD_WAYPOINT) && w->IsWidgetLowered(i)) {
    00330       ToggleRailButton_Remove(w);
    00331       return true;
    00332     }
    00333   }
    00334
    00335   return false;
    00336 }
    00337
    00338
    00344 static void BuildRailClick_N(Window *w)
    00345 {
    00346   HandlePlacePushButton(w, RTW_BUILD_NS, GetRailTypeInfo(_cur_railtype)->cursor.rail_ns, HT_LINE | HT_DIR_VL, PlaceRail_N);
    00347 }
    00348
    00354 static void BuildRailClick_NE(Window *w)
    00355 {
    00356   HandlePlacePushButton(w, RTW_BUILD_X, GetRailTypeInfo(_cur_railtype)->cursor.rail_swne, HT_LINE | HT_DIR_X, PlaceRail_NE);
    00357 }
    00358
    00364 static void BuildRailClick_E(Window *w)
    00365 {
    00366   HandlePlacePushButton(w, RTW_BUILD_EW, GetRailTypeInfo(_cur_railtype)->cursor.rail_ew, HT_LINE | HT_DIR_HL, PlaceRail_E);
    00367 }
    00368
    00374 static void BuildRailClick_NW(Window *w)
    00375 {
    00376   HandlePlacePushButton(w, RTW_BUILD_Y, GetRailTypeInfo(_cur_railtype)->cursor.rail_nwse, HT_LINE | HT_DIR_Y, PlaceRail_NW);
    00377 }
    00378
    00384 static void BuildRailClick_AutoRail(Window *w)
    00385 {
    00386   HandlePlacePushButton(w, RTW_AUTORAIL, GetRailTypeInfo(_cur_railtype)->cursor.autorail, HT_RAIL, PlaceRail_AutoRail);
    00387 }
    00388
    00394 static void BuildRailClick_Demolish(Window *w)
    00395 {
    00396   HandlePlacePushButton(w, RTW_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT, PlaceProc_DemolishArea);
    00397 }
    00398
    00404 static void BuildRailClick_Depot(Window *w)
    00405 {
    00406   if (HandlePlacePushButton(w, RTW_BUILD_DEPOT, GetRailTypeInfo(_cur_railtype)->cursor.depot, HT_RECT, PlaceRail_Depot)) {
    00407     ShowBuildTrainDepotPicker(w);
    00408   }
    00409 }
    00410
    00417 static void BuildRailClick_Waypoint(Window *w)
    00418 {
    00419   _waypoint_count = GetNumCustomStations(STAT_CLASS_WAYP);
    00420   if (HandlePlacePushButton(w, RTW_BUILD_WAYPOINT, SPR_CURSOR_WAYPOINT, HT_RECT, PlaceRail_Waypoint) &&
    00421       _waypoint_count > 1) {
    00422     ShowBuildWaypointPicker(w);
    00423   }
    00424 }
    00425
    00431 static void BuildRailClick_Station(Window *w)
    00432 {
    00433   if (HandlePlacePushButton(w, RTW_BUILD_STATION, SPR_CURSOR_RAIL_STATION, HT_RECT, PlaceRail_Station)) ShowStationBuilder(w);
    00434 }
    00435
    00442 static void BuildRailClick_AutoSignals(Window *w)
    00443 {
    00444   if (_settings_client.gui.enable_signal_gui != _ctrl_pressed) {
    00445     if (HandlePlacePushButton(w, RTW_BUILD_SIGNALS, ANIMCURSOR_BUILDSIGNALS, HT_RECT, PlaceRail_AutoSignals)) ShowSignalBuilder(w);
    00446   } else {
    00447     HandlePlacePushButton(w, RTW_BUILD_SIGNALS, ANIMCURSOR_BUILDSIGNALS, HT_RECT, PlaceRail_AutoSignals);
    00448   }
    00449 }
    00450
    00456 static void BuildRailClick_Bridge(Window *w)
    00457 {
    00458   HandlePlacePushButton(w, RTW_BUILD_BRIDGE, SPR_CURSOR_BRIDGE, HT_RECT, PlaceRail_Bridge);
    00459 }
    00460
    00466 static void BuildRailClick_Tunnel(Window *w)
    00467 {
    00468   HandlePlacePushButton(w, RTW_BUILD_TUNNEL, GetRailTypeInfo(_cur_railtype)->cursor.tunnel, HT_SPECIAL, PlaceRail_Tunnel);
    00469 }
    00470
    00476 static void BuildRailClick_Remove(Window *w)
    00477 {
    00478   if (w->IsWidgetDisabled(RTW_REMOVE)) return;
    00479   ToggleRailButton_Remove(w);
    00480   SndPlayFx(SND_15_BEEP);
    00481
    00482   /* handle station builder */
    00483   if (w->IsWidgetLowered(RTW_BUILD_STATION)) {
    00484     if (_remove_button_clicked) {
    00485       /* starting drag & drop remove */
    00486       if (!_settings_client.gui.station_dragdrop) {
    00487         SetTileSelectSize(1, 1);
    00488       } else {
    00489         VpSetPlaceSizingLimit(-1);
    00490       }
    00491     } else {
    00492       /* starting station build mode */
    00493       if (!_settings_client.gui.station_dragdrop) {
    00494         int x = _settings_client.gui.station_numtracks;
    00495         int y = _settings_client.gui.station_platlength;
    00496         if (_railstation.orientation == 0) Swap(x, y);
    00497         SetTileSelectSize(x, y);
    00498       } else {
    00499         VpSetPlaceSizingLimit(_settings_game.station.station_spread);
    00500       }
    00501     }
    00502   }
    00503 }
    00504
    00511 static void BuildRailClick_Convert(Window *w)
    00512 {
    00513   HandlePlacePushButton(w, RTW_CONVERT_RAIL, GetRailTypeInfo(_cur_railtype)->cursor.convert, HT_RECT, PlaceRail_ConvertRail);
    00514 }
    00515
    00516
    00517 static void DoRailroadTrack(int mode)
    00518 {
    00519   DoCommandP(TileVirtXY(_thd.selstart.x, _thd.selstart.y), TileVirtXY(_thd.selend.x, _thd.selend.y), _cur_railtype | (mode << 4),
    00520     _remove_button_clicked ?
    00521     CMD_REMOVE_RAILROAD_TRACK | CMD_MSG(STR_ERROR_CAN_T_REMOVE_RAILROAD_TRACK) :
    00522     CMD_BUILD_RAILROAD_TRACK  | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK)
    00523   );
    00524 }
    00525
    00526 static void HandleAutodirPlacement()
    00527 {
    00528   TileHighlightData *thd = &_thd;
    00529   int trackstat = thd->drawstyle & 0xF; // 0..5
    00530
    00531   if (thd->drawstyle & HT_RAIL) { // one tile case
    00532     GenericPlaceRail(TileVirtXY(thd->selend.x, thd->selend.y), trackstat);
    00533     return;
    00534   }
    00535
    00536   DoRailroadTrack(trackstat);
    00537 }
    00538
    00545 static void HandleAutoSignalPlacement()
    00546 {
    00547   TileHighlightData *thd = &_thd;
    00548   uint32 p2 = GB(thd->drawstyle, 0, 3); // 0..5
    00549
    00550   if (thd->drawstyle == HT_RECT) { // one tile case
    00551     GenericPlaceSignals(TileVirtXY(thd->selend.x, thd->selend.y));
    00552     return;
    00553   }
    00554
    00555   const Window *w = FindWindowById(WC_BUILD_SIGNAL, 0);
    00556
    00557   if (w != NULL) {
    00558     /* signal GUI is used */
    00559     SB(p2,  3, 1, 0);
    00560     SB(p2,  4, 1, _cur_signal_variant);
    00561     SB(p2,  6, 1, _ctrl_pressed);
    00562     SB(p2,  7, 3, _cur_signal_type);
    00563     SB(p2, 24, 8, _settings_client.gui.drag_signals_density);
    00564   } else {
    00565     SB(p2,  3, 1, 0);
    00566     SB(p2,  4, 1, (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC));
    00567     SB(p2,  6, 1, _ctrl_pressed);
    00568     SB(p2,  7, 3, _default_signal_type[_settings_client.gui.default_signal_type]);
    00569     SB(p2, 24, 8, _settings_client.gui.drag_signals_density);
    00570   }
    00571
    00572   /* _settings_client.gui.drag_signals_density is given as a parameter such that each user
    00573    * in a network game can specify his/her own signal density */
    00574   DoCommandP(
    00575     TileVirtXY(thd->selstart.x, thd->selstart.y),
    00576     TileVirtXY(thd->selend.x, thd->selend.y),
    00577     p2,
    00578     _remove_button_clicked ?
    00579       CMD_REMOVE_SIGNAL_TRACK | CMD_MSG(STR_ERROR_CAN_T_REMOVE_SIGNALS_FROM) :
    00580       CMD_BUILD_SIGNAL_TRACK  | CMD_MSG(STR_ERROR_CAN_T_BUILD_SIGNALS_HERE),
    00581     CcPlaySound1E);
    00582 }
    00583
    00584
    00585 typedef void OnButtonClick(Window *w);
    00586
    00588 struct RailBuildingGUIButtonData {
    00589   uint16 keycode;
    00590   OnButtonClick *click_proc;
    00591 };
    00592
    00597 static const RailBuildingGUIButtonData _rail_build_button_data[] = {
    00598   {'1', BuildRailClick_N          },
    00599   {'2', BuildRailClick_NE         },
    00600   {'3', BuildRailClick_E          },
    00601   {'4', BuildRailClick_NW         },
    00602   {'5', BuildRailClick_AutoRail   },
    00603   {'6', BuildRailClick_Demolish   },
    00604   {'7', BuildRailClick_Depot      },
    00605   {'8', BuildRailClick_Waypoint   },
    00606   {'9', BuildRailClick_Station    },
    00607   {'S', BuildRailClick_AutoSignals},
    00608   {'B', BuildRailClick_Bridge     },
    00609   {'T', BuildRailClick_Tunnel     },
    00610   {'R', BuildRailClick_Remove     },
    00611   {'C', BuildRailClick_Convert    }
    00612 };
    00613
    00619 struct BuildRailToolbarWindow : Window {
    00620   RailType railtype;
    00621
    00622   BuildRailToolbarWindow(const WindowDesc *desc, WindowNumber window_number, RailType railtype) : Window()
    00623   {
    00624     this->InitNested(desc);
    00625     this->SetupRailToolbar(railtype);
    00626     this->DisableWidget(RTW_REMOVE);
    00627
    00628     if (_settings_client.gui.link_terraform_toolbar) ShowTerraformToolbar(this);
    00629   }
    00630
    00631   ~BuildRailToolbarWindow()
    00632   {
    00633     if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false);
    00634   }
    00635
    00639   void SetupRailToolbar(RailType railtype)
    00640   {
    00641     this->railtype = railtype;
    00642     const RailtypeInfo *rti = GetRailTypeInfo(railtype);
    00643
    00644     assert(railtype < RAILTYPE_END);
    00645     this->GetWidget<NWidgetCore>(RTW_BUILD_NS)->widget_data     = rti->gui_sprites.build_ns_rail;
    00646     this->GetWidget<NWidgetCore>(RTW_BUILD_X)->widget_data      = rti->gui_sprites.build_x_rail;
    00647     this->GetWidget<NWidgetCore>(RTW_BUILD_EW)->widget_data     = rti->gui_sprites.build_ew_rail;
    00648     this->GetWidget<NWidgetCore>(RTW_BUILD_Y)->widget_data      = rti->gui_sprites.build_y_rail;
    00649     this->GetWidget<NWidgetCore>(RTW_AUTORAIL)->widget_data     = rti->gui_sprites.auto_rail;
    00650     this->GetWidget<NWidgetCore>(RTW_BUILD_DEPOT)->widget_data  = rti->gui_sprites.build_depot;
    00651     this->GetWidget<NWidgetCore>(RTW_CONVERT_RAIL)->widget_data = rti->gui_sprites.convert_rail;
    00652     this->GetWidget<NWidgetCore>(RTW_BUILD_TUNNEL)->widget_data = rti->gui_sprites.build_tunnel;
    00653   }
    00654
    00658   void ModifyRailType(RailType railtype)
    00659   {
    00660     this->SetupRailToolbar(railtype);
    00661     this->ReInit();
    00662   }
    00663
    00664   void UpdateRemoveWidgetStatus(int clicked_widget)
    00665   {
    00666     switch (clicked_widget) {
    00667       case RTW_REMOVE:
    00668         /* If it is the removal button that has been clicked, do nothing,
    00669          * as it is up to the other buttons to drive removal status */
    00670         return;
    00671         break;
    00672       case RTW_BUILD_NS:
    00673       case RTW_BUILD_X:
    00674       case RTW_BUILD_EW:
    00675       case RTW_BUILD_Y:
    00676       case RTW_AUTORAIL:
    00677       case RTW_BUILD_WAYPOINT:
    00678       case RTW_BUILD_STATION:
    00679       case RTW_BUILD_SIGNALS:
    00680         /* Removal button is enabled only if the rail/signal/waypoint/station
    00681          * button is still lowered.  Once raised, it has to be disabled */
    00682         this->SetWidgetDisabledState(RTW_REMOVE, !this->IsWidgetLowered(clicked_widget));
    00683         break;
    00684
    00685       default:
    00686         /* When any other buttons than rail/signal/waypoint/station, raise and
    00687          * disable the removal button */
    00688         this->DisableWidget(RTW_REMOVE);
    00689         this->RaiseWidget(RTW_REMOVE);
    00690         break;
    00691     }
    00692   }
    00693
    00694   virtual void SetStringParameters(int widget) const
    00695   {
    00696     if (widget == RTW_CAPTION) {
    00697       const RailtypeInfo *rti = GetRailTypeInfo(this->railtype);
    00698       if (rti->max_speed > 0) {
    00699         SetDParam(0, STR_TOOLBAR_RAILTYPE_VELOCITY);
    00700         SetDParam(1, rti->strings.toolbar_caption);
    00701         SetDParam(2, rti->max_speed);
    00702       } else {
    00703         SetDParam(0, rti->strings.toolbar_caption);
    00704       }
    00705     }
    00706   }
    00707
    00708   virtual void OnPaint()
    00709   {
    00710     this->DrawWidgets();
    00711   }
    00712
    00713   virtual void OnClick(Point pt, int widget, int click_count)
    00714   {
    00715     if (widget >= RTW_BUILD_NS) {
    00716       _remove_button_clicked = false;
    00717       _rail_build_button_data[widget - RTW_BUILD_NS].click_proc(this);
    00718     }
    00719     this->UpdateRemoveWidgetStatus(widget);
    00720     if (_ctrl_pressed) RailToolbar_CtrlChanged(this);
    00721   }
    00722
    00723   virtual EventState OnKeyPress(uint16 key, uint16 keycode)
    00724   {
    00725     EventState state = ES_NOT_HANDLED;
    00726     for (uint8 i = 0; i != lengthof(_rail_build_button_data); i++) {
    00727       if (keycode == _rail_build_button_data[i].keycode) {
    00728         _remove_button_clicked = false;
    00729         _rail_build_button_data[i].click_proc(this);
    00730         this->UpdateRemoveWidgetStatus(i + RTW_BUILD_NS);
    00731         if (_ctrl_pressed) RailToolbar_CtrlChanged(this);
    00732         state = ES_HANDLED;
    00733         break;
    00734       }
    00735     }
    00736     MarkTileDirtyByTile(TileVirtXY(_thd.pos.x, _thd.pos.y)); // redraw tile selection
    00737     return state;
    00738   }
    00739
    00740   virtual void OnPlaceObject(Point pt, TileIndex tile)
    00741   {
    00742     _place_proc(tile);
    00743   }
    00744
    00745   virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
    00746   {
    00747     /* no dragging if you have pressed the convert button */
    00748     if (FindWindowById(WC_BUILD_SIGNAL, 0) != NULL && _convert_signal_button && this->IsWidgetLowered(RTW_BUILD_SIGNALS)) return;
    00749
    00750     VpSelectTilesWithMethod(pt.x, pt.y, select_method);
    00751   }
    00752
    00753   virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
    00754   {
    00755     if (pt.x != -1) {
    00756       switch (select_proc) {
    00757         default: NOT_REACHED();
    00758         case DDSP_BUILD_BRIDGE:
    00759           if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
    00760           ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_RAIL, _cur_railtype);
    00761           break;
    00762
    00763         case DDSP_PLACE_RAIL:
    00764           HandleAutodirPlacement();
    00765           break;
    00766
    00767         case DDSP_BUILD_SIGNALS:
    00768           HandleAutoSignalPlacement();
    00769           break;
    00770
    00771         case DDSP_DEMOLISH_AREA:
    00772           GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
    00773           break;
    00774
    00775         case DDSP_CONVERT_RAIL:
    00776           DoCommandP(end_tile, start_tile, _cur_railtype, CMD_CONVERT_RAIL | CMD_MSG(STR_ERROR_CAN_T_CONVERT_RAIL), CcPlaySound10);
    00777           break;
    00778
    00779         case DDSP_REMOVE_STATION:
    00780         case DDSP_BUILD_STATION:
    00781           if (this->IsWidgetLowered(RTW_BUILD_STATION)) {
    00782             /* Station */
    00783             if (_remove_button_clicked) {
    00784               DoCommandP(end_tile, start_tile, _ctrl_pressed ? 0 : 1, CMD_REMOVE_FROM_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_REMOVE_PART_OF_STATION), CcPlaySound1E);
    00785             } else {
    00786               HandleStationPlacement(start_tile, end_tile);
    00787             }
    00788           } else {
    00789             /* Waypoint */
    00790             if (_remove_button_clicked) {
    00791               DoCommandP(end_tile, start_tile, _ctrl_pressed ? 0 : 1, CMD_REMOVE_FROM_RAIL_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_REMOVE_TRAIN_WAYPOINT), CcPlaySound1E);
    00792             } else {
    00793               TileArea ta(start_tile, end_tile);
    00794               uint32 p1 = _cur_railtype | (select_method == VPM_FIX_X ? AXIS_X : AXIS_Y) << 4 | ta.w << 8 | ta.h << 16 | _ctrl_pressed << 24;
    00795               uint32 p2 = STAT_CLASS_WAYP | _cur_waypoint_type << 8 | INVALID_STATION << 16;
    00796
    00797               CommandContainer cmdcont = { ta.tile, p1, p2, CMD_BUILD_RAIL_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT), CcPlaySound1E, "" };
    00798               ShowSelectWaypointIfNeeded(cmdcont, ta);
    00799             }
    00800           }
    00801           break;
    00802       }
    00803     }
    00804   }
    00805
    00806   virtual void OnPlaceObjectAbort()
    00807   {
    00808     this->RaiseButtons();
    00809     this->DisableWidget(RTW_REMOVE);
    00810     this->SetWidgetDirty(RTW_REMOVE);
    00811
    00812     DeleteWindowById(WC_BUILD_SIGNAL, TRANSPORT_RAIL);
    00813     DeleteWindowById(WC_BUILD_STATION, TRANSPORT_RAIL);
    00814     DeleteWindowById(WC_BUILD_DEPOT, TRANSPORT_RAIL);
    00815     DeleteWindowById(WC_SELECT_STATION, 0);
    00816     DeleteWindowByClass(WC_BUILD_BRIDGE);
    00817   }
    00818
    00819   virtual void OnPlacePresize(Point pt, TileIndex tile)
    00820   {
    00821     DoCommand(tile, _cur_railtype | (TRANSPORT_RAIL << 8), 0, DC_AUTO, CMD_BUILD_TUNNEL);
    00822     VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile);
    00823   }
    00824
    00825   virtual EventState OnCTRLStateChange()
    00826   {
    00827     /* do not toggle Remove button by Ctrl when placing station */
    00828     if (!this->IsWidgetLowered(RTW_BUILD_STATION) && !this->IsWidgetLowered(RTW_BUILD_WAYPOINT) && RailToolbar_CtrlChanged(this)) return ES_HANDLED;
    00829     return ES_NOT_HANDLED;
    00830   }
    00831 };
    00832
    00833 static const NWidgetPart _nested_build_rail_widgets[] = {
    00834   NWidget(NWID_HORIZONTAL),
    00835     NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
    00836     NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, RTW_CAPTION), SetDataTip(STR_WHITE_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    00837     NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN),
    00838   EndContainer(),
    00839   NWidget(NWID_HORIZONTAL),
    00840     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_BUILD_NS),
    00841             SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_NS, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK),
    00842     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_BUILD_X),
    00843             SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_NE, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK),
    00844     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_BUILD_EW),
    00845             SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_EW, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK),
    00846     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_BUILD_Y),
    00847             SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_NW, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK),
    00848     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_AUTORAIL),
    00849             SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTORAIL, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_AUTORAIL),
    00850
    00851     NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(4, 22), SetDataTip(0x0, STR_NULL), EndContainer(),
    00852
    00853     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_DEMOLISH),
    00854             SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC),
    00855     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_BUILD_DEPOT),
    00856             SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DEPOT_RAIL, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING),
    00857     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_BUILD_WAYPOINT),
    00858             SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_WAYPOINT, STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT),
    00859     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_BUILD_STATION),
    00860             SetFill(0, 1), SetMinimalSize(42, 22), SetDataTip(SPR_IMG_RAIL_STATION, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION),
    00861     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_BUILD_SIGNALS),
    00862             SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_SIGNALS, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS),
    00863     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_BUILD_BRIDGE),
    00864             SetFill(0, 1), SetMinimalSize(42, 22), SetDataTip(SPR_IMG_BRIDGE, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_BRIDGE),
    00865     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_BUILD_TUNNEL),
    00866             SetFill(0, 1), SetMinimalSize(20, 22), SetDataTip(SPR_IMG_TUNNEL_RAIL, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TUNNEL),
    00867     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_REMOVE),
    00868             SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_RAIL_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR),
    00869     NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, RTW_CONVERT_RAIL),
    00870             SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_CONVERT_RAIL, STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL),
    00871   EndContainer(),
    00872 };
    00873
    00874 static const WindowDesc _build_rail_desc(
    00875   WDP_ALIGN_TOOLBAR, 0, 0,
    00876   WC_BUILD_TOOLBAR, WC_NONE,
    00877   WDF_CONSTRUCTION,
    00878   _nested_build_rail_widgets, lengthof(_nested_build_rail_widgets)
    00879 );
    00880
    00881
    00893 void ShowBuildRailToolbar(RailType railtype, int button)
    00894 {
    00895   if (!Company::IsValidID(_local_company)) return;
    00896   if (!ValParamRailtype(railtype)) return;
    00897
    00898   BuildRailToolbarWindow *w = (BuildRailToolbarWindow *)FindWindowById(WC_BUILD_TOOLBAR, TRANSPORT_RAIL);
    00899
    00900   /* don't recreate the window if we're clicking on a button and the window exists. */
    00901   if (button < 0 || w == NULL) {
    00902     DeleteWindowByClass(WC_BUILD_TOOLBAR);
    00903     _cur_railtype = railtype;
    00904     w = new BuildRailToolbarWindow(&_build_rail_desc, TRANSPORT_RAIL, railtype);
    00905   }
    00906
    00907   _remove_button_clicked = false;
    00908   if (w != NULL && button >= 0) {
    00909     _rail_build_button_data[button].click_proc(w);
    00910     w->UpdateRemoveWidgetStatus(button + RTW_BUILD_NS);
    00911   }
    00912 }
    00913
    00914 /* TODO: For custom stations, respect their allowed platforms/lengths bitmasks!
    00915  * --pasky */
    00916
    00917 static void HandleStationPlacement(TileIndex start, TileIndex end)
    00918 {
    00919   TileArea ta(start, end);
    00920   uint numtracks = ta.w;
    00921   uint platlength = ta.h;
    00922
    00923   if (_railstation.orientation == AXIS_X) Swap(numtracks, platlength);
    00924
    00925   uint32 p1 = _cur_railtype | _railstation.orientation << 4 | numtracks << 8 | platlength << 16 | _ctrl_pressed << 24;
    00926   uint32 p2 = _railstation.station_class | _railstation.station_type << 8 | INVALID_STATION << 16;
    00927
    00928   CommandContainer cmdcont = { ta.tile, p1, p2, CMD_BUILD_RAIL_STATION | CMD_MSG(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION), CcStation, "" };
    00929   ShowSelectStationIfNeeded(cmdcont, ta);
    00930 }
    00931
    00933 enum BuildRailStationWidgets {
    00934   BRSW_BACKGROUND,
    00935
    00936   BRSW_PLATFORM_DIR_X,
    00937   BRSW_PLATFORM_DIR_Y,
    00938
    00939   BRSW_PLATFORM_NUM_1,
    00940   BRSW_PLATFORM_NUM_2,
    00941   BRSW_PLATFORM_NUM_3,
    00942   BRSW_PLATFORM_NUM_4,
    00943   BRSW_PLATFORM_NUM_5,
    00944   BRSW_PLATFORM_NUM_6,
    00945   BRSW_PLATFORM_NUM_7,
    00946
    00947   BRSW_PLATFORM_LEN_1,
    00948   BRSW_PLATFORM_LEN_2,
    00949   BRSW_PLATFORM_LEN_3,
    00950   BRSW_PLATFORM_LEN_4,
    00951   BRSW_PLATFORM_LEN_5,
    00952   BRSW_PLATFORM_LEN_6,
    00953   BRSW_PLATFORM_LEN_7,
    00954
    00955   BRSW_PLATFORM_DRAG_N_DROP,
    00956
    00957   BRSW_HIGHLIGHT_OFF,
    00958   BRSW_HIGHLIGHT_ON,
    00959
    00960   BRSW_NEWST_DROPDOWN,
    00961   BRSW_NEWST_LIST,
    00962   BRSW_NEWST_SCROLL,
    00963
    00964   BRSW_PLATFORM_NUM_BEGIN = BRSW_PLATFORM_NUM_1 - 1,
    00965   BRSW_PLATFORM_LEN_BEGIN = BRSW_PLATFORM_LEN_1 - 1,
    00966 };
    00967
    00968 struct BuildRailStationWindow : public PickerWindowBase {
    00969 private:
    00970   uint line_height;
    00971
    00977   void CheckSelectedSize(const StationSpec *statspec)
    00978   {
    00979     if (statspec == NULL || _settings_client.gui.station_dragdrop) return;
    00980
    00981     /* If current number of tracks is not allowed, make it as big as possible (which is always less than currently selected) */
    00982     if (HasBit(statspec->disallowed_platforms, _settings_client.gui.station_numtracks - 1)) {
    00983       this->RaiseWidget(_settings_client.gui.station_numtracks + BRSW_PLATFORM_NUM_BEGIN);
    00984       _settings_client.gui.station_numtracks = 1;
    00985       while (HasBit(statspec->disallowed_platforms, _settings_client.gui.station_numtracks - 1)) {
    00986         _settings_client.gui.station_numtracks++;
    00987       }
    00988       this->LowerWidget(_settings_client.gui.station_numtracks + BRSW_PLATFORM_NUM_BEGIN);
    00989     }
    00990
    00991     if (HasBit(statspec->disallowed_lengths, _settings_client.gui.station_platlength - 1)) {
    00992       this->RaiseWidget(_settings_client.gui.station_platlength + BRSW_PLATFORM_LEN_BEGIN);
    00993       _settings_client.gui.station_platlength = 1;
    00994       while (HasBit(statspec->disallowed_lengths, _settings_client.gui.station_platlength - 1)) {
    00995         _settings_client.gui.station_platlength++;
    00996       }
    00997       this->LowerWidget(_settings_client.gui.station_platlength + BRSW_PLATFORM_LEN_BEGIN);
    00998     }
    00999   }
    01000
    01002   static DropDownList *BuildStationClassDropDown()
    01003   {
    01004     DropDownList *list = new DropDownList();
    01005
    01006     for (uint i = 0; i < GetNumStationClasses(); i++) {
    01007       if (i == STAT_CLASS_WAYP) continue;
    01008       list->push_back(new DropDownListStringItem(GetStationClassName((StationClassID)i), i, false));
    01009     }
    01010
    01011     return list;
    01012   }
    01013
    01014 public:
    01015   BuildRailStationWindow(const WindowDesc *desc, Window *parent, bool newstation) : PickerWindowBase(parent)
    01016   {
    01017     this->InitNested(desc, TRANSPORT_RAIL);
    01018
    01019     this->LowerWidget(_railstation.orientation + BRSW_PLATFORM_DIR_X);
    01020     if (_settings_client.gui.station_dragdrop) {
    01021       this->LowerWidget(BRSW_PLATFORM_DRAG_N_DROP);
    01022     } else {
    01023       this->LowerWidget(_settings_client.gui.station_numtracks + BRSW_PLATFORM_NUM_BEGIN);
    01024       this->LowerWidget(_settings_client.gui.station_platlength + BRSW_PLATFORM_LEN_BEGIN);
    01025     }
    01026     this->SetWidgetLoweredState(BRSW_HIGHLIGHT_OFF, !_settings_client.gui.station_show_coverage);
    01027     this->SetWidgetLoweredState(BRSW_HIGHLIGHT_ON, _settings_client.gui.station_show_coverage);
    01028
    01029     _railstation.newstations = newstation;
    01030
    01031     if (newstation) {
    01032       _railstation.station_count = GetNumCustomStations(_railstation.station_class);
    01033
    01034       this->vscroll.SetCount(_railstation.station_count);
    01035       this->vscroll.SetCapacity(GB(this->GetWidget<NWidgetCore>(BRSW_NEWST_LIST)->widget_data, MAT_ROW_START, MAT_ROW_BITS));
    01036       this->vscroll.SetPosition(Clamp(_railstation.station_type - 2, 0, max(this->vscroll.GetCount() - this->vscroll.GetCapacity(), 0)));
    01037     } else {
    01038       /* New stations are not available, so ensure the default station
    01039        * type is 'selected'. */
    01040       _railstation.station_class = STAT_CLASS_DFLT;
    01041       _railstation.station_type = 0;
    01042     }
    01043   }
    01044
    01045   virtual ~BuildRailStationWindow()
    01046   {
    01047     DeleteWindowById(WC_SELECT_STATION, 0);
    01048   }
    01049
    01050   virtual void OnPaint()
    01051   {
    01052     bool newstations = _railstation.newstations;
    01053     const StationSpec *statspec = newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
    01054
    01055     if (_settings_client.gui.station_dragdrop) {
    01056       SetTileSelectSize(1, 1);
    01057     } else {
    01058       int x = _settings_client.gui.station_numtracks;
    01059       int y = _settings_client.gui.station_platlength;
    01060       if (_railstation.orientation == AXIS_X) Swap(x, y);
    01061       if (!_remove_button_clicked)
    01062         SetTileSelectSize(x, y);
    01063     }
    01064
    01065     int rad = (_settings_game.station.modified_catchment) ? CA_TRAIN : CA_UNMODIFIED;
    01066
    01067     if (_settings_client.gui.station_show_coverage)
    01068       SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
    01069
    01070     for (uint bits = 0; bits < 7; bits++) {
    01071       bool disable = bits >= _settings_game.station.station_spread;
    01072       if (statspec == NULL) {
    01073         this->SetWidgetDisabledState(bits + BRSW_PLATFORM_NUM_1, disable);
    01074         this->SetWidgetDisabledState(bits + BRSW_PLATFORM_LEN_1, disable);
    01075       } else {
    01076         this->SetWidgetDisabledState(bits + BRSW_PLATFORM_NUM_1, HasBit(statspec->disallowed_platforms, bits) || disable);
    01077         this->SetWidgetDisabledState(bits + BRSW_PLATFORM_LEN_1, HasBit(statspec->disallowed_lengths,   bits) || disable);
    01078       }
    01079     }
    01080
    01081     this->DrawWidgets();
    01082
    01083     /* 'Accepts' and 'Supplies' texts. */
    01084     int top = this->GetWidget<NWidgetBase>(BRSW_HIGHLIGHT_ON)->pos_y + this->GetWidget<NWidgetBase>(BRSW_HIGHLIGHT_ON)->current_y + WD_PAR_VSEP_NORMAL;
    01085     NWidgetBase *back_nwi = this->GetWidget<NWidgetBase>(BRSW_BACKGROUND);
    01086     int right = back_nwi->pos_x +  back_nwi->current_x;
    01087     int bottom = back_nwi->pos_y +  back_nwi->current_y;
    01088     top = DrawStationCoverageAreaText(back_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, SCT_ALL, rad, false) + WD_PAR_VSEP_NORMAL;
    01089     top = DrawStationCoverageAreaText(back_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, SCT_ALL, rad, true) + WD_PAR_VSEP_NORMAL;
    01090     /* Resize background if the text is not equally long as the window. */
    01091     if (top > bottom || (top < bottom && back_nwi->current_y > back_nwi->smallest_y)) {
    01092       ResizeWindow(this, 0, top - bottom);
    01093     }
    01094   }
    01095
    01096   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
    01097   {
    01098     switch (widget) {
    01099       case BRSW_NEWST_DROPDOWN: {
    01100         Dimension d = {0, 0};
    01101         for (uint i = 0; i < GetNumStationClasses(); i++) {
    01102           if (i == STAT_CLASS_WAYP) continue;
    01103           SetDParam(0, GetStationClassName((StationClassID)i));
    01104           d = maxdim(d, GetStringBoundingBox(STR_BLACK_STRING));
    01105         }
    01106         d.width += padding.width;
    01107         d.height += padding.height;
    01108         *size = maxdim(*size, d);
    01109         break;
    01110       }
    01111       case BRSW_NEWST_LIST: {
    01112         Dimension d = GetStringBoundingBox(STR_STATION_CLASS_DFLT);
    01113         for (StationClassID statclass = STAT_CLASS_BEGIN; statclass < (StationClassID)GetNumStationClasses(); statclass++) {
    01114           if (statclass == STAT_CLASS_WAYP) continue;
    01115           for (uint16 j = 0; j < GetNumCustomStations(statclass); j++) {
    01116             const StationSpec *statspec = GetCustomStationSpec(statclass, j);
    01117             if (statspec != NULL && statspec->name != 0) d = maxdim(d, GetStringBoundingBox(statspec->name));
    01118           }
    01119         }
    01120         size->width = max(size->width, d.width + padding.width);
    01121
    01122         this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM;
    01123         size->height = GB(this->GetWidget<NWidgetCore>(widget)->widget_data, MAT_ROW_START, MAT_ROW_BITS) * this->line_height;
    01124         break;
    01125       }
    01126     }
    01127   }
    01128
    01129   virtual void DrawWidget(const Rect &r, int widget) const
    01130   {
    01131     DrawPixelInfo tmp_dpi;
    01132
    01133     switch (widget) {
    01134       case BRSW_PLATFORM_DIR_X:
    01135         /* Set up a clipping area for the '/' station preview */
    01136         if (FillDrawPixelInfo(&tmp_dpi, r.left, r.top, r.right - r.left + 1, r.bottom - r.top + 1)) {
    01137           DrawPixelInfo *old_dpi = _cur_dpi;
    01138           _cur_dpi = &tmp_dpi;
    01139           if (!DrawStationTile(32, 16, _cur_railtype, AXIS_X, _railstation.station_class, _railstation.station_type)) {
    01140             StationPickerDrawSprite(32, 16, STATION_RAIL, _cur_railtype, INVALID_ROADTYPE, 2);
    01141           }
    01142           _cur_dpi = old_dpi;
    01143         }
    01144         break;
    01145
    01146       case BRSW_PLATFORM_DIR_Y:
    01147         /* Set up a clipping area for the '\' station preview */
    01148         if (FillDrawPixelInfo(&tmp_dpi, r.left, r.top, r.right - r.left + 1, r.bottom - r.top + 1)) {
    01149           DrawPixelInfo *old_dpi = _cur_dpi;
    01150           _cur_dpi = &tmp_dpi;
    01151           if (!DrawStationTile(32, 16, _cur_railtype, AXIS_Y, _railstation.station_class, _railstation.station_type)) {
    01152             StationPickerDrawSprite(32, 16, STATION_RAIL, _cur_railtype, INVALID_ROADTYPE, 3);
    01153           }
    01154           _cur_dpi = old_dpi;
    01155         }
    01156         break;
    01157
    01158       case BRSW_NEWST_LIST: {
    01159         uint y = r.top;
    01160         for (uint16 i = this->vscroll.GetPosition(); i < _railstation.station_count && this->vscroll.IsVisible(i); i++) {
    01161           const StationSpec *statspec = GetCustomStationSpec(_railstation.station_class, i);
    01162
    01163           StringID str = STR_STATION_CLASS_DFLT;
    01164           if (statspec != NULL && statspec->name != 0) {
    01165             if (HasBit(statspec->callback_mask, CBM_STATION_AVAIL) && GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) {
    01166               GfxFillRect(r.left + 1, y + 1, r.right - 1, y + this->line_height - 2, 0, FILLRECT_CHECKER);
    01167             }
    01168             str = statspec->name;
    01169           }
    01170           DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, y + WD_MATRIX_TOP, str, i == _railstation.station_type ? TC_WHITE : TC_BLACK);
    01171
    01172           y += this->line_height;
    01173         }
    01174         break;
    01175       }
    01176     }
    01177   }
    01178
    01179   virtual void SetStringParameters(int widget) const
    01180   {
    01181     if (widget == BRSW_NEWST_DROPDOWN) SetDParam(0, GetStationClassName(_railstation.station_class));
    01182   }
    01183
    01184   virtual void OnClick(Point pt, int widget, int click_count)
    01185   {
    01186     switch (widget) {
    01187       case BRSW_PLATFORM_DIR_X:
    01188       case BRSW_PLATFORM_DIR_Y:
    01189         this->RaiseWidget(_railstation.orientation + BRSW_PLATFORM_DIR_X);
    01190         _railstation.orientation = (Axis)(widget - BRSW_PLATFORM_DIR_X);
    01191         this->LowerWidget(_railstation.orientation + BRSW_PLATFORM_DIR_X);
    01192         SndPlayFx(SND_15_BEEP);
    01193         this->SetDirty();
    01194         DeleteWindowById(WC_SELECT_STATION, 0);
    01195         break;
    01196
    01197       case BRSW_PLATFORM_NUM_1:
    01198       case BRSW_PLATFORM_NUM_2:
    01199       case BRSW_PLATFORM_NUM_3:
    01200       case BRSW_PLATFORM_NUM_4:
    01201       case BRSW_PLATFORM_NUM_5:
    01202       case BRSW_PLATFORM_NUM_6:
    01203       case BRSW_PLATFORM_NUM_7: {
    01204         this->RaiseWidget(_settings_client.gui.station_numtracks + BRSW_PLATFORM_NUM_BEGIN);
    01205         this->RaiseWidget(BRSW_PLATFORM_DRAG_N_DROP);
    01206
    01207         _settings_client.gui.station_numtracks = widget - BRSW_PLATFORM_NUM_BEGIN;
    01208         _settings_client.gui.station_dragdrop = false;
    01209
    01210         _settings_client.gui.station_dragdrop = false;
    01211
    01212         const StationSpec *statspec = _railstation.newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
    01213         if (statspec != NULL && HasBit(statspec->disallowed_lengths, _settings_client.gui.station_platlength - 1)) {
    01214           /* The previously selected number of platforms in invalid */
    01215           for (uint i = 0; i < 7; i++) {
    01216             if (!HasBit(statspec->disallowed_lengths, i)) {
    01217               this->RaiseWidget(_settings_client.gui.station_platlength + BRSW_PLATFORM_LEN_BEGIN);
    01218               _settings_client.gui.station_platlength = i + 1;
    01219               break;
    01220             }
    01221           }
    01222         }
    01223
    01224         this->LowerWidget(_settings_client.gui.station_numtracks + BRSW_PLATFORM_NUM_BEGIN);
    01225         this->LowerWidget(_settings_client.gui.station_platlength + BRSW_PLATFORM_LEN_BEGIN);
    01226         SndPlayFx(SND_15_BEEP);
    01227         this->SetDirty();
    01228         DeleteWindowById(WC_SELECT_STATION, 0);
    01229         break;
    01230       }
    01231
    01232       case BRSW_PLATFORM_LEN_1:
    01233       case BRSW_PLATFORM_LEN_2:
    01234       case BRSW_PLATFORM_LEN_3:
    01235       case BRSW_PLATFORM_LEN_4:
    01236       case BRSW_PLATFORM_LEN_5:
    01237       case BRSW_PLATFORM_LEN_6:
    01238       case BRSW_PLATFORM_LEN_7: {
    01239         this->RaiseWidget(_settings_client.gui.station_platlength + BRSW_PLATFORM_LEN_BEGIN);
    01240         this->RaiseWidget(BRSW_PLATFORM_DRAG_N_DROP);
    01241
    01242         _settings_client.gui.station_platlength = widget - BRSW_PLATFORM_LEN_BEGIN;
    01243         _settings_client.gui.station_dragdrop = false;
    01244
    01245         _settings_client.gui.station_dragdrop = false;
    01246
    01247         const StationSpec *statspec = _railstation.newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
    01248         if (statspec != NULL && HasBit(statspec->disallowed_platforms, _settings_client.gui.station_numtracks - 1)) {
    01249           /* The previously selected number of tracks in invalid */
    01250           for (uint i = 0; i < 7; i++) {
    01251             if (!HasBit(statspec->disallowed_platforms, i)) {
    01252               this->RaiseWidget(_settings_client.gui.station_numtracks + BRSW_PLATFORM_NUM_BEGIN);
    01253               _settings_client.gui.station_numtracks = i + 1;
    01254               break;
    01255             }
    01256           }
    01257         }
    01258
    01259         this->LowerWidget(_settings_client.gui.station_numtracks + BRSW_PLATFORM_NUM_BEGIN);
    01260         this->LowerWidget(_settings_client.gui.station_platlength + BRSW_PLATFORM_LEN_BEGIN);
    01261         SndPlayFx(SND_15_BEEP);
    01262         this->SetDirty();
    01263         DeleteWindowById(WC_SELECT_STATION, 0);
    01264         break;
    01265       }
    01266
    01267       case BRSW_PLATFORM_DRAG_N_DROP: {
    01268         _settings_client.gui.station_dragdrop ^= true;
    01269
    01270         this->ToggleWidgetLoweredState(BRSW_PLATFORM_DRAG_N_DROP);
    01271
    01272         /* get the first allowed length/number of platforms */
    01273         const StationSpec *statspec = _railstation.newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
    01274         if (statspec != NULL && HasBit(statspec->disallowed_lengths, _settings_client.gui.station_platlength - 1)) {
    01275           for (uint i = 0; i < 7; i++) {
    01276             if (!HasBit(statspec->disallowed_lengths, i)) {
    01277               this->RaiseWidget(_settings_client.gui.station_platlength + BRSW_PLATFORM_LEN_BEGIN);
    01278               _settings_client.gui.station_platlength = i + 1;
    01279               break;
    01280             }
    01281           }
    01282         }
    01283         if (statspec != NULL && HasBit(statspec->disallowed_platforms, _settings_client.gui.station_numtracks - 1)) {
    01284           for (uint i = 0; i < 7; i++) {
    01285             if (!HasBit(statspec->disallowed_platforms, i)) {
    01286               this->RaiseWidget(_settings_client.gui.station_numtracks + BRSW_PLATFORM_NUM_BEGIN);
    01287               _settings_client.gui.station_numtracks = i + 1;
    01288               break;
    01289             }
    01290           }
    01291         }
    01292
    01293         this->SetWidgetLoweredState(_settings_client.gui.station_numtracks + BRSW_PLATFORM_NUM_BEGIN, !_settings_client.gui.station_dragdrop);
    01294         this->SetWidgetLoweredState(_settings_client.gui.station_platlength + BRSW_PLATFORM_LEN_BEGIN, !_settings_client.gui.station_dragdrop);
    01295         SndPlayFx(SND_15_BEEP);
    01296         this->SetDirty();
    01297         DeleteWindowById(WC_SELECT_STATION, 0);
    01298       } break;
    01299
    01300       case BRSW_HIGHLIGHT_OFF:
    01301       case BRSW_HIGHLIGHT_ON:
    01302         _settings_client.gui.station_show_coverage = (widget != BRSW_HIGHLIGHT_OFF);
    01303
    01304         this->SetWidgetLoweredState(BRSW_HIGHLIGHT_OFF, !_settings_client.gui.station_show_coverage);
    01305         this->SetWidgetLoweredState(BRSW_HIGHLIGHT_ON, _settings_client.gui.station_show_coverage);
    01306         SndPlayFx(SND_15_BEEP);
    01307         this->SetDirty();
    01308         break;
    01309
    01310       case BRSW_NEWST_DROPDOWN:
    01311         ShowDropDownList(this, BuildStationClassDropDown(), _railstation.station_class, BRSW_NEWST_DROPDOWN);
    01312         break;
    01313
    01314       case BRSW_NEWST_LIST: {
    01315         const StationSpec *statspec;
    01316         int y = (pt.y - this->GetWidget<NWidgetBase>(BRSW_NEWST_LIST)->pos_y) / this->line_height;
    01317
    01318         if (y >= this->vscroll.GetCapacity()) return;
    01319         y += this->vscroll.GetPosition();
    01320         if (y >= _railstation.station_count) return;
    01321
    01322         /* Check station availability callback */
    01323         statspec = GetCustomStationSpec(_railstation.station_class, y);
    01324         if (statspec != NULL &&
    01325           HasBit(statspec->callback_mask, CBM_STATION_AVAIL) &&
    01326           GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) return;
    01327
    01328         _railstation.station_type = y;
    01329
    01330         this->CheckSelectedSize(statspec);
    01331
    01332         SndPlayFx(SND_15_BEEP);
    01333         this->SetDirty();
    01334         DeleteWindowById(WC_SELECT_STATION, 0);
    01335         break;
    01336       }
    01337     }
    01338   }
    01339
    01340   virtual void OnDropdownSelect(int widget, int index)
    01341   {
    01342     if (_railstation.station_class != index) {
    01343       _railstation.station_class = (StationClassID)index;
    01344       _railstation.station_type  = 0;
    01345       _railstation.station_count = GetNumCustomStations(_railstation.station_class);
    01346
    01347       this->CheckSelectedSize(GetCustomStationSpec(_railstation.station_class, _railstation.station_type));
    01348
    01349       this->vscroll.SetCount(_railstation.station_count);
    01350       this->vscroll.SetPosition(_railstation.station_type);
    01351     }
    01352
    01353     SndPlayFx(SND_15_BEEP);
    01354     this->SetDirty();
    01355     DeleteWindowById(WC_SELECT_STATION, 0);
    01356   }
    01357
    01358   virtual void OnTick()
    01359   {
    01360     CheckRedrawStationCoverage(this);
    01361   }
    01362 };
    01363
    01364 static const NWidgetPart _nested_station_builder_widgets[] = {
    01365   NWidget(NWID_HORIZONTAL),
    01366     NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
    01367     NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_RAIL_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    01368   EndContainer(),
    01369   NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BRSW_BACKGROUND),
    01370     NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_ORIENTATION, STR_NULL), SetPadding(1, 2, 0, 2),
    01371     NWidget(NWID_HORIZONTAL),
    01372       NWidget(NWID_SPACER), SetMinimalSize(7, 0), SetFill(1, 0),
    01373       NWidget(WWT_PANEL, COLOUR_GREY, BRSW_PLATFORM_DIR_X), SetMinimalSize(66, 48), SetFill(0, 0), SetDataTip(0x0, STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP), EndContainer(),
    01374       NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0),
    01375       NWidget(WWT_PANEL, COLOUR_GREY, BRSW_PLATFORM_DIR_Y), SetMinimalSize(66, 48), SetFill(0, 0), SetDataTip(0x0, STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP), EndContainer(),
    01376       NWidget(NWID_SPACER), SetMinimalSize(7, 0), SetFill(1, 0),
    01377     EndContainer(),
    01378     NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_NUMBER_OF_TRACKS, STR_NULL), SetPadding(2, 2, 0, 2),
    01379     NWidget(NWID_HORIZONTAL),
    01380       NWidget(NWID_SPACER), SetFill(1, 0),
    01381       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_1), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_1, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
    01382       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_2), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_2, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
    01383       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_3), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_3, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
    01384       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_4), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_4, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
    01385       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_5), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_5, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
    01386       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_6), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_6, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
    01387       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_7), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_7, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
    01388       NWidget(NWID_SPACER), SetFill(1, 0),
    01389     EndContainer(),
    01390     NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_PLATFORM_LENGTH, STR_NULL), SetPadding(2, 2, 0, 2),
    01391     NWidget(NWID_HORIZONTAL),
    01392       NWidget(NWID_SPACER), SetFill(1, 0),
    01393       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_1), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_1, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
    01394       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_2), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_2, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
    01395       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_3), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_3, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
    01396       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_4), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_4, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
    01397       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_5), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_5, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
    01398       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_6), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_6, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
    01399       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_7), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_7, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
    01400       NWidget(NWID_SPACER), SetFill(1, 0),
    01401     EndContainer(),
    01402     NWidget(NWID_SPACER), SetMinimalSize(0, 2),
    01403     NWidget(NWID_HORIZONTAL),
    01404       NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0),
    01405       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_DRAG_N_DROP), SetMinimalSize(75, 12), SetDataTip(STR_STATION_BUILD_DRAG_DROP, STR_STATION_BUILD_DRAG_DROP_TOOLTIP),
    01406       NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0),
    01407     EndContainer(),
    01408     NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), SetPadding(3, 2, 0, 2),
    01409     NWidget(NWID_HORIZONTAL),
    01410       NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0),
    01411       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_HIGHLIGHT_OFF), SetMinimalSize(60, 12),
    01412                     SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP),
    01413       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_HIGHLIGHT_ON), SetMinimalSize(60, 12),
    01414                     SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP),
    01415       NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0),
    01416     EndContainer(),
    01417     NWidget(NWID_SPACER), SetMinimalSize(0, 20), SetResize(0, 1),
    01418   EndContainer(),
    01419 };
    01420
    01421 static const NWidgetPart _nested_newstation_builder_widgets[] = {
    01422   NWidget(NWID_HORIZONTAL),
    01423     NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
    01424     NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_RAIL_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    01425   EndContainer(),
    01426   NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BRSW_BACKGROUND),
    01427     /* begin newstations gui additions. */
    01428     NWidget(WWT_DROPDOWN, COLOUR_GREY, BRSW_NEWST_DROPDOWN), SetMinimalSize(134, 12), SetFill(1, 0), SetPadding(3, 7, 3, 7), SetDataTip(STR_BLACK_STRING, STR_STATION_BUILD_STATION_CLASS_TOOLTIP),
    01429     NWidget(NWID_HORIZONTAL), SetPIP(7, 0, 7),
    01430       NWidget(WWT_MATRIX, COLOUR_GREY, BRSW_NEWST_LIST), SetMinimalSize(122, 71), SetFill(1, 0), SetDataTip(0x501, STR_STATION_BUILD_STATION_TYPE_TOOLTIP),
    01431       NWidget(WWT_SCROLLBAR, COLOUR_GREY, BRSW_NEWST_SCROLL),
    01432     EndContainer(),
    01433     NWidget(NWID_SPACER), SetMinimalSize(0, 1),
    01434     /* end newstations gui additions. */
    01435     NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_ORIENTATION, STR_NULL), SetPadding(1, 2, 0, 2),
    01436     NWidget(NWID_HORIZONTAL),
    01437       NWidget(NWID_SPACER), SetMinimalSize(7, 0), SetFill(1, 0),
    01438       NWidget(WWT_PANEL, COLOUR_GREY, BRSW_PLATFORM_DIR_X), SetMinimalSize(66, 48), SetFill(0, 0), SetDataTip(0x0, STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP), EndContainer(),
    01439       NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0),
    01440       NWidget(WWT_PANEL, COLOUR_GREY, BRSW_PLATFORM_DIR_Y), SetMinimalSize(66, 48), SetFill(0, 0), SetDataTip(0x0, STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP), EndContainer(),
    01441       NWidget(NWID_SPACER), SetMinimalSize(7, 0), SetFill(1, 0),
    01442     EndContainer(),
    01443     NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_NUMBER_OF_TRACKS, STR_NULL), SetPadding(2, 2, 0, 2),
    01444     NWidget(NWID_HORIZONTAL),
    01445       NWidget(NWID_SPACER), SetFill(1, 0),
    01446       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_1), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_1, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
    01447       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_2), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_2, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
    01448       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_3), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_3, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
    01449       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_4), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_4, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
    01450       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_5), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_5, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
    01451       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_6), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_6, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
    01452       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_NUM_7), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_7, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP),
    01453       NWidget(NWID_SPACER), SetFill(1, 0),
    01454     EndContainer(),
    01455     NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_PLATFORM_LENGTH, STR_NULL), SetPadding(2, 2, 0, 2),
    01456     NWidget(NWID_HORIZONTAL),
    01457       NWidget(NWID_SPACER), SetFill(1, 0),
    01458       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_1), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_1, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
    01459       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_2), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_2, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
    01460       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_3), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_3, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
    01461       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_4), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_4, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
    01462       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_5), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_5, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
    01463       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_6), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_6, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
    01464       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_LEN_7), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_7, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP),
    01465       NWidget(NWID_SPACER), SetFill(1, 0),
    01466     EndContainer(),
    01467     NWidget(NWID_SPACER), SetMinimalSize(0, 2),
    01468     NWidget(NWID_HORIZONTAL),
    01469       NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0),
    01470       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_PLATFORM_DRAG_N_DROP), SetMinimalSize(75, 12), SetDataTip(STR_STATION_BUILD_DRAG_DROP, STR_STATION_BUILD_DRAG_DROP_TOOLTIP),
    01471       NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0),
    01472     EndContainer(),
    01473     NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), SetPadding(3, 2, 0, 2),
    01474     NWidget(NWID_HORIZONTAL),
    01475       NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0),
    01476       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_HIGHLIGHT_OFF), SetMinimalSize(60, 12),
    01477                     SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP),
    01478       NWidget(WWT_TEXTBTN, COLOUR_GREY, BRSW_HIGHLIGHT_ON), SetMinimalSize(60, 12),
    01479                     SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP),
    01480       NWidget(NWID_SPACER), SetMinimalSize(2, 0), SetFill(1, 0),
    01481     EndContainer(),
    01482     NWidget(NWID_SPACER), SetMinimalSize(0, 20), SetResize(0, 1),
    01483   EndContainer(),
    01484 };
    01485
    01487 static const WindowDesc _station_builder_desc(
    01488   WDP_AUTO, 0, 0,
    01489   WC_BUILD_STATION, WC_BUILD_TOOLBAR,
    01490   WDF_CONSTRUCTION,
    01491   _nested_station_builder_widgets, lengthof(_nested_station_builder_widgets)
    01492 );
    01493
    01495 static const WindowDesc _newstation_builder_desc(
    01496   WDP_AUTO, 0, 0,
    01497   WC_BUILD_STATION, WC_BUILD_TOOLBAR,
    01498   WDF_CONSTRUCTION,
    01499   _nested_newstation_builder_widgets, lengthof(_nested_newstation_builder_widgets)
    01500 );
    01501
    01503 static void ShowStationBuilder(Window *parent)
    01504 {
    01505   if (GetNumStationClasses() <= 2 && GetNumCustomStations(STAT_CLASS_DFLT) == 1) {
    01506     new BuildRailStationWindow(&_station_builder_desc, parent, false);
    01507   } else {
    01508     new BuildRailStationWindow(&_newstation_builder_desc, parent, true);
    01509   }
    01510 }
    01511
    01513 enum BuildSignalWidgets {
    01514   BSW_SEMAPHORE_NORM,
    01515   BSW_SEMAPHORE_ENTRY,
    01516   BSW_SEMAPHORE_EXIT,
    01517   BSW_SEMAPHORE_COMBO,
    01518   BSW_SEMAPHORE_PBS,
    01519   BSW_SEMAPHORE_PBS_OWAY,
    01520   BSW_ELECTRIC_NORM,
    01521   BSW_ELECTRIC_ENTRY,
    01522   BSW_ELECTRIC_EXIT,
    01523   BSW_ELECTRIC_COMBO,
    01524   BSW_ELECTRIC_PBS,
    01525   BSW_ELECTRIC_PBS_OWAY,
    01526   BSW_CONVERT,
    01527   BSW_DRAG_SIGNALS_DENSITY,
    01528   BSW_DRAG_SIGNALS_DENSITY_LABEL,
    01529   BSW_DRAG_SIGNALS_DENSITY_DECREASE,
    01530   BSW_DRAG_SIGNALS_DENSITY_INCREASE,
    01531 };
    01532
    01533 struct BuildSignalWindow : public PickerWindowBase {
    01534 private:
    01542   void DrawSignalSprite(byte widget_index, SpriteID image) const
    01543   {
    01544     /* First get the right image, which is one later for 'green' signals. */
    01545     image += this->IsWidgetLowered(widget_index);
    01546
    01547     /* Next get the actual sprite so we can calculate the right offsets. */
    01548     const Sprite *sprite = GetSprite(image, ST_NORMAL);
    01549
    01550     /* For the x offset we want the sprite to be centered, so undo the offset
    01551      * for sprite drawing and add half of the sprite's width. For the y offset
    01552      * we want the sprite to be aligned on the bottom, so again we undo the
    01553      * offset for sprite drawing and assume it is the bottom of the sprite. */
    01554     int sprite_center_x_offset = sprite->x_offs + sprite->width / 2;
    01555     int sprite_bottom_y_offset = sprite->height + sprite->y_offs;
    01556
    01557     /* Next we want to know where on the window to draw. Calculate the center
    01558      * and the bottom of the area to draw. */
    01559     const NWidgetBase *widget = this->GetWidget<NWidgetBase>(widget_index);
    01560     int widget_center_x = widget->pos_x + widget->current_x / 2;
    01561     int widget_bottom_y = widget->pos_y + widget->current_y - 2;
    01562
    01563     /* Finally we draw the signal. */
    01564     DrawSprite(image, PAL_NONE,
    01565         widget_center_x - sprite_center_x_offset + this->IsWidgetLowered(widget_index),
    01566         widget_bottom_y - sprite_bottom_y_offset + this->IsWidgetLowered(widget_index));
    01567   }
    01568
    01569 public:
    01570   BuildSignalWindow(const WindowDesc *desc, Window *parent) : PickerWindowBase(parent)
    01571   {
    01572     this->InitNested(desc, TRANSPORT_RAIL);
    01573     this->OnInvalidateData();
    01574   };
    01575
    01576   virtual void SetStringParameters(int widget) const
    01577   {
    01578     switch (widget) {
    01579       case BSW_DRAG_SIGNALS_DENSITY_LABEL:
    01580         SetDParam(0, _settings_client.gui.drag_signals_density);
    01581         break;
    01582     }
    01583   }
    01584
    01585   virtual void OnPaint()
    01586   {
    01587     this->DrawWidgets();
    01588   }
    01589
    01590   virtual void DrawWidget(const Rect &r, int widget) const
    01591   {
    01592     if (IsInsideMM(widget, BSW_SEMAPHORE_NORM, BSW_ELECTRIC_PBS_OWAY + 1)) {
    01593       /* We need to do some custom sprite widget drawing for the signals. */
    01594       const SpriteID _signal_lookup[] = {
    01595         SPR_IMG_SIGNAL_SEMAPHORE_NORM,  SPR_IMG_SIGNAL_SEMAPHORE_ENTRY, SPR_IMG_SIGNAL_SEMAPHORE_EXIT,
    01596         SPR_IMG_SIGNAL_SEMAPHORE_COMBO, SPR_IMG_SIGNAL_SEMAPHORE_PBS,   SPR_IMG_SIGNAL_SEMAPHORE_PBS_OWAY,
    01597
    01598         SPR_IMG_SIGNAL_ELECTRIC_NORM,  SPR_IMG_SIGNAL_ELECTRIC_ENTRY, SPR_IMG_SIGNAL_ELECTRIC_EXIT,
    01599         SPR_IMG_SIGNAL_ELECTRIC_COMBO, SPR_IMG_SIGNAL_ELECTRIC_PBS,   SPR_IMG_SIGNAL_ELECTRIC_PBS_OWAY
    01600       };
    01601
    01602       this->DrawSignalSprite(widget, _signal_lookup[widget - BSW_SEMAPHORE_NORM]);
    01603     }
    01604   }
    01605
    01606   virtual void OnClick(Point pt, int widget, int click_count)
    01607   {
    01608     switch (widget) {
    01609       case BSW_SEMAPHORE_NORM:
    01610       case BSW_SEMAPHORE_ENTRY:
    01611       case BSW_SEMAPHORE_EXIT:
    01612       case BSW_SEMAPHORE_COMBO:
    01613       case BSW_SEMAPHORE_PBS:
    01614       case BSW_SEMAPHORE_PBS_OWAY:
    01615       case BSW_ELECTRIC_NORM:
    01616       case BSW_ELECTRIC_ENTRY:
    01617       case BSW_ELECTRIC_EXIT:
    01618       case BSW_ELECTRIC_COMBO:
    01619       case BSW_ELECTRIC_PBS:
    01620       case BSW_ELECTRIC_PBS_OWAY:
    01621         this->RaiseWidget((_cur_signal_variant == SIG_ELECTRIC ? BSW_ELECTRIC_NORM : BSW_SEMAPHORE_NORM) + _cur_signal_type);
    01622
    01623         _cur_signal_type = (SignalType)((uint)((widget - BSW_SEMAPHORE_NORM) % (SIGTYPE_LAST + 1)));
    01624         _cur_signal_variant = widget >= BSW_ELECTRIC_NORM ? SIG_ELECTRIC : SIG_SEMAPHORE;
    01625         break;
    01626
    01627       case BSW_CONVERT:
    01628         _convert_signal_button = !_convert_signal_button;
    01629         break;
    01630
    01631       case BSW_DRAG_SIGNALS_DENSITY_DECREASE:
    01632         if (_settings_client.gui.drag_signals_density > 1) {
    01633           _settings_client.gui.drag_signals_density--;
    01634           SetWindowDirty(WC_GAME_OPTIONS, 0);
    01635         }
    01636         break;
    01637
    01638       case BSW_DRAG_SIGNALS_DENSITY_INCREASE:
    01639         if (_settings_client.gui.drag_signals_density < 20) {
    01640           _settings_client.gui.drag_signals_density++;
    01641           SetWindowDirty(WC_GAME_OPTIONS, 0);
    01642         }
    01643         break;
    01644
    01645       default: break;
    01646     }
    01647
    01648     this->InvalidateData();
    01649   }
    01650
    01651   virtual void OnInvalidateData(int data = 0)
    01652   {
    01653     this->LowerWidget((_cur_signal_variant == SIG_ELECTRIC ? BSW_ELECTRIC_NORM : BSW_SEMAPHORE_NORM) + _cur_signal_type);
    01654
    01655     this->SetWidgetLoweredState(BSW_CONVERT, _convert_signal_button);
    01656
    01657     this->SetWidgetDisabledState(BSW_DRAG_SIGNALS_DENSITY_DECREASE, _settings_client.gui.drag_signals_density == 1);
    01658     this->SetWidgetDisabledState(BSW_DRAG_SIGNALS_DENSITY_INCREASE, _settings_client.gui.drag_signals_density == 20);
    01659   }
    01660 };
    01661
    01663 static const NWidgetPart _nested_signal_builder_widgets[] = {
    01664   NWidget(NWID_HORIZONTAL),
    01665     NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
    01666     NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_BUILD_SIGNAL_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    01667   EndContainer(),
    01668   NWidget(NWID_VERTICAL, NC_EQUALSIZE),
    01669     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
    01670       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BSW_SEMAPHORE_NORM), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_NORM_TOOLTIP), EndContainer(), SetFill(1, 1),
    01671       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BSW_SEMAPHORE_ENTRY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_ENTRY_TOOLTIP), EndContainer(), SetFill(1, 1),
    01672       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BSW_SEMAPHORE_EXIT), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_EXIT_TOOLTIP), EndContainer(), SetFill(1, 1),
    01673       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BSW_SEMAPHORE_COMBO), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_COMBO_TOOLTIP), EndContainer(), SetFill(1, 1),
    01674       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BSW_SEMAPHORE_PBS), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_TOOLTIP), EndContainer(), SetFill(1, 1),
    01675       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BSW_SEMAPHORE_PBS_OWAY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_SEMAPHORE_PBS_OWAY_TOOLTIP), EndContainer(), SetFill(1, 1),
    01676       NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, BSW_CONVERT), SetDataTip(SPR_IMG_SIGNAL_CONVERT, STR_BUILD_SIGNAL_CONVERT_TOOLTIP), SetFill(1, 1),
    01677     EndContainer(),
    01678     NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
    01679       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BSW_ELECTRIC_NORM), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_NORM_TOOLTIP), EndContainer(), SetFill(1, 1),
    01680       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BSW_ELECTRIC_ENTRY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_ENTRY_TOOLTIP), EndContainer(), SetFill(1, 1),
    01681       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BSW_ELECTRIC_EXIT), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_EXIT_TOOLTIP), EndContainer(), SetFill(1, 1),
    01682       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BSW_ELECTRIC_COMBO), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_COMBO_TOOLTIP), EndContainer(), SetFill(1, 1),
    01683       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BSW_ELECTRIC_PBS), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_PBS_TOOLTIP), EndContainer(), SetFill(1, 1),
    01684       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BSW_ELECTRIC_PBS_OWAY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_ELECTRIC_PBS_OWAY_TOOLTIP), EndContainer(), SetFill(1, 1),
    01685       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BSW_DRAG_SIGNALS_DENSITY), SetDataTip(STR_NULL, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP), SetFill(1, 1),
    01686         NWidget(WWT_LABEL, COLOUR_DARK_GREEN, BSW_DRAG_SIGNALS_DENSITY_LABEL), SetDataTip(STR_ORANGE_INT, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP), SetFill(1, 1),
    01687         NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2),
    01688           NWidget(NWID_SPACER), SetFill(1, 0),
    01689           NWidget(NWID_BUTTON_ARROW, COLOUR_GREY, BSW_DRAG_SIGNALS_DENSITY_DECREASE), SetMinimalSize(9, 12), SetDataTip(AWV_DECREASE, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP),
    01690           NWidget(NWID_BUTTON_ARROW, COLOUR_GREY, BSW_DRAG_SIGNALS_DENSITY_INCREASE), SetMinimalSize(9, 12), SetDataTip(AWV_INCREASE, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP),
    01691           NWidget(NWID_SPACER), SetFill(1, 0),
    01692         EndContainer(),
    01693         NWidget(NWID_SPACER), SetMinimalSize(0, 2), SetFill(1, 0),
    01694       EndContainer(),
    01695     EndContainer(),
    01696   EndContainer(),
    01697 };
    01698
    01700 static const WindowDesc _signal_builder_desc(
    01701   WDP_AUTO, 0, 0,
    01702   WC_BUILD_SIGNAL, WC_BUILD_TOOLBAR,
    01703   WDF_UNCLICK_BUTTONS | WDF_CONSTRUCTION,
    01704   _nested_signal_builder_widgets, lengthof(_nested_signal_builder_widgets)
    01705 );
    01706
    01710 static void ShowSignalBuilder(Window *parent)
    01711 {
    01712   new BuildSignalWindow(&_signal_builder_desc, parent);
    01713 }
    01714
    01716 enum BuildRailDepotWidgets {
    01717   BRDW_DEPOT_NE,
    01718   BRDW_DEPOT_SE,
    01719   BRDW_DEPOT_SW,
    01720   BRDW_DEPOT_NW,
    01721 };
    01722
    01723 struct BuildRailDepotWindow : public PickerWindowBase {
    01724   BuildRailDepotWindow(const WindowDesc *desc, Window *parent) : PickerWindowBase(parent)
    01725   {
    01726     this->InitNested(desc, TRANSPORT_RAIL);
    01727     this->LowerWidget(_build_depot_direction + BRDW_DEPOT_NE);
    01728   }
    01729
    01730   virtual void OnPaint()
    01731   {
    01732     this->DrawWidgets();
    01733   }
    01734
    01735   virtual void DrawWidget(const Rect &r, int widget) const
    01736   {
    01737     if (!IsInsideMM(widget, BRDW_DEPOT_NE, BRDW_DEPOT_NW + 1)) return;
    01738
    01739     DrawTrainDepotSprite(r.left - 1, r.top, widget - BRDW_DEPOT_NE + DIAGDIR_NE, _cur_railtype);
    01740   }
    01741
    01742   virtual void OnClick(Point pt, int widget, int click_count)
    01743   {
    01744     switch (widget) {
    01745       case BRDW_DEPOT_NE:
    01746       case BRDW_DEPOT_SE:
    01747       case BRDW_DEPOT_SW:
    01748       case BRDW_DEPOT_NW:
    01749         this->RaiseWidget(_build_depot_direction + BRDW_DEPOT_NE);
    01750         _build_depot_direction = (DiagDirection)(widget - BRDW_DEPOT_NE);
    01751         this->LowerWidget(_build_depot_direction + BRDW_DEPOT_NE);
    01752         SndPlayFx(SND_15_BEEP);
    01753         this->SetDirty();
    01754         break;
    01755     }
    01756   }
    01757 };
    01758
    01760 static const NWidgetPart _nested_build_depot_widgets[] = {
    01761   NWidget(NWID_HORIZONTAL),
    01762     NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
    01763     NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_BUILD_DEPOT_TRAIN_ORIENTATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    01764   EndContainer(),
    01765   NWidget(WWT_PANEL, COLOUR_DARK_GREEN),
    01766     NWidget(NWID_SPACER), SetMinimalSize(0, 3),
    01767     NWidget(NWID_HORIZONTAL_LTR),
    01768       NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0),
    01769       NWidget(NWID_VERTICAL),
    01770         NWidget(WWT_PANEL, COLOUR_GREY, BRDW_DEPOT_NW), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP),
    01771         EndContainer(),
    01772         NWidget(NWID_SPACER), SetMinimalSize(0, 2),
    01773         NWidget(WWT_PANEL, COLOUR_GREY, BRDW_DEPOT_SW), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP),
    01774         EndContainer(),
    01775       EndContainer(),
    01776       NWidget(NWID_SPACER), SetMinimalSize(2, 0),
    01777       NWidget(NWID_VERTICAL),
    01778         NWidget(WWT_PANEL, COLOUR_GREY, BRDW_DEPOT_NE), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP),
    01779         EndContainer(),
    01780         NWidget(NWID_SPACER), SetMinimalSize(0, 2),
    01781         NWidget(WWT_PANEL, COLOUR_GREY, BRDW_DEPOT_SE), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP),
    01782         EndContainer(),
    01783       EndContainer(),
    01784       NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0),
    01785     EndContainer(),
    01786     NWidget(NWID_SPACER), SetMinimalSize(0, 3),
    01787   EndContainer(),
    01788 };
    01789
    01790 static const WindowDesc _build_depot_desc(
    01791   WDP_AUTO, 0, 0,
    01792   WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
    01793   WDF_CONSTRUCTION,
    01794   _nested_build_depot_widgets, lengthof(_nested_build_depot_widgets)
    01795 );
    01796
    01797 static void ShowBuildTrainDepotPicker(Window *parent)
    01798 {
    01799   new BuildRailDepotWindow(&_build_depot_desc, parent);
    01800 }
    01801
    01803 enum BuildRailWaypointWidgets {
    01804   BRWW_WAYPOINT_1,
    01805   BRWW_WAYPOINT_2,
    01806   BRWW_WAYPOINT_3,
    01807   BRWW_WAYPOINT_4,
    01808   BRWW_WAYPOINT_5,
    01809   BRWW_SCROLL,
    01810 };
    01811
    01812 struct BuildRailWaypointWindow : PickerWindowBase {
    01813   BuildRailWaypointWindow(const WindowDesc *desc, Window *parent) : PickerWindowBase(parent)
    01814   {
    01815     this->InitNested(desc, TRANSPORT_RAIL);
    01816     this->hscroll.SetCapacity(5);
    01817     this->hscroll.SetCount(_waypoint_count);
    01818   };
    01819
    01820   virtual void OnPaint()
    01821   {
    01822     for (uint i = 0; i < this->hscroll.GetCapacity(); i++) {
    01823       this->SetWidgetLoweredState(i + BRWW_WAYPOINT_1, (this->hscroll.GetPosition() + i) == _cur_waypoint_type);
    01824     }
    01825
    01826     this->DrawWidgets();
    01827
    01828     for (uint i = 0; i < this->hscroll.GetCapacity(); i++) {
    01829       if (this->hscroll.GetPosition() + i < this->hscroll.GetCount()) {
    01830         const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, this->hscroll.GetPosition() + i);
    01831         NWidgetBase *nw = this->GetWidget<NWidgetBase>(BRWW_WAYPOINT_1 + i);
    01832
    01833         int bottom = nw->pos_y + nw->current_y;
    01834         DrawWaypointSprite(nw->pos_x + TILE_PIXELS, bottom - TILE_PIXELS, this->hscroll.GetPosition() + i, _cur_railtype);
    01835
    01836         if (statspec != NULL &&
    01837             HasBit(statspec->callback_mask, CBM_STATION_AVAIL) &&
    01838             GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) {
    01839           GfxFillRect(nw->pos_x + 1, nw->pos_y + 1, nw->pos_x + nw->current_x - 2, bottom - 2, 0, FILLRECT_CHECKER);
    01840         }
    01841       }
    01842     }
    01843   }
    01844
    01845   virtual void OnClick(Point pt, int widget, int click_count)
    01846   {
    01847     switch (widget) {
    01848       case BRWW_WAYPOINT_1:
    01849       case BRWW_WAYPOINT_2:
    01850       case BRWW_WAYPOINT_3:
    01851       case BRWW_WAYPOINT_4:
    01852       case BRWW_WAYPOINT_5: {
    01853         byte type = widget - BRWW_WAYPOINT_1 + this->hscroll.GetPosition();
    01854
    01855         /* Check station availability callback */
    01856         const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, type);
    01857         if (statspec != NULL &&
    01858             HasBit(statspec->callback_mask, CBM_STATION_AVAIL) &&
    01859             GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) return;
    01860
    01861         _cur_waypoint_type = type;
    01862         SndPlayFx(SND_15_BEEP);
    01863         this->SetDirty();
    01864         break;
    01865       }
    01866     }
    01867   }
    01868 };
    01869
    01871 static const NWidgetPart _nested_build_waypoint_widgets[] = {
    01872   NWidget(NWID_HORIZONTAL),
    01873     NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
    01874     NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_WAYPOINT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    01875   EndContainer(),
    01876   NWidget(WWT_PANEL, COLOUR_DARK_GREEN),
    01877     NWidget(NWID_SPACER), SetMinimalSize(0, 3),
    01878     NWidget(NWID_HORIZONTAL), SetPIP(3, 2, 3),
    01879       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BRWW_WAYPOINT_1), SetMinimalSize(66, 60), SetDataTip(0x0, STR_WAYPOINT_GRAPHICS_TOOLTIP), EndContainer(),
    01880       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BRWW_WAYPOINT_2), SetMinimalSize(66, 60), SetDataTip(0x0, STR_WAYPOINT_GRAPHICS_TOOLTIP), EndContainer(),
    01881       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BRWW_WAYPOINT_3), SetMinimalSize(66, 60), SetDataTip(0x0, STR_WAYPOINT_GRAPHICS_TOOLTIP), EndContainer(),
    01882       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BRWW_WAYPOINT_4), SetMinimalSize(66, 60), SetDataTip(0x0, STR_WAYPOINT_GRAPHICS_TOOLTIP), EndContainer(),
    01883       NWidget(WWT_PANEL, COLOUR_DARK_GREEN, BRWW_WAYPOINT_5), SetMinimalSize(66, 60), SetDataTip(0x0, STR_WAYPOINT_GRAPHICS_TOOLTIP), EndContainer(),
    01884     EndContainer(),
    01885     NWidget(NWID_SPACER), SetMinimalSize(0, 3),
    01886     NWidget(WWT_HSCROLLBAR, COLOUR_DARK_GREEN, BRWW_SCROLL),
    01887   EndContainer(),
    01888 };
    01889
    01890 static const WindowDesc _build_waypoint_desc(
    01891   WDP_AUTO, 0, 0,
    01892   WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
    01893   WDF_CONSTRUCTION,
    01894   _nested_build_waypoint_widgets, lengthof(_nested_build_waypoint_widgets)
    01895 );
    01896
    01897 static void ShowBuildWaypointPicker(Window *parent)
    01898 {
    01899   new BuildRailWaypointWindow(&_build_waypoint_desc, parent);
    01900 }
    01901
    01905 void InitializeRailGui()
    01906 {
    01907   _build_depot_direction = DIAGDIR_NW;
    01908 }
    01909
    01914 void ReinitGuiAfterToggleElrail(bool disable)
    01915 {
    01916   extern RailType _last_built_railtype;
    01917   if (disable && _last_built_railtype == RAILTYPE_ELECTRIC) {
    01918     _last_built_railtype = _cur_railtype = RAILTYPE_RAIL;
    01919     BuildRailToolbarWindow *w = dynamic_cast<BuildRailToolbarWindow *>(FindWindowById(WC_BUILD_TOOLBAR, TRANSPORT_RAIL));
    01920     if (w != NULL) w->ModifyRailType(_cur_railtype);
    01921   }
    01922   MarkWholeScreenDirty();
    01923 }
    01924
    01926 static void SetDefaultRailGui()
    01927 {
    01928   if (_local_company == COMPANY_SPECTATOR || !Company::IsValidID(_local_company)) return;
    01929
    01930   extern RailType _last_built_railtype;
    01931   RailType rt = (RailType)(_settings_client.gui.default_rail_type + RAILTYPE_END);
    01932   if (rt == DEF_RAILTYPE_MOST_USED) {
    01933     /* Find the most used rail type */
    01934     RailType count[RAILTYPE_END];
    01935     memset(count, 0, sizeof(count));
    01936     for (TileIndex t = 0; t < MapSize(); t++) {
    01937       if (IsTileType(t, MP_RAILWAY) || IsLevelCrossingTile(t) || HasStationTileRail(t) ||
    01938           (IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL)) {
    01939         count[GetRailType(t)]++;
    01940       }
    01941     }
    01942
    01943     rt = RAILTYPE_RAIL;
    01944     for (RailType r = RAILTYPE_ELECTRIC; r < RAILTYPE_END; r++) {
    01945       if (count[r] >= count[rt]) rt = r;
    01946     }
    01947
    01948     /* No rail, just get the first available one */
    01949     if (count[rt] == 0) rt = DEF_RAILTYPE_FIRST;
    01950   }
    01951   switch (rt) {
    01952     case DEF_RAILTYPE_FIRST:
    01953       rt = RAILTYPE_RAIL;
    01954       while (rt < RAILTYPE_END && !HasRailtypeAvail(_local_company, rt)) rt++;
    01955       break;
    01956
    01957     case DEF_RAILTYPE_LAST:
    01958       rt = GetBestRailtype(_local_company);
    01959       break;
    01960
    01961     default:
    01962       break;
    01963   }
    01964
    01965   _last_built_railtype = _cur_railtype = rt;
    01966   BuildRailToolbarWindow *w = dynamic_cast<BuildRailToolbarWindow *>(FindWindowById(WC_BUILD_TOOLBAR, TRANSPORT_RAIL));
    01967   if (w != NULL) w->ModifyRailType(_cur_railtype);
    01968 }
    01969
    01976 bool ResetSignalVariant(int32 p = 0)
    01977 {
    01978   SignalVariant new_variant = (_cur_year < _settings_client.gui.semaphore_build_before ? SIG_SEMAPHORE : SIG_ELECTRIC);
    01979
    01980   if (new_variant != _cur_signal_variant) {
    01981     Window *w = FindWindowById(WC_BUILD_SIGNAL, 0);
    01982     if (w != NULL) {
    01983       w->SetDirty();
    01984       w->RaiseWidget((_cur_signal_variant == SIG_ELECTRIC ? BSW_ELECTRIC_NORM : BSW_SEMAPHORE_NORM) + _cur_signal_type);
    01985     }
    01986     _cur_signal_variant = new_variant;
    01987   }
    01988
    01989   return true;
    01990 }
    01991
    01995 void InitializeRailGUI()
    01996 {
    01997   SetDefaultRailGui();
    01998
    01999   _convert_signal_button = false;
    02000   _cur_signal_type = _default_signal_type[_settings_client.gui.default_signal_type];
    02001   ResetSignalVariant();
    02002 }