2018-02-09 18:55:53 +00:00
|
|
|
# Copyright 2018 Stuart Buchanan
|
|
|
|
# This file is part of FlightGear.
|
|
|
|
#
|
2018-05-28 19:15:57 +00:00
|
|
|
# FlightGear is free software: you can redistribute it and/or modify
|
2018-02-09 18:55:53 +00:00
|
|
|
# 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.
|
|
|
|
#
|
|
|
|
# FlightGear 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 FlightGear. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#
|
2017-12-10 22:15:21 +00:00
|
|
|
# NearestAirports
|
|
|
|
var NearestAirports =
|
|
|
|
{
|
|
|
|
new : func (mfd, myCanvas, device, svg)
|
|
|
|
{
|
|
|
|
var obj = {
|
2017-12-27 19:51:54 +00:00
|
|
|
parents : [
|
|
|
|
NearestAirports,
|
|
|
|
MFDPage.new(mfd, myCanvas, device, svg, "NearestAirports", "NRST - NEAREST AIRPORTS")
|
|
|
|
],
|
2017-12-10 22:15:21 +00:00
|
|
|
};
|
|
|
|
|
2018-01-26 19:06:06 +00:00
|
|
|
obj.setController(fg1000.NearestAirportsController.new(obj, svg));
|
2017-12-10 22:15:21 +00:00
|
|
|
|
2017-12-27 19:51:54 +00:00
|
|
|
# Dynamic elements. There are 4 different sets of dynamic elements:
|
|
|
|
#
|
|
|
|
# Nearest Airports - this is a scrolling list of up to 25 airports within 200nm, shown 5 at a time.
|
|
|
|
# Runways - just a single scroll element
|
|
|
|
# Frequencies - 3 displayed in a scrolling list
|
|
|
|
# Approaches - 3 displayed in a scrolling list
|
|
|
|
#
|
|
|
|
# Selection is via softkeys, the FMS knob, or via the page menu.
|
2017-12-10 22:15:21 +00:00
|
|
|
|
2017-12-27 19:51:54 +00:00
|
|
|
obj.airportSelect = PFD.GroupElement.new(
|
|
|
|
obj.pageName,
|
|
|
|
svg,
|
|
|
|
[ "Arrow", "ID", "CRS", "DST"],
|
|
|
|
5,
|
|
|
|
"Arrow",
|
2017-12-31 16:10:52 +00:00
|
|
|
1,
|
|
|
|
"AirportScrollBar",
|
|
|
|
"AirportScroll",
|
|
|
|
100
|
2017-12-27 19:51:54 +00:00
|
|
|
);
|
2017-12-10 22:15:21 +00:00
|
|
|
|
2017-12-27 19:51:54 +00:00
|
|
|
obj.runwaySelect = PFD.ScrollElement.new(obj.pageName, svg, "RunwayID", [36,18]); # Dummy values
|
|
|
|
|
|
|
|
obj.freqSelect = PFD.GroupElement.new(
|
|
|
|
obj.pageName,
|
|
|
|
svg,
|
|
|
|
["FreqLabel", "Freq"],
|
|
|
|
3,
|
2017-12-31 16:10:52 +00:00
|
|
|
"Freq",
|
|
|
|
0,
|
|
|
|
"FreqScrollBar",
|
|
|
|
"FreqScroll",
|
|
|
|
75
|
2017-12-27 19:51:54 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
obj.approachSelect = PFD.GroupElement.new(
|
|
|
|
obj.pageName,
|
|
|
|
svg,
|
|
|
|
["Approach"],
|
|
|
|
3,
|
2017-12-31 16:10:52 +00:00
|
|
|
"Approach",
|
|
|
|
0,
|
|
|
|
"ApproachScrollBar",
|
|
|
|
"ApproachScroll",
|
|
|
|
75
|
2017-12-27 19:51:54 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
# Other dynamic text elements
|
|
|
|
obj.addTextElements(["Name", "Alt", "RunwaySurface", "RunwayDimensions"]);
|
2017-12-10 22:15:21 +00:00
|
|
|
|
2017-12-31 16:10:52 +00:00
|
|
|
obj.topMenu(device, obj, nil);
|
2017-12-10 22:15:21 +00:00
|
|
|
|
|
|
|
return obj;
|
|
|
|
},
|
|
|
|
|
2017-12-27 19:51:54 +00:00
|
|
|
# Indicate which group is selected by colour of the softkeys
|
|
|
|
display_toggle : func(device, svg, mi, group) {
|
|
|
|
var bg_name = sprintf("SoftKey%d-bg",mi.menu_id);
|
2018-01-26 19:06:06 +00:00
|
|
|
if (me.getController().getSelectedGroup() == group) {
|
2017-12-27 19:51:54 +00:00
|
|
|
device.svg.getElementById(bg_name).setColorFill(0.5,0.5,0.5);
|
|
|
|
svg.setColor(0.0,0.0,0.0);
|
|
|
|
} else {
|
|
|
|
device.svg.getElementById(bg_name).setColorFill(0.0,0.0,0.0);
|
|
|
|
svg.setColor(1.0,1.0,1.0);
|
|
|
|
}
|
|
|
|
svg.setText(mi.title);
|
|
|
|
svg.setVisible(1); # display function
|
|
|
|
},
|
|
|
|
|
|
|
|
# Function to highlight the APT softkey - used when CRSR is pressed to indicate
|
|
|
|
# that we're editing the airports selection.
|
|
|
|
selectAirports : func() {
|
2017-12-31 16:10:52 +00:00
|
|
|
me.resetMenuColors();
|
2017-12-27 19:51:54 +00:00
|
|
|
var bg_name = sprintf("SoftKey%d-bg",4);
|
|
|
|
var tname = sprintf("SoftKey%d",4);
|
|
|
|
me.device.svg.getElementById(bg_name).setColorFill(0.5,0.5,0.5);
|
|
|
|
me.device.svg.getElementById(tname).setColor(0.0,0.0,0.0);
|
|
|
|
},
|
|
|
|
|
|
|
|
# Clear any cursor, highlights. Used when exiting from CRSR mode
|
|
|
|
resetCRSR : func() {
|
2018-02-01 22:28:39 +00:00
|
|
|
me.airportSelect.hideCRSR();
|
2017-12-27 19:51:54 +00:00
|
|
|
me.runwaySelect.unhighlightElement();
|
|
|
|
me.freqSelect.hideCRSR();
|
|
|
|
me.approachSelect.hideCRSR();
|
2017-12-31 16:10:52 +00:00
|
|
|
me.resetMenuColors();
|
2017-12-10 22:15:21 +00:00
|
|
|
},
|
2017-12-27 19:51:54 +00:00
|
|
|
|
|
|
|
offdisplay : func() {
|
|
|
|
# The Nearest... pages use the underlying navigation map.
|
|
|
|
me.mfd.NavigationMap.offdisplayPartial();
|
|
|
|
|
|
|
|
# Reset the menu colours. Shouldn't have to do this here, but
|
|
|
|
# there's not currently an obvious other location to do so.
|
2017-12-31 16:10:52 +00:00
|
|
|
me.resetMenuColors();
|
2017-12-27 19:51:54 +00:00
|
|
|
|
2018-01-26 19:06:06 +00:00
|
|
|
me.getController().offdisplay();
|
2017-12-27 19:51:54 +00:00
|
|
|
},
|
2017-12-10 22:15:21 +00:00
|
|
|
ondisplay : func() {
|
2018-01-26 19:06:06 +00:00
|
|
|
me.getController().ondisplay();
|
2017-12-27 19:51:54 +00:00
|
|
|
|
|
|
|
# The Nearest... pages use the underlying navigation map.
|
|
|
|
me.mfd.NavigationMap.ondisplayPartial();
|
|
|
|
|
2017-12-10 22:15:21 +00:00
|
|
|
me.mfd.setPageTitle(me.title);
|
2017-12-27 19:51:54 +00:00
|
|
|
},
|
|
|
|
updateAirports : func(apts) {
|
|
|
|
|
2018-01-13 21:07:32 +00:00
|
|
|
if (apts == nil) return;
|
|
|
|
|
2017-12-27 19:51:54 +00:00
|
|
|
var airportlist = [];
|
|
|
|
for (var i = 0; i < size(apts); i = i + 1) {
|
|
|
|
var apt = apts[i];
|
|
|
|
var crsAndDst = courseAndDistance(apt);
|
2017-12-31 16:10:52 +00:00
|
|
|
|
2018-01-31 22:47:35 +00:00
|
|
|
# Display the course and distance in NM .
|
2018-03-17 22:04:41 +00:00
|
|
|
var crs = sprintf("%i°", crsAndDst[0]);
|
2017-12-27 19:51:54 +00:00
|
|
|
var dst = sprintf("%.1fnm", crsAndDst[1]);
|
|
|
|
|
|
|
|
# Convert into something we can pass straight to the UIGroup.
|
|
|
|
append(airportlist, {
|
|
|
|
Arrow : apt.id,
|
|
|
|
ID: apt.id,
|
|
|
|
CRS: crs,
|
|
|
|
DST: dst,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
me.airportSelect.setValues(airportlist);
|
|
|
|
|
|
|
|
if (size(airportlist) > 0) {
|
|
|
|
me.updateAirportData(apts[0]);
|
2018-02-01 22:28:39 +00:00
|
|
|
#me.airportSelect.showCRSR();
|
2017-12-27 19:51:54 +00:00
|
|
|
} else {
|
2018-02-01 22:28:39 +00:00
|
|
|
#me.airportSelect.hideCRSR();
|
2017-12-27 19:51:54 +00:00
|
|
|
me.setTextElement("Name", "NONE WITHIN 200NM");
|
|
|
|
me.setTextElement("Alt", "");
|
|
|
|
}
|
|
|
|
},
|
|
|
|
updateAirportData : func(apt) {
|
2018-01-13 21:07:32 +00:00
|
|
|
|
|
|
|
if (apt == nil) return;
|
|
|
|
|
2017-12-27 19:51:54 +00:00
|
|
|
me.setTextElement("Name", apt.name);
|
|
|
|
me.setTextElement("Alt", sprintf("%ift", M2FT * apt.elevation));
|
|
|
|
|
2017-12-31 16:10:52 +00:00
|
|
|
# Set up the runways list, but ignoring reciprocals so we don't get
|
|
|
|
# runways displayed twice.
|
|
|
|
var rwys = [];
|
|
|
|
var recips = {};
|
|
|
|
foreach(var rwy; sort(keys(apt.runways), string.icmp)) {
|
|
|
|
var rwy_info = apt.runways[rwy];
|
|
|
|
if (recips[rwy_info.id] == nil) {
|
|
|
|
var lbl = rwy_info.id ~ "-" ~ rwy_info.reciprocal.id;
|
|
|
|
append(rwys, lbl);
|
|
|
|
recips[rwy_info.reciprocal.id] = 1;
|
|
|
|
}
|
|
|
|
}
|
2017-12-27 19:51:54 +00:00
|
|
|
|
2017-12-31 16:10:52 +00:00
|
|
|
if (size(rwys) > 0) {
|
|
|
|
me.runwaySelect.setValues(rwys);
|
|
|
|
me.updateRunwayInfo(apt.runways[keys(apt.runways)[0]]);
|
2017-12-27 19:51:54 +00:00
|
|
|
} else {
|
|
|
|
me.runwaySelect.setValues([""]);
|
|
|
|
me.updateRunwayInfo(nil);
|
|
|
|
}
|
|
|
|
|
|
|
|
var freqarray = [];
|
2018-01-13 21:48:38 +00:00
|
|
|
|
|
|
|
# Add Comm Frequencies
|
2017-12-27 19:51:54 +00:00
|
|
|
var apt_comms = apt.comms();
|
|
|
|
if (size(apt_comms) > 0) {
|
|
|
|
# Airport has one or more frequencies assigned to it.
|
|
|
|
var freqs = {};
|
|
|
|
foreach (var c; apt_comms) {
|
2018-01-13 21:48:38 +00:00
|
|
|
freqs[c.ident] = sprintf("%.3f", c.frequency);
|
2017-12-27 19:51:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
foreach (var c; sort(keys(freqs), string.icmp)) {
|
|
|
|
append(freqarray, {FreqLabel: c, Freq: freqs[c]});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-13 21:48:38 +00:00
|
|
|
# Add any ILS frequencies as well
|
|
|
|
foreach(var rwy; sort(keys(apt.runways), string.icmp)) {
|
|
|
|
var rwy_info = apt.runways[rwy];
|
|
|
|
if (rwy_info.ils_frequency_mhz != nil) {
|
|
|
|
var label = "ILS " ~ rwy_info.id;
|
|
|
|
var freq = sprintf("%.3f", rwy_info.ils_frequency_mhz);
|
|
|
|
append(freqarray, {FreqLabel: label, Freq: freq});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-27 19:51:54 +00:00
|
|
|
me.freqSelect.setValues(freqarray);
|
|
|
|
|
|
|
|
# Approaches
|
|
|
|
var approachList = apt.getApproachList();
|
|
|
|
me.approachSelect.setValues(approachList);
|
2017-12-31 16:10:52 +00:00
|
|
|
|
|
|
|
# Display the DTO line to the airport
|
2018-01-26 19:06:06 +00:00
|
|
|
me.mfd.NavigationMap.getController().setDTOLineTarget(apt.lat, apt.lon);
|
2017-12-27 19:51:54 +00:00
|
|
|
},
|
|
|
|
updateRunwayInfo : func(rwy_info) {
|
|
|
|
if (rwy_info != nil ) {
|
|
|
|
var dim = sprintf("%ift x %ift", 3.28 * rwy_info.length, 3.28 * rwy_info.width);
|
|
|
|
me.setTextElement("RunwayDimensions", dim);
|
|
|
|
me.setTextElement("RunwaySurface", SURFACE_TYPES[rwy_info.surface]);
|
|
|
|
} else {
|
|
|
|
me.setTextElement("RunwayDimensions", "");
|
|
|
|
me.setTextElement("RunwaySurface", "");
|
|
|
|
}
|
|
|
|
},
|
|
|
|
getSelectedAirportID : func() {
|
|
|
|
return me.airportSelect.getValue();
|
|
|
|
},
|
|
|
|
getSelectedRunway : func() {
|
|
|
|
return me.runwaySelect.getValue();
|
|
|
|
},
|
|
|
|
getSelectedFreq : func() {
|
|
|
|
return me.freqSelect.getValue();
|
|
|
|
},
|
|
|
|
getSelectedApproach : func() {
|
|
|
|
return me.approachSelect.getValue();
|
2017-12-10 22:15:21 +00:00
|
|
|
},
|
2017-12-31 16:10:52 +00:00
|
|
|
|
|
|
|
topMenu : func(device, pg, menuitem) {
|
|
|
|
pg.clearMenu();
|
|
|
|
pg.resetMenuColors();
|
|
|
|
pg.addMenuItem(0, "ENGINE", pg, pg.mfd.EIS.engineMenu);
|
|
|
|
pg.addMenuItem(2, "MAP", pg, pg.mfd.NavigationMap.mapMenu);
|
|
|
|
pg.addMenuItem(4, "APT", pg,
|
2018-01-26 19:06:06 +00:00
|
|
|
func(dev, pg, mi) { pg.getController().selectAirports(); device.updateMenus(); }, # callback
|
2017-12-31 16:10:52 +00:00
|
|
|
func(svg, mi) { pg.display_toggle(device, svg, mi, NearestAirportsController.UIGROUP.APT); }
|
|
|
|
);
|
|
|
|
|
|
|
|
pg.addMenuItem(5, "RNWY", pg,
|
2018-01-26 19:06:06 +00:00
|
|
|
func(dev, pg, mi) { pg.getController().selectRunways(); device.updateMenus(); }, # callback
|
2017-12-31 16:10:52 +00:00
|
|
|
func(svg, mi) { pg.display_toggle(device, svg, mi, NearestAirportsController.UIGROUP.RNWY); }
|
|
|
|
);
|
|
|
|
|
|
|
|
pg.addMenuItem(6, "FREQ", pg,
|
2018-01-26 19:06:06 +00:00
|
|
|
func(dev, pg, mi) { pg.getController().selectFrequencies(); device.updateMenus(); }, # callback
|
2017-12-31 16:10:52 +00:00
|
|
|
func(svg, mi) { pg.display_toggle(device, svg, mi, NearestAirportsController.UIGROUP.FREQ); }
|
|
|
|
);
|
|
|
|
|
|
|
|
pg.addMenuItem(7, "APR", pg,
|
2018-01-26 19:06:06 +00:00
|
|
|
func(dev, pg, mi) { pg.getController().selectApproaches(); device.updateMenus(); }, # callback
|
2017-12-31 16:10:52 +00:00
|
|
|
func(svg, mi) { pg.display_toggle(device, svg, mi, NearestAirportsController.UIGROUP.APR); }
|
|
|
|
);
|
|
|
|
|
|
|
|
device.updateMenus();
|
|
|
|
},
|
2017-12-10 22:15:21 +00:00
|
|
|
};
|