Flight planning in the launcher
Still evolving but usable to import or build a route now
This commit is contained in:
parent
331939f640
commit
df7e13d734
13 changed files with 1396 additions and 8 deletions
|
@ -157,10 +157,14 @@ if (HAVE_QT)
|
||||||
UnitsModel.hxx
|
UnitsModel.hxx
|
||||||
NavaidSearchModel.hxx
|
NavaidSearchModel.hxx
|
||||||
NavaidSearchModel.cxx
|
NavaidSearchModel.cxx
|
||||||
|
FlightPlanController.cxx
|
||||||
|
FlightPlanController.hxx
|
||||||
|
RouteDiagram.cxx
|
||||||
|
RouteDiagram.hxx
|
||||||
)
|
)
|
||||||
|
|
||||||
set_property(TARGET fgqmlui PROPERTY AUTOMOC ON)
|
set_property(TARGET fgqmlui PROPERTY AUTOMOC ON)
|
||||||
target_link_libraries(fgqmlui Qt5::Quick Qt5::Network Qt5::Qml SimGearCore)
|
target_link_libraries(fgqmlui Qt5::Quick Qt5::Widgets Qt5::Network Qt5::Qml SimGearCore)
|
||||||
target_include_directories(fgqmlui PRIVATE ${PROJECT_BINARY_DIR}/src/GUI)
|
target_include_directories(fgqmlui PRIVATE ${PROJECT_BINARY_DIR}/src/GUI)
|
||||||
add_dependencies(fgqmlui fgfs_qm_files)
|
add_dependencies(fgqmlui fgfs_qm_files)
|
||||||
|
|
||||||
|
|
552
src/GUI/FlightPlanController.cxx
Normal file
552
src/GUI/FlightPlanController.cxx
Normal file
|
@ -0,0 +1,552 @@
|
||||||
|
#include "FlightPlanController.hxx"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QAbstractListModel>
|
||||||
|
#include <QQmlEngine>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include <simgear/misc/sg_path.hxx>
|
||||||
|
|
||||||
|
#include <Main/globals.hxx>
|
||||||
|
#include <Navaids/waypoint.hxx>
|
||||||
|
#include <Navaids/airways.hxx>
|
||||||
|
#include <Navaids/navrecord.hxx>
|
||||||
|
#include <Navaids/airways.hxx>
|
||||||
|
|
||||||
|
#include "QmlPositioned.hxx"
|
||||||
|
#include "LaunchConfig.hxx"
|
||||||
|
|
||||||
|
using namespace flightgear;
|
||||||
|
|
||||||
|
const int LegDistanceRole = Qt::UserRole;
|
||||||
|
const int LegTrackRole = Qt::UserRole + 1;
|
||||||
|
const int LegTerminatorNavRole = Qt::UserRole + 2;
|
||||||
|
const int LegAirwayIdentRole = Qt::UserRole + 3;
|
||||||
|
const int LegTerminatorTypeRole = Qt::UserRole + 4;
|
||||||
|
const int LegTerminatorNavNameRole = Qt::UserRole + 5;
|
||||||
|
const int LegTerminatorNavFrequencyRole = Qt::UserRole + 6;
|
||||||
|
|
||||||
|
class LegsModel : public QAbstractListModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
void setFlightPlan(flightgear::FlightPlanRef f)
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
_fp = f;
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
int rowCount(const QModelIndex &parent) const override
|
||||||
|
{
|
||||||
|
Q_UNUSED(parent)
|
||||||
|
return _fp->numLegs();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant data(const QModelIndex &index, int role) const override
|
||||||
|
{
|
||||||
|
const auto leg = _fp->legAtIndex(index.row());
|
||||||
|
if (!leg)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
switch (role) {
|
||||||
|
case Qt::DisplayRole:
|
||||||
|
return QString::fromStdString(leg->waypoint()->ident());
|
||||||
|
case LegDistanceRole:
|
||||||
|
return QVariant::fromValue(QuantityValue{Units::NauticalMiles, leg->distanceNm()});
|
||||||
|
case LegTrackRole:
|
||||||
|
return QVariant::fromValue(QuantityValue{Units::DegreesTrue, leg->courseDeg()});
|
||||||
|
|
||||||
|
case LegAirwayIdentRole:
|
||||||
|
{
|
||||||
|
const auto wp = leg->waypoint();
|
||||||
|
if (wp->type() == "via") {
|
||||||
|
auto via = static_cast<flightgear::Via*>(leg->waypoint());
|
||||||
|
return QString::fromStdString(via->airway());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wp->flag(WPT_VIA)) {
|
||||||
|
AirwayRef awy = static_cast<Airway*>(wp->owner());
|
||||||
|
return QString::fromStdString(awy->ident());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case LegTerminatorNavRole:
|
||||||
|
{
|
||||||
|
if (leg->waypoint()->source()) {
|
||||||
|
return QString::fromStdString(leg->waypoint()->source()->ident());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case LegTerminatorNavFrequencyRole:
|
||||||
|
{
|
||||||
|
const auto n = fgpositioned_cast<FGNavRecord>(leg->waypoint()->source());
|
||||||
|
if (n) {
|
||||||
|
const double f = n->get_freq() / 100.0;
|
||||||
|
if (n->type() == FGPositioned::NDB) {
|
||||||
|
return QVariant::fromValue(QuantityValue(Units::FreqKHz, f));
|
||||||
|
}
|
||||||
|
|
||||||
|
return QVariant::fromValue(QuantityValue(Units::FreqMHz, f));
|
||||||
|
}
|
||||||
|
return QVariant::fromValue(QuantityValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
case LegTerminatorNavNameRole:
|
||||||
|
{
|
||||||
|
if (leg->waypoint()->source()) {
|
||||||
|
return QString::fromStdString(leg->waypoint()->source()->name());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case LegTerminatorTypeRole:
|
||||||
|
return QString::fromStdString(leg->waypoint()->type());
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void waypointsChanged()
|
||||||
|
{
|
||||||
|
beginResetModel();
|
||||||
|
endResetModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<int, QByteArray> roleNames() const override
|
||||||
|
{
|
||||||
|
QHash<int, QByteArray> result = QAbstractListModel::roleNames();
|
||||||
|
|
||||||
|
result[Qt::DisplayRole] = "label";
|
||||||
|
result[LegDistanceRole] = "distance";
|
||||||
|
result[LegTrackRole] = "track";
|
||||||
|
result[LegTerminatorNavRole] = "to";
|
||||||
|
result[LegTerminatorNavFrequencyRole] = "frequency";
|
||||||
|
result[LegAirwayIdentRole] = "via";
|
||||||
|
result[LegTerminatorTypeRole] = "wpType";
|
||||||
|
result[LegTerminatorNavNameRole] = "toName";
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
flightgear::FlightPlanRef _fp;
|
||||||
|
};
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class FPDelegate : public FlightPlan::Delegate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void arrivalChanged() override
|
||||||
|
{
|
||||||
|
p->infoChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void departureChanged() override
|
||||||
|
{
|
||||||
|
p->infoChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cruiseChanged() override
|
||||||
|
{
|
||||||
|
p->infoChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void waypointsChanged() override
|
||||||
|
{
|
||||||
|
QTimer::singleShot(0, p->_legs, &LegsModel::waypointsChanged);
|
||||||
|
p->waypointsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
FlightPlanController* p;
|
||||||
|
};
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
FlightPlanController::FlightPlanController(QObject *parent, LaunchConfig* config)
|
||||||
|
: QObject(parent)
|
||||||
|
{
|
||||||
|
_config = config;
|
||||||
|
connect(_config, &LaunchConfig::collect, this, &FlightPlanController::onCollectConfig);
|
||||||
|
connect(_config, &LaunchConfig::save, this, &FlightPlanController::onSave);
|
||||||
|
connect(_config, &LaunchConfig::restore, this, &FlightPlanController::onRestore);
|
||||||
|
|
||||||
|
_delegate.reset(new FPDelegate);
|
||||||
|
_delegate->p = this; // link back to us
|
||||||
|
|
||||||
|
qmlRegisterUncreatableType<LegsModel>("FlightGear", 1, 0, "LegsModel", "singleton");
|
||||||
|
_fp.reset(new flightgear::FlightPlan);
|
||||||
|
_fp->addDelegate(_delegate.get());
|
||||||
|
_legs = new LegsModel();
|
||||||
|
_legs->setFlightPlan(_fp);
|
||||||
|
|
||||||
|
// initial restore
|
||||||
|
onRestore();
|
||||||
|
}
|
||||||
|
|
||||||
|
FlightPlanController::~FlightPlanController()
|
||||||
|
{
|
||||||
|
_fp->removeDelegate(_delegate.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlightPlanController::clearPlan()
|
||||||
|
{
|
||||||
|
auto fp = new flightgear::FlightPlan;
|
||||||
|
_fp->removeDelegate(_delegate.get());
|
||||||
|
_fp = fp;
|
||||||
|
_fp->addDelegate(_delegate.get());
|
||||||
|
_legs->setFlightPlan(fp);
|
||||||
|
emit infoChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FlightPlanController::loadFromPath(QString path)
|
||||||
|
{
|
||||||
|
auto fp = new flightgear::FlightPlan;
|
||||||
|
bool ok = fp->load(SGPath(path.toUtf8().data()));
|
||||||
|
if (!ok) {
|
||||||
|
qWarning() << "Failed to load flightplan " << path;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_fp->removeDelegate(_delegate.get());
|
||||||
|
_fp = fp;
|
||||||
|
_fp->addDelegate(_delegate.get());
|
||||||
|
_legs->setFlightPlan(fp);
|
||||||
|
|
||||||
|
// notify that everything changed
|
||||||
|
emit infoChanged();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FlightPlanController::saveToPath(QString path) const
|
||||||
|
{
|
||||||
|
SGPath p(path.toUtf8().data());
|
||||||
|
return _fp->save(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlightPlanController::onCollectConfig()
|
||||||
|
{
|
||||||
|
SGPath p = globals->get_fg_home() / "launcher.fgfp";
|
||||||
|
_fp->save(p);
|
||||||
|
|
||||||
|
_config->setArg("flight-plan", p.utf8Str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlightPlanController::onSave()
|
||||||
|
{
|
||||||
|
std::ostringstream ss;
|
||||||
|
_fp->save(ss);
|
||||||
|
_config->setValueForKey("", "fp", QString::fromStdString(ss.str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlightPlanController::onRestore()
|
||||||
|
{
|
||||||
|
std::string planXML = _config->getValueForKey("", "fp", QString()).toString().toStdString();
|
||||||
|
if (!planXML.empty()) {
|
||||||
|
std::istringstream ss(planXML);
|
||||||
|
_fp->load(ss);
|
||||||
|
emit infoChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QuantityValue FlightPlanController::cruiseAltitude() const
|
||||||
|
{
|
||||||
|
if (_fp->cruiseFlightLevel() > 0)
|
||||||
|
return {Units::FlightLevel, _fp->cruiseFlightLevel()};
|
||||||
|
|
||||||
|
return {Units::FeetMSL, _fp->cruiseAltitudeFt()};
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlightPlanController::setCruiseAltitude(QuantityValue alt)
|
||||||
|
{
|
||||||
|
const int ival = static_cast<int>(alt.value);
|
||||||
|
if (alt.unit == Units::FlightLevel) {
|
||||||
|
if (_fp->cruiseFlightLevel() == ival) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_fp->setCruiseFlightLevel(ival);
|
||||||
|
} else if (alt.unit == Units::FeetMSL) {
|
||||||
|
if (_fp->cruiseAltitudeFt() == ival) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_fp->setCruiseAltitudeFt(ival);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit infoChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
QmlPositioned *FlightPlanController::departure() const
|
||||||
|
{
|
||||||
|
if (!_fp->departureAirport())
|
||||||
|
return new QmlPositioned;
|
||||||
|
|
||||||
|
return new QmlPositioned(_fp->departureAirport());
|
||||||
|
}
|
||||||
|
|
||||||
|
QmlPositioned *FlightPlanController::destination() const
|
||||||
|
{
|
||||||
|
if (!_fp->destinationAirport())
|
||||||
|
return new QmlPositioned;
|
||||||
|
|
||||||
|
return new QmlPositioned(_fp->destinationAirport());
|
||||||
|
}
|
||||||
|
|
||||||
|
QmlPositioned *FlightPlanController::alternate() const
|
||||||
|
{
|
||||||
|
if (!_fp->alternate())
|
||||||
|
return new QmlPositioned;
|
||||||
|
|
||||||
|
return new QmlPositioned(_fp->alternate());
|
||||||
|
}
|
||||||
|
|
||||||
|
QuantityValue FlightPlanController::cruiseSpeed() const
|
||||||
|
{
|
||||||
|
if (_fp->cruiseSpeedMach() > 0.0) {
|
||||||
|
return {Units::Mach, _fp->cruiseSpeedMach()};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {Units::Knots, _fp->cruiseSpeedKnots()};
|
||||||
|
}
|
||||||
|
|
||||||
|
FlightPlanController::FlightRules FlightPlanController::flightRules() const
|
||||||
|
{
|
||||||
|
return static_cast<FlightRules>(_fp->flightRules());
|
||||||
|
}
|
||||||
|
|
||||||
|
FlightPlanController::FlightType FlightPlanController::flightType() const
|
||||||
|
{
|
||||||
|
return static_cast<FlightType>(_fp->flightType());
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlightPlanController::setFlightRules(FlightRules r)
|
||||||
|
{
|
||||||
|
_fp->setFlightRules(static_cast<flightgear::ICAOFlightRules>(r));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlightPlanController::setFlightType(FlightType ty)
|
||||||
|
{
|
||||||
|
_fp->setFlightType(static_cast<flightgear::ICAOFlightType>(ty));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString FlightPlanController::callsign() const
|
||||||
|
{
|
||||||
|
return QString::fromStdString(_fp->callsign());
|
||||||
|
}
|
||||||
|
|
||||||
|
QString FlightPlanController::remarks() const
|
||||||
|
{
|
||||||
|
return QString::fromStdString(_fp->remarks());
|
||||||
|
}
|
||||||
|
|
||||||
|
QString FlightPlanController::aircraftType() const
|
||||||
|
{
|
||||||
|
return QString::fromStdString(_fp->icaoAircraftType());
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlightPlanController::setCallsign(QString s)
|
||||||
|
{
|
||||||
|
const auto stdS = s.toStdString();
|
||||||
|
if (_fp->callsign() == stdS)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_fp->setCallsign(stdS);
|
||||||
|
emit infoChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlightPlanController::setRemarks(QString r)
|
||||||
|
{
|
||||||
|
const auto stdR = r.toStdString();
|
||||||
|
if (_fp->remarks() == stdR)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_fp->setRemarks(stdR);
|
||||||
|
emit infoChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlightPlanController::setAircraftType(QString ty)
|
||||||
|
{
|
||||||
|
const auto stdT = ty.toStdString();
|
||||||
|
if (_fp->icaoAircraftType() == stdT)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_fp->setIcaoAircraftType(stdT);
|
||||||
|
emit infoChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
int FlightPlanController::estimatedDurationMinutes() const
|
||||||
|
{
|
||||||
|
return _fp->estimatedDurationMinutes();
|
||||||
|
}
|
||||||
|
|
||||||
|
QuantityValue FlightPlanController::totalDistanceNm() const
|
||||||
|
{
|
||||||
|
return QuantityValue{Units::NauticalMiles, _fp->totalDistanceNm()};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FlightPlanController::tryParseRoute(QString routeDesc)
|
||||||
|
{
|
||||||
|
bool ok = _fp->parseICAORouteString(routeDesc.toStdString());
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FlightPlanController::tryGenerateRoute()
|
||||||
|
{
|
||||||
|
if (!_fp->departureAirport() || !_fp->destinationAirport()) {
|
||||||
|
qWarning() << "departure or destination not set";
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto net = Airway::highLevel();
|
||||||
|
auto fromNode = net->findClosestNode(_fp->departureAirport()->geod());
|
||||||
|
auto toNode = net->findClosestNode(_fp->destinationAirport()->geod());
|
||||||
|
if (!fromNode.first) {
|
||||||
|
qWarning() << "Couldn't find airway network transition for "
|
||||||
|
<< QString::fromStdString(_fp->departureAirport()->ident());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!toNode.first) {
|
||||||
|
qWarning() << "Couldn't find airway network transition for "
|
||||||
|
<< QString::fromStdString(_fp->destinationAirport()->ident());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
WayptRef fromWp = new NavaidWaypoint(fromNode.first, _fp);
|
||||||
|
WayptRef toWp = new NavaidWaypoint(toNode.first, _fp);
|
||||||
|
WayptVec path;
|
||||||
|
bool ok = net->route(fromWp, toWp, path);
|
||||||
|
if (!ok) {
|
||||||
|
qWarning() << "unable to find a route";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_fp->clear();
|
||||||
|
_fp->insertWayptAtIndex(fromWp, -1);
|
||||||
|
_fp->insertWayptsAtIndex(path, -1);
|
||||||
|
_fp->insertWayptAtIndex(toWp, -1);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlightPlanController::clearRoute()
|
||||||
|
{
|
||||||
|
_fp->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString FlightPlanController::icaoRoute() const
|
||||||
|
{
|
||||||
|
return QString::fromStdString(_fp->asICAORouteString());
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlightPlanController::setEstimatedDurationMinutes(int mins)
|
||||||
|
{
|
||||||
|
if (_fp->estimatedDurationMinutes() == mins)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_fp->setEstimatedDurationMinutes(mins);
|
||||||
|
emit infoChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlightPlanController::computeDuration()
|
||||||
|
{
|
||||||
|
_fp->computeDurationMinutes();
|
||||||
|
emit infoChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FlightPlanController::loadPlan()
|
||||||
|
{
|
||||||
|
QString file = QFileDialog::getOpenFileName(nullptr, tr("Load a flight-plan"),
|
||||||
|
{}, "*.fgfp");
|
||||||
|
if (file.isEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return loadFromPath(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlightPlanController::savePlan()
|
||||||
|
{
|
||||||
|
QString file = QFileDialog::getSaveFileName(nullptr, tr("Save flight-plan"),
|
||||||
|
{}, "*.fgfp");
|
||||||
|
if (file.isEmpty())
|
||||||
|
return;
|
||||||
|
if (!file.endsWith(".fgfp")) {
|
||||||
|
file += ".fgfp";
|
||||||
|
}
|
||||||
|
|
||||||
|
saveToPath(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlightPlanController::setDeparture(QmlPositioned *apt)
|
||||||
|
{
|
||||||
|
if (!apt) {
|
||||||
|
_fp->clearDeparture();
|
||||||
|
} else {
|
||||||
|
if (apt->inner() == _fp->departureAirport())
|
||||||
|
return;
|
||||||
|
|
||||||
|
_fp->setDeparture(fgpositioned_cast<FGAirport>(apt->inner()));
|
||||||
|
}
|
||||||
|
|
||||||
|
emit infoChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlightPlanController::setDestination(QmlPositioned *apt)
|
||||||
|
{
|
||||||
|
if (apt) {
|
||||||
|
if (apt->inner() == _fp->destinationAirport())
|
||||||
|
return;
|
||||||
|
|
||||||
|
_fp->setDestination(fgpositioned_cast<FGAirport>(apt->inner()));
|
||||||
|
} else {
|
||||||
|
_fp->clearDestination();
|
||||||
|
|
||||||
|
}
|
||||||
|
emit infoChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlightPlanController::setAlternate(QmlPositioned *apt)
|
||||||
|
{
|
||||||
|
if (apt) {
|
||||||
|
if (apt->inner() == _fp->alternate())
|
||||||
|
return;
|
||||||
|
|
||||||
|
_fp->setAlternate(fgpositioned_cast<FGAirport>(apt->inner()));
|
||||||
|
} else {
|
||||||
|
_fp->setAlternate(nullptr);
|
||||||
|
|
||||||
|
}
|
||||||
|
emit infoChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FlightPlanController::setCruiseSpeed(QuantityValue speed)
|
||||||
|
{
|
||||||
|
qInfo() << Q_FUNC_INFO << speed.unit << speed.value;
|
||||||
|
if (speed.unit == Units::Mach) {
|
||||||
|
if (speed == QuantityValue(Units::Mach, _fp->cruiseSpeedMach())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_fp->setCruiseSpeedMach(speed.value);
|
||||||
|
} else if (speed.unit == Units::Knots) {
|
||||||
|
const int knotsVal = static_cast<int>(speed.value);
|
||||||
|
if (_fp->cruiseSpeedKnots() == knotsVal) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_fp->setCruiseSpeedKnots(knotsVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit infoChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "FlightPlanController.moc"
|
148
src/GUI/FlightPlanController.hxx
Normal file
148
src/GUI/FlightPlanController.hxx
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
#ifndef FLIGHTPLANCONTROLLER_HXX
|
||||||
|
#define FLIGHTPLANCONTROLLER_HXX
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
#include <Navaids/FlightPlan.hxx>
|
||||||
|
|
||||||
|
#include "UnitsModel.hxx"
|
||||||
|
|
||||||
|
class QmlPositioned;
|
||||||
|
class LegsModel;
|
||||||
|
class FPDelegate;
|
||||||
|
class LaunchConfig;
|
||||||
|
|
||||||
|
class FlightPlanController : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PROPERTY(QString callsign READ callsign WRITE setCallsign NOTIFY infoChanged)
|
||||||
|
Q_PROPERTY(QString remarks READ remarks WRITE setRemarks NOTIFY infoChanged)
|
||||||
|
Q_PROPERTY(QString aircraftType READ aircraftType WRITE setAircraftType NOTIFY infoChanged)
|
||||||
|
|
||||||
|
Q_PROPERTY(LegsModel* legs READ legs CONSTANT)
|
||||||
|
|
||||||
|
Q_PROPERTY(QString icaoRoute READ icaoRoute NOTIFY waypointsChanged)
|
||||||
|
|
||||||
|
Q_ENUMS(FlightRules)
|
||||||
|
Q_ENUMS(FlightType)
|
||||||
|
|
||||||
|
Q_PROPERTY(FlightRules flightRules READ flightRules WRITE setFlightRules NOTIFY infoChanged)
|
||||||
|
Q_PROPERTY(FlightType flightType READ flightType WRITE setFlightType NOTIFY infoChanged)
|
||||||
|
|
||||||
|
// planned departure date + time
|
||||||
|
|
||||||
|
Q_PROPERTY(QuantityValue totalDistanceNm READ totalDistanceNm NOTIFY infoChanged)
|
||||||
|
|
||||||
|
Q_PROPERTY(int estimatedDurationMinutes READ estimatedDurationMinutes WRITE setEstimatedDurationMinutes NOTIFY infoChanged)
|
||||||
|
|
||||||
|
Q_PROPERTY(QuantityValue cruiseAltitude READ cruiseAltitude WRITE setCruiseAltitude NOTIFY infoChanged)
|
||||||
|
Q_PROPERTY(QuantityValue cruiseSpeed READ cruiseSpeed WRITE setCruiseSpeed NOTIFY infoChanged)
|
||||||
|
|
||||||
|
Q_PROPERTY(QmlPositioned* departure READ departure WRITE setDeparture NOTIFY infoChanged)
|
||||||
|
Q_PROPERTY(QmlPositioned* destination READ destination WRITE setDestination NOTIFY infoChanged)
|
||||||
|
Q_PROPERTY(QmlPositioned* alternate READ alternate WRITE setAlternate NOTIFY infoChanged)
|
||||||
|
|
||||||
|
// equipment
|
||||||
|
public:
|
||||||
|
virtual ~FlightPlanController();
|
||||||
|
|
||||||
|
// alias these enums to QML
|
||||||
|
enum FlightRules
|
||||||
|
{
|
||||||
|
VFR = 0,
|
||||||
|
IFR,
|
||||||
|
IFR_VFR,
|
||||||
|
VFR_IFR
|
||||||
|
};
|
||||||
|
|
||||||
|
enum FlightType
|
||||||
|
{
|
||||||
|
Scheduled = 0,
|
||||||
|
NonScheduled,
|
||||||
|
GeneralAviation,
|
||||||
|
Military,
|
||||||
|
Other
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit FlightPlanController(QObject *parent,
|
||||||
|
LaunchConfig* config);
|
||||||
|
|
||||||
|
bool loadFromPath(QString path);
|
||||||
|
bool saveToPath(QString path) const;
|
||||||
|
|
||||||
|
QuantityValue cruiseAltitude() const;
|
||||||
|
void setCruiseAltitude(QuantityValue alt);
|
||||||
|
|
||||||
|
QmlPositioned* departure() const;
|
||||||
|
QmlPositioned* destination() const;
|
||||||
|
QmlPositioned* alternate() const;
|
||||||
|
|
||||||
|
QuantityValue cruiseSpeed() const;
|
||||||
|
|
||||||
|
FlightRules flightRules() const;
|
||||||
|
FlightType flightType() const;
|
||||||
|
|
||||||
|
QString callsign() const;
|
||||||
|
QString remarks() const;
|
||||||
|
QString aircraftType() const;
|
||||||
|
|
||||||
|
int estimatedDurationMinutes() const;
|
||||||
|
QuantityValue totalDistanceNm() const;
|
||||||
|
|
||||||
|
Q_INVOKABLE bool tryParseRoute(QString routeDesc);
|
||||||
|
|
||||||
|
Q_INVOKABLE bool tryGenerateRoute();
|
||||||
|
Q_INVOKABLE void clearRoute();
|
||||||
|
|
||||||
|
LegsModel* legs() const
|
||||||
|
{ return _legs; }
|
||||||
|
|
||||||
|
QString icaoRoute() const;
|
||||||
|
|
||||||
|
flightgear::FlightPlanRef flightplan() const
|
||||||
|
{ return _fp; }
|
||||||
|
|
||||||
|
Q_INVOKABLE bool loadPlan();
|
||||||
|
signals:
|
||||||
|
void infoChanged();
|
||||||
|
void waypointsChanged();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
void setFlightType(FlightType ty);
|
||||||
|
void setFlightRules(FlightRules r);
|
||||||
|
|
||||||
|
void setCallsign(QString s);
|
||||||
|
void setRemarks(QString r);
|
||||||
|
void setAircraftType(QString ty);
|
||||||
|
|
||||||
|
void setDeparture(QmlPositioned* destinationAirport);
|
||||||
|
void setDestination(QmlPositioned* destinationAirport);
|
||||||
|
void setAlternate(QmlPositioned* apt);
|
||||||
|
|
||||||
|
void setCruiseSpeed(QuantityValue cruiseSpeed);
|
||||||
|
|
||||||
|
void setEstimatedDurationMinutes(int mins);
|
||||||
|
|
||||||
|
void computeDuration();
|
||||||
|
|
||||||
|
void clearPlan();
|
||||||
|
void savePlan();
|
||||||
|
private slots:
|
||||||
|
void onCollectConfig();
|
||||||
|
void onSave();
|
||||||
|
void onRestore();
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class FPDelegate;
|
||||||
|
|
||||||
|
flightgear::FlightPlanRef _fp;
|
||||||
|
LegsModel* _legs = nullptr;
|
||||||
|
std::unique_ptr<FPDelegate> _delegate;
|
||||||
|
LaunchConfig* _config = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FLIGHTPLANCONTROLLER_HXX
|
|
@ -46,9 +46,11 @@
|
||||||
#include "PixmapImageItem.hxx"
|
#include "PixmapImageItem.hxx"
|
||||||
#include "AirportDiagram.hxx"
|
#include "AirportDiagram.hxx"
|
||||||
#include "NavaidDiagram.hxx"
|
#include "NavaidDiagram.hxx"
|
||||||
|
#include "RouteDiagram.hxx"
|
||||||
#include "QmlRadioButtonHelper.hxx"
|
#include "QmlRadioButtonHelper.hxx"
|
||||||
#include "UnitsModel.hxx"
|
#include "UnitsModel.hxx"
|
||||||
#include "NavaidSearchModel.hxx"
|
#include "NavaidSearchModel.hxx"
|
||||||
|
#include "FlightPlanController.hxx"
|
||||||
|
|
||||||
using namespace simgear::pkg;
|
using namespace simgear::pkg;
|
||||||
|
|
||||||
|
@ -66,6 +68,8 @@ LauncherController::LauncherController(QObject *parent, QWindow* window) :
|
||||||
connect(m_config, &LaunchConfig::save, this, &LauncherController::saveAircraft);
|
connect(m_config, &LaunchConfig::save, this, &LauncherController::saveAircraft);
|
||||||
connect(m_config, &LaunchConfig::restore, this, &LauncherController::restoreAircraft);
|
connect(m_config, &LaunchConfig::restore, this, &LauncherController::restoreAircraft);
|
||||||
|
|
||||||
|
m_flightPlan = new FlightPlanController(this, m_config);
|
||||||
|
|
||||||
m_location->setLaunchConfig(m_config);
|
m_location->setLaunchConfig(m_config);
|
||||||
connect(m_location, &LocationController::descriptionChanged,
|
connect(m_location, &LocationController::descriptionChanged,
|
||||||
this, &LauncherController::summaryChanged);
|
this, &LauncherController::summaryChanged);
|
||||||
|
@ -126,6 +130,7 @@ void LauncherController::initQML()
|
||||||
{
|
{
|
||||||
qmlRegisterUncreatableType<LauncherController>("FlightGear.Launcher", 1, 0, "LauncherController", "no");
|
qmlRegisterUncreatableType<LauncherController>("FlightGear.Launcher", 1, 0, "LauncherController", "no");
|
||||||
qmlRegisterUncreatableType<LocationController>("FlightGear.Launcher", 1, 0, "LocationController", "no");
|
qmlRegisterUncreatableType<LocationController>("FlightGear.Launcher", 1, 0, "LocationController", "no");
|
||||||
|
qmlRegisterUncreatableType<FlightPlanController>("FlightGear.Launcher", 1, 0, "FlightPlanController", "no");
|
||||||
|
|
||||||
qmlRegisterType<LauncherArgumentTokenizer>("FlightGear.Launcher", 1, 0, "ArgumentTokenizer");
|
qmlRegisterType<LauncherArgumentTokenizer>("FlightGear.Launcher", 1, 0, "ArgumentTokenizer");
|
||||||
qmlRegisterUncreatableType<QAbstractItemModel>("FlightGear.Launcher", 1, 0, "QAIM", "no");
|
qmlRegisterUncreatableType<QAbstractItemModel>("FlightGear.Launcher", 1, 0, "QAIM", "no");
|
||||||
|
@ -156,6 +161,7 @@ void LauncherController::initQML()
|
||||||
qmlRegisterType<PixmapImageItem>("FlightGear", 1, 0, "PixmapImage");
|
qmlRegisterType<PixmapImageItem>("FlightGear", 1, 0, "PixmapImage");
|
||||||
qmlRegisterType<AirportDiagram>("FlightGear", 1, 0, "AirportDiagram");
|
qmlRegisterType<AirportDiagram>("FlightGear", 1, 0, "AirportDiagram");
|
||||||
qmlRegisterType<NavaidDiagram>("FlightGear", 1, 0, "NavaidDiagram");
|
qmlRegisterType<NavaidDiagram>("FlightGear", 1, 0, "NavaidDiagram");
|
||||||
|
qmlRegisterType<RouteDiagram>("FlightGear", 1, 0, "RouteDiagram");
|
||||||
qmlRegisterType<QmlRadioButtonGroup>("FlightGear", 1, 0, "RadioButtonGroup");
|
qmlRegisterType<QmlRadioButtonGroup>("FlightGear", 1, 0, "RadioButtonGroup");
|
||||||
|
|
||||||
qmlRegisterSingletonType(QUrl("qrc:///qml/OverlayShared.qml"), "FlightGear", 1, 0, "OverlayShared");
|
qmlRegisterSingletonType(QUrl("qrc:///qml/OverlayShared.qml"), "FlightGear", 1, 0, "OverlayShared");
|
||||||
|
|
|
@ -41,6 +41,7 @@ class AircraftItemModel;
|
||||||
class QQuickItem;
|
class QQuickItem;
|
||||||
class LaunchConfig;
|
class LaunchConfig;
|
||||||
class LocationController;
|
class LocationController;
|
||||||
|
class FlightPlanController;
|
||||||
|
|
||||||
class LauncherController : public QObject
|
class LauncherController : public QObject
|
||||||
{
|
{
|
||||||
|
@ -54,6 +55,7 @@ class LauncherController : public QObject
|
||||||
Q_PROPERTY(AircraftItemModel* baseAircraftModel MEMBER m_aircraftModel CONSTANT)
|
Q_PROPERTY(AircraftItemModel* baseAircraftModel MEMBER m_aircraftModel CONSTANT)
|
||||||
|
|
||||||
Q_PROPERTY(LocationController* location MEMBER m_location CONSTANT)
|
Q_PROPERTY(LocationController* location MEMBER m_location CONSTANT)
|
||||||
|
Q_PROPERTY(FlightPlanController* flightPlan MEMBER m_flightPlan CONSTANT)
|
||||||
|
|
||||||
Q_PROPERTY(MPServersModel* mpServersModel MEMBER m_serversModel CONSTANT)
|
Q_PROPERTY(MPServersModel* mpServersModel MEMBER m_serversModel CONSTANT)
|
||||||
|
|
||||||
|
@ -246,6 +248,7 @@ private:
|
||||||
AircraftProxyModel* m_aircraftWithUpdatesModel;
|
AircraftProxyModel* m_aircraftWithUpdatesModel;
|
||||||
MPServersModel* m_serversModel = nullptr;
|
MPServersModel* m_serversModel = nullptr;
|
||||||
LocationController* m_location = nullptr;
|
LocationController* m_location = nullptr;
|
||||||
|
FlightPlanController* m_flightPlan = nullptr;
|
||||||
|
|
||||||
QUrl m_selectedAircraft;
|
QUrl m_selectedAircraft;
|
||||||
QString m_aircraftState;
|
QString m_aircraftState;
|
||||||
|
|
141
src/GUI/RouteDiagram.cxx
Normal file
141
src/GUI/RouteDiagram.cxx
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
// RouteDiagram.cxx - GUI diagram of a route
|
||||||
|
//
|
||||||
|
// Written by James Turner, started August 2018.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2018 James Turner <james@flightgear.org>
|
||||||
|
//
|
||||||
|
// This program 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; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program 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 this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
#include "RouteDiagram.hxx"
|
||||||
|
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QVector2D>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
|
||||||
|
#include <Navaids/NavDataCache.hxx>
|
||||||
|
|
||||||
|
#include "FlightPlanController.hxx"
|
||||||
|
|
||||||
|
using namespace flightgear;
|
||||||
|
|
||||||
|
RouteDiagram::RouteDiagram(QQuickItem* pr) :
|
||||||
|
BaseDiagram(pr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void RouteDiagram::setFlightplan(FlightPlanController *fp)
|
||||||
|
{
|
||||||
|
if (fp == m_flightplan)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_flightplan) {
|
||||||
|
// disconnect from old signal
|
||||||
|
disconnect(m_flightplan, nullptr, this, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_flightplan = fp;
|
||||||
|
emit flightplanChanged(fp);
|
||||||
|
|
||||||
|
if (fp) {
|
||||||
|
connect(fp, &FlightPlanController::infoChanged, this, &RouteDiagram::fpChanged);
|
||||||
|
connect(fp, &FlightPlanController::waypointsChanged, this, &RouteDiagram::fpChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
fpChanged();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
int RouteDiagram::numLegs() const
|
||||||
|
{
|
||||||
|
if (!m_flightplan)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
FlightPlanRef fp = m_flightplan->flightplan();
|
||||||
|
if (!fp)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return fp->numLegs();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RouteDiagram::setActiveLegIndex(int activeLegIndex)
|
||||||
|
{
|
||||||
|
if (m_activeLegIndex == activeLegIndex)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_activeLegIndex = activeLegIndex;
|
||||||
|
emit legIndexChanged(m_activeLegIndex);
|
||||||
|
|
||||||
|
const double halfLegDistance = m_path->distanceForIndex(m_activeLegIndex) * 0.5;
|
||||||
|
m_projectionCenter = m_path->positionForDistanceFrom(m_activeLegIndex, halfLegDistance);
|
||||||
|
recomputeBounds(true);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RouteDiagram::paintContents(QPainter *painter)
|
||||||
|
{
|
||||||
|
if (!m_flightplan)
|
||||||
|
return;
|
||||||
|
|
||||||
|
FlightPlanRef fp = m_flightplan->flightplan();
|
||||||
|
QVector<QLineF> lines;
|
||||||
|
QVector<QLineF> activeLines;
|
||||||
|
for (int l=0; l < fp->numLegs(); ++l) {
|
||||||
|
QPointF previous;
|
||||||
|
bool isFirst = true;
|
||||||
|
for (auto g : m_path->pathForIndex(l)) {
|
||||||
|
QPointF p = project(g);
|
||||||
|
if (isFirst) {
|
||||||
|
isFirst = false;
|
||||||
|
} else if (l == m_activeLegIndex) {
|
||||||
|
activeLines.append(QLineF(previous, p));
|
||||||
|
} else {
|
||||||
|
lines.append(QLineF(previous, p));
|
||||||
|
}
|
||||||
|
previous = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QPen linePen(Qt::magenta, 2);
|
||||||
|
linePen.setCosmetic(true);
|
||||||
|
painter->setPen(linePen);
|
||||||
|
painter->drawLines(lines);
|
||||||
|
|
||||||
|
linePen.setColor(Qt::yellow);
|
||||||
|
painter->setPen(linePen);
|
||||||
|
painter->drawLines(activeLines);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RouteDiagram::doComputeBounds()
|
||||||
|
{
|
||||||
|
FlightPlanRef fp = m_flightplan->flightplan();
|
||||||
|
const SGGeodVec gv(m_path->pathForIndex(m_activeLegIndex));
|
||||||
|
std::for_each(gv.begin(), gv.end(), [this](const SGGeod& g)
|
||||||
|
{this->extendBounds(this->project(g)); }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RouteDiagram::fpChanged()
|
||||||
|
{
|
||||||
|
FlightPlanRef fp = m_flightplan->flightplan();
|
||||||
|
m_path.reset(new RoutePath(fp));
|
||||||
|
if (fp) {
|
||||||
|
const double halfLegDistance = m_path->distanceForIndex(m_activeLegIndex) * 0.5;
|
||||||
|
m_projectionCenter = m_path->positionForDistanceFrom(m_activeLegIndex, halfLegDistance);
|
||||||
|
}
|
||||||
|
recomputeBounds(true);
|
||||||
|
update();
|
||||||
|
}
|
81
src/GUI/RouteDiagram.hxx
Normal file
81
src/GUI/RouteDiagram.hxx
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
// RouteDiagram.hxx - show a route graphically
|
||||||
|
//
|
||||||
|
// Written by James Turner, started August 2018.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2018 James Turner <james@flightgear.org>
|
||||||
|
//
|
||||||
|
// This program 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; either version 2 of the
|
||||||
|
// License, or (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program 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 this program; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
#ifndef GUI_ROUTE_DIAGRAM_HXX
|
||||||
|
#define GUI_ROUTE_DIAGRAM_HXX
|
||||||
|
|
||||||
|
#include "BaseDiagram.hxx"
|
||||||
|
#include "QmlPositioned.hxx"
|
||||||
|
#include "UnitsModel.hxx"
|
||||||
|
|
||||||
|
#include <Navaids/navrecord.hxx>
|
||||||
|
#include <Navaids/routePath.hxx>
|
||||||
|
|
||||||
|
#include <simgear/math/sg_geodesy.hxx>
|
||||||
|
|
||||||
|
class FlightPlanController;
|
||||||
|
|
||||||
|
class RouteDiagram : public BaseDiagram
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PROPERTY(FlightPlanController* flightplan READ flightplan WRITE setFlightplan NOTIFY flightplanChanged)
|
||||||
|
|
||||||
|
Q_PROPERTY(int activeLegIndex READ activeLegIndex WRITE setActiveLegIndex NOTIFY legIndexChanged)
|
||||||
|
Q_PROPERTY(int numLegs READ numLegs NOTIFY flightplanChanged)
|
||||||
|
public:
|
||||||
|
RouteDiagram(QQuickItem* pr = nullptr);
|
||||||
|
|
||||||
|
FlightPlanController* flightplan() const
|
||||||
|
{
|
||||||
|
return m_flightplan;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setFlightplan(FlightPlanController* fp);
|
||||||
|
|
||||||
|
int numLegs() const;
|
||||||
|
|
||||||
|
int activeLegIndex() const
|
||||||
|
{
|
||||||
|
return m_activeLegIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void setActiveLegIndex(int activeLegIndex);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void flightplanChanged(FlightPlanController* flightplan);
|
||||||
|
|
||||||
|
void legIndexChanged(int activeLegIndex);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paintContents(QPainter *) override;
|
||||||
|
|
||||||
|
void doComputeBounds() override;
|
||||||
|
private:
|
||||||
|
void fpChanged();
|
||||||
|
|
||||||
|
FlightPlanController* m_flightplan = nullptr;
|
||||||
|
|
||||||
|
std::unique_ptr<RoutePath> m_path;
|
||||||
|
int m_activeLegIndex = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // of GUI_ROUTE_DIAGRAM_HXX
|
|
@ -10,15 +10,58 @@ Item {
|
||||||
height: parent.height
|
height: parent.height
|
||||||
width: parent.width - scrollbar.width
|
width: parent.width - scrollbar.width
|
||||||
flickableDirection: Flickable.VerticalFlick
|
flickableDirection: Flickable.VerticalFlick
|
||||||
contentHeight: contents.childrenRect.height
|
contentHeight: contents.childrenRect.height + Style.margin * 2
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
if (_launcher.flightPlan.cruiseSpeed.value === 0.0) {
|
||||||
|
_launcher.flightPlan.cruiseSpeed = _launcher.selectedAircraftInfo.cruiseSpeed
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_launcher.flightPlan.cruiseAltitude.value === 0.0) {
|
||||||
|
_launcher.flightPlan.cruiseAltitude = _launcher.selectedAircraftInfo.cruiseAltitude
|
||||||
|
}
|
||||||
|
|
||||||
|
_launcher.flightPlan.aircraftType = _launcher.selectedAircraftInfo.icaoType
|
||||||
|
route.text = _launcher.flightPlan.icaoRoute
|
||||||
|
}
|
||||||
|
|
||||||
Column
|
Column
|
||||||
{
|
{
|
||||||
id: contents
|
id: contents
|
||||||
width: parent.width - (Style.margin * 2)
|
width: parent.width - (Style.margin * 2)
|
||||||
x: Style.margin
|
x: Style.margin
|
||||||
|
y: Style.margin
|
||||||
spacing: Style.margin
|
spacing: Style.margin
|
||||||
|
|
||||||
|
Row {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Style.margin
|
||||||
|
height: childrenRect.height
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: qsTr("Load");
|
||||||
|
onClicked: {
|
||||||
|
var ok = _launcher.flightPlan.loadPlan();
|
||||||
|
if (ok) {
|
||||||
|
route.text = _launcher.flightPlan.icaoRoute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: qsTr("Save");
|
||||||
|
onClicked: _launcher.flightPlan.savePlan();
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: qsTr("Clear");
|
||||||
|
onClicked: {
|
||||||
|
_launcher.flightPlan.clearPlan();
|
||||||
|
route.text = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
HeaderBox {
|
HeaderBox {
|
||||||
title: qsTr("Aircraft & flight information")
|
title: qsTr("Aircraft & flight information")
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
@ -35,13 +78,17 @@ Item {
|
||||||
text: qsTr("Callsign / Flight No.")
|
text: qsTr("Callsign / Flight No.")
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
LineEdit {
|
|
||||||
// Aircraft identication - callsign (share with MP)
|
|
||||||
|
|
||||||
|
LineEdit {
|
||||||
id: aircraftIdent
|
id: aircraftIdent
|
||||||
placeholder: "D-FGFS"
|
placeholder: "D-FGFS"
|
||||||
suggestedWidthString: "XXXXXX";
|
suggestedWidthString: "XXXXXX";
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
text: _launcher.flightPlan.callsign
|
||||||
|
|
||||||
|
onTextChanged: {
|
||||||
|
_launcher.flightPlan.callsign = text
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item { width: Style.strutSize; height: 1 }
|
Item { width: Style.strutSize; height: 1 }
|
||||||
|
@ -54,6 +101,11 @@ Item {
|
||||||
placeholder: "B738"
|
placeholder: "B738"
|
||||||
suggestedWidthString: "XXXX";
|
suggestedWidthString: "XXXX";
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
text: _launcher.flightPlan.aircraftType
|
||||||
|
|
||||||
|
onTextChanged: {
|
||||||
|
_launcher.flightPlan.aircraftType = text
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,6 +118,14 @@ Item {
|
||||||
id: flightRules
|
id: flightRules
|
||||||
label: qsTr("Flight rules:")
|
label: qsTr("Flight rules:")
|
||||||
model: ["VFR", "IFR"] // initially IFR (Y), initially VFR (Z)
|
model: ["VFR", "IFR"] // initially IFR (Y), initially VFR (Z)
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
select(_launcher.flightPlan.flightRules);
|
||||||
|
}
|
||||||
|
|
||||||
|
onCurrentIndexChanged: {
|
||||||
|
_launcher.flightPlan.flightRules = currentIndex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item { width: Style.strutSize; height: 1 }
|
Item { width: Style.strutSize; height: 1 }
|
||||||
|
@ -78,6 +138,14 @@ Item {
|
||||||
qsTr("General aviation"),
|
qsTr("General aviation"),
|
||||||
qsTr("Military"),
|
qsTr("Military"),
|
||||||
qsTr("Other")]
|
qsTr("Other")]
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
select(_launcher.flightPlan.flightType);
|
||||||
|
}
|
||||||
|
|
||||||
|
onCurrentIndexChanged: {
|
||||||
|
_launcher.flightPlan.flightType = currentIndex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,6 +179,22 @@ Item {
|
||||||
|
|
||||||
AirportEntry {
|
AirportEntry {
|
||||||
label: qsTr("Departure airport:")
|
label: qsTr("Departure airport:")
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
selectAirport(_launcher.flightPlan.departure.guid)
|
||||||
|
}
|
||||||
|
|
||||||
|
onPickAirport: {
|
||||||
|
selectAirport(guid)
|
||||||
|
_launcher.flightPlan.departure = airport
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickedName: {
|
||||||
|
detailLoader.airportGuid = airport.guid
|
||||||
|
detailLoader.sourceComponent = airportDetails;
|
||||||
|
}
|
||||||
|
|
||||||
|
KeyNavigation.tab: departureTime
|
||||||
}
|
}
|
||||||
|
|
||||||
// padding
|
// padding
|
||||||
|
@ -132,14 +216,23 @@ Item {
|
||||||
NumericalEdit {
|
NumericalEdit {
|
||||||
label: qsTr("Cruise speed:")
|
label: qsTr("Cruise speed:")
|
||||||
unitsMode: Units.Speed
|
unitsMode: Units.Speed
|
||||||
|
quantity: _launcher.flightPlan.cruiseSpeed
|
||||||
|
onCommit: {
|
||||||
|
_launcher.flightPlan.cruiseSpeed = newValue
|
||||||
|
}
|
||||||
|
KeyNavigation.tab: cruiseAltitude
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// padding
|
// padding
|
||||||
Item { width: Style.strutSize; height: 1 }
|
Item { width: Style.strutSize; height: 1 }
|
||||||
|
|
||||||
NumericalEdit {
|
NumericalEdit {
|
||||||
|
id: cruiseAltitude
|
||||||
label: qsTr("Cruise altitude:")
|
label: qsTr("Cruise altitude:")
|
||||||
unitsMode: Units.AltitudeIncludingMeters
|
unitsMode: Units.AltitudeIncludingMeters
|
||||||
|
quantity: _launcher.flightPlan.cruiseAltitude
|
||||||
|
onCommit: _launcher.flightPlan.cruiseAltitude = newValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +244,69 @@ Item {
|
||||||
PlainTextEditBox {
|
PlainTextEditBox {
|
||||||
id: route
|
id: route
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
enabled: _launcher.flightPlan.departure.valid && _launcher.flightPlan.destination.valid
|
||||||
|
|
||||||
|
onEditingFinished: {
|
||||||
|
var ok = _launcher.flightPlan.tryParseRoute(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
height: generateRouteButton.height
|
||||||
|
width: parent.width
|
||||||
|
spacing: Style.margin
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: generateRouteButton
|
||||||
|
text: qsTr("Generate route")
|
||||||
|
enabled: route.enabled
|
||||||
|
onClicked: {
|
||||||
|
var ok = _launcher.flightPlan.tryGenerateRoute();
|
||||||
|
if (ok) {
|
||||||
|
route.text = _launcher.flightPlan.icaoRoute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
PopupChoice {
|
||||||
|
id: routeNetwork
|
||||||
|
label: qsTr("Using")
|
||||||
|
model: [qsTr("High-level (Jet) airways"),
|
||||||
|
qsTr("Low-level (Victor) airways"),
|
||||||
|
qsTr("High- & low-level airways")]
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: qsTr("View route")
|
||||||
|
onClicked: {
|
||||||
|
detailLoader.airportGuid = 0
|
||||||
|
detailLoader.sourceComponent = routeDetails;
|
||||||
|
}
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: qsTr("Clear route")
|
||||||
|
onClicked: {
|
||||||
|
_launcher.flightPlan.clearRoute();
|
||||||
|
route.text = "";
|
||||||
|
}
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RouteLegsView
|
||||||
|
{
|
||||||
|
id: legsView
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
onClickedLeg: {
|
||||||
|
detailLoader.airportGuid = 0
|
||||||
|
detailLoader.legIndex = index
|
||||||
|
detailLoader.sourceComponent = routeDetails;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
|
@ -162,6 +317,20 @@ Item {
|
||||||
AirportEntry {
|
AirportEntry {
|
||||||
id: destinationICAO
|
id: destinationICAO
|
||||||
label: qsTr("Destination airport:")
|
label: qsTr("Destination airport:")
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
selectAirport(_launcher.flightPlan.destination.guid)
|
||||||
|
}
|
||||||
|
|
||||||
|
onPickAirport: {
|
||||||
|
selectAirport(guid)
|
||||||
|
_launcher.flightPlan.destination = airport
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickedName: {
|
||||||
|
detailLoader.airportGuid = airport.guid
|
||||||
|
detailLoader.sourceComponent = airportDetails;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item { width: Style.strutSize; height: 1 }
|
Item { width: Style.strutSize; height: 1 }
|
||||||
|
@ -169,15 +338,47 @@ Item {
|
||||||
TimeEdit {
|
TimeEdit {
|
||||||
id: enrouteEstimate
|
id: enrouteEstimate
|
||||||
label: qsTr("Estimated enroute time:")
|
label: qsTr("Estimated enroute time:")
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
setDurationMinutes(_launcher.flightPlan.estimatedDurationMinutes)
|
||||||
|
}
|
||||||
|
|
||||||
|
onValueChanged: {
|
||||||
|
_launcher.flightPlan.estimatedDurationMinutes = value.getHours() * 60 + value.getMinutes();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item { width: Style.strutSize; height: 1 }
|
Item { width: Style.strutSize; height: 1 }
|
||||||
|
|
||||||
|
StyledText
|
||||||
|
{
|
||||||
|
text: qsTr("Total distance: %1").arg(_launcher.flightPlan.totalDistanceNm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
height: childrenRect.height
|
||||||
|
width: parent.width
|
||||||
|
spacing: Style.margin
|
||||||
|
|
||||||
AirportEntry {
|
AirportEntry {
|
||||||
id: alternate1
|
id: alternate1
|
||||||
label: qsTr("Alternate airport:")
|
label: qsTr("Alternate airport:")
|
||||||
}
|
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
selectAirport(_launcher.flightPlan.alternate.guid)
|
||||||
|
}
|
||||||
|
|
||||||
|
onPickAirport: {
|
||||||
|
selectAirport(guid)
|
||||||
|
_launcher.flightPlan.alternate = airport
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickedName: {
|
||||||
|
detailLoader.airportGuid = airport.guid
|
||||||
|
detailLoader.sourceComponent = airportDetails;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HeaderBox {
|
HeaderBox {
|
||||||
|
@ -193,10 +394,12 @@ Item {
|
||||||
PlainTextEditBox {
|
PlainTextEditBox {
|
||||||
id: remarks
|
id: remarks
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
text: _launcher.flightPlan.remarks
|
||||||
|
|
||||||
|
onEditingFinished: {
|
||||||
|
_launcher.flightPlan.remarks = text;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// speak to Act-pie guy about passing all this over MP props?
|
|
||||||
} // of main column
|
} // of main column
|
||||||
|
|
||||||
} // of flickable
|
} // of flickable
|
||||||
|
@ -208,4 +411,50 @@ Item {
|
||||||
flickable: flick
|
flickable: flick
|
||||||
visible: flick.contentHeight > flick.height
|
visible: flick.contentHeight > flick.height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: airportDetails
|
||||||
|
PlanAirportView {
|
||||||
|
id: airportView
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: routeDetails
|
||||||
|
PlanRouteDetails {
|
||||||
|
id: routeView
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: detailLoader
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: sourceComponent != null
|
||||||
|
|
||||||
|
property var airportGuid
|
||||||
|
property int legIndex
|
||||||
|
|
||||||
|
onStatusChanged: {
|
||||||
|
if (status == Loader.Ready) {
|
||||||
|
if (item.hasOwnProperty("location")) {
|
||||||
|
item.location = airportGuid
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.hasOwnProperty("legIndex")) {
|
||||||
|
item.legIndex = legIndex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: backButton
|
||||||
|
anchors { left: parent.left; top: parent.top; margins: Style.margin }
|
||||||
|
width: Style.strutSize
|
||||||
|
visible: detailLoader.visible
|
||||||
|
text: "< Back"
|
||||||
|
onClicked: {
|
||||||
|
detailLoader.sourceComponent = null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -149,7 +149,7 @@ Item {
|
||||||
MenuItem { text:qsTr("Save configuration as..."); shortcut: "Ctrl+S";
|
MenuItem { text:qsTr("Save configuration as..."); shortcut: "Ctrl+S";
|
||||||
onTriggered: _launcher.saveConfigAs(); },
|
onTriggered: _launcher.saveConfigAs(); },
|
||||||
MenuDivider {},
|
MenuDivider {},
|
||||||
MenuItem { text:qsTr("Flight-planning"); onTriggered: root.enterFlightPlan(); shortcut: "Ctrl+P"; enabled: false},
|
MenuItem { text:qsTr("Flight-planning"); onTriggered: root.enterFlightPlan(); shortcut: "Ctrl+P"; enabled: true},
|
||||||
MenuDivider {},
|
MenuDivider {},
|
||||||
MenuItem { text:qsTr("View command line"); onTriggered: _launcher.viewCommandLine(); shortcut: "Ctrl+L"},
|
MenuItem { text:qsTr("View command line"); onTriggered: _launcher.viewCommandLine(); shortcut: "Ctrl+L"},
|
||||||
MenuItem { text:qsTr("Select data files location..."); onTriggered: _launcher.requestChangeDataPath(); },
|
MenuItem { text:qsTr("Select data files location..."); onTriggered: _launcher.requestChangeDataPath(); },
|
||||||
|
|
28
src/GUI/qml/PlanAirportView.qml
Normal file
28
src/GUI/qml/PlanAirportView.qml
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import QtQuick 2.4
|
||||||
|
import FlightGear 1.0
|
||||||
|
import FlightGear.Launcher 1.0
|
||||||
|
import "."
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
property alias location: airportData.guid
|
||||||
|
|
||||||
|
Positioned {
|
||||||
|
id: airportData
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AirportDiagram {
|
||||||
|
id: diagram
|
||||||
|
anchors.fill: parent
|
||||||
|
airport: airportData.guid
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
if (pos === null)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
approachExtensionEnabled: false
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
43
src/GUI/qml/PlanRouteDetails.qml
Normal file
43
src/GUI/qml/PlanRouteDetails.qml
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import QtQuick 2.4
|
||||||
|
import FlightGear 1.0
|
||||||
|
import FlightGear.Launcher 1.0
|
||||||
|
import "."
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property alias legIndex: diagram.activeLegIndex
|
||||||
|
|
||||||
|
RouteDiagram {
|
||||||
|
id: diagram
|
||||||
|
anchors.fill: parent
|
||||||
|
flightplan: _launcher.flightPlan
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: previousButton
|
||||||
|
text: qsTr("Previous Leg")
|
||||||
|
enabled: diagram.activeLegIndex > 0
|
||||||
|
onClicked: {
|
||||||
|
diagram.activeLegIndex = diagram.activeLegIndex - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors.right: root.horizontalCenter
|
||||||
|
anchors.bottom: root.bottom
|
||||||
|
anchors.margins: Style.margin
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: qsTr("Next Leg")
|
||||||
|
width: previousButton.width
|
||||||
|
|
||||||
|
enabled: diagram.activeLegIndex < (diagram.numLegs - 1)
|
||||||
|
onClicked: {
|
||||||
|
diagram.activeLegIndex = diagram.activeLegIndex + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
anchors.left: root.horizontalCenter
|
||||||
|
anchors.bottom: root.bottom
|
||||||
|
anchors.margins: Style.margin
|
||||||
|
}
|
||||||
|
}
|
130
src/GUI/qml/RouteLegsView.qml
Normal file
130
src/GUI/qml/RouteLegsView.qml
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
import QtQuick 2.4
|
||||||
|
import FlightGear.Launcher 1.0
|
||||||
|
import FlightGear 1.0
|
||||||
|
import "."
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
{
|
||||||
|
id: root
|
||||||
|
implicitHeight: childrenRect.height + Style.margin * 2
|
||||||
|
|
||||||
|
border.width: 1
|
||||||
|
border.color: Style.minorFrameColor
|
||||||
|
|
||||||
|
signal clickedLeg(var index)
|
||||||
|
|
||||||
|
TextMetrics {
|
||||||
|
id: legDistanceWidth
|
||||||
|
font.pixelSize: Style.baseFontPixelSize
|
||||||
|
text: "0000Nm"
|
||||||
|
}
|
||||||
|
|
||||||
|
TextMetrics {
|
||||||
|
id: legBearingWidth
|
||||||
|
font.pixelSize: Style.baseFontPixelSize
|
||||||
|
text: "000*True"
|
||||||
|
}
|
||||||
|
|
||||||
|
TextMetrics {
|
||||||
|
id: legIdentWidth
|
||||||
|
font.pixelSize: Style.baseFontPixelSize
|
||||||
|
text: "XXXXX"
|
||||||
|
}
|
||||||
|
|
||||||
|
TextMetrics {
|
||||||
|
id: legViaWidth
|
||||||
|
font.pixelSize: Style.baseFontPixelSize
|
||||||
|
text: "via XXXXX"
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property int legDistanceColumnStart: root.width - (legDistanceWidth.width + (Style.margin * 2))
|
||||||
|
readonly property int legBearingColumnStart: legDistanceColumnStart - (legBearingWidth.width + Style.margin)
|
||||||
|
|
||||||
|
// description string fills the middle space, gets elided
|
||||||
|
readonly property int legDescriptionColumnStart: legIdentWidth.width + legViaWidth.width + Style.margin * 3
|
||||||
|
readonly property int legDescriptStringWidth: legBearingColumnStart - legDescriptionColumnStart
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width - Style.margin * 2
|
||||||
|
x: Style.margin
|
||||||
|
y: Style.margin
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
id: routeLegs
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
|
model: _launcher.flightPlan.legs
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
id: delegateRect
|
||||||
|
height: rowLabel.height + Style.margin
|
||||||
|
width: routeLegs.width
|
||||||
|
color: (model.index % 2) ? "#dfdfdf" : "white"
|
||||||
|
|
||||||
|
readonly property string description: {
|
||||||
|
var s = model.toName;
|
||||||
|
if (model.wpType === "navaid") {
|
||||||
|
var freq = model.frequency
|
||||||
|
if (freq.isValid())
|
||||||
|
s += " (" + freq.toString() + ")"
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
id: rowLabel
|
||||||
|
text: model.label
|
||||||
|
x: Style.margin
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
id: rowAirway
|
||||||
|
text: {
|
||||||
|
var awy = model.via;
|
||||||
|
if (awy === undefined) return "";
|
||||||
|
return "via " + awy;
|
||||||
|
}
|
||||||
|
|
||||||
|
x: Style.margin * 2 + legIdentWidth.width
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
visible: model.wpType === "navaid"
|
||||||
|
text: delegateRect.description
|
||||||
|
x: legDescriptionColumnStart
|
||||||
|
width: legDescriptStringWidth
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
x: legBearingColumnStart
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
visible: (model.index > 0)
|
||||||
|
text: model.track.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
x: legDistanceColumnStart
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
visible: (model.index > 0)
|
||||||
|
text: model.distance.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: {
|
||||||
|
root.clickedLeg(model.index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // of delegate rect
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -118,6 +118,9 @@
|
||||||
<file>qml/Overlay.qml</file>
|
<file>qml/Overlay.qml</file>
|
||||||
<file>qml/OverlayShared.qml</file>
|
<file>qml/OverlayShared.qml</file>
|
||||||
<file>qml/Weblink.qml</file>
|
<file>qml/Weblink.qml</file>
|
||||||
|
<file>qml/PlanAirportView.qml</file>
|
||||||
|
<file>qml/PlanRouteDetails.qml</file>
|
||||||
|
<file>qml/RouteLegsView.qml</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="/preview">
|
<qresource prefix="/preview">
|
||||||
<file alias="close-icon">preview-close.png</file>
|
<file alias="close-icon">preview-close.png</file>
|
||||||
|
|
Loading…
Reference in a new issue