From 611bfe7d7b3acaef100e2db4f40a28142b44a423 Mon Sep 17 00:00:00 2001
From: Stuart Buchanan <stuart_d_buchanan@yahoo.co.uk>
Date: Sat, 7 Apr 2018 13:23:26 +0100
Subject: [PATCH] FG1000 - Formatting fixes and lazy-loading maps

---
 .../Nasal/Interfaces/NavDataInterface.nas     |  11 +-
 .../Nasal/MFDPages/DirectTo/DirectTo.nas      |   2 +
 .../NearestIntersections.nas                  |  19 +--
 .../Nasal/MFDPages/NearestVOR/NearestVOR.nas  |  16 +-
 .../PFDInstruments/PFDInstruments.nas         |   9 --
 .../MFDPages/WaypointEntry/WaypointEntry.nas  |   1 +
 .../Instruments-3d/FG1000/Nasal/NavMap.nas    | 150 +++++++++++-------
 7 files changed, 114 insertions(+), 94 deletions(-)

diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/NavDataInterface.nas b/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/NavDataInterface.nas
index 2b66c1c3e..9c1b04808 100644
--- a/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/NavDataInterface.nas
+++ b/Aircraft/Instruments-3d/FG1000/Nasal/Interfaces/NavDataInterface.nas
@@ -150,6 +150,12 @@ getFlightplan : func ()
   return flightplan();
 },
 
+# Retrieve the checklists for this aircraft.
+getChecklists : func()
+{
+  return props.globals.getNode("/sim/checklists");
+},
+
 insertWaypoint : func (data)
 {
   assert(data["index"] != nil, "InsertWaypoint message with no index parameter");
@@ -367,7 +373,10 @@ RegisterWithEmesary : func()
           controller.insertWaypoint(notification.EventParameter.Value);
           return emesary.Transmitter.ReceiptStatus_Finished;
         }
-
+        if (id == "getChecklists") {
+          notification.EventParameter.Value = controller.getChecklists();
+          return emesary.Transmitter.ReceiptStatus_Finished;
+        }
       }
       return emesary.Transmitter.ReceiptStatus_NotProcessed;
     };
diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/DirectTo/DirectTo.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/DirectTo/DirectTo.nas
index 15dc5e4be..0f4267783 100644
--- a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/DirectTo/DirectTo.nas
+++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/DirectTo/DirectTo.nas
@@ -113,11 +113,13 @@ var DirectTo =
   },
 
   offdisplay : func() {
+    me.DirectToChart.setVisible(0);
     me._group.setVisible(0);
     me.getElement("Group").setVisible(0);
     me.getController().offdisplay();
   },
   ondisplay : func() {
+    me.DirectToChart.setVisible(1);
     me._group.setVisible(1);
     me.getElement("Group").setVisible(1);
     me.getController().ondisplay();
diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/NearestIntersections/NearestIntersections.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/NearestIntersections/NearestIntersections.nas
index 9db4b8964..738679db9 100644
--- a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/NearestIntersections/NearestIntersections.nas
+++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/NearestIntersections/NearestIntersections.nas
@@ -100,8 +100,7 @@ var NearestIntersections =
       var crsAndDst = courseAndDistance(nav);
 
       # Display the course and distance in NM .
-      # 248 is the extended ASCII code for the degree symbol
-      var crs = sprintf("%i%c", crsAndDst[0], 248);
+      var crs = sprintf("%i°", crsAndDst[0]);
       var dst = sprintf("%.1fnm", crsAndDst[1]);
 
       # Convert into something we can pass straight to the UIGroup.
@@ -126,27 +125,17 @@ var NearestIntersections =
     }
   },
   updateNavDataItem : func(nav) {
-
     if (nav == nil) return;
 
-    if (nav.lat < 0.0) {
-      me.setTextElement("Lat", sprintf("S %.4f", -nav.lat));
-    } else {
-      me.setTextElement("Lat", sprintf("N %.4f", nav.lat));
-    }
-
-    if (nav.lon < 0.0) {
-      me.setTextElement("Lon", sprintf("W%3.4f", -nav.lon));
-    } else {
-      me.setTextElement("Lon", sprintf("E%3.4f", nav.lon));
-    }
+    me.setTextElementLat("Lat", nav.lat);
+    me.setTextElementLon("Lon", nav.lon);
 
     # Determine the nearest VOR, and the bearing and distance TO the VOR,
     var vordata = me.getController().getNearestNavData("vor");
 
     if ((vordata != nil ) and (size(vordata) > 0)) {
       var crsAndDst = courseAndDistance(nav, vordata[0]);
-      var crs = sprintf("%i%c", crsAndDst[0], 248);
+      var crs = sprintf("%i°", crsAndDst[0]);
       var dst = sprintf("%.1fnm", crsAndDst[1]);
       me.setTextElement("VORID", vordata[0].id);
       me.setTextElement("VORFreq", sprintf("%.2f", vordata[0].frequency / 100.0));
diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/NearestVOR/NearestVOR.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/NearestVOR/NearestVOR.nas
index 0a13b1915..309285f02 100644
--- a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/NearestVOR/NearestVOR.nas
+++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/NearestVOR/NearestVOR.nas
@@ -109,7 +109,7 @@ var NearestVOR =
 
       # Display the course and distance in NM .
       # 248 is the extended ASCII code for the degree symbol
-      var crs = sprintf("%i%c", crsAndDst[0], 248);
+      var crs = sprintf("%i°", crsAndDst[0]);
       var dst = sprintf("%.1fnm", crsAndDst[1]);
 
       # Convert into something we can pass straight to the UIGroup.
@@ -136,18 +136,8 @@ var NearestVOR =
 
     if (nav == nil) return;
 
-    if (nav.lat < 0.0) {
-      me.setTextElement("Lat", sprintf("S %.4f", -nav.lat));
-    } else {
-      me.setTextElement("Lat", sprintf("N %.4f", nav.lat));
-    }
-
-    if (nav.lon < 0.0) {
-      me.setTextElement("Lon", sprintf("W%3.4f", -nav.lon));
-    } else {
-      me.setTextElement("Lon", sprintf("E%3.4f", nav.lon));
-    }
-
+    me.setTextElementLat("Lat", nav.lat);
+    me.setTextElementLon("Lon", nav.lon);
     me.setTextElement("Freq", sprintf("%.2f", nav.frequency / 100.0));
     me.setTextElement("Name", nav.name);
 
diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/PFDInstruments/PFDInstruments.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/PFDInstruments/PFDInstruments.nas
index 5093f71c0..7e51e65cc 100644
--- a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/PFDInstruments/PFDInstruments.nas
+++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/PFDInstruments/PFDInstruments.nas
@@ -42,10 +42,8 @@ var PFDInstruments =
       _BRG2 : "OFF",
       _DME : 0,
       _OMI : "",
-      _Map : 0,
       _Multiline : 0,
       _annunciation : 0,
-
     };
 
     # Hide various elements for the moment. TODO - implement
@@ -101,7 +99,6 @@ var PFDInstruments =
     obj.setBRG1("OFF");
     obj.setBRG2("OFF");
     obj.setDME(0);
-    obj.setMap(0);
     obj.setMultiline(0);
     obj.setAnnunciation(0);
     obj.setOMI("");
@@ -684,12 +681,6 @@ var PFDInstruments =
     }
   },
 
