OpenTTD

- Main Page
- Related Pages
- Modules
- Namespaces
- Data Structures
- Files

- File List
- Globals

road_gui.cpp
Go to the documentation of this file.
1 /* $Id: road_gui.cpp 27577 2016-05-22 10:52:02Z frosch $ */
2
3 /*
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/>.
8 */
9
12 #include "stdafx.h"
13 #include "gui.h"
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 "road_cmd.h"
20 #include "station_func.h"
21 #include "window_func.h"
22 #include "vehicle_func.h"
23 #include "sound_func.h"
24 #include "company_func.h"
25 #include "tunnelbridge.h"
26 #include "tunnelbridge_map.h"
27 #include "tilehighlight_func.h"
28 #include "company_base.h"
29 #include "hotkeys.h"
30 #include "road_gui.h"
31 #include "zoom_func.h"
32
33 #include "widgets/road_widget.h"
34
35 #include "table/strings.h"
36
37 #include "safeguards.h"
38
39 static void ShowRVStationPicker(Window *parent, RoadStopType rs);
40 static void ShowRoadDepotPicker(Window *parent);
41
42 static bool _remove_button_clicked;
43 static bool _one_way_button_clicked;
44
49 enum RoadFlags {
50 RF_NONE = 0x00,
51 RF_START_HALFROAD_Y = 0x01, // The start tile in Y-dir should have only a half road
52 RF_END_HALFROAD_Y = 0x02, // The end tile in Y-dir should have only a half road
53 RF_DIR_Y = 0x04, // The direction is Y-dir
54 RF_DIR_X = RF_NONE, // Dummy; Dir X is set when RF_DIR_Y is not set
55 RF_START_HALFROAD_X = 0x08, // The start tile in X-dir should have only a half road
56 RF_END_HALFROAD_X = 0x10, // The end tile in X-dir should have only a half road
57 };
58 DECLARE_ENUM_AS_BIT_SET(RoadFlags)
59
60 static RoadFlags _place_road_flag;
61
62 static RoadType _cur_roadtype;
63
64 static DiagDirection _road_depot_orientation;
65 static DiagDirection _road_station_picker_orientation;
66
67 void CcPlaySound_SPLAT_OTHER(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
68 {
69 if (result.Succeeded() && _settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT_OTHER, tile);
70 }
71
76 static void PlaceRoad_Bridge(TileIndex tile, Window *w)
77 {
78 if (IsBridgeTile(tile)) {
79 TileIndex other_tile = GetOtherTunnelBridgeEnd(tile);
80 Point pt = {0, 0};
81 w->OnPlaceMouseUp(VPM_X_OR_Y, DDSP_BUILD_BRIDGE, pt, other_tile, tile);
82 } else {
83 VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_BUILD_BRIDGE);
84 }
85 }
86
96 void CcBuildRoadTunnel(const CommandCost &result, TileIndex start_tile, uint32 p1, uint32 p2)
97 {
98 if (result.Succeeded()) {
99 if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT_OTHER, start_tile);
100 if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
101
102 DiagDirection start_direction = ReverseDiagDir(GetTunnelBridgeDirection(start_tile));
103 ConnectRoadToStructure(start_tile, start_direction);
104
105 TileIndex end_tile = GetOtherTunnelBridgeEnd(start_tile);
106 DiagDirection end_direction = ReverseDiagDir(GetTunnelBridgeDirection(end_tile));
107 ConnectRoadToStructure(end_tile, end_direction);
108 } else {
109 SetRedErrorSquare(_build_tunnel_endtile);
110 }
111 }
112
114 struct RoadTypeInfo {
115 StringID err_build_road;
116 StringID err_remove_road;
117 StringID err_depot;
118 StringID err_build_station[2];
119 StringID err_remove_station[2];
120
121 StringID picker_title[2];
122 StringID picker_tooltip[2];
123
124 SpriteID cursor_nesw;
125 SpriteID cursor_nwse;
126 SpriteID cursor_autoroad;
127 };
128
130 static const RoadTypeInfo _road_type_infos[] = {
131 {
132 STR_ERROR_CAN_T_BUILD_ROAD_HERE,
133 STR_ERROR_CAN_T_REMOVE_ROAD_FROM,
134 STR_ERROR_CAN_T_BUILD_ROAD_DEPOT,
135 { STR_ERROR_CAN_T_BUILD_BUS_STATION, STR_ERROR_CAN_T_BUILD_TRUCK_STATION },
136 { STR_ERROR_CAN_T_REMOVE_BUS_STATION, STR_ERROR_CAN_T_REMOVE_TRUCK_STATION },
137 { STR_STATION_BUILD_BUS_ORIENTATION, STR_STATION_BUILD_TRUCK_ORIENTATION },
138 { STR_STATION_BUILD_BUS_ORIENTATION_TOOLTIP, STR_STATION_BUILD_TRUCK_ORIENTATION_TOOLTIP },
139
140 SPR_CURSOR_ROAD_NESW,
141 SPR_CURSOR_ROAD_NWSE,
142 SPR_CURSOR_AUTOROAD,
143 },
144 {
145 STR_ERROR_CAN_T_BUILD_TRAMWAY_HERE,
146 STR_ERROR_CAN_T_REMOVE_TRAMWAY_FROM,
147 STR_ERROR_CAN_T_BUILD_TRAM_DEPOT,
148 { STR_ERROR_CAN_T_BUILD_PASSENGER_TRAM_STATION, STR_ERROR_CAN_T_BUILD_CARGO_TRAM_STATION },
149 { STR_ERROR_CAN_T_REMOVE_PASSENGER_TRAM_STATION, STR_ERROR_CAN_T_REMOVE_CARGO_TRAM_STATION },
150 { STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION, STR_STATION_BUILD_CARGO_TRAM_ORIENTATION },
151 { STR_STATION_BUILD_PASSENGER_TRAM_ORIENTATION_TOOLTIP, STR_STATION_BUILD_CARGO_TRAM_ORIENTATION_TOOLTIP },
152
153 SPR_CURSOR_TRAMWAY_NESW,
154 SPR_CURSOR_TRAMWAY_NWSE,
155 SPR_CURSOR_AUTOTRAM,
156 },
157 };
158
164 void ConnectRoadToStructure(TileIndex tile, DiagDirection direction)
165 {
166 tile += TileOffsByDiagDir(direction);
167 /* if there is a roadpiece just outside of the station entrance, build a connecting route */
168 if (IsNormalRoadTile(tile)) {
169 if (GetRoadBits(tile, _cur_roadtype) != ROAD_NONE) {
170 DoCommandP(tile, _cur_roadtype << 4 | DiagDirToRoadBits(ReverseDiagDir(direction)), 0, CMD_BUILD_ROAD);
171 }
172 }
173 }
174
175 void CcRoadDepot(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
176 {
177 if (result.Failed()) return;
178
179 DiagDirection dir = (DiagDirection)GB(p1, 0, 2);
180 if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT_OTHER, tile);
181 if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
182 ConnectRoadToStructure(tile, dir);
183 }
184
199 void CcRoadStop(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2)
200 {
201 if (result.Failed()) return;
202
203 DiagDirection dir = (DiagDirection)GB(p2, 6, 2);
204 if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_SPLAT_OTHER, tile);
205 if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
206 TileArea roadstop_area(tile, GB(p1, 0, 8), GB(p1, 8, 8));
207 TILE_AREA_LOOP(cur_tile, roadstop_area) {
208 ConnectRoadToStructure(cur_tile, dir);
209 /* For a drive-through road stop build connecting road for other entrance. */
210 if (HasBit(p2, 1)) ConnectRoadToStructure(cur_tile, ReverseDiagDir(dir));
211 }
212 }
213
224 static void PlaceRoadStop(TileIndex start_tile, TileIndex end_tile, uint32 p2, uint32 cmd)
225 {
226 uint8 ddir = _road_station_picker_orientation;
227 SB(p2, 16, 16, INVALID_STATION); // no station to join
228
229 if (ddir >= DIAGDIR_END) {
230 SetBit(p2, 1); // It's a drive-through stop.
231 ddir -= DIAGDIR_END; // Adjust picker result to actual direction.
232 }
233 p2 |= ddir << 6; // Set the DiagDirecion into p2 bits 6 and 7.
234
235 TileArea ta(start_tile, end_tile);
236 CommandContainer cmdcont = { ta.tile, (uint32)(ta.w | ta.h << 8), p2, cmd, CcRoadStop, "" };
237 ShowSelectStationIfNeeded(cmdcont, ta);
238 }
239
244 static void PlaceRoad_BusStation(TileIndex tile)
245 {
246 if (_remove_button_clicked) {
247 VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_REMOVE_BUSSTOP);
248 } else {
249 if (_road_station_picker_orientation < DIAGDIR_END) { // Not a drive-through stop.
250 VpStartPlaceSizing(tile, (DiagDirToAxis(_road_station_picker_orientation) == AXIS_X) ? VPM_X_LIMITED : VPM_Y_LIMITED, DDSP_BUILD_BUSSTOP);
251 } else {
252 VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_BUSSTOP);
253 }
254 VpSetPlaceSizingLimit(_settings_game.station.station_spread);
255 }
256 }
257
262 static void PlaceRoad_TruckStation(TileIndex tile)
263 {
264 if (_remove_button_clicked) {
265 VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_REMOVE_TRUCKSTOP);
266 } else {
267 if (_road_station_picker_orientation < DIAGDIR_END) { // Not a drive-through stop.
268 VpStartPlaceSizing(tile, (DiagDirToAxis(_road_station_picker_orientation) == AXIS_X) ? VPM_X_LIMITED : VPM_Y_LIMITED, DDSP_BUILD_TRUCKSTOP);
269 } else {
270 VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_BUILD_TRUCKSTOP);
271 }
272 VpSetPlaceSizingLimit(_settings_game.station.station_spread);
273 }
274 }
275
276 typedef void OnButtonClick(Window *w);
277
282 static void ToggleRoadButton_Remove(Window *w)
283 {
284 w->ToggleWidgetLoweredState(WID_ROT_REMOVE);
285 w->SetWidgetDirty(WID_ROT_REMOVE);
286 _remove_button_clicked = w->IsWidgetLowered(WID_ROT_REMOVE);
287 SetSelectionRed(_remove_button_clicked);
288 }
289
295 static bool RoadToolbar_CtrlChanged(Window *w)
296 {
297 if (w->IsWidgetDisabled(WID_ROT_REMOVE)) return false;
298
299 /* allow ctrl to switch remove mode only for these widgets */
300 for (uint i = WID_ROT_ROAD_X; i <= WID_ROT_AUTOROAD; i++) {
301 if (w->IsWidgetLowered(i)) {
302 ToggleRoadButton_Remove(w);
303 return true;
304 }
305 }
306
307 return false;
308 }
309
311 struct BuildRoadToolbarWindow : Window {
312 int last_started_action;
313
314 BuildRoadToolbarWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc)
315 {
316 this->InitNested(window_number);
317 this->SetWidgetsDisabledState(true,
318 WID_ROT_REMOVE,
319 WID_ROT_ONE_WAY,
320 WIDGET_LIST_END);
321
322 this->OnInvalidateData();
323 this->last_started_action = WIDGET_LIST_END;
324
325 if (_settings_client.gui.link_terraform_toolbar) ShowTerraformToolbar(this);
326 }
327
328 ~BuildRoadToolbarWindow()
329 {
330 if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false);
331 }
332
338 virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
339 {
340 if (!gui_scope) return;
341
342 bool can_build = CanBuildVehicleInfrastructure(VEH_ROAD);
343 this->SetWidgetsDisabledState(!can_build,
344 WID_ROT_DEPOT,
345 WID_ROT_BUS_STATION,
346 WID_ROT_TRUCK_STATION,
347 WIDGET_LIST_END);
348 if (!can_build) {
349 DeleteWindowById(WC_BUILD_DEPOT, TRANSPORT_ROAD);
350 DeleteWindowById(WC_BUS_STATION, TRANSPORT_ROAD);
351 DeleteWindowById(WC_TRUCK_STATION, TRANSPORT_ROAD);
352 }
353 }
354
360 void UpdateOptionWidgetStatus(RoadToolbarWidgets clicked_widget)
361 {
362 /* The remove and the one way button state is driven
363 * by the other buttons so they don't act on themselves.
364 * Both are only valid if they are able to apply as options. */
365 switch (clicked_widget) {
366 case WID_ROT_REMOVE:
367 this->RaiseWidget(WID_ROT_ONE_WAY);
368 this->SetWidgetDirty(WID_ROT_ONE_WAY);
369 break;
370
371 case WID_ROT_ONE_WAY:
372 this->RaiseWidget(WID_ROT_REMOVE);
373 this->SetWidgetDirty(WID_ROT_REMOVE);
374 break;
375
376 case WID_ROT_BUS_STATION:
377 case WID_ROT_TRUCK_STATION:
378 this->DisableWidget(WID_ROT_ONE_WAY);
379 this->SetWidgetDisabledState(WID_ROT_REMOVE, !this->IsWidgetLowered(clicked_widget));
380 break;
381
382 case WID_ROT_ROAD_X:
383 case WID_ROT_ROAD_Y:
384 case WID_ROT_AUTOROAD:
385 this->SetWidgetsDisabledState(!this->IsWidgetLowered(clicked_widget),
386 WID_ROT_REMOVE,
387 WID_ROT_ONE_WAY,
388 WIDGET_LIST_END);
389 break;
390
391 default:
392 /* When any other buttons than road/station, raise and
393 * disable the removal button */
394 this->SetWidgetsDisabledState(true,
395 WID_ROT_REMOVE,
396 WID_ROT_ONE_WAY,
397 WIDGET_LIST_END);
398 this->SetWidgetsLoweredState(false,
399 WID_ROT_REMOVE,
400 WID_ROT_ONE_WAY,
401 WIDGET_LIST_END);
402 break;
403 }
404 }
405
406 virtual void OnClick(Point pt, int widget, int click_count)
407 {
408 _remove_button_clicked = false;
409 _one_way_button_clicked = false;
410 switch (widget) {
411 case WID_ROT_ROAD_X:
412 HandlePlacePushButton(this, WID_ROT_ROAD_X, _road_type_infos[_cur_roadtype].cursor_nwse, HT_RECT);
413 this->last_started_action = widget;
414 break;
415
416 case WID_ROT_ROAD_Y:
417 HandlePlacePushButton(this, WID_ROT_ROAD_Y, _road_type_infos[_cur_roadtype].cursor_nesw, HT_RECT);
418 this->last_started_action = widget;
419 break;
420
421 case WID_ROT_AUTOROAD:
422 HandlePlacePushButton(this, WID_ROT_AUTOROAD, _road_type_infos[_cur_roadtype].cursor_autoroad, HT_RECT);
423 this->last_started_action = widget;
424 break;
425
426 case WID_ROT_DEMOLISH:
427 HandlePlacePushButton(this, WID_ROT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL);
428 this->last_started_action = widget;
429 break;
430
431 case WID_ROT_DEPOT:
432 if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD)) return;
433 if (HandlePlacePushButton(this, WID_ROT_DEPOT, SPR_CURSOR_ROAD_DEPOT, HT_RECT)) {
434 ShowRoadDepotPicker(this);
435 this->last_started_action = widget;
436 }
437 break;
438
439 case WID_ROT_BUS_STATION:
440 if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD)) return;
441 if (HandlePlacePushButton(this, WID_ROT_BUS_STATION, SPR_CURSOR_BUS_STATION, HT_RECT)) {
442 ShowRVStationPicker(this, ROADSTOP_BUS);
443 this->last_started_action = widget;
444 }
445 break;
446
447 case WID_ROT_TRUCK_STATION:
448 if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD)) return;
449 if (HandlePlacePushButton(this, WID_ROT_TRUCK_STATION, SPR_CURSOR_TRUCK_STATION, HT_RECT)) {
450 ShowRVStationPicker(this, ROADSTOP_TRUCK);
451 this->last_started_action = widget;
452 }
453 break;
454
455 case WID_ROT_ONE_WAY:
456 if (this->IsWidgetDisabled(WID_ROT_ONE_WAY)) return;
457 this->SetDirty();
458 this->ToggleWidgetLoweredState(WID_ROT_ONE_WAY);
459 SetSelectionRed(false);
460 break;
461
462 case WID_ROT_BUILD_BRIDGE:
463 HandlePlacePushButton(this, WID_ROT_BUILD_BRIDGE, SPR_CURSOR_BRIDGE, HT_RECT);
464 this->last_started_action = widget;
465 break;
466
467 case WID_ROT_BUILD_TUNNEL:
468 HandlePlacePushButton(this, WID_ROT_BUILD_TUNNEL, SPR_CURSOR_ROAD_TUNNEL, HT_SPECIAL);
469 this->last_started_action = widget;
470 break;
471
472 case WID_ROT_REMOVE:
473 if (this->IsWidgetDisabled(WID_ROT_REMOVE)) return;
474
475 DeleteWindowById(WC_SELECT_STATION, 0);
476 ToggleRoadButton_Remove(this);
477 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
478 break;
479
480 default: NOT_REACHED();
481 }
482 this->UpdateOptionWidgetStatus((RoadToolbarWidgets)widget);
483 if (_ctrl_pressed) RoadToolbar_CtrlChanged(this);
484 }
485
486 virtual EventState OnHotkey(int hotkey)
487 {
488 MarkTileDirtyByTile(TileVirtXY(_thd.pos.x, _thd.pos.y)); // redraw tile selection
489 return Window::OnHotkey(hotkey);
490 }
491
492 virtual void OnPlaceObject(Point pt, TileIndex tile)
493 {
494 _remove_button_clicked = this->IsWidgetLowered(WID_ROT_REMOVE);
495 _one_way_button_clicked = this->IsWidgetLowered(WID_ROT_ONE_WAY);
496 switch (this->last_started_action) {
497 case WID_ROT_ROAD_X:
498 _place_road_flag = RF_DIR_X;
499 if (_tile_fract_coords.x >= 8) _place_road_flag |= RF_START_HALFROAD_X;
500 VpStartPlaceSizing(tile, VPM_FIX_Y, DDSP_PLACE_ROAD_X_DIR);
501 break;
502
503 case WID_ROT_ROAD_Y:
504 _place_road_flag = RF_DIR_Y;
505 if (_tile_fract_coords.y >= 8) _place_road_flag |= RF_START_HALFROAD_Y;
506 VpStartPlaceSizing(tile, VPM_FIX_X, DDSP_PLACE_ROAD_Y_DIR);
507 break;
508
509 case WID_ROT_AUTOROAD:
510 _place_road_flag = RF_NONE;
511 if (_tile_fract_coords.x >= 8) _place_road_flag |= RF_START_HALFROAD_X;
512 if (_tile_fract_coords.y >= 8) _place_road_flag |= RF_START_HALFROAD_Y;
513 VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_PLACE_AUTOROAD);
514 break;
515
516 case WID_ROT_DEMOLISH:
517 PlaceProc_DemolishArea(tile);
518 break;
519
520 case WID_ROT_DEPOT:
521 DoCommandP(tile, _cur_roadtype << 2 | _road_depot_orientation, 0,
522 CMD_BUILD_ROAD_DEPOT | CMD_MSG(_road_type_infos[_cur_roadtype].err_depot), CcRoadDepot);
523 break;
524
525 case WID_ROT_BUS_STATION:
526 PlaceRoad_BusStation(tile);
527 break;
528
529 case WID_ROT_TRUCK_STATION:
530 PlaceRoad_TruckStation(tile);
531 break;
532
533 case WID_ROT_BUILD_BRIDGE:
534 PlaceRoad_Bridge(tile, this);
535 break;
536
537 case WID_ROT_BUILD_TUNNEL:
538 DoCommandP(tile, RoadTypeToRoadTypes(_cur_roadtype) | (TRANSPORT_ROAD << 8), 0,
539 CMD_BUILD_TUNNEL | CMD_MSG(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE), CcBuildRoadTunnel);
540 break;
541
542 default: NOT_REACHED();
543 }
544 }
545
546 virtual void OnPlaceObjectAbort()
547 {
548 this->RaiseButtons();
549 this->SetWidgetsDisabledState(true,
550 WID_ROT_REMOVE,
551 WID_ROT_ONE_WAY,
552 WIDGET_LIST_END);
553 this->SetWidgetDirty(WID_ROT_REMOVE);
554 this->SetWidgetDirty(WID_ROT_ONE_WAY);
555
556 DeleteWindowById(WC_BUS_STATION, TRANSPORT_ROAD);
557 DeleteWindowById(WC_TRUCK_STATION, TRANSPORT_ROAD);
558 DeleteWindowById(WC_BUILD_DEPOT, TRANSPORT_ROAD);
559 DeleteWindowById(WC_SELECT_STATION, 0);
560 DeleteWindowByClass(WC_BUILD_BRIDGE);
561 }
562
563 virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
564 {
565 /* Here we update the end tile flags
566 * of the road placement actions.
567 * At first we reset the end halfroad
568 * bits and if needed we set them again. */
569 switch (select_proc) {
570 case DDSP_PLACE_ROAD_X_DIR:
571 _place_road_flag &= ~RF_END_HALFROAD_X;
572 if (pt.x & 8) _place_road_flag |= RF_END_HALFROAD_X;
573 break;
574
575 case DDSP_PLACE_ROAD_Y_DIR:
576 _place_road_flag &= ~RF_END_HALFROAD_Y;
577 if (pt.y & 8) _place_road_flag |= RF_END_HALFROAD_Y;
578 break;
579
580 case DDSP_PLACE_AUTOROAD:
581 _place_road_flag &= ~(RF_END_HALFROAD_Y | RF_END_HALFROAD_X);
582 if (pt.y & 8) _place_road_flag |= RF_END_HALFROAD_Y;
583 if (pt.x & 8) _place_road_flag |= RF_END_HALFROAD_X;
584
585 /* For autoroad we need to update the
586 * direction of the road */
587 if (_thd.size.x > _thd.size.y || (_thd.size.x == _thd.size.y &&
588 ( (_tile_fract_coords.x < _tile_fract_coords.y && (_tile_fract_coords.x + _tile_fract_coords.y) < 16) ||
589 (_tile_fract_coords.x > _tile_fract_coords.y && (_tile_fract_coords.x + _tile_fract_coords.y) > 16) ))) {
590 /* Set dir = X */
591 _place_road_flag &= ~RF_DIR_Y;
592 } else {
593 /* Set dir = Y */
594 _place_road_flag |= RF_DIR_Y;
595 }
596
597 break;
598
599 default:
600 break;
601 }
602
603 VpSelectTilesWithMethod(pt.x, pt.y, select_method);
604 }
605
606 virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
607 {
608 if (pt.x != -1) {
609 switch (select_proc) {
610 default: NOT_REACHED();
611 case DDSP_BUILD_BRIDGE:
612 if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
613 ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_ROAD, RoadTypeToRoadTypes(_cur_roadtype));
614 break;
615
616 case DDSP_DEMOLISH_AREA:
617 GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
618 break;
619
620 case DDSP_PLACE_ROAD_X_DIR:
621 case DDSP_PLACE_ROAD_Y_DIR:
622 case DDSP_PLACE_AUTOROAD:
623 /* Flag description:
624 * Use the first three bits (0x07) if dir == Y
625 * else use the last 2 bits (X dir has
626 * not the 3rd bit set) */
627 _place_road_flag = (RoadFlags)((_place_road_flag & RF_DIR_Y) ? (_place_road_flag & 0x07) : (_place_road_flag >> 3));
628
629 DoCommandP(start_tile, end_tile, _place_road_flag | (_cur_roadtype << 3) | (_one_way_button_clicked << 5),
630 _remove_button_clicked ?
631 CMD_REMOVE_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_road) :
632 CMD_BUILD_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_road), CcPlaySound_SPLAT_OTHER);
633 break;
634
635 case DDSP_BUILD_BUSSTOP:
636 PlaceRoadStop(start_tile, end_tile, (_ctrl_pressed << 5) | RoadTypeToRoadTypes(_cur_roadtype) << 2 | ROADSTOP_BUS, CMD_BUILD_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_station[ROADSTOP_BUS]));
637 break;
638
639 case DDSP_BUILD_TRUCKSTOP:
640 PlaceRoadStop(start_tile, end_tile, (_ctrl_pressed << 5) | RoadTypeToRoadTypes(_cur_roadtype) << 2 | ROADSTOP_TRUCK, CMD_BUILD_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_station[ROADSTOP_TRUCK]));
641 break;
642
643 case DDSP_REMOVE_BUSSTOP: {
644 TileArea ta(start_tile, end_tile);
645 DoCommandP(ta.tile, ta.w | ta.h << 8, (_ctrl_pressed << 1) | ROADSTOP_BUS, CMD_REMOVE_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_station[ROADSTOP_BUS]), CcPlaySound_SPLAT_OTHER);
646 break;
647 }
648
649 case DDSP_REMOVE_TRUCKSTOP: {
650 TileArea ta(start_tile, end_tile);
651 DoCommandP(ta.tile, ta.w | ta.h << 8, (_ctrl_pressed << 1) | ROADSTOP_TRUCK, CMD_REMOVE_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_station[ROADSTOP_TRUCK]), CcPlaySound_SPLAT_OTHER);
652 break;
653 }
654 }
655 }
656 }
657
658 virtual void OnPlacePresize(Point pt, TileIndex tile)
659 {
660 DoCommand(tile, RoadTypeToRoadTypes(_cur_roadtype) | (TRANSPORT_ROAD << 8), 0, DC_AUTO, CMD_BUILD_TUNNEL);
661 VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile);
662 }
663
664 virtual EventState OnCTRLStateChange()
665 {
666 if (RoadToolbar_CtrlChanged(this)) return ES_HANDLED;
667 return ES_NOT_HANDLED;
668 }
669
670 static HotkeyList hotkeys;
671 };
672
678 static EventState RoadToolbarGlobalHotkeys(int hotkey)
679 {
680 Window *w = NULL;
681 switch (_game_mode) {
682 case GM_NORMAL: {
683 extern RoadType _last_built_roadtype;
684 w = ShowBuildRoadToolbar(_last_built_roadtype);
685 break;
686 }
687
688 case GM_EDITOR:
689 w = ShowBuildRoadScenToolbar();
690 break;
691
692 default:
693 break;
694 }
695
696 if (w == NULL) return ES_NOT_HANDLED;
697 return w->OnHotkey(hotkey);
698 }
699
700 static Hotkey roadtoolbar_hotkeys[] = {
701 Hotkey('1', "build_x", WID_ROT_ROAD_X),
702 Hotkey('2', "build_y", WID_ROT_ROAD_Y),
703 Hotkey('3', "autoroad", WID_ROT_AUTOROAD),
704 Hotkey('4', "demolish", WID_ROT_DEMOLISH),
705 Hotkey('5', "depot", WID_ROT_DEPOT),
706 Hotkey('6', "bus_station", WID_ROT_BUS_STATION),
707 Hotkey('7', "truck_station", WID_ROT_TRUCK_STATION),
708 Hotkey('8', "oneway", WID_ROT_ONE_WAY),
709 Hotkey('B', "bridge", WID_ROT_BUILD_BRIDGE),
710 Hotkey('T', "tunnel", WID_ROT_BUILD_TUNNEL),
711 Hotkey('R', "remove", WID_ROT_REMOVE),
712 HOTKEY_LIST_END
713 };
714 HotkeyList BuildRoadToolbarWindow::hotkeys("roadtoolbar", roadtoolbar_hotkeys, RoadToolbarGlobalHotkeys);
715
716
717 static const NWidgetPart _nested_build_road_widgets[] = {
718 NWidget(NWID_HORIZONTAL),
719 NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
720 NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_ROAD_TOOLBAR_ROAD_CONSTRUCTION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
721 NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN),
722 EndContainer(),
723 NWidget(NWID_HORIZONTAL),
724 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_X),
725 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_X_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION),
726 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_Y),
727 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_Y_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION),
728 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_AUTOROAD),
729 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTOROAD, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD),
730 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEMOLISH),
731 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC),
732 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEPOT),
733 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_DEPOT, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT),
734 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUS_STATION),
735 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_BUS_STATION, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_BUS_STATION),
736 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_TRUCK_STATION),
737 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRUCK_BAY, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRUCK_LOADING_BAY),
738 NWidget(WWT_PANEL, COLOUR_DARK_GREEN, -1), SetMinimalSize(0, 22), SetFill(1, 1), EndContainer(),
739 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ONE_WAY),
740 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_ONE_WAY, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_ONE_WAY_ROAD),
741 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_BRIDGE),
742 SetFill(0, 1), SetMinimalSize(43, 22), SetDataTip(SPR_IMG_BRIDGE, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_BRIDGE),
743 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_TUNNEL),
744 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_TUNNEL, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL),
745 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_REMOVE),
746 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD),
747 EndContainer(),
748 };
749
750 static WindowDesc _build_road_desc(
751 WDP_ALIGN_TOOLBAR, "toolbar_road", 0, 0,
752 WC_BUILD_TOOLBAR, WC_NONE,
753 WDF_CONSTRUCTION,
754 _nested_build_road_widgets, lengthof(_nested_build_road_widgets),
755 &BuildRoadToolbarWindow::hotkeys
756 );
757
758 static const NWidgetPart _nested_build_tramway_widgets[] = {
759 NWidget(NWID_HORIZONTAL),
760 NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
761 NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_ROAD_TOOLBAR_TRAM_CONSTRUCTION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
762 NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN),
763 EndContainer(),
764 NWidget(NWID_HORIZONTAL),
765 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_X),
766 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRAMWAY_X_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION),
767 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_Y),
768 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRAMWAY_Y_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION),
769 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_AUTOROAD),
770 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTOTRAM, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM),
771 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEMOLISH),
772 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC),
773 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEPOT),
774 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_DEPOT, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT),
775 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUS_STATION),
776 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_BUS_STATION, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_PASSENGER_TRAM_STATION),
777 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_TRUCK_STATION),
778 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRUCK_BAY, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_CARGO_TRAM_STATION),
779 NWidget(WWT_PANEL, COLOUR_DARK_GREEN, -1), SetMinimalSize(0, 22), SetFill(1, 1), EndContainer(),
780 NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_ROT_ONE_WAY), SetMinimalSize(0, 0),
781 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_BRIDGE),
782 SetFill(0, 1), SetMinimalSize(43, 22), SetDataTip(SPR_IMG_BRIDGE, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_BRIDGE),
783 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_TUNNEL),
784 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_TUNNEL, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL),
785 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_REMOVE),
786 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS),
787 EndContainer(),
788 };
789
790 static WindowDesc _build_tramway_desc(
791 WDP_ALIGN_TOOLBAR, "toolbar_tramway", 0, 0,
792 WC_BUILD_TOOLBAR, WC_NONE,
793 WDF_CONSTRUCTION,
794 _nested_build_tramway_widgets, lengthof(_nested_build_tramway_widgets),
795 &BuildRoadToolbarWindow::hotkeys
796 );
797
805 Window *ShowBuildRoadToolbar(RoadType roadtype)
806 {
807 if (!Company::IsValidID(_local_company)) return NULL;
808 _cur_roadtype = roadtype;
809
810 DeleteWindowByClass(WC_BUILD_TOOLBAR);
811 return AllocateWindowDescFront<BuildRoadToolbarWindow>(roadtype == ROADTYPE_ROAD ? &_build_road_desc : &_build_tramway_desc, TRANSPORT_ROAD);
812 }
813
814 static const NWidgetPart _nested_build_road_scen_widgets[] = {
815 NWidget(NWID_HORIZONTAL),
816 NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
817 NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_ROAD_TOOLBAR_ROAD_CONSTRUCTION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
818 NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN),
819 EndContainer(),
820 NWidget(NWID_HORIZONTAL),
821 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_X),
822 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_X_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION),
823 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_Y),
824 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_Y_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION),
825 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_AUTOROAD),
826 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTOROAD, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD),
827 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEMOLISH),
828 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC),
829 NWidget(WWT_PANEL, COLOUR_DARK_GREEN, -1), SetMinimalSize(0, 22), SetFill(1, 1), EndContainer(),
830 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ONE_WAY),
831 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_ONE_WAY, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_ONE_WAY_ROAD),
832 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_BRIDGE),
833 SetFill(0, 1), SetMinimalSize(43, 22), SetDataTip(SPR_IMG_BRIDGE, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_BRIDGE),
834 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_TUNNEL),
835 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_TUNNEL, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL),
836 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_REMOVE),
837 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD),
838 EndContainer(),
839 };
840
841 static WindowDesc _build_road_scen_desc(
842 WDP_AUTO, "toolbar_road_scen", 0, 0,
843 WC_SCEN_BUILD_TOOLBAR, WC_NONE,
844 WDF_CONSTRUCTION,
845 _nested_build_road_scen_widgets, lengthof(_nested_build_road_scen_widgets),
846 &BuildRoadToolbarWindow::hotkeys
847 );
848
853 Window *ShowBuildRoadScenToolbar()
854 {
855 _cur_roadtype = ROADTYPE_ROAD;
856 return AllocateWindowDescFront<BuildRoadToolbarWindow>(&_build_road_scen_desc, TRANSPORT_ROAD);
857 }
858
859 struct BuildRoadDepotWindow : public PickerWindowBase {
860 BuildRoadDepotWindow(WindowDesc *desc, Window *parent) : PickerWindowBase(desc, parent)
861 {
862 this->CreateNestedTree();
863
864 this->LowerWidget(_road_depot_orientation + WID_BROD_DEPOT_NE);
865 if ( _cur_roadtype == ROADTYPE_TRAM) {
866 this->GetWidget<NWidgetCore>(WID_BROD_CAPTION)->widget_data = STR_BUILD_DEPOT_TRAM_ORIENTATION_CAPTION;
867 for (int i = WID_BROD_DEPOT_NE; i <= WID_BROD_DEPOT_NW; i++) this->GetWidget<NWidgetCore>(i)->tool_tip = STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP;
868 }
869
870 this->FinishInitNested(TRANSPORT_ROAD);
871 }
872
873 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
874 {
875 if (!IsInsideMM(widget, WID_BROD_DEPOT_NE, WID_BROD_DEPOT_NW + 1)) return;
876
877 size->width = ScaleGUITrad(64) + 2;
878 size->height = ScaleGUITrad(48) + 2;
879 }
880
881 virtual void DrawWidget(const Rect &r, int widget) const
882 {
883 if (!IsInsideMM(widget, WID_BROD_DEPOT_NE, WID_BROD_DEPOT_NW + 1)) return;
884
885 DrawRoadDepotSprite(r.left + 1 + ScaleGUITrad(31), r.bottom - ScaleGUITrad(31), (DiagDirection)(widget - WID_BROD_DEPOT_NE + DIAGDIR_NE), _cur_roadtype);
886 }
887
888 virtual void OnClick(Point pt, int widget, int click_count)
889 {
890 switch (widget) {
891 case WID_BROD_DEPOT_NW:
892 case WID_BROD_DEPOT_NE:
893 case WID_BROD_DEPOT_SW:
894 case WID_BROD_DEPOT_SE:
895 this->RaiseWidget(_road_depot_orientation + WID_BROD_DEPOT_NE);
896 _road_depot_orientation = (DiagDirection)(widget - WID_BROD_DEPOT_NE);
897 this->LowerWidget(_road_depot_orientation + WID_BROD_DEPOT_NE);
898 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
899 this->SetDirty();
900 break;
901
902 default:
903 break;
904 }
905 }
906 };
907
908 static const NWidgetPart _nested_build_road_depot_widgets[] = {
909 NWidget(NWID_HORIZONTAL),
910 NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
911 NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_BROD_CAPTION), SetDataTip(STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
912 EndContainer(),
913 NWidget(WWT_PANEL, COLOUR_DARK_GREEN),
914 NWidget(NWID_SPACER), SetMinimalSize(0, 3),
915 NWidget(NWID_HORIZONTAL_LTR),
916 NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0),
917 NWidget(NWID_VERTICAL),
918 NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_NW), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP),
919 EndContainer(),
920 NWidget(NWID_SPACER), SetMinimalSize(0, 2),
921 NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_SW), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP),
922 EndContainer(),
923 EndContainer(),
924 NWidget(NWID_SPACER), SetMinimalSize(2, 0),
925 NWidget(NWID_VERTICAL),
926 NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_NE), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP),
927 EndContainer(),
928 NWidget(NWID_SPACER), SetMinimalSize(0, 2),
929 NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_SE), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP),
930 EndContainer(),
931 EndContainer(),
932 NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0),
933 EndContainer(),
934 NWidget(NWID_SPACER), SetMinimalSize(0, 3),
935 EndContainer(),
936 };
937
938 static WindowDesc _build_road_depot_desc(
939 WDP_AUTO, NULL, 0, 0,
940 WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
941 WDF_CONSTRUCTION,
942 _nested_build_road_depot_widgets, lengthof(_nested_build_road_depot_widgets)
943 );
944
945 static void ShowRoadDepotPicker(Window *parent)
946 {
947 new BuildRoadDepotWindow(&_build_road_depot_desc, parent);
948 }
949
950 struct BuildRoadStationWindow : public PickerWindowBase {
951 BuildRoadStationWindow(WindowDesc *desc, Window *parent, RoadStopType rs) : PickerWindowBase(desc, parent)
952 {
953 this->CreateNestedTree();
954
955 /* Trams don't have non-drivethrough stations */
956 if (_cur_roadtype == ROADTYPE_TRAM && _road_station_picker_orientation < DIAGDIR_END) {
957 _road_station_picker_orientation = DIAGDIR_END;
958 }
959 this->SetWidgetsDisabledState(_cur_roadtype == ROADTYPE_TRAM,
960 WID_BROS_STATION_NE,
961 WID_BROS_STATION_SE,
962 WID_BROS_STATION_SW,
963 WID_BROS_STATION_NW,
964 WIDGET_LIST_END);
965
966 this->GetWidget<NWidgetCore>(WID_BROS_CAPTION)->widget_data = _road_type_infos[_cur_roadtype].picker_title[rs];
967 for (uint i = WID_BROS_STATION_NE; i < WID_BROS_LT_OFF; i++) this->GetWidget<NWidgetCore>(i)->tool_tip = _road_type_infos[_cur_roadtype].picker_tooltip[rs];
968
969 this->LowerWidget(_road_station_picker_orientation + WID_BROS_STATION_NE);
970 this->LowerWidget(_settings_client.gui.station_show_coverage + WID_BROS_LT_OFF);
971
972 this->FinishInitNested(TRANSPORT_ROAD);
973
974 this->window_class = (rs == ROADSTOP_BUS) ? WC_BUS_STATION : WC_TRUCK_STATION;
975 }
976
977 virtual ~BuildRoadStationWindow()
978 {
979 DeleteWindowById(WC_SELECT_STATION, 0);
980 }
981
982 virtual void OnPaint()
983 {
984 this->DrawWidgets();
985
986 int rad = _settings_game.station.modified_catchment ? ((this->window_class == WC_BUS_STATION) ? CA_BUS : CA_TRUCK) : CA_UNMODIFIED;
987 if (_settings_client.gui.station_show_coverage) {
988 SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
989 } else {
990 SetTileSelectSize(1, 1);
991 }
992
993 /* 'Accepts' and 'Supplies' texts. */
994 StationCoverageType sct = (this->window_class == WC_BUS_STATION) ? SCT_PASSENGERS_ONLY : SCT_NON_PASSENGERS_ONLY;
995 int top = this->GetWidget<NWidgetBase>(WID_BROS_LT_ON)->pos_y + this->GetWidget<NWidgetBase>(WID_BROS_LT_ON)->current_y + WD_PAR_VSEP_NORMAL;
996 NWidgetBase *back_nwi = this->GetWidget<NWidgetBase>(WID_BROS_BACKGROUND);
997 int right = back_nwi->pos_x + back_nwi->current_x;
998 int bottom = back_nwi->pos_y + back_nwi->current_y;
999 top = DrawStationCoverageAreaText(back_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, sct, rad, false) + WD_PAR_VSEP_NORMAL;
1000 top = DrawStationCoverageAreaText(back_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, sct, rad, true) + WD_PAR_VSEP_NORMAL;
1001 /* Resize background if the window is too small.
1002 * Never make the window smaller to avoid oscillating if the size change affects the acceptance.
1003 * (This is the case, if making the window bigger moves the mouse into the window.) */
1004 if (top > bottom) {
1005 ResizeWindow(this, 0, top - bottom, false);
1006 }
1007 }
1008
1009 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
1010 {
1011 if (!IsInsideMM(widget, WID_BROS_STATION_NE, WID_BROS_STATION_Y + 1)) return;
1012
1013 size->width = ScaleGUITrad(64) + 2;
1014 size->height = ScaleGUITrad(48) + 2;
1015 }
1016
1017 virtual void DrawWidget(const Rect &r, int widget) const
1018 {
1019 if (!IsInsideMM(widget, WID_BROS_STATION_NE, WID_BROS_STATION_Y + 1)) return;
1020
1021 StationType st = (this->window_class == WC_BUS_STATION) ? STATION_BUS : STATION_TRUCK;
1022 StationPickerDrawSprite(r.left + 1 + ScaleGUITrad(31), r.bottom - ScaleGUITrad(31), st, INVALID_RAILTYPE, widget < WID_BROS_STATION_X ? ROADTYPE_ROAD : _cur_roadtype, widget - WID_BROS_STATION_NE);
1023 }
1024
1025 virtual void OnClick(Point pt, int widget, int click_count)
1026 {
1027 switch (widget) {
1028 case WID_BROS_STATION_NE:
1029 case WID_BROS_STATION_SE:
1030 case WID_BROS_STATION_SW:
1031 case WID_BROS_STATION_NW:
1032 case WID_BROS_STATION_X:
1033 case WID_BROS_STATION_Y:
1034 this->RaiseWidget(_road_station_picker_orientation + WID_BROS_STATION_NE);
1035 _road_station_picker_orientation = (DiagDirection)(widget - WID_BROS_STATION_NE);
1036 this->LowerWidget(_road_station_picker_orientation + WID_BROS_STATION_NE);
1037 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1038 this->SetDirty();
1039 DeleteWindowById(WC_SELECT_STATION, 0);
1040 break;
1041
1042 case WID_BROS_LT_OFF:
1043 case WID_BROS_LT_ON:
1044 this->RaiseWidget(_settings_client.gui.station_show_coverage + WID_BROS_LT_OFF);
1045 _settings_client.gui.station_show_coverage = (widget != WID_BROS_LT_OFF);
1046 this->LowerWidget(_settings_client.gui.station_show_coverage + WID_BROS_LT_OFF);
1047 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1048 this->SetDirty();
1049 break;
1050
1051 default:
1052 break;
1053 }
1054 }
1055
1056 virtual void OnTick()
1057 {
1058 CheckRedrawStationCoverage(this);
1059 }
1060 };
1061
1063 static const NWidgetPart _nested_rv_station_picker_widgets[] = {
1064 NWidget(NWID_HORIZONTAL),
1065 NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
1066 NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_BROS_CAPTION),
1067 EndContainer(),
1068 NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BROS_BACKGROUND),
1069 NWidget(NWID_SPACER), SetMinimalSize(0, 3),
1070 NWidget(NWID_HORIZONTAL), SetPIP(0, 2, 0),
1071 NWidget(NWID_SPACER), SetFill(1, 0),
1072 NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_NW), SetMinimalSize(66, 50), EndContainer(),
1073 NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_NE), SetMinimalSize(66, 50), EndContainer(),
1074 NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_X), SetMinimalSize(66, 50), EndContainer(),
1075 NWidget(NWID_SPACER), SetFill(1, 0),
1076 EndContainer(),
1077 NWidget(NWID_SPACER), SetMinimalSize(0, 2),
1078 NWidget(NWID_HORIZONTAL), SetPIP(0, 2, 0),
1079 NWidget(NWID_SPACER), SetFill(1, 0),
1080 NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_SW), SetMinimalSize(66, 50), EndContainer(),
1081 NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_SE), SetMinimalSize(66, 50), EndContainer(),
1082 NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_Y), SetMinimalSize(66, 50), EndContainer(),
1083 NWidget(NWID_SPACER), SetFill(1, 0),
1084 EndContainer(),
1085 NWidget(NWID_SPACER), SetMinimalSize(0, 1),
1086 NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2),
1087 NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BROS_INFO), SetMinimalSize(140, 14), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL),
1088 NWidget(NWID_SPACER), SetFill(1, 0),
1089 EndContainer(),
1090 NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2),
1091 NWidget(NWID_SPACER), SetFill(1, 0),
1092 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROS_LT_OFF), SetMinimalSize(60, 12),
1093 SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP),
1094 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROS_LT_ON), SetMinimalSize(60, 12),
1095 SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP),
1096 NWidget(NWID_SPACER), SetFill(1, 0),
1097 EndContainer(),
1098 NWidget(NWID_SPACER), SetMinimalSize(0, 10), SetResize(0, 1),
1099 EndContainer(),
1100 };
1101
1102 static WindowDesc _rv_station_picker_desc(
1103 WDP_AUTO, NULL, 0, 0,
1104 WC_BUS_STATION, WC_BUILD_TOOLBAR,
1105 WDF_CONSTRUCTION,
1106 _nested_rv_station_picker_widgets, lengthof(_nested_rv_station_picker_widgets)
1107 );
1108
1109 static void ShowRVStationPicker(Window *parent, RoadStopType rs)
1110 {
1111 new BuildRoadStationWindow(&_rv_station_picker_desc, parent, rs);
1112 }
1113
1114 void InitializeRoadGui()
1115 {
1116 _road_depot_orientation = DIAGDIR_NW;
1117 _road_station_picker_orientation = DIAGDIR_NW;
1118 }