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 27134 2015-02-01 20:54:24Z 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 CcPlaySound1D(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, 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 this->SetWidgetsDisabledState(!CanBuildVehicleInfrastructure(VEH_ROAD),
342 WID_ROT_DEPOT,
343 WID_ROT_BUS_STATION,
344 WID_ROT_TRUCK_STATION,
345 WIDGET_LIST_END);
346 }
347
353 void UpdateOptionWidgetStatus(RoadToolbarWidgets clicked_widget)
354 {
355 /* The remove and the one way button state is driven
356 * by the other buttons so they don't act on themselves.
357 * Both are only valid if they are able to apply as options. */
358 switch (clicked_widget) {
359 case WID_ROT_REMOVE:
360 this->RaiseWidget(WID_ROT_ONE_WAY);
361 this->SetWidgetDirty(WID_ROT_ONE_WAY);
362 break;
363
364 case WID_ROT_ONE_WAY:
365 this->RaiseWidget(WID_ROT_REMOVE);
366 this->SetWidgetDirty(WID_ROT_REMOVE);
367 break;
368
369 case WID_ROT_BUS_STATION:
370 case WID_ROT_TRUCK_STATION:
371 this->DisableWidget(WID_ROT_ONE_WAY);
372 this->SetWidgetDisabledState(WID_ROT_REMOVE, !this->IsWidgetLowered(clicked_widget));
373 break;
374
375 case WID_ROT_ROAD_X:
376 case WID_ROT_ROAD_Y:
377 case WID_ROT_AUTOROAD:
378 this->SetWidgetsDisabledState(!this->IsWidgetLowered(clicked_widget),
379 WID_ROT_REMOVE,
380 WID_ROT_ONE_WAY,
381 WIDGET_LIST_END);
382 break;
383
384 default:
385 /* When any other buttons than road/station, raise and
386 * disable the removal button */
387 this->SetWidgetsDisabledState(true,
388 WID_ROT_REMOVE,
389 WID_ROT_ONE_WAY,
390 WIDGET_LIST_END);
391 this->SetWidgetsLoweredState(false,
392 WID_ROT_REMOVE,
393 WID_ROT_ONE_WAY,
394 WIDGET_LIST_END);
395 break;
396 }
397 }
398
399 virtual void OnClick(Point pt, int widget, int click_count)
400 {
401 _remove_button_clicked = false;
402 _one_way_button_clicked = false;
403 switch (widget) {
404 case WID_ROT_ROAD_X:
405 HandlePlacePushButton(this, WID_ROT_ROAD_X, _road_type_infos[_cur_roadtype].cursor_nwse, HT_RECT);
406 this->last_started_action = widget;
407 break;
408
409 case WID_ROT_ROAD_Y:
410 HandlePlacePushButton(this, WID_ROT_ROAD_Y, _road_type_infos[_cur_roadtype].cursor_nesw, HT_RECT);
411 this->last_started_action = widget;
412 break;
413
414 case WID_ROT_AUTOROAD:
415 HandlePlacePushButton(this, WID_ROT_AUTOROAD, _road_type_infos[_cur_roadtype].cursor_autoroad, HT_RECT);
416 this->last_started_action = widget;
417 break;
418
419 case WID_ROT_DEMOLISH:
420 HandlePlacePushButton(this, WID_ROT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL);
421 this->last_started_action = widget;
422 break;
423
424 case WID_ROT_DEPOT:
425 if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD)) return;
426 if (HandlePlacePushButton(this, WID_ROT_DEPOT, SPR_CURSOR_ROAD_DEPOT, HT_RECT)) {
427 ShowRoadDepotPicker(this);
428 this->last_started_action = widget;
429 }
430 break;
431
432 case WID_ROT_BUS_STATION:
433 if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD)) return;
434 if (HandlePlacePushButton(this, WID_ROT_BUS_STATION, SPR_CURSOR_BUS_STATION, HT_RECT)) {
435 ShowRVStationPicker(this, ROADSTOP_BUS);
436 this->last_started_action = widget;
437 }
438 break;
439
440 case WID_ROT_TRUCK_STATION:
441 if (_game_mode == GM_EDITOR || !CanBuildVehicleInfrastructure(VEH_ROAD)) return;
442 if (HandlePlacePushButton(this, WID_ROT_TRUCK_STATION, SPR_CURSOR_TRUCK_STATION, HT_RECT)) {
443 ShowRVStationPicker(this, ROADSTOP_TRUCK);
444 this->last_started_action = widget;
445 }
446 break;
447
448 case WID_ROT_ONE_WAY:
449 if (this->IsWidgetDisabled(WID_ROT_ONE_WAY)) return;
450 this->SetDirty();
451 this->ToggleWidgetLoweredState(WID_ROT_ONE_WAY);
452 SetSelectionRed(false);
453 break;
454
455 case WID_ROT_BUILD_BRIDGE:
456 HandlePlacePushButton(this, WID_ROT_BUILD_BRIDGE, SPR_CURSOR_BRIDGE, HT_RECT);
457 this->last_started_action = widget;
458 break;
459
460 case WID_ROT_BUILD_TUNNEL:
461 HandlePlacePushButton(this, WID_ROT_BUILD_TUNNEL, SPR_CURSOR_ROAD_TUNNEL, HT_SPECIAL);
462 this->last_started_action = widget;
463 break;
464
465 case WID_ROT_REMOVE:
466 if (this->IsWidgetDisabled(WID_ROT_REMOVE)) return;
467
468 DeleteWindowById(WC_SELECT_STATION, 0);
469 ToggleRoadButton_Remove(this);
470 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
471 break;
472
473 default: NOT_REACHED();
474 }
475 this->UpdateOptionWidgetStatus((RoadToolbarWidgets)widget);
476 if (_ctrl_pressed) RoadToolbar_CtrlChanged(this);
477 }
478
479 virtual EventState OnHotkey(int hotkey)
480 {
481 MarkTileDirtyByTile(TileVirtXY(_thd.pos.x, _thd.pos.y)); // redraw tile selection
482 return Window::OnHotkey(hotkey);
483 }
484
485 virtual void OnPlaceObject(Point pt, TileIndex tile)
486 {
487 _remove_button_clicked = this->IsWidgetLowered(WID_ROT_REMOVE);
488 _one_way_button_clicked = this->IsWidgetLowered(WID_ROT_ONE_WAY);
489 switch (this->last_started_action) {
490 case WID_ROT_ROAD_X:
491 _place_road_flag = RF_DIR_X;
492 if (_tile_fract_coords.x >= 8) _place_road_flag |= RF_START_HALFROAD_X;
493 VpStartPlaceSizing(tile, VPM_FIX_Y, DDSP_PLACE_ROAD_X_DIR);
494 break;
495
496 case WID_ROT_ROAD_Y:
497 _place_road_flag = RF_DIR_Y;
498 if (_tile_fract_coords.y >= 8) _place_road_flag |= RF_START_HALFROAD_Y;
499 VpStartPlaceSizing(tile, VPM_FIX_X, DDSP_PLACE_ROAD_Y_DIR);
500 break;
501
502 case WID_ROT_AUTOROAD:
503 _place_road_flag = RF_NONE;
504 if (_tile_fract_coords.x >= 8) _place_road_flag |= RF_START_HALFROAD_X;
505 if (_tile_fract_coords.y >= 8) _place_road_flag |= RF_START_HALFROAD_Y;
506 VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_PLACE_AUTOROAD);
507 break;
508
509 case WID_ROT_DEMOLISH:
510 PlaceProc_DemolishArea(tile);
511 break;
512
513 case WID_ROT_DEPOT:
514 DoCommandP(tile, _cur_roadtype << 2 | _road_depot_orientation, 0,
515 CMD_BUILD_ROAD_DEPOT | CMD_MSG(_road_type_infos[_cur_roadtype].err_depot), CcRoadDepot);
516 break;
517
518 case WID_ROT_BUS_STATION:
519 PlaceRoad_BusStation(tile);
520 break;
521
522 case WID_ROT_TRUCK_STATION:
523 PlaceRoad_TruckStation(tile);
524 break;
525
526 case WID_ROT_BUILD_BRIDGE:
527 PlaceRoad_Bridge(tile, this);
528 break;
529
530 case WID_ROT_BUILD_TUNNEL:
531 DoCommandP(tile, RoadTypeToRoadTypes(_cur_roadtype) | (TRANSPORT_ROAD << 8), 0,
532 CMD_BUILD_TUNNEL | CMD_MSG(STR_ERROR_CAN_T_BUILD_TUNNEL_HERE), CcBuildRoadTunnel);
533 break;
534
535 default: NOT_REACHED();
536 }
537 }
538
539 virtual void OnPlaceObjectAbort()
540 {
541 this->RaiseButtons();
542 this->SetWidgetsDisabledState(true,
543 WID_ROT_REMOVE,
544 WID_ROT_ONE_WAY,
545 WIDGET_LIST_END);
546 this->SetWidgetDirty(WID_ROT_REMOVE);
547 this->SetWidgetDirty(WID_ROT_ONE_WAY);
548
549 DeleteWindowById(WC_BUS_STATION, TRANSPORT_ROAD);
550 DeleteWindowById(WC_TRUCK_STATION, TRANSPORT_ROAD);
551 DeleteWindowById(WC_BUILD_DEPOT, TRANSPORT_ROAD);
552 DeleteWindowById(WC_SELECT_STATION, 0);
553 DeleteWindowByClass(WC_BUILD_BRIDGE);
554 }
555
556 virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
557 {
558 /* Here we update the end tile flags
559 * of the road placement actions.
560 * At first we reset the end halfroad
561 * bits and if needed we set them again. */
562 switch (select_proc) {
563 case DDSP_PLACE_ROAD_X_DIR:
564 _place_road_flag &= ~RF_END_HALFROAD_X;
565 if (pt.x & 8) _place_road_flag |= RF_END_HALFROAD_X;
566 break;
567
568 case DDSP_PLACE_ROAD_Y_DIR:
569 _place_road_flag &= ~RF_END_HALFROAD_Y;
570 if (pt.y & 8) _place_road_flag |= RF_END_HALFROAD_Y;
571 break;
572
573 case DDSP_PLACE_AUTOROAD:
574 _place_road_flag &= ~(RF_END_HALFROAD_Y | RF_END_HALFROAD_X);
575 if (pt.y & 8) _place_road_flag |= RF_END_HALFROAD_Y;
576 if (pt.x & 8) _place_road_flag |= RF_END_HALFROAD_X;
577
578 /* For autoroad we need to update the
579 * direction of the road */
580 if (_thd.size.x > _thd.size.y || (_thd.size.x == _thd.size.y &&
581 ( (_tile_fract_coords.x < _tile_fract_coords.y && (_tile_fract_coords.x + _tile_fract_coords.y) < 16) ||
582 (_tile_fract_coords.x > _tile_fract_coords.y && (_tile_fract_coords.x + _tile_fract_coords.y) > 16) ))) {
583 /* Set dir = X */
584 _place_road_flag &= ~RF_DIR_Y;
585 } else {
586 /* Set dir = Y */
587 _place_road_flag |= RF_DIR_Y;
588 }
589
590 break;
591
592 default:
593 break;
594 }
595
596 VpSelectTilesWithMethod(pt.x, pt.y, select_method);
597 }
598
599 virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
600 {
601 if (pt.x != -1) {
602 switch (select_proc) {
603 default: NOT_REACHED();
604 case DDSP_BUILD_BRIDGE:
605 if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace();
606 ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_ROAD, RoadTypeToRoadTypes(_cur_roadtype));
607 break;
608
609 case DDSP_DEMOLISH_AREA:
610 GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
611 break;
612
613 case DDSP_PLACE_ROAD_X_DIR:
614 case DDSP_PLACE_ROAD_Y_DIR:
615 case DDSP_PLACE_AUTOROAD:
616 /* Flag description:
617 * Use the first three bits (0x07) if dir == Y
618 * else use the last 2 bits (X dir has
619 * not the 3rd bit set) */
620 _place_road_flag = (RoadFlags)((_place_road_flag & RF_DIR_Y) ? (_place_road_flag & 0x07) : (_place_road_flag >> 3));
621
622 DoCommandP(start_tile, end_tile, _place_road_flag | (_cur_roadtype << 3) | (_one_way_button_clicked << 5),
623 _remove_button_clicked ?
624 CMD_REMOVE_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_road) :
625 CMD_BUILD_LONG_ROAD | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_road), CcPlaySound1D);
626 break;
627
628 case DDSP_BUILD_BUSSTOP:
629 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]));
630 break;
631
632 case DDSP_BUILD_TRUCKSTOP:
633 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]));
634 break;
635
636 case DDSP_REMOVE_BUSSTOP: {
637 TileArea ta(start_tile, end_tile);
638 DoCommandP(ta.tile, ta.w | ta.h << 8, ROADSTOP_BUS, CMD_REMOVE_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_station[ROADSTOP_BUS]), CcPlaySound1D);
639 break;
640 }
641
642 case DDSP_REMOVE_TRUCKSTOP: {
643 TileArea ta(start_tile, end_tile);
644 DoCommandP(ta.tile, ta.w | ta.h << 8, ROADSTOP_TRUCK, CMD_REMOVE_ROAD_STOP | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_station[ROADSTOP_TRUCK]), CcPlaySound1D);
645 break;
646 }
647 }
648 }
649 }
650
651 virtual void OnPlacePresize(Point pt, TileIndex tile)
652 {
653 DoCommand(tile, RoadTypeToRoadTypes(_cur_roadtype) | (TRANSPORT_ROAD << 8), 0, DC_AUTO, CMD_BUILD_TUNNEL);
654 VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile);
655 }
656
657 virtual EventState OnCTRLStateChange()
658 {
659 if (RoadToolbar_CtrlChanged(this)) return ES_HANDLED;
660 return ES_NOT_HANDLED;
661 }
662
663 static HotkeyList hotkeys;
664 };
665
671 static EventState RoadToolbarGlobalHotkeys(int hotkey)
672 {
673 Window *w = NULL;
674 switch (_game_mode) {
675 case GM_NORMAL: {
676 extern RoadType _last_built_roadtype;
677 w = ShowBuildRoadToolbar(_last_built_roadtype);
678 break;
679 }
680
681 case GM_EDITOR:
682 w = ShowBuildRoadScenToolbar();
683 break;
684
685 default:
686 break;
687 }
688
689 if (w == NULL) return ES_NOT_HANDLED;
690 return w->OnHotkey(hotkey);
691 }
692
693 static Hotkey roadtoolbar_hotkeys[] = {
694 Hotkey('1', "build_x", WID_ROT_ROAD_X),
695 Hotkey('2', "build_y", WID_ROT_ROAD_Y),
696 Hotkey('3', "autoroad", WID_ROT_AUTOROAD),
697 Hotkey('4', "demolish", WID_ROT_DEMOLISH),
698 Hotkey('5', "depot", WID_ROT_DEPOT),
699 Hotkey('6', "bus_station", WID_ROT_BUS_STATION),
700 Hotkey('7', "truck_station", WID_ROT_TRUCK_STATION),
701 Hotkey('8', "oneway", WID_ROT_ONE_WAY),
702 Hotkey('B', "bridge", WID_ROT_BUILD_BRIDGE),
703 Hotkey('T', "tunnel", WID_ROT_BUILD_TUNNEL),
704 Hotkey('R', "remove", WID_ROT_REMOVE),
705 HOTKEY_LIST_END
706 };
707 HotkeyList BuildRoadToolbarWindow::hotkeys("roadtoolbar", roadtoolbar_hotkeys, RoadToolbarGlobalHotkeys);
708
709
710 static const NWidgetPart _nested_build_road_widgets[] = {
711 NWidget(NWID_HORIZONTAL),
712 NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
713 NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_ROAD_TOOLBAR_ROAD_CONSTRUCTION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
714 NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN),
715 EndContainer(),
716 NWidget(NWID_HORIZONTAL),
717 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_X),
718 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_X_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION),
719 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_Y),
720 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_Y_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION),
721 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_AUTOROAD),
722 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTOROAD, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD),
723 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEMOLISH),
724 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC),
725 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEPOT),
726 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_DEPOT, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT),
727 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUS_STATION),
728 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_BUS_STATION, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_BUS_STATION),
729 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_TRUCK_STATION),
730 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRUCK_BAY, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRUCK_LOADING_BAY),
731 NWidget(WWT_PANEL, COLOUR_DARK_GREEN, -1), SetMinimalSize(0, 22), SetFill(1, 1), EndContainer(),
732 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ONE_WAY),
733 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_ONE_WAY, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_ONE_WAY_ROAD),
734 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_BRIDGE),
735 SetFill(0, 1), SetMinimalSize(43, 22), SetDataTip(SPR_IMG_BRIDGE, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_BRIDGE),
736 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_TUNNEL),
737 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_TUNNEL, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL),
738 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_REMOVE),
739 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD),
740 EndContainer(),
741 };
742
743 static WindowDesc _build_road_desc(
744 WDP_ALIGN_TOOLBAR, "toolbar_road", 0, 0,
745 WC_BUILD_TOOLBAR, WC_NONE,
746 WDF_CONSTRUCTION,
747 _nested_build_road_widgets, lengthof(_nested_build_road_widgets),
748 &BuildRoadToolbarWindow::hotkeys
749 );
750
751 static const NWidgetPart _nested_build_tramway_widgets[] = {
752 NWidget(NWID_HORIZONTAL),
753 NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
754 NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_ROAD_TOOLBAR_TRAM_CONSTRUCTION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
755 NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN),
756 EndContainer(),
757 NWidget(NWID_HORIZONTAL),
758 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_X),
759 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRAMWAY_X_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION),
760 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_Y),
761 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRAMWAY_Y_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_SECTION),
762 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_AUTOROAD),
763 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTOTRAM, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM),
764 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEMOLISH),
765 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC),
766 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEPOT),
767 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_DEPOT, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT),
768 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUS_STATION),
769 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_BUS_STATION, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_PASSENGER_TRAM_STATION),
770 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_TRUCK_STATION),
771 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_TRUCK_BAY, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_CARGO_TRAM_STATION),
772 NWidget(WWT_PANEL, COLOUR_DARK_GREEN, -1), SetMinimalSize(0, 22), SetFill(1, 1), EndContainer(),
773 NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_ROT_ONE_WAY), SetMinimalSize(0, 0),
774 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_BRIDGE),
775 SetFill(0, 1), SetMinimalSize(43, 22), SetDataTip(SPR_IMG_BRIDGE, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_BRIDGE),
776 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_TUNNEL),
777 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_TUNNEL, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAMWAY_TUNNEL),
778 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_REMOVE),
779 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_TRAMWAYS),
780 EndContainer(),
781 };
782
783 static WindowDesc _build_tramway_desc(
784 WDP_ALIGN_TOOLBAR, "toolbar_tramway", 0, 0,
785 WC_BUILD_TOOLBAR, WC_NONE,
786 WDF_CONSTRUCTION,
787 _nested_build_tramway_widgets, lengthof(_nested_build_tramway_widgets),
788 &BuildRoadToolbarWindow::hotkeys
789 );
790
798 Window *ShowBuildRoadToolbar(RoadType roadtype)
799 {
800 if (!Company::IsValidID(_local_company)) return NULL;
801 _cur_roadtype = roadtype;
802
803 DeleteWindowByClass(WC_BUILD_TOOLBAR);
804 return AllocateWindowDescFront<BuildRoadToolbarWindow>(roadtype == ROADTYPE_ROAD ? &_build_road_desc : &_build_tramway_desc, TRANSPORT_ROAD);
805 }
806
807 static const NWidgetPart _nested_build_road_scen_widgets[] = {
808 NWidget(NWID_HORIZONTAL),
809 NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
810 NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_ROAD_TOOLBAR_ROAD_CONSTRUCTION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
811 NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN),
812 EndContainer(),
813 NWidget(NWID_HORIZONTAL),
814 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_X),
815 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_X_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION),
816 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ROAD_Y),
817 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_Y_DIR, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_SECTION),
818 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_AUTOROAD),
819 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_AUTOROAD, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD),
820 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEMOLISH),
821 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC),
822 NWidget(WWT_PANEL, COLOUR_DARK_GREEN, -1), SetMinimalSize(0, 22), SetFill(1, 1), EndContainer(),
823 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_ONE_WAY),
824 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_ONE_WAY, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_ONE_WAY_ROAD),
825 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_BRIDGE),
826 SetFill(0, 1), SetMinimalSize(43, 22), SetDataTip(SPR_IMG_BRIDGE, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_BRIDGE),
827 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_TUNNEL),
828 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_TUNNEL, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_TUNNEL),
829 NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_REMOVE),
830 SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_REMOVE, STR_ROAD_TOOLBAR_TOOLTIP_TOGGLE_BUILD_REMOVE_FOR_ROAD),
831 EndContainer(),
832 };
833
834 static WindowDesc _build_road_scen_desc(
835 WDP_AUTO, "toolbar_road_scen", 0, 0,
836 WC_SCEN_BUILD_TOOLBAR, WC_NONE,
837 WDF_CONSTRUCTION,
838 _nested_build_road_scen_widgets, lengthof(_nested_build_road_scen_widgets),
839 &BuildRoadToolbarWindow::hotkeys
840 );
841
846 Window *ShowBuildRoadScenToolbar()
847 {
848 _cur_roadtype = ROADTYPE_ROAD;
849 return AllocateWindowDescFront<BuildRoadToolbarWindow>(&_build_road_scen_desc, TRANSPORT_ROAD);
850 }
851
852 struct BuildRoadDepotWindow : public PickerWindowBase {
853 BuildRoadDepotWindow(WindowDesc *desc, Window *parent) : PickerWindowBase(desc, parent)
854 {
855 this->CreateNestedTree();
856
857 this->LowerWidget(_road_depot_orientation + WID_BROD_DEPOT_NE);
858 if ( _cur_roadtype == ROADTYPE_TRAM) {
859 this->GetWidget<NWidgetCore>(WID_BROD_CAPTION)->widget_data = STR_BUILD_DEPOT_TRAM_ORIENTATION_CAPTION;
860 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;
861 }
862
863 this->FinishInitNested(TRANSPORT_ROAD);
864 }
865
866 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
867 {
868 if (!IsInsideMM(widget, WID_BROD_DEPOT_NE, WID_BROD_DEPOT_NW + 1)) return;
869
870 size->width = ScaleGUITrad(64) + 2;
871 size->height = ScaleGUITrad(48) + 2;
872 }
873
874 virtual void DrawWidget(const Rect &r, int widget) const
875 {
876 if (!IsInsideMM(widget, WID_BROD_DEPOT_NE, WID_BROD_DEPOT_NW + 1)) return;
877
878 DrawRoadDepotSprite(r.left + 1 + ScaleGUITrad(31), r.bottom - ScaleGUITrad(31), (DiagDirection)(widget - WID_BROD_DEPOT_NE + DIAGDIR_NE), _cur_roadtype);
879 }
880
881 virtual void OnClick(Point pt, int widget, int click_count)
882 {
883 switch (widget) {
884 case WID_BROD_DEPOT_NW:
885 case WID_BROD_DEPOT_NE:
886 case WID_BROD_DEPOT_SW:
887 case WID_BROD_DEPOT_SE:
888 this->RaiseWidget(_road_depot_orientation + WID_BROD_DEPOT_NE);
889 _road_depot_orientation = (DiagDirection)(widget - WID_BROD_DEPOT_NE);
890 this->LowerWidget(_road_depot_orientation + WID_BROD_DEPOT_NE);
891 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
892 this->SetDirty();
893 break;
894
895 default:
896 break;
897 }
898 }
899 };
900
901 static const NWidgetPart _nested_build_road_depot_widgets[] = {
902 NWidget(NWID_HORIZONTAL),
903 NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
904 NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_BROD_CAPTION), SetDataTip(STR_BUILD_DEPOT_ROAD_ORIENTATION_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
905 EndContainer(),
906 NWidget(WWT_PANEL, COLOUR_DARK_GREEN),
907 NWidget(NWID_SPACER), SetMinimalSize(0, 3),
908 NWidget(NWID_HORIZONTAL_LTR),
909 NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0),
910 NWidget(NWID_VERTICAL),
911 NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_NW), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP),
912 EndContainer(),
913 NWidget(NWID_SPACER), SetMinimalSize(0, 2),
914 NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_SW), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP),
915 EndContainer(),
916 EndContainer(),
917 NWidget(NWID_SPACER), SetMinimalSize(2, 0),
918 NWidget(NWID_VERTICAL),
919 NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_NE), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP),
920 EndContainer(),
921 NWidget(NWID_SPACER), SetMinimalSize(0, 2),
922 NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_SE), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP),
923 EndContainer(),
924 EndContainer(),
925 NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0),
926 EndContainer(),
927 NWidget(NWID_SPACER), SetMinimalSize(0, 3),
928 EndContainer(),
929 };
930
931 static WindowDesc _build_road_depot_desc(
932 WDP_AUTO, NULL, 0, 0,
933 WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
934 WDF_CONSTRUCTION,
935 _nested_build_road_depot_widgets, lengthof(_nested_build_road_depot_widgets)
936 );
937
938 static void ShowRoadDepotPicker(Window *parent)
939 {
940 new BuildRoadDepotWindow(&_build_road_depot_desc, parent);
941 }
942
943 struct BuildRoadStationWindow : public PickerWindowBase {
944 BuildRoadStationWindow(WindowDesc *desc, Window *parent, RoadStopType rs) : PickerWindowBase(desc, parent)
945 {
946 this->CreateNestedTree();
947
948 /* Trams don't have non-drivethrough stations */
949 if (_cur_roadtype == ROADTYPE_TRAM && _road_station_picker_orientation < DIAGDIR_END) {
950 _road_station_picker_orientation = DIAGDIR_END;
951 }
952 this->SetWidgetsDisabledState(_cur_roadtype == ROADTYPE_TRAM,
953 WID_BROS_STATION_NE,
954 WID_BROS_STATION_SE,
955 WID_BROS_STATION_SW,
956 WID_BROS_STATION_NW,
957 WIDGET_LIST_END);
958
959 this->GetWidget<NWidgetCore>(WID_BROS_CAPTION)->widget_data = _road_type_infos[_cur_roadtype].picker_title[rs];
960 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];
961
962 this->LowerWidget(_road_station_picker_orientation + WID_BROS_STATION_NE);
963 this->LowerWidget(_settings_client.gui.station_show_coverage + WID_BROS_LT_OFF);
964
965 this->FinishInitNested(TRANSPORT_ROAD);
966
967 this->window_class = (rs == ROADSTOP_BUS) ? WC_BUS_STATION : WC_TRUCK_STATION;
968 }
969
970 virtual ~BuildRoadStationWindow()
971 {
972 DeleteWindowById(WC_SELECT_STATION, 0);
973 }
974
975 virtual void OnPaint()
976 {
977 this->DrawWidgets();
978
979 int rad = _settings_game.station.modified_catchment ? ((this->window_class == WC_BUS_STATION) ? CA_BUS : CA_TRUCK) : CA_UNMODIFIED;
980 if (_settings_client.gui.station_show_coverage) {
981 SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
982 } else {
983 SetTileSelectSize(1, 1);
984 }
985
986 /* 'Accepts' and 'Supplies' texts. */
987 StationCoverageType sct = (this->window_class == WC_BUS_STATION) ? SCT_PASSENGERS_ONLY : SCT_NON_PASSENGERS_ONLY;
988 int top = this->GetWidget<NWidgetBase>(WID_BROS_LT_ON)->pos_y + this->GetWidget<NWidgetBase>(WID_BROS_LT_ON)->current_y + WD_PAR_VSEP_NORMAL;
989 NWidgetBase *back_nwi = this->GetWidget<NWidgetBase>(WID_BROS_BACKGROUND);
990 int right = back_nwi->pos_x + back_nwi->current_x;
991 int bottom = back_nwi->pos_y + back_nwi->current_y;
992 top = DrawStationCoverageAreaText(back_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, sct, rad, false) + WD_PAR_VSEP_NORMAL;
993 top = DrawStationCoverageAreaText(back_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, sct, rad, true) + WD_PAR_VSEP_NORMAL;
994 /* Resize background if the window is too small.
995 * Never make the window smaller to avoid oscillating if the size change affects the acceptance.
996 * (This is the case, if making the window bigger moves the mouse into the window.) */
997 if (top > bottom) {
998 ResizeWindow(this, 0, top - bottom);
999 }
1000 }
1001
1002 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
1003 {
1004 if (!IsInsideMM(widget, WID_BROS_STATION_NE, WID_BROS_STATION_Y + 1)) return;
1005
1006 size->width = ScaleGUITrad(64) + 2;
1007 size->height = ScaleGUITrad(48) + 2;
1008 }
1009
1010 virtual void DrawWidget(const Rect &r, int widget) const
1011 {
1012 if (!IsInsideMM(widget, WID_BROS_STATION_NE, WID_BROS_STATION_Y + 1)) return;
1013
1014 StationType st = (this->window_class == WC_BUS_STATION) ? STATION_BUS : STATION_TRUCK;
1015 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);
1016 }
1017
1018 virtual void OnClick(Point pt, int widget, int click_count)
1019 {
1020 switch (widget) {
1021 case WID_BROS_STATION_NE:
1022 case WID_BROS_STATION_SE:
1023 case WID_BROS_STATION_SW:
1024 case WID_BROS_STATION_NW:
1025 case WID_BROS_STATION_X:
1026 case WID_BROS_STATION_Y:
1027 this->RaiseWidget(_road_station_picker_orientation + WID_BROS_STATION_NE);
1028 _road_station_picker_orientation = (DiagDirection)(widget - WID_BROS_STATION_NE);
1029 this->LowerWidget(_road_station_picker_orientation + WID_BROS_STATION_NE);
1030 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1031 this->SetDirty();
1032 DeleteWindowById(WC_SELECT_STATION, 0);
1033 break;
1034
1035 case WID_BROS_LT_OFF:
1036 case WID_BROS_LT_ON:
1037 this->RaiseWidget(_settings_client.gui.station_show_coverage + WID_BROS_LT_OFF);
1038 _settings_client.gui.station_show_coverage = (widget != WID_BROS_LT_OFF);
1039 this->LowerWidget(_settings_client.gui.station_show_coverage + WID_BROS_LT_OFF);
1040 if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP);
1041 this->SetDirty();
1042 break;
1043
1044 default:
1045 break;
1046 }
1047 }
1048
1049 virtual void OnTick()
1050 {
1051 CheckRedrawStationCoverage(this);
1052 }
1053 };
1054
1056 static const NWidgetPart _nested_rv_station_picker_widgets[] = {
1057 NWidget(NWID_HORIZONTAL),
1058 NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN),
1059 NWidget(WWT_CAPTION, COLOUR_DARK_GREEN, WID_BROS_CAPTION),
1060 EndContainer(),
1061 NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_BROS_BACKGROUND),
1062 NWidget(NWID_SPACER), SetMinimalSize(0, 3),
1063 NWidget(NWID_HORIZONTAL), SetPIP(0, 2, 0),
1064 NWidget(NWID_SPACER), SetFill(1, 0),
1065 NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_NW), SetMinimalSize(66, 50), EndContainer(),
1066 NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_NE), SetMinimalSize(66, 50), EndContainer(),
1067 NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_X), SetMinimalSize(66, 50), EndContainer(),
1068 NWidget(NWID_SPACER), SetFill(1, 0),
1069 EndContainer(),
1070 NWidget(NWID_SPACER), SetMinimalSize(0, 2),
1071 NWidget(NWID_HORIZONTAL), SetPIP(0, 2, 0),
1072 NWidget(NWID_SPACER), SetFill(1, 0),
1073 NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_SW), SetMinimalSize(66, 50), EndContainer(),
1074 NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_SE), SetMinimalSize(66, 50), EndContainer(),
1075 NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_Y), SetMinimalSize(66, 50), EndContainer(),
1076 NWidget(NWID_SPACER), SetFill(1, 0),
1077 EndContainer(),
1078 NWidget(NWID_SPACER), SetMinimalSize(0, 1),
1079 NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2),
1080 NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BROS_INFO), SetMinimalSize(140, 14), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL),
1081 NWidget(NWID_SPACER), SetFill(1, 0),
1082 EndContainer(),
1083 NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2),
1084 NWidget(NWID_SPACER), SetFill(1, 0),
1085 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROS_LT_OFF), SetMinimalSize(60, 12),
1086 SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP),
1087 NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROS_LT_ON), SetMinimalSize(60, 12),
1088 SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP),
1089 NWidget(NWID_SPACER), SetFill(1, 0),
1090 EndContainer(),
1091 NWidget(NWID_SPACER), SetMinimalSize(0, 10), SetResize(0, 1),
1092 EndContainer(),
1093 };
1094
1095 static WindowDesc _rv_station_picker_desc(
1096 WDP_AUTO, NULL, 0, 0,
1097 WC_BUS_STATION, WC_BUILD_TOOLBAR,
1098 WDF_CONSTRUCTION,
1099 _nested_rv_station_picker_widgets, lengthof(_nested_rv_station_picker_widgets)
1100 );
1101
1102 static void ShowRVStationPicker(Window *parent, RoadStopType rs)
1103 {
1104 new BuildRoadStationWindow(&_rv_station_picker_desc, parent, rs);
1105 }
1106
1107 void InitializeRoadGui()
1108 {
1109 _road_depot_orientation = DIAGDIR_NW;
1110 _road_station_picker_orientation = DIAGDIR_NW;
1111 }