4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
10 /** @file rail_gui.cpp %File for dealing with rail construction user interface */
14 #include "window_gui.h"
15 #include "station_gui.h"
16 #include "terraform_gui.h"
17 #include "viewport_func.h"
18 #include "command_func.h"
19 #include "waypoint_func.h"
20 #include "newgrf_station.h"
21 #include "company_base.h"
22 #include "strings_func.h"
23 #include "window_func.h"
24 #include "date_func.h"
25 #include "sound_func.h"
26 #include "company_func.h"
27 #include "widgets/dropdown_type.h"
28 #include "tunnelbridge.h"
29 #include "tilehighlight_func.h"
30 #include "spritecache.h"
31 #include "core/geometry_func.hpp"
33 #include "engine_base.h"
34 #include "vehicle_func.h"
35 #include "zoom_func.h"
38 #include "station_func.h"
43 #include "map/depot.h"
44 #include "map/bridge.h"
46 #include "widgets/rail_widget.h"
49 static RailType _cur_railtype
; ///< Rail type of the current build-rail toolbar.
50 static bool _remove_button_clicked
; ///< Flag whether 'remove' toggle-button is currently enabled
51 static DiagDirection _build_depot_direction
; ///< Currently selected depot direction
52 static byte _waypoint_count
= 1; ///< Number of waypoint types
53 static byte _cur_waypoint_type
; ///< Currently selected waypoint type
54 static bool _convert_signal_button
; ///< convert signal button in the signal GUI pressed
55 static SignalVariant _cur_signal_variant
; ///< set the signal variant (for signal GUI)
56 static SignalType _cur_signal_type
; ///< set the signal type (for signal GUI)
58 /* Map the setting: default_signal_type to the corresponding signal type */
59 static const SignalType _default_signal_type
[] = {SIGTYPE_NORMAL
, SIGTYPE_PBS
, SIGTYPE_PBS_ONEWAY
};
61 struct RailStationGUISettings
{
62 Axis orientation
; ///< Currently selected rail station orientation
64 bool newstations
; ///< Are custom station definitions available?
65 StationClassID station_class
; ///< Currently selected custom station class (if newstations is \c true )
66 byte station_type
; ///< %Station type within the currently selected custom station class (if newstations is \c true )
67 byte station_count
; ///< Number of custom stations (if newstations is \c true )
69 static RailStationGUISettings _railstation
; ///< Settings of the station builder GUI
72 /** Dragging actions in the rail toolbar. */
74 DRAG_DEMOLISH_AREA
, ///< Clear area
75 DRAG_BUILD_BRIDGE
, ///< Bridge placement
76 DRAG_PLACE_RAIL
, ///< Rail placement
77 DRAG_BUILD_SIGNALS
, ///< Signal placement
78 DRAG_STATION
, ///< Station placement/removal
79 DRAG_BUILD_WAYPOINT_X
, ///< Waypoint placement along AXIS_X
80 DRAG_BUILD_WAYPOINT_Y
, ///< Waypoint placement along AXIS_Y
81 DRAG_REMOVE_WAYPOINT
, ///< Waypoint removal
82 DRAG_CONVERT_RAIL
, ///< Rail conversion
86 static void HandleStationPlacement(TileIndex start
, TileIndex end
);
87 static void ShowBuildTrainDepotPicker(Window
*parent
);
88 static void ShowBuildWaypointPicker(Window
*parent
);
89 static void ShowStationBuilder(Window
*parent
);
90 static void ShowSignalBuilder(Window
*parent
);
93 * Check whether a station type can be build.
94 * @return true if building is allowed.
96 static bool IsStationAvailable(const StationSpec
*statspec
)
98 if (statspec
== NULL
|| !HasBit(statspec
->callback_mask
, CBM_STATION_AVAIL
)) return true;
100 uint16 cb_res
= GetStationCallback(CBID_STATION_AVAILABILITY
, 0, 0, statspec
, NULL
, INVALID_TILE
);
101 if (cb_res
== CALLBACK_FAILED
) return true;
103 return Convert8bitBooleanCallback(statspec
->grf_prop
.grffile
, CBID_STATION_AVAILABILITY
, cb_res
);
106 void CcPlaySound_SPLAT_RAIL(const CommandCost
&result
, TileIndex tile
, uint32 p1
, uint32 p2
)
108 if (result
.Succeeded() && _settings_client
.sound
.confirm
) SndPlayTileFx(SND_20_SPLAT_RAIL
, tile
);
111 void CcSingleRail(const CommandCost
&result
, TileIndex tile
, uint32 p1
, uint32 p2
)
113 if (HasBit(p1
, 31)) return;
115 CcPlaySound_SPLAT_RAIL(result
, tile
, p1
, p2
);
118 StringID
GetErrBuildSingleRail (TileIndex tile
, uint32 p1
, uint32 p2
, const char *text
)
120 return HasBit(p1
, 31) ? 0 : STR_ERROR_CAN_T_BUILD_RAILROAD_TRACK
;
123 void CcRailDepot(const CommandCost
&result
, TileIndex tile
, uint32 p1
, uint32 p2
)
125 struct PlaceDepotExtraData
{
126 DiagDirection dir
; ///< direction to check
127 Track track
; ///< track to build
130 static const PlaceDepotExtraData place_depot_extra_data
[4][3] = {
131 { {DIAGDIR_SE
, TRACK_LEFT
}, {DIAGDIR_SW
, TRACK_X
}, {DIAGDIR_NW
, TRACK_LOWER
} },
132 { {DIAGDIR_SW
, TRACK_UPPER
}, {DIAGDIR_NW
, TRACK_Y
}, {DIAGDIR_NE
, TRACK_LEFT
} },
133 { {DIAGDIR_SE
, TRACK_UPPER
}, {DIAGDIR_NE
, TRACK_X
}, {DIAGDIR_NW
, TRACK_RIGHT
} },
134 { {DIAGDIR_SW
, TRACK_RIGHT
}, {DIAGDIR_SE
, TRACK_Y
}, {DIAGDIR_NE
, TRACK_LOWER
} },
137 if (result
.Failed()) return;
139 DiagDirection dir
= (DiagDirection
)p2
;
141 if (_settings_client
.sound
.confirm
) SndPlayTileFx(SND_20_SPLAT_RAIL
, tile
);
142 if (!_settings_client
.gui
.persistent_buildingtools
) ResetPointerMode();
144 tile
+= TileOffsByDiagDir(dir
);
146 if (IsNormalRailTile(tile
) && !HasSignalOnTrack(tile
, TRACK_UPPER
) && !HasSignalOnTrack(tile
, TRACK_LOWER
)) {
147 for (int i
= 0; i
< 3; i
++) {
148 if ((GetTrackBits(tile
) & DiagdirReachesTracks(place_depot_extra_data
[dir
][i
].dir
)) != TRACK_BIT_NONE
) {
149 DoCommandP(tile
, _cur_railtype
| (1 << 31), place_depot_extra_data
[dir
][i
].track
, CMD_BUILD_SINGLE_RAIL
);
156 * Place a rail waypoint.
157 * @param tile Position to start dragging a waypoint.
159 static void PlaceRail_Waypoint(TileIndex tile
)
161 if (_remove_button_clicked
) {
162 VpStartPlaceSizing(tile
, VPM_X_AND_Y
, DRAG_REMOVE_WAYPOINT
);
166 switch (GetAxisForNewWaypoint(tile
)) {
168 VpStartPlaceSizing (tile
, VPM_Y
, DRAG_BUILD_WAYPOINT_X
);
172 VpStartPlaceSizing (tile
, VPM_X
, DRAG_BUILD_WAYPOINT_Y
);
176 /* Tile where we can't build rail waypoints. This is always going to fail,
177 * but provides the user with a proper error message. */
178 DoCommandP (tile
, 1 << 8 | 1 << 16, STAT_CLASS_WAYP
| INVALID_STATION
<< 16, CMD_BUILD_RAIL_WAYPOINT
);
182 VpSetPlaceSizingLimit (_settings_game
.station
.station_spread
);
185 void CcStation(const CommandCost
&result
, TileIndex tile
, uint32 p1
, uint32 p2
)
187 if (result
.Failed()) return;
189 if (_settings_client
.sound
.confirm
) SndPlayTileFx(SND_20_SPLAT_RAIL
, tile
);
190 /* Only close the station builder window if the default station and non persistent building is chosen. */
191 if (_railstation
.station_class
== STAT_CLASS_DFLT
&& _railstation
.station_type
== 0 && !_settings_client
.gui
.persistent_buildingtools
) ResetPointerMode();
195 * Place a rail station.
196 * @param tile Position to place or start dragging a station.
198 static void PlaceRail_Station(TileIndex tile
)
200 if (_remove_button_clicked
) {
201 VpStartPlaceSizing (tile
, VPM_X_AND_Y
, DRAG_STATION
);
202 } else if (_settings_client
.gui
.station_dragdrop
) {
203 VpStartPlaceSizing (tile
, VPM_X_AND_Y
, DRAG_STATION
, _settings_game
.station
.station_spread
);
205 uint32 p1
= _cur_railtype
| _railstation
.orientation
<< 4 | _settings_client
.gui
.station_numtracks
<< 8 | _settings_client
.gui
.station_platlength
<< 16 | _ctrl_pressed
<< 24;
206 uint32 p2
= _railstation
.station_class
| _railstation
.station_type
<< 8 | INVALID_STATION
<< 16;
208 int w
= _settings_client
.gui
.station_numtracks
;
209 int h
= _settings_client
.gui
.station_platlength
;
210 if (!_railstation
.orientation
) Swap(w
, h
);
212 Command
cmdcont (tile
, p1
, p2
, CMD_BUILD_RAIL_STATION
);
213 ShowSelectStationIfNeeded (&cmdcont
, TileArea(tile
, w
, h
));
217 StringID
GetErrBuildSignals (TileIndex tile
, uint32 p1
, uint32 p2
, const char *text
)
219 switch (GB(p1
, 17, 3)) {
220 case SIGNALS_CONVERT
:
221 case SIGNALS_TOGGLE_VARIANT
:
222 return STR_ERROR_SIGNAL_CAN_T_CONVERT_SIGNALS_HERE
;
225 return STR_ERROR_CAN_T_BUILD_SIGNALS_HERE
;
230 * Build a new signal or edit/remove a present signal, use CmdBuildSingleSignal() or CmdRemoveSingleSignal() in rail_cmd.cpp
232 * @param tile The tile where the signal will build or edit
234 static void GenericPlaceSignals(TileIndex tile
)
236 TrackBits trackbits
= TrackStatusToTrackBits(GetTileRailwayStatus(tile
));
238 if (trackbits
& TRACK_BIT_VERT
) { // N-S direction
239 trackbits
= (_tile_fract_coords
.x
<= _tile_fract_coords
.y
) ? TRACK_BIT_RIGHT
: TRACK_BIT_LEFT
;
242 if (trackbits
& TRACK_BIT_HORZ
) { // E-W direction
243 trackbits
= (_tile_fract_coords
.x
+ _tile_fract_coords
.y
<= 15) ? TRACK_BIT_UPPER
: TRACK_BIT_LOWER
;
246 Track track
= FindFirstTrack(trackbits
);
248 if (_remove_button_clicked
) {
249 DoCommandP(tile
, track
, 0, CMD_REMOVE_SIGNALS
);
251 const Window
*w
= FindWindowById(WC_BUILD_SIGNAL
, 0);
253 /* Map the setting cycle_signal_types to the allowed signal bitmask. */
254 static const uint signal_mask
[] = {
255 (1 << SIGTYPE_PBS
) - 1,
256 (1 << SIGTYPE_END
) - (1 << SIGTYPE_PBS
),
257 (1 << SIGTYPE_END
) - 1,
260 /* various bitstuffed elements for CmdBuildSingleSignal() */
264 /* signal GUI not used */
265 SB(p1
, 4, 1, ((_cur_year
< _settings_client
.gui
.semaphore_build_before
) ^ _ctrl_pressed
) ? SIG_SEMAPHORE
: SIG_ELECTRIC
);
266 SB(p1
, 5, 3, _default_signal_type
[_settings_client
.gui
.default_signal_type
]);
267 SB(p1
, 17, 3, _ctrl_pressed
? SIGNALS_CYCLE_TYPE
: SIGNALS_BUILD
);
268 } else if (!_convert_signal_button
) {
269 /* signal GUI is used, not converting */
270 SB(p1
, 4, 1, _cur_signal_variant
^ _ctrl_pressed
);
271 SB(p1
, 5, 3, _cur_signal_type
);
272 SB(p1
, 17, 3, _ctrl_pressed
? SIGNALS_CYCLE_TYPE
: SIGNALS_BUILD
);
274 /* signal GUI is used, converting */
275 SB(p1
, 4, 1, _cur_signal_variant
^ _ctrl_pressed
);
276 SB(p1
, 5, 3, _cur_signal_type
);
277 SB(p1
, 17, 3, _ctrl_pressed
? SIGNALS_TOGGLE_VARIANT
: SIGNALS_CONVERT
);
280 DoCommandP(tile
, p1
, signal_mask
[_settings_client
.gui
.cycle_signal_types
], CMD_BUILD_SIGNALS
);
284 /** Show the bridge building window between a pair of tiles. */
285 static void HandleBuildRailBridge (TileIndex start_tile
, TileIndex end_tile
)
287 if (!_settings_client
.gui
.persistent_buildingtools
) ResetPointerMode();
288 ShowBuildBridgeWindow (start_tile
, end_tile
, TRANSPORT_RAIL
, _cur_railtype
);
292 * Toggles state of the Remove button of Build rail toolbar
293 * @param w window the button belongs to
295 static void ToggleRailButton_Remove(Window
*w
)
297 DeleteWindowById(WC_SELECT_STATION
, 0);
298 w
->ToggleWidgetLoweredState(WID_RAT_REMOVE
);
299 w
->SetWidgetDirty(WID_RAT_REMOVE
);
300 _remove_button_clicked
= w
->IsWidgetLowered(WID_RAT_REMOVE
);
301 SetSelectionRed(_remove_button_clicked
);
305 * Updates the Remove button because of Ctrl state change
306 * @param w window the button belongs to
307 * @return true iff the remove button was changed
309 static bool RailToolbar_CtrlChanged(Window
*w
)
311 if (w
->IsWidgetDisabled(WID_RAT_REMOVE
)) return false;
313 /* allow ctrl to switch remove mode only for these widgets */
314 for (uint i
= WID_RAT_BUILD_NS
; i
<= WID_RAT_BUILD_STATION
; i
++) {
315 if ((i
<= WID_RAT_AUTORAIL
|| i
>= WID_RAT_BUILD_WAYPOINT
) && w
->IsWidgetLowered(i
)) {
316 ToggleRailButton_Remove(w
);
326 * The "remove"-button click proc of the build-rail toolbar.
327 * @param w Build-rail toolbar window
328 * @see BuildRailToolbarWindow::OnClick()
330 static void BuildRailClick_Remove(Window
*w
)
332 if (w
->IsWidgetDisabled(WID_RAT_REMOVE
)) return;
333 ToggleRailButton_Remove(w
);
334 if (_settings_client
.sound
.click_beep
) SndPlayFx(SND_15_BEEP
);
336 /* handle station builder */
337 if (w
->IsWidgetLowered(WID_RAT_BUILD_STATION
)) {
338 if (_remove_button_clicked
) {
339 /* starting drag & drop remove */
340 if (!_settings_client
.gui
.station_dragdrop
) {
341 SetTileSelectSize(1, 1);
343 VpSetPlaceSizingLimit (0);
346 /* starting station build mode */
347 if (!_settings_client
.gui
.station_dragdrop
) {
348 int x
= _settings_client
.gui
.station_numtracks
;
349 int y
= _settings_client
.gui
.station_platlength
;
350 if (_railstation
.orientation
== 0) Swap(x
, y
);
351 SetTileSelectSize(x
, y
);
353 VpSetPlaceSizingLimit(_settings_game
.station
.station_spread
);
356 } else if (w
->IsWidgetLowered(WID_RAT_BUILD_WAYPOINT
)) {
357 /* Dragging is different for waypoints when removing,
363 static void HandleAutodirPlacement (TileIndex start
, TileIndex end
)
365 Track track
= (Track
)(_thd
.drawstyle
& HT_TRACK_MASK
); // 0..5
366 assert (IsValidTrack (track
));
368 if (start
== end
) { // one-tile case
369 DoCommandP (end
, _cur_railtype
, track
,
370 _remove_button_clicked
? CMD_REMOVE_SINGLE_RAIL
: CMD_BUILD_SINGLE_RAIL
);
374 DoCommandP (start
, end
, _cur_railtype
| (track
<< 4),
375 _remove_button_clicked
? CMD_REMOVE_RAILROAD_TRACK
: CMD_BUILD_RAILROAD_TRACK
);
379 * Build new signals or remove signals or (if only one tile marked) edit a signal.
381 * If one tile marked abort and use GenericPlaceSignals()
382 * else use CmdBuildSingleSignal() or CmdRemoveSingleSignal() in rail_cmd.cpp to build many signals
384 static void HandleAutoSignalPlacement (TileIndex start
, TileIndex end
)
386 uint32 p2
= GB(_thd
.drawstyle
, 0, 3); // 0..5
388 if (start
== end
) { // one-tile case
389 GenericPlaceSignals (end
);
393 const Window
*w
= FindWindowById(WC_BUILD_SIGNAL
, 0);
396 /* signal GUI is used */
397 SB(p2
, 4, 1, _cur_signal_variant
);
398 SB(p2
, 6, 1, _ctrl_pressed
);
399 SB(p2
, 7, 3, _cur_signal_type
);
400 SB(p2
, 24, 8, _settings_client
.gui
.drag_signals_density
);
401 SB(p2
, 10, 1, !_settings_client
.gui
.drag_signals_fixed_distance
);
403 SB(p2
, 4, 1, (_cur_year
< _settings_client
.gui
.semaphore_build_before
? SIG_SEMAPHORE
: SIG_ELECTRIC
));
404 SB(p2
, 6, 1, _ctrl_pressed
);
405 SB(p2
, 7, 3, _default_signal_type
[_settings_client
.gui
.default_signal_type
]);
406 SB(p2
, 24, 8, _settings_client
.gui
.drag_signals_density
);
407 SB(p2
, 10, 1, !_settings_client
.gui
.drag_signals_fixed_distance
);
410 /* _settings_client.gui.drag_signals_density is given as a parameter such that each user
411 * in a network game can specify his/her own signal density */
412 DoCommandP (start
, end
, p2
,
413 _remove_button_clicked
? CMD_REMOVE_SIGNAL_TRACK
: CMD_BUILD_SIGNAL_TRACK
);
417 /** Rail toolbar management class. */
418 struct BuildRailToolbarWindow
: Window
{
419 RailType railtype
; ///< Rail type to build.
420 int last_user_action
; ///< Last started user action.
422 BuildRailToolbarWindow (const WindowDesc
*desc
, RailType railtype
) :
423 Window (desc
), railtype ((RailType
)0),
424 last_user_action (WIDGET_LIST_END
)
426 this->InitNested(TRANSPORT_RAIL
);
427 this->SetupRailToolbar(railtype
);
428 this->DisableWidget(WID_RAT_REMOVE
);
430 if (_settings_client
.gui
.link_terraform_toolbar
) ShowTerraformToolbar(this);
433 void OnDelete (void) FINAL_OVERRIDE
435 if (_settings_client
.gui
.link_terraform_toolbar
) DeleteWindowById(WC_SCEN_LAND_GEN
, 0, false);
439 * Some data on this window has become invalid.
440 * @param data Information about the changed data.
441 * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
443 virtual void OnInvalidateData(int data
= 0, bool gui_scope
= true)
445 if (!gui_scope
) return;
447 if (!CanBuildVehicleInfrastructure(VEH_TRAIN
)) this->Delete();
451 * Configures the rail toolbar for railtype given
452 * @param railtype the railtype to display
454 void SetupRailToolbar(RailType railtype
)
456 this->railtype
= railtype
;
457 const RailtypeInfo
*rti
= GetRailTypeInfo(railtype
);
459 assert(railtype
< RAILTYPE_END
);
460 this->GetWidget
<NWidgetCore
>(WID_RAT_BUILD_NS
)->widget_data
= rti
->gui_sprites
.build_ns_rail
;
461 this->GetWidget
<NWidgetCore
>(WID_RAT_BUILD_X
)->widget_data
= rti
->gui_sprites
.build_x_rail
;
462 this->GetWidget
<NWidgetCore
>(WID_RAT_BUILD_EW
)->widget_data
= rti
->gui_sprites
.build_ew_rail
;
463 this->GetWidget
<NWidgetCore
>(WID_RAT_BUILD_Y
)->widget_data
= rti
->gui_sprites
.build_y_rail
;
464 this->GetWidget
<NWidgetCore
>(WID_RAT_AUTORAIL
)->widget_data
= rti
->gui_sprites
.auto_rail
;
465 this->GetWidget
<NWidgetCore
>(WID_RAT_BUILD_DEPOT
)->widget_data
= rti
->gui_sprites
.build_depot
;
466 this->GetWidget
<NWidgetCore
>(WID_RAT_CONVERT_RAIL
)->widget_data
= rti
->gui_sprites
.convert_rail
;
467 this->GetWidget
<NWidgetCore
>(WID_RAT_BUILD_TUNNEL
)->widget_data
= rti
->gui_sprites
.build_tunnel
;
471 * Switch to another rail type.
472 * @param railtype New rail type.
474 void ModifyRailType(RailType railtype
)
476 this->SetupRailToolbar(railtype
);
480 void UpdateRemoveWidgetStatus(int clicked_widget
)
482 switch (clicked_widget
) {
484 /* If it is the removal button that has been clicked, do nothing,
485 * as it is up to the other buttons to drive removal status */
488 case WID_RAT_BUILD_NS
:
489 case WID_RAT_BUILD_X
:
490 case WID_RAT_BUILD_EW
:
491 case WID_RAT_BUILD_Y
:
492 case WID_RAT_AUTORAIL
:
493 case WID_RAT_BUILD_WAYPOINT
:
494 case WID_RAT_BUILD_STATION
:
495 case WID_RAT_BUILD_SIGNALS
:
496 /* Removal button is enabled only if the rail/signal/waypoint/station
497 * button is still lowered. Once raised, it has to be disabled */
498 this->SetWidgetDisabledState(WID_RAT_REMOVE
, !this->IsWidgetLowered(clicked_widget
));
502 /* When any other buttons than rail/signal/waypoint/station, raise and
503 * disable the removal button */
504 this->DisableWidget(WID_RAT_REMOVE
);
505 this->RaiseWidget(WID_RAT_REMOVE
);
510 virtual void SetStringParameters(int widget
) const
512 if (widget
== WID_RAT_CAPTION
) {
513 const RailtypeInfo
*rti
= GetRailTypeInfo(this->railtype
);
514 if (rti
->max_speed
> 0) {
515 SetDParam(0, STR_TOOLBAR_RAILTYPE_VELOCITY
);
516 SetDParam(1, rti
->strings
.toolbar_caption
);
517 SetDParam(2, rti
->max_speed
);
519 SetDParam(0, rti
->strings
.toolbar_caption
);
524 virtual void OnClick(Point pt
, int widget
, int click_count
)
526 if (widget
< WID_RAT_BUILD_NS
) return;
528 _remove_button_clicked
= false;
530 case WID_RAT_BUILD_NS
:
531 HandlePlacePushButton (this, WID_RAT_BUILD_NS
, GetRailTypeInfo(_cur_railtype
)->cursor
.rail_ns
, POINTER_RAIL_V
);
532 this->last_user_action
= widget
;
535 case WID_RAT_BUILD_X
:
536 HandlePlacePushButton (this, WID_RAT_BUILD_X
, GetRailTypeInfo(_cur_railtype
)->cursor
.rail_swne
, POINTER_RAIL_X
);
537 this->last_user_action
= widget
;
540 case WID_RAT_BUILD_EW
:
541 HandlePlacePushButton (this, WID_RAT_BUILD_EW
, GetRailTypeInfo(_cur_railtype
)->cursor
.rail_ew
, POINTER_RAIL_H
);
542 this->last_user_action
= widget
;
545 case WID_RAT_BUILD_Y
:
546 HandlePlacePushButton (this, WID_RAT_BUILD_Y
, GetRailTypeInfo(_cur_railtype
)->cursor
.rail_nwse
, POINTER_RAIL_Y
);
547 this->last_user_action
= widget
;
550 case WID_RAT_AUTORAIL
:
551 HandlePlacePushButton (this, WID_RAT_AUTORAIL
, GetRailTypeInfo(_cur_railtype
)->cursor
.autorail
, POINTER_RAIL_AUTO
);
552 this->last_user_action
= widget
;
555 case WID_RAT_DEMOLISH
:
556 HandlePlacePushButton (this, WID_RAT_DEMOLISH
, ANIMCURSOR_DEMOLISH
, POINTER_TILE
);
557 this->last_user_action
= widget
;
560 case WID_RAT_BUILD_DEPOT
:
561 if (HandlePlacePushButton (this, WID_RAT_BUILD_DEPOT
, GetRailTypeInfo(_cur_railtype
)->cursor
.depot
, POINTER_TILE
)) {
562 ShowBuildTrainDepotPicker(this);
563 this->last_user_action
= widget
;
567 case WID_RAT_BUILD_WAYPOINT
:
568 this->last_user_action
= widget
;
569 _waypoint_count
= StationClass::Get(STAT_CLASS_WAYP
)->GetSpecCount();
570 if (HandlePlacePushButton (this, WID_RAT_BUILD_WAYPOINT
, SPR_CURSOR_WAYPOINT
, POINTER_TILE
) && _waypoint_count
> 1) {
571 ShowBuildWaypointPicker(this);
575 case WID_RAT_BUILD_STATION
:
576 if (HandlePlacePushButton (this, WID_RAT_BUILD_STATION
, SPR_CURSOR_RAIL_STATION
, POINTER_TILE
)) {
577 ShowStationBuilder(this);
578 this->last_user_action
= widget
;
582 case WID_RAT_BUILD_SIGNALS
: {
583 this->last_user_action
= widget
;
584 bool started
= HandlePlacePushButton (this, WID_RAT_BUILD_SIGNALS
, ANIMCURSOR_BUILDSIGNALS
, POINTER_TILE
);
585 if (started
&& _settings_client
.gui
.enable_signal_gui
!= _ctrl_pressed
) {
586 ShowSignalBuilder(this);
591 case WID_RAT_BUILD_BRIDGE
:
592 HandlePlacePushButton (this, WID_RAT_BUILD_BRIDGE
, SPR_CURSOR_BRIDGE
, POINTER_TILE
);
593 this->last_user_action
= widget
;
596 case WID_RAT_BUILD_TUNNEL
:
597 HandlePlacePushButton (this, WID_RAT_BUILD_TUNNEL
, GetRailTypeInfo(_cur_railtype
)->cursor
.tunnel
, POINTER_AREA
);
598 this->last_user_action
= widget
;
602 BuildRailClick_Remove(this);
605 case WID_RAT_CONVERT_RAIL
:
606 HandlePlacePushButton (this, WID_RAT_CONVERT_RAIL
, GetRailTypeInfo(_cur_railtype
)->cursor
.convert
, POINTER_TILE
);
607 this->last_user_action
= widget
;
610 default: NOT_REACHED();
612 this->UpdateRemoveWidgetStatus(widget
);
613 if (_ctrl_pressed
) RailToolbar_CtrlChanged(this);
616 virtual EventState
OnHotkey(int hotkey
)
618 MarkTileDirtyByTile(TileVirtXY(_thd
.pos
.x
, _thd
.pos
.y
)); // redraw tile selection
619 return Window::OnHotkey(hotkey
);
622 virtual void OnPlaceObject(Point pt
, TileIndex tile
)
624 switch (this->last_user_action
) {
625 case WID_RAT_BUILD_NS
:
626 case WID_RAT_BUILD_X
:
627 case WID_RAT_BUILD_EW
:
628 case WID_RAT_BUILD_Y
:
629 case WID_RAT_AUTORAIL
:
630 VpStartPlaceSizing(tile
, VPM_RAILDIRS
, DRAG_PLACE_RAIL
);
633 case WID_RAT_DEMOLISH
:
634 VpStartPlaceSizing(tile
, VPM_X_AND_Y_ROTATED
, DRAG_DEMOLISH_AREA
);
637 case WID_RAT_BUILD_DEPOT
:
638 DoCommandP(tile
, _cur_railtype
, _build_depot_direction
, CMD_BUILD_TRAIN_DEPOT
);
641 case WID_RAT_BUILD_WAYPOINT
:
642 PlaceRail_Waypoint(tile
);
645 case WID_RAT_BUILD_STATION
:
646 PlaceRail_Station(tile
);
649 case WID_RAT_BUILD_SIGNALS
:
650 VpStartPlaceSizing (tile
, VPM_RAILDIRS
, DRAG_BUILD_SIGNALS
);
653 case WID_RAT_BUILD_BRIDGE
:
654 if (IsBridgeHeadTile(tile
)) {
655 TileIndex other_tile
= GetOtherBridgeEnd (tile
);
656 HandleBuildRailBridge (other_tile
, tile
);
658 VpStartPlaceSizing (tile
, VPM_X_OR_Y
, DRAG_BUILD_BRIDGE
);
662 case WID_RAT_BUILD_TUNNEL
:
663 DoCommandP(tile
, _cur_railtype
| (TRANSPORT_RAIL
<< 8), 0, CMD_BUILD_TUNNEL
);
666 case WID_RAT_CONVERT_RAIL
:
667 VpStartPlaceSizing(tile
, VPM_X_AND_Y_ROTATED
, DRAG_CONVERT_RAIL
);
670 default: NOT_REACHED();
674 bool OnPlaceDrag (int userdata
, Point pt
) OVERRIDE
676 /* no dragging if you have pressed the convert button */
677 return (FindWindowById (WC_BUILD_SIGNAL
, 0) == NULL
)
678 || !_convert_signal_button
679 || !this->IsWidgetLowered (WID_RAT_BUILD_SIGNALS
);
682 void OnPlaceMouseUp (int userdata
, Point pt
, TileIndex start_tile
, TileIndex end_tile
) OVERRIDE
686 default: NOT_REACHED();
687 case DRAG_BUILD_BRIDGE
:
688 HandleBuildRailBridge (start_tile
, end_tile
);
691 case DRAG_PLACE_RAIL
:
692 HandleAutodirPlacement (start_tile
, end_tile
);
695 case DRAG_BUILD_SIGNALS
:
696 HandleAutoSignalPlacement (start_tile
, end_tile
);
699 case DRAG_DEMOLISH_AREA
:
700 HandleDemolishMouseUp (start_tile
, end_tile
);
703 case DRAG_CONVERT_RAIL
:
704 DoCommandP(end_tile
, start_tile
, _cur_railtype
| (_ctrl_pressed
? 0x10 : 0), CMD_CONVERT_RAIL
);
708 if (_remove_button_clicked
) {
709 DoCommandP (end_tile
, start_tile
, _ctrl_pressed
? 0 : 1, CMD_REMOVE_FROM_RAIL_STATION
);
711 HandleStationPlacement (start_tile
, end_tile
);
715 case DRAG_BUILD_WAYPOINT_X
:
716 case DRAG_BUILD_WAYPOINT_Y
: {
717 TileArea
ta (start_tile
, end_tile
);
718 uint32 p1
= _cur_railtype
| (userdata
== DRAG_BUILD_WAYPOINT_X
? AXIS_X
: AXIS_Y
) << 4 | ta
.w
<< 8 | ta
.h
<< 16 | _ctrl_pressed
<< 24;
719 uint32 p2
= STAT_CLASS_WAYP
| _cur_waypoint_type
<< 8 | INVALID_STATION
<< 16;
721 Command
cmdcont (ta
.tile
, p1
, p2
, CMD_BUILD_RAIL_WAYPOINT
);
722 ShowSelectWaypointIfNeeded (&cmdcont
, ta
);
726 case DRAG_REMOVE_WAYPOINT
:
727 DoCommandP (end_tile
, start_tile
, _ctrl_pressed
? 0 : 1, CMD_REMOVE_FROM_RAIL_WAYPOINT
);
733 virtual void OnPlaceObjectAbort()
735 this->RaiseButtons();
736 this->DisableWidget(WID_RAT_REMOVE
);
737 this->SetWidgetDirty(WID_RAT_REMOVE
);
739 DeleteWindowById(WC_BUILD_SIGNAL
, TRANSPORT_RAIL
);
740 DeleteWindowById(WC_BUILD_STATION
, TRANSPORT_RAIL
);
741 DeleteWindowById(WC_BUILD_DEPOT
, TRANSPORT_RAIL
);
742 DeleteWindowById(WC_BUILD_WAYPOINT
, TRANSPORT_RAIL
);
743 DeleteWindowById(WC_SELECT_STATION
, 0);
744 DeleteWindowByClass(WC_BUILD_BRIDGE
);
747 void OnPlacePresize (TileIndex
*tile
, TileIndex
*tile2
) OVERRIDE
749 DoCommand (*tile
, _cur_railtype
| (TRANSPORT_RAIL
<< 8), 0, DC_AUTO
, CMD_BUILD_TUNNEL
);
750 if (_build_tunnel_endtile
!= 0) *tile2
= _build_tunnel_endtile
;
753 virtual EventState
OnCTRLStateChange()
755 /* do not toggle Remove button by Ctrl when placing station */
756 if (!this->IsWidgetLowered(WID_RAT_BUILD_STATION
) && !this->IsWidgetLowered(WID_RAT_BUILD_WAYPOINT
) && RailToolbar_CtrlChanged(this)) return ES_HANDLED
;
757 return ES_NOT_HANDLED
;
760 static HotkeyList hotkeys
;
764 * Handler for global hotkeys of the BuildRailToolbarWindow.
765 * @param hotkey Hotkey
766 * @return ES_HANDLED if hotkey was accepted.
768 static EventState
RailToolbarGlobalHotkeys(int hotkey
)
770 if (_game_mode
!= GM_NORMAL
|| !CanBuildVehicleInfrastructure(VEH_TRAIN
)) return ES_NOT_HANDLED
;
771 extern RailType _last_built_railtype
;
772 Window
*w
= ShowBuildRailToolbar(_last_built_railtype
);
773 if (w
== NULL
) return ES_NOT_HANDLED
;
774 return w
->OnHotkey(hotkey
);
777 static const Hotkey railtoolbar_hotkeys
[] = {
778 Hotkey ("build_ns", WID_RAT_BUILD_NS
, '1'),
779 Hotkey ("build_x", WID_RAT_BUILD_X
, '2'),
780 Hotkey ("build_ew", WID_RAT_BUILD_EW
, '3'),
781 Hotkey ("build_y", WID_RAT_BUILD_Y
, '4'),
782 Hotkey ("autorail", WID_RAT_AUTORAIL
, '5', 'A' | WKC_GLOBAL_HOTKEY
),
783 Hotkey ("demolish", WID_RAT_DEMOLISH
, '6'),
784 Hotkey ("depot", WID_RAT_BUILD_DEPOT
, '7'),
785 Hotkey ("waypoint", WID_RAT_BUILD_WAYPOINT
, '8'),
786 Hotkey ("station", WID_RAT_BUILD_STATION
, '9'),
787 Hotkey ("signal", WID_RAT_BUILD_SIGNALS
, 'S'),
788 Hotkey ("bridge", WID_RAT_BUILD_BRIDGE
, 'B'),
789 Hotkey ("tunnel", WID_RAT_BUILD_TUNNEL
, 'T'),
790 Hotkey ("remove", WID_RAT_REMOVE
, 'R'),
791 Hotkey ("convert", WID_RAT_CONVERT_RAIL
, 'C'),
793 HotkeyList
BuildRailToolbarWindow::hotkeys("railtoolbar", railtoolbar_hotkeys
, RailToolbarGlobalHotkeys
);
795 static const NWidgetPart _nested_build_rail_widgets
[] = {
796 NWidget(NWID_HORIZONTAL
),
797 NWidget(WWT_CLOSEBOX
, COLOUR_DARK_GREEN
),
798 NWidget(WWT_CAPTION
, COLOUR_DARK_GREEN
, WID_RAT_CAPTION
), SetDataTip(STR_WHITE_STRING
, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS
),
799 NWidget(WWT_STICKYBOX
, COLOUR_DARK_GREEN
),
801 NWidget(NWID_HORIZONTAL
),
802 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_RAT_BUILD_NS
),
803 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_NS
, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK
),
804 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_RAT_BUILD_X
),
805 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_NE
, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK
),
806 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_RAT_BUILD_EW
),
807 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_EW
, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK
),
808 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_RAT_BUILD_Y
),
809 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_NW
, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TRACK
),
810 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_RAT_AUTORAIL
),
811 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTORAIL
, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_AUTORAIL
),
813 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
), SetMinimalSize(4, 22), SetDataTip(0x0, STR_NULL
), EndContainer(),
815 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_RAT_DEMOLISH
),
816 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE
, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC
),
817 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_RAT_BUILD_DEPOT
),
818 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DEPOT_RAIL
, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_TRAIN_DEPOT_FOR_BUILDING
),
819 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_RAT_BUILD_WAYPOINT
),
820 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_WAYPOINT
, STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL_TO_WAYPOINT
),
821 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_RAT_BUILD_STATION
),
822 SetFill(0, 1), SetMinimalSize(42, 22), SetDataTip(SPR_IMG_RAIL_STATION
, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_STATION
),
823 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_RAT_BUILD_SIGNALS
),
824 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_RAIL_SIGNALS
, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_SIGNALS
),
825 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_RAT_BUILD_BRIDGE
),
826 SetFill(0, 1), SetMinimalSize(42, 22), SetDataTip(SPR_IMG_BRIDGE
, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_BRIDGE
),
827 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_RAT_BUILD_TUNNEL
),
828 SetFill(0, 1), SetMinimalSize(20, 22), SetDataTip(SPR_IMG_TUNNEL_RAIL
, STR_RAIL_TOOLBAR_TOOLTIP_BUILD_RAILROAD_TUNNEL
),
829 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_RAT_REMOVE
),
830 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE
, STR_RAIL_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR
),
831 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_RAT_CONVERT_RAIL
),
832 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_CONVERT_RAIL
, STR_RAIL_TOOLBAR_TOOLTIP_CONVERT_RAIL
),
836 static WindowDesc::Prefs
_build_rail_prefs ("toolbar_rail");
838 static const WindowDesc
_build_rail_desc(
839 WDP_ALIGN_TOOLBAR
, 0, 0,
840 WC_BUILD_TOOLBAR
, WC_NONE
,
842 _nested_build_rail_widgets
, lengthof(_nested_build_rail_widgets
),
843 &_build_rail_prefs
, &BuildRailToolbarWindow::hotkeys
848 * Open the build rail toolbar window for a specific rail type.
850 * If the terraform toolbar is linked to the toolbar, that window is also opened.
852 * @param railtype Rail type to open the window for
853 * @return newly opened rail toolbar, or NULL if the toolbar could not be opened.
855 Window
*ShowBuildRailToolbar(RailType railtype
)
857 if (!Company::IsValidID(_local_company
)) return NULL
;
858 if (!ValParamRailtype(railtype
)) return NULL
;
860 DeleteWindowByClass(WC_BUILD_TOOLBAR
);
861 _cur_railtype
= railtype
;
862 _remove_button_clicked
= false;
863 return new BuildRailToolbarWindow(&_build_rail_desc
, railtype
);
866 /* TODO: For custom stations, respect their allowed platforms/lengths bitmasks!
869 static void HandleStationPlacement(TileIndex start
, TileIndex end
)
871 TileArea
ta(start
, end
);
872 uint numtracks
= ta
.w
;
873 uint platlength
= ta
.h
;
875 if (_railstation
.orientation
== AXIS_X
) Swap(numtracks
, platlength
);
877 uint32 p1
= _cur_railtype
| _railstation
.orientation
<< 4 | numtracks
<< 8 | platlength
<< 16 | _ctrl_pressed
<< 24;
878 uint32 p2
= _railstation
.station_class
| _railstation
.station_type
<< 8 | INVALID_STATION
<< 16;
880 Command
cmdcont (ta
.tile
, p1
, p2
, CMD_BUILD_RAIL_STATION
);
881 ShowSelectStationIfNeeded (&cmdcont
, ta
);
884 /** Draw a station preview in a widget. */
885 static void DrawStationPreview (BlitArea
*dpi
, const Rect
&r
,
886 StationClassID cls
, uint type
, uint image
, bool check_avail
)
888 /* Set up a clipping area for the station preview. */
890 if (InitBlitArea (dpi
, &tmp_dpi
, r
.left
, r
.top
, r
.right
- r
.left
+ 1, r
.bottom
- r
.top
+ 1)) {
891 int x
= ScaleGUITrad(31) + 1;
892 int y
= r
.bottom
- r
.top
- ScaleGUITrad(31);
893 if (!DrawStationTile (&tmp_dpi
, x
, y
, _cur_railtype
, (Axis
)(image
% 2), cls
, type
)) {
894 RailStationPickerDrawSprite (&tmp_dpi
, x
, y
, cls
== STAT_CLASS_WAYP
, _cur_railtype
, image
);
898 /* Check station availability callback */
899 if (check_avail
&& !IsStationAvailable (StationClass::Get(cls
)->GetSpec(type
))) {
900 GfxFillRect (dpi
, r
.left
+ 1, r
.top
+ 1, r
.right
- 1, r
.bottom
- 1, PC_BLACK
, FILLRECT_CHECKER
);
904 struct BuildRailStationWindow
: public PickerWindowBase
{
906 uint line_height
; ///< Height of a single line in the newstation selection matrix (#WID_BRAS_NEWST_LIST widget).
907 uint coverage_height
; ///< Height of the coverage texts.
908 Scrollbar
*vscroll
; ///< Vertical scrollbar of the new station list.
909 Scrollbar
*vscroll2
; ///< Vertical scrollbar of the matrix with new stations.
912 * Verify whether the currently selected station size is allowed after selecting a new station class/type.
913 * If not, change the station size variables ( _settings_client.gui.station_numtracks and _settings_client.gui.station_platlength ).
914 * @param statspec Specification of the new station class/type
916 void CheckSelectedSize(const StationSpec
*statspec
)
918 if (statspec
== NULL
|| _settings_client
.gui
.station_dragdrop
) return;
920 /* If current number of tracks is not allowed, make it as big as possible */
921 if (HasBit(statspec
->disallowed_platforms
, _settings_client
.gui
.station_numtracks
- 1)) {
922 this->RaiseWidget(_settings_client
.gui
.station_numtracks
+ WID_BRAS_PLATFORM_NUM_BEGIN
);
923 _settings_client
.gui
.station_numtracks
= 1;
924 if (statspec
->disallowed_platforms
!= UINT8_MAX
) {
925 while (HasBit(statspec
->disallowed_platforms
, _settings_client
.gui
.station_numtracks
- 1)) {
926 _settings_client
.gui
.station_numtracks
++;
928 this->LowerWidget(_settings_client
.gui
.station_numtracks
+ WID_BRAS_PLATFORM_NUM_BEGIN
);
932 if (HasBit(statspec
->disallowed_lengths
, _settings_client
.gui
.station_platlength
- 1)) {
933 this->RaiseWidget(_settings_client
.gui
.station_platlength
+ WID_BRAS_PLATFORM_LEN_BEGIN
);
934 _settings_client
.gui
.station_platlength
= 1;
935 if (statspec
->disallowed_lengths
!= UINT8_MAX
) {
936 while (HasBit(statspec
->disallowed_lengths
, _settings_client
.gui
.station_platlength
- 1)) {
937 _settings_client
.gui
.station_platlength
++;
939 this->LowerWidget(_settings_client
.gui
.station_platlength
+ WID_BRAS_PLATFORM_LEN_BEGIN
);
945 BuildRailStationWindow (const WindowDesc
*desc
, Window
*parent
, bool newstation
) :
946 PickerWindowBase (desc
, parent
), line_height (0),
947 coverage_height (2 * FONT_HEIGHT_NORMAL
+ 3 * WD_PAR_VSEP_NORMAL
),
948 vscroll (NULL
), vscroll2 (NULL
)
950 _railstation
.newstations
= newstation
;
952 this->CreateNestedTree();
953 NWidgetStacked
*newst_additions
= this->GetWidget
<NWidgetStacked
>(WID_BRAS_SHOW_NEWST_ADDITIONS
);
954 newst_additions
->SetDisplayedPlane(newstation
? 0 : SZSP_NONE
);
955 newst_additions
= this->GetWidget
<NWidgetStacked
>(WID_BRAS_SHOW_NEWST_MATRIX
);
956 newst_additions
->SetDisplayedPlane(newstation
? 0 : SZSP_NONE
);
957 newst_additions
= this->GetWidget
<NWidgetStacked
>(WID_BRAS_SHOW_NEWST_DEFSIZE
);
958 newst_additions
->SetDisplayedPlane(newstation
? 0 : SZSP_NONE
);
959 newst_additions
= this->GetWidget
<NWidgetStacked
>(WID_BRAS_SHOW_NEWST_RESIZE
);
960 newst_additions
->SetDisplayedPlane(newstation
? 0 : SZSP_NONE
);
962 this->vscroll
= this->GetScrollbar(WID_BRAS_NEWST_SCROLL
);
963 this->vscroll2
= this->GetScrollbar(WID_BRAS_MATRIX_SCROLL
);
965 this->InitNested(TRANSPORT_RAIL
);
967 this->LowerWidget(_railstation
.orientation
+ WID_BRAS_PLATFORM_DIR_X
);
968 if (_settings_client
.gui
.station_dragdrop
) {
969 this->LowerWidget(WID_BRAS_PLATFORM_DRAG_N_DROP
);
971 this->LowerWidget(_settings_client
.gui
.station_numtracks
+ WID_BRAS_PLATFORM_NUM_BEGIN
);
972 this->LowerWidget(_settings_client
.gui
.station_platlength
+ WID_BRAS_PLATFORM_LEN_BEGIN
);
974 this->SetWidgetLoweredState(WID_BRAS_HIGHLIGHT_OFF
, !_settings_client
.gui
.station_show_coverage
);
975 this->SetWidgetLoweredState(WID_BRAS_HIGHLIGHT_ON
, _settings_client
.gui
.station_show_coverage
);
977 if (!newstation
|| _railstation
.station_class
>= (int)StationClass::GetClassCount()) {
978 /* New stations are not available or changed, so ensure the default station
979 * type is 'selected'. */
980 _railstation
.station_class
= STAT_CLASS_DFLT
;
981 _railstation
.station_type
= 0;
982 this->vscroll2
= NULL
;
985 _railstation
.station_count
= StationClass::Get(_railstation
.station_class
)->GetSpecCount();
986 _railstation
.station_type
= min(_railstation
.station_type
, _railstation
.station_count
- 1);
989 for (uint i
= 0; i
< StationClass::GetClassCount(); i
++) {
990 if (i
== STAT_CLASS_WAYP
) continue;
993 this->vscroll
->SetCount(count
);
994 this->vscroll
->SetPosition(Clamp(_railstation
.station_class
- 2, 0, max(this->vscroll
->GetCount() - this->vscroll
->GetCapacity(), 0)));
996 NWidgetMatrix
*matrix
= this->GetWidget
<NWidgetMatrix
>(WID_BRAS_MATRIX
);
997 matrix
->SetScrollbar(this->vscroll2
);
998 matrix
->SetCount(_railstation
.station_count
);
999 matrix
->SetClicked(_railstation
.station_type
);
1003 void OnDelete (void) FINAL_OVERRIDE
1005 DeleteWindowById(WC_SELECT_STATION
, 0);
1006 this->PickerWindowBase::OnDelete();
1009 void OnPaint (BlitArea
*dpi
) OVERRIDE
1011 bool newstations
= _railstation
.newstations
;
1012 const StationSpec
*statspec
= newstations
? StationClass::Get(_railstation
.station_class
)->GetSpec(_railstation
.station_type
) : NULL
;
1014 if (_settings_client
.gui
.station_dragdrop
) {
1015 SetTileSelectSize(1, 1);
1017 int x
= _settings_client
.gui
.station_numtracks
;
1018 int y
= _settings_client
.gui
.station_platlength
;
1019 if (_railstation
.orientation
== AXIS_X
) Swap(x
, y
);
1020 if (!_remove_button_clicked
) {
1021 SetTileSelectSize(x
, y
);
1025 int rad
= (_settings_game
.station
.modified_catchment
) ? CA_TRAIN
: CA_UNMODIFIED
;
1027 if (_settings_client
.gui
.station_show_coverage
) SetTileSelectBigSize(-rad
, -rad
, 2 * rad
, 2 * rad
);
1029 for (uint bits
= 0; bits
< 7; bits
++) {
1030 bool disable
= bits
>= _settings_game
.station
.station_spread
;
1031 if (statspec
== NULL
) {
1032 this->SetWidgetDisabledState(bits
+ WID_BRAS_PLATFORM_NUM_1
, disable
);
1033 this->SetWidgetDisabledState(bits
+ WID_BRAS_PLATFORM_LEN_1
, disable
);
1035 this->SetWidgetDisabledState(bits
+ WID_BRAS_PLATFORM_NUM_1
, HasBit(statspec
->disallowed_platforms
, bits
) || disable
);
1036 this->SetWidgetDisabledState(bits
+ WID_BRAS_PLATFORM_LEN_1
, HasBit(statspec
->disallowed_lengths
, bits
) || disable
);
1040 this->DrawWidgets (dpi
);
1042 /* 'Accepts' and 'Supplies' texts. */
1043 NWidgetBase
*cov
= this->GetWidget
<NWidgetBase
>(WID_BRAS_COVERAGE_TEXTS
);
1044 int top
= cov
->pos_y
+ WD_PAR_VSEP_NORMAL
;
1045 int left
= cov
->pos_x
+ WD_FRAMERECT_LEFT
;
1046 int right
= cov
->pos_x
+ cov
->current_x
- WD_FRAMERECT_RIGHT
;
1047 int bottom
= cov
->pos_y
+ cov
->current_y
;
1048 top
= DrawStationCoverageAreaText (dpi
, left
, right
, top
, rad
);
1049 /* Resize background if the window is too small.
1050 * Never make the window smaller to avoid oscillating if the size change affects the acceptance.
1051 * (This is the case, if making the window bigger moves the mouse into the window.) */
1053 this->coverage_height
+= top
- bottom
;
1058 virtual void UpdateWidgetSize(int widget
, Dimension
*size
, const Dimension
&padding
, Dimension
*fill
, Dimension
*resize
)
1061 case WID_BRAS_NEWST_LIST
: {
1062 Dimension d
= {0, 0};
1063 for (uint i
= 0; i
< StationClass::GetClassCount(); i
++) {
1064 if (i
== STAT_CLASS_WAYP
) continue;
1065 d
= maxdim(d
, GetStringBoundingBox(StationClass::Get((StationClassID
)i
)->name
));
1067 size
->width
= max(size
->width
, d
.width
+ padding
.width
);
1068 this->line_height
= FONT_HEIGHT_NORMAL
+ WD_MATRIX_TOP
+ WD_MATRIX_BOTTOM
;
1069 size
->height
= 5 * this->line_height
;
1070 resize
->height
= this->line_height
;
1074 case WID_BRAS_SHOW_NEWST_TYPE
: {
1075 if (!_railstation
.newstations
) {
1081 /* If newstations exist, compute the non-zero minimal size. */
1082 Dimension d
= {0, 0};
1083 StringID str
= this->GetWidget
<NWidgetCore
>(widget
)->widget_data
;
1084 for (StationClassID statclass
= STAT_CLASS_BEGIN
; statclass
< (StationClassID
)StationClass::GetClassCount(); statclass
++) {
1085 if (statclass
== STAT_CLASS_WAYP
) continue;
1086 StationClass
*stclass
= StationClass::Get(statclass
);
1087 for (uint16 j
= 0; j
< stclass
->GetSpecCount(); j
++) {
1088 const StationSpec
*statspec
= stclass
->GetSpec(j
);
1089 SetDParam(0, (statspec
!= NULL
&& statspec
->name
!= 0) ? statspec
->name
: STR_STATION_CLASS_DFLT
);
1090 d
= maxdim(d
, GetStringBoundingBox(str
));
1093 size
->width
= max(size
->width
, d
.width
+ padding
.width
);
1097 case WID_BRAS_PLATFORM_DIR_X
:
1098 case WID_BRAS_PLATFORM_DIR_Y
:
1099 case WID_BRAS_IMAGE
:
1100 size
->width
= ScaleGUITrad(64) + 2;
1101 size
->height
= ScaleGUITrad(58) + 2;
1104 case WID_BRAS_COVERAGE_TEXTS
:
1105 size
->height
= this->coverage_height
;
1108 case WID_BRAS_MATRIX
:
1115 void DrawWidget (BlitArea
*dpi
, const Rect
&r
, int widget
) const OVERRIDE
1117 int widn
= GB(widget
, 0, 16);
1119 case WID_BRAS_PLATFORM_DIR_X
:
1120 case WID_BRAS_PLATFORM_DIR_Y
:
1121 assert_compile (WID_BRAS_PLATFORM_DIR_X
== 0);
1122 assert_compile (WID_BRAS_PLATFORM_DIR_Y
== 1);
1123 DrawStationPreview (dpi
, r
, _railstation
.station_class
, _railstation
.station_type
, 2 + widn
, false);
1126 case WID_BRAS_NEWST_LIST
: {
1129 for (uint i
= 0; i
< StationClass::GetClassCount(); i
++) {
1130 if (i
== STAT_CLASS_WAYP
) continue;
1131 if (this->vscroll
->IsVisible(statclass
)) {
1132 DrawString (dpi
, r
.left
+ WD_MATRIX_LEFT
, r
.right
- WD_MATRIX_RIGHT
, row
* this->line_height
+ r
.top
+ WD_MATRIX_TOP
,
1133 StationClass::Get((StationClassID
)i
)->name
,
1134 (StationClassID
)i
== _railstation
.station_class
? TC_WHITE
: TC_BLACK
);
1142 case WID_BRAS_IMAGE
: {
1143 byte type
= GB(widget
, 16, 16);
1144 assert(type
< _railstation
.station_count
);
1145 DrawStationPreview (dpi
, r
, _railstation
.station_class
, type
, 2 + _railstation
.orientation
, true);
1151 virtual void OnResize()
1153 if (this->vscroll
!= NULL
) { // New stations available.
1154 this->vscroll
->SetCapacityFromWidget(this, WID_BRAS_NEWST_LIST
);
1158 virtual void SetStringParameters(int widget
) const
1160 if (widget
== WID_BRAS_SHOW_NEWST_TYPE
) {
1161 const StationSpec
*statspec
= StationClass::Get(_railstation
.station_class
)->GetSpec(_railstation
.station_type
);
1162 SetDParam(0, (statspec
!= NULL
&& statspec
->name
!= 0) ? statspec
->name
: STR_STATION_CLASS_DFLT
);
1166 virtual void OnClick(Point pt
, int widget
, int click_count
)
1168 switch (GB(widget
, 0, 16)) {
1169 case WID_BRAS_PLATFORM_DIR_X
:
1170 case WID_BRAS_PLATFORM_DIR_Y
:
1171 this->RaiseWidget(_railstation
.orientation
+ WID_BRAS_PLATFORM_DIR_X
);
1172 _railstation
.orientation
= (Axis
)(widget
- WID_BRAS_PLATFORM_DIR_X
);
1173 this->LowerWidget(_railstation
.orientation
+ WID_BRAS_PLATFORM_DIR_X
);
1174 if (_settings_client
.sound
.click_beep
) SndPlayFx(SND_15_BEEP
);
1176 DeleteWindowById(WC_SELECT_STATION
, 0);
1179 case WID_BRAS_PLATFORM_NUM_1
:
1180 case WID_BRAS_PLATFORM_NUM_2
:
1181 case WID_BRAS_PLATFORM_NUM_3
:
1182 case WID_BRAS_PLATFORM_NUM_4
:
1183 case WID_BRAS_PLATFORM_NUM_5
:
1184 case WID_BRAS_PLATFORM_NUM_6
:
1185 case WID_BRAS_PLATFORM_NUM_7
: {
1186 this->RaiseWidget(_settings_client
.gui
.station_numtracks
+ WID_BRAS_PLATFORM_NUM_BEGIN
);
1187 this->RaiseWidget(WID_BRAS_PLATFORM_DRAG_N_DROP
);
1189 _settings_client
.gui
.station_numtracks
= widget
- WID_BRAS_PLATFORM_NUM_BEGIN
;
1190 _settings_client
.gui
.station_dragdrop
= false;
1192 _settings_client
.gui
.station_dragdrop
= false;
1194 const StationSpec
*statspec
= _railstation
.newstations
? StationClass::Get(_railstation
.station_class
)->GetSpec(_railstation
.station_type
) : NULL
;
1195 if (statspec
!= NULL
&& HasBit(statspec
->disallowed_lengths
, _settings_client
.gui
.station_platlength
- 1)) {
1196 /* The previously selected number of platforms in invalid */
1197 for (uint i
= 0; i
< 7; i
++) {
1198 if (!HasBit(statspec
->disallowed_lengths
, i
)) {
1199 this->RaiseWidget(_settings_client
.gui
.station_platlength
+ WID_BRAS_PLATFORM_LEN_BEGIN
);
1200 _settings_client
.gui
.station_platlength
= i
+ 1;
1206 this->LowerWidget(_settings_client
.gui
.station_numtracks
+ WID_BRAS_PLATFORM_NUM_BEGIN
);
1207 this->LowerWidget(_settings_client
.gui
.station_platlength
+ WID_BRAS_PLATFORM_LEN_BEGIN
);
1208 if (_settings_client
.sound
.click_beep
) SndPlayFx(SND_15_BEEP
);
1210 DeleteWindowById(WC_SELECT_STATION
, 0);
1214 case WID_BRAS_PLATFORM_LEN_1
:
1215 case WID_BRAS_PLATFORM_LEN_2
:
1216 case WID_BRAS_PLATFORM_LEN_3
:
1217 case WID_BRAS_PLATFORM_LEN_4
:
1218 case WID_BRAS_PLATFORM_LEN_5
:
1219 case WID_BRAS_PLATFORM_LEN_6
:
1220 case WID_BRAS_PLATFORM_LEN_7
: {
1221 this->RaiseWidget(_settings_client
.gui
.station_platlength
+ WID_BRAS_PLATFORM_LEN_BEGIN
);
1222 this->RaiseWidget(WID_BRAS_PLATFORM_DRAG_N_DROP
);
1224 _settings_client
.gui
.station_platlength
= widget
- WID_BRAS_PLATFORM_LEN_BEGIN
;
1225 _settings_client
.gui
.station_dragdrop
= false;
1227 _settings_client
.gui
.station_dragdrop
= false;
1229 const StationSpec
*statspec
= _railstation
.newstations
? StationClass::Get(_railstation
.station_class
)->GetSpec(_railstation
.station_type
) : NULL
;
1230 if (statspec
!= NULL
&& HasBit(statspec
->disallowed_platforms
, _settings_client
.gui
.station_numtracks
- 1)) {
1231 /* The previously selected number of tracks in invalid */
1232 for (uint i
= 0; i
< 7; i
++) {
1233 if (!HasBit(statspec
->disallowed_platforms
, i
)) {
1234 this->RaiseWidget(_settings_client
.gui
.station_numtracks
+ WID_BRAS_PLATFORM_NUM_BEGIN
);
1235 _settings_client
.gui
.station_numtracks
= i
+ 1;
1241 this->LowerWidget(_settings_client
.gui
.station_numtracks
+ WID_BRAS_PLATFORM_NUM_BEGIN
);
1242 this->LowerWidget(_settings_client
.gui
.station_platlength
+ WID_BRAS_PLATFORM_LEN_BEGIN
);
1243 if (_settings_client
.sound
.click_beep
) SndPlayFx(SND_15_BEEP
);
1245 DeleteWindowById(WC_SELECT_STATION
, 0);
1249 case WID_BRAS_PLATFORM_DRAG_N_DROP
: {
1250 _settings_client
.gui
.station_dragdrop
^= true;
1252 this->ToggleWidgetLoweredState(WID_BRAS_PLATFORM_DRAG_N_DROP
);
1254 /* get the first allowed length/number of platforms */
1255 const StationSpec
*statspec
= _railstation
.newstations
? StationClass::Get(_railstation
.station_class
)->GetSpec(_railstation
.station_type
) : NULL
;
1256 if (statspec
!= NULL
&& HasBit(statspec
->disallowed_lengths
, _settings_client
.gui
.station_platlength
- 1)) {
1257 for (uint i
= 0; i
< 7; i
++) {
1258 if (!HasBit(statspec
->disallowed_lengths
, i
)) {
1259 this->RaiseWidget(_settings_client
.gui
.station_platlength
+ WID_BRAS_PLATFORM_LEN_BEGIN
);
1260 _settings_client
.gui
.station_platlength
= i
+ 1;
1265 if (statspec
!= NULL
&& HasBit(statspec
->disallowed_platforms
, _settings_client
.gui
.station_numtracks
- 1)) {
1266 for (uint i
= 0; i
< 7; i
++) {
1267 if (!HasBit(statspec
->disallowed_platforms
, i
)) {
1268 this->RaiseWidget(_settings_client
.gui
.station_numtracks
+ WID_BRAS_PLATFORM_NUM_BEGIN
);
1269 _settings_client
.gui
.station_numtracks
= i
+ 1;
1275 this->SetWidgetLoweredState(_settings_client
.gui
.station_numtracks
+ WID_BRAS_PLATFORM_NUM_BEGIN
, !_settings_client
.gui
.station_dragdrop
);
1276 this->SetWidgetLoweredState(_settings_client
.gui
.station_platlength
+ WID_BRAS_PLATFORM_LEN_BEGIN
, !_settings_client
.gui
.station_dragdrop
);
1277 if (_settings_client
.sound
.click_beep
) SndPlayFx(SND_15_BEEP
);
1279 DeleteWindowById(WC_SELECT_STATION
, 0);
1283 case WID_BRAS_HIGHLIGHT_OFF
:
1284 case WID_BRAS_HIGHLIGHT_ON
:
1285 _settings_client
.gui
.station_show_coverage
= (widget
!= WID_BRAS_HIGHLIGHT_OFF
);
1287 this->SetWidgetLoweredState(WID_BRAS_HIGHLIGHT_OFF
, !_settings_client
.gui
.station_show_coverage
);
1288 this->SetWidgetLoweredState(WID_BRAS_HIGHLIGHT_ON
, _settings_client
.gui
.station_show_coverage
);
1289 if (_settings_client
.sound
.click_beep
) SndPlayFx(SND_15_BEEP
);
1293 case WID_BRAS_NEWST_LIST
: {
1294 int y
= this->vscroll
->GetScrolledRowFromWidget(pt
.y
, this, WID_BRAS_NEWST_LIST
, 0, this->line_height
);
1295 if (y
>= (int)StationClass::GetClassCount()) return;
1296 for (uint i
= 0; i
< StationClass::GetClassCount(); i
++) {
1297 if (i
== STAT_CLASS_WAYP
) continue;
1299 if (_railstation
.station_class
!= (StationClassID
)i
) {
1300 _railstation
.station_class
= (StationClassID
)i
;
1301 StationClass
*stclass
= StationClass::Get(_railstation
.station_class
);
1302 _railstation
.station_count
= stclass
->GetSpecCount();
1303 _railstation
.station_type
= min((int)_railstation
.station_type
, max(0, (int)_railstation
.station_count
- 1));
1305 this->CheckSelectedSize(stclass
->GetSpec(_railstation
.station_type
));
1307 NWidgetMatrix
*matrix
= this->GetWidget
<NWidgetMatrix
>(WID_BRAS_MATRIX
);
1308 matrix
->SetCount(_railstation
.station_count
);
1309 matrix
->SetClicked(_railstation
.station_type
);
1311 if (_settings_client
.sound
.click_beep
) SndPlayFx(SND_15_BEEP
);
1313 DeleteWindowById(WC_SELECT_STATION
, 0);
1321 case WID_BRAS_IMAGE
: {
1322 int y
= GB(widget
, 16, 16);
1323 if (y
>= _railstation
.station_count
) return;
1325 /* Check station availability callback */
1326 const StationSpec
*statspec
= StationClass::Get(_railstation
.station_class
)->GetSpec(y
);
1327 if (!IsStationAvailable(statspec
)) return;
1329 _railstation
.station_type
= y
;
1331 this->CheckSelectedSize(statspec
);
1332 this->GetWidget
<NWidgetMatrix
>(WID_BRAS_MATRIX
)->SetClicked(_railstation
.station_type
);
1334 if (_settings_client
.sound
.click_beep
) SndPlayFx(SND_15_BEEP
);
1336 DeleteWindowById(WC_SELECT_STATION
, 0);
1342 virtual void OnTick()
1344 CheckRedrawStationCoverage(this);
1348 static const NWidgetPart _nested_station_builder_widgets
[] = {
1349 NWidget(NWID_HORIZONTAL
),
1350 NWidget(WWT_CLOSEBOX
, COLOUR_DARK_GREEN
),
1351 NWidget(WWT_CAPTION
, COLOUR_DARK_GREEN
), SetDataTip(STR_STATION_BUILD_RAIL_CAPTION
, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS
),
1352 NWidget(NWID_SELECTION
, INVALID_COLOUR
, WID_BRAS_SHOW_NEWST_DEFSIZE
),
1353 NWidget(WWT_DEFSIZEBOX
, COLOUR_DARK_GREEN
),
1356 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
),
1357 NWidget(NWID_HORIZONTAL
),
1358 NWidget(NWID_VERTICAL
),
1359 NWidget(NWID_SELECTION
, INVALID_COLOUR
, WID_BRAS_SHOW_NEWST_ADDITIONS
),
1360 NWidget(NWID_HORIZONTAL
), SetPIP(7, 0, 7), SetPadding(2, 0, 1, 0),
1361 NWidget(WWT_MATRIX
, COLOUR_GREY
, WID_BRAS_NEWST_LIST
), SetMinimalSize(122, 71), SetFill(1, 0),
1362 SetMatrixDataTip(1, 0, STR_STATION_BUILD_STATION_CLASS_TOOLTIP
), SetScrollbar(WID_BRAS_NEWST_SCROLL
),
1363 NWidget(NWID_VSCROLLBAR
, COLOUR_GREY
, WID_BRAS_NEWST_SCROLL
),
1366 NWidget(WWT_LABEL
, COLOUR_DARK_GREEN
), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_ORIENTATION
, STR_NULL
), SetPadding(1, 2, 0, 2),
1367 NWidget(NWID_HORIZONTAL
),
1368 NWidget(NWID_SPACER
), SetMinimalSize(7, 0), SetFill(1, 0),
1369 NWidget(WWT_PANEL
, COLOUR_GREY
, WID_BRAS_PLATFORM_DIR_X
), SetMinimalSize(66, 60), SetFill(0, 0), SetDataTip(0x0, STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP
), EndContainer(),
1370 NWidget(NWID_SPACER
), SetMinimalSize(2, 0), SetFill(1, 0),
1371 NWidget(WWT_PANEL
, COLOUR_GREY
, WID_BRAS_PLATFORM_DIR_Y
), SetMinimalSize(66, 60), SetFill(0, 0), SetDataTip(0x0, STR_STATION_BUILD_RAILROAD_ORIENTATION_TOOLTIP
), EndContainer(),
1372 NWidget(NWID_SPACER
), SetMinimalSize(7, 0), SetFill(1, 0),
1374 NWidget(WWT_LABEL
, COLOUR_DARK_GREEN
, WID_BRAS_SHOW_NEWST_TYPE
), SetMinimalSize(144, 11), SetDataTip(STR_ORANGE_STRING
, STR_NULL
), SetPadding(1, 2, 4, 2),
1375 NWidget(WWT_LABEL
, COLOUR_DARK_GREEN
), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_NUMBER_OF_TRACKS
, STR_NULL
), SetPadding(0, 2, 0, 2),
1376 NWidget(NWID_HORIZONTAL
),
1377 NWidget(NWID_SPACER
), SetFill(1, 0),
1378 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_BRAS_PLATFORM_NUM_1
), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_1
, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP
),
1379 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_BRAS_PLATFORM_NUM_2
), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_2
, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP
),
1380 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_BRAS_PLATFORM_NUM_3
), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_3
, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP
),
1381 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_BRAS_PLATFORM_NUM_4
), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_4
, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP
),
1382 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_BRAS_PLATFORM_NUM_5
), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_5
, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP
),
1383 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_BRAS_PLATFORM_NUM_6
), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_6
, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP
),
1384 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_BRAS_PLATFORM_NUM_7
), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_7
, STR_STATION_BUILD_NUMBER_OF_TRACKS_TOOLTIP
),
1385 NWidget(NWID_SPACER
), SetFill(1, 0),
1387 NWidget(WWT_LABEL
, COLOUR_DARK_GREEN
), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_PLATFORM_LENGTH
, STR_NULL
), SetPadding(2, 2, 0, 2),
1388 NWidget(NWID_HORIZONTAL
),
1389 NWidget(NWID_SPACER
), SetFill(1, 0),
1390 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_BRAS_PLATFORM_LEN_1
), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_1
, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP
),
1391 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_BRAS_PLATFORM_LEN_2
), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_2
, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP
),
1392 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_BRAS_PLATFORM_LEN_3
), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_3
, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP
),
1393 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_BRAS_PLATFORM_LEN_4
), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_4
, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP
),
1394 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_BRAS_PLATFORM_LEN_5
), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_5
, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP
),
1395 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_BRAS_PLATFORM_LEN_6
), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_6
, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP
),
1396 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_BRAS_PLATFORM_LEN_7
), SetMinimalSize(15, 12), SetDataTip(STR_BLACK_7
, STR_STATION_BUILD_PLATFORM_LENGTH_TOOLTIP
),
1397 NWidget(NWID_SPACER
), SetFill(1, 0),
1399 NWidget(NWID_SPACER
), SetMinimalSize(0, 2),
1400 NWidget(NWID_HORIZONTAL
),
1401 NWidget(NWID_SPACER
), SetMinimalSize(2, 0), SetFill(1, 0),
1402 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_BRAS_PLATFORM_DRAG_N_DROP
), SetMinimalSize(75, 12), SetDataTip(STR_STATION_BUILD_DRAG_DROP
, STR_STATION_BUILD_DRAG_DROP_TOOLTIP
),
1403 NWidget(NWID_SPACER
), SetMinimalSize(2, 0), SetFill(1, 0),
1405 NWidget(WWT_LABEL
, COLOUR_DARK_GREEN
), SetMinimalSize(144, 11), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE
, STR_NULL
), SetPadding(3, 2, 0, 2),
1406 NWidget(NWID_HORIZONTAL
),
1407 NWidget(NWID_SPACER
), SetMinimalSize(2, 0), SetFill(1, 0),
1408 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_BRAS_HIGHLIGHT_OFF
), SetMinimalSize(60, 12),
1409 SetDataTip(STR_STATION_BUILD_COVERAGE_OFF
, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP
),
1410 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_BRAS_HIGHLIGHT_ON
), SetMinimalSize(60, 12),
1411 SetDataTip(STR_STATION_BUILD_COVERAGE_ON
, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP
),
1412 NWidget(NWID_SPACER
), SetMinimalSize(2, 0), SetFill(1, 0),
1415 NWidget(NWID_SELECTION
, INVALID_COLOUR
, WID_BRAS_SHOW_NEWST_MATRIX
),
1416 /* We need an additional background for the matrix, as the matrix cannot handle the scrollbar due to not being an NWidgetCore. */
1417 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
), SetScrollbar(WID_BRAS_MATRIX_SCROLL
),
1418 NWidget(NWID_HORIZONTAL
),
1419 NWidget(NWID_MATRIX
, COLOUR_DARK_GREEN
, WID_BRAS_MATRIX
), SetScrollbar(WID_BRAS_MATRIX_SCROLL
), SetPIP(0, 2, 0), SetPadding(2, 0, 0, 0),
1420 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
, WID_BRAS_IMAGE
), SetMinimalSize(66, 60),
1421 SetFill(0, 0), SetResize(0, 0), SetDataTip(0x0, STR_STATION_BUILD_STATION_TYPE_TOOLTIP
), SetScrollbar(WID_BRAS_MATRIX_SCROLL
),
1424 NWidget(NWID_VSCROLLBAR
, COLOUR_DARK_GREEN
, WID_BRAS_MATRIX_SCROLL
),
1429 NWidget(NWID_HORIZONTAL
),
1430 NWidget(WWT_EMPTY
, INVALID_COLOUR
, WID_BRAS_COVERAGE_TEXTS
), SetFill(1, 1), SetResize(1, 0),
1431 NWidget(NWID_SELECTION
, INVALID_COLOUR
, WID_BRAS_SHOW_NEWST_RESIZE
),
1432 NWidget(NWID_VERTICAL
),
1433 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
), SetFill(0, 1), EndContainer(),
1434 NWidget(WWT_RESIZEBOX
, COLOUR_DARK_GREEN
),
1441 /** Window preferences of the station-build window (default & newGRF) */
1442 static WindowDesc::Prefs
_station_builder_prefs ("build_station_rail");
1444 /** High level window description of the station-build window (default & newGRF) */
1445 static const WindowDesc
_station_builder_desc(
1447 WC_BUILD_STATION
, WC_BUILD_TOOLBAR
,
1449 _nested_station_builder_widgets
, lengthof(_nested_station_builder_widgets
),
1450 &_station_builder_prefs
1453 /** Open station build window */
1454 static void ShowStationBuilder(Window
*parent
)
1456 bool newstations
= StationClass::GetClassCount() > 2 || StationClass::Get(STAT_CLASS_DFLT
)->GetSpecCount() != 1;
1457 new BuildRailStationWindow(&_station_builder_desc
, parent
, newstations
);
1460 struct BuildSignalWindow
: public PickerWindowBase
{
1462 Dimension sig_sprite_size
; ///< Maximum size of signal GUI sprites.
1463 int sig_sprite_bottom_offset
; ///< Maximum extent of signal GUI sprite from reference point towards bottom.
1466 * Draw dynamic a signal-sprite in a button in the signal GUI
1467 * Draw the sprite +1px to the right and down if the button is lowered
1469 * @param widget_index index of this widget in the window
1470 * @param image the sprite to draw
1472 void DrawSignalSprite (BlitArea
*dpi
, byte widget_index
, SpriteID image
) const
1475 Dimension sprite_size
= GetSpriteSize(image
, &offset
);
1476 const NWidgetBase
*widget
= this->GetWidget
<NWidgetBase
>(widget_index
);
1477 int x
= widget
->pos_x
- offset
.x
+
1478 (widget
->current_x
- sprite_size
.width
+ offset
.x
) / 2; // centered
1479 int y
= widget
->pos_y
- sig_sprite_bottom_offset
+ WD_IMGBTN_TOP
+
1480 (widget
->current_y
- WD_IMGBTN_TOP
- WD_IMGBTN_BOTTOM
+ sig_sprite_size
.height
) / 2; // aligned to bottom
1482 DrawSprite (dpi
, image
, PAL_NONE
,
1483 x
+ this->IsWidgetLowered(widget_index
),
1484 y
+ this->IsWidgetLowered(widget_index
));
1488 BuildSignalWindow (const WindowDesc
*desc
, Window
*parent
) :
1489 PickerWindowBase (desc
, parent
), sig_sprite_bottom_offset (0)
1491 this->sig_sprite_size
.width
= 0;
1492 this->sig_sprite_size
.height
= 0;
1494 this->InitNested(TRANSPORT_RAIL
);
1495 this->OnInvalidateData();
1498 void OnDelete (void) FINAL_OVERRIDE
1500 _convert_signal_button
= false;
1501 this->PickerWindowBase::OnDelete();
1504 virtual void OnInit()
1506 /* Calculate maximum signal sprite size. */
1507 this->sig_sprite_size
.width
= 0;
1508 this->sig_sprite_size
.height
= 0;
1509 this->sig_sprite_bottom_offset
= 0;
1510 const RailtypeInfo
*rti
= GetRailTypeInfo(_cur_railtype
);
1511 for (uint type
= SIGTYPE_NORMAL
; type
< SIGTYPE_END
; type
++) {
1512 for (uint variant
= SIG_ELECTRIC
; variant
<= SIG_SEMAPHORE
; variant
++) {
1513 for (uint lowered
= 0; lowered
< 2; lowered
++) {
1515 Dimension sprite_size
= GetSpriteSize(rti
->gui_sprites
.signals
[type
][variant
][lowered
], &offset
);
1516 this->sig_sprite_bottom_offset
= max
<int>(this->sig_sprite_bottom_offset
, sprite_size
.height
);
1517 this->sig_sprite_size
.width
= max
<int>(this->sig_sprite_size
.width
, sprite_size
.width
- offset
.x
);
1518 this->sig_sprite_size
.height
= max
<int>(this->sig_sprite_size
.height
, sprite_size
.height
- offset
.y
);
1524 virtual void UpdateWidgetSize(int widget
, Dimension
*size
, const Dimension
&padding
, Dimension
*fill
, Dimension
*resize
)
1526 if (widget
== WID_BS_DRAG_SIGNALS_DENSITY_LABEL
) {
1527 /* Two digits for signals density. */
1528 size
->width
= max(size
->width
, 2 * GetDigitWidth() + padding
.width
+ WD_FRAMERECT_LEFT
+ WD_FRAMERECT_RIGHT
);
1529 } else if (IsInsideMM(widget
, WID_BS_SEMAPHORE_NORM
, WID_BS_ELECTRIC_PBS_OWAY
+ 1)) {
1530 size
->width
= max(size
->width
, this->sig_sprite_size
.width
+ WD_IMGBTN_LEFT
+ WD_IMGBTN_RIGHT
);
1531 size
->height
= max(size
->height
, this->sig_sprite_size
.height
+ WD_IMGBTN_TOP
+ WD_IMGBTN_BOTTOM
);
1535 virtual void SetStringParameters(int widget
) const
1538 case WID_BS_DRAG_SIGNALS_DENSITY_LABEL
:
1539 SetDParam(0, _settings_client
.gui
.drag_signals_density
);
1544 void DrawWidget (BlitArea
*dpi
, const Rect
&r
, int widget
) const OVERRIDE
1546 if (IsInsideMM(widget
, WID_BS_SEMAPHORE_NORM
, WID_BS_ELECTRIC_PBS_OWAY
+ 1)) {
1547 /* Extract signal from widget number. */
1548 int type
= (widget
- WID_BS_SEMAPHORE_NORM
) % SIGTYPE_END
;
1549 int var
= SIG_SEMAPHORE
- (widget
- WID_BS_SEMAPHORE_NORM
) / SIGTYPE_END
; // SignalVariant order is reversed compared to the widgets.
1550 SpriteID sprite
= GetRailTypeInfo(_cur_railtype
)->gui_sprites
.signals
[type
][var
][this->IsWidgetLowered(widget
)];
1552 this->DrawSignalSprite (dpi
, widget
, sprite
);
1556 virtual void OnClick(Point pt
, int widget
, int click_count
)
1559 case WID_BS_SEMAPHORE_NORM
:
1560 case WID_BS_SEMAPHORE_ENTRY
:
1561 case WID_BS_SEMAPHORE_EXIT
:
1562 case WID_BS_SEMAPHORE_COMBO
:
1563 case WID_BS_SEMAPHORE_PBS
:
1564 case WID_BS_SEMAPHORE_PBS_OWAY
:
1565 case WID_BS_ELECTRIC_NORM
:
1566 case WID_BS_ELECTRIC_ENTRY
:
1567 case WID_BS_ELECTRIC_EXIT
:
1568 case WID_BS_ELECTRIC_COMBO
:
1569 case WID_BS_ELECTRIC_PBS
:
1570 case WID_BS_ELECTRIC_PBS_OWAY
:
1571 this->RaiseWidget((_cur_signal_variant
== SIG_ELECTRIC
? WID_BS_ELECTRIC_NORM
: WID_BS_SEMAPHORE_NORM
) + _cur_signal_type
);
1573 _cur_signal_type
= (SignalType
)((uint
)((widget
- WID_BS_SEMAPHORE_NORM
) % SIGTYPE_END
));
1574 _cur_signal_variant
= widget
>= WID_BS_ELECTRIC_NORM
? SIG_ELECTRIC
: SIG_SEMAPHORE
;
1576 /* If 'remove' button of rail build toolbar is active, disable it. */
1577 if (_remove_button_clicked
) {
1578 Window
*w
= FindWindowById(WC_BUILD_TOOLBAR
, TRANSPORT_RAIL
);
1579 if (w
!= NULL
) ToggleRailButton_Remove(w
);
1584 case WID_BS_CONVERT
:
1585 _convert_signal_button
= !_convert_signal_button
;
1588 case WID_BS_DRAG_SIGNALS_DENSITY_DECREASE
:
1589 if (_settings_client
.gui
.drag_signals_density
> 1) {
1590 _settings_client
.gui
.drag_signals_density
--;
1591 SetWindowDirty(WC_GAME_OPTIONS
, WN_GAME_OPTIONS_GAME_SETTINGS
);
1595 case WID_BS_DRAG_SIGNALS_DENSITY_INCREASE
:
1596 if (_settings_client
.gui
.drag_signals_density
< 20) {
1597 _settings_client
.gui
.drag_signals_density
++;
1598 SetWindowDirty(WC_GAME_OPTIONS
, WN_GAME_OPTIONS_GAME_SETTINGS
);
1605 this->InvalidateData();
1609 * Some data on this window has become invalid.
1610 * @param data Information about the changed data.
1611 * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
1613 virtual void OnInvalidateData(int data
= 0, bool gui_scope
= true)
1615 if (!gui_scope
) return;
1616 this->LowerWidget((_cur_signal_variant
== SIG_ELECTRIC
? WID_BS_ELECTRIC_NORM
: WID_BS_SEMAPHORE_NORM
) + _cur_signal_type
);
1618 this->SetWidgetLoweredState(WID_BS_CONVERT
, _convert_signal_button
);
1620 this->SetWidgetDisabledState(WID_BS_DRAG_SIGNALS_DENSITY_DECREASE
, _settings_client
.gui
.drag_signals_density
== 1);
1621 this->SetWidgetDisabledState(WID_BS_DRAG_SIGNALS_DENSITY_INCREASE
, _settings_client
.gui
.drag_signals_density
== 20);
1625 /** Nested widget definition of the build signal window */
1626 static const NWidgetPart _nested_signal_builder_widgets
[] = {
1627 NWidget(NWID_HORIZONTAL
),
1628 NWidget(WWT_CLOSEBOX
, COLOUR_DARK_GREEN
),
1629 NWidget(WWT_CAPTION
, COLOUR_DARK_GREEN
), SetDataTip(STR_BUILD_SIGNAL_CAPTION
, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS
),
1631 NWidget(NWID_VERTICAL
, NC_EQUALSIZE
),
1632 NWidget(NWID_HORIZONTAL
, NC_EQUALSIZE
),
1633 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
, WID_BS_SEMAPHORE_NORM
), SetDataTip(STR_NULL
, STR_BUILD_SIGNAL_SEMAPHORE_NORM_TOOLTIP
), EndContainer(), SetFill(1, 1),
1634 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
, WID_BS_SEMAPHORE_ENTRY
), SetDataTip(STR_NULL
, STR_BUILD_SIGNAL_SEMAPHORE_ENTRY_TOOLTIP
), EndContainer(), SetFill(1, 1),
1635 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
, WID_BS_SEMAPHORE_EXIT
), SetDataTip(STR_NULL
, STR_BUILD_SIGNAL_SEMAPHORE_EXIT_TOOLTIP
), EndContainer(), SetFill(1, 1),
1636 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
, WID_BS_SEMAPHORE_COMBO
), SetDataTip(STR_NULL
, STR_BUILD_SIGNAL_SEMAPHORE_COMBO_TOOLTIP
), EndContainer(), SetFill(1, 1),
1637 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
, WID_BS_SEMAPHORE_PBS
), SetDataTip(STR_NULL
, STR_BUILD_SIGNAL_SEMAPHORE_PBS_TOOLTIP
), EndContainer(), SetFill(1, 1),
1638 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
, WID_BS_SEMAPHORE_PBS_OWAY
), SetDataTip(STR_NULL
, STR_BUILD_SIGNAL_SEMAPHORE_PBS_OWAY_TOOLTIP
), EndContainer(), SetFill(1, 1),
1639 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_BS_CONVERT
), SetDataTip(SPR_IMG_SIGNAL_CONVERT
, STR_BUILD_SIGNAL_CONVERT_TOOLTIP
), SetFill(1, 1),
1641 NWidget(NWID_HORIZONTAL
, NC_EQUALSIZE
),
1642 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
, WID_BS_ELECTRIC_NORM
), SetDataTip(STR_NULL
, STR_BUILD_SIGNAL_ELECTRIC_NORM_TOOLTIP
), EndContainer(), SetFill(1, 1),
1643 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
, WID_BS_ELECTRIC_ENTRY
), SetDataTip(STR_NULL
, STR_BUILD_SIGNAL_ELECTRIC_ENTRY_TOOLTIP
), EndContainer(), SetFill(1, 1),
1644 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
, WID_BS_ELECTRIC_EXIT
), SetDataTip(STR_NULL
, STR_BUILD_SIGNAL_ELECTRIC_EXIT_TOOLTIP
), EndContainer(), SetFill(1, 1),
1645 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
, WID_BS_ELECTRIC_COMBO
), SetDataTip(STR_NULL
, STR_BUILD_SIGNAL_ELECTRIC_COMBO_TOOLTIP
), EndContainer(), SetFill(1, 1),
1646 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
, WID_BS_ELECTRIC_PBS
), SetDataTip(STR_NULL
, STR_BUILD_SIGNAL_ELECTRIC_PBS_TOOLTIP
), EndContainer(), SetFill(1, 1),
1647 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
, WID_BS_ELECTRIC_PBS_OWAY
), SetDataTip(STR_NULL
, STR_BUILD_SIGNAL_ELECTRIC_PBS_OWAY_TOOLTIP
), EndContainer(), SetFill(1, 1),
1648 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
), SetDataTip(STR_NULL
, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP
), SetFill(1, 1),
1649 NWidget(WWT_LABEL
, COLOUR_DARK_GREEN
, WID_BS_DRAG_SIGNALS_DENSITY_LABEL
), SetDataTip(STR_ORANGE_INT
, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_TOOLTIP
), SetFill(1, 1),
1650 NWidget(NWID_HORIZONTAL
), SetPIP(2, 0, 2),
1651 NWidget(NWID_SPACER
), SetFill(1, 0),
1652 NWidget(WWT_PUSHARROWBTN
, COLOUR_GREY
, WID_BS_DRAG_SIGNALS_DENSITY_DECREASE
), SetMinimalSize(9, 12), SetDataTip(AWV_DECREASE
, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_DECREASE_TOOLTIP
),
1653 NWidget(WWT_PUSHARROWBTN
, COLOUR_GREY
, WID_BS_DRAG_SIGNALS_DENSITY_INCREASE
), SetMinimalSize(9, 12), SetDataTip(AWV_INCREASE
, STR_BUILD_SIGNAL_DRAG_SIGNALS_DENSITY_INCREASE_TOOLTIP
),
1654 NWidget(NWID_SPACER
), SetFill(1, 0),
1656 NWidget(NWID_SPACER
), SetMinimalSize(0, 2), SetFill(1, 0),
1662 /** Signal selection window preferences */
1663 static WindowDesc::Prefs
_signal_builder_prefs ("build_signal");
1665 /** Signal selection window description */
1666 static const WindowDesc
_signal_builder_desc(
1668 WC_BUILD_SIGNAL
, WC_BUILD_TOOLBAR
,
1670 _nested_signal_builder_widgets
, lengthof(_nested_signal_builder_widgets
),
1671 &_signal_builder_prefs
1675 * Open the signal selection window
1677 static void ShowSignalBuilder(Window
*parent
)
1679 new BuildSignalWindow(&_signal_builder_desc
, parent
);
1682 struct BuildRailDepotWindow
: public PickerWindowBase
{
1683 BuildRailDepotWindow (const WindowDesc
*desc
, Window
*parent
) : PickerWindowBase(desc
, parent
)
1685 this->InitNested(TRANSPORT_RAIL
);
1686 this->LowerWidget(_build_depot_direction
+ WID_BRAD_DEPOT_NE
);
1689 virtual void UpdateWidgetSize(int widget
, Dimension
*size
, const Dimension
&padding
, Dimension
*fill
, Dimension
*resize
)
1691 if (!IsInsideMM(widget
, WID_BRAD_DEPOT_NE
, WID_BRAD_DEPOT_NW
+ 1)) return;
1693 size
->width
= ScaleGUITrad(64) + 2;
1694 size
->height
= ScaleGUITrad(48) + 2;
1697 void DrawWidget (BlitArea
*dpi
, const Rect
&r
, int widget
) const OVERRIDE
1699 if (!IsInsideMM(widget
, WID_BRAD_DEPOT_NE
, WID_BRAD_DEPOT_NW
+ 1)) return;
1701 DrawTrainDepotSprite (dpi
, r
.left
+ 1 + ScaleGUITrad(31), r
.bottom
- ScaleGUITrad(31), widget
- WID_BRAD_DEPOT_NE
+ DIAGDIR_NE
, _cur_railtype
);
1704 virtual void OnClick(Point pt
, int widget
, int click_count
)
1707 case WID_BRAD_DEPOT_NE
:
1708 case WID_BRAD_DEPOT_SE
:
1709 case WID_BRAD_DEPOT_SW
:
1710 case WID_BRAD_DEPOT_NW
:
1711 this->RaiseWidget(_build_depot_direction
+ WID_BRAD_DEPOT_NE
);
1712 _build_depot_direction
= (DiagDirection
)(widget
- WID_BRAD_DEPOT_NE
);
1713 this->LowerWidget(_build_depot_direction
+ WID_BRAD_DEPOT_NE
);
1714 if (_settings_client
.sound
.click_beep
) SndPlayFx(SND_15_BEEP
);
1721 /** Nested widget definition of the build rail depot window */
1722 static const NWidgetPart _nested_build_depot_widgets
[] = {
1723 NWidget(NWID_HORIZONTAL
),
1724 NWidget(WWT_CLOSEBOX
, COLOUR_DARK_GREEN
),
1725 NWidget(WWT_CAPTION
, COLOUR_DARK_GREEN
), SetDataTip(STR_BUILD_DEPOT_TRAIN_ORIENTATION_CAPTION
, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS
),
1727 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
),
1728 NWidget(NWID_SPACER
), SetMinimalSize(0, 3),
1729 NWidget(NWID_HORIZONTAL_LTR
),
1730 NWidget(NWID_SPACER
), SetMinimalSize(3, 0), SetFill(1, 0),
1731 NWidget(NWID_VERTICAL
),
1732 NWidget(WWT_PANEL
, COLOUR_GREY
, WID_BRAD_DEPOT_NW
), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP
),
1734 NWidget(NWID_SPACER
), SetMinimalSize(0, 2),
1735 NWidget(WWT_PANEL
, COLOUR_GREY
, WID_BRAD_DEPOT_SW
), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP
),
1738 NWidget(NWID_SPACER
), SetMinimalSize(2, 0),
1739 NWidget(NWID_VERTICAL
),
1740 NWidget(WWT_PANEL
, COLOUR_GREY
, WID_BRAD_DEPOT_NE
), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP
),
1742 NWidget(NWID_SPACER
), SetMinimalSize(0, 2),
1743 NWidget(WWT_PANEL
, COLOUR_GREY
, WID_BRAD_DEPOT_SE
), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP
),
1746 NWidget(NWID_SPACER
), SetMinimalSize(3, 0), SetFill(1, 0),
1748 NWidget(NWID_SPACER
), SetMinimalSize(0, 3),
1752 static const WindowDesc
_build_depot_desc(
1754 WC_BUILD_DEPOT
, WC_BUILD_TOOLBAR
,
1756 _nested_build_depot_widgets
, lengthof(_nested_build_depot_widgets
)
1759 static void ShowBuildTrainDepotPicker(Window
*parent
)
1761 new BuildRailDepotWindow(&_build_depot_desc
, parent
);
1764 struct BuildRailWaypointWindow
: PickerWindowBase
{
1765 BuildRailWaypointWindow (const WindowDesc
*desc
, Window
*parent
) : PickerWindowBase(desc
, parent
)
1767 this->CreateNestedTree();
1769 NWidgetMatrix
*matrix
= this->GetWidget
<NWidgetMatrix
>(WID_BRW_WAYPOINT_MATRIX
);
1770 matrix
->SetScrollbar(this->GetScrollbar(WID_BRW_SCROLL
));
1772 this->InitNested(TRANSPORT_RAIL
);
1774 matrix
->SetCount(_waypoint_count
);
1775 matrix
->SetClicked(_cur_waypoint_type
);
1778 virtual void UpdateWidgetSize(int widget
, Dimension
*size
, const Dimension
&padding
, Dimension
*fill
, Dimension
*resize
)
1781 case WID_BRW_WAYPOINT_MATRIX
:
1782 /* Three blobs high and wide. */
1783 size
->width
+= resize
->width
* 2;
1784 size
->height
+= resize
->height
* 2;
1786 /* Resizing in X direction only at blob size, but at pixel level in Y. */
1790 case WID_BRW_WAYPOINT
:
1791 size
->width
= ScaleGUITrad(64) + 2;
1792 size
->height
= ScaleGUITrad(58) + 2;
1797 void DrawWidget (BlitArea
*dpi
, const Rect
&r
, int widget
) const OVERRIDE
1799 switch (GB(widget
, 0, 16)) {
1800 case WID_BRW_WAYPOINT
: {
1801 byte type
= GB(widget
, 16, 16);
1802 DrawStationPreview (dpi
, r
, STAT_CLASS_WAYP
, type
, AXIS_X
, true);
1808 virtual void OnClick(Point pt
, int widget
, int click_count
)
1810 switch (GB(widget
, 0, 16)) {
1811 case WID_BRW_WAYPOINT
: {
1812 byte type
= GB(widget
, 16, 16);
1813 this->GetWidget
<NWidgetMatrix
>(WID_BRW_WAYPOINT_MATRIX
)->SetClicked(_cur_waypoint_type
);
1815 /* Check station availability callback */
1816 const StationSpec
*statspec
= StationClass::Get(STAT_CLASS_WAYP
)->GetSpec(type
);
1817 if (!IsStationAvailable(statspec
)) return;
1819 _cur_waypoint_type
= type
;
1820 this->GetWidget
<NWidgetMatrix
>(WID_BRW_WAYPOINT_MATRIX
)->SetClicked(_cur_waypoint_type
);
1821 if (_settings_client
.sound
.click_beep
) SndPlayFx(SND_15_BEEP
);
1829 /** Nested widget definition for the build NewGRF rail waypoint window */
1830 static const NWidgetPart _nested_build_waypoint_widgets
[] = {
1831 NWidget(NWID_HORIZONTAL
),
1832 NWidget(WWT_CLOSEBOX
, COLOUR_DARK_GREEN
),
1833 NWidget(WWT_CAPTION
, COLOUR_DARK_GREEN
), SetDataTip(STR_WAYPOINT_CAPTION
, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS
),
1834 NWidget(WWT_DEFSIZEBOX
, COLOUR_DARK_GREEN
),
1836 NWidget(NWID_HORIZONTAL
),
1837 NWidget(NWID_MATRIX
, COLOUR_DARK_GREEN
, WID_BRW_WAYPOINT_MATRIX
), SetPIP(3, 2, 3), SetScrollbar(WID_BRW_SCROLL
),
1838 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
, WID_BRW_WAYPOINT
), SetMinimalSize(66, 60), SetDataTip(0x0, STR_WAYPOINT_GRAPHICS_TOOLTIP
), SetScrollbar(WID_BRW_SCROLL
), EndContainer(),
1840 NWidget(NWID_VERTICAL
),
1841 NWidget(NWID_VSCROLLBAR
, COLOUR_DARK_GREEN
, WID_BRW_SCROLL
),
1842 NWidget(WWT_RESIZEBOX
, COLOUR_DARK_GREEN
),
1847 static WindowDesc::Prefs
_build_waypoint_prefs ("build_waypoint");
1849 static const WindowDesc
_build_waypoint_desc(
1851 WC_BUILD_WAYPOINT
, WC_BUILD_TOOLBAR
,
1853 _nested_build_waypoint_widgets
, lengthof(_nested_build_waypoint_widgets
),
1854 &_build_waypoint_prefs
1857 static void ShowBuildWaypointPicker(Window
*parent
)
1859 new BuildRailWaypointWindow(&_build_waypoint_desc
, parent
);
1863 * Initialize rail building GUI settings
1865 void InitializeRailGui()
1867 _build_depot_direction
= DIAGDIR_NW
;
1871 * Re-initialize rail-build toolbar after toggling support for electric trains
1872 * @param disable Boolean whether electric trains are disabled (removed from the game)
1874 void ReinitGuiAfterToggleElrail(bool disable
)
1876 extern RailType _last_built_railtype
;
1877 if (disable
&& _last_built_railtype
== RAILTYPE_ELECTRIC
) {
1878 _last_built_railtype
= _cur_railtype
= RAILTYPE_RAIL
;
1879 BuildRailToolbarWindow
*w
= dynamic_cast<BuildRailToolbarWindow
*>(FindWindowById(WC_BUILD_TOOLBAR
, TRANSPORT_RAIL
));
1880 if (w
!= NULL
) w
->ModifyRailType(_cur_railtype
);
1882 MarkWholeScreenDirty();
1885 /** Set the initial (default) railtype to use */
1886 static void SetDefaultRailGui()
1888 if (_local_company
== COMPANY_SPECTATOR
|| !Company::IsValidID(_local_company
)) return;
1890 extern RailType _last_built_railtype
;
1891 RailType rt
= (RailType
)(_settings_client
.gui
.default_rail_type
+ RAILTYPE_END
);
1892 if (rt
== DEF_RAILTYPE_MOST_USED
) {
1893 /* Find the most used rail type */
1894 RailType count
[RAILTYPE_END
];
1895 memset(count
, 0, sizeof(count
));
1896 for (TileIndex t
= 0; t
< MapSize(); t
++) {
1897 if (IsRailwayTile(t
) || IsRailDepotTile(t
) || IsLevelCrossingTile(t
) || HasStationTileRail(t
) ||
1898 maptile_is_rail_tunnel(t
)) {
1899 count
[GetRailType(t
)]++;
1904 for (RailType r
= RAILTYPE_ELECTRIC
; r
< RAILTYPE_END
; r
++) {
1905 if (count
[r
] >= count
[rt
]) rt
= r
;
1908 /* No rail, just get the first available one */
1909 if (count
[rt
] == 0) rt
= DEF_RAILTYPE_FIRST
;
1912 case DEF_RAILTYPE_FIRST
:
1914 while (rt
< RAILTYPE_END
&& !HasRailtypeAvail(_local_company
, rt
)) rt
++;
1917 case DEF_RAILTYPE_LAST
:
1918 rt
= GetBestRailtype(_local_company
);
1925 _last_built_railtype
= _cur_railtype
= rt
;
1926 BuildRailToolbarWindow
*w
= dynamic_cast<BuildRailToolbarWindow
*>(FindWindowById(WC_BUILD_TOOLBAR
, TRANSPORT_RAIL
));
1927 if (w
!= NULL
) w
->ModifyRailType(_cur_railtype
);
1931 * Updates the current signal variant used in the signal GUI
1932 * to the one adequate to current year.
1933 * @param p needed to be called when a setting changes
1934 * @return success, needed for settings
1936 bool ResetSignalVariant(int32 p
)
1938 SignalVariant new_variant
= (_cur_year
< _settings_client
.gui
.semaphore_build_before
? SIG_SEMAPHORE
: SIG_ELECTRIC
);
1940 if (new_variant
!= _cur_signal_variant
) {
1941 Window
*w
= FindWindowById(WC_BUILD_SIGNAL
, 0);
1944 w
->RaiseWidget((_cur_signal_variant
== SIG_ELECTRIC
? WID_BS_ELECTRIC_NORM
: WID_BS_SEMAPHORE_NORM
) + _cur_signal_type
);
1946 _cur_signal_variant
= new_variant
;
1953 * Resets the rail GUI - sets default railtype to build
1954 * and resets the signal GUI
1956 void InitializeRailGUI()
1958 SetDefaultRailGui();
1960 _convert_signal_button
= false;
1961 _cur_signal_type
= _default_signal_type
[_settings_client
.gui
.default_signal_type
];
1962 ResetSignalVariant();
1966 * Create a drop down list for all the rail types of the local company.
1967 * @param for_replacement Whether this list is for the replacement window.
1968 * @param all_option Whether to add an 'all types' item.
1969 * @return The populated and sorted #DropDownList.
1971 DropDownList
*GetRailTypeDropDownList(bool for_replacement
, bool all_option
)
1973 RailTypes used_railtypes
= RAILTYPES_NONE
;
1975 /* Find the used railtypes. */
1977 FOR_ALL_ENGINES_OF_TYPE(e
, VEH_TRAIN
) {
1978 if (!HasBit(e
->info
.climates
, _settings_game
.game_creation
.landscape
)) continue;
1980 used_railtypes
|= GetRailTypeInfo(e
->u
.rail
.railtype
)->introduces_railtypes
;
1983 /* Get the date introduced railtypes as well. */
1984 used_railtypes
= AddDateIntroducedRailTypes(used_railtypes
, MAX_DAY
);
1986 const Company
*c
= Company::Get(_local_company
);
1987 DropDownList
*list
= new DropDownList();
1990 DropDownListStringItem
*item
= new DropDownListStringItem(STR_REPLACE_ALL_RAILTYPE
, INVALID_RAILTYPE
, false);
1991 *list
->Append() = item
;
1995 FOR_ALL_SORTED_RAILTYPES(rt
) {
1996 /* If it's not used ever, don't show it to the user. */
1997 if (!HasBit(used_railtypes
, rt
)) continue;
1999 const RailtypeInfo
*rti
= GetRailTypeInfo(rt
);
2001 StringID str
= for_replacement
? rti
->strings
.replace_text
: (rti
->max_speed
> 0 ? STR_TOOLBAR_RAILTYPE_VELOCITY
: STR_JUST_STRING
);
2002 DropDownListParamStringItem
*item
= new DropDownListParamStringItem(str
, rt
, !HasBit(c
->avail_railtypes
, rt
));
2003 item
->SetParam(0, rti
->strings
.menu_text
);
2004 item
->SetParam(1, rti
->max_speed
);
2005 *list
->Append() = item
;