diff --git a/Aircraft/Instruments-3d/FG1000/MFDPages/ActiveFlightPlanNarrow.svg b/Aircraft/Instruments-3d/FG1000/MFDPages/ActiveFlightPlanNarrow.svg
new file mode 100644
index 000000000..9fd9057dc
--- /dev/null
+++ b/Aircraft/Instruments-3d/FG1000/MFDPages/ActiveFlightPlanNarrow.svg
@@ -0,0 +1,1295 @@
+
+
+
+
diff --git a/Aircraft/Instruments-3d/FG1000/MFDPages/Surround.svg b/Aircraft/Instruments-3d/FG1000/MFDPages/Surround.svg
index a01e3c8cb..3fbfa9f5f 100644
--- a/Aircraft/Instruments-3d/FG1000/MFDPages/Surround.svg
+++ b/Aircraft/Instruments-3d/FG1000/MFDPages/Surround.svg
@@ -15,7 +15,7 @@
version="1.1"
id="SVGRoot"
inkscape:version="0.91 r13725"
- sodipodi:docname="MFD.svg">
+ sodipodi:docname="Surround.svg">
+
+
+
diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericFMSPublisher.nas b/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericFMSPublisher.nas
index 5d55e5429..22f789d85 100644
--- a/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericFMSPublisher.nas
+++ b/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericFMSPublisher.nas
@@ -15,6 +15,7 @@
# along with FlightGear. If not, see .
#
# FMS Driver using Emesary to publish data from the inbuilt FMS properties
+
var GenericFMSPublisher =
{
@@ -23,6 +24,7 @@ var GenericFMSPublisher =
parents : [
GenericFMSPublisher,
],
+ _running : 0,
};
# We have two publishers here:
@@ -119,12 +121,88 @@ var GenericFMSPublisher =
start : func() {
me._triggeredPublisher.start();
me._periodicPublisher.start();
+ me._running = 1;
},
stop : func() {
me._triggeredPublisher.stop();
me._periodicPublisher.stop();
+ me._running = 0;
},
+ isRunning : func() {
+ return me._running;
+ },
};
+
+# FMS Delegate which will be triggered by the underlying route manager
+var FMSDataDelegate = {
+ new : func(fp) {
+ var obj = {
+ parents : [FMSDataDelegate],
+ flightplan : fp,
+ };
+ return obj;
+ },
+ currentWaypointChanged : func (fp) {
+ var notification = notifications.PFDEventNotification.new(
+ "MFD",
+ 1,
+ notifications.PFDEventNotification.FMSData,
+ {"FMSFlightPlanSequenced" : fp.current});
+ emesary.GlobalTransmitter.NotifyAll(notification);
+ },
+ departureChanged : func (fp) {
+ var notification = notifications.PFDEventNotification.new(
+ "MFD",
+ 1,
+ notifications.PFDEventNotification.FMSData,
+ {"FMSFlightPlanEdited" : 1});
+ emesary.GlobalTransmitter.NotifyAll(notification);
+ },
+ arrivalChanged : func (fp) {
+ var notification = notifications.PFDEventNotification.new(
+ "MFD",
+ 1,
+ notifications.PFDEventNotification.FMSData,
+ {"FMSFlightPlanEdited" : 1});
+ emesary.GlobalTransmitter.NotifyAll(notification);
+ },
+ waypointsChanged : func (fp) {
+ var notification = notifications.PFDEventNotification.new(
+ "MFD",
+ 1,
+ notifications.PFDEventNotification.FMSData,
+ {"FMSFlightPlanEdited" : 1});
+ emesary.GlobalTransmitter.NotifyAll(notification);
+ },
+ activated : func (fp) {
+ var notification = notifications.PFDEventNotification.new(
+ "MFD",
+ 1,
+ notifications.PFDEventNotification.FMSData,
+ {"FMSFlightPlanEdited" : 1});
+ emesary.GlobalTransmitter.NotifyAll(notification);
+ },
+ cleared : func (fp) {
+ me.sendFMSNotification({"FMSFlightPlanEdited" : 1});
+ var notification = notifications.PFDEventNotification.new(
+ "MFD",
+ 1,
+ notifications.PFDEventNotification.FMSData,
+ {"FMSFlightPlanEdited" : 1});
+ },
+ endOfFlightPlan: func (fp) {
+ var notification = notifications.PFDEventNotification.new(
+ "MFD",
+ 1,
+ notifications.PFDEventNotification.FMSData,
+ {"FMSFlightPlanFinished" : 1});
+ emesary.GlobalTransmitter.NotifyAll(notification);
+ },
+};
+
+var dd = FMSDataDelegate.new(flightplan());
+
+registerFlightPlanDelegate(FMSDataDelegate.new);
diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericInterfaceController.nas b/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericInterfaceController.nas
index 870442dbf..239481c93 100644
--- a/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericInterfaceController.nas
+++ b/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/GenericInterfaceController.nas
@@ -27,7 +27,6 @@ io.load_nasal(nasal_dir ~ 'Interfaces/GenericFMSPublisher.nas', "fg1000");
io.load_nasal(nasal_dir ~ 'Interfaces/GenericFMSUpdater.nas', "fg1000");
io.load_nasal(nasal_dir ~ 'Interfaces/GenericADCPublisher.nas', "fg1000");
-
var GenericInterfaceController = {
_instance : nil,
@@ -54,6 +53,7 @@ var GenericInterfaceController = {
obj.gpsPublisher = fg1000.GenericFMSPublisher.new();
obj.gpsUpdater = fg1000.GenericFMSUpdater.new();
obj.adcPublisher = fg1000.GenericADCPublisher.new();
+
return obj;
},
diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/NavDataInterface.nas b/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/NavDataInterface.nas
index 886b07418..2b66c1c3e 100644
--- a/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/NavDataInterface.nas
+++ b/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/NavDataInterface.nas
@@ -20,6 +20,14 @@
var NavDataInterface = {
+# Valid FMS Modes
+
+FMS_MODES : {
+ direct : 1,
+ leg : 1,
+ obs : 1,
+},
+
new : func ()
{
var obj = { parents : [ NavDataInterface ] };
@@ -142,6 +150,47 @@ getFlightplan : func ()
return flightplan();
},
+insertWaypoint : func (data)
+{
+ assert(data["index"] != nil, "InsertWaypoint message with no index parameter");
+ assert(data["wp"] != nil, "InsertWaypoint message with no wp parameter");
+
+ var wp = data["wp"];
+ var idx = int(data["index"]);
+
+ # Simple data verification that we have the parameters we need
+ assert(idx != nil, "InsertWaypoint index parameter does not contain an integer index");
+ assert(wp.id != nil, "InsertWaypoint wp parameter does not contain an id");
+ assert(wp.lat != nil, "InsertWaypoint wp parameter does not contain a lat");
+ assert(wp.lon != nil, "InsertWaypoint wp parameter does not contain an lon");
+
+ var newwp = createWP(wp.lat, wp.lon, wp.id);
+
+ var fp = flightplan();
+ fp.insertWP(newwp, idx);
+
+ # Set a suitable name.
+ if ((fp.id == nil) or (fp.id == "default-flightplan")) {
+ var from = "????";
+ var dest = "????";
+
+ if ((fp.getWP(0) != nil) and (fp.getWP(0).wp_name != nil)) {
+ from = fp.getWP(0).wp_name;
+ }
+
+ if ((fp.getWP(fp.getPlanSize() -1) != nil) and (fp.getWP(fp.getPlanSize() -1).wp_name != nil)) {
+ dest = fp.getWP(fp.getPlanSize() -1).wp_name;
+ }
+
+ if (fp.departure != nil) from = fp.departure.id;
+ if (fp.destination != nil) dest = fp.destination.id;
+ fp.id == from ~ " / " ~ dest;
+ }
+
+ # Activate flightplan
+ if (fp.getPlanSize() == 2) fgcommand("activate-flightplan", props.Node.new({"activate": 1}));
+},
+
# Retrieve the Airway waypoints on the current leg.
getAirwayWaypoints : func() {
var fp = flightplan();
@@ -220,6 +269,15 @@ setDirectTo : func(param)
setprop("/instrumentation/gps/command", "direct");
},
+setFMSMode : func(mode) {
+ if (NavDataInterface.FMS_MODES[mode] != nil) {
+ # mode is valid, so simply set it as the GPS command
+ setprop("/instrumentation/gps/command", mode);
+ } else {
+ die("Invalid FMS Mode " ~ mode);
+ }
+},
+
# Return the current DTO location to use
getCurrentDTO : func()
{
@@ -301,6 +359,15 @@ RegisterWithEmesary : func()
controller.setDefaultDTO(notification.EventParameter.Value);
return emesary.Transmitter.ReceiptStatus_Finished;
}
+ if (id == "SetFMSMode") {
+ controller.setFMSMode(notification.EventParameter.Value);
+ return emesary.Transmitter.ReceiptStatus_Finished;
+ }
+ if (id == "InsertWaypoint") {
+ controller.insertWaypoint(notification.EventParameter.Value);
+ return emesary.Transmitter.ReceiptStatus_Finished;
+ }
+
}
return emesary.Transmitter.ReceiptStatus_NotProcessed;
};
diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFD.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFD.nas
index c00e14807..6a450234a 100644
--- a/Aircraft/Instruments-3d/FG1000/Nasal/MFD.nas
+++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFD.nas
@@ -38,8 +38,8 @@ var MFDPages = [
"XMRadio",
"XMInfo",
"SystemStatus",
- "ActiveFlightPlanWide",
"ActiveFlightPlanNarrow",
+ "ActiveFlightPlanWide",
"FlightPlanCatalog",
"StoredFlightPlan",
"Checklist1",
@@ -54,6 +54,7 @@ var MFDPages = [
"NearestUserWPT",
"NearestFrequencies",
"NearestAirspaces",
+ "WaypointEntry",
"DirectTo",
"Surround",
];
@@ -117,6 +118,11 @@ var MFDDisplay =
obj._DTO = fg1000.DirectTo.new(obj, myCanvas, obj._MFDDevice, obj._svg);
obj._DTO.getController().RegisterWithEmesary();
+ # Next, the WaypointEntry "Page" so that it too receives any Emesary notifications
+ # _before_ the actual page.
+ obj._WaypointEntry = fg1000.WaypointEntry.new(obj, myCanvas, obj._MFDDevice, obj._svg);
+ obj._WaypointEntry.getController().RegisterWithEmesary();
+
obj._MFDDevice.RegisterWithEmesary();
# Surround dynamic elements
@@ -139,7 +145,7 @@ var MFDDisplay =
# Now load the other pages normally;
foreach (var page; MFDPages) {
- if ((page != "NavigationMap") and (page != "EIS") and (page != "DirectTo")) {
+ if ((page != "NavigationMap") and (page != "EIS") and (page != "DirectTo") and (page != "WaypointEntry")) {
#var code = "obj.Surround.addPage(\"" ~ page ~ "\", fg1000." ~ page ~ ".new(obj, myCanvas, obj._MFDDevice, obj._svg));";
var code = "obj.addPage(\"" ~ page ~ "\", fg1000." ~ page ~ ".new(obj, myCanvas, obj._MFDDevice, obj._svg));";
var addPageFn = compile(code);
diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPage.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPage.nas
index c3af81dad..557cf1611 100644
--- a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPage.nas
+++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPage.nas
@@ -129,6 +129,37 @@ setTextElement : func(symbolName, value) {
sym.setValue(value);
},
+setTextElementLat : func(symbolName, value) {
+ var degrees_part = int(value);
+
+ if (degrees_part == nil) {
+ me.setTextElement(symbolName, "_ __°__.__'");
+ } else {
+ var minutes_part = 100.0 * (value - degrees_part);
+ if (value < 0.0) {
+ me.setTextElement(symbolName, sprintf("S %2d°%.2f'", -degrees_part, -minutes_part));
+ } else {
+ me.setTextElement(symbolName, sprintf("N %2d°%.2f'", degrees_part, minutes_part));
+ }
+ }
+},
+
+setTextElementLon : func(symbolName, value) {
+ var degrees_part = int(value);
+
+ if (degrees_part == nil) {
+ me.setTextElement(symbolName, "____°__.__'");
+ } else {
+ var minutes_part = 100.0 * (value - degrees_part);
+ if (value < 0.0) {
+ me.setTextElement(symbolName, sprintf("W%3d°%.2f'", -degrees_part, -minutes_part));
+ } else {
+ me.setTextElement(symbolName, sprintf("E%3d°%.2f'", degrees_part, minutes_part));
+ }
+ }
+},
+
+
# Function to undo any colors set by display_toggle when loading a new menu
resetMenuColors : func() {
for(var i = 0; i < 12; i +=1) {
@@ -159,6 +190,6 @@ getSVG : func() {
},
getGroup : func() {
return me._group;
-}
+},
};
diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPageController.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPageController.nas
index 92a014128..4d9497f2c 100644
--- a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPageController.nas
+++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPageController.nas
@@ -30,10 +30,6 @@ new : func (page)
obj._page = page;
obj._transmitter = emesary.GlobalTransmitter;
obj._registered = 0;
-
- # DirectTo controls
- obj._directTo = 0;
-
return obj;
},
@@ -70,9 +66,19 @@ handleComFreqTransferHold : func (value) { return me.page.mfd.SurroundController
handleComVol : func (value) { return me.page.mfd.SurroundController.handleComVol(value); },
handleComVolToggle : func (value) { return me.page.mfd.SurroundController.handleComVolToggle(value); },
-# DTO button brings up the DirectTo Page.
handleDTO : func (value) { return emesary.Transmitter.ReceiptStatus_NotProcessed; },
-handleFPL : func (value) { return emesary.Transmitter.ReceiptStatus_NotProcessed; },
+
+
+handleFPL : func (value) {
+ var fppage = me._page.getMFD().getPage("ActiveFlightPlanNarrow");
+ if (fppage != nil) {
+ me._page.getDevice().selectPage(fppage);
+ return emesary.Transmitter.ReceiptStatus_Finished;
+ } else {
+ return emesary.Transmitter.ReceiptStatus_NotProcessed;
+ }
+},
+
handleClear : func (value) { return emesary.Transmitter.ReceiptStatus_NotProcessed; },
# Holding the Clear button goes straight to the Navigation Map page.
@@ -203,7 +209,7 @@ setDefaultDTOWayPoint : func(id)
},
getDeviceID : func() {
- return me.page.mfd.getDeviceID();
+ return me._page.mfd.getDeviceID();
},
diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/ActiveFlightPlanNarrow/ActiveFlightPlanNarrow.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/ActiveFlightPlanNarrow/ActiveFlightPlanNarrow.nas
index f5209b91a..a421512ce 100644
--- a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/ActiveFlightPlanNarrow/ActiveFlightPlanNarrow.nas
+++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/ActiveFlightPlanNarrow/ActiveFlightPlanNarrow.nas
@@ -17,6 +17,8 @@
# ActiveFlightPlanNarrow
var ActiveFlightPlanNarrow =
{
+ SHORTCUTS : [ "FPL", "NRST", "RECENT", "USER", "AIRWAY" ],
+
new : func (mfd, myCanvas, device, svg)
{
var obj = {
@@ -24,8 +26,45 @@ var ActiveFlightPlanNarrow =
ActiveFlightPlanNarrow,
MFDPage.new(mfd, myCanvas, device, svg, "ActiveFlightPlanNarrow", "FPL - ACTIVE FLIGHT PLAN")
],
+ current_flightplan : nil,
};
+ # Scrolling list of waypoints. We have _two_ lists here as we use one
+ # Arrow highlight element to show the current leg, and another to allow
+ # the FMS knob to highlight a waypoint for insertion/deletion or to make
+ # active.
+ obj.flightplanList = PFD.GroupElement.new(
+ obj.pageName,
+ svg,
+ [ "Header", "Leg", "DTK", "DIS", "ALT"],
+ 11,
+ "Leg",
+ 0,
+ "ScrollTrough",
+ "ScrollThumb",
+ 180
+ );
+
+ obj.currentLegIndicator = PFD.GroupElement.new(
+ obj.pageName,
+ svg,
+ [ "Arrow"],
+ 11,
+ "Arrow",
+ 1,
+ );
+
+ obj.Map = fg1000.NavMap.new(
+ obj,
+ obj.getElement("NavMap"),
+ #[360, 275],
+ #[fg1000.MAP_PARTIAL.CENTER.X, fg1000.MAP_PARTIAL.CENTER.Y],
+ [860,400],
+ #"rect(345, 233, -345, -233)",
+ "",
+ -50,
+ 2);
+
obj.topMenu(device, obj, nil);
obj.setController(fg1000.ActiveFlightPlanNarrowController.new(obj, svg));
@@ -42,18 +81,111 @@ var ActiveFlightPlanNarrow =
me.device.svg.getElementById(name ~ "-bg").setColorFill(0.0,0.0,0.0);
me.device.svg.getElementById(name).setColor(1.0,1.0,1.0);
}
+ me.getElement("NavMap").setVisible(0);
+ me.Map.setVisible(0);
me.getController().offdisplay();
},
ondisplay : func() {
me._group.setVisible(1);
me.mfd.setPageTitle(me.title);
+ me.getElement("NavMap").setVisible(1);
+ me.Map.setVisible(1);
me.getController().ondisplay();
},
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);
+
device.updateMenus();
},
+ # Update the FlightPlan display with an updated flightplan.
+ setFlightPlan : func(fp, current_wp) {
+ var elements = [];
+ var arrowElements = [];
+ if (fp == nil) {
+ me.flightplanList.setValues([]);
+ me.flightplanList.setCRSR(0);
+ me.flightplanList.displayGroup();
+ me.currentLegIndicator.setValues([]);
+ me.currentLegIndicator.setCRSR(0);
+ me.currentLegIndicator.displayGroup();
+ return;
+ }
+
+ for (var i = 0; i < fp.getPlanSize(); i = i + 1) {
+ var wp = fp.getWP(i);
+
+ var element = {
+ Header : "",
+ Leg : "",
+ DTK : "",
+ DIS : "",
+ ALT : "_____ft",
+ };
+
+ if (wp.wp_name != nil) {
+ element.Leg = substr(wp.wp_name, 0, 7);
+ } else {
+ element.Leg = "____";
+ }
+
+ if (i == 0) {
+ element.DIS = "";
+ element.DTK = "";
+ element.ALT = "_____ft";
+ } else if (i < current_wp) {
+ # Passed waypoints are blanked out on the display
+ element.DIS = "___nm";
+ element.DTK = "___°";
+ element.ALT = "_____ft";
+ } else {
+ if (wp.leg_distance != nil) element.DIS = sprintf("%.1fnm", wp.leg_distance);
+ if (wp.leg_bearing != nil) element.DTK = sprintf("%03d°", wp.leg_bearing);
+ if (wp.alt_cstr_type != nil) element.ALT = sprintf("%dft", wp.alt_cstr);
+ }
+
+ append(elements, element);
+ append(arrowElements, { Arrow : i});
+ }
+
+ me.flightplanList.setValues(elements);
+ me.currentLegIndicator.setValues(arrowElements);
+
+ if (current_wp == -1) {
+ me.flightplanList.setCRSR(0);
+ me.currentLegIndicator.setCRSR(0);
+ } else {
+ me.flightplanList.setCRSR(current_wp);
+ me.currentLegIndicator.setCRSR(current_wp);
+ }
+
+ me.flightplanList.displayGroup();
+ me.currentLegIndicator.displayGroup();
+
+ # Determine a suitable name to display, using the flightplan name if there is one,
+ # but falling back to the flightplan departure / destination airports, or failing
+ # that the IDs of the first and last waypoints.
+ if ((fp.id == nil) or (fp.id == "default-flightplan")) {
+ var from = "????";
+ var dest = "????";
+
+ if ((fp.getWP(0) != nil) and (fp.getWP(0).wp_name != nil)) {
+ from = fp.getWP(0).wp_name;
+ }
+
+ if ((fp.getWP(fp.getPlanSize() -1) != nil) and (fp.getWP(fp.getPlanSize() -1).wp_name != nil)) {
+ dest = fp.getWP(fp.getPlanSize() -1).wp_name;
+ }
+
+ if (fp.departure != nil) from = fp.departure.id;
+ if (fp.destination != nil) dest = fp.destination.id;
+ me.getElement("Name").setText(from ~ " / " ~ dest);
+ } else {
+ me.getElement("Name").setText(fp.id);
+ }
+ },
};
diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/ActiveFlightPlanNarrow/ActiveFlightPlanNarrowController.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/ActiveFlightPlanNarrow/ActiveFlightPlanNarrowController.nas
index 56f8d3821..c6d6dea18 100644
--- a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/ActiveFlightPlanNarrow/ActiveFlightPlanNarrowController.nas
+++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/ActiveFlightPlanNarrow/ActiveFlightPlanNarrowController.nas
@@ -24,24 +24,44 @@ var ActiveFlightPlanNarrowController =
_crsrToggle : 0,
_recipient : nil,
_page : page,
+ _fp_current_wp : 0,
+ _fp_active : 0,
+ _current_flightplan : nil,
+ _fprecipient : nil,
+ transmitter : nil,
+ _waypointSubmenuVisible : 0,
};
+ obj._current_flightplan = obj.getNavData("Flightplan");
+ if (obj._current_flightplan != nil) {
+ obj._fp_current_wp = obj._current_flightplan.current;
+ obj._page.setFlightPlan(obj._current_flightplan, obj._fp_current_wp);
+ } else {
+ obj._page.setFlightPlan(nil, nil);
+ }
+
return obj;
},
-
# Input Handling
handleCRSR : func() {
me._crsrToggle = (! me._crsrToggle);
if (me._crsrToggle) {
+ me._page.flightplanList.showCRSR();
} else {
- me._page.hideCRSR();
+ me._page.flightplanList.hideCRSR();
}
return emesary.Transmitter.ReceiptStatus_Finished;
},
handleFMSInner : func(value) {
if (me._crsrToggle == 1) {
- # Scroll through whatever is the current list
+ # Enable the WaypointEntry window
+ me._page.mfd._WaypointEntry.ondisplay();
+
+ # Also directly pass in the message. This is because the WaypointEntry page
+ # is above this in the Emesary stack, and as it was not displayed, it won't
+ # have picked up the message to display either an entry box or the submenu.
+ me._page.mfd._WaypointEntry.getController().handleFMSInner(value);
return emesary.Transmitter.ReceiptStatus_Finished;
} else {
# Pass to the page group controller to display and scroll through the page group menu
@@ -50,6 +70,7 @@ var ActiveFlightPlanNarrowController =
},
handleFMSOuter : func(value) {
if (me._crsrToggle == 1) {
+ me._page.flightplanList.incrLarge(value);
return emesary.Transmitter.ReceiptStatus_Finished;
} else {
# Pass to the page group controller to display and scroll through the page group menu
@@ -64,12 +85,177 @@ var ActiveFlightPlanNarrowController =
}
},
+ handleRange : func(val)
+ {
+ # Pass any range entries to the NavMapController
+ me._page.Map.handleRange(val);
+ },
+
+ # Handle the user entry of a waypoint. We now need to insert it into the
+ # flightplan at the point after the selected waypoint, then update the
+ # flightplan. This should cause a cascade of Emesary updates, which will
+ # subsequently update this display (and any others).
+ handleWaypointEntry : func(data) {
+ assert(data.id != nil, "handleWaypointEntry called with invalid hash");
+ # Place this after the current index
+ var params = {
+ index : me._page.flightplanList.getCRSR() + 1,
+ wp : data
+ };
+
+ # Update the FMS with the new flightplan via Emesary
+ var notification = notifications.PFDEventNotification.new(
+ "MFD",
+ me.getDeviceID(),
+ notifications.PFDEventNotification.NavData,
+ {Id: "InsertWaypoint", Value: params});
+
+ var response = me._transmitter.NotifyAll(notification);
+
+ if (me._transmitter.IsFailed(response)) {
+ print("ActiveFlightPlanNarrowController.handleWaypointEntry() : Failed to set FMS Data " ~ params);
+ debug.dump(params);
+ } else {
+ # The flightplan has changed. For some reason this isn't triggering an
+ # update from the flightplan delegate, so we'll just trigger an update
+ # ourselves.
+ var notification = notifications.PFDEventNotification.new(
+ "MFD",
+ 1,
+ notifications.PFDEventNotification.FMSData,
+ {"FMSFlightPlanEdited" : 1});
+
+ var response = me._transmitter.NotifyAll(notification);
+
+ if (me._transmitter.IsFailed(response)) {
+ print("ActiveFlightPlanNarrowController.handleWaypointEntry() : Failed to set FMS Data " ~ params);
+ debug.dump(params);
+ }
+ }
+
+ # Critically, only this page should handle the waypoint entry.
+ return emesary.Transmitter.ReceiptStatus_Finished;
+ },
+
+ # Handle update to the FMS information. Note that there is no guarantee
+ # that the entire set of FMS data will be available.
+ handleFMSData : func(data) {
+ var update_fp = 0;
+ var reload_fp = 0;
+
+ if (data["FMSLegID"] != nil) me._leg_id = data["FMSLegID"];
+
+ if ((data["FMSFlightPlanSequenced"] != nil) and (data["FMSFlightPlanSequenced"] != me._fp_current_wp)) {
+ me._fp_current_wp = data["FMSFlightPlanSequenced"];
+ update_fp = 1;
+ }
+
+ if (data["FMSFlightPlanEdited"] != nil) {
+ reload_fp = 1;
+ }
+
+ if ((data["FMSFlightPlanActive"] != nil) and (data["FMSFlightPlanActive"] != me._fp_active)) {
+ me._fp_active = data["FMSFlightPlanActive"];
+ if (me._fp_active) {
+ reload_fp = 1;
+ } else {
+ # No flightplan active, so we will display nothing.
+ me._current_flightplan = nil;
+ me._fp_current_wp = -1;
+ update_fp = 1;
+ }
+ }
+
+ if ((data["FMSFlightPlanCurrentWP"] != nil) and (data["FMSFlightPlanCurrentWP"] != me._fp_current_wp)) {
+ me._fp_current_wp = data["FMSFlightPlanCurrentWP"];
+ update_fp = 1;
+ }
+
+ if (reload_fp) {
+ # The flightplan has changed in some way, so reload it.
+ me._current_flightplan = me.getNavData("Flightplan");
+ if (me._current_flightplan != nil) {
+ me._fp_current_wp = me._current_flightplan.current;
+ update_fp = 1;
+ }
+ }
+
+ if (update_fp) {
+ #me._current_flightplan = me.getNavData("Flightplan");
+ me._page.setFlightPlan(me._current_flightplan, me._fp_current_wp);
+ }
+
+ return emesary.Transmitter.ReceiptStatus_OK;
+ },
+
# Reset controller if required when the page is displayed or hidden
ondisplay : func() {
me.RegisterWithEmesary();
+ me.FPRegisterWithEmesary();
},
offdisplay : func() {
me.DeRegisterWithEmesary();
+ me.FPDeRegisterWithEmesary();
},
+ FPRegisterWithEmesary : func(transmitter = nil){
+ if (transmitter == nil)
+ transmitter = emesary.GlobalTransmitter;
+
+ if (me._fprecipient == nil){
+ me._fprecipient = emesary.Recipient.new("ActiveFlightPlanNarrowController_" ~ me._page.device.designation);
+ var pfd_obj = me._page.device;
+ var controller = me;
+ me._fprecipient.Receive = func(notification)
+ {
+
+ if (notification.Device_Id == pfd_obj.device_id and
+ notification.NotificationType == notifications.PFDEventNotification.DefaultType and
+ notification.Event_Id == notifications.PFDEventNotification.FMSData and
+ notification.EventParameter != nil and
+ notification.EventParameter["Id"] == "SetWaypointEntry")
+ {
+ # Special case where THIS DEVICE has displayed the WaypointEntry page and
+ # we are now receiving the entered waypoint. In this case we need to
+ # determine where to enter it in the flightplan and update it.
+ return controller.handleWaypointEntry(notification.EventParameter.Value);
+ }
+
+ if (notification.NotificationType == notifications.PFDEventNotification.DefaultType and
+ notification.Event_Id == notifications.PFDEventNotification.FMSData and
+ notification.EventParameter != nil)
+ {
+ return controller.handleFMSData(notification.EventParameter);
+ }
+
+ return emesary.Transmitter.ReceiptStatus_NotProcessed;
+ };
+ }
+ transmitter.Register(me._fprecipient);
+ me.transmitter = transmitter;
+ },
+ FPDeRegisterWithEmesary : func(transmitter = nil){
+ # remove registration from transmitter; but keep the recipient once it is created.
+ if (me.transmitter != nil)
+ me.transmitter.DeRegister(me._fprecipient);
+ me.transmitter = nil;
+ },
+
+ getNavData : func(type, value=nil) {
+ # Use Emesary to get a piece from the NavData system, using the provided
+ # type and value;
+ var notification = notifications.PFDEventNotification.new(
+ "MFD",
+ me._page.mfd.getDeviceID(),
+ notifications.PFDEventNotification.NavData,
+ {Id: type, Value: value});
+
+ var response = me._transmitter.NotifyAll(notification);
+
+ if (! me._transmitter.IsFailed(response)) {
+ return notification.EventParameter.Value;
+ } else {
+ return nil;
+ }
+ },
};
diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/AirportInfo/AirportInfo.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/AirportInfo/AirportInfo.nas
index 06d5d19ad..5f1a51564 100644
--- a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/AirportInfo/AirportInfo.nas
+++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/AirportInfo/AirportInfo.nas
@@ -117,19 +117,8 @@ var AirportInfo =
me.setTextElement("City", "CITY");
me.setTextElement("Region", "REGION");
me.setTextElement("Alt", sprintf("%ift", M2FT * apt_info.elevation));
-
- if (apt_info.lat < 0.0) {
- me.setTextElement("Lat", sprintf("S %.4f", -apt_info.lat));
- } else {
- me.setTextElement("Lat", sprintf("N %.4f", apt_info.lat));
- }
-
- if (apt_info.lon < 0.0) {
- me.setTextElement("Lon", sprintf("W%3.4f", -apt_info.lon));
- } else {
- me.setTextElement("Lon", sprintf("E%3.4f", apt_info.lon));
- }
-
+ me.setTextElementLat("Lat", apt_info.lat);
+ me.setTextElementLon("Lon", apt_info.lon);
me.setTextElement("Fuel", "AVGAS, AVTUR");
me.setTextElement("TZ", "UTC-6");
diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/DirectTo/DirectTo.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/DirectTo/DirectTo.nas
index 79f90eca6..15dc5e4be 100644
--- a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/DirectTo/DirectTo.nas
+++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/DirectTo/DirectTo.nas
@@ -69,9 +69,8 @@ var DirectTo =
obj.WaypointSubmenuSelect = PFD.ScrollElement.new(obj.pageName, svg, "WaypointSubmenuSelect", DirectTo.SHORTCUTS);
obj.WaypointSubmenuScroll = PFD.GroupElement.new(obj.pageName, svg, [ "WaypointSubmenuScroll" ] , 4, "WaypointSubmenuScroll", 0, "WaypointSubmenuScrollTrough" , "WaypointSubmenuScrollThumb", 60);
- # The Airport Chart
+ # The Airport Chart - only displayed on the MFD variant (where thre's if there's a Map SVG element present)
if (obj.elementExists("Map")) {
- print("DirectoTo Map exists");
obj.DirectToChart = fg1000.NavMap.new(obj, obj.getElement("Map"), [860,440], "rect(-160px, 160px, 160px, -160px)", 0, 2, 1);
} else {
obj.DirectToChart = nil;
diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/DirectTo/DirectToController.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/DirectTo/DirectToController.nas
index 7704127b6..0c8a1854f 100644
--- a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/DirectTo/DirectToController.nas
+++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/DirectTo/DirectToController.nas
@@ -177,6 +177,8 @@ var DirectToController =
handleRange : func(val)
{
+ if (! me.dto_displayed) return emesary.Transmitter.ReceiptStatus_NotProcessed;
+
if (me.page.DirectToChart != nil) {
return me.page.DirectToChart.handleRange(val);
} else {
@@ -336,7 +338,7 @@ var DirectToController =
# Some elements don't have names
var name = destination.id;
- if (!defined("destination.name")) name = destination.name;
+ if (defined("destination.name")) name = destination.name;
var point = { lat: destination.lat, lon: destination.lon };
var (course, dist) = courseAndDistance(point);
diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/NavigationMap/NavigationMapController.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/NavigationMap/NavigationMapController.nas
index 52f21345f..4ec647340 100644
--- a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/NavigationMap/NavigationMapController.nas
+++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/NavigationMap/NavigationMapController.nas
@@ -17,15 +17,6 @@
# Navigation Map Controller
var NavigationMapController =
{
- # TODO: Add STAMEN topo layer, which is visible on all levels as opposed to
- # roads, railways, boundaries, cities which are only visible on declutter 0.
-
- # Declutter levels.
- DCLTR : [ "DCLTR", "DCLTR-1", "DCLTR-2", "DCLTR-3"],
-
- # Airways levels.
- AIRWAYS : [ "AIRWAYS", "AIRWY ON", "AIRWY LO", "AIRWY HI"],
-
new : func (page, svg)
{
var obj = { parents : [ NavigationMapController, MFDPageController.new(page) ] };
diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/PFDInstruments/PFDInstruments.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/PFDInstruments/PFDInstruments.nas
index c782d9813..5093f71c0 100644
--- a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/PFDInstruments/PFDInstruments.nas
+++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/PFDInstruments/PFDInstruments.nas
@@ -95,6 +95,7 @@ var PFDInstruments =
);
obj.setController(fg1000.PFDInstrumentsController.new(obj, svg));
+
obj.setWindDisplay(0);
obj.setCDISource("GPS");
obj.setBRG1("OFF");
@@ -728,6 +729,8 @@ var PFDInstruments =
if (fp == nil) return;
+ var current_wp = fp.current;
+
for (var i = 0; i < fp.getPlanSize(); i = i + 1) {
var wp = fp.getWP(i);
@@ -736,22 +739,30 @@ var PFDInstruments =
FlightPlanID : "",
FlightPlanType : "",
FlightPlanDTK : 0,
- FlightPlanDIS : 0
+ FlightPlanDIS : 0,
};
if (wp.wp_name != nil) element.FlightPlanID = substr(wp.wp_name, 0, 7);
if (wp.wp_role != nil) element.FlightPlanType = substr(wp.wp_role, 0, 4);
- if (wp.leg_distance != nil) element.FlightPlanDIS = sprintf("%.1fnm", wp.leg_distance);
- if (wp.leg_bearing != nil) element.FlightPlanDTK = sprintf("%03d°", wp.leg_bearing);
+
+ if (i < current_wp) {
+ # Passed waypoints are blanked out on the display
+ element.FlightPlanDIS = "___nm";
+ element.FlightPlanDTK = "___°";
+ } else {
+ if (wp.leg_distance != nil) element.FlightPlanDIS = sprintf("%.1fnm", wp.leg_distance);
+ if (wp.leg_bearing != nil) element.FlightPlanDTK = sprintf("%03d°", wp.leg_bearing);
+ }
append(elements, element);
}
me.flightplanList.setValues(elements);
+ me.flightplanList.setCRSR(current_wp);
# Determine a suitable name to display, using the flightplan name if there is one,
# but falling back to the flightplan departure / destination airports, or failing
# that the IDs of the first and last waypoints.
- if (fp.id == nil) {
+ if ((fp.id == nil) or (fp.id == "default-flightplan")) {
var from = "????";
var dest = "????";
diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/PFDInstruments/PFDInstrumentsController.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/PFDInstruments/PFDInstrumentsController.nas
index cd9f1fa2a..23c8cebd9 100644
--- a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/PFDInstruments/PFDInstrumentsController.nas
+++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/PFDInstruments/PFDInstrumentsController.nas
@@ -131,6 +131,13 @@ var PFDInstrumentsController =
var incr_or_decr = (val > 0) ? me.page.insetMap.zoomIn() : me.page.insetMap.zoomOut();
},
+ handleFPL : func (value) {
+ # Display/hide the FPL display
+ me._fp_visible = (! me._fp_visible);
+ me.page.setFlightPlanVisible(me._fp_active and me._fp_visible);
+ return emesary.Transmitter.ReceiptStatus_Finished;
+ },
+
# Set the STD BARO to 29.92 in Hg
setStdBaro : func() {
var data = {};
@@ -254,12 +261,17 @@ var PFDInstrumentsController =
if (data["FMSFlightPlanEdited"] != nil) {
# The flightplan has changed in some way, so reload it.
- update_fp = 1;
+ me._current_flightplan = me.getNavData("Flightplan");
+ if (me._current_flightplan != nil) {
+ me._fp_current_wp = me._current_flightplan.current;
+ me.page.setFlightPlan(me._current_flightplan);
+ update_fp = 1;
+ }
}
if ((data["FMSFlightPlanActive"] != nil) and (data["FMSFlightPlanActive"] != me._fp_active)) {
me._fp_active = data["FMSFlightPlanActive"];
- me.page.setFlightPlanVisible(me._fp_active);
+ me.page.setFlightPlanVisible(me._fp_active and me._fp_visible);
update_fp = 1;
}
@@ -268,16 +280,7 @@ var PFDInstrumentsController =
update_fp = 1;
}
- if (update_fp and me._fp_active) {
- # For some reason the signals to indicate a FP change aren't firing, so reload the
- # flightplan here
- me._current_flightplan = me.getNavData("Flightplan");
- if (me._current_flightplan != nil) {
- me._fp_current_wp = me._current_flightplan.current;
- me.page.setFlightPlan(me._current_flightplan);
- update_fp = 1;
- }
-
+ if (me._fp_visible and update_fp and me._fp_active) {
me.page.updateFlightPlan(me._fp_current_wp);
}
diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/Surround/Surround.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/Surround/Surround.nas
index c4f2b78e3..c38371be0 100644
--- a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/Surround/Surround.nas
+++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/Surround/Surround.nas
@@ -40,7 +40,7 @@ var PAGE_GROUPS = [
{ label: "FPLGroupLabel",
group: "FPLPageGroup",
- pages: [ "ActiveFlightPlanWide", "FlightPlanCatalog", "StoredFlightPlan"],
+ pages: [ "ActiveFlightPlanNarrow", "FlightPlanCatalog", "StoredFlightPlan"],
},
{ label: "LstGroupLabel",
diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/DirectTo.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/WaypointEntry/WaypointEntry.nas
similarity index 50%
rename from Aircraft/Instruments-3d/FG1000/Nasal/DirectTo.nas
rename to Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/WaypointEntry/WaypointEntry.nas
index 889355a7c..bd4f0e90f 100644
--- a/Aircraft/Instruments-3d/FG1000/Nasal/DirectTo.nas
+++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/WaypointEntry/WaypointEntry.nas
@@ -14,14 +14,11 @@
# You should have received a copy of the GNU General Public License
# along with FlightGear. If not, see .
#
-# DirectTo page
-#
-# Technically this is supposed to be an overlay page, sitting on top of
-# whatever page the user was on already. However, to simplify implementation,
-# we will assume that the user was on the Map page, and simply display the
-# NavigationMap page underneath.
+# WaypointEntry page. This is an overlay, sitting on whatever page the user
+# is on already. Hence it is not called in the normal way, but instead
+# explicitly called by Flightplan pages to insert a waypoint.
-var DirectTo =
+var WaypointEntry =
{
SHORTCUTS : [ "FPL", "NRST", "RECENT", "USER", "AIRWAY" ],
@@ -29,21 +26,23 @@ var DirectTo =
{
var obj = {
parents : [
- DirectTo,
- MFDPage.new(mfd, myCanvas, device, svg, "DirectTo", "DIRECT TO")
+ WaypointEntry,
+ MFDPage.new(mfd, myCanvas, device, svg, "WaypointEntry", "")
],
symbols : {},
};
obj.crsrIdx = 0;
- # Dynamic text elements in the SVG file. In the SVG these have an "DirectTo" prefix.
+ # Dynamic text elements in the SVG file. In the SVG these have an "WaypointEntry" prefix.
textelements = [
"Name",
"City",
"Region",
"LocationBRG",
"LocationDIS",
+ "LocationLat",
+ "LocationLon",
];
obj.addTextElements(textelements);
@@ -59,88 +58,62 @@ var DirectTo =
# .chars is the set of characters, used to scroll through using the small
# FMS knob.
obj.IDEntry = PFD.DataEntryElement.new(obj.pageName, svg, "ID", "", 4, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
- obj.VNVAltEntry = PFD.DataEntryElement.new(obj.pageName, svg, "VNVAlt", "", 5, "0123456789");
- obj.VNVOffsetEntry = PFD.DataEntryElement.new(obj.pageName, svg, "VNVOffset", "", 2, "0123456789");
- obj.CourseEntry = PFD.DataEntryElement.new(obj.pageName, svg, "Course", "", 3, "0123456789");
- obj.Activate = PFD.TextElement.new(obj.pageName, svg, "Activate", "ACTIVATE?");
# The Shortcut window. This allows the user to scroll through a set of lists
# of waypoints.
- obj.WaypointSubmenuGroup = obj._SVGGroup.getElementById("DirectToWaypointSubmenuGroup");
- assert(obj.WaypointSubmenuGroup != nil, "Unable to find DirectToWaypointSubmenuGroup");
+ obj.WaypointSubmenuGroup = obj._SVGGroup.getElementById("WaypointEntryWaypointSubmenuGroup");
+ assert(obj.WaypointSubmenuGroup != nil, "Unable to find WaypointEntryWaypointSubmenuGroup");
obj.WaypointSubmenuGroup.setVisible(0);
- obj.WaypointSubmenuSelect = PFD.ScrollElement.new(obj.pageName, svg, "WaypointSubmenuSelect", DirectTo.SHORTCUTS);
+ obj.WaypointSubmenuSelect = PFD.ScrollElement.new(obj.pageName, svg, "WaypointSubmenuSelect", WaypointEntry.SHORTCUTS);
obj.WaypointSubmenuScroll = PFD.GroupElement.new(obj.pageName, svg, [ "WaypointSubmenuScroll" ] , 4, "WaypointSubmenuScroll", 0, "WaypointSubmenuScrollTrough" , "WaypointSubmenuScrollThumb", 60);
- # The Airport Chart
+ # The Airport Chart - only displayed on the MFD variant (where thre's if there's a Map SVG element present)
if (obj.elementExists("Map")) {
- obj.DirectToChart = fg1000.NavMap.new(obj, obj.getElement("Map"), [860,440], "rect(-160px, 160px, 160px, -160px)", 0, 2, 1);
+ obj.WaypointEntryChart = fg1000.NavMap.new(obj, obj.getElement("Map"), [860,440], "rect(-160px, 160px, 160px, -160px)", 0, 2, 1);
+ } else {
+ obj.WaypointEntryChart = nil;
}
- obj.setController(fg1000.DirectToController.new(obj, svg));
+ obj.setController(fg1000.WaypointEntryController.new(obj, svg));
return obj;
},
+
displayDestination : func(destination) {
-
- #me.IDEntry.clearElement();
-
if (destination != nil) {
# Display a given location
- if (me.DirectToChart) {
- me.DirectToChart.setVisible(1);
- me.DirectToChart.getController().setPosition(destination.lat,destination.lon);
+ if (me.WaypointEntryChart != nil) {
+ me.WaypointEntryChart.setVisible(1);
+ me.WaypointEntryChart.getController().setPosition(destination.lat,destination.lon);
}
me.setTextElement("Name", string.uc(destination.name));
- me.setTextElement("City", "CITY");
- me.setTextElement("Region", "REGION");
- me.setTextElement("LocationBRG", "" ~ sprintf("%03d°", destination.course));
- me.setTextElement("LocationDIS", sprintf("%d", destination.range_nm) ~ "nm");
-
- me.IDEntry.setValue(destination.id);
- me.VNVAltEntry.setValue("00000");
- me.VNVOffsetEntry.setValue("00");
- me.CourseEntry.setValue("" ~ sprintf("%03d°", destination.course));
- } else {
- if (me.DirectToChart) me.DirectToChart.setVisible(0);
- me.setTextElement("Name", "");
me.setTextElement("City", "");
me.setTextElement("Region", "");
- me.setTextElement("LocationBRG", "_");
- me.setTextElement("LocationDIS", "_");
-
- me.IDEntry.setValue("____");
- me.VNVAltEntry.setValue("00000");
- me.VNVOffsetEntry.setValue("00");
- me.CourseEntry.setValue(0);
+ me.setTextElement("LocationBRG", "" ~ sprintf("%03d°", destination.course));
+ me.setTextElement("LocationDIS", sprintf("%d", destination.range_nm) ~ "nm");
+ me.setTextElementLat("LocationLat", destination.lat);
+ me.setTextElementLon("LocationLon", destination.lon);
+ me.IDEntry.setValue(destination.id);
+ } else {
+ if (me.WaypointEntryChart != nil) me.WaypointEntryChart.setVisible(0);
+ me.setTextElement("Name", "___");
+ me.setTextElement("City", "____________");
+ me.setTextElement("Region", "____________");
+ me.setTextElement("LocationBRG", "___°");
+ me.setTextElement("LocationDIS", "__._nm");
+ me.setTextElement("LocationLat", "_ __°__.__'");
+ me.setTextElement("LocationLon", "____°__.__'");
+ me.IDEntry.setValue("####");
}
},
offdisplay : func() {
me._group.setVisible(0);
+ me.getElement("Group").setVisible(0);
me.getController().offdisplay();
- me.mfd.NavigationMap.offdisplay(0);
},
ondisplay : func() {
me._group.setVisible(1);
- # Display a false title, as underneath we're showing the navigation map.
- me.mfd.setPageTitle("MAP - NAVIGATION MAP");
- me.getElement("Map").setVisible(1);
- me.getElement("Map-bg").setVisible(1);
- if (me.DirectToChart) me.DirectToChart.setVisible(1);
+ me.getElement("Group").setVisible(1);
me.getController().ondisplay();
-
- # The DirectTo pages displays over the NavigationMap. This is a hack
- # as the page should just magically sit ontop of whatever page the user was
- # on. However, we also need to disable the NavMap's own controller so there's
- # no confusion.
- me.mfd.NavigationMap.ondisplay(0);
},
-
- # When the Direct To display is enabled, nothing is displayed on the softkeys.
- topMenu : func(device, pg, menuitem) {
- pg.clearMenu();
- pg.resetMenuColors();
- device.updateMenus();
- },
-
};
diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/WaypointEntry/WaypointEntryController.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/WaypointEntry/WaypointEntryController.nas
new file mode 100644
index 000000000..f269ea432
--- /dev/null
+++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/WaypointEntry/WaypointEntryController.nas
@@ -0,0 +1,314 @@
+# Copyright 2018 Stuart Buchanan
+# This file is part of FlightGear.
+#
+# Foobar 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.
+#
+# 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 .
+#
+# WaypointEntry Controller
+var WaypointEntryController =
+{
+ new : func (page, svg)
+ {
+ var obj = { parents : [ WaypointEntryController, MFDPageController.new(page)] };
+ obj.id = "";
+ obj.page = page;
+ obj._wpentry_displayed = 0;
+ obj._destination = nil;
+
+ obj._cursorElements = [
+ obj.page.IDEntry,
+ ];
+
+ obj._activateIndex = size(obj._cursorElements) - 1;
+
+ obj._selectedElement = 0;
+
+ # Whether the WaypointSubmenuGroup is enabled
+ obj._waypointSubmenuVisible = 0;
+
+ return obj;
+ },
+
+ setCursorElement : func(value) {
+
+ for (var i = 0; i < size(me._cursorElements); i = i+1) {
+ me._cursorElements[i].unhighlightElement();
+ }
+
+ if (value < 0) value = 0;
+ if (value > (size(me._cursorElements) -1)) value = size(me._cursorElements) -1;
+ me._selectedElement = value;
+ me._cursorElements[me._selectedElement].highlightElement();
+ },
+
+ nextCursorElement : func(value) {
+ var incr_or_decr = (value > 0) ? 1 : -1;
+ me.setCursorElement(me._selectedElement + incr_or_decr);
+ },
+
+ handleCRSR : func() {
+ if (! me._wpentry_displayed) return emesary.Transmitter.ReceiptStatus_NotProcessed;
+
+ # No effect, but shouldn't be passed to underlying page?
+ return emesary.Transmitter.ReceiptStatus_Finished;
+ },
+ updateWaypointSubmenu : func() {
+ var type = me.page.WaypointSubmenuSelect.getValue();
+
+ var items = [];
+
+ if (type == "FPL") {
+ # Get the contents of the flightplan and display the list of waypoints.
+ var fp = me.getNavData("Flightplan");
+
+ for (var i = 0; i < fp.getPlanSize(); i = i + 1) {
+ var wp = fp.getWP(i);
+ if (wp.wp_name != nil) append(items, wp.wp_name);
+ }
+ }
+
+ if (type == "NRST") {
+ # Get the nearest airports
+ var apts = me.getNavData("NearestAirports");
+
+ for (var i = 0; i < size(apts); i = i + 1) {
+ var apt = apts[i];
+ if (apt.id != nil) append(items, apt.id);
+ }
+ }
+
+ if (type == "RECENT") {
+ # Get the set of recent waypoints
+ items = me.getNavData("RecentWaypoints");
+ }
+
+ if (type == "USER") {
+ items = me.getNavData("UserWaypoints");
+ }
+
+ if (type == "AIRWAY") {
+ var airways = me.getNavData("AirwayWaypoints");
+ if (airways != nil) {
+ foreach (var wp; airways) {
+ if (wp.wp_name != nil) append(items, wp.wp_name);
+ }
+ }
+ }
+
+ if ((items != nil) and (size(items) > 0)) {
+ # At this point we have a vector of waypoint names. We need to convert
+ # this into a vector of { "WaypointSubmenuScroll" : [name] } hashes for consumption by the
+ # list of waypoints
+ var groupitems = [];
+ foreach (var item; items) {
+ append(groupitems, { "WaypointSubmenuScroll" : item } );
+ }
+
+ # Now display them!
+ me.page.WaypointSubmenuScroll.setValues(groupitems);
+ } else {
+ # Nothing to display
+ me.page.WaypointSubmenuScroll.setValues([]);
+ }
+ },
+
+ getNavData : func(type, value=nil) {
+ # Use Emesary to get a piece from the NavData system, using the provided
+ # type and value;
+ var notification = notifications.PFDEventNotification.new(
+ "MFD",
+ me.getDeviceID(),
+ notifications.PFDEventNotification.NavData,
+ {Id: type, Value: value});
+
+ var response = me._transmitter.NotifyAll(notification);
+
+ if (! me._transmitter.IsFailed(response)) {
+ return notification.EventParameter.Value;
+ } else {
+ return nil;
+ }
+ },
+
+ setFMSData : func(type, value=nil) {
+ # Use Emesary to set a piece of data in the NavData system, using the provided
+ # type and value;
+ var notification = notifications.PFDEventNotification.new(
+ "MFD",
+ me.getDeviceID(),
+ notifications.PFDEventNotification.FMSData,
+ {Id: type, Value: value});
+
+ var response = me._transmitter.NotifyAll(notification);
+
+ if (me._transmitter.IsFailed(response)) {
+ print("WaypointEntryController.setNavData() : Failed to set Nav Data " ~ value);
+ debug.dump(value);
+ }
+ },
+
+ handleRange : func(val)
+ {
+ if (! me._wpentry_displayed) return emesary.Transmitter.ReceiptStatus_NotProcessed;
+
+ if (me.page.WaypointEntryChart != nil) {
+ return me.page.WaypointEntryChart.handleRange(val);
+ } else {
+ return emesary.Transmitter.ReceiptStatus_NotProcessed;
+ }
+ },
+
+ handleFMSInner : func(value) {
+ if (! me._wpentry_displayed) return emesary.Transmitter.ReceiptStatus_NotProcessed;
+
+ if (me._waypointSubmenuVisible) {
+ # We're in the Waypoint Submenu, in which case the inner FMS knob
+ # selects between the different waypoint types.
+ me.page.WaypointSubmenuSelect.highlightElement();
+ me.page.WaypointSubmenuSelect.incrSmall(value);
+ # Now update the Scroll group with the new type of waypoints
+ me.updateWaypointSubmenu();
+ } else if ((me._selectedElement == 0) and (! me.page.IDEntry.isInEdit()) and (value == -1)) {
+ # The WaypointSubmenuGroup group is displayed if the small FMS knob is rotated
+ # anti-clockwise as an initial rotation where the ID Entry is not being editted.
+ me._cursorElements[0].unhighlightElement();
+
+ me.page.WaypointSubmenuGroup.setVisible(1);
+ me.page.WaypointSubmenuSelect.highlightElement();
+ me._waypointSubmenuVisible = 1;
+ me.updateWaypointSubmenu();
+ } else {
+ # We've already got something selected, and we're not in the
+ # WaypointSubmenuGroup, so increment it.
+ me._cursorElements[me._selectedElement].incrSmall(value);
+ }
+
+ return emesary.Transmitter.ReceiptStatus_Finished;
+ },
+
+ handleFMSOuter : func(value) {
+ if (! me._wpentry_displayed) return emesary.Transmitter.ReceiptStatus_NotProcessed;
+
+ if (me._waypointSubmenuVisible) {
+ # We're in the Waypoint Submenu, in which case the outer FMS knob
+ # selects between the different waypoints in the Waypoint Submenu.
+ me.page.WaypointSubmenuSelect.unhighlightElement();
+ me.page.WaypointSubmenuScroll.showCRSR();
+ me.page.WaypointSubmenuScroll.incrLarge(value);
+ } else if (me._cursorElements[me._selectedElement].isInEdit()) {
+ # If we're editing an element, then get on with it!
+ me._cursorElements[me._selectedElement].incrLarge(value);
+ } else {
+ me.nextCursorElement(value);
+ }
+
+ return emesary.Transmitter.ReceiptStatus_Finished;
+ },
+
+ handleEnter : func(value) {
+ if (! me._wpentry_displayed) return emesary.Transmitter.ReceiptStatus_NotProcessed;
+
+ if (me._waypointSubmenuVisible) {
+ # If we're in the Waypoint Submenu, then take whatever is highlighted
+ # in the scroll list, load it and hide the Waypoint submenu
+ var id = me.page.WaypointSubmenuScroll.getValue();
+ if (id != nil) me.loadDestination(id);
+ me.page.WaypointSubmenuGroup.setVisible(0);
+ me._waypointSubmenuVisible = 0;
+ } else if (me.page.IDEntry.isInEdit()) {
+ # If we're editing an element, complete the data entry, the load it.
+ me.page.IDEntry.enterElement();
+ me.loadDestination(me.page.IDEntry.getValue());
+ } else {
+ # Pass the entered waypoint to the surrounding page TODO
+ me.setFMSData("SetWaypointEntry", me._destination);
+
+ me._wpentry_displayed = 0;
+ me.page.offdisplay();
+
+ return emesary.Transmitter.ReceiptStatus_Finished;
+ }
+
+ return emesary.Transmitter.ReceiptStatus_Finished;
+ },
+
+ handleClear : func(value) {
+ if (! me._wpentry_displayed) return emesary.Transmitter.ReceiptStatus_NotProcessed;
+
+ if (me._waypointSubmenuVisible) {
+ # If we're in the Waypoint Submenu, then this clears it.
+ me.page.WaypointSubmenuGroup.setVisible(0);
+ me._waypointSubmenuVisible = 0;
+ } else if (me._cursorElements[me._selectedElement].isInEdit()) {
+ me._cursorElements[me._selectedElement].clearElement();
+ } else {
+ # Cancel the entire Waypoint Entry page.
+ me._wpentry_displayed = 0;
+ me.page.offdisplay();
+ }
+ return emesary.Transmitter.ReceiptStatus_Finished;
+ },
+
+ # Reset controller if required when the page is displayed or hidden
+ # Note that we explicitly do NOT RegisterWithEmesary/DeRegisterWithEmesary!
+ # This page should RegisterWithEmesary at start of day instead.
+ ondisplay : func() {
+ # On initial display we simply display a blank destination
+ me._wpentry_displayed = 1;
+ me.loadDestination(nil);
+ },
+
+ offdisplay : func() {
+ me._wpentry_displayed = 0;
+ },
+
+ loadDestination : func(id) {
+ if ((id == nil) or (id == "")) {
+ me._destination = nil;
+ } else {
+ # Use Emesary to get the destination
+ var notification = notifications.PFDEventNotification.new(
+ "MFD",
+ me.getDeviceID(),
+ notifications.PFDEventNotification.NavData,
+ {Id: "NavDataByID", Value: id});
+
+ var response = me._transmitter.NotifyAll(notification);
+ var retval = notification.EventParameter.Value;
+
+ if ((! me._transmitter.IsFailed(response)) and (size(retval) > 0)) {
+ var destination = retval[0];
+ # set the course and distance to the destination if required
+
+ # Some elements don't have names
+ var name = destination.id;
+ if (defined("destination.name")) name = destination.name;
+
+ var point = { lat: destination.lat, lon: destination.lon };
+ var (course, dist) = courseAndDistance(point);
+
+ me._destination = {
+ id: destination.id,
+ name: name,
+ lat: destination.lat,
+ lon: destination.lon,
+ course : course,
+ range_nm : dist,
+ };
+ }
+ }
+
+
+ me.page.displayDestination(me._destination);
+ },
+};
diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/WaypointEntry/WaypointEntryOptions.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/WaypointEntry/WaypointEntryOptions.nas
new file mode 100644
index 000000000..b10a9ff0a
--- /dev/null
+++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/WaypointEntry/WaypointEntryOptions.nas
@@ -0,0 +1,44 @@
+# Copyright 2018 Stuart Buchanan
+# This file is part of FlightGear.
+#
+# Foobar 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.
+#
+# 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 .
+#
+# WaypointEntry Options
+var WaypointEntryOptions =
+{
+ new : func() {
+ var obj = { parents : [WaypointEntryOptions] };
+ obj.Options= {};
+ obj.loadOptions();
+ return obj;
+ },
+
+ getOption : func(type) {
+ return me.Options[type];
+ },
+
+ setOption : func(type, name, value) {
+ me.Options[type][name] = value;
+ },
+
+ loadOptions : func() {
+ me.clearOptions();
+ me.Options.APS = {};
+ },
+
+ clearOptions : func() {
+ me.Options = {};
+ },
+
+};
diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/WaypointEntry/WaypointEntryStyles.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/WaypointEntry/WaypointEntryStyles.nas
new file mode 100644
index 000000000..98ee135f1
--- /dev/null
+++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/WaypointEntry/WaypointEntryStyles.nas
@@ -0,0 +1,82 @@
+# Copyright 2018 Stuart Buchanan
+# This file is part of FlightGear.
+#
+# Foobar 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.
+#
+# 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 .
+#
+# WaypointEntry Styles
+var WaypointEntryStyles =
+{
+ new : func() {
+ var obj = { parents : [ WaypointEntryStyles ]};
+ obj.Styles = {};
+ obj.loadStyles();
+ return obj;
+ },
+
+ getStyle : func(type) {
+ return me.Styles[type];
+ },
+
+ setStyle : func(type, name, value) {
+ me.Styles[type][name] = value;
+ },
+
+ loadStyles : func() {
+ me. clearStyles();
+ me.Styles.DME = {};
+ me.Styles.DME.debug = 1; # HACK for benchmarking/debugging purposes
+ me.Styles.DME.animation_test = 0; # for prototyping animated symbols
+
+ me.Styles.DME.scale_factor = 0.4; # 40% (applied to whole group)
+ me.Styles.DME.line_width = 3.0;
+ me.Styles.DME.color_tuned = [0,1,0]; #rgb
+ me.Styles.DME.color_default = [1,1,0]; #rgb
+
+ me.Styles.APT = {};
+ me.Styles.APT.scale_factor = 0.4; # 40% (applied to whole group)
+ me.Styles.APT.line_width = 3.0;
+ me.Styles.APT.color_default = [0,0.6,0.85]; #rgb
+ me.Styles.APT.label_font_color = me.Styles.APT.color_default;
+ me.Styles.APT.label_font_size=28;
+
+ me.Styles.TFC = {};
+ me.Styles.TFC.scale_factor = 0.4; # 40% (applied to whole group)
+
+ me.Styles.WPT = {};
+ me.Styles.WPT.scale_factor = 0.5; # 50% (applied to whole group)
+
+ me.Styles.RTE = {};
+ me.Styles.RTE.line_width = 2;
+
+ me.Styles.FLT = {};
+ me.Styles.FLT.line_width = 3;
+
+ me.Styles.FIX = {};
+ me.Styles.FIX.color = [1,0,0];
+ me.Styles.FIX.scale_factor = 0.4; # 40%
+
+ me.Styles.VOR = {};
+ me.Styles.VOR.range_line_width = 2;
+ me.Styles.VOR.radial_line_width = 1;
+ me.Styles.VOR.scale_factor = 0.6; # 60%
+
+ me.Styles.APS = {};
+ me.Styles.APS.scale_factor = 0.25;
+ },
+
+ clearStyles : func() {
+ me.Styles = {};
+ },
+
+};
diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/NavMap.nas b/Aircraft/Instruments-3d/FG1000/Nasal/NavMap.nas
index d6f079a9f..9253c30ee 100644
--- a/Aircraft/Instruments-3d/FG1000/Nasal/NavMap.nas
+++ b/Aircraft/Instruments-3d/FG1000/Nasal/NavMap.nas
@@ -42,8 +42,8 @@ var NavMap = {
obj.Styles = fg1000.NavigationMapStyles.new();
obj.Options = fg1000.NavigationMapOptions.new();
- obj.Map = element.createChild("map");
- obj.Map.setScreenRange(689/2.0);
+ obj._map = element.createChild("map");
+ obj._map.setScreenRange(689/2.0);
obj._rangeDisplay = obj._svg.getElementById(obj._pageName ~ "RangeDisplay");
if (obj._rangeDisplay == nil) die("Unable to find element " ~ obj._pageName ~ "RangeDisplay");
@@ -53,7 +53,7 @@ var NavMap = {
# Initialize the controllers:
if (static) {
- obj.Map.setController("Static position", "main");
+ obj._map.setController("Static position", "main");
} else {
var ctrl_ns = canvas.Map.Controller.get("Aircraft position");
var source = ctrl_ns.SOURCES["current-pos"];
@@ -74,12 +74,12 @@ var NavMap = {
source.aircraft_heading = n.getBoolValue();
}, 1);
# Make it move with our aircraft:
- obj.Map.setController("Aircraft position", "current-pos"); # from aircraftpos.controller
+ obj._map.setController("Aircraft position", "current-pos"); # from aircraftpos.controller
}
if (clip != "") {
- obj.Map.set("clip-frame", canvas.Element.LOCAL);
- obj.Map.set("clip", clip);
+ obj._map.set("clip-frame", canvas.Element.LOCAL);
+ obj._map.set("clip", clip);
}
if (zindex != 0) {
@@ -94,7 +94,7 @@ var NavMap = {
if ((static == 0) or (layer.static == 1)) {
# Not all layers are displayed for all map types. Specifically,
# some layers are not displayed on static maps - e.g. DirectTo
- obj.Map.addLayer(
+ obj._map.addLayer(
factory: layer.factory,
type_arg: layer_name,
priority: layer.priority,
@@ -106,29 +106,24 @@ var NavMap = {
obj.setZoom(obj.current_zoom);
obj.setOrientation(0);
- obj.Map.setVisible(0);
+ obj._map.setVisible(0);
return obj;
},
setController : func(type, controller ) {
- me.Map.setController(type, controller);
+ me._map.setController(type, controller);
},
getController : func() {
- return me.Map.getController();
+ return me._map.getController();
},
toggleLayerVisible : func(name) {
- (var l = me.Map.getLayer(name)).setVisible(l.getVisible());
+ (var l = me._map.getLayer(name)).setVisible(l.getVisible());
},
setLayerVisible : func(name,n=1) {
- me.Map.getLayer(name).setVisible(n);
- },
-
- setRange : func(range, label) {
- me.Map.setRange(range);
- me._rangeDisplay.setText(label);
+ me._map.getLayer(name).setVisible(n);
},
setOrientation : func(orientation) {
@@ -137,7 +132,7 @@ var NavMap = {
},
setScreenRange : func(range) {
- me.Map.setScreenRange(range);
+ me._map.setScreenRange(range);
},
zoomIn : func() {
@@ -151,10 +146,8 @@ var NavMap = {
setZoom : func(zoom) {
if ((zoom < 0) or (zoom > (size(fg1000.RANGES) - 1))) return;
me.current_zoom = zoom;
- # Ranges above represent vertical ranges, but the display is a rectangle, so
- # we need to use the diagonal range of the 1024 x 689, which is 617px.
- # 617px is 1.8 x 689/2, so we need to increase the range values by x1.8
- me.setRange(fg1000.RANGES[zoom].range, fg1000.RANGES[zoom].label);
+ me._rangeDisplay.setText(fg1000.RANGES[zoom].label);
+ me._map.setRange(fg1000.RANGES[zoom].range);
me.updateVisibility();
},
@@ -163,7 +156,7 @@ var NavMap = {
foreach (var layer_name; me._page.mfd.ConfigStore.getLayerNames()) {
var layer = me._page.mfd.ConfigStore.getLayer(layer_name);
- if (me.Map.getLayer(layer_name) == nil) continue;
+ if (me._map.getLayer(layer_name) == nil) continue;
# Layers are only displayed if:
# 1) the user has enabled them.
@@ -171,15 +164,15 @@ var NavMap = {
# (i.e. as the range gets larger, we remove layers). Note that for
# inset maps, the range that items are removed is lower.
# 3) They haven't been removed due to the declutter level.
- var effective_zoom = math.clamp(me.current_zoom + me.vis_shift, 0, size(fg1000.RANGES));
+ var effective_zoom = math.clamp(me.current_zoom + me.vis_shift, 0, size(fg1000.RANGES) -1);
var effective_range = fg1000.RANGES[effective_zoom].range;
if (layer.enabled and
(effective_range <= layer.range) and
(me.declutter <= layer.declutter) )
{
- me.Map.getLayer(layer_name).setVisible(1);
+ me._map.getLayer(layer_name).setVisible(1);
} else {
- me.Map.getLayer(layer_name).setVisible(0);
+ me._map.getLayer(layer_name).setVisible(0);
}
}
},
@@ -220,7 +213,7 @@ var NavMap = {
# Set the DTO line target
setDTOLineTarget : func(lat, lon) {
- me.Map.getLayer("DTO").controller.setTarget(lat,lon);
+ me._map.getLayer("DTO").controller.setTarget(lat,lon);
},
enableDTO : func(enable) {
me._page.mfd.ConfigStore.setLayerEnabled("DTO", enable);
@@ -235,16 +228,16 @@ var NavMap = {
},
getMap : func() {
- return me.Map;
+ return me._map;
},
show : func() {
- me.Map.show();
+ me._map.show();
},
hide : func() {
- me.Map.hide();
+ me._map.hide();
},
setVisible : func(visible) {
- me.Map.setVisible(visible);
+ me._map.setVisible(visible);
}
};
diff --git a/Nasal/canvas/PFD/GroupElement.nas b/Nasal/canvas/PFD/GroupElement.nas
index 529fbbcde..8eeab874e 100644
--- a/Nasal/canvas/PFD/GroupElement.nas
+++ b/Nasal/canvas/PFD/GroupElement.nas
@@ -2,7 +2,7 @@
var GroupElement =
{
-new : func (pageName, svg, elementNames, size, highlightElement, arrow=0, scrollTroughElement=nil, scrollThumbElement=nil, scrollHeight=0, style=nil)
+new : func (pageName, svg, elementNames, displaysize, highlightElement, arrow=0, scrollTroughElement=nil, scrollThumbElement=nil, scrollHeight=0, style=nil)
{
var obj = {
parents : [ GroupElement ],
@@ -18,7 +18,7 @@ new : func (pageName, svg, elementNames, size, highlightElement, arrow=0, scroll
# The size of the group. For each of the ._elementNames hash values there
# must be an SVG Element [pageName][elementName]{0...pageSize}
- _size : size,
+ _size : displaysize,
# ElementName to be highlighted. Must be an hash value from ._elementNames
_highlightElement : highlightElement,
@@ -66,7 +66,7 @@ new : func (pageName, svg, elementNames, size, highlightElement, arrow=0, scroll
if (style == nil) obj._style = PFD.DefaultStyle;
- for (var i = 0; i < size; i = i + 1) {
+ for (var i = 0; i < displaysize; i = i + 1) {
if (obj._arrow == 1) {
append(obj._elements, PFD.HighlightElement.new(pageName, svg, highlightElement ~ i, i, obj._style));
} else {
@@ -87,12 +87,12 @@ setValues : func (values_array) {
if (size(me._values) > me._size) {
# Number of elements exceeds our ability to display them, so enable
# the scroll bar.
- me._scrollThumbElement.setVisible(1);
- me._scrollTroughElement.setVisible(1);
+ if (me._scrollThumbElement != nil) me._scrollThumbElement.setVisible(1);
+ if (me._scrollTroughElement != nil) me._scrollTroughElement.setVisible(1);
} else {
# There is no scrolling to do, so hide the scrollbar.
- me._scrollThumbElement.setVisible(0);
- me._scrollTroughElement.setVisible(0);
+ if (me._scrollThumbElement != nil) me._scrollThumbElement.setVisible(0);
+ if (me._scrollTroughElement != nil) me._scrollTroughElement.setVisible(0);
}
me.displayGroup();
@@ -203,6 +203,9 @@ setCRSR : func(index) {
me._crsrIndex = math.min(index, size(me._values) -1);
me._crsrIndex = math.max(0, me._crsrIndex);
},
+getCRSR : func() {
+ return me._crsrIndex;
+},
getCursorElementName : func() {
if (me._crsrEnabled == -1) return nil;
return me._elements[me._crsrIndex - me._pageIndex].name;
@@ -232,7 +235,6 @@ incrSmall : func(value) {
var incr_or_decr = (value > 0) ? 1 : -1;
if (me._elements[me._crsrIndex - me._pageIndex].isInEdit()) {
# We're editing, so pass to the element.
- #print("Moving cursor to next character entry");
me._elements[me._crsrIndex - me._pageIndex].incrSmall(val);
} else {
# Move to next selection element
@@ -247,7 +249,6 @@ incrLarge : func(val) {
var incr_or_decr = (val > 0) ? 1 : -1;
if (me._elements[me._crsrIndex - me._pageIndex].isInEdit()) {
# We're editing, so pass to the element.
- #print("Moving cursor to next character entry");
me._elements[me._crsrIndex - me._pageIndex].incrLarge(val);
} else {
# Move to next selection element