From 3993fc7d3545f661f6ad6c3f1efc3a1cb17ac16a Mon Sep 17 00:00:00 2001 From: James Turner Date: Mon, 13 Jul 2020 14:28:53 +0100 Subject: [PATCH] Launcher: fix helipad selection Helipads were not being shown for convention airports, only for heliports. Fix this up so helipads work alongside runways at conventional airports, when the selected aircraft is a helicopter. --- src/GUI/LocationController.cxx | 64 ++++++++++++++--------- src/GUI/LocationController.hxx | 2 + src/GUI/QmlPositioned.cxx | 2 + src/GUI/qml/LocationAirportView.qml | 78 +++++++++++++++++++++++++---- 4 files changed, 112 insertions(+), 34 deletions(-) diff --git a/src/GUI/LocationController.cxx b/src/GUI/LocationController.cxx index 4d3b9ae00..ccb95aa1b 100644 --- a/src/GUI/LocationController.cxx +++ b/src/GUI/LocationController.cxx @@ -258,6 +258,7 @@ void LocationController::setBaseLocation(QmlPositioned* pos) // disable offset when selecting a heliport if (m_airportLocation->isHeliport()) { m_onFinal = false; + m_useActiveRunway = false; } } else { m_airportLocation.clear(); @@ -325,20 +326,25 @@ QObjectList LocationController::airportRunways() const return {}; QObjectList result; - if (m_airportLocation->isHeliport()) { - // helipads - for (unsigned int r=0; rnumHelipads(); ++r) { - auto p = new QmlPositioned(m_airportLocation->getHelipadByIndex(r).ptr()); - QQmlEngine::setObjectOwnership(p, QQmlEngine::JavaScriptOwnership); - result.push_back(p); - } - } else { - // regular runways - for (unsigned int r=0; rnumRunways(); ++r) { - auto p = new QmlPositioned(m_airportLocation->getRunwayByIndex(r).ptr()); - QQmlEngine::setObjectOwnership(p, QQmlEngine::JavaScriptOwnership); - result.push_back(p); - } + for (unsigned int r = 0; r < m_airportLocation->numRunways(); ++r) { + auto p = new QmlPositioned(m_airportLocation->getRunwayByIndex(r).ptr()); + QQmlEngine::setObjectOwnership(p, QQmlEngine::JavaScriptOwnership); + result.push_back(p); + } + + return result; +} + +QObjectList LocationController::airportHelipads() const +{ + if (!m_airportLocation) + return {}; + + QObjectList result; + for (unsigned int r = 0; r < m_airportLocation->numHelipads(); ++r) { + auto p = new QmlPositioned(m_airportLocation->getHelipadByIndex(r).ptr()); + QQmlEngine::setObjectOwnership(p, QQmlEngine::JavaScriptOwnership); + result.push_back(p); } return result; @@ -564,12 +570,18 @@ void LocationController::restoreLocation(QVariantMap l) if (l.contains("location-apt-runway")) { QString runway = l.value("location-apt-runway").toString().toUpper(); + const auto runwayStr = runway.toStdString(); if (runway == QStringLiteral("ACTIVE")) { m_useActiveRunway = true; } else if (m_airportLocation->isHeliport()) { - m_detailLocation = m_airportLocation->getHelipadByIdent(runway.toStdString()); + m_detailLocation = m_airportLocation->getHelipadByIdent(runwayStr); } else { - m_detailLocation = m_airportLocation->getRunwayByIdent(runway.toStdString()); + // could be a helipad at a regular airport + if (m_airportLocation->hasHelipadWithIdent(runwayStr)) { + m_detailLocation = m_airportLocation->getHelipadByIdent(runwayStr); + } else { + m_detailLocation = m_airportLocation->getRunwayByIdent(runwayStr); + } } } else if (l.contains("location-apt-parking")) { QString parking = l.value("location-apt-parking").toString(); @@ -646,7 +658,7 @@ QVariantMap LocationController::saveLocation() const locationSet.insert("location-apt-parking", "AVAILABLE"); } else if (m_detailLocation) { const auto detailType = m_detailLocation->type(); - if (detailType == FGPositioned::RUNWAY) { + if ((detailType == FGPositioned::RUNWAY) || (detailType == FGPositioned::HELIPAD)) { locationSet.insert("location-apt-runway", QString::fromStdString(m_detailLocation->ident())); } else if (detailType == FGPositioned::PARKING) { locationSet.insert("location-apt-parking", QString::fromStdString(m_detailLocation->ident())); @@ -755,7 +767,7 @@ void LocationController::setLocationProperties() fgSetString("/sim/presets/parkpos", "AVAILABLE"); } else if (onRunway) { if (m_airportLocation->type() == FGPositioned::AIRPORT) { - // explicit runway choice + // explicit runway choice (this also works for helipads) fgSetString("/sim/presets/runway", m_detailLocation->ident() ); fgSetBool("/sim/presets/runway-requested", true ); @@ -948,8 +960,9 @@ void LocationController::onCollectConfig() if (m_airportLocation) { m_config->setArg("airport", QString::fromStdString(m_airportLocation->ident())); - const bool onRunway = (m_detailLocation && (m_detailLocation->type() == FGPositioned::RUNWAY)); - const bool atParking = (m_detailLocation && (m_detailLocation->type() == FGPositioned::PARKING)); + const auto ty = m_detailLocation ? m_detailLocation->type() : FGPositioned::INVALID; + const bool onRunway = (ty == FGPositioned::RUNWAY) || (ty == FGPositioned::HELIPAD); + const bool atParking = ty == FGPositioned::PARKING; if (m_useActiveRunway) { // pick by default @@ -1082,8 +1095,11 @@ QString LocationController::description() const name = fixNavaidName(name); if (m_airportLocation) { - const bool onRunway = (m_detailLocation && (m_detailLocation->type() == FGPositioned::RUNWAY)); - const bool atParking = (m_detailLocation && (m_detailLocation->type() == FGPositioned::PARKING)); + const auto ty = m_detailLocation ? m_detailLocation->type() : FGPositioned::INVALID; + const bool onRunway = ty == FGPositioned::RUNWAY; + const bool onPad = ty == FGPositioned::HELIPAD; + const bool atParking = ty == FGPositioned::PARKING; + QString locationOnAirport; if (m_useActiveRunway) { @@ -1094,7 +1110,7 @@ QString LocationController::description() const } } else if (m_useAvailableParking) { locationOnAirport = tr("at an available parking position"); - } if (onRunway) { + } else if (onRunway) { QString runwayName = QString("runway %1").arg(QString::fromStdString(m_detailLocation->ident())); if (m_onFinal) { @@ -1102,6 +1118,8 @@ QString LocationController::description() const } else { locationOnAirport = tr("on %1").arg(runwayName); } + } else if (onPad) { + locationOnAirport = tr("on pad %1").arg(QString::fromStdString(m_detailLocation->ident())); } else if (atParking) { locationOnAirport = tr("at parking position %1").arg(QString::fromStdString(m_detailLocation->ident())); } diff --git a/src/GUI/LocationController.hxx b/src/GUI/LocationController.hxx index 81737aaa8..08337c82b 100644 --- a/src/GUI/LocationController.hxx +++ b/src/GUI/LocationController.hxx @@ -45,6 +45,7 @@ class LocationController : public QObject Q_PROPERTY(QList airportRunways READ airportRunways NOTIFY baseLocationChanged) Q_PROPERTY(QList airportParkings READ airportParkings NOTIFY baseLocationChanged) + Q_PROPERTY(QList airportHelipads READ airportHelipads NOTIFY baseLocationChanged) Q_PROPERTY(bool offsetEnabled READ offsetEnabled WRITE setOffsetEnabled NOTIFY offsetChanged) Q_PROPERTY(QuantityValue offsetRadial READ offsetRadial WRITE setOffsetRadial NOTIFY offsetChanged) @@ -145,6 +146,7 @@ public: Q_INVOKABLE void addToRecent(QmlPositioned* pos); QObjectList airportRunways() const; + QObjectList airportHelipads() const; QObjectList airportParkings() const; Q_INVOKABLE void showHistoryInSearchModel(); diff --git a/src/GUI/QmlPositioned.cxx b/src/GUI/QmlPositioned.cxx index ac3770aa3..b717558f3 100644 --- a/src/GUI/QmlPositioned.cxx +++ b/src/GUI/QmlPositioned.cxx @@ -166,6 +166,8 @@ void QmlPositioned::setInner(FGPositionedRef p) } else { m_pos = p; } + + emit infoChanged(); } FGPositionedRef QmlPositioned::inner() const diff --git a/src/GUI/qml/LocationAirportView.qml b/src/GUI/qml/LocationAirportView.qml index 0fb5b80f3..152662fd6 100644 --- a/src/GUI/qml/LocationAirportView.qml +++ b/src/GUI/qml/LocationAirportView.qml @@ -24,7 +24,12 @@ Item { if (pos === null) return; - console.info("Saw airport click on:" + pos.ident) + // only allow selction of helipads if the aircraft type in + // use is a helicopter. + if ((pos.type == Positioned.Helipad) && (_launcher.aircraftType != LauncherController.Helicopter)) { + return; + } + _location.setDetailLocation(pos) diagram.selection = pos syncUIFromController(); @@ -40,10 +45,13 @@ Item { if (_location.useAvailableParking || (_location.detail.type === Positioned.Parking)) { parkingRadio.select() parkingChoice.syncCurrentIndex(); + } else if (_location.detail.type === Positioned.Helipad) { + helipadRadio.select(); + helipadChoice.syncCurrentIndex(); } else { runwayRadio.select(); runwayChoice.syncCurrentIndex(); - } + } } RadioButtonGroup { @@ -101,6 +109,7 @@ Item { Row { width: parent.width spacing: Style.margin + visible: !root.isHeliport RadioButton { id: runwayRadio @@ -113,7 +122,7 @@ Item { } StyledText { - text: isHeliport ? qsTr("Pad") : qsTr("Runway") + text: qsTr("Runway") anchors.verticalCenter: parent.verticalCenter } @@ -165,15 +174,13 @@ Item { ToggleBox { id: onFinalBox + visible: !root.isHeliport anchors.left: parent.left anchors.leftMargin: Style.strutSize height: onFinalContents.height + onFinalContents.y + Style.margin anchors.right: parent.right anchors.rightMargin: Style.margin - // no offset for helipads - visible: !isHeliport - enabled: runwayRadio.selected selected: _location.onFinal @@ -241,10 +248,8 @@ Item { ToggleSwitch { x: Style.strutSize - // no localizer for helipads - visible: !isHeliport enabled:runwayRadio.selected - + visible: !root.isHeliport // enable if selected runway has ILS label: qsTr("Tune navigation radio (NAV1) to runway localizer") checked: _location.tuneNAV1 @@ -254,6 +259,59 @@ Item { } } + // helipads row + Row { + width: parent.width + spacing: Style.margin + visible: (_launcher.aircraftType === LauncherController.Helicopter) && ( _location.airportHelipads.length > 0) + + RadioButton { + id: helipadRadio + anchors.verticalCenter: parent.verticalCenter + group: radioGroup + + onClicked: { + if (selected) helipadChoice.setLocation(); + } + } + + StyledText { + text: qsTr("Pad") + anchors.verticalCenter: parent.verticalCenter + } + + PopupChoice { + id: helipadChoice + model: _location.airportHelipads + displayRole: "ident" + width: parent.width * 0.5 + anchors.verticalCenter: parent.verticalCenter + enabled: helipadRadio.selected + + onCurrentIndexChanged: { + setLocation(); + } + + function setLocation() + { + _location.setDetailLocation(_location.airportHelipads[currentIndex]) + diagram.selection = _location.airportHelipads[currentIndex] + } + + function syncCurrentIndex() + { + for (var i=0; i < _location.airportHelipads.length; ++i) { + if (_location.airportHelipads[i].equals(_location.detail)) { + currentIndex = i; + return; + } + } + + currentIndex = 0; + } + } + } + // parking row Row { width: parent.width @@ -293,14 +351,12 @@ Item { function syncCurrentIndex() { if (_location.useAvailableParking) { - console.info("Parking: controller says use available") currentIndex = -1; return; } for (var i=0; i < _location.airportParkings.length; ++i) { if (_location.airportParkings[i].equals(_location.detail)) { - console.info("Found explicit parking " + _location.detail.ident + " at index " + i); currentIndex = i; return; }