-  # Enable/disable the inset PFD Map.
-  setMap : func (enabled) {
-    me._Map = enabled;
-    me.getElement("PFD-Map").setVisible(enabled);
-  },
-
   # Enable/disable the multiline display on the right hand side of the PFD
   setMultiline : func(enabled) {
     me._Multiline = enabled;
diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/WaypointEntry/WaypointEntry.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/WaypointEntry/WaypointEntry.nas
index bd4f0e90f..71732981d 100644
--- a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/WaypointEntry/WaypointEntry.nas
+++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/WaypointEntry/WaypointEntry.nas
@@ -108,6 +108,7 @@ var WaypointEntry =
 
   offdisplay : func() {
     me._group.setVisible(0);
+    if (me.WaypointEntryChart != nil) me.WaypointEntryChart.setVisible(0);
     me.getElement("Group").setVisible(0);
     me.getController().offdisplay();
   },
diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/NavMap.nas b/Aircraft/Instruments-3d/FG1000/Nasal/NavMap.nas
index 9253c30ee..9207ecc00 100644
--- a/Aircraft/Instruments-3d/FG1000/Nasal/NavMap.nas
+++ b/Aircraft/Instruments-3d/FG1000/Nasal/NavMap.nas
@@ -23,6 +23,10 @@ var NavMap = {
   # Airways levels.
   AIRWAYS : [ "AIRWAYS", "AIRWY ON", "AIRWY LO", "AIRWY HI"],
 
+  # Lazy-loading - only create the map element when the page becomes visible,
+  # and delete afterwards.
+  LAZY_LOADING : 1,
+
   new : func(page, element, center, clip="", zindex=0, vis_shift=0, static=0 )
   {
     var obj = {
@@ -31,10 +35,16 @@ var NavMap = {
       _svg : page.getSVG(),
       _page : page,
       _pageName : page.getPageName(),
-      current_zoom : 13,
-      declutter : 0,
-      airways : 0,
-      vis_shift : vis_shift,
+      _element : element,
+      _center : center,
+      _clip : clip,
+      _zindex : zindex,
+      _vis_shift : vis_shift,
+      _static : static,
+      _current_zoom : 13,
+      _declutter : 0,
+      _airways : 0,
+      _map : nil,
     };
 
     element.setTranslation(center[0], center[1]);
@@ -42,88 +52,104 @@ var NavMap = {
     obj.Styles = fg1000.NavigationMapStyles.new();
     obj.Options = fg1000.NavigationMapOptions.new();
 
-    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");
 
     obj._orientationDisplay = obj._svg.getElementById(obj._pageName ~ "OrientationDisplay");
     if (obj._orientationDisplay == nil) die("Unable to find element " ~ obj._pageName ~ "OrientationDisplay");
 
+    if (NavMap.LAZY_LOADING == 0) {
+      obj.createMapElement();
+      obj._map.setVisible(0);
+    }
+
+    return obj;
+  },
+
+  # Create the map element itself.  Depending on whether we are doing lazy loading
+  # or not, this may be called by the constructor, or when the NavMap is made visible.
+  createMapElement : func() {
+
+    if (me._map != nil) return;
+
+    me._map = me._element.createChild("map");
+    me._map.setScreenRange(689/2.0);
+
     # Initialize the controllers:
-    if (static) {
-      obj._map.setController("Static position", "main");
+    if (me._static) {
+      me._map.setController("Static position", "main");
     } else {
       var ctrl_ns = canvas.Map.Controller.get("Aircraft position");
       var source = ctrl_ns.SOURCES["current-pos"];
       if (source == nil) {
-          # TODO: amend
-          var source = ctrl_ns.SOURCES["current-pos"] = {
-              getPosition: func subvec(geo.aircraft_position().latlon(), 0, 2),
-              getAltitude: func getprop('/position/altitude-ft'),
-              getHeading:  func {
-                  if (me.aircraft_heading)
-                      getprop('/orientation/heading-deg')
-                  else 0
-              },
-              aircraft_heading: 1,
-          };
+        # TODO: amend
+        var source = ctrl_ns.SOURCES["current-pos"] = {
+          getPosition: func subvec(geo.aircraft_position().latlon(), 0, 2),
+          getAltitude: func getprop('/position/altitude-ft'),
+          getHeading:  func {
+              if (me.aircraft_heading)
+                  getprop('/orientation/heading-deg')
+              else 0
+          },
+          aircraft_heading: 1,
+        };
+        setlistener("/sim/gui/dialogs/map-canvas/aircraft-heading-up", func(n) {
+          source.aircraft_heading = n.getBoolValue();
+        }, 1);
       }
-      setlistener("/sim/gui/dialogs/map-canvas/aircraft-heading-up", func(n) {
-        source.aircraft_heading = n.getBoolValue();
-      }, 1);
       # Make it move with our aircraft:
-      obj._map.setController("Aircraft position", "current-pos"); # from aircraftpos.controller
+      me._map.setController("Aircraft position", "current-pos"); # from aircraftpos.controller
     }
 
-    if (clip != "") {
-      obj._map.set("clip-frame", canvas.Element.LOCAL);
-      obj._map.set("clip", clip);
+    if (me._clip != "") {
+      me._map.set("clip-frame", canvas.Element.LOCAL);
+      me._map.set("clip", me._clip);
     }
 
-    if (zindex != 0) {
-      element.setInt("z-index", zindex);
+    if (me._zindex != 0) {
+      me._element.setInt("z-index", me._zindex);
     }
 
     var r = func(name,on_static=1, vis=1,zindex=nil) return caller(0)[0];
     # TODO: we'll need some z-indexing here, right now it's just random
-    foreach (var layer_name; obj._page.mfd.ConfigStore.getLayerNames()) {
-      var layer = obj._page.mfd.ConfigStore.getLayer(layer_name);
+    foreach (var layer_name; me._page.mfd.ConfigStore.getLayerNames()) {
+      var layer = me._page.mfd.ConfigStore.getLayer(layer_name);
 
-      if ((static == 0) or (layer.static == 1)) {
+      if ((me._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(
+        me._map.addLayer(
           factory: layer.factory,
           type_arg: layer_name,
           priority: layer.priority,
-          style: obj.Styles.getStyle(layer_name),
-          options: obj.Options.getOption(layer_name),
+          style: me.Styles.getStyle(layer_name),
+          options: me.Options.getOption(layer_name),
           visible: 0);
       }
     }
 
-    obj.setZoom(obj.current_zoom);
-    obj.setOrientation(0);
-    obj._map.setVisible(0);
-    return obj;
+    me.setZoom(me._current_zoom);
+    me.setOrientation(0);
   },
 
   setController : func(type, controller ) {
+    if (NavMap.LAZY_LOADING) me.createMapElement();
     me._map.setController(type, controller);
   },
 
   getController : func() {
+    if (NavMap.LAZY_LOADING) me.createMapElement();
     return me._map.getController();
   },
 
   toggleLayerVisible : func(name) {
-      (var l = me._map.getLayer(name)).setVisible(l.getVisible());
+    if (NavMap.LAZY_LOADING) me.createMapElement();
+    (var l = me._map.getLayer(name)).setVisible(l.getVisible());
   },
 
   setLayerVisible : func(name,n=1) {
-      me._map.getLayer(name).setVisible(n);
+    if (NavMap.LAZY_LOADING) me.createMapElement();
+    me._map.getLayer(name).setVisible(n);
   },
 
   setOrientation : func(orientation) {
@@ -132,26 +158,29 @@ var NavMap = {
   },
 
   setScreenRange : func(range) {
+    if (NavMap.LAZY_LOADING) me.createMapElement();
     me._map.setScreenRange(range);
   },
 
   zoomIn : func() {
-    me.setZoom(me.current_zoom -1);
+    me.setZoom(me._current_zoom -1);
   },
 
   zoomOut : func() {
-    me.setZoom(me.current_zoom +1);
+    me.setZoom(me._current_zoom +1);
   },
 
   setZoom : func(zoom) {
+    if (NavMap.LAZY_LOADING) me.createMapElement();
     if ((zoom < 0) or (zoom > (size(fg1000.RANGES) - 1))) return;
-    me.current_zoom = zoom;
+    me._current_zoom = zoom;
     me._rangeDisplay.setText(fg1000.RANGES[zoom].label);
     me._map.setRange(fg1000.RANGES[zoom].range);
     me.updateVisibility();
   },
 
   updateVisibility : func() {
+    if (NavMap.LAZY_LOADING) me.createMapElement();
     # Determine which layers should be visible.
     foreach (var layer_name; me._page.mfd.ConfigStore.getLayerNames()) {
       var layer = me._page.mfd.ConfigStore.getLayer(layer_name);
@@ -164,11 +193,11 @@ 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) -1);
+      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._declutter <= layer.declutter)    )
       {
         me._map.getLayer(layer_name).setVisible(1);
       } else {
@@ -189,30 +218,31 @@ var NavMap = {
   # Increment through the de-clutter levels, which impact what layers are
   # displayed.  We also need to update the declutter menu item.
   incrDCLTR : func(device, menuItem) {
-    me.declutter = math.mod(me.declutter +1, 4);
+    me._declutter = math.mod(me._declutter +1, 4);
     me.updateVisibility();
-    return me.DCLTR[me.declutter];
+    return me.DCLTR[me._declutter];
   },
 
   getDCLTRTitle : func() {
-    return me.DCLTR[me.declutter];
+    return me.DCLTR[me._declutter];
   },
 
   # Increment through the AIRWAYS levels.  At present this doesn't do anything
   # except change the label.  It should enable/disable different airways
   # information.
   incrAIRWAYS : func(device, menuItem) {
-    me.airways = math.mod(me.airways +1, 4);
+    me._airways = math.mod(me._airways +1, 4);
     me.updateVisibility();
-    return me.AIRWAYS[me.airways];
+    return me.AIRWAYS[me._airways];
   },
 
   getAIRWAYSTitle : func() {
-    return me.AIRWAYS[me.airways];
+    return me.AIRWAYS[me._airways];
   },
 
   # Set the DTO line target
   setDTOLineTarget : func(lat, lon) {
+    if (NavMap.LAZY_LOADING) me.createMapElement();
     me._map.getLayer("DTO").controller.setTarget(lat,lon);
   },
   enableDTO : func(enable) {
@@ -223,21 +253,29 @@ var NavMap = {
   handleRange : func(val)
   {
     var incr_or_decr = (val > 0) ? 1 : -1;
-    me.setZoom(me.current_zoom + incr_or_decr);
+    me.setZoom(me._current_zoom + incr_or_decr);
     return emesary.Transmitter.ReceiptStatus_Finished;
   },
 
   getMap : func() {
+    if (NavMap.LAZY_LOADING) me.createMapElement();
     return me._map;
   },
   show : func() {
+    if (NavMap.LAZY_LOADING) me.createMapElement();
     me._map.show();
   },
   hide : func() {
     me._map.hide();
+    if (NavMap.LAZY_LOADING) me._map = nil;
   },
   setVisible : func(visible) {
-    me._map.setVisible(visible);
-  }
-
+    if (visible) {
+      if (NavMap.LAZY_LOADING) me.createMapElement();
+      me._map.setVisible(visible);
+    } else {
+      me._map.setVisible(visible);
+      if (NavMap.LAZY_LOADING) me._map = nil;
+    }
+  },
 };