2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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/>.
8 /** @file road_gui.cpp GUI for building roads. */
12 #include "window_gui.h"
13 #include "station_gui.h"
14 #include "terraform_gui.h"
15 #include "viewport_func.h"
16 #include "command_func.h"
18 #include "station_func.h"
19 #include "waypoint_func.h"
20 #include "window_func.h"
21 #include "vehicle_func.h"
22 #include "sound_func.h"
23 #include "company_func.h"
24 #include "tunnelbridge.h"
25 #include "tunnelbridge_map.h"
26 #include "tilehighlight_func.h"
27 #include "company_base.h"
30 #include "zoom_func.h"
31 #include "dropdown_type.h"
32 #include "dropdown_func.h"
33 #include "engine_base.h"
34 #include "station_base.h"
35 #include "waypoint_base.h"
36 #include "strings_func.h"
37 #include "core/geometry_func.hpp"
38 #include "station_cmd.h"
39 #include "waypoint_cmd.h"
41 #include "tunnelbridge_cmd.h"
42 #include "newgrf_roadstop.h"
43 #include "picker_gui.h"
44 #include "timer/timer.h"
45 #include "timer/timer_game_calendar.h"
47 #include "widgets/road_widget.h"
49 #include "table/strings.h"
51 #include "safeguards.h"
53 static void ShowRVStationPicker(Window
*parent
, RoadStopType rs
);
54 static void ShowRoadDepotPicker(Window
*parent
);
55 static void ShowBuildRoadWaypointPicker(Window
*parent
);
57 static bool _remove_button_clicked
;
58 static bool _one_way_button_clicked
;
60 static Axis _place_road_dir
;
61 static bool _place_road_start_half_x
;
62 static bool _place_road_start_half_y
;
63 static bool _place_road_end_half
;
65 static RoadType _cur_roadtype
;
67 static DiagDirection _road_depot_orientation
;
69 struct RoadWaypointPickerSelection
{
70 RoadStopClassID sel_class
; ///< Selected road waypoint class.
71 uint16_t sel_type
; ///< Selected road waypoint type within the class.
73 static RoadWaypointPickerSelection _waypoint_gui
; ///< Settings of the road waypoint picker.
75 struct RoadStopPickerSelection
{
76 RoadStopClassID sel_class
; ///< Selected road stop class.
77 uint16_t sel_type
; ///< Selected road stop type within the class.
78 DiagDirection orientation
; ///< Selected orientation of the road stop.
80 static RoadStopPickerSelection _roadstop_gui
;
82 static bool IsRoadStopEverAvailable(const RoadStopSpec
*spec
, StationType type
)
84 if (spec
== nullptr) return true;
86 if (HasBit(spec
->flags
, RSF_BUILD_MENU_ROAD_ONLY
) && !RoadTypeIsRoad(_cur_roadtype
)) return false;
87 if (HasBit(spec
->flags
, RSF_BUILD_MENU_TRAM_ONLY
) && !RoadTypeIsTram(_cur_roadtype
)) return false;
89 switch (spec
->stop_type
) {
90 case ROADSTOPTYPE_ALL
: return true;
91 case ROADSTOPTYPE_PASSENGER
: return type
== STATION_BUS
;
92 case ROADSTOPTYPE_FREIGHT
: return type
== STATION_TRUCK
;
93 default: NOT_REACHED();
98 * Check whether a road stop type can be built.
99 * @return true if building is allowed.
101 static bool IsRoadStopAvailable(const RoadStopSpec
*spec
, StationType type
)
103 if (spec
== nullptr) return true;
104 if (!IsRoadStopEverAvailable(spec
, type
)) return false;
106 if (!HasBit(spec
->callback_mask
, CBM_ROAD_STOP_AVAIL
)) return true;
108 uint16_t cb_res
= GetRoadStopCallback(CBID_STATION_AVAILABILITY
, 0, 0, spec
, nullptr, INVALID_TILE
, _cur_roadtype
, type
, 0);
109 if (cb_res
== CALLBACK_FAILED
) return true;
111 return Convert8bitBooleanCallback(spec
->grf_prop
.grffile
, CBID_STATION_AVAILABILITY
, cb_res
);
114 void CcPlaySound_CONSTRUCTION_OTHER(Commands
, const CommandCost
&result
, TileIndex tile
)
116 if (result
.Succeeded() && _settings_client
.sound
.confirm
) SndPlayTileFx(SND_1F_CONSTRUCTION_OTHER
, tile
);
120 * Callback to start placing a bridge.
121 * @param tile Start tile of the bridge.
123 static void PlaceRoad_Bridge(TileIndex tile
, Window
*w
)
125 if (IsBridgeTile(tile
)) {
126 TileIndex other_tile
= GetOtherTunnelBridgeEnd(tile
);
128 w
->OnPlaceMouseUp(VPM_X_OR_Y
, DDSP_BUILD_BRIDGE
, pt
, other_tile
, tile
);
130 VpStartPlaceSizing(tile
, VPM_X_OR_Y
, DDSP_BUILD_BRIDGE
);
135 * Callback executed after a build road tunnel command has been called.
137 * @param result Whether the build succeeded.
138 * @param start_tile Starting tile of the tunnel.
140 void CcBuildRoadTunnel(Commands
, const CommandCost
&result
, TileIndex start_tile
)
142 if (result
.Succeeded()) {
143 if (_settings_client
.sound
.confirm
) SndPlayTileFx(SND_1F_CONSTRUCTION_OTHER
, start_tile
);
144 if (!_settings_client
.gui
.persistent_buildingtools
) ResetObjectToPlace();
146 DiagDirection start_direction
= ReverseDiagDir(GetTunnelBridgeDirection(start_tile
));
147 ConnectRoadToStructure(start_tile
, start_direction
);
149 TileIndex end_tile
= GetOtherTunnelBridgeEnd(start_tile
);
150 DiagDirection end_direction
= ReverseDiagDir(GetTunnelBridgeDirection(end_tile
));
151 ConnectRoadToStructure(end_tile
, end_direction
);
153 SetRedErrorSquare(_build_tunnel_endtile
);
158 * If required, connects a new structure to an existing road or tram by building the missing roadbit.
159 * @param tile Tile containing the structure to connect.
160 * @param direction Direction to check.
162 void ConnectRoadToStructure(TileIndex tile
, DiagDirection direction
)
164 tile
+= TileOffsByDiagDir(direction
);
165 /* if there is a roadpiece just outside of the station entrance, build a connecting route */
166 if (IsNormalRoadTile(tile
)) {
167 if (GetRoadBits(tile
, GetRoadTramType(_cur_roadtype
)) != ROAD_NONE
) {
168 Command
<CMD_BUILD_ROAD
>::Post(tile
, DiagDirToRoadBits(ReverseDiagDir(direction
)), _cur_roadtype
, DRD_NONE
, 0);
173 void CcRoadDepot(Commands
, const CommandCost
&result
, TileIndex tile
, RoadType
, DiagDirection dir
)
175 if (result
.Failed()) return;
177 if (_settings_client
.sound
.confirm
) SndPlayTileFx(SND_1F_CONSTRUCTION_OTHER
, tile
);
178 if (!_settings_client
.gui
.persistent_buildingtools
) ResetObjectToPlace();
179 ConnectRoadToStructure(tile
, dir
);
183 * Command callback for building road stops.
184 * @param result Result of the build road stop command.
185 * @param tile Start tile.
186 * @param width Width of the road stop.
187 * @param length Length of the road stop.
188 * @param is_drive_through False for normal stops, true for drive-through.
189 * @param dir Entrance direction (#DiagDirection) for normal stops. Converted to the axis for drive-through stops.
190 * @param spec_class Road stop spec class.
191 * @param spec_index Road stop spec index.
192 * @see CmdBuildRoadStop
194 void CcRoadStop(Commands
, const CommandCost
&result
, TileIndex tile
, uint8_t width
, uint8_t length
, RoadStopType
, bool is_drive_through
,
195 DiagDirection dir
, RoadType
, RoadStopClassID spec_class
, uint16_t spec_index
, StationID
, bool)
197 if (result
.Failed()) return;
199 if (_settings_client
.sound
.confirm
) SndPlayTileFx(SND_1F_CONSTRUCTION_OTHER
, tile
);
200 if (!_settings_client
.gui
.persistent_buildingtools
) ResetObjectToPlace();
202 bool connect_to_road
= true;
203 if ((uint
)spec_class
< RoadStopClass::GetClassCount() && spec_index
< RoadStopClass::Get(spec_class
)->GetSpecCount()) {
204 const RoadStopSpec
*roadstopspec
= RoadStopClass::Get(spec_class
)->GetSpec(spec_index
);
205 if (roadstopspec
!= nullptr && HasBit(roadstopspec
->flags
, RSF_NO_AUTO_ROAD_CONNECTION
)) connect_to_road
= false;
208 if (connect_to_road
) {
209 TileArea
roadstop_area(tile
, width
, length
);
210 for (TileIndex cur_tile
: roadstop_area
) {
211 ConnectRoadToStructure(cur_tile
, dir
);
212 /* For a drive-through road stop build connecting road for other entrance. */
213 if (is_drive_through
) ConnectRoadToStructure(cur_tile
, ReverseDiagDir(dir
));
219 * Place a new road stop.
220 * @param start_tile First tile of the area.
221 * @param end_tile Last tile of the area.
222 * @param stop_type Type of stop (bus/truck).
223 * @param adjacent Allow stations directly adjacent to other stations.
224 * @param rt The roadtypes.
225 * @param err_msg Error message to show.
228 static void PlaceRoadStop(TileIndex start_tile
, TileIndex end_tile
, RoadStopType stop_type
, bool adjacent
, RoadType rt
, StringID err_msg
)
230 TileArea
ta(start_tile
, end_tile
);
231 DiagDirection ddir
= _roadstop_gui
.orientation
;
232 bool drive_through
= ddir
>= DIAGDIR_END
;
233 if (drive_through
) ddir
= static_cast<DiagDirection
>(ddir
- DIAGDIR_END
); // Adjust picker result to actual direction.
234 RoadStopClassID spec_class
= _roadstop_gui
.sel_class
;
235 uint16_t spec_index
= _roadstop_gui
.sel_type
;
237 auto proc
= [=](bool test
, StationID to_join
) -> bool {
239 return Command
<CMD_BUILD_ROAD_STOP
>::Do(CommandFlagsToDCFlags(GetCommandFlags
<CMD_BUILD_ROAD_STOP
>()), ta
.tile
, ta
.w
, ta
.h
, stop_type
, drive_through
,
240 ddir
, rt
, spec_class
, spec_index
, INVALID_STATION
, adjacent
).Succeeded();
242 return Command
<CMD_BUILD_ROAD_STOP
>::Post(err_msg
, CcRoadStop
, ta
.tile
, ta
.w
, ta
.h
, stop_type
, drive_through
,
243 ddir
, rt
, spec_class
, spec_index
, to_join
, adjacent
);
247 ShowSelectStationIfNeeded(ta
, proc
);
251 * Place a road waypoint.
252 * @param tile Position to start dragging a waypoint.
254 static void PlaceRoad_Waypoint(TileIndex tile
)
256 if (_remove_button_clicked
) {
257 VpStartPlaceSizing(tile
, VPM_X_AND_Y
, DDSP_REMOVE_ROAD_WAYPOINT
);
261 Axis axis
= GetAxisForNewRoadWaypoint(tile
);
262 if (IsValidAxis(axis
)) {
263 /* Valid tile for waypoints */
264 VpStartPlaceSizing(tile
, axis
== AXIS_X
? VPM_X_LIMITED
: VPM_Y_LIMITED
, DDSP_BUILD_ROAD_WAYPOINT
);
265 VpSetPlaceSizingLimit(_settings_game
.station
.station_spread
);
267 /* Tile where we can't build road waypoints. This is always going to fail,
268 * but provides the user with a proper error message. */
269 Command
<CMD_BUILD_ROAD_WAYPOINT
>::Post(STR_ERROR_CAN_T_BUILD_ROAD_WAYPOINT
, tile
, AXIS_X
, 1, 1, ROADSTOP_CLASS_WAYP
, 0, INVALID_STATION
, false);
274 * Callback for placing a bus station.
275 * @param tile Position to place the station.
277 static void PlaceRoad_BusStation(TileIndex tile
)
279 if (_remove_button_clicked
) {
280 VpStartPlaceSizing(tile
, VPM_X_AND_Y
, DDSP_REMOVE_BUSSTOP
);
282 if (_roadstop_gui
.orientation
< DIAGDIR_END
) { // Not a drive-through stop.
283 VpStartPlaceSizing(tile
, (DiagDirToAxis(_roadstop_gui
.orientation
) == AXIS_X
) ? VPM_X_LIMITED
: VPM_Y_LIMITED
, DDSP_BUILD_BUSSTOP
);
285 VpStartPlaceSizing(tile
, VPM_X_AND_Y_LIMITED
, DDSP_BUILD_BUSSTOP
);
287 VpSetPlaceSizingLimit(_settings_game
.station
.station_spread
);
292 * Callback for placing a truck station.
293 * @param tile Position to place the station.
295 static void PlaceRoad_TruckStation(TileIndex tile
)
297 if (_remove_button_clicked
) {
298 VpStartPlaceSizing(tile
, VPM_X_AND_Y
, DDSP_REMOVE_TRUCKSTOP
);
300 if (_roadstop_gui
.orientation
< DIAGDIR_END
) { // Not a drive-through stop.
301 VpStartPlaceSizing(tile
, (DiagDirToAxis(_roadstop_gui
.orientation
) == AXIS_X
) ? VPM_X_LIMITED
: VPM_Y_LIMITED
, DDSP_BUILD_TRUCKSTOP
);
303 VpStartPlaceSizing(tile
, VPM_X_AND_Y_LIMITED
, DDSP_BUILD_TRUCKSTOP
);
305 VpSetPlaceSizingLimit(_settings_game
.station
.station_spread
);
309 typedef void OnButtonClick(Window
*w
);
312 * Toggles state of the Remove button of Build road toolbar
313 * @param w window the button belongs to
315 static void ToggleRoadButton_Remove(Window
*w
)
317 w
->ToggleWidgetLoweredState(WID_ROT_REMOVE
);
318 w
->SetWidgetDirty(WID_ROT_REMOVE
);
319 _remove_button_clicked
= w
->IsWidgetLowered(WID_ROT_REMOVE
);
320 SetSelectionRed(_remove_button_clicked
);
324 * Updates the Remove button because of Ctrl state change
325 * @param w window the button belongs to
326 * @return true iff the remove button was changed
328 static bool RoadToolbar_CtrlChanged(Window
*w
)
330 if (w
->IsWidgetDisabled(WID_ROT_REMOVE
)) return false;
332 /* allow ctrl to switch remove mode only for these widgets */
333 for (WidgetID i
= WID_ROT_ROAD_X
; i
<= WID_ROT_AUTOROAD
; i
++) {
334 if (w
->IsWidgetLowered(i
)) {
335 ToggleRoadButton_Remove(w
);
343 /** Road toolbar window handler. */
344 struct BuildRoadToolbarWindow
: Window
{
345 RoadType roadtype
; ///< Road type to build.
346 int last_started_action
; ///< Last started user action.
348 BuildRoadToolbarWindow(WindowDesc
&desc
, WindowNumber window_number
) : Window(desc
)
350 this->roadtype
= _cur_roadtype
;
351 this->CreateNestedTree();
352 this->FinishInitNested(window_number
);
353 this->SetWidgetDisabledState(WID_ROT_REMOVE
, true);
355 if (RoadTypeIsRoad(this->roadtype
)) {
356 this->SetWidgetDisabledState(WID_ROT_ONE_WAY
, true);
359 this->OnInvalidateData();
360 this->last_started_action
= INVALID_WID_ROT
;
362 if (_settings_client
.gui
.link_terraform_toolbar
) ShowTerraformToolbar(this);
365 void Close([[maybe_unused
]] int data
= 0) override
367 if (_game_mode
== GM_NORMAL
&& (this->IsWidgetLowered(WID_ROT_BUS_STATION
) || this->IsWidgetLowered(WID_ROT_TRUCK_STATION
))) SetViewportCatchmentStation(nullptr, true);
368 if (_settings_client
.gui
.link_terraform_toolbar
) CloseWindowById(WC_SCEN_LAND_GEN
, 0, false);
369 this->Window::Close();
373 * Some data on this window has become invalid.
374 * @param data Information about the changed data.
375 * @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.
377 void OnInvalidateData([[maybe_unused
]] int data
= 0, [[maybe_unused
]] bool gui_scope
= true) override
379 if (!gui_scope
) return;
381 if (!ValParamRoadType(this->roadtype
)) {
382 /* Close toolbar if road type is not available. */
387 RoadTramType rtt
= GetRoadTramType(this->roadtype
);
389 bool can_build
= CanBuildVehicleInfrastructure(VEH_ROAD
, rtt
);
390 this->SetWidgetsDisabledState(!can_build
,
392 WID_ROT_BUILD_WAYPOINT
,
394 WID_ROT_TRUCK_STATION
);
396 CloseWindowById(WC_BUS_STATION
, TRANSPORT_ROAD
);
397 CloseWindowById(WC_TRUCK_STATION
, TRANSPORT_ROAD
);
398 CloseWindowById(WC_BUILD_DEPOT
, TRANSPORT_ROAD
);
399 CloseWindowById(WC_BUILD_WAYPOINT
, TRANSPORT_ROAD
);
402 if (_game_mode
!= GM_EDITOR
) {
404 /* Show in the tooltip why this button is disabled. */
405 this->GetWidget
<NWidgetCore
>(WID_ROT_DEPOT
)->SetToolTip(STR_TOOLBAR_DISABLED_NO_VEHICLE_AVAILABLE
);
406 this->GetWidget
<NWidgetCore
>(WID_ROT_BUILD_WAYPOINT
)->SetToolTip(STR_TOOLBAR_DISABLED_NO_VEHICLE_AVAILABLE
);
407 this->GetWidget
<NWidgetCore
>(WID_ROT_BUS_STATION
)->SetToolTip(STR_TOOLBAR_DISABLED_NO_VEHICLE_AVAILABLE
);
408 this->GetWidget
<NWidgetCore
>(WID_ROT_TRUCK_STATION
)->SetToolTip(STR_TOOLBAR_DISABLED_NO_VEHICLE_AVAILABLE
);
410 this->GetWidget
<NWidgetCore
>(WID_ROT_DEPOT
)->SetToolTip(rtt
== RTT_ROAD
? STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT
: STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT
);
411 this->GetWidget
<NWidgetCore
>(WID_ROT_BUILD_WAYPOINT
)->SetToolTip(rtt
== RTT_ROAD
? STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_ROAD_TO_WAYPOINT
: STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_TRAM_TO_WAYPOINT
);
412 this->GetWidget
<NWidgetCore
>(WID_ROT_BUS_STATION
)->SetToolTip(rtt
== RTT_ROAD
? STR_ROAD_TOOLBAR_TOOLTIP_BUILD_BUS_STATION
: STR_ROAD_TOOLBAR_TOOLTIP_BUILD_PASSENGER_TRAM_STATION
);
413 this->GetWidget
<NWidgetCore
>(WID_ROT_TRUCK_STATION
)->SetToolTip(rtt
== RTT_ROAD
? STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRUCK_LOADING_BAY
: STR_ROAD_TOOLBAR_TOOLTIP_BUILD_CARGO_TRAM_STATION
);
418 void OnInit() override
420 /* Configure the road toolbar for the roadtype. */
421 const RoadTypeInfo
*rti
= GetRoadTypeInfo(this->roadtype
);
422 this->GetWidget
<NWidgetCore
>(WID_ROT_ROAD_X
)->widget_data
= rti
->gui_sprites
.build_x_road
;
423 this->GetWidget
<NWidgetCore
>(WID_ROT_ROAD_Y
)->widget_data
= rti
->gui_sprites
.build_y_road
;
424 this->GetWidget
<NWidgetCore
>(WID_ROT_AUTOROAD
)->widget_data
= rti
->gui_sprites
.auto_road
;
425 if (_game_mode
!= GM_EDITOR
) {
426 this->GetWidget
<NWidgetCore
>(WID_ROT_DEPOT
)->widget_data
= rti
->gui_sprites
.build_depot
;
428 this->GetWidget
<NWidgetCore
>(WID_ROT_CONVERT_ROAD
)->widget_data
= rti
->gui_sprites
.convert_road
;
429 this->GetWidget
<NWidgetCore
>(WID_ROT_BUILD_TUNNEL
)->widget_data
= rti
->gui_sprites
.build_tunnel
;
433 * Switch to another road type.
434 * @param roadtype New road type.
436 void ModifyRoadType(RoadType roadtype
)
438 this->roadtype
= roadtype
;
442 void SetStringParameters(WidgetID widget
) const override
444 if (widget
== WID_ROT_CAPTION
) {
445 const RoadTypeInfo
*rti
= GetRoadTypeInfo(this->roadtype
);
446 if (rti
->max_speed
> 0) {
447 SetDParam(0, STR_TOOLBAR_RAILTYPE_VELOCITY
);
448 SetDParam(1, rti
->strings
.toolbar_caption
);
449 SetDParam(2, PackVelocity(rti
->max_speed
/ 2, VEH_ROAD
));
451 SetDParam(0, rti
->strings
.toolbar_caption
);
457 * Update the remove button lowered state of the road toolbar
459 * @param clicked_widget The widget which the client clicked just now
461 void UpdateOptionWidgetStatus(RoadToolbarWidgets clicked_widget
)
463 /* The remove and the one way button state is driven
464 * by the other buttons so they don't act on themselves.
465 * Both are only valid if they are able to apply as options. */
466 switch (clicked_widget
) {
468 if (RoadTypeIsRoad(this->roadtype
)) {
469 this->RaiseWidget(WID_ROT_ONE_WAY
);
470 this->SetWidgetDirty(WID_ROT_ONE_WAY
);
475 case WID_ROT_ONE_WAY
:
476 this->RaiseWidget(WID_ROT_REMOVE
);
477 this->SetWidgetDirty(WID_ROT_REMOVE
);
480 case WID_ROT_BUS_STATION
:
481 case WID_ROT_TRUCK_STATION
:
482 case WID_ROT_BUILD_WAYPOINT
:
483 if (RoadTypeIsRoad(this->roadtype
)) this->DisableWidget(WID_ROT_ONE_WAY
);
484 this->SetWidgetDisabledState(WID_ROT_REMOVE
, !this->IsWidgetLowered(clicked_widget
));
489 case WID_ROT_AUTOROAD
:
490 this->SetWidgetDisabledState(WID_ROT_REMOVE
, !this->IsWidgetLowered(clicked_widget
));
491 if (RoadTypeIsRoad(this->roadtype
)) {
492 this->SetWidgetDisabledState(WID_ROT_ONE_WAY
, !this->IsWidgetLowered(clicked_widget
));
497 /* When any other buttons than road/station, raise and
498 * disable the removal button */
499 this->SetWidgetDisabledState(WID_ROT_REMOVE
, true);
500 this->SetWidgetLoweredState(WID_ROT_REMOVE
, false);
502 if (RoadTypeIsRoad(this->roadtype
)) {
503 this->SetWidgetDisabledState(WID_ROT_ONE_WAY
, true);
504 this->SetWidgetLoweredState(WID_ROT_ONE_WAY
, false);
511 void OnClick([[maybe_unused
]] Point pt
, WidgetID widget
, [[maybe_unused
]] int click_count
) override
513 _remove_button_clicked
= false;
514 _one_way_button_clicked
= false;
517 HandlePlacePushButton(this, WID_ROT_ROAD_X
, GetRoadTypeInfo(this->roadtype
)->cursor
.road_nwse
, HT_RECT
);
518 this->last_started_action
= widget
;
522 HandlePlacePushButton(this, WID_ROT_ROAD_Y
, GetRoadTypeInfo(this->roadtype
)->cursor
.road_swne
, HT_RECT
);
523 this->last_started_action
= widget
;
526 case WID_ROT_AUTOROAD
:
527 HandlePlacePushButton(this, WID_ROT_AUTOROAD
, GetRoadTypeInfo(this->roadtype
)->cursor
.autoroad
, HT_RECT
);
528 this->last_started_action
= widget
;
531 case WID_ROT_DEMOLISH
:
532 HandlePlacePushButton(this, WID_ROT_DEMOLISH
, ANIMCURSOR_DEMOLISH
, HT_RECT
| HT_DIAGONAL
);
533 this->last_started_action
= widget
;
537 if (HandlePlacePushButton(this, WID_ROT_DEPOT
, GetRoadTypeInfo(this->roadtype
)->cursor
.depot
, HT_RECT
)) {
538 ShowRoadDepotPicker(this);
539 this->last_started_action
= widget
;
543 case WID_ROT_BUILD_WAYPOINT
:
544 this->last_started_action
= widget
;
545 if (HandlePlacePushButton(this, WID_ROT_BUILD_WAYPOINT
, SPR_CURSOR_WAYPOINT
, HT_RECT
)) {
546 ShowBuildRoadWaypointPicker(this);
550 case WID_ROT_BUS_STATION
:
551 if (HandlePlacePushButton(this, WID_ROT_BUS_STATION
, SPR_CURSOR_BUS_STATION
, HT_RECT
)) {
552 ShowRVStationPicker(this, ROADSTOP_BUS
);
553 this->last_started_action
= widget
;
557 case WID_ROT_TRUCK_STATION
:
558 if (HandlePlacePushButton(this, WID_ROT_TRUCK_STATION
, SPR_CURSOR_TRUCK_STATION
, HT_RECT
)) {
559 ShowRVStationPicker(this, ROADSTOP_TRUCK
);
560 this->last_started_action
= widget
;
564 case WID_ROT_ONE_WAY
:
565 if (this->IsWidgetDisabled(WID_ROT_ONE_WAY
)) return;
567 this->ToggleWidgetLoweredState(WID_ROT_ONE_WAY
);
568 SetSelectionRed(false);
571 case WID_ROT_BUILD_BRIDGE
:
572 HandlePlacePushButton(this, WID_ROT_BUILD_BRIDGE
, SPR_CURSOR_BRIDGE
, HT_RECT
);
573 this->last_started_action
= widget
;
576 case WID_ROT_BUILD_TUNNEL
:
577 HandlePlacePushButton(this, WID_ROT_BUILD_TUNNEL
, GetRoadTypeInfo(this->roadtype
)->cursor
.tunnel
, HT_SPECIAL
);
578 this->last_started_action
= widget
;
582 if (this->IsWidgetDisabled(WID_ROT_REMOVE
)) return;
584 CloseWindowById(WC_SELECT_STATION
, 0);
585 ToggleRoadButton_Remove(this);
586 if (_settings_client
.sound
.click_beep
) SndPlayFx(SND_15_BEEP
);
589 case WID_ROT_CONVERT_ROAD
:
590 HandlePlacePushButton(this, WID_ROT_CONVERT_ROAD
, GetRoadTypeInfo(this->roadtype
)->cursor
.convert_road
, HT_RECT
);
591 this->last_started_action
= widget
;
594 default: NOT_REACHED();
596 this->UpdateOptionWidgetStatus((RoadToolbarWidgets
)widget
);
597 if (_ctrl_pressed
) RoadToolbar_CtrlChanged(this);
600 EventState
OnHotkey(int hotkey
) override
602 MarkTileDirtyByTile(TileVirtXY(_thd
.pos
.x
, _thd
.pos
.y
)); // redraw tile selection
603 return Window::OnHotkey(hotkey
);
606 void OnPlaceObject([[maybe_unused
]] Point pt
, TileIndex tile
) override
608 _remove_button_clicked
= this->IsWidgetLowered(WID_ROT_REMOVE
);
609 _one_way_button_clicked
= RoadTypeIsRoad(this->roadtype
) ? this->IsWidgetLowered(WID_ROT_ONE_WAY
) : false;
610 switch (this->last_started_action
) {
612 _place_road_dir
= AXIS_X
;
613 _place_road_start_half_x
= _tile_fract_coords
.x
>= 8;
614 VpStartPlaceSizing(tile
, VPM_FIX_Y
, DDSP_PLACE_ROAD_X_DIR
);
618 _place_road_dir
= AXIS_Y
;
619 _place_road_start_half_y
= _tile_fract_coords
.y
>= 8;
620 VpStartPlaceSizing(tile
, VPM_FIX_X
, DDSP_PLACE_ROAD_Y_DIR
);
623 case WID_ROT_AUTOROAD
:
624 _place_road_dir
= INVALID_AXIS
;
625 _place_road_start_half_x
= _tile_fract_coords
.x
>= 8;
626 _place_road_start_half_y
= _tile_fract_coords
.y
>= 8;
627 VpStartPlaceSizing(tile
, VPM_X_OR_Y
, DDSP_PLACE_AUTOROAD
);
630 case WID_ROT_DEMOLISH
:
631 PlaceProc_DemolishArea(tile
);
635 Command
<CMD_BUILD_ROAD_DEPOT
>::Post(GetRoadTypeInfo(this->roadtype
)->strings
.err_depot
, CcRoadDepot
,
636 tile
, _cur_roadtype
, _road_depot_orientation
);
639 case WID_ROT_BUILD_WAYPOINT
:
640 PlaceRoad_Waypoint(tile
);
643 case WID_ROT_BUS_STATION
:
644 PlaceRoad_BusStation(tile
);
647 case WID_ROT_TRUCK_STATION
:
648 PlaceRoad_TruckStation(tile
);
651 case WID_ROT_BUILD_BRIDGE
:
652 PlaceRoad_Bridge(tile
, this);
655 case WID_ROT_BUILD_TUNNEL
:
656 Command
<CMD_BUILD_TUNNEL
>::Post(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE
, CcBuildRoadTunnel
,
657 tile
, TRANSPORT_ROAD
, _cur_roadtype
);
660 case WID_ROT_CONVERT_ROAD
:
661 VpStartPlaceSizing(tile
, VPM_X_AND_Y
, DDSP_CONVERT_ROAD
);
664 default: NOT_REACHED();
668 void OnPlaceObjectAbort() override
670 if (_game_mode
!= GM_EDITOR
&& (this->IsWidgetLowered(WID_ROT_BUS_STATION
) || this->IsWidgetLowered(WID_ROT_TRUCK_STATION
))) SetViewportCatchmentStation(nullptr, true);
672 this->RaiseButtons();
673 this->SetWidgetDisabledState(WID_ROT_REMOVE
, true);
674 this->SetWidgetDirty(WID_ROT_REMOVE
);
676 if (RoadTypeIsRoad(this->roadtype
)) {
677 this->SetWidgetDisabledState(WID_ROT_ONE_WAY
, true);
678 this->SetWidgetDirty(WID_ROT_ONE_WAY
);
681 CloseWindowById(WC_BUS_STATION
, TRANSPORT_ROAD
);
682 CloseWindowById(WC_TRUCK_STATION
, TRANSPORT_ROAD
);
683 CloseWindowById(WC_BUILD_DEPOT
, TRANSPORT_ROAD
);
684 CloseWindowById(WC_BUILD_WAYPOINT
, TRANSPORT_ROAD
);
685 CloseWindowById(WC_SELECT_STATION
, 0);
686 CloseWindowByClass(WC_BUILD_BRIDGE
);
689 void OnPlaceDrag(ViewportPlaceMethod select_method
, [[maybe_unused
]] ViewportDragDropSelectionProcess select_proc
, [[maybe_unused
]] Point pt
) override
691 /* Here we update the end tile flags
692 * of the road placement actions.
693 * At first we reset the end halfroad
694 * bits and if needed we set them again. */
695 switch (select_proc
) {
696 case DDSP_PLACE_ROAD_X_DIR
:
697 _place_road_end_half
= pt
.x
& 8;
700 case DDSP_PLACE_ROAD_Y_DIR
:
701 _place_road_end_half
= pt
.y
& 8;
704 case DDSP_PLACE_AUTOROAD
:
705 /* For autoroad we need to update the
706 * direction of the road */
707 if (_thd
.size
.x
> _thd
.size
.y
|| (_thd
.size
.x
== _thd
.size
.y
&&
708 ( (_tile_fract_coords
.x
< _tile_fract_coords
.y
&& (_tile_fract_coords
.x
+ _tile_fract_coords
.y
) < 16) ||
709 (_tile_fract_coords
.x
> _tile_fract_coords
.y
&& (_tile_fract_coords
.x
+ _tile_fract_coords
.y
) > 16) ))) {
711 _place_road_dir
= AXIS_X
;
712 _place_road_end_half
= pt
.x
& 8;
715 _place_road_dir
= AXIS_Y
;
716 _place_road_end_half
= pt
.y
& 8;
725 VpSelectTilesWithMethod(pt
.x
, pt
.y
, select_method
);
728 void OnPlaceMouseUp([[maybe_unused
]] ViewportPlaceMethod select_method
, ViewportDragDropSelectionProcess select_proc
, [[maybe_unused
]] Point pt
, TileIndex start_tile
, TileIndex end_tile
) override
731 switch (select_proc
) {
732 default: NOT_REACHED();
733 case DDSP_BUILD_BRIDGE
:
734 if (!_settings_client
.gui
.persistent_buildingtools
) ResetObjectToPlace();
735 ShowBuildBridgeWindow(start_tile
, end_tile
, TRANSPORT_ROAD
, _cur_roadtype
);
738 case DDSP_DEMOLISH_AREA
:
739 GUIPlaceProcDragXY(select_proc
, start_tile
, end_tile
);
742 case DDSP_PLACE_ROAD_X_DIR
:
743 case DDSP_PLACE_ROAD_Y_DIR
:
744 case DDSP_PLACE_AUTOROAD
: {
745 bool start_half
= _place_road_dir
== AXIS_Y
? _place_road_start_half_y
: _place_road_start_half_x
;
747 if (_remove_button_clicked
) {
748 Command
<CMD_REMOVE_LONG_ROAD
>::Post(GetRoadTypeInfo(this->roadtype
)->strings
.err_remove_road
, CcPlaySound_CONSTRUCTION_OTHER
,
749 end_tile
, start_tile
, _cur_roadtype
, _place_road_dir
, start_half
, _place_road_end_half
);
751 Command
<CMD_BUILD_LONG_ROAD
>::Post(GetRoadTypeInfo(this->roadtype
)->strings
.err_build_road
, CcPlaySound_CONSTRUCTION_OTHER
,
752 end_tile
, start_tile
, _cur_roadtype
, _place_road_dir
, _one_way_button_clicked
? DRD_NORTHBOUND
: DRD_NONE
, start_half
, _place_road_end_half
, false);
757 case DDSP_BUILD_ROAD_WAYPOINT
:
758 case DDSP_REMOVE_ROAD_WAYPOINT
:
759 if (this->IsWidgetLowered(WID_ROT_BUILD_WAYPOINT
)) {
760 if (_remove_button_clicked
) {
761 Command
<CMD_REMOVE_FROM_ROAD_WAYPOINT
>::Post(STR_ERROR_CAN_T_REMOVE_ROAD_WAYPOINT
, CcPlaySound_CONSTRUCTION_OTHER
, end_tile
, start_tile
);
763 TileArea
ta(start_tile
, end_tile
);
764 Axis axis
= select_method
== VPM_X_LIMITED
? AXIS_X
: AXIS_Y
;
765 bool adjacent
= _ctrl_pressed
;
767 auto proc
= [=](bool test
, StationID to_join
) -> bool {
769 return Command
<CMD_BUILD_ROAD_WAYPOINT
>::Do(CommandFlagsToDCFlags(GetCommandFlags
<CMD_BUILD_ROAD_WAYPOINT
>()), ta
.tile
, axis
, ta
.w
, ta
.h
, _waypoint_gui
.sel_class
, _waypoint_gui
.sel_type
, INVALID_STATION
, adjacent
).Succeeded();
771 return Command
<CMD_BUILD_ROAD_WAYPOINT
>::Post(STR_ERROR_CAN_T_BUILD_ROAD_WAYPOINT
, CcPlaySound_CONSTRUCTION_OTHER
, ta
.tile
, axis
, ta
.w
, ta
.h
, _waypoint_gui
.sel_class
, _waypoint_gui
.sel_type
, to_join
, adjacent
);
775 ShowSelectRoadWaypointIfNeeded(ta
, proc
);
780 case DDSP_BUILD_BUSSTOP
:
781 case DDSP_REMOVE_BUSSTOP
:
782 if (this->IsWidgetLowered(WID_ROT_BUS_STATION
) && GetIfClassHasNewStopsByType(RoadStopClass::Get(_roadstop_gui
.sel_class
), ROADSTOP_BUS
, _cur_roadtype
)) {
783 if (_remove_button_clicked
) {
784 TileArea
ta(start_tile
, end_tile
);
785 Command
<CMD_REMOVE_ROAD_STOP
>::Post(GetRoadTypeInfo(this->roadtype
)->strings
.err_remove_station
[ROADSTOP_BUS
], CcPlaySound_CONSTRUCTION_OTHER
, ta
.tile
, ta
.w
, ta
.h
, ROADSTOP_BUS
, _ctrl_pressed
);
787 PlaceRoadStop(start_tile
, end_tile
, ROADSTOP_BUS
, _ctrl_pressed
, _cur_roadtype
, GetRoadTypeInfo(this->roadtype
)->strings
.err_build_station
[ROADSTOP_BUS
]);
792 case DDSP_BUILD_TRUCKSTOP
:
793 case DDSP_REMOVE_TRUCKSTOP
:
794 if (this->IsWidgetLowered(WID_ROT_TRUCK_STATION
) && GetIfClassHasNewStopsByType(RoadStopClass::Get(_roadstop_gui
.sel_class
), ROADSTOP_TRUCK
, _cur_roadtype
)) {
795 if (_remove_button_clicked
) {
796 TileArea
ta(start_tile
, end_tile
);
797 Command
<CMD_REMOVE_ROAD_STOP
>::Post(GetRoadTypeInfo(this->roadtype
)->strings
.err_remove_station
[ROADSTOP_TRUCK
], CcPlaySound_CONSTRUCTION_OTHER
, ta
.tile
, ta
.w
, ta
.h
, ROADSTOP_TRUCK
, _ctrl_pressed
);
799 PlaceRoadStop(start_tile
, end_tile
, ROADSTOP_TRUCK
, _ctrl_pressed
, _cur_roadtype
, GetRoadTypeInfo(this->roadtype
)->strings
.err_build_station
[ROADSTOP_TRUCK
]);
804 case DDSP_CONVERT_ROAD
:
805 Command
<CMD_CONVERT_ROAD
>::Post(GetRoadTypeInfo(this->roadtype
)->strings
.err_convert_road
, CcPlaySound_CONSTRUCTION_OTHER
, end_tile
, start_tile
, _cur_roadtype
);
811 void OnPlacePresize([[maybe_unused
]] Point pt
, TileIndex tile
) override
813 Command
<CMD_BUILD_TUNNEL
>::Do(DC_AUTO
, tile
, TRANSPORT_ROAD
, _cur_roadtype
);
814 VpSetPresizeRange(tile
, _build_tunnel_endtile
== 0 ? tile
: _build_tunnel_endtile
);
817 EventState
OnCTRLStateChange() override
819 if (RoadToolbar_CtrlChanged(this)) return ES_HANDLED
;
820 return ES_NOT_HANDLED
;
823 void OnRealtimeTick([[maybe_unused
]] uint delta_ms
) override
825 if (_game_mode
== GM_NORMAL
&& this->IsWidgetLowered(WID_ROT_BUILD_WAYPOINT
)) CheckRedrawRoadWaypointCoverage(this);
829 * Handler for global hotkeys of the BuildRoadToolbarWindow.
830 * @param hotkey Hotkey
831 * @param last_build Last build road type
832 * @return ES_HANDLED if hotkey was accepted.
834 static EventState
RoadTramToolbarGlobalHotkeys(int hotkey
, RoadType last_build
, RoadTramType rtt
)
837 switch (_game_mode
) {
839 w
= ShowBuildRoadToolbar(last_build
);
843 if ((GetRoadTypes(true) & ((rtt
== RTT_ROAD
) ? ~_roadtypes_type
: _roadtypes_type
)) == ROADTYPES_NONE
) return ES_NOT_HANDLED
;
844 w
= ShowBuildRoadScenToolbar(last_build
);
851 if (w
== nullptr) return ES_NOT_HANDLED
;
852 return w
->OnHotkey(hotkey
);
855 static EventState
RoadToolbarGlobalHotkeys(int hotkey
)
857 extern RoadType _last_built_roadtype
;
858 return RoadTramToolbarGlobalHotkeys(hotkey
, _last_built_roadtype
, RTT_ROAD
);
861 static EventState
TramToolbarGlobalHotkeys(int hotkey
)
863 extern RoadType _last_built_tramtype
;
864 return RoadTramToolbarGlobalHotkeys(hotkey
, _last_built_tramtype
, RTT_TRAM
);
867 static inline HotkeyList road_hotkeys
{"roadtoolbar", {
868 Hotkey('1', "build_x", WID_ROT_ROAD_X
),
869 Hotkey('2', "build_y", WID_ROT_ROAD_Y
),
870 Hotkey('3', "autoroad", WID_ROT_AUTOROAD
),
871 Hotkey('4', "demolish", WID_ROT_DEMOLISH
),
872 Hotkey('5', "depot", WID_ROT_DEPOT
),
873 Hotkey('6', "bus_station", WID_ROT_BUS_STATION
),
874 Hotkey('7', "truck_station", WID_ROT_TRUCK_STATION
),
875 Hotkey('8', "oneway", WID_ROT_ONE_WAY
),
876 Hotkey('9', "waypoint", WID_ROT_BUILD_WAYPOINT
),
877 Hotkey('B', "bridge", WID_ROT_BUILD_BRIDGE
),
878 Hotkey('T', "tunnel", WID_ROT_BUILD_TUNNEL
),
879 Hotkey('R', "remove", WID_ROT_REMOVE
),
880 Hotkey('C', "convert", WID_ROT_CONVERT_ROAD
),
881 }, RoadToolbarGlobalHotkeys
};
883 static inline HotkeyList tram_hotkeys
{"tramtoolbar", {
884 Hotkey('1', "build_x", WID_ROT_ROAD_X
),
885 Hotkey('2', "build_y", WID_ROT_ROAD_Y
),
886 Hotkey('3', "autoroad", WID_ROT_AUTOROAD
),
887 Hotkey('4', "demolish", WID_ROT_DEMOLISH
),
888 Hotkey('5', "depot", WID_ROT_DEPOT
),
889 Hotkey('6', "bus_station", WID_ROT_BUS_STATION
),
890 Hotkey('7', "truck_station", WID_ROT_TRUCK_STATION
),
891 Hotkey('9', "waypoint", WID_ROT_BUILD_WAYPOINT
),
892 Hotkey('B', "bridge", WID_ROT_BUILD_BRIDGE
),
893 Hotkey('T', "tunnel", WID_ROT_BUILD_TUNNEL
),
894 Hotkey('R', "remove", WID_ROT_REMOVE
),
895 Hotkey('C', "convert", WID_ROT_CONVERT_ROAD
),
896 }, TramToolbarGlobalHotkeys
};
899 static constexpr NWidgetPart _nested_build_road_widgets
[] = {
900 NWidget(NWID_HORIZONTAL
),
901 NWidget(WWT_CLOSEBOX
, COLOUR_DARK_GREEN
),
902 NWidget(WWT_CAPTION
, COLOUR_DARK_GREEN
, WID_ROT_CAPTION
), SetDataTip(STR_JUST_STRING2
, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS
), SetTextStyle(TC_WHITE
),
903 NWidget(WWT_STICKYBOX
, COLOUR_DARK_GREEN
),
905 NWidget(NWID_HORIZONTAL
),
906 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_ROAD_X
),
907 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_X_DIR
, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION
),
908 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_ROAD_Y
),
909 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_Y_DIR
, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION
),
910 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_AUTOROAD
),
911 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTOROAD
, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD
),
912 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_DEMOLISH
),
913 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE
, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC
),
914 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_DEPOT
),
915 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_DEPOT
, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT
),
916 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_BUILD_WAYPOINT
),
917 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_WAYPOINT
, STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_ROAD_TO_WAYPOINT
),
918 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_BUS_STATION
),
919 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_BUS_STATION
, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_BUS_STATION
),
920 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_TRUCK_STATION
),
921 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRUCK_BAY
, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRUCK_LOADING_BAY
),
922 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
, -1), SetMinimalSize(0, 22), SetFill(1, 1), EndContainer(),
923 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_ONE_WAY
),
924 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_ONE_WAY
, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_ONE_WAY_ROAD
),
925 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_BUILD_BRIDGE
),
926 SetFill(0, 1), SetMinimalSize(43, 22), SetDataTip(SPR_IMG_BRIDGE
, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_BRIDGE
),
927 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_BUILD_TUNNEL
),
928 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_TUNNEL
, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL
),
929 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_REMOVE
),
930 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE
, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD
),
931 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_CONVERT_ROAD
),
932 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_CONVERT_ROAD
, STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_ROAD
),
936 static WindowDesc
_build_road_desc(
937 WDP_ALIGN_TOOLBAR
, "toolbar_road", 0, 0,
938 WC_BUILD_TOOLBAR
, WC_NONE
,
940 _nested_build_road_widgets
,
941 &BuildRoadToolbarWindow::road_hotkeys
944 static constexpr NWidgetPart _nested_build_tramway_widgets
[] = {
945 NWidget(NWID_HORIZONTAL
),
946 NWidget(WWT_CLOSEBOX
, COLOUR_DARK_GREEN
),
947 NWidget(WWT_CAPTION
, COLOUR_DARK_GREEN
, WID_ROT_CAPTION
), SetDataTip(STR_JUST_STRING2
, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS
), SetTextStyle(TC_WHITE
),
948 NWidget(WWT_STICKYBOX
, COLOUR_DARK_GREEN
),
950 NWidget(NWID_HORIZONTAL
),
951 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_ROAD_X
),
952 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRAMWAY_X_DIR
, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION
),
953 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_ROAD_Y
),
954 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRAMWAY_Y_DIR
, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION
),
955 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_AUTOROAD
),
956 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTOTRAM
, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM
),
957 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_DEMOLISH
),
958 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE
, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC
),
959 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_DEPOT
),
960 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_DEPOT
, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT
),
961 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_BUILD_WAYPOINT
),
962 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_WAYPOINT
, STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_TRAM_TO_WAYPOINT
),
963 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_BUS_STATION
),
964 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_BUS_STATION
, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_PASSENGER_TRAM_STATION
),
965 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_TRUCK_STATION
),
966 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRUCK_BAY
, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_CARGO_TRAM_STATION
),
967 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
, -1), SetMinimalSize(0, 22), SetFill(1, 1), EndContainer(),
968 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_BUILD_BRIDGE
),
969 SetFill(0, 1), SetMinimalSize(43, 22), SetDataTip(SPR_IMG_BRIDGE
, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_BRIDGE
),
970 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_BUILD_TUNNEL
),
971 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_TUNNEL
, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL
),
972 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_REMOVE
),
973 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE
, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS
),
974 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_CONVERT_ROAD
),
975 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_CONVERT_ROAD
, STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_TRAM
),
979 static WindowDesc
_build_tramway_desc(
980 WDP_ALIGN_TOOLBAR
, "toolbar_tramway", 0, 0,
981 WC_BUILD_TOOLBAR
, WC_NONE
,
983 _nested_build_tramway_widgets
,
984 &BuildRoadToolbarWindow::tram_hotkeys
988 * Open the build road toolbar window
990 * If the terraform toolbar is linked to the toolbar, that window is also opened.
992 * @return newly opened road toolbar, or nullptr if the toolbar could not be opened.
994 Window
*ShowBuildRoadToolbar(RoadType roadtype
)
996 if (!Company::IsValidID(_local_company
)) return nullptr;
997 if (!ValParamRoadType(roadtype
)) return nullptr;
999 CloseWindowByClass(WC_BUILD_TOOLBAR
);
1000 _cur_roadtype
= roadtype
;
1002 return AllocateWindowDescFront
<BuildRoadToolbarWindow
>(RoadTypeIsRoad(_cur_roadtype
) ? _build_road_desc
: _build_tramway_desc
, TRANSPORT_ROAD
);
1005 static constexpr NWidgetPart _nested_build_road_scen_widgets
[] = {
1006 NWidget(NWID_HORIZONTAL
),
1007 NWidget(WWT_CLOSEBOX
, COLOUR_DARK_GREEN
),
1008 NWidget(WWT_CAPTION
, COLOUR_DARK_GREEN
, WID_ROT_CAPTION
), SetDataTip(STR_JUST_STRING2
, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS
), SetTextStyle(TC_WHITE
),
1009 NWidget(WWT_STICKYBOX
, COLOUR_DARK_GREEN
),
1011 NWidget(NWID_HORIZONTAL
),
1012 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_ROAD_X
),
1013 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_X_DIR
, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION
),
1014 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_ROAD_Y
),
1015 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_Y_DIR
, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION
),
1016 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_AUTOROAD
),
1017 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTOROAD
, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD
),
1018 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_DEMOLISH
),
1019 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE
, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC
),
1020 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
, -1), SetMinimalSize(0, 22), SetFill(1, 1), EndContainer(),
1021 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_ONE_WAY
),
1022 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_ONE_WAY
, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_ONE_WAY_ROAD
),
1023 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_BUILD_BRIDGE
),
1024 SetFill(0, 1), SetMinimalSize(43, 22), SetDataTip(SPR_IMG_BRIDGE
, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_BRIDGE
),
1025 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_BUILD_TUNNEL
),
1026 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_TUNNEL
, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL
),
1027 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_REMOVE
),
1028 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE
, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD
),
1029 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_CONVERT_ROAD
),
1030 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_CONVERT_ROAD
, STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_ROAD
),
1034 static WindowDesc
_build_road_scen_desc(
1035 WDP_AUTO
, "toolbar_road_scen", 0, 0,
1036 WC_SCEN_BUILD_TOOLBAR
, WC_NONE
,
1038 _nested_build_road_scen_widgets
,
1039 &BuildRoadToolbarWindow::road_hotkeys
1042 static constexpr NWidgetPart _nested_build_tramway_scen_widgets
[] = {
1043 NWidget(NWID_HORIZONTAL
),
1044 NWidget(WWT_CLOSEBOX
, COLOUR_DARK_GREEN
),
1045 NWidget(WWT_CAPTION
, COLOUR_DARK_GREEN
, WID_ROT_CAPTION
), SetDataTip(STR_JUST_STRING2
, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS
), SetTextStyle(TC_WHITE
),
1046 NWidget(WWT_STICKYBOX
, COLOUR_DARK_GREEN
),
1048 NWidget(NWID_HORIZONTAL
),
1049 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_ROAD_X
),
1050 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRAMWAY_X_DIR
, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION
),
1051 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_ROAD_Y
),
1052 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRAMWAY_Y_DIR
, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION
),
1053 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_AUTOROAD
),
1054 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTOTRAM
, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM
),
1055 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_DEMOLISH
),
1056 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE
, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC
),
1057 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
, -1), SetMinimalSize(0, 22), SetFill(1, 1), EndContainer(),
1058 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_BUILD_BRIDGE
),
1059 SetFill(0, 1), SetMinimalSize(43, 22), SetDataTip(SPR_IMG_BRIDGE
, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_BRIDGE
),
1060 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_BUILD_TUNNEL
),
1061 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_TUNNEL
, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL
),
1062 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_REMOVE
),
1063 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE
, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS
),
1064 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_ROT_CONVERT_ROAD
),
1065 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_CONVERT_ROAD
, STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_TRAM
),
1069 static WindowDesc
_build_tramway_scen_desc(
1070 WDP_AUTO
, "toolbar_tram_scen", 0, 0,
1071 WC_SCEN_BUILD_TOOLBAR
, WC_NONE
,
1073 _nested_build_tramway_scen_widgets
,
1074 &BuildRoadToolbarWindow::tram_hotkeys
1078 * Show the road building toolbar in the scenario editor.
1079 * @return The just opened toolbar, or \c nullptr if the toolbar was already open.
1081 Window
*ShowBuildRoadScenToolbar(RoadType roadtype
)
1083 CloseWindowById(WC_SCEN_BUILD_TOOLBAR
, TRANSPORT_ROAD
);
1084 _cur_roadtype
= roadtype
;
1086 return AllocateWindowDescFront
<BuildRoadToolbarWindow
>(RoadTypeIsRoad(_cur_roadtype
) ? _build_road_scen_desc
: _build_tramway_scen_desc
, TRANSPORT_ROAD
);
1089 struct BuildRoadDepotWindow
: public PickerWindowBase
{
1090 BuildRoadDepotWindow(WindowDesc
&desc
, Window
*parent
) : PickerWindowBase(desc
, parent
)
1092 this->CreateNestedTree();
1094 this->LowerWidget(WID_BROD_DEPOT_NE
+ _road_depot_orientation
);
1095 if (RoadTypeIsTram(_cur_roadtype
)) {
1096 this->GetWidget
<NWidgetCore
>(WID_BROD_CAPTION
)->widget_data
= STR_BUILD_DEPOT_TRAM_ORIENTATION_CAPTION
;
1097 for (WidgetID i
= WID_BROD_DEPOT_NE
; i
<= WID_BROD_DEPOT_NW
; i
++) {
1098 this->GetWidget
<NWidgetCore
>(i
)->tool_tip
= STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP
;
1102 this->FinishInitNested(TRANSPORT_ROAD
);
1105 void UpdateWidgetSize(WidgetID widget
, Dimension
&size
, [[maybe_unused
]] const Dimension
&padding
, [[maybe_unused
]] Dimension
&fill
, [[maybe_unused
]] Dimension
&resize
) override
1107 if (!IsInsideMM(widget
, WID_BROD_DEPOT_NE
, WID_BROD_DEPOT_NW
+ 1)) return;
1109 size
.width
= ScaleGUITrad(64) + WidgetDimensions::scaled
.fullbevel
.Horizontal();
1110 size
.height
= ScaleGUITrad(48) + WidgetDimensions::scaled
.fullbevel
.Vertical();
1113 void DrawWidget(const Rect
&r
, WidgetID widget
) const override
1115 if (!IsInsideMM(widget
, WID_BROD_DEPOT_NE
, WID_BROD_DEPOT_NW
+ 1)) return;
1117 DrawPixelInfo tmp_dpi
;
1118 Rect ir
= r
.Shrink(WidgetDimensions::scaled
.bevel
);
1119 if (FillDrawPixelInfo(&tmp_dpi
, ir
)) {
1120 AutoRestoreBackup
dpi_backup(_cur_dpi
, &tmp_dpi
);
1121 int x
= (ir
.Width() - ScaleSpriteTrad(64)) / 2 + ScaleSpriteTrad(31);
1122 int y
= (ir
.Height() + ScaleSpriteTrad(48)) / 2 - ScaleSpriteTrad(31);
1123 DrawRoadDepotSprite(x
, y
, (DiagDirection
)(widget
- WID_BROD_DEPOT_NE
+ DIAGDIR_NE
), _cur_roadtype
);
1127 void OnClick([[maybe_unused
]] Point pt
, WidgetID widget
, [[maybe_unused
]] int click_count
) override
1130 case WID_BROD_DEPOT_NW
:
1131 case WID_BROD_DEPOT_NE
:
1132 case WID_BROD_DEPOT_SW
:
1133 case WID_BROD_DEPOT_SE
:
1134 this->RaiseWidget(WID_BROD_DEPOT_NE
+ _road_depot_orientation
);
1135 _road_depot_orientation
= (DiagDirection
)(widget
- WID_BROD_DEPOT_NE
);
1136 this->LowerWidget(WID_BROD_DEPOT_NE
+ _road_depot_orientation
);
1137 if (_settings_client
.sound
.click_beep
) SndPlayFx(SND_15_BEEP
);
1147 static constexpr NWidgetPart _nested_build_road_depot_widgets
[] = {
1148 NWidget(NWID_HORIZONTAL
),
1149 NWidget(WWT_CLOSEBOX
, COLOUR_DARK_GREEN
),
1150 NWidget(WWT_CAPTION
, COLOUR_DARK_GREEN
, WID_BROD_CAPTION
), SetDataTip(STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION
, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS
),
1152 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
),
1153 NWidget(NWID_HORIZONTAL_LTR
), SetPIP(0, WidgetDimensions::unscaled
.hsep_normal
, 0), SetPIPRatio(1, 0, 1), SetPadding(WidgetDimensions::unscaled
.picker
),
1154 NWidget(NWID_VERTICAL
), SetPIP(0, WidgetDimensions::unscaled
.vsep_normal
, 0),
1155 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_BROD_DEPOT_NW
), SetFill(0, 0), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP
),
1156 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_BROD_DEPOT_SW
), SetFill(0, 0), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP
),
1158 NWidget(NWID_VERTICAL
), SetPIP(0, WidgetDimensions::unscaled
.vsep_normal
, 0),
1159 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_BROD_DEPOT_NE
), SetFill(0, 0), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP
),
1160 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_BROD_DEPOT_SE
), SetFill(0, 0), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP
),
1166 static WindowDesc
_build_road_depot_desc(
1167 WDP_AUTO
, nullptr, 0, 0,
1168 WC_BUILD_DEPOT
, WC_BUILD_TOOLBAR
,
1170 _nested_build_road_depot_widgets
1173 static void ShowRoadDepotPicker(Window
*parent
)
1175 new BuildRoadDepotWindow(_build_road_depot_desc
, parent
);
1178 template <RoadStopType roadstoptype
>
1179 class RoadStopPickerCallbacks
: public PickerCallbacksNewGRFClass
<RoadStopClass
> {
1181 RoadStopPickerCallbacks(const std::string
&ini_group
) : PickerCallbacksNewGRFClass
<RoadStopClass
>(ini_group
) {}
1183 StringID
GetClassTooltip() const override
;
1184 StringID
GetTypeTooltip() const override
;
1186 bool IsActive() const override
1188 for (const auto &cls
: RoadStopClass::Classes()) {
1189 if (IsWaypointClass(cls
)) continue;
1190 for (const auto *spec
: cls
.Specs()) {
1191 if (spec
== nullptr) continue;
1192 if (roadstoptype
== ROADSTOP_TRUCK
&& spec
->stop_type
!= ROADSTOPTYPE_FREIGHT
&& spec
->stop_type
!= ROADSTOPTYPE_ALL
) continue;
1193 if (roadstoptype
== ROADSTOP_BUS
&& spec
->stop_type
!= ROADSTOPTYPE_PASSENGER
&& spec
->stop_type
!= ROADSTOPTYPE_ALL
) continue;
1200 static bool IsClassChoice(const RoadStopClass
&cls
)
1202 return !IsWaypointClass(cls
) && GetIfClassHasNewStopsByType(&cls
, roadstoptype
, _cur_roadtype
);
1205 bool HasClassChoice() const override
1207 return std::count_if(std::begin(RoadStopClass::Classes()), std::end(RoadStopClass::Classes()), IsClassChoice
);
1210 int GetSelectedClass() const override
{ return _roadstop_gui
.sel_class
; }
1211 void SetSelectedClass(int id
) const override
{ _roadstop_gui
.sel_class
= this->GetClassIndex(id
); }
1213 StringID
GetClassName(int id
) const override
1215 const auto *rsc
= this->GetClass(id
);
1216 if (!IsClassChoice(*rsc
)) return INVALID_STRING_ID
;
1220 int GetSelectedType() const override
{ return _roadstop_gui
.sel_type
; }
1221 void SetSelectedType(int id
) const override
{ _roadstop_gui
.sel_type
= id
; }
1223 StringID
GetTypeName(int cls_id
, int id
) const override
1225 const auto *spec
= this->GetSpec(cls_id
, id
);
1226 if (!IsRoadStopEverAvailable(spec
, roadstoptype
== ROADSTOP_BUS
? STATION_BUS
: STATION_TRUCK
)) return INVALID_STRING_ID
;
1227 return (spec
== nullptr) ? STR_STATION_CLASS_DFLT_ROADSTOP
: spec
->name
;
1230 bool IsTypeAvailable(int cls_id
, int id
) const override
1232 const auto *spec
= this->GetSpec(cls_id
, id
);
1233 return IsRoadStopAvailable(spec
, roadstoptype
== ROADSTOP_BUS
? STATION_BUS
: STATION_TRUCK
);
1236 void DrawType(int x
, int y
, int cls_id
, int id
) const override
1238 const auto *spec
= this->GetSpec(cls_id
, id
);
1239 if (spec
== nullptr) {
1240 StationPickerDrawSprite(x
, y
, roadstoptype
== ROADSTOP_BUS
? STATION_BUS
: STATION_TRUCK
, INVALID_RAILTYPE
, _cur_roadtype
, _roadstop_gui
.orientation
);
1242 DiagDirection orientation
= _roadstop_gui
.orientation
;
1243 if (orientation
< DIAGDIR_END
&& HasBit(spec
->flags
, RSF_DRIVE_THROUGH_ONLY
)) orientation
= DIAGDIR_END
;
1244 DrawRoadStopTile(x
, y
, _cur_roadtype
, spec
, roadstoptype
== ROADSTOP_BUS
? STATION_BUS
: STATION_TRUCK
, (uint8_t)orientation
);
1248 void FillUsedItems(std::set
<PickerItem
> &items
) override
1250 for (const Station
*st
: Station::Iterate()) {
1251 if (st
->owner
!= _local_company
) continue;
1252 if (roadstoptype
== ROADSTOP_TRUCK
&& !(st
->facilities
& FACIL_TRUCK_STOP
)) continue;
1253 if (roadstoptype
== ROADSTOP_BUS
&& !(st
->facilities
& FACIL_BUS_STOP
)) continue;
1254 items
.insert({0, 0, ROADSTOP_CLASS_DFLT
, 0}); // We would need to scan the map to find out if default is used.
1255 for (const auto &sm
: st
->roadstop_speclist
) {
1256 if (sm
.spec
== nullptr) continue;
1257 if (roadstoptype
== ROADSTOP_TRUCK
&& sm
.spec
->stop_type
!= ROADSTOPTYPE_FREIGHT
&& sm
.spec
->stop_type
!= ROADSTOPTYPE_ALL
) continue;
1258 if (roadstoptype
== ROADSTOP_BUS
&& sm
.spec
->stop_type
!= ROADSTOPTYPE_PASSENGER
&& sm
.spec
->stop_type
!= ROADSTOPTYPE_ALL
) continue;
1259 items
.insert({sm
.grfid
, sm
.localidx
, sm
.spec
->class_index
, sm
.spec
->index
});
1265 template <> StringID RoadStopPickerCallbacks
<ROADSTOP_BUS
>::GetClassTooltip() const { return STR_PICKER_ROADSTOP_BUS_CLASS_TOOLTIP
; }
1266 template <> StringID RoadStopPickerCallbacks
<ROADSTOP_BUS
>::GetTypeTooltip() const { return STR_PICKER_ROADSTOP_BUS_TYPE_TOOLTIP
; }
1268 template <> StringID RoadStopPickerCallbacks
<ROADSTOP_TRUCK
>::GetClassTooltip() const { return STR_PICKER_ROADSTOP_TRUCK_CLASS_TOOLTIP
; }
1269 template <> StringID RoadStopPickerCallbacks
<ROADSTOP_TRUCK
>::GetTypeTooltip() const { return STR_PICKER_ROADSTOP_TRUCK_TYPE_TOOLTIP
; }
1271 static RoadStopPickerCallbacks
<ROADSTOP_BUS
> _bus_callback_instance("fav_passenger_roadstops");
1272 static RoadStopPickerCallbacks
<ROADSTOP_TRUCK
> _truck_callback_instance("fav_freight_roadstops");
1274 static PickerCallbacks
&GetRoadStopPickerCallbacks(RoadStopType rs
)
1276 return rs
== ROADSTOP_BUS
? static_cast<PickerCallbacks
&>(_bus_callback_instance
) : static_cast<PickerCallbacks
&>(_truck_callback_instance
);
1279 struct BuildRoadStationWindow
: public PickerWindow
{
1281 uint coverage_height
; ///< Height of the coverage texts.
1283 void CheckOrientationValid()
1285 const RoadStopSpec
*spec
= RoadStopClass::Get(_roadstop_gui
.sel_class
)->GetSpec(_roadstop_gui
.sel_type
);
1287 /* Raise and lower to ensure the correct widget is lowered after changing displayed orientation plane. */
1288 if (RoadTypeIsRoad(_cur_roadtype
)) {
1289 this->RaiseWidget(WID_BROS_STATION_NE
+ _roadstop_gui
.orientation
);
1290 this->GetWidget
<NWidgetStacked
>(WID_BROS_AVAILABLE_ORIENTATIONS
)->SetDisplayedPlane((spec
!= nullptr && HasBit(spec
->flags
, RSF_DRIVE_THROUGH_ONLY
)) ? 1 : 0);
1291 this->LowerWidget(WID_BROS_STATION_NE
+ _roadstop_gui
.orientation
);
1294 if (_roadstop_gui
.orientation
>= DIAGDIR_END
) return;
1296 if (spec
!= nullptr && HasBit(spec
->flags
, RSF_DRIVE_THROUGH_ONLY
)) {
1297 this->RaiseWidget(WID_BROS_STATION_NE
+ _roadstop_gui
.orientation
);
1298 _roadstop_gui
.orientation
= DIAGDIR_END
;
1299 this->LowerWidget(WID_BROS_STATION_NE
+ _roadstop_gui
.orientation
);
1301 CloseWindowById(WC_SELECT_STATION
, 0);
1306 BuildRoadStationWindow(WindowDesc
&desc
, Window
*parent
, RoadStopType rs
) : PickerWindow(desc
, parent
, TRANSPORT_ROAD
, GetRoadStopPickerCallbacks(rs
))
1308 this->coverage_height
= 2 * GetCharacterHeight(FS_NORMAL
) + WidgetDimensions::scaled
.vsep_normal
;
1310 /* Trams don't have non-drivethrough stations */
1311 if (RoadTypeIsTram(_cur_roadtype
) && _roadstop_gui
.orientation
< DIAGDIR_END
) {
1312 _roadstop_gui
.orientation
= DIAGDIR_END
;
1314 this->ConstructWindow();
1316 const RoadTypeInfo
*rti
= GetRoadTypeInfo(_cur_roadtype
);
1317 this->GetWidget
<NWidgetCore
>(WID_BROS_CAPTION
)->widget_data
= rti
->strings
.picker_title
[rs
];
1319 for (WidgetID i
= RoadTypeIsTram(_cur_roadtype
) ? WID_BROS_STATION_X
: WID_BROS_STATION_NE
; i
< WID_BROS_LT_OFF
; i
++) {
1320 this->GetWidget
<NWidgetCore
>(i
)->tool_tip
= rti
->strings
.picker_tooltip
[rs
];
1323 this->LowerWidget(WID_BROS_STATION_NE
+ _roadstop_gui
.orientation
);
1324 this->LowerWidget(WID_BROS_LT_OFF
+ _settings_client
.gui
.station_show_coverage
);
1326 this->window_class
= (rs
== ROADSTOP_BUS
) ? WC_BUS_STATION
: WC_TRUCK_STATION
;
1329 void Close([[maybe_unused
]] int data
= 0) override
1331 CloseWindowById(WC_SELECT_STATION
, 0);
1332 this->PickerWindow::Close();
1335 void OnInvalidateData([[maybe_unused
]] int data
= 0, [[maybe_unused
]] bool gui_scope
= true) override
1337 this->PickerWindow::OnInvalidateData(data
, gui_scope
);
1340 this->CheckOrientationValid();
1344 void OnPaint() override
1346 this->DrawWidgets();
1348 int rad
= _settings_game
.station
.modified_catchment
? ((this->window_class
== WC_BUS_STATION
) ? CA_BUS
: CA_TRUCK
) : CA_UNMODIFIED
;
1349 if (_settings_client
.gui
.station_show_coverage
) {
1350 SetTileSelectBigSize(-rad
, -rad
, 2 * rad
, 2 * rad
);
1352 SetTileSelectSize(1, 1);
1355 if (this->IsShaded()) return;
1357 /* 'Accepts' and 'Supplies' texts. */
1358 StationCoverageType sct
= (this->window_class
== WC_BUS_STATION
) ? SCT_PASSENGERS_ONLY
: SCT_NON_PASSENGERS_ONLY
;
1359 Rect r
= this->GetWidget
<NWidgetBase
>(WID_BROS_ACCEPTANCE
)->GetCurrentRect();
1361 top
= DrawStationCoverageAreaText(r
.left
, r
.right
, top
, sct
, rad
, false) + WidgetDimensions::scaled
.vsep_normal
;
1362 top
= DrawStationCoverageAreaText(r
.left
, r
.right
, top
, sct
, rad
, true);
1363 /* Resize background if the window is too small.
1364 * Never make the window smaller to avoid oscillating if the size change affects the acceptance.
1365 * (This is the case, if making the window bigger moves the mouse into the window.) */
1366 if (top
> r
.bottom
) {
1367 this->coverage_height
+= top
- r
.bottom
;
1372 void UpdateWidgetSize(WidgetID widget
, Dimension
&size
, [[maybe_unused
]] const Dimension
&padding
, [[maybe_unused
]] Dimension
&fill
, [[maybe_unused
]] Dimension
&resize
) override
1375 case WID_BROS_STATION_NE
:
1376 case WID_BROS_STATION_SE
:
1377 case WID_BROS_STATION_SW
:
1378 case WID_BROS_STATION_NW
:
1379 case WID_BROS_STATION_X
:
1380 case WID_BROS_STATION_Y
:
1381 size
.width
= ScaleGUITrad(PREVIEW_WIDTH
) + WidgetDimensions::scaled
.fullbevel
.Horizontal();
1382 size
.height
= ScaleGUITrad(PREVIEW_HEIGHT
) + WidgetDimensions::scaled
.fullbevel
.Vertical();
1385 case WID_BROS_ACCEPTANCE
:
1386 size
.height
= this->coverage_height
;
1390 this->PickerWindow::UpdateWidgetSize(widget
, size
, padding
, fill
, resize
);
1396 * Simply to have a easier way to get the StationType for bus, truck and trams from the WindowClass.
1398 StationType
GetRoadStationTypeByWindowClass(WindowClass window_class
) const
1400 switch (window_class
) {
1401 case WC_BUS_STATION
: return STATION_BUS
;
1402 case WC_TRUCK_STATION
: return STATION_TRUCK
;
1403 default: NOT_REACHED();
1407 void DrawWidget(const Rect
&r
, WidgetID widget
) const override
1410 case WID_BROS_STATION_NE
:
1411 case WID_BROS_STATION_SE
:
1412 case WID_BROS_STATION_SW
:
1413 case WID_BROS_STATION_NW
:
1414 case WID_BROS_STATION_X
:
1415 case WID_BROS_STATION_Y
: {
1416 StationType st
= GetRoadStationTypeByWindowClass(this->window_class
);
1417 const RoadStopSpec
*spec
= RoadStopClass::Get(_roadstop_gui
.sel_class
)->GetSpec(_roadstop_gui
.sel_type
);
1418 DrawPixelInfo tmp_dpi
;
1419 Rect ir
= r
.Shrink(WidgetDimensions::scaled
.bevel
);
1420 if (FillDrawPixelInfo(&tmp_dpi
, ir
)) {
1421 AutoRestoreBackup
dpi_backup(_cur_dpi
, &tmp_dpi
);
1422 int x
= (ir
.Width() - ScaleSpriteTrad(PREVIEW_WIDTH
)) / 2 + ScaleSpriteTrad(PREVIEW_LEFT
);
1423 int y
= (ir
.Height() + ScaleSpriteTrad(PREVIEW_HEIGHT
)) / 2 - ScaleSpriteTrad(PREVIEW_BOTTOM
);
1424 if (spec
== nullptr) {
1425 StationPickerDrawSprite(x
, y
, st
, INVALID_RAILTYPE
, _cur_roadtype
, widget
- WID_BROS_STATION_NE
);
1427 DrawRoadStopTile(x
, y
, _cur_roadtype
, spec
, st
, widget
- WID_BROS_STATION_NE
);
1434 this->PickerWindow::DrawWidget(r
, widget
);
1439 void OnClick([[maybe_unused
]] Point pt
, WidgetID widget
, [[maybe_unused
]] int click_count
) override
1442 case WID_BROS_STATION_NE
:
1443 case WID_BROS_STATION_SE
:
1444 case WID_BROS_STATION_SW
:
1445 case WID_BROS_STATION_NW
:
1446 case WID_BROS_STATION_X
:
1447 case WID_BROS_STATION_Y
:
1448 if (widget
< WID_BROS_STATION_X
) {
1449 const RoadStopSpec
*spec
= RoadStopClass::Get(_roadstop_gui
.sel_class
)->GetSpec(_roadstop_gui
.sel_type
);
1450 if (spec
!= nullptr && HasBit(spec
->flags
, RSF_DRIVE_THROUGH_ONLY
)) return;
1452 this->RaiseWidget(WID_BROS_STATION_NE
+ _roadstop_gui
.orientation
);
1453 _roadstop_gui
.orientation
= (DiagDirection
)(widget
- WID_BROS_STATION_NE
);
1454 this->LowerWidget(WID_BROS_STATION_NE
+ _roadstop_gui
.orientation
);
1455 if (_settings_client
.sound
.click_beep
) SndPlayFx(SND_15_BEEP
);
1457 CloseWindowById(WC_SELECT_STATION
, 0);
1460 case WID_BROS_LT_OFF
:
1461 case WID_BROS_LT_ON
:
1462 this->RaiseWidget(_settings_client
.gui
.station_show_coverage
+ WID_BROS_LT_OFF
);
1463 _settings_client
.gui
.station_show_coverage
= (widget
!= WID_BROS_LT_OFF
);
1464 this->LowerWidget(_settings_client
.gui
.station_show_coverage
+ WID_BROS_LT_OFF
);
1465 if (_settings_client
.sound
.click_beep
) SndPlayFx(SND_15_BEEP
);
1467 SetViewportCatchmentStation(nullptr, true);
1471 this->PickerWindow::OnClick(pt
, widget
, click_count
);
1476 void OnRealtimeTick([[maybe_unused
]] uint delta_ms
) override
1478 CheckRedrawStationCoverage(this);
1481 static inline HotkeyList road_hotkeys
{"buildroadstop", {
1482 Hotkey('F', "focus_filter_box", PCWHK_FOCUS_FILTER_BOX
),
1485 static inline HotkeyList tram_hotkeys
{"buildtramstop", {
1486 Hotkey('F', "focus_filter_box", PCWHK_FOCUS_FILTER_BOX
),
1490 /** Widget definition of the build road station window */
1491 static constexpr NWidgetPart _nested_road_station_picker_widgets
[] = {
1492 NWidget(NWID_HORIZONTAL
),
1493 NWidget(WWT_CLOSEBOX
, COLOUR_DARK_GREEN
),
1494 NWidget(WWT_CAPTION
, COLOUR_DARK_GREEN
, WID_BROS_CAPTION
),
1495 NWidget(WWT_SHADEBOX
, COLOUR_DARK_GREEN
),
1496 NWidget(WWT_DEFSIZEBOX
, COLOUR_DARK_GREEN
),
1498 NWidget(NWID_HORIZONTAL
),
1499 NWidget(NWID_VERTICAL
),
1500 NWidgetFunction(MakePickerClassWidgets
),
1501 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
),
1502 NWidget(NWID_VERTICAL
), SetPIP(0, WidgetDimensions::unscaled
.vsep_picker
, 0), SetPadding(WidgetDimensions::unscaled
.picker
),
1503 NWidget(NWID_SELECTION
, INVALID_COLOUR
, WID_BROS_AVAILABLE_ORIENTATIONS
),
1504 /* 6-orientation plane. */
1505 NWidget(NWID_VERTICAL
), SetPIP(0, WidgetDimensions::unscaled
.vsep_normal
, 0),
1506 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_normal
, 0), SetPIPRatio(1, 0, 1),
1507 NWidget(NWID_HORIZONTAL_LTR
), SetPIP(0, WidgetDimensions::unscaled
.hsep_normal
, 0),
1508 NWidget(WWT_PANEL
, COLOUR_GREY
, WID_BROS_STATION_NW
), SetFill(0, 0), EndContainer(),
1509 NWidget(WWT_PANEL
, COLOUR_GREY
, WID_BROS_STATION_NE
), SetFill(0, 0), EndContainer(),
1511 NWidget(WWT_PANEL
, COLOUR_GREY
, WID_BROS_STATION_X
), SetFill(0, 0), EndContainer(),
1513 NWidget(NWID_HORIZONTAL
), SetPIP(0, WidgetDimensions::unscaled
.hsep_normal
, 0), SetPIPRatio(1, 0, 1),
1514 NWidget(NWID_HORIZONTAL_LTR
), SetPIP(0, WidgetDimensions::unscaled
.hsep_normal
, 0),
1515 NWidget(WWT_PANEL
, COLOUR_GREY
, WID_BROS_STATION_SW
), SetFill(0, 0), EndContainer(),
1516 NWidget(WWT_PANEL
, COLOUR_GREY
, WID_BROS_STATION_SE
), SetFill(0, 0), EndContainer(),
1518 NWidget(WWT_PANEL
, COLOUR_GREY
, WID_BROS_STATION_Y
), SetFill(0, 0), EndContainer(),
1521 /* 2-orientation plane. */
1522 NWidget(NWID_VERTICAL
), SetPIPRatio(0, 0, 1),
1523 NWidget(NWID_HORIZONTAL_LTR
), SetPIP(0, WidgetDimensions::unscaled
.hsep_normal
, 0), SetPIPRatio(1, 0, 1),
1524 NWidget(WWT_PANEL
, COLOUR_GREY
, WID_BROS_STATION_X
), SetFill(0, 0), EndContainer(),
1525 NWidget(WWT_PANEL
, COLOUR_GREY
, WID_BROS_STATION_Y
), SetFill(0, 0), EndContainer(),
1529 NWidget(WWT_LABEL
, COLOUR_DARK_GREEN
), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE
, STR_NULL
), SetFill(1, 0),
1530 NWidget(NWID_HORIZONTAL
), SetPIPRatio(1, 0, 1),
1531 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_BROS_LT_OFF
), SetMinimalSize(60, 12),
1532 SetDataTip(STR_STATION_BUILD_COVERAGE_OFF
, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP
),
1533 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_BROS_LT_ON
), SetMinimalSize(60, 12),
1534 SetDataTip(STR_STATION_BUILD_COVERAGE_ON
, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP
),
1536 NWidget(WWT_EMPTY
, INVALID_COLOUR
, WID_BROS_ACCEPTANCE
), SetFill(1, 1), SetResize(1, 0), SetMinimalTextLines(2, 0),
1540 NWidgetFunction(MakePickerTypeWidgets
),
1544 static WindowDesc
_road_station_picker_desc(
1545 WDP_AUTO
, "build_station_road", 0, 0,
1546 WC_BUS_STATION
, WC_BUILD_TOOLBAR
,
1548 _nested_road_station_picker_widgets
,
1549 &BuildRoadStationWindow::road_hotkeys
1552 /** Widget definition of the build tram station window */
1553 static constexpr NWidgetPart _nested_tram_station_picker_widgets
[] = {
1554 NWidget(NWID_HORIZONTAL
),
1555 NWidget(WWT_CLOSEBOX
, COLOUR_DARK_GREEN
),
1556 NWidget(WWT_CAPTION
, COLOUR_DARK_GREEN
, WID_BROS_CAPTION
),
1557 NWidget(WWT_SHADEBOX
, COLOUR_DARK_GREEN
),
1558 NWidget(WWT_DEFSIZEBOX
, COLOUR_DARK_GREEN
),
1560 NWidget(NWID_HORIZONTAL
),
1561 NWidget(NWID_VERTICAL
),
1562 NWidgetFunction(MakePickerClassWidgets
),
1563 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
),
1564 NWidget(NWID_VERTICAL
), SetPIP(0, WidgetDimensions::unscaled
.vsep_picker
, 0), SetPadding(WidgetDimensions::unscaled
.picker
),
1565 NWidget(NWID_HORIZONTAL_LTR
), SetPIP(0, WidgetDimensions::unscaled
.hsep_normal
, 0), SetPIPRatio(1, 0, 1),
1566 NWidget(WWT_PANEL
, COLOUR_GREY
, WID_BROS_STATION_X
), SetFill(0, 0), EndContainer(),
1567 NWidget(WWT_PANEL
, COLOUR_GREY
, WID_BROS_STATION_Y
), SetFill(0, 0), EndContainer(),
1569 NWidget(WWT_LABEL
, COLOUR_DARK_GREEN
), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE
, STR_NULL
), SetFill(1, 0),
1570 NWidget(NWID_HORIZONTAL
), SetPIPRatio(1, 0, 1),
1571 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_BROS_LT_OFF
), SetMinimalSize(60, 12),
1572 SetDataTip(STR_STATION_BUILD_COVERAGE_OFF
, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP
),
1573 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_BROS_LT_ON
), SetMinimalSize(60, 12),
1574 SetDataTip(STR_STATION_BUILD_COVERAGE_ON
, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP
),
1576 NWidget(WWT_EMPTY
, INVALID_COLOUR
, WID_BROS_ACCEPTANCE
), SetFill(1, 1), SetResize(1, 0), SetMinimalTextLines(2, 0),
1580 NWidgetFunction(MakePickerTypeWidgets
),
1584 static WindowDesc
_tram_station_picker_desc(
1585 WDP_AUTO
, "build_station_tram", 0, 0,
1586 WC_BUS_STATION
, WC_BUILD_TOOLBAR
,
1588 _nested_tram_station_picker_widgets
,
1589 &BuildRoadStationWindow::tram_hotkeys
1592 static void ShowRVStationPicker(Window
*parent
, RoadStopType rs
)
1594 new BuildRoadStationWindow(RoadTypeIsRoad(_cur_roadtype
) ? _road_station_picker_desc
: _tram_station_picker_desc
, parent
, rs
);
1597 class RoadWaypointPickerCallbacks
: public PickerCallbacksNewGRFClass
<RoadStopClass
> {
1599 RoadWaypointPickerCallbacks() : PickerCallbacksNewGRFClass
<RoadStopClass
>("fav_road_waypoints") {}
1601 StringID
GetClassTooltip() const override
{ return STR_PICKER_WAYPOINT_CLASS_TOOLTIP
; }
1602 StringID
GetTypeTooltip() const override
{ return STR_PICKER_WAYPOINT_TYPE_TOOLTIP
; }
1604 bool IsActive() const override
1606 for (const auto &cls
: RoadStopClass::Classes()) {
1607 if (!IsWaypointClass(cls
)) continue;
1608 for (const auto *spec
: cls
.Specs()) {
1609 if (spec
!= nullptr) return true;
1615 bool HasClassChoice() const override
1617 return std::count_if(std::begin(RoadStopClass::Classes()), std::end(RoadStopClass::Classes()), IsWaypointClass
) > 1;
1620 void Close(int) override
{ ResetObjectToPlace(); }
1621 int GetSelectedClass() const override
{ return _waypoint_gui
.sel_class
; }
1622 void SetSelectedClass(int id
) const override
{ _waypoint_gui
.sel_class
= this->GetClassIndex(id
); }
1624 StringID
GetClassName(int id
) const override
1626 const auto *sc
= GetClass(id
);
1627 if (!IsWaypointClass(*sc
)) return INVALID_STRING_ID
;
1631 int GetSelectedType() const override
{ return _waypoint_gui
.sel_type
; }
1632 void SetSelectedType(int id
) const override
{ _waypoint_gui
.sel_type
= id
; }
1634 StringID
GetTypeName(int cls_id
, int id
) const override
1636 const auto *spec
= this->GetSpec(cls_id
, id
);
1637 return (spec
== nullptr) ? STR_STATION_CLASS_WAYP_WAYPOINT
: spec
->name
;
1640 bool IsTypeAvailable(int cls_id
, int id
) const override
1642 return IsRoadStopAvailable(this->GetSpec(cls_id
, id
), STATION_ROADWAYPOINT
);
1645 void DrawType(int x
, int y
, int cls_id
, int id
) const override
1647 const auto *spec
= this->GetSpec(cls_id
, id
);
1648 if (spec
== nullptr) {
1649 StationPickerDrawSprite(x
, y
, STATION_ROADWAYPOINT
, INVALID_RAILTYPE
, _cur_roadtype
, RSV_DRIVE_THROUGH_X
);
1651 DrawRoadStopTile(x
, y
, _cur_roadtype
, spec
, STATION_ROADWAYPOINT
, RSV_DRIVE_THROUGH_X
);
1655 void FillUsedItems(std::set
<PickerItem
> &items
) override
1657 for (const Waypoint
*wp
: Waypoint::Iterate()) {
1658 if (wp
->owner
!= _local_company
|| !HasBit(wp
->waypoint_flags
, WPF_ROAD
)) continue;
1659 items
.insert({0, 0, ROADSTOP_CLASS_WAYP
, 0}); // We would need to scan the map to find out if default is used.
1660 for (const auto &sm
: wp
->roadstop_speclist
) {
1661 if (sm
.spec
== nullptr) continue;
1662 items
.insert({sm
.grfid
, sm
.localidx
, sm
.spec
->class_index
, sm
.spec
->index
});
1667 static RoadWaypointPickerCallbacks instance
;
1669 /* static */ RoadWaypointPickerCallbacks
RoadWaypointPickerCallbacks::instance
;
1671 struct BuildRoadWaypointWindow
: public PickerWindow
{
1672 BuildRoadWaypointWindow(WindowDesc
&desc
, Window
*parent
) : PickerWindow(desc
, parent
, TRANSPORT_ROAD
, RoadWaypointPickerCallbacks::instance
)
1674 this->ConstructWindow();
1675 this->InvalidateData();
1678 static inline HotkeyList hotkeys
{"buildroadwaypoint", {
1679 Hotkey('F', "focus_filter_box", PCWHK_FOCUS_FILTER_BOX
),
1683 /** Nested widget definition for the build NewGRF road waypoint window */
1684 static constexpr NWidgetPart _nested_build_road_waypoint_widgets
[] = {
1685 NWidget(NWID_HORIZONTAL
),
1686 NWidget(WWT_CLOSEBOX
, COLOUR_DARK_GREEN
),
1687 NWidget(WWT_CAPTION
, COLOUR_DARK_GREEN
), SetDataTip(STR_WAYPOINT_CAPTION
, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS
),
1688 NWidget(WWT_SHADEBOX
, COLOUR_DARK_GREEN
),
1689 NWidget(WWT_DEFSIZEBOX
, COLOUR_DARK_GREEN
),
1691 NWidget(NWID_HORIZONTAL
),
1692 NWidgetFunction(MakePickerClassWidgets
),
1693 NWidgetFunction(MakePickerTypeWidgets
),
1697 static WindowDesc
_build_road_waypoint_desc(
1698 WDP_AUTO
, "build_road_waypoint", 0, 0,
1699 WC_BUILD_WAYPOINT
, WC_BUILD_TOOLBAR
,
1701 _nested_build_road_waypoint_widgets
,
1702 &BuildRoadWaypointWindow::hotkeys
1705 static void ShowBuildRoadWaypointPicker(Window
*parent
)
1707 if (!RoadWaypointPickerCallbacks::instance
.IsActive()) return;
1708 new BuildRoadWaypointWindow(_build_road_waypoint_desc
, parent
);
1711 void InitializeRoadGui()
1713 _road_depot_orientation
= DIAGDIR_NW
;
1714 _roadstop_gui
.orientation
= DIAGDIR_NW
;
1715 _waypoint_gui
.sel_class
= RoadStopClassID::ROADSTOP_CLASS_WAYP
;
1716 _waypoint_gui
.sel_type
= 0;
1720 * I really don't know why rail_gui.cpp has this too, shouldn't be included in the other one?
1722 void InitializeRoadGUI()
1724 BuildRoadToolbarWindow
*w
= dynamic_cast<BuildRoadToolbarWindow
*>(FindWindowById(WC_BUILD_TOOLBAR
, TRANSPORT_ROAD
));
1725 if (w
!= nullptr) w
->ModifyRoadType(_cur_roadtype
);
1728 DropDownList
GetRoadTypeDropDownList(RoadTramTypes rtts
, bool for_replacement
, bool all_option
)
1730 RoadTypes used_roadtypes
;
1731 RoadTypes avail_roadtypes
;
1733 const Company
*c
= Company::Get(_local_company
);
1735 /* Find the used roadtypes. */
1736 if (for_replacement
) {
1737 avail_roadtypes
= GetCompanyRoadTypes(c
->index
, false);
1738 used_roadtypes
= GetRoadTypes(false);
1740 avail_roadtypes
= c
->avail_roadtypes
;
1741 used_roadtypes
= GetRoadTypes(true);
1744 /* Filter listed road types */
1745 if (!HasBit(rtts
, RTT_ROAD
)) used_roadtypes
&= _roadtypes_type
;
1746 if (!HasBit(rtts
, RTT_TRAM
)) used_roadtypes
&= ~_roadtypes_type
;
1751 list
.push_back(MakeDropDownListStringItem(STR_REPLACE_ALL_ROADTYPE
, INVALID_ROADTYPE
));
1754 Dimension d
= { 0, 0 };
1755 /* Get largest icon size, to ensure text is aligned on each menu item. */
1756 if (!for_replacement
) {
1757 for (const auto &rt
: _sorted_roadtypes
) {
1758 if (!HasBit(used_roadtypes
, rt
)) continue;
1759 const RoadTypeInfo
*rti
= GetRoadTypeInfo(rt
);
1760 d
= maxdim(d
, GetSpriteSize(rti
->gui_sprites
.build_x_road
));
1764 for (const auto &rt
: _sorted_roadtypes
) {
1765 /* If it's not used ever, don't show it to the user. */
1766 if (!HasBit(used_roadtypes
, rt
)) continue;
1768 const RoadTypeInfo
*rti
= GetRoadTypeInfo(rt
);
1770 SetDParam(0, rti
->strings
.menu_text
);
1771 SetDParam(1, rti
->max_speed
/ 2);
1772 if (for_replacement
) {
1773 list
.push_back(MakeDropDownListStringItem(rti
->strings
.replace_text
, rt
, !HasBit(avail_roadtypes
, rt
)));
1775 StringID str
= rti
->max_speed
> 0 ? STR_TOOLBAR_RAILTYPE_VELOCITY
: STR_JUST_STRING
;
1776 list
.push_back(MakeDropDownListIconItem(d
, rti
->gui_sprites
.build_x_road
, PAL_NONE
, str
, rt
, !HasBit(avail_roadtypes
, rt
)));
1781 /* Empty dropdowns are not allowed */
1782 list
.push_back(MakeDropDownListStringItem(STR_NONE
, INVALID_ROADTYPE
, true));
1788 DropDownList
GetScenRoadTypeDropDownList(RoadTramTypes rtts
)
1790 RoadTypes avail_roadtypes
= GetRoadTypes(false);
1791 avail_roadtypes
= AddDateIntroducedRoadTypes(avail_roadtypes
, TimerGameCalendar::date
);
1792 RoadTypes used_roadtypes
= GetRoadTypes(true);
1794 /* Filter listed road types */
1795 if (!HasBit(rtts
, RTT_ROAD
)) used_roadtypes
&= _roadtypes_type
;
1796 if (!HasBit(rtts
, RTT_TRAM
)) used_roadtypes
&= ~_roadtypes_type
;
1800 /* If it's not used ever, don't show it to the user. */
1801 Dimension d
= { 0, 0 };
1802 for (const auto &rt
: _sorted_roadtypes
) {
1803 if (!HasBit(used_roadtypes
, rt
)) continue;
1804 const RoadTypeInfo
*rti
= GetRoadTypeInfo(rt
);
1805 d
= maxdim(d
, GetSpriteSize(rti
->gui_sprites
.build_x_road
));
1807 for (const auto &rt
: _sorted_roadtypes
) {
1808 if (!HasBit(used_roadtypes
, rt
)) continue;
1810 const RoadTypeInfo
*rti
= GetRoadTypeInfo(rt
);
1812 SetDParam(0, rti
->strings
.menu_text
);
1813 SetDParam(1, rti
->max_speed
/ 2);
1814 StringID str
= rti
->max_speed
> 0 ? STR_TOOLBAR_RAILTYPE_VELOCITY
: STR_JUST_STRING
;
1815 list
.push_back(MakeDropDownListIconItem(d
, rti
->gui_sprites
.build_x_road
, PAL_NONE
, str
, rt
, !HasBit(avail_roadtypes
, rt
)));
1819 /* Empty dropdowns are not allowed */
1820 list
.push_back(MakeDropDownListStringItem(STR_NONE
, -1, true));