/* * This file is part of OpenTTD. * 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. * 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. * 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 . */ /** @file airport_gui.cpp The GUI for airports. */ #include "stdafx.h" #include "window_gui.h" #include "station_gui.h" #include "terraform_gui.h" #include "sound_func.h" #include "window_func.h" #include "strings_func.h" #include "viewport_func.h" #include "company_func.h" #include "tilehighlight_func.h" #include "company_base.h" #include "station_type.h" #include "newgrf_airport.h" #include "newgrf_callbacks.h" #include "widgets/dropdown_type.h" #include "core/geometry_func.hpp" #include "hotkeys.h" #include "vehicle_func.h" #include "gui.h" #include "command_func.h" #include "airport_cmd.h" #include "station_cmd.h" #include "widgets/airport_widget.h" #include "safeguards.h" static AirportClassID _selected_airport_class; ///< the currently visible airport class static int _selected_airport_index; ///< the index of the selected airport in the current class or -1 static byte _selected_airport_layout; ///< selected airport layout number. static void ShowBuildAirportPicker(Window *parent); SpriteID GetCustomAirportSprite(const AirportSpec *as, byte layout); void CcBuildAirport(const CommandCost &result, Commands cmd, TileIndex tile, uint32 p1, uint32 p2, const std::string &text) { if (result.Failed()) return; if (_settings_client.sound.confirm) SndPlayTileFx(SND_1F_CONSTRUCTION_OTHER, tile); if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); } /** * Place an airport. * @param tile Position to put the new airport. */ static void PlaceAirport(TileIndex tile) { if (_selected_airport_index == -1) return; uint32 p2 = _ctrl_pressed; SB(p2, 16, 16, INVALID_STATION); // no station to join uint32 p1 = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index)->GetIndex(); p1 |= _selected_airport_layout << 8; auto proc = [=](bool test, StationID to_join) -> bool { if (test) { return Command::Do(CommandFlagsToDCFlags(GetCommandFlags()), tile, p1, p2, {}).Succeeded(); } else { uint32 p2_final = p2; if (to_join != INVALID_STATION) SB(p2_final, 16, 16, to_join); return DoCommandP(CMD_BUILD_AIRPORT, STR_ERROR_CAN_T_BUILD_AIRPORT_HERE, CcBuildAirport, tile, p1, p2_final); } }; ShowSelectStationIfNeeded(TileArea(tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE), proc); } /** Airport build toolbar window handler. */ struct BuildAirToolbarWindow : Window { int last_user_action; // Last started user action. BuildAirToolbarWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) { this->InitNested(window_number); this->OnInvalidateData(); if (_settings_client.gui.link_terraform_toolbar) ShowTerraformToolbar(this); this->last_user_action = WIDGET_LIST_END; } void Close() override { if (this->IsWidgetLowered(WID_AT_AIRPORT)) SetViewportCatchmentStation(nullptr, true); if (_settings_client.gui.link_terraform_toolbar) CloseWindowById(WC_SCEN_LAND_GEN, 0, false); this->Window::Close(); } /** * Some data on this window has become invalid. * @param data Information about the changed data. * @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. */ void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; bool can_build = CanBuildVehicleInfrastructure(VEH_AIRCRAFT); this->SetWidgetsDisabledState(!can_build, WID_AT_AIRPORT, WIDGET_LIST_END); if (!can_build) { CloseWindowById(WC_BUILD_STATION, TRANSPORT_AIR); /* Show in the tooltip why this button is disabled. */ this->GetWidget(WID_AT_AIRPORT)->SetToolTip(STR_TOOLBAR_DISABLED_NO_VEHICLE_AVAILABLE); } else { this->GetWidget(WID_AT_AIRPORT)->SetToolTip(STR_TOOLBAR_AIRCRAFT_BUILD_AIRPORT_TOOLTIP); } } void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_AT_AIRPORT: if (HandlePlacePushButton(this, WID_AT_AIRPORT, SPR_CURSOR_AIRPORT, HT_RECT)) { ShowBuildAirportPicker(this); this->last_user_action = widget; } break; case WID_AT_DEMOLISH: HandlePlacePushButton(this, WID_AT_DEMOLISH, ANIMCURSOR_DEMOLISH, HT_RECT | HT_DIAGONAL); this->last_user_action = widget; break; default: break; } } void OnPlaceObject(Point pt, TileIndex tile) override { switch (this->last_user_action) { case WID_AT_AIRPORT: PlaceAirport(tile); break; case WID_AT_DEMOLISH: PlaceProc_DemolishArea(tile); break; default: NOT_REACHED(); } } void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) override { VpSelectTilesWithMethod(pt.x, pt.y, select_method); } void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) override { if (pt.x != -1 && select_proc == DDSP_DEMOLISH_AREA) { GUIPlaceProcDragXY(select_proc, start_tile, end_tile); } } void OnPlaceObjectAbort() override { if (this->IsWidgetLowered(WID_AT_AIRPORT)) SetViewportCatchmentStation(nullptr, true); this->RaiseButtons(); CloseWindowById(WC_BUILD_STATION, TRANSPORT_AIR); CloseWindowById(WC_SELECT_STATION, 0); } static HotkeyList hotkeys; }; /** * Handler for global hotkeys of the BuildAirToolbarWindow. * @param hotkey Hotkey * @return ES_HANDLED if hotkey was accepted. */ static EventState AirportToolbarGlobalHotkeys(int hotkey) { if (_game_mode != GM_NORMAL) return ES_NOT_HANDLED; Window *w = ShowBuildAirToolbar(); if (w == nullptr) return ES_NOT_HANDLED; return w->OnHotkey(hotkey); } static Hotkey airtoolbar_hotkeys[] = { Hotkey('1', "airport", WID_AT_AIRPORT), Hotkey('2', "demolish", WID_AT_DEMOLISH), HOTKEY_LIST_END }; HotkeyList BuildAirToolbarWindow::hotkeys("airtoolbar", airtoolbar_hotkeys, AirportToolbarGlobalHotkeys); static const NWidgetPart _nested_air_toolbar_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_TOOLBAR_AIRCRAFT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_STICKYBOX, COLOUR_DARK_GREEN), EndContainer(), NWidget(NWID_HORIZONTAL), 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), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetMinimalSize(4, 22), SetFill(1, 1), EndContainer(), NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_AT_DEMOLISH), SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC), EndContainer(), }; static WindowDesc _air_toolbar_desc( WDP_ALIGN_TOOLBAR, "toolbar_air", 0, 0, WC_BUILD_TOOLBAR, WC_NONE, WDF_CONSTRUCTION, _nested_air_toolbar_widgets, lengthof(_nested_air_toolbar_widgets), &BuildAirToolbarWindow::hotkeys ); /** * Open the build airport toolbar window * * If the terraform toolbar is linked to the toolbar, that window is also opened. * * @return newly opened airport toolbar, or nullptr if the toolbar could not be opened. */ Window *ShowBuildAirToolbar() { if (!Company::IsValidID(_local_company)) return nullptr; CloseWindowByClass(WC_BUILD_TOOLBAR); return AllocateWindowDescFront(&_air_toolbar_desc, TRANSPORT_AIR); } class BuildAirportWindow : public PickerWindowBase { SpriteID preview_sprite; ///< Cached airport preview sprite. int line_height; Scrollbar *vscroll; /** Build a dropdown list of available airport classes */ static DropDownList BuildAirportClassDropDown() { DropDownList list; for (uint i = 0; i < AirportClass::GetClassCount(); i++) { list.emplace_back(new DropDownListStringItem(AirportClass::Get((AirportClassID)i)->name, i, false)); } return list; } public: BuildAirportWindow(WindowDesc *desc, Window *parent) : PickerWindowBase(desc, parent) { this->CreateNestedTree(); this->vscroll = this->GetScrollbar(WID_AP_SCROLLBAR); this->vscroll->SetCapacity(5); this->vscroll->SetPosition(0); this->FinishInitNested(TRANSPORT_AIR); this->SetWidgetLoweredState(WID_AP_BTN_DONTHILIGHT, !_settings_client.gui.station_show_coverage); this->SetWidgetLoweredState(WID_AP_BTN_DOHILIGHT, _settings_client.gui.station_show_coverage); this->OnInvalidateData(); /* Ensure airport class is valid (changing NewGRFs). */ _selected_airport_class = Clamp(_selected_airport_class, APC_BEGIN, (AirportClassID)(AirportClass::GetClassCount() - 1)); const AirportClass *ac = AirportClass::Get(_selected_airport_class); this->vscroll->SetCount(ac->GetSpecCount()); /* Ensure the airport index is valid for this class (changing NewGRFs). */ _selected_airport_index = Clamp(_selected_airport_index, -1, ac->GetSpecCount() - 1); /* Only when no valid airport was selected, we want to select the first airport. */ bool selectFirstAirport = true; if (_selected_airport_index != -1) { const AirportSpec *as = ac->GetSpec(_selected_airport_index); if (as->IsAvailable()) { /* Ensure the airport layout is valid. */ _selected_airport_layout = Clamp(_selected_airport_layout, 0, as->num_table - 1); selectFirstAirport = false; this->UpdateSelectSize(); } } if (selectFirstAirport) this->SelectFirstAvailableAirport(true); } void Close() override { CloseWindowById(WC_SELECT_STATION, 0); this->PickerWindowBase::Close(); } void SetStringParameters(int widget) const override { switch (widget) { case WID_AP_CLASS_DROPDOWN: SetDParam(0, AirportClass::Get(_selected_airport_class)->name); break; case WID_AP_LAYOUT_NUM: SetDParam(0, STR_EMPTY); if (_selected_airport_index != -1) { const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index); StringID string = GetAirportTextCallback(as, _selected_airport_layout, CBID_AIRPORT_LAYOUT_NAME); if (string != STR_UNDEFINED) { SetDParam(0, string); } else if (as->num_table > 1) { SetDParam(0, STR_STATION_BUILD_AIRPORT_LAYOUT_NAME); SetDParam(1, _selected_airport_layout + 1); } } break; default: break; } } void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override { switch (widget) { case WID_AP_CLASS_DROPDOWN: { Dimension d = {0, 0}; for (uint i = 0; i < AirportClass::GetClassCount(); i++) { SetDParam(0, AirportClass::Get((AirportClassID)i)->name); d = maxdim(d, GetStringBoundingBox(STR_BLACK_STRING)); } d.width += padding.width; d.height += padding.height; *size = maxdim(*size, d); break; } case WID_AP_AIRPORT_LIST: { for (int i = 0; i < NUM_AIRPORTS; i++) { const AirportSpec *as = AirportSpec::Get(i); if (!as->enabled) continue; size->width = std::max(size->width, GetStringBoundingBox(as->name).width); } this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM; size->height = 5 * this->line_height; break; } case WID_AP_AIRPORT_SPRITE: for (int i = 0; i < NUM_AIRPORTS; i++) { const AirportSpec *as = AirportSpec::Get(i); if (!as->enabled) continue; for (byte layout = 0; layout < as->num_table; layout++) { SpriteID sprite = GetCustomAirportSprite(as, layout); if (sprite != 0) { Dimension d = GetSpriteSize(sprite); d.width += WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; d.height += WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM; *size = maxdim(d, *size); } } } break; case WID_AP_EXTRA_TEXT: for (int i = NEW_AIRPORT_OFFSET; i < NUM_AIRPORTS; i++) { const AirportSpec *as = AirportSpec::Get(i); if (!as->enabled) continue; for (byte layout = 0; layout < as->num_table; layout++) { StringID string = GetAirportTextCallback(as, layout, CBID_AIRPORT_ADDITIONAL_TEXT); if (string == STR_UNDEFINED) continue; /* STR_BLACK_STRING is used to start the string with {BLACK} */ SetDParam(0, string); Dimension d = GetStringMultiLineBoundingBox(STR_BLACK_STRING, *size); *size = maxdim(d, *size); } } break; default: break; } } void DrawWidget(const Rect &r, int widget) const override { switch (widget) { case WID_AP_AIRPORT_LIST: { int y = r.top; AirportClass *apclass = AirportClass::Get(_selected_airport_class); for (uint i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < apclass->GetSpecCount(); i++) { const AirportSpec *as = apclass->GetSpec(i); if (!as->IsAvailable()) { GfxFillRect(r.left + 1, y + 1, r.right - 1, y + this->line_height - 2, PC_BLACK, FILLRECT_CHECKER); } DrawString(r.left + WD_MATRIX_LEFT, r.right - WD_MATRIX_RIGHT, y + WD_MATRIX_TOP, as->name, ((int)i == _selected_airport_index) ? TC_WHITE : TC_BLACK); y += this->line_height; } break; } case WID_AP_AIRPORT_SPRITE: if (this->preview_sprite != 0) { Dimension d = GetSpriteSize(this->preview_sprite); DrawSprite(this->preview_sprite, COMPANY_SPRITE_COLOUR(_local_company), (r.left + r.right - d.width) / 2, (r.top + r.bottom - d.height) / 2); } break; case WID_AP_EXTRA_TEXT: if (_selected_airport_index != -1) { const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index); StringID string = GetAirportTextCallback(as, _selected_airport_layout, CBID_AIRPORT_ADDITIONAL_TEXT); if (string != STR_UNDEFINED) { SetDParam(0, string); DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_BLACK_STRING); } } break; } } void OnPaint() override { this->DrawWidgets(); uint16 top = this->GetWidget(WID_AP_BTN_DOHILIGHT)->pos_y + this->GetWidget(WID_AP_BTN_DOHILIGHT)->current_y + WD_PAR_VSEP_NORMAL; NWidgetBase *panel_nwi = this->GetWidget(WID_AP_BOTTOMPANEL); int right = panel_nwi->pos_x + panel_nwi->current_x; int bottom = panel_nwi->pos_y + panel_nwi->current_y; if (_selected_airport_index != -1) { const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index); int rad = _settings_game.station.modified_catchment ? as->catchment : (uint)CA_UNMODIFIED; /* only show the station (airport) noise, if the noise option is activated */ if (_settings_game.economy.station_noise_level) { /* show the noise of the selected airport */ SetDParam(0, as->noise_level); DrawString(panel_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, STR_STATION_BUILD_NOISE); top += FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL; } /* strings such as 'Size' and 'Coverage Area' */ top = DrawStationCoverageAreaText(panel_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, SCT_ALL, rad, false) + WD_PAR_VSEP_NORMAL; top = DrawStationCoverageAreaText(panel_nwi->pos_x + WD_FRAMERECT_LEFT, right - WD_FRAMERECT_RIGHT, top, SCT_ALL, rad, true) + WD_PAR_VSEP_NORMAL; } /* Resize background if the window is too small. * Never make the window smaller to avoid oscillating if the size change affects the acceptance. * (This is the case, if making the window bigger moves the mouse into the window.) */ if (top > bottom) { ResizeWindow(this, 0, top - bottom, false); } } void SelectOtherAirport(int airport_index) { _selected_airport_index = airport_index; _selected_airport_layout = 0; this->UpdateSelectSize(); this->SetDirty(); } void UpdateSelectSize() { if (_selected_airport_index == -1) { SetTileSelectSize(1, 1); this->DisableWidget(WID_AP_LAYOUT_DECREASE); this->DisableWidget(WID_AP_LAYOUT_INCREASE); } else { const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index); int w = as->size_x; int h = as->size_y; Direction rotation = as->rotation[_selected_airport_layout]; if (rotation == DIR_E || rotation == DIR_W) Swap(w, h); SetTileSelectSize(w, h); this->preview_sprite = GetCustomAirportSprite(as, _selected_airport_layout); this->SetWidgetDisabledState(WID_AP_LAYOUT_DECREASE, _selected_airport_layout == 0); this->SetWidgetDisabledState(WID_AP_LAYOUT_INCREASE, _selected_airport_layout + 1 >= as->num_table); int rad = _settings_game.station.modified_catchment ? as->catchment : (uint)CA_UNMODIFIED; if (_settings_client.gui.station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad); } } void OnClick(Point pt, int widget, int click_count) override { switch (widget) { case WID_AP_CLASS_DROPDOWN: ShowDropDownList(this, BuildAirportClassDropDown(), _selected_airport_class, WID_AP_CLASS_DROPDOWN); break; case WID_AP_AIRPORT_LIST: { int num_clicked = this->vscroll->GetPosition() + (pt.y - this->GetWidget(widget)->pos_y) / this->line_height; if (num_clicked >= this->vscroll->GetCount()) break; const AirportSpec *as = AirportClass::Get(_selected_airport_class)->GetSpec(num_clicked); if (as->IsAvailable()) this->SelectOtherAirport(num_clicked); break; } case WID_AP_BTN_DONTHILIGHT: case WID_AP_BTN_DOHILIGHT: _settings_client.gui.station_show_coverage = (widget != WID_AP_BTN_DONTHILIGHT); this->SetWidgetLoweredState(WID_AP_BTN_DONTHILIGHT, !_settings_client.gui.station_show_coverage); this->SetWidgetLoweredState(WID_AP_BTN_DOHILIGHT, _settings_client.gui.station_show_coverage); this->SetDirty(); if (_settings_client.sound.click_beep) SndPlayFx(SND_15_BEEP); this->UpdateSelectSize(); SetViewportCatchmentStation(nullptr, true); break; case WID_AP_LAYOUT_DECREASE: _selected_airport_layout--; this->UpdateSelectSize(); this->SetDirty(); break; case WID_AP_LAYOUT_INCREASE: _selected_airport_layout++; this->UpdateSelectSize(); this->SetDirty(); break; } } /** * Select the first available airport. * @param change_class If true, change the class if no airport in the current * class is available. */ void SelectFirstAvailableAirport(bool change_class) { /* First try to select an airport in the selected class. */ AirportClass *sel_apclass = AirportClass::Get(_selected_airport_class); for (uint i = 0; i < sel_apclass->GetSpecCount(); i++) { const AirportSpec *as = sel_apclass->GetSpec(i); if (as->IsAvailable()) { this->SelectOtherAirport(i); return; } } if (change_class) { /* If that fails, select the first available airport * from a random class. */ for (AirportClassID j = APC_BEGIN; j < APC_MAX; j++) { AirportClass *apclass = AirportClass::Get(j); for (uint i = 0; i < apclass->GetSpecCount(); i++) { const AirportSpec *as = apclass->GetSpec(i); if (as->IsAvailable()) { _selected_airport_class = j; this->SelectOtherAirport(i); return; } } } } /* If all airports are unavailable, select nothing. */ this->SelectOtherAirport(-1); } void OnDropdownSelect(int widget, int index) override { assert(widget == WID_AP_CLASS_DROPDOWN); _selected_airport_class = (AirportClassID)index; this->vscroll->SetCount(AirportClass::Get(_selected_airport_class)->GetSpecCount()); this->SelectFirstAvailableAirport(false); } void OnRealtimeTick(uint delta_ms) override { CheckRedrawStationCoverage(this); } }; static const NWidgetPart _nested_build_airport_widgets[] = { NWidget(NWID_HORIZONTAL), NWidget(WWT_CLOSEBOX, COLOUR_DARK_GREEN), NWidget(WWT_CAPTION, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_AIRPORT_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), SetFill(1, 0), SetPIP(2, 0, 2), NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_AIRPORT_CLASS_LABEL, STR_NULL), SetFill(1, 0), NWidget(WWT_DROPDOWN, COLOUR_GREY, WID_AP_CLASS_DROPDOWN), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_STATION_BUILD_AIRPORT_TOOLTIP), NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_AP_AIRPORT_SPRITE), SetFill(1, 0), NWidget(NWID_HORIZONTAL), NWidget(WWT_MATRIX, COLOUR_GREY, WID_AP_AIRPORT_LIST), SetFill(1, 0), SetMatrixDataTip(1, 5, STR_STATION_BUILD_AIRPORT_TOOLTIP), SetScrollbar(WID_AP_SCROLLBAR), NWidget(NWID_VSCROLLBAR, COLOUR_GREY, WID_AP_SCROLLBAR), EndContainer(), NWidget(NWID_HORIZONTAL), NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_AP_LAYOUT_DECREASE), SetMinimalSize(12, 0), SetDataTip(AWV_DECREASE, STR_NULL), NWidget(WWT_LABEL, COLOUR_GREY, WID_AP_LAYOUT_NUM), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_BLACK_STRING, STR_NULL), NWidget(WWT_PUSHARROWBTN, COLOUR_GREY, WID_AP_LAYOUT_INCREASE), SetMinimalSize(12, 0), SetDataTip(AWV_INCREASE, STR_NULL), EndContainer(), NWidget(WWT_EMPTY, COLOUR_DARK_GREEN, WID_AP_EXTRA_TEXT), SetFill(1, 0), SetMinimalSize(150, 0), EndContainer(), /* Bottom panel. */ NWidget(WWT_PANEL, COLOUR_DARK_GREEN, WID_AP_BOTTOMPANEL), SetPIP(2, 2, 2), NWidget(WWT_LABEL, COLOUR_DARK_GREEN), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), SetFill(1, 0), NWidget(NWID_HORIZONTAL), NWidget(NWID_SPACER), SetMinimalSize(14, 0), SetFill(1, 0), NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_AP_BTN_DONTHILIGHT), SetMinimalSize(60, 12), SetFill(1, 0), SetDataTip(STR_STATION_BUILD_COVERAGE_OFF, STR_STATION_BUILD_COVERAGE_AREA_OFF_TOOLTIP), NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_AP_BTN_DOHILIGHT), SetMinimalSize(60, 12), SetFill(1, 0), SetDataTip(STR_STATION_BUILD_COVERAGE_ON, STR_STATION_BUILD_COVERAGE_AREA_ON_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(14, 0), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 10), SetResize(0, 1), SetFill(1, 0), EndContainer(), }; static WindowDesc _build_airport_desc( WDP_AUTO, "build_station_air", 0, 0, WC_BUILD_STATION, WC_BUILD_TOOLBAR, WDF_CONSTRUCTION, _nested_build_airport_widgets, lengthof(_nested_build_airport_widgets) ); static void ShowBuildAirportPicker(Window *parent) { new BuildAirportWindow(&_build_airport_desc, parent); } void InitializeAirportGui() { _selected_airport_class = APC_BEGIN; _selected_airport_index = -1; }