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 airport_gui.cpp The GUI for airports. */
11 #include "economy_func.h"
12 #include "window_gui.h"
13 #include "station_gui.h"
14 #include "terraform_gui.h"
15 #include "sound_func.h"
16 #include "window_func.h"
17 #include "strings_func.h"
18 #include "viewport_func.h"
19 #include "company_func.h"
20 #include "tilehighlight_func.h"
21 #include "company_base.h"
22 #include "station_type.h"
23 #include "newgrf_airport.h"
24 #include "newgrf_callbacks.h"
25 #include "widgets/dropdown_type.h"
26 #include "core/geometry_func.hpp"
28 #include "vehicle_func.h"
30 #include "command_func.h"
31 #include "airport_cmd.h"
32 #include "station_cmd.h"
33 #include "zoom_func.h"
34 #include "timer/timer.h"
35 #include "timer/timer_game_calendar.h"
37 #include "widgets/airport_widget.h"
39 #include "safeguards.h"
42 static AirportClassID _selected_airport_class
; ///< the currently visible airport class
43 static int _selected_airport_index
; ///< the index of the selected airport in the current class or -1
44 static byte _selected_airport_layout
; ///< selected airport layout number.
46 static void ShowBuildAirportPicker(Window
*parent
);
48 SpriteID
GetCustomAirportSprite(const AirportSpec
*as
, byte layout
);
50 void CcBuildAirport(Commands
, const CommandCost
&result
, TileIndex tile
)
52 if (result
.Failed()) return;
54 if (_settings_client
.sound
.confirm
) SndPlayTileFx(SND_1F_CONSTRUCTION_OTHER
, tile
);
55 if (!_settings_client
.gui
.persistent_buildingtools
) ResetObjectToPlace();
60 * @param tile Position to put the new airport.
62 static void PlaceAirport(TileIndex tile
)
64 if (_selected_airport_index
== -1) return;
66 byte airport_type
= AirportClass::Get(_selected_airport_class
)->GetSpec(_selected_airport_index
)->GetIndex();
67 byte layout
= _selected_airport_layout
;
68 bool adjacent
= _ctrl_pressed
;
70 auto proc
= [=](bool test
, StationID to_join
) -> bool {
72 return Command
<CMD_BUILD_AIRPORT
>::Do(CommandFlagsToDCFlags(GetCommandFlags
<CMD_BUILD_AIRPORT
>()), tile
, airport_type
, layout
, INVALID_STATION
, adjacent
).Succeeded();
74 return Command
<CMD_BUILD_AIRPORT
>::Post(STR_ERROR_CAN_T_BUILD_AIRPORT_HERE
, CcBuildAirport
, tile
, airport_type
, layout
, to_join
, adjacent
);
78 ShowSelectStationIfNeeded(TileArea(tile
, _thd
.size
.x
/ TILE_SIZE
, _thd
.size
.y
/ TILE_SIZE
), proc
);
81 /** Airport build toolbar window handler. */
82 struct BuildAirToolbarWindow
: Window
{
83 int last_user_action
; // Last started user action.
85 BuildAirToolbarWindow(WindowDesc
*desc
, WindowNumber window_number
) : Window(desc
)
87 this->InitNested(window_number
);
88 this->OnInvalidateData();
89 if (_settings_client
.gui
.link_terraform_toolbar
) ShowTerraformToolbar(this);
90 this->last_user_action
= INVALID_WID_AT
;
93 void Close([[maybe_unused
]] int data
= 0) override
95 if (this->IsWidgetLowered(WID_AT_AIRPORT
)) SetViewportCatchmentStation(nullptr, true);
96 if (_settings_client
.gui
.link_terraform_toolbar
) CloseWindowById(WC_SCEN_LAND_GEN
, 0, false);
97 this->Window::Close();
101 * Some data on this window has become invalid.
102 * @param data Information about the changed data.
103 * @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.
105 void OnInvalidateData([[maybe_unused
]] int data
= 0, [[maybe_unused
]] bool gui_scope
= true) override
107 if (!gui_scope
) return;
109 bool can_build
= CanBuildVehicleInfrastructure(VEH_AIRCRAFT
);
110 this->SetWidgetDisabledState(WID_AT_AIRPORT
, !can_build
);
112 CloseWindowById(WC_BUILD_STATION
, TRANSPORT_AIR
);
114 /* Show in the tooltip why this button is disabled. */
115 this->GetWidget
<NWidgetCore
>(WID_AT_AIRPORT
)->SetToolTip(STR_TOOLBAR_DISABLED_NO_VEHICLE_AVAILABLE
);
117 this->GetWidget
<NWidgetCore
>(WID_AT_AIRPORT
)->SetToolTip(STR_TOOLBAR_AIRCRAFT_BUILD_AIRPORT_TOOLTIP
);
121 void OnClick([[maybe_unused
]] Point pt
, WidgetID widget
, [[maybe_unused
]] int click_count
) override
125 if (HandlePlacePushButton(this, WID_AT_AIRPORT
, SPR_CURSOR_AIRPORT
, HT_RECT
)) {
126 ShowBuildAirportPicker(this);
127 this->last_user_action
= widget
;
131 case WID_AT_DEMOLISH
:
132 HandlePlacePushButton(this, WID_AT_DEMOLISH
, ANIMCURSOR_DEMOLISH
, HT_RECT
| HT_DIAGONAL
);
133 this->last_user_action
= widget
;
141 void OnPlaceObject([[maybe_unused
]] Point pt
, TileIndex tile
) override
143 switch (this->last_user_action
) {
148 case WID_AT_DEMOLISH
:
149 PlaceProc_DemolishArea(tile
);
152 default: NOT_REACHED();
156 void OnPlaceDrag(ViewportPlaceMethod select_method
, [[maybe_unused
]] ViewportDragDropSelectionProcess select_proc
, [[maybe_unused
]] Point pt
) override
158 VpSelectTilesWithMethod(pt
.x
, pt
.y
, select_method
);
161 void OnPlaceMouseUp([[maybe_unused
]] ViewportPlaceMethod select_method
, ViewportDragDropSelectionProcess select_proc
, [[maybe_unused
]] Point pt
, TileIndex start_tile
, TileIndex end_tile
) override
163 if (pt
.x
!= -1 && select_proc
== DDSP_DEMOLISH_AREA
) {
164 GUIPlaceProcDragXY(select_proc
, start_tile
, end_tile
);
168 void OnPlaceObjectAbort() override
170 if (this->IsWidgetLowered(WID_AT_AIRPORT
)) SetViewportCatchmentStation(nullptr, true);
172 this->RaiseButtons();
174 CloseWindowById(WC_BUILD_STATION
, TRANSPORT_AIR
);
175 CloseWindowById(WC_SELECT_STATION
, 0);
179 * Handler for global hotkeys of the BuildAirToolbarWindow.
180 * @param hotkey Hotkey
181 * @return ES_HANDLED if hotkey was accepted.
183 static EventState
AirportToolbarGlobalHotkeys(int hotkey
)
185 if (_game_mode
!= GM_NORMAL
) return ES_NOT_HANDLED
;
186 Window
*w
= ShowBuildAirToolbar();
187 if (w
== nullptr) return ES_NOT_HANDLED
;
188 return w
->OnHotkey(hotkey
);
191 static inline HotkeyList hotkeys
{"airtoolbar", {
192 Hotkey('1', "airport", WID_AT_AIRPORT
),
193 Hotkey('2', "demolish", WID_AT_DEMOLISH
),
194 }, AirportToolbarGlobalHotkeys
};
197 static constexpr NWidgetPart _nested_air_toolbar_widgets
[] = {
198 NWidget(NWID_HORIZONTAL
),
199 NWidget(WWT_CLOSEBOX
, COLOUR_DARK_GREEN
),
200 NWidget(WWT_CAPTION
, COLOUR_DARK_GREEN
), SetDataTip(STR_TOOLBAR_AIRCRAFT_CAPTION
, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS
),
201 NWidget(WWT_STICKYBOX
, COLOUR_DARK_GREEN
),
203 NWidget(NWID_HORIZONTAL
),
204 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_AT_AIRPORT
), SetFill(0, 1), SetMinimalSize(42, 22), SetDataTip(SPR_IMG_AIRPORT
, STR_TOOLBAR_AIRCRAFT_BUILD_AIRPORT_TOOLTIP
),
205 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
), SetMinimalSize(4, 22), SetFill(1, 1), EndContainer(),
206 NWidget(WWT_IMGBTN
, COLOUR_DARK_GREEN
, WID_AT_DEMOLISH
), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE
, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC
),
210 static WindowDesc
_air_toolbar_desc(__FILE__
, __LINE__
,
211 WDP_ALIGN_TOOLBAR
, "toolbar_air", 0, 0,
212 WC_BUILD_TOOLBAR
, WC_NONE
,
214 std::begin(_nested_air_toolbar_widgets
), std::end(_nested_air_toolbar_widgets
),
215 &BuildAirToolbarWindow::hotkeys
219 * Open the build airport toolbar window
221 * If the terraform toolbar is linked to the toolbar, that window is also opened.
223 * @return newly opened airport toolbar, or nullptr if the toolbar could not be opened.
225 Window
*ShowBuildAirToolbar()
227 if (!Company::IsValidID(_local_company
)) return nullptr;
229 CloseWindowByClass(WC_BUILD_TOOLBAR
);
230 return AllocateWindowDescFront
<BuildAirToolbarWindow
>(&_air_toolbar_desc
, TRANSPORT_AIR
);
233 class BuildAirportWindow
: public PickerWindowBase
{
234 SpriteID preview_sprite
; ///< Cached airport preview sprite.
238 /** Build a dropdown list of available airport classes */
239 static DropDownList
BuildAirportClassDropDown()
243 for (uint i
= 0; i
< AirportClass::GetClassCount(); i
++) {
244 list
.push_back(std::make_unique
<DropDownListStringItem
>(AirportClass::Get((AirportClassID
)i
)->name
, i
, false));
251 BuildAirportWindow(WindowDesc
*desc
, Window
*parent
) : PickerWindowBase(desc
, parent
)
253 this->CreateNestedTree();
255 this->vscroll
= this->GetScrollbar(WID_AP_SCROLLBAR
);
256 this->vscroll
->SetCapacity(5);
257 this->vscroll
->SetPosition(0);
259 this->FinishInitNested(TRANSPORT_AIR
);
261 this->SetWidgetLoweredState(WID_AP_BTN_DONTHILIGHT
, !_settings_client
.gui
.station_show_coverage
);
262 this->SetWidgetLoweredState(WID_AP_BTN_DOHILIGHT
, _settings_client
.gui
.station_show_coverage
);
263 this->OnInvalidateData();
265 /* Ensure airport class is valid (changing NewGRFs). */
266 _selected_airport_class
= Clamp(_selected_airport_class
, APC_BEGIN
, (AirportClassID
)(AirportClass::GetClassCount() - 1));
267 const AirportClass
*ac
= AirportClass::Get(_selected_airport_class
);
268 this->vscroll
->SetCount(ac
->GetSpecCount());
270 /* Ensure the airport index is valid for this class (changing NewGRFs). */
271 _selected_airport_index
= Clamp(_selected_airport_index
, -1, ac
->GetSpecCount() - 1);
273 /* Only when no valid airport was selected, we want to select the first airport. */
274 bool selectFirstAirport
= true;
275 if (_selected_airport_index
!= -1) {
276 const AirportSpec
*as
= ac
->GetSpec(_selected_airport_index
);
277 if (as
->IsAvailable()) {
278 /* Ensure the airport layout is valid. */
279 _selected_airport_layout
= Clamp(_selected_airport_layout
, 0, as
->num_table
- 1);
280 selectFirstAirport
= false;
281 this->UpdateSelectSize();
285 if (selectFirstAirport
) this->SelectFirstAvailableAirport(true);
288 void Close([[maybe_unused
]] int data
= 0) override
290 CloseWindowById(WC_SELECT_STATION
, 0);
291 this->PickerWindowBase::Close();
294 void SetStringParameters(WidgetID widget
) const override
297 case WID_AP_CLASS_DROPDOWN
:
298 SetDParam(0, AirportClass::Get(_selected_airport_class
)->name
);
301 case WID_AP_LAYOUT_NUM
:
302 SetDParam(0, STR_EMPTY
);
303 if (_selected_airport_index
!= -1) {
304 const AirportSpec
*as
= AirportClass::Get(_selected_airport_class
)->GetSpec(_selected_airport_index
);
305 StringID string
= GetAirportTextCallback(as
, _selected_airport_layout
, CBID_AIRPORT_LAYOUT_NAME
);
306 if (string
!= STR_UNDEFINED
) {
307 SetDParam(0, string
);
308 } else if (as
->num_table
> 1) {
309 SetDParam(0, STR_STATION_BUILD_AIRPORT_LAYOUT_NAME
);
310 SetDParam(1, _selected_airport_layout
+ 1);
319 void UpdateWidgetSize(WidgetID widget
, Dimension
*size
, [[maybe_unused
]] const Dimension
&padding
, [[maybe_unused
]] Dimension
*fill
, [[maybe_unused
]] Dimension
*resize
) override
322 case WID_AP_CLASS_DROPDOWN
: {
323 Dimension d
= {0, 0};
324 for (uint i
= 0; i
< AirportClass::GetClassCount(); i
++) {
325 d
= maxdim(d
, GetStringBoundingBox(AirportClass::Get((AirportClassID
)i
)->name
));
327 d
.width
+= padding
.width
;
328 d
.height
+= padding
.height
;
329 *size
= maxdim(*size
, d
);
333 case WID_AP_AIRPORT_LIST
: {
334 for (int i
= 0; i
< NUM_AIRPORTS
; i
++) {
335 const AirportSpec
*as
= AirportSpec::Get(i
);
336 if (!as
->enabled
) continue;
338 size
->width
= std::max(size
->width
, GetStringBoundingBox(as
->name
).width
+ padding
.width
);
341 this->line_height
= GetCharacterHeight(FS_NORMAL
) + padding
.height
;
342 size
->height
= 5 * this->line_height
;
346 case WID_AP_AIRPORT_SPRITE
:
347 for (int i
= 0; i
< NUM_AIRPORTS
; i
++) {
348 const AirportSpec
*as
= AirportSpec::Get(i
);
349 if (!as
->enabled
) continue;
350 for (byte layout
= 0; layout
< as
->num_table
; layout
++) {
351 SpriteID sprite
= GetCustomAirportSprite(as
, layout
);
353 Dimension d
= GetSpriteSize(sprite
);
354 d
.width
+= WidgetDimensions::scaled
.framerect
.Horizontal();
355 d
.height
+= WidgetDimensions::scaled
.framerect
.Vertical();
356 *size
= maxdim(d
, *size
);
362 case WID_AP_EXTRA_TEXT
:
363 for (int i
= NEW_AIRPORT_OFFSET
; i
< NUM_AIRPORTS
; i
++) {
364 const AirportSpec
*as
= AirportSpec::Get(i
);
365 if (!as
->enabled
) continue;
366 for (byte layout
= 0; layout
< as
->num_table
; layout
++) {
367 StringID string
= GetAirportTextCallback(as
, layout
, CBID_AIRPORT_ADDITIONAL_TEXT
);
368 if (string
== STR_UNDEFINED
) continue;
370 Dimension d
= GetStringMultiLineBoundingBox(string
, *size
);
371 *size
= maxdim(d
, *size
);
380 void DrawWidget(const Rect
&r
, WidgetID widget
) const override
383 case WID_AP_AIRPORT_LIST
: {
384 Rect row
= r
.WithHeight(this->line_height
).Shrink(WidgetDimensions::scaled
.bevel
);
385 Rect text
= r
.WithHeight(this->line_height
).Shrink(WidgetDimensions::scaled
.matrix
);
386 AirportClass
*apclass
= AirportClass::Get(_selected_airport_class
);
387 for (uint i
= this->vscroll
->GetPosition(); this->vscroll
->IsVisible(i
) && i
< apclass
->GetSpecCount(); i
++) {
388 const AirportSpec
*as
= apclass
->GetSpec(i
);
389 if (!as
->IsAvailable()) {
390 GfxFillRect(row
, PC_BLACK
, FILLRECT_CHECKER
);
392 DrawString(text
, as
->name
, ((int)i
== _selected_airport_index
) ? TC_WHITE
: TC_BLACK
);
393 row
= row
.Translate(0, this->line_height
);
394 text
= text
.Translate(0, this->line_height
);
399 case WID_AP_AIRPORT_SPRITE
:
400 if (this->preview_sprite
!= 0) {
401 Dimension d
= GetSpriteSize(this->preview_sprite
);
402 DrawSprite(this->preview_sprite
, COMPANY_SPRITE_COLOUR(_local_company
), CenterBounds(r
.left
, r
.right
, d
.width
), CenterBounds(r
.top
, r
.bottom
, d
.height
));
406 case WID_AP_EXTRA_TEXT
:
407 if (_selected_airport_index
!= -1) {
408 const AirportSpec
*as
= AirportClass::Get(_selected_airport_class
)->GetSpec(_selected_airport_index
);
409 StringID string
= GetAirportTextCallback(as
, _selected_airport_layout
, CBID_AIRPORT_ADDITIONAL_TEXT
);
410 if (string
!= STR_UNDEFINED
) {
411 DrawStringMultiLine(r
.left
, r
.right
, r
.top
, r
.bottom
, string
, TC_BLACK
);
418 void OnPaint() override
422 Rect r
= this->GetWidget
<NWidgetBase
>(WID_AP_ACCEPTANCE
)->GetCurrentRect();
425 if (_selected_airport_index
!= -1) {
426 const AirportSpec
*as
= AirportClass::Get(_selected_airport_class
)->GetSpec(_selected_airport_index
);
427 int rad
= _settings_game
.station
.modified_catchment
? as
->catchment
: (uint
)CA_UNMODIFIED
;
429 /* only show the station (airport) noise, if the noise option is activated */
430 if (_settings_game
.economy
.station_noise_level
) {
431 /* show the noise of the selected airport */
432 SetDParam(0, as
->noise_level
);
433 DrawString(r
.left
, r
.right
, top
, STR_STATION_BUILD_NOISE
);
434 top
+= GetCharacterHeight(FS_NORMAL
) + WidgetDimensions::scaled
.vsep_normal
;
437 if (_settings_game
.economy
.infrastructure_maintenance
) {
438 Money monthly
= _price
[PR_INFRASTRUCTURE_AIRPORT
] * as
->maintenance_cost
>> 3;
439 SetDParam(0, monthly
* 12);
440 DrawString(r
.left
, r
.right
, top
, TimerGameEconomy::UsingWallclockUnits() ? STR_STATION_BUILD_INFRASTRUCTURE_COST_PERIOD
: STR_STATION_BUILD_INFRASTRUCTURE_COST_YEAR
);
441 top
+= GetCharacterHeight(FS_NORMAL
) + WidgetDimensions::scaled
.vsep_normal
;
444 /* strings such as 'Size' and 'Coverage Area' */
445 top
= DrawStationCoverageAreaText(r
.left
, r
.right
, top
, SCT_ALL
, rad
, false) + WidgetDimensions::scaled
.vsep_normal
;
446 top
= DrawStationCoverageAreaText(r
.left
, r
.right
, top
, SCT_ALL
, rad
, true);
449 /* Resize background if the window is too small.
450 * Never make the window smaller to avoid oscillating if the size change affects the acceptance.
451 * (This is the case, if making the window bigger moves the mouse into the window.) */
452 if (top
> r
.bottom
) {
453 ResizeWindow(this, 0, top
- r
.bottom
, false);
457 void SelectOtherAirport(int airport_index
)
459 _selected_airport_index
= airport_index
;
460 _selected_airport_layout
= 0;
462 this->UpdateSelectSize();
466 void UpdateSelectSize()
468 if (_selected_airport_index
== -1) {
469 SetTileSelectSize(1, 1);
470 this->DisableWidget(WID_AP_LAYOUT_DECREASE
);
471 this->DisableWidget(WID_AP_LAYOUT_INCREASE
);
473 const AirportSpec
*as
= AirportClass::Get(_selected_airport_class
)->GetSpec(_selected_airport_index
);
476 Direction rotation
= as
->rotation
[_selected_airport_layout
];
477 if (rotation
== DIR_E
|| rotation
== DIR_W
) Swap(w
, h
);
478 SetTileSelectSize(w
, h
);
480 this->preview_sprite
= GetCustomAirportSprite(as
, _selected_airport_layout
);
482 this->SetWidgetDisabledState(WID_AP_LAYOUT_DECREASE
, _selected_airport_layout
== 0);
483 this->SetWidgetDisabledState(WID_AP_LAYOUT_INCREASE
, _selected_airport_layout
+ 1 >= as
->num_table
);
485 int rad
= _settings_game
.station
.modified_catchment
? as
->catchment
: (uint
)CA_UNMODIFIED
;
486 if (_settings_client
.gui
.station_show_coverage
) SetTileSelectBigSize(-rad
, -rad
, 2 * rad
, 2 * rad
);
490 void OnClick([[maybe_unused
]] Point pt
, WidgetID widget
, [[maybe_unused
]] int click_count
) override
493 case WID_AP_CLASS_DROPDOWN
:
494 ShowDropDownList(this, BuildAirportClassDropDown(), _selected_airport_class
, WID_AP_CLASS_DROPDOWN
);
497 case WID_AP_AIRPORT_LIST
: {
498 int num_clicked
= this->vscroll
->GetScrolledRowFromWidget(pt
.y
, this, widget
, 0, this->line_height
);
499 if (num_clicked
== INT_MAX
) break;
500 const AirportSpec
*as
= AirportClass::Get(_selected_airport_class
)->GetSpec(num_clicked
);
501 if (as
->IsAvailable()) this->SelectOtherAirport(num_clicked
);
505 case WID_AP_BTN_DONTHILIGHT
: case WID_AP_BTN_DOHILIGHT
:
506 _settings_client
.gui
.station_show_coverage
= (widget
!= WID_AP_BTN_DONTHILIGHT
);
507 this->SetWidgetLoweredState(WID_AP_BTN_DONTHILIGHT
, !_settings_client
.gui
.station_show_coverage
);
508 this->SetWidgetLoweredState(WID_AP_BTN_DOHILIGHT
, _settings_client
.gui
.station_show_coverage
);
510 if (_settings_client
.sound
.click_beep
) SndPlayFx(SND_15_BEEP
);
511 this->UpdateSelectSize();
512 SetViewportCatchmentStation(nullptr, true);
515 case WID_AP_LAYOUT_DECREASE
:
516 _selected_airport_layout
--;
517 this->UpdateSelectSize();
521 case WID_AP_LAYOUT_INCREASE
:
522 _selected_airport_layout
++;
523 this->UpdateSelectSize();
530 * Select the first available airport.
531 * @param change_class If true, change the class if no airport in the current
532 * class is available.
534 void SelectFirstAvailableAirport(bool change_class
)
536 /* First try to select an airport in the selected class. */
537 AirportClass
*sel_apclass
= AirportClass::Get(_selected_airport_class
);
538 for (uint i
= 0; i
< sel_apclass
->GetSpecCount(); i
++) {
539 const AirportSpec
*as
= sel_apclass
->GetSpec(i
);
540 if (as
->IsAvailable()) {
541 this->SelectOtherAirport(i
);
546 /* If that fails, select the first available airport
547 * from the first class where airports are available. */
548 for (AirportClassID j
= APC_BEGIN
; j
< APC_MAX
; j
++) {
549 AirportClass
*apclass
= AirportClass::Get(j
);
550 for (uint i
= 0; i
< apclass
->GetSpecCount(); i
++) {
551 const AirportSpec
*as
= apclass
->GetSpec(i
);
552 if (as
->IsAvailable()) {
553 _selected_airport_class
= j
;
554 this->vscroll
->SetCount(apclass
->GetSpecCount());
555 this->SelectOtherAirport(i
);
561 /* If all airports are unavailable, select nothing. */
562 this->SelectOtherAirport(-1);
565 void OnDropdownSelect(WidgetID widget
, int index
) override
567 if (widget
== WID_AP_CLASS_DROPDOWN
) {
568 _selected_airport_class
= (AirportClassID
)index
;
569 this->vscroll
->SetCount(AirportClass::Get(_selected_airport_class
)->GetSpecCount());
570 this->SelectFirstAvailableAirport(false);
574 void OnRealtimeTick([[maybe_unused
]] uint delta_ms
) override
576 CheckRedrawStationCoverage(this);
579 IntervalTimer
<TimerGameCalendar
> yearly_interval
= {{TimerGameCalendar::YEAR
, TimerGameCalendar::Priority::NONE
}, [this](auto) {
580 this->InvalidateData();
584 static constexpr NWidgetPart _nested_build_airport_widgets
[] = {
585 NWidget(NWID_HORIZONTAL
),
586 NWidget(WWT_CLOSEBOX
, COLOUR_DARK_GREEN
),
587 NWidget(WWT_CAPTION
, COLOUR_DARK_GREEN
), SetDataTip(STR_STATION_BUILD_AIRPORT_CAPTION
, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS
),
589 NWidget(WWT_PANEL
, COLOUR_DARK_GREEN
),
590 NWidget(NWID_VERTICAL
), SetPIP(0, WidgetDimensions::unscaled
.vsep_normal
, 0), SetPadding(WidgetDimensions::unscaled
.picker
),
591 NWidget(NWID_VERTICAL
), SetPIP(0, WidgetDimensions::unscaled
.vsep_picker
, 0),
592 NWidget(WWT_LABEL
, COLOUR_DARK_GREEN
), SetDataTip(STR_STATION_BUILD_AIRPORT_CLASS_LABEL
, STR_NULL
), SetFill(1, 0),
593 NWidget(WWT_DROPDOWN
, COLOUR_GREY
, WID_AP_CLASS_DROPDOWN
), SetFill(1, 0), SetDataTip(STR_JUST_STRING
, STR_STATION_BUILD_AIRPORT_TOOLTIP
),
594 NWidget(WWT_EMPTY
, COLOUR_DARK_GREEN
, WID_AP_AIRPORT_SPRITE
), SetFill(1, 0),
595 NWidget(NWID_HORIZONTAL
),
596 NWidget(WWT_MATRIX
, COLOUR_GREY
, WID_AP_AIRPORT_LIST
), SetFill(1, 0), SetMatrixDataTip(1, 5, STR_STATION_BUILD_AIRPORT_TOOLTIP
), SetScrollbar(WID_AP_SCROLLBAR
),
597 NWidget(NWID_VSCROLLBAR
, COLOUR_GREY
, WID_AP_SCROLLBAR
),
599 NWidget(WWT_LABEL
, COLOUR_DARK_GREEN
), SetDataTip(STR_STATION_BUILD_ORIENTATION
, STR_NULL
), SetFill(1, 0),
600 NWidget(NWID_HORIZONTAL
),
601 NWidget(WWT_PUSHARROWBTN
, COLOUR_GREY
, WID_AP_LAYOUT_DECREASE
), SetMinimalSize(12, 0), SetDataTip(AWV_DECREASE
, STR_NULL
),
602 NWidget(WWT_LABEL
, COLOUR_GREY
, WID_AP_LAYOUT_NUM
), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_JUST_STRING1
, STR_NULL
),
603 NWidget(WWT_PUSHARROWBTN
, COLOUR_GREY
, WID_AP_LAYOUT_INCREASE
), SetMinimalSize(12, 0), SetDataTip(AWV_INCREASE
, STR_NULL
),
605 NWidget(WWT_EMPTY
, COLOUR_DARK_GREEN
, WID_AP_EXTRA_TEXT
), SetFill(1, 0), SetMinimalSize(150, 0),
606 NWidget(WWT_LABEL
, COLOUR_DARK_GREEN
), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE
, STR_NULL
), SetFill(1, 0),
607 NWidget(NWID_HORIZONTAL
), SetPIP(14, 0, 14), SetPIPRatio(1, 0, 1),
608 NWidget(NWID_HORIZONTAL
, NC_EQUALSIZE
),
609 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_AP_BTN_DONTHILIGHT
), SetMinimalSize(60, 12), SetFill(1, 0),
610 SetDataTip(STR_STATION_BUILD_COVERAGE_OFF
, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP
),
611 NWidget(WWT_TEXTBTN
, COLOUR_GREY
, WID_AP_BTN_DOHILIGHT
), SetMinimalSize(60, 12), SetFill(1, 0),
612 SetDataTip(STR_STATION_BUILD_COVERAGE_ON
, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP
),
616 NWidget(WWT_EMPTY
, COLOUR_DARK_GREEN
, WID_AP_ACCEPTANCE
), SetResize(0, 1), SetFill(1, 0), SetMinimalTextLines(2, WidgetDimensions::unscaled
.vsep_normal
),
621 static WindowDesc
_build_airport_desc(__FILE__
, __LINE__
,
622 WDP_AUTO
, nullptr, 0, 0,
623 WC_BUILD_STATION
, WC_BUILD_TOOLBAR
,
625 std::begin(_nested_build_airport_widgets
), std::end(_nested_build_airport_widgets
)
628 static void ShowBuildAirportPicker(Window
*parent
)
630 new BuildAirportWindow(&_build_airport_desc
, parent
);
633 void InitializeAirportGui()
635 _selected_airport_class
= APC_BEGIN
;
636 _selected_airport_index
= -1;