From 86344dfe5779e9a5970ebe5112c6a8c2cc3b177c Mon Sep 17 00:00:00 2001
From: Thomas Geymayer <tomgey@gmail.com>
Date: Mon, 17 Sep 2012 18:12:57 +0200
Subject: [PATCH 01/11] Canvas: Add method to retrieve all child elements of a
 group.

---
 Nasal/canvas/api.nas | 33 +++++++++++++++++++++++++++------
 1 file changed, 27 insertions(+), 6 deletions(-)

diff --git a/Nasal/canvas/api.nas b/Nasal/canvas/api.nas
index c6ae4d55e..9c8c4b2f6 100644
--- a/Nasal/canvas/api.nas
+++ b/Nasal/canvas/api.nas
@@ -324,6 +324,7 @@ var Element = {
 # Class for a group element on a canvas
 #
 var Group = {
+# public:
   new: func(node, id)
   {
     return { parents: [Group, Element.new(node, id)] };
@@ -342,6 +343,17 @@ var Group = {
     
     return factory([me._node, type], id);
   },
+  # Get a vector of all child elements
+  getChildren: func()
+  {
+    var children = [];
+
+    foreach(var c; me._node.getChildren())
+      if( me._isElementNode(c) )
+        append(children, me._wrapElement(c));
+
+    return children;
+  },
   # Get first child with given id (breadth-first search)
   #
   # @note Use with care as it can take several miliseconds (for me eg. ~2ms).
@@ -361,15 +373,11 @@ var Group = {
       {
         var node_id = node.getNode("id");
         if( node_id != nil and node_id.getValue() == id )
-          # Create element from existing node
-          return me._element_factories[ node.getName() ](node, nil);
+          return me._wrapElement(node);
       }
         
       foreach(var c; node.getChildren())
-        # element nodes have type NONE and valid element names (those in the the
-        # factor list)
-        if(     c.getType() == "NONE"
-            and me._element_factories[ c.getName() ] != nil )
+        if( me._isElementNode(c) )
           append(stack, c);
     }
   },
@@ -379,6 +387,19 @@ var Group = {
     foreach(var type; keys(me._element_factories))
       me._node.removeChildren(type, 0);
     return me;
+  },
+# private:
+  _isElementNode: func(el)
+  {
+    # element nodes have type NONE and valid element names (those in the factory
+    # list)
+    return el.getType() == "NONE"
+        and me._element_factories[ el.getName() ] != nil;
+  },
+  _wrapElement: func(node)
+  {
+    # Create element from existing node
+    return me._element_factories[ node.getName() ](node, nil);
   }
 };
 

From f3ac93b1ef4cbd6bdb10f377f57c9041848b73f0 Mon Sep 17 00:00:00 2001
From: Stuart Buchanan <stuart_d_buchanan@yahoo.co.uk>
Date: Mon, 17 Sep 2012 20:17:52 +0100
Subject: [PATCH 02/11] Updated Select Airport dialog, making the
 location-on-ground dialog redundant and adding a Canvas map to show the
 selected airport.

---
 Translations/en/menu.xml           |   3 +-
 gui/dialogs/airports.xml           | 691 ++++++++++++++++++++++++++---
 gui/dialogs/location-on-ground.xml | 303 -------------
 gui/menubar.xml                    |   8 -
 4 files changed, 627 insertions(+), 378 deletions(-)
 delete mode 100644 gui/dialogs/location-on-ground.xml

diff --git a/Translations/en/menu.xml b/Translations/en/menu.xml
index a21e90682..940d1dd5c 100644
--- a/Translations/en/menu.xml
+++ b/Translations/en/menu.xml
@@ -27,9 +27,8 @@
 
 	<!-- Location menu -->
 	<location>Location</location>
-	<position-on-ground>Position Aircraft On Ground</position-on-ground>
 	<position-in-air>Position Aircraft In Air</position-in-air>
-	<goto-airport>Select Airport From List</goto-airport>
+	<goto-airport>Select Airport</goto-airport>
 	<random-attitude>Random Attitude</random-attitude>
 	<tower-position>Tower Position</tower-position>
 
diff --git a/gui/dialogs/airports.xml b/gui/dialogs/airports.xml
index 75fb36749..8bb959074 100644
--- a/gui/dialogs/airports.xml
+++ b/gui/dialogs/airports.xml
@@ -31,20 +31,90 @@
 
   <nasal>
     <open>
-      var id = "";
-      var node = props.globals.getNode("/sim/gui/dialogs/airports", 1);
-      if (node.getNode("list") == nil)
-          node.getNode("list", 1).setValue("");
+      var airport_id = getprop("/sim/presets/airport-id");
+      setprop("/sim/gui/dialogs/airports/selected-airport/rwy", "");
+      setprop("/sim/gui/dialogs/airports/selected-airport/parkpos", "");
 
-      node = node.getNode("list");
+      if (airport_id == nil) { airport_id = "KSFO"; }
+      
+      var dlg = props.globals.getNode("/sim/gui/dialogs/airports", 1);
+      var avail_runways = dlg.getNode("available-runways", 1);
+      var avail_parking = dlg.getNode("available-parking", 1);
+            
+      if (dlg.getNode("list") == nil)
+          dlg.getNode("list", 1).setValue("");
+
+      var airportlist = dlg.getNode("list");
+      
+      var mode = {
+        runway:     dlg.getNode("use_runway", 1),
+        bestrunway: dlg.getNode("use_best_runway", 1),
+        parkpos:    dlg.getNode("use_parkpos", 1)
+      };
+
+      var set_radio = func(m) {
+        foreach (k; keys(mode)) {
+          mode[k].setBoolValue(m == k);
+        }
+      }
+
+      var initialized = 0;
+      foreach (k; keys(mode)) {
+        if (mode[k].getType() == "NONE" or initialized) {
+          mode[k].setBoolValue(0);
+        } else {
+          initialized += mode[k].getBoolValue();
+        }
+      }
+      if (!initialized) {
+        set_radio("bestrunway");
+      }
+
+      var update_info = func {
+          var info = airportinfo(airport_id);
+          setprop("/sim/gui/dialogs/airports/selected-airport/id", airport_id);
+          setprop("/sim/gui/dialogs/airports/selected-airport/name", info.name ~ " (" ~ airport_id ~ ")");
+          setprop("/sim/gui/dialogs/airports/selected-airport/location", sprintf("%.3f / %.3f", info.lon, info.lat));
+          setprop("/sim/gui/dialogs/airports/selected-airport/lon", info.lon);
+          setprop("/sim/gui/dialogs/airports/selected-airport/elevation-ft", 3.28 * info.elevation);
+          
+          var longest_runway = 0;
+          var runway_string = "";
+          var runways = info.runways;          
+          
+          avail_runways.removeChildren("value");
+          avail_parking.removeChildren("value");
+          var runway_keys = sort(keys(runways), string.icmp);
+          var i = 0;
+                    
+          foreach(var rwy; runway_keys) {
+              runway_string = runway_string ~ rwy ~ " ";
+              longest_runway = math.max(longest_runway, runways[rwy].length * 3.28);
+              avail_runways.getNode("value[" ~ i ~ "]", 1).setValue(rwy);
+              i += 1;
+          }                    
+
+          i = 0;
+          foreach (var park; info.parking()) {
+              avail_parking.getNode("value[" ~ i ~ "]", 1).setValue(park.name);
+              i += 1;
+          }          
+
+          setprop("/sim/gui/dialogs/airports/selected-airport/longest-runway", longest_runway);
+          
+          gui.dialog_update("airports", "runway-list");
+          gui.dialog_update("airports", "parking-list");         
+      }
 
       var listbox = func {
-          id = pop(split(" ", node.getValue()));
-          id = substr(id, 1, size(id) - 2);  # strip parentheses
+          airport_id = pop(split(" ", airportlist.getValue()));
+          airport_id = substr(airport_id, 1, size(airport_id) - 2);  # strip parentheses
+          
+          update_info();
       }
 
       var apply = func {
-          setprop("/sim/presets/airport-id", id);
+          setprop("/sim/presets/airport-id", airport_id);
           setprop("/sim/presets/longitude-deg", -9999);
           setprop("/sim/presets/latitude-deg", -9999);
           setprop("/sim/presets/altitude-ft", -9999);
@@ -53,79 +123,567 @@
           setprop("/sim/presets/offset-azimuth-deg", 0);
           setprop("/sim/presets/glideslope-deg", 0);
           setprop("/sim/presets/heading-deg", 0);
-          setprop("/sim/presets/runway", "");
-          setprop("/sim/presets/parkpos", "");
-      }
+          
+          if (mode["bestrunway"].getBoolValue()) {
+            setprop("/sim/presets/runway", "");
+            setprop("/sim/presets/parkpos", "");
+          } else if (mode["runway"].getBoolValue()) {
+            setprop("/sim/presets/runway", getprop("/sim/gui/dialogs/airports/selected-airport/rwy"));
+            setprop("/sim/presets/parkpos", "");
+          } else {
+            setprop("/sim/presets/runway", "");
+            setprop("/sim/presets/parkpos", getprop("/sim/gui/dialogs/airports/selected-airport/parkpos"));
+          }
+         
+      }    
     </open>
   </nasal>
-
-  <airport-list>
-    <name>airport-list</name>
-    <pref-width>440</pref-width>
-    <pref-height>360</pref-height>
-    <halign>fill</halign>
-    <valign>fill</valign>
-    <stretch>true</stretch>
-    <property>/sim/gui/dialogs/airports/list</property>
-    <binding>
-      <command>dialog-apply</command>
-      <object-name>airport-list</object-name>
-    </binding>
-    <binding>
-      <command>nasal</command>
-      <script>listbox()</script>
-    </binding>
-  </airport-list>
-
+  
   <group>
     <layout>hbox</layout>
     <default-padding>4</default-padding>
+  
+    <group>
+      <layout>vbox</layout>
 
-    <text>
-      <label>Airport:</label>
-      <pref-width>60</pref-width>
-    </text>
+      <group>
+        <layout>hbox</layout>
+        <default-padding>4</default-padding>
 
-    <input>
-      <name>input</name>
-      <pref-width>280</pref-width>
-      <halign>fill</halign>
-      <stretch>true</stretch>
-      <property>/sim/gui/dialogs/airports/list</property>
-      <binding>
-        <command>dialog-apply</command>
-        <object-name>input</object-name>
-      </binding>
-      <binding>
-        <command>dialog-update</command>
-        <object-name>airport-list</object-name>
-      </binding>
-    </input>
+        <text>
+          <label>Airport:</label>
+        </text>
 
-    <button>
-      <legend>Search</legend>
-      <binding>
-        <command>dialog-apply</command>
-        <object-name>input</object-name>
-      </binding>
-      <binding>
-        <command>dialog-update</command>
-        <object-name>airport-list</object-name>
-      </binding>
-    </button>
+        <input>
+          <name>input</name>
+          <pref-width>200</pref-width>
+          <halign>fill</halign>
+          <stretch>true</stretch>
+          <property>/sim/gui/dialogs/airports/list</property>
+          <binding>
+            <command>dialog-apply</command>
+            <object-name>input</object-name>
+          </binding>
+          <binding>
+            <command>dialog-update</command>
+            <object-name>airport-list</object-name>
+          </binding>
+        </input>
+
+        <button>
+          <legend>Clear</legend>
+          <binding>
+            <command>property-assign</command>
+            <property>/sim/gui/dialogs/airports/list</property>
+            <value></value>
+          </binding>
+          <binding>
+            <command>dialog-update</command>
+            <object-name>input</object-name>
+          </binding>
+          <binding>
+            <command>dialog-update</command>
+            <object-name>airport-list</object-name>
+          </binding>
+        </button>
+
+        <button>
+          <legend>Search</legend>
+          <default>true</default>
+          <binding>
+            <command>dialog-apply</command>
+            <object-name>input</object-name>
+          </binding>
+          <binding>
+            <command>dialog-update</command>
+            <object-name>airport-list</object-name>
+          </binding>
+        </button>
+
+      </group>
+
+      <airport-list>
+        <name>airport-list</name>
+        <pref-width>300</pref-width>
+        <pref-height>260</pref-height>
+        <halign>fill</halign>
+        <valign>fill</valign>
+        <stretch>true</stretch>
+        <property>/sim/gui/dialogs/airports/list</property>
+        <binding>
+          <command>dialog-apply</command>
+          <object-name>airport-list</object-name>
+        </binding>
+        <binding>
+          <command>nasal</command>
+          <script>listbox()</script>
+        </binding>
+      </airport-list>
+
+      <hrule/>
+      
+      <group>
+        <layout>table</layout>
+        
+        <text>
+          <row>0</row>
+          <col>0</col>
+          <width>200</width>
+          <halign>right</halign>        
+          <label>Airport:</label>
+        </text>
+        <text>
+          <row>0</row>
+          <col>1</col>
+          <colspan>3</colspan>
+          <halign>left</halign>
+          <live>true</live>
+          <property>/sim/gui/dialogs/airports/selected-airport/name</property>
+        </text>
+        
+        <text>
+          <row>1</row>
+          <col>0</col>
+          <halign>right</halign>
+          <label>Lon/Lat:</label>
+        </text>
+        <text>
+          <row>1</row>
+          <col>1</col>
+          <halign>left</halign>
+          <live>true</live>
+          <property>/sim/gui/dialogs/airports/selected-airport/location</property>
+        </text>
+
+        <text>
+          <row>1</row>
+          <col>3</col>
+          <halign>right</halign>
+          <label>Elevation (ft):</label>
+        </text>
+        <text>
+          <row>1</row>
+          <col>4</col>
+          <halign>left</halign>
+          <live>true</live>
+          <format>%.0f</format>
+          <property>/sim/gui/dialogs/airports/selected-airport/elevation-ft</property>
+        </text>
+
+        <text>
+          <row>2</row>
+          <col>0</col>
+          <halign>right</halign>
+          <label>Longest runway (ft):</label>
+        </text>
+        <text>
+          <row>2</row>
+          <col>1</col>
+          <halign>left</halign>
+          <live>true</live>
+          <format>%.0f</format>
+          <property>/sim/gui/dialogs/airports/selected-airport/longest-runway</property>
+        </text>
+
+      </group>
+      
+      <hrule/>
+      
+      <group>
+        <layout>table</layout>
+        <halign>center</halign>
+        
+        <radio>
+          <row>2</row><col>0</col>
+          <property>/sim/gui/dialogs/airports/use_best_runway</property>
+          <live>true</live>
+          <binding>
+            <command>nasal</command>
+            <script>set_radio("bestrunway")</script>
+          </binding>
+        </radio>
+
+        <text>
+          <row>2</row><col>1</col>
+          <halign>right</halign>
+          <label>Best runway</label>
+          <enable>
+            <property>/sim/gui/dialogs/airports/use_best_runway</property>
+          </enable>
+        </text>
+        <text>
+          <row>2</row><col>2</col>
+          <halign>right</halign>
+          <label>(based on wind)</label>
+          <enable>
+            <property>/sim/gui/dialogs/airports/use_best_runway</property>
+          </enable>
+        </text>
+
+        <radio>
+          <row>3</row><col>0</col>
+          <property>/sim/gui/dialogs/airports/use_runway</property>
+          <live>true</live>
+          <binding>
+            <command>nasal</command>
+            <script>set_radio("runway")</script>
+          </binding>
+        </radio>
+
+        <text>
+          <row>3</row><col>1</col>
+          <halign>right</halign>
+          <label>Runway:</label>
+          <enable>
+            <property>/sim/gui/dialogs/airports/use_runway</property>
+          </enable>
+        </text>
+
+        <combo>
+          <name>runway-list</name>
+          <row>3</row><col>2</col>
+          <pref-width>85</pref-width>
+          <enable>
+            <property>/sim/gui/dialogs/airports/use_runway</property>
+          </enable>
+          <property>/sim/gui/dialogs/airports/selected-airport/rwy</property>
+          <editable>false</editable>
+          <properties>sim/gui/dialogs/airports/available-runways</properties>
+          <binding>
+            <command>dialog-apply</command>
+            <object-name>runway-list</object-name>
+          </binding>
+        </combo>
+
+        <radio>
+          <row>4</row><col>0</col>
+          <property>/sim/gui/dialogs/airports/use_parkpos</property>
+          <live>true</live>
+          <binding>
+            <command>nasal</command>
+            <script>set_radio("parkpos")</script>
+          </binding>
+        </radio>
+
+        <text>
+          <row>4</row><col>1</col>
+          <halign>right</halign>
+          <label>Parking:</label>
+          <enable>
+            <property>/sim/gui/dialogs/airports/use_parkpos</property>
+          </enable>
+        </text>
+        
+        <combo>
+          <name>parking-list</name>
+          <row>4</row><col>2</col>
+          <pref-width>85</pref-width>
+          <enable>
+            <property>/sim/gui/dialogs/airports/use_parkpos</property>
+          </enable>
+          <property>/sim/gui/dialogs/airports/selected-airport/parkpos</property>
+          <editable>false</editable>
+          <properties>sim/gui/dialogs/airports/available-parking</properties>
+          <binding>
+            <command>dialog-apply</command>
+            <object-name>parking-list</object-name>
+          </binding>
+        </combo>
+      </group>
+
+    </group>    
+    
+    <vrule/>
+  
+    <group>
+      <layout>vbox</layout>
+
+      <canvas>
+        <name>map-dialog</name>
+        <valign>fill</valign>
+        <halign>fill</halign>
+        <stretch>true</stretch>
+        <pref-width>600</pref-width>
+        <pref-height>400</pref-height>
+        <view n="0">600</view>
+        <view n="1">400</view>
+        
+        <nasal>
+      
+      
+        <load><![CDATA[
+          var Runway = {
+            new: func(rwy)
+            {
+              return {
+                parents: [Runway],
+                rwy: rwy
+              };
+            },
+            pointOffCenterline: func(pos, off = 0)
+            {
+              var coord = geo.Coord.new();
+              coord.set_latlon(me.rwy.lat, me.rwy.lon);
+              coord.apply_course_distance(me.rwy.heading, pos - 0.5 * me.rwy.length);
+              
+              if( off )
+                coord.apply_course_distance(me.rwy.heading + 90, off);
+              
+              return ["N" ~ coord.lat(), "E" ~ coord.lon()];
+            }
+          };
+          
+          var AirportMap = {
+            new: func(apt)
+            {
+              return {
+                parents: [AirportMap],
+                _apt: apt
+              };
+            },
+            build: func(layer_runways)
+            {
+              var rws_done = {};
+
+              me.grp_apt = layer_runways.createChild("group", "apt-" ~ me._apt.id);
+              var selected_rwy = getprop("/sim/gui/dialogs/airports/selected-airport/rwy");          
+              
+              foreach(var rw; keys(me._apt.runways))
+              {
+                var is_heli = substr(rw, 0, 1) == "H";
+                var rw_dir = is_heli ? nil : int(substr(rw, 0, 2));
+                
+                var rw_rec = "";            
+                var thresh_rec = 0;
+                if( rw_dir != nil )
+                {
+                  rw_rec = sprintf("%02d", math.mod(rw_dir - 18, 36));
+                  if( size(rw) == 3 )
+                  {
+                    var map_rec = {
+                      "R": "L",
+                      "L": "R",
+                      "C": "C"
+                    };
+                    rw_rec ~= map_rec[substr(rw, 2)];
+                  }
+                  
+                  if( rws_done[rw_rec] != nil )
+                    continue;
+                  
+                  var rw_rec = me._apt.runways[rw_rec];
+                  if( rw_rec != nil )
+                    thresh_rec = rw_rec.threshold;
+                }
+
+                rws_done[rw] = 1; 
+
+                rw = me._apt.runways[rw];
+                var icon_rw = me.grp_apt.createChild("path", "runway");
+                
+                icon_rw.setStrokeLineWidth(0.5);
+                icon_rw.setColor(1.0,1.0,1.0);
+                icon_rw.setColorFill(0.2, 0.2, 0.2);
+                icon_rw.setFill(1);
+                
+                var rwy = Runway.new(rw);
+                var beg_thr  = rwy.pointOffCenterline(rw.threshold);
+                var beg_thr1 = rwy.pointOffCenterline(rw.threshold,  0.5 * rw.width);
+                var beg_thr2 = rwy.pointOffCenterline(rw.threshold, -0.5 * rw.width);
+                var beg1 = rwy.pointOffCenterline(0,  0.5 * rw.width);
+                var beg2 = rwy.pointOffCenterline(0, -0.5 * rw.width);
+                
+                var end_thr  = rwy.pointOffCenterline(rw.length - thresh_rec);
+                var end_thr1 = rwy.pointOffCenterline(rw.length - thresh_rec,  0.5 * rw.width);
+                var end_thr2 = rwy.pointOffCenterline(rw.length - thresh_rec, -0.5 * rw.width);
+                var end1 = rwy.pointOffCenterline(rw.length,  0.5 * rw.width);
+                var end2 = rwy.pointOffCenterline(rw.length, -0.5 * rw.width);
+
+                icon_rw.setDataGeo
+                (
+                  [ canvas.Path.VG_MOVE_TO,
+                    canvas.Path.VG_LINE_TO,
+                    canvas.Path.VG_LINE_TO,
+                    canvas.Path.VG_LINE_TO,
+                    canvas.Path.VG_CLOSE_PATH ],
+                  [ beg1[0], beg1[1],
+                    beg2[0], beg2[1],
+                    end2[0], end2[1],
+                    end1[0], end1[1] ]
+                );
+                
+                if( rw.length / rw.width > 3 and !is_heli )
+                {
+                  # only runways which are much longer than wide are
+                  # real runways, otherwise it's probably a heliport.
+                  var icon_cl = me.grp_apt.createChild("path", "centerline");
+                  icon_cl.setStrokeLineWidth(0.5);
+                  icon_cl.setColor(1,1,1);
+                  icon_cl.setStrokeDashArray([15, 10]);
+                  
+                  icon_cl.setDataGeo
+                  (
+                    [ canvas.Path.VG_MOVE_TO,
+                      canvas.Path.VG_LINE_TO ],
+                    [ beg_thr[0], beg_thr[1],
+                      end_thr[0], end_thr[1] ]
+                  );
+                  
+                  var icon_thr = me.grp_apt.createChild("path", "threshold");
+                  icon_thr.setStrokeLineWidth(1.5);
+                  icon_thr.setColor(1,1,1);
+                  
+                  icon_thr.setDataGeo
+                  (
+                    [ canvas.Path.VG_MOVE_TO,
+                      canvas.Path.VG_LINE_TO,
+                      canvas.Path.VG_MOVE_TO,
+                      canvas.Path.VG_LINE_TO ],
+                    [ beg_thr1[0], beg_thr1[1],
+                      beg_thr2[0], beg_thr2[1],
+                      end_thr1[0], end_thr1[1],
+                      end_thr2[0], end_thr2[1] ]
+                  );
+                }
+              }
+              
+              foreach(var park; me._apt.parking())
+              {
+                var icon_park = me.grp_apt.createChild("text");
+                icon_park.setDrawMode(9);
+                icon_park.setText(park.name);
+                icon_park.setFont("LiberationFonts/LiberationMono-Bold.ttf");
+                icon_park.setGeoPosition(park.lat, park.lon);
+                icon_park.setFontSize(15, 1.3);
+              }
+            }
+          };
+
+          var my_canvas = canvas.get(cmdarg());
+          my_canvas.setColorBackground(0.2, 0.5, 0.2, 0.5);
+
+          var root = my_canvas.createGroup();
+          
+          var map = root.createChild("map", "map-test");
+          map.setTranslation(300, 200);
+          
+          var layer_runways = map.createChild("group", "runways");
+          var icon_tower = map.createChild("path", "tower");
+          icon_tower.setStrokeLineWidth(1);
+          icon_tower.setScale(1.5);
+          icon_tower.setColor(0.2,0.2,1.0);
+          
+          icon_tower.setData
+          (
+            [ canvas.Path.VG_MOVE_TO,
+              canvas.Path.VG_VLINE_TO_REL,
+              canvas.Path.VG_LINE_TO_REL,
+              canvas.Path.VG_HLINE_TO_REL,
+              canvas.Path.VG_LINE_TO_REL,
+              canvas.Path.VG_VLINE_TO_REL ],
+            [ -3, 0,
+             -10,
+              -3, -10,
+              12,
+              -3, 10,
+              10 ]
+          );
+          
+          var updateMap = func() {
+            var id = getprop("/sim/gui/dialogs/airports/selected-airport/id");
+          
+            if (id != "") {
+              var apt = airportinfo(id);
+              var airport = AirportMap.new(apt);
+              airport.build(layer_runways);
+
+              var pos = apt.tower();
+              icon_tower.setGeoPosition(pos.lat, pos.lon);
+              map._node.getNode("ref-lat", 1).setDoubleValue(apt.lat);
+              map._node.getNode("ref-lon", 1).setDoubleValue(apt.lon);
+              map._node.getNode("hdg", 1).setDoubleValue(0.0);
+              }
+          }
+                
+          var ranges = [0.1, 0.25, 0.5, 1, 2.5, 5];
+          
+          var updateZoom = func()
+          {
+            var z = getprop("/sim/gui/dialogs/airports/zoom");
+            if( z == nil )
+              z = 0;
+            var zoom = ranges[4 - z];
+            map._node.getNode("range", 1).setDoubleValue(zoom);
+                    
+            settimer(updateZoom, 0.5);
+          };
+          
+          var aptlistener = setlistener("/sim/gui/dialogs/airports/selected-airport/id", updateMap);
+          
+          update_info();
+          updateZoom();
+          ]]>
+          </load>
+          <close>
+            removelistener(aptlistener);      
+          </close>
+        </nasal>
+      </canvas>
+
+      <hrule/>
+      
+      <group>
+          <layout>hbox</layout>
+          
+          <button>
+              <name>zoomout</name>
+              <legend>-</legend>
+              <pref-width>22</pref-width>
+              <pref-height>22</pref-height>
+
+              <binding>
+                  <command>property-adjust</command>
+                  <property>/sim/gui/dialogs/airports/zoom</property>
+                  <min>0</min>
+                  <step>-1</step>
+              </binding>
+          </button>
+          
+          <text>
+              <label>MMM</label>
+              <format>Zoom %d</format>
+              <property>/sim/gui/dialogs/airports/zoom</property>
+              <live>true</live>
+          </text>
+          
+          <button>
+              <name>zoomin</name>
+              <legend>+</legend>
+              <pref-width>22</pref-width>
+              <pref-height>22</pref-height>
+
+              <binding>
+                  <command>property-adjust</command>
+                  <property>//sim/gui/dialogs/airports/zoom</property>
+                  <step>1</step>
+                  <max>4</max>
+              </binding>
+          </button>
+      </group>
+    </group>
   </group>
-
+  
   <hrule/>
-
+  
   <group>
     <layout>hbox</layout>
     <default-padding>10</default-padding>
+    
     <empty><stretch>true</stretch></empty>
 
     <button>
-      <legend>Apply</legend>
+      <legend>OK</legend>
       <equal>true</equal>
-      <default>true</default>
       <binding>
         <command>dialog-apply</command>
         <object-name>airport-list</object-name>
@@ -137,12 +695,15 @@
       <binding>
         <command>presets-commit</command>
       </binding>
+      <binding>
+        <command>dialog-close</command>
+      </binding>
     </button>
 
     <empty><stretch>true</stretch></empty>
 
     <button>
-      <legend>Close</legend>
+      <legend>Cancel</legend>
       <equal>true</equal>
       <key>Esc</key>
       <binding>
diff --git a/gui/dialogs/location-on-ground.xml b/gui/dialogs/location-on-ground.xml
deleted file mode 100644
index 2e58660f9..000000000
--- a/gui/dialogs/location-on-ground.xml
+++ /dev/null
@@ -1,303 +0,0 @@
-<?xml version="1.0"?>
-
-<PropertyList>
-  <name>location-on-ground</name>
-  <layout>vbox</layout>
-
-  <group>
-    <layout>hbox</layout>
-    <empty><stretch>1</stretch></empty>
-
-    <text>
-      <label>Position Aircraft On Ground</label>
-    </text>
-
-    <empty><stretch>1</stretch></empty>
-
-    <button>
-      <pref-width>16</pref-width>
-      <pref-height>16</pref-height>
-      <legend></legend>
-      <keynum>27</keynum>
-      <border>2</border>
-      <binding>
-        <command>dialog-close</command>
-      </binding>
-    </button>
-  </group>
-
-  <hrule/>
-
-  <nasal>
-    <open>
-      var dlg = props.globals.getNode("/sim/gui/dialogs/location-on-ground", 1);
-      var apt = dlg.getNode("airport", 1);
-      var aptname = dlg.getNode("airport-name", 1);
-      apt.setValue(getprop("/sim/presets/airport-id"));
-      var rwy = dlg.getNode("runway", 1);
-      rwy.setValue("");
-      var parkpos = dlg.getNode("parkpos", 1);
-      parkpos.setValue("");
-
-      var mode = {
-        runway:     dlg.getNode("use_runway", 1),
-        bestrunway: dlg.getNode("use_best_runway", 1),
-        parkpos:    dlg.getNode("use_parkpos", 1)
-      };
-
-      var set_radio = func(m) {
-        foreach (k; keys(mode)) {
-          mode[k].setBoolValue(m == k);
-        }
-      }
-
-      var initialized = 0;
-      foreach (k; keys(mode)) {
-        if (mode[k].getType() == "NONE" or initialized) {
-          mode[k].setBoolValue(0);
-        } else {
-          initialized += mode[k].getBoolValue();
-        }
-      }
-      if (!initialized) {
-        set_radio("bestrunway");
-      }
-
-      var runways = dlg.getNode("available-runways", 1);
-      var parking = dlg.getNode("available-parking", 1);
-      
-      var updateAirport = func {
-        var icao = apt.getValue();
-        runways.removeChildren("value");
-        parking.removeChildren("value");
-        
-        var a = airportinfo(icao);
-        if (a == nil) {
-            aptname.setValue("");
-            return;
-        }
-        
-        aptname.setValue(a.name);
-        var i=0;
-        foreach (var rwy; keys(a.runways)) {
-          runways.getNode("value[" ~ i ~ "]", 1).setValue(rwy);
-          i += 1;
-        }
-
-        i = 0;
-        foreach (var park; a.parking()) {
-          parking.getNode("value[" ~ i ~ "]", 1).setValue(park.name);
-          i += 1;
-        }
-        
-        gui.dialog_update("location-on-ground");
-      }
-      
-      updateAirport();
-    </open>
-  </nasal>
-
-  <group>
-    <layout>table</layout>
-    <halign>center</halign>
-
-    <text>
-      <row>0</row><col>1</col>
-      <halign>right</halign>
-      <label>Airport:</label>
-    </text>
-
-    <input>
-      <row>0</row><col>2</col>
-      <live>true</live>
-      <property>/sim/gui/dialogs/location-on-ground/airport</property>
-      <binding>
-        <command>dialog-apply</command>
-      </binding>
-      <binding>
-        <command>nasal</command>
-        <script>
-            updateAirport();
-        </script>
-      </binding>
-    </input>
-
-    <text>
-        <row>1</row>
-        <col>1</col>
-        <format>%s</format>
-        <property>/sim/gui/dialogs/location-on-ground/airport-name</property>
-        <live>true</live>
-        <stretch>true</stretch>
-        <halign>fill</halign>
-    </text>
-    
-    <radio>
-      <row>2</row><col>0</col>
-      <property>/sim/gui/dialogs/location-on-ground/use_best_runway</property>
-      <live>true</live>
-      <binding>
-        <command>nasal</command>
-        <script>set_radio("bestrunway")</script>
-      </binding>
-    </radio>
-
-    <text>
-      <row>2</row><col>1</col>
-      <halign>right</halign>
-      <label>Best runway</label>
-      <enable>
-        <property>/sim/gui/dialogs/location-on-ground/use_best_runway</property>
-      </enable>
-    </text>
-    <text>
-      <row>2</row><col>2</col>
-      <halign>right</halign>
-      <label>(based on wind)</label>
-      <enable>
-        <property>/sim/gui/dialogs/location-on-ground/use_best_runway</property>
-      </enable>
-    </text>
-
-    <radio>
-      <row>3</row><col>0</col>
-      <property>/sim/gui/dialogs/location-on-ground/use_runway</property>
-      <live>true</live>
-      <binding>
-        <command>nasal</command>
-        <script>set_radio("runway")</script>
-      </binding>
-    </radio>
-
-    <text>
-      <row>3</row><col>1</col>
-      <halign>right</halign>
-      <label>Runway:</label>
-      <enable>
-        <property>/sim/gui/dialogs/location-on-ground/use_runway</property>
-      </enable>
-    </text>
-
-    <combo>
-      <name>runway</name>
-      <row>3</row><col>2</col>
-      <pref-width>85</pref-width>
-      <enable>
-        <property>/sim/gui/dialogs/location-on-ground/use_runway</property>
-      </enable>
-      <property>sim/gui/dialogs/location-on-ground/runway</property>
-      <editable>false</editable>
-      <properties>sim/gui/dialogs/location-on-ground/available-runways</properties>
-      <binding>
-        <command>dialog-apply</command>
-        <object-name>runway</object-name>
-      </binding>
-    </combo>
-
-    <radio>
-      <row>4</row><col>0</col>
-      <property>/sim/gui/dialogs/location-on-ground/use_parkpos</property>
-      <live>true</live>
-      <binding>
-        <command>nasal</command>
-        <script>set_radio("parkpos")</script>
-      </binding>
-    </radio>
-
-    <text>
-      <row>4</row><col>1</col>
-      <halign>right</halign>
-      <label>Parking:</label>
-      <enable>
-        <property>/sim/gui/dialogs/location-on-ground/use_parkpos</property>
-      </enable>
-    </text>
-    
-    <combo>
-      <name>parking</name>
-      <row>4</row><col>2</col>
-      <pref-width>85</pref-width>
-      <enable>
-        <property>/sim/gui/dialogs/location-on-ground/use_parkpos</property>
-      </enable>
-      <property>/sim/gui/dialogs/location-on-ground/parkpos</property>
-      <editable>false</editable>
-      <properties>sim/gui/dialogs/location-on-ground/available-parking</properties>
-      <binding>
-        <command>dialog-apply</command>
-        <object-name>parking</object-name>
-      </binding>
-    </combo>
-  </group>
-
-  <hrule/>
-
-  <group>
-    <layout>hbox</layout>
-    <default-padding>10</default-padding>
-    <empty><stretch>true</stretch></empty>
-
-    <button>
-      <legend>OK</legend>
-      <default>true</default>
-      <equal>true</equal>
-      <binding>
-        <command>dialog-apply</command>
-      </binding>
-      <enable>
-        <not>
-          <and>
-            <property>/sim/gui/dialogs/location-on-ground/use_runway</property>
-            <equals>
-              <property>/sim/gui/dialogs/location-on-ground/runway</property>
-              <value></value>
-            </equals>
-          </and>
-        </not>
-      </enable>
-      <binding>
-        <command>nasal</command>
-        <script>
-          setprop("/sim/presets/airport-id", apt.getValue());
-          if (mode["bestrunway"].getBoolValue()) {
-            setprop("/sim/presets/runway", "");
-            setprop("/sim/presets/parkpos", "");
-          } else if (mode["runway"].getBoolValue()) {
-            setprop("/sim/presets/runway", rwy.getValue());
-            setprop("/sim/presets/parkpos", "");
-          } else {
-            setprop("/sim/presets/runway", "");
-            setprop("/sim/presets/parkpos", parkpos.getValue());
-          }
-          setprop("/sim/presets/longitude-deg", -9999);
-          setprop("/sim/presets/latitude-deg", -9999);
-          setprop("/sim/presets/altitude-ft", -9999);
-          setprop("/sim/presets/airspeed-kt", 0);
-          setprop("/sim/presets/offset-distance-nm", 0);
-          setprop("/sim/presets/offset-azimuth-nm", 0);
-          setprop("/sim/presets/glideslope-deg", 0);
-          setprop("/sim/presets/heading-deg", 9999);
-        </script>
-      </binding>
-      <binding>
-        <command>presets-commit</command>
-      </binding>
-      <binding>
-        <command>dialog-close</command>
-      </binding>
-    </button>
-
-    <empty><stretch>true</stretch></empty>
-
-    <button>
-      <legend>Cancel</legend>
-      <equal>true</equal>
-      <key>Esc</key>
-      <binding>
-        <command>dialog-close</command>
-      </binding>
-    </button>
-
-    <empty><stretch>true</stretch></empty>
-  </group>
-</PropertyList>
diff --git a/gui/menubar.xml b/gui/menubar.xml
index 2d074f404..c6bdf4a69 100644
--- a/gui/menubar.xml
+++ b/gui/menubar.xml
@@ -172,14 +172,6 @@
 	<menu>
 		<name>location</name>
 
-		<item>
-			<name>position-on-ground</name>
-			<binding>
-				<command>dialog-show</command>
-				<dialog-name>location-on-ground</dialog-name>
-			</binding>
-		</item>
-
 		<item>
 			<name>position-in-air</name>
 			<binding>

From a870d8c4a349e7a4fe27180115b7599795628bd0 Mon Sep 17 00:00:00 2001
From: Thomas Geymayer <tomgey@gmail.com>
Date: Tue, 18 Sep 2012 00:32:54 +0200
Subject: [PATCH 03/11] Clean up Select Airport dialog a bit to make use of
 recent Canvas API improvements

---
 gui/dialogs/airports.xml | 82 +++++++++++++++++++---------------------
 1 file changed, 38 insertions(+), 44 deletions(-)

diff --git a/gui/dialogs/airports.xml b/gui/dialogs/airports.xml
index 8bb959074..2fce23517 100644
--- a/gui/dialogs/airports.xml
+++ b/gui/dialogs/airports.xml
@@ -479,13 +479,12 @@
                 rws_done[rw] = 1; 
 
                 rw = me._apt.runways[rw];
-                var icon_rw = me.grp_apt.createChild("path", "runway");
-                
-                icon_rw.setStrokeLineWidth(0.5);
-                icon_rw.setColor(1.0,1.0,1.0);
-                icon_rw.setColorFill(0.2, 0.2, 0.2);
-                icon_rw.setFill(1);
-                
+                var icon_rw =
+                  me.grp_apt.createChild("path", "runway")
+                            .setStrokeLineWidth(0.5)
+                            .setColor(1.0,1.0,1.0)
+                            .setColorFill(0.2, 0.2, 0.2);
+
                 var rwy = Runway.new(rw);
                 var beg_thr  = rwy.pointOffCenterline(rw.threshold);
                 var beg_thr1 = rwy.pointOffCenterline(rw.threshold,  0.5 * rw.width);
@@ -516,10 +515,11 @@
                 {
                   # only runways which are much longer than wide are
                   # real runways, otherwise it's probably a heliport.
-                  var icon_cl = me.grp_apt.createChild("path", "centerline");
-                  icon_cl.setStrokeLineWidth(0.5);
-                  icon_cl.setColor(1,1,1);
-                  icon_cl.setStrokeDashArray([15, 10]);
+                  var icon_cl =
+                    me.grp_apt.createChild("path", "centerline")
+                              .setStrokeLineWidth(0.5)
+                              .setColor(1,1,1)
+                              .setStrokeDashArray([15, 10]);
                   
                   icon_cl.setDataGeo
                   (
@@ -529,9 +529,10 @@
                       end_thr[0], end_thr[1] ]
                   );
                   
-                  var icon_thr = me.grp_apt.createChild("path", "threshold");
-                  icon_thr.setStrokeLineWidth(1.5);
-                  icon_thr.setColor(1,1,1);
+                  var icon_thr =
+                    me.grp_apt.createChild("path", "threshold")
+                              .setStrokeLineWidth(1.5)
+                              .setColor(1,1,1);
                   
                   icon_thr.setDataGeo
                   (
@@ -549,12 +550,14 @@
               
               foreach(var park; me._apt.parking())
               {
-                var icon_park = me.grp_apt.createChild("text");
-                icon_park.setDrawMode(9);
-                icon_park.setText(park.name);
-                icon_park.setFont("LiberationFonts/LiberationMono-Bold.ttf");
-                icon_park.setGeoPosition(park.lat, park.lon);
-                icon_park.setFontSize(15, 1.3);
+                var icon_park =
+                  me.grp_apt.createChild("text")
+                            .setDrawMode( canvas.Text.ALIGNMENT
+                                        + canvas.Text.TEXT )
+                            .setText(park.name)
+                            .setFont("LiberationFonts/LiberationMono-Bold.ttf")
+                            .setGeoPosition(park.lat, park.lon)
+                            .setFontSize(15, 1.3);
               }
             }
           };
@@ -564,31 +567,22 @@
 
           var root = my_canvas.createGroup();
           
-          var map = root.createChild("map", "map-test");
-          map.setTranslation(300, 200);
+          var map = root.createChild("map", "map-test")
+                        .setTranslation(300, 200);
           
           var layer_runways = map.createChild("group", "runways");
-          var icon_tower = map.createChild("path", "tower");
-          icon_tower.setStrokeLineWidth(1);
-          icon_tower.setScale(1.5);
-          icon_tower.setColor(0.2,0.2,1.0);
-          
-          icon_tower.setData
-          (
-            [ canvas.Path.VG_MOVE_TO,
-              canvas.Path.VG_VLINE_TO_REL,
-              canvas.Path.VG_LINE_TO_REL,
-              canvas.Path.VG_HLINE_TO_REL,
-              canvas.Path.VG_LINE_TO_REL,
-              canvas.Path.VG_VLINE_TO_REL ],
-            [ -3, 0,
-             -10,
-              -3, -10,
-              12,
-              -3, 10,
-              10 ]
-          );
-          
+          var icon_tower =
+            map.createChild("path", "tower")
+               .setStrokeLineWidth(1)
+               .setScale(1.5)
+               .setColor(0.2,0.2,1.0)
+               .moveTo(-3, 0)
+               .vert(-10)
+               .line(-3, -10)
+               .horiz(12)
+               .line(-3, 10)
+               .vert(10);
+
           var updateMap = func() {
             var id = getprop("/sim/gui/dialogs/airports/selected-airport/id");
           
@@ -615,7 +609,7 @@
             var zoom = ranges[4 - z];
             map._node.getNode("range", 1).setDoubleValue(zoom);
                     
-            settimer(updateZoom, 0.5);
+            settimer(updateZoom, 0.5, 1);
           };
           
           var aptlistener = setlistener("/sim/gui/dialogs/airports/selected-airport/id", updateMap);

From 602ae34af4108e801c2c316ae0f2e1537c422b56 Mon Sep 17 00:00:00 2001
From: Stuart Buchanan <stuart_d_buchanan@yahoo.co.uk>
Date: Tue, 18 Sep 2012 11:29:17 +0100
Subject: [PATCH 04/11] Add support for a Aircraft Checklists GUI item.

---
 Aircraft/c172p/c172-help.xml |  28 +-----
 Aircraft/c172p/c172p-set.xml |   2 +
 Nasal/gui.nas                |   1 +
 Translations/en/menu.xml     |   1 +
 gui/dialogs/checklist.xml    | 186 +++++++++++++++++++++++++++++++++++
 gui/menubar.xml              |   8 ++
 6 files changed, 201 insertions(+), 25 deletions(-)
 create mode 100644 gui/dialogs/checklist.xml

diff --git a/Aircraft/c172p/c172-help.xml b/Aircraft/c172p/c172-help.xml
index 0429466be..e210fcb59 100644
--- a/Aircraft/c172p/c172-help.xml
+++ b/Aircraft/c172p/c172-help.xml
@@ -13,33 +13,11 @@
     <desc>Increase/decrease panel lighting</desc>
   </key>
   <line/>
-  <line>_________Engine Start Checklist_________</line>
-  <line>Mixture: Rich</line>
-  <line>Throttle: Open 1/8"</line>
-  <line>Parking Brake: Applied (Shift-B)</line>
-  <line>Prop Area: Clear</line>
-  <line>Magnetos: Both ( } three times )</line>
-  <line>Ignition: Start (s)</line>
-  <line>Throttle: 800-1000rpm</line>
-  <line/>
-  <line>_________Pre-Takeoff Checklist_________</line>
-  <line>Parking Brake: Applied (Shift-B)</line>
-  <line>Flight Controls: Free and Correct</line>
-  <line>Elevator Trim: Takeoff</line>
-  <line>Mixture: Rich</line>
-  <line>Throttle: 1700rpm</line>
-  <line>Suction gauge: Check</line>
-  <line>Engine Instruments: Check</line>
-  <line>Ammeter: Check</line>
-  <line>Magnetos: Check (125rpm max drop, 50rpm max diff</line>
-  <line>Throttle: Closed (check idle)</line>
-  <line>Throttle: 800-1000rpm</line>
-  <line>Mixture: As required</line>
-  <line/>
-  <line>_________Procedures_________</line>
+  <line>For checklists, see under Help->Aircraft Checklists</line>
+  <line/>  
   <line>Takeoff: no flaps, full throttle, rotate at 55 KIAS</line>
   <line>Climbout: no flaps, full throttle, 80 KIAS</line>
-  <line>Cruise: Throttle 65%, Mixture rich of peak,</line>
+  <line>Cruise: Throttle 65%, Mixture rich of peak</line>
   <line>Landing: full flaps, 65 KIAS</line>
   <line/>
   <line>_________V Speeds_________</line>
diff --git a/Aircraft/c172p/c172p-set.xml b/Aircraft/c172p/c172p-set.xml
index bacf17e12..5cdedc57e 100644
--- a/Aircraft/c172p/c172p-set.xml
+++ b/Aircraft/c172p/c172p-set.xml
@@ -96,6 +96,8 @@ Started October 23 2001 by John Check, fgpanels@rockfish.net
   </sound>
 
   <help include="c172-help.xml"/>
+  
+  <checklists include="c172-checklists.xml"/>
 
   <tutorials include="Tutorials/c172-tutorials.xml"/>
   
diff --git a/Nasal/gui.nas b/Nasal/gui.nas
index de1f97c29..6c4c7e95f 100644
--- a/Nasal/gui.nas
+++ b/Nasal/gui.nas
@@ -146,6 +146,7 @@ _setlistener("/sim/signals/nasal-dir-initialized", func {
 
     # enable/disable menu entries
     menuEnable("fuel-and-payload", fdm == "yasim" or fdm == "jsb");
+    menuEnable("aircraft-checklists", props.globals.getNode("/sim/checklists") != nil);
     var isAutopilotMenuEnabled = func {
       foreach( var apdp; autopilotDisableProps ) {
         if( props.globals.getNode( apdp ) != nil )
diff --git a/Translations/en/menu.xml b/Translations/en/menu.xml
index 940d1dd5c..51c6e8e8d 100644
--- a/Translations/en/menu.xml
+++ b/Translations/en/menu.xml
@@ -109,6 +109,7 @@
 	<help>Help</help>
 	<help-browser>Help  (opens in browser)</help-browser>
 	<aircraft-keys>Aircraft Help</aircraft-keys>
+  <aircraft-checklists>Aircraft Checklists</aircraft-checklists>
 	<common-keys>Common Aircraft Keys</common-keys>
 	<basic-keys>Basic Simulator Keys</basic-keys>
 	<joystick-config>Joystick Configuration</joystick-config>
diff --git a/gui/dialogs/checklist.xml b/gui/dialogs/checklist.xml
new file mode 100644
index 000000000..b459abb65
--- /dev/null
+++ b/gui/dialogs/checklist.xml
@@ -0,0 +1,186 @@
+<?xml version="1.0"?>
+
+<PropertyList>
+  <name>checklist</name>
+  <layout>vbox</layout>
+	<default-padding>1</default-padding>
+
+  <color>
+    <red type="float">0.41</red>
+    <green type="float">0.4</green>
+    <blue type="float">0.42</blue>
+    <alpha type="float">1.0</alpha>
+    <alpha type="float">1.0</alpha>
+  </color>
+
+  <nasal>
+    <open>
+      var dlgRoot = cmdarg();
+      var checklists = props.globals.getNode("/sim/checklists", 1).getChildren("checklist");
+      
+      if (size(checklists) > 0) {
+        
+        var combo = gui.findElementByName(dlgRoot, "checklist-combo");
+        var group = gui.findElementByName(dlgRoot, "checklist-table-group");
+        
+        forindex (var idx; checklists) {
+          combo.getChild("value", idx, 1).setValue(checklists[idx].getNode("title", 1).getValue());
+          var c = checklists[idx];        
+          var row = 0;
+          
+          # Set up a new table, only visible when this checklist is selected.
+          var table = group.getChild("group", idx, 1);
+          table.getNode("row", 1).setValue(0);
+          table.getNode("col", 1).setValue(0);
+          table.getNode("default-padding", 1).setValue(4);
+          table.getNode("layout", 1).setValue("table");
+          table.getNode("valign", 1).setValue("top");
+          
+          var vis = table.getNode("visible", 1).getNode("equals", 1);
+          vis.getNode("property", 1).setValue("sim/gui/dialogs/checklist/selected-checklist");
+          vis.getNode("value", 1).setValue(c.getNode("title").getValue());
+          
+          var items = c.getChildren("item");
+          var txtcount = 0;
+          
+          forindex (var i; items) {          
+            var item = items[i];
+
+            var t = table.getChild("text", txtcount, 1);
+            txtcount += 1;
+            
+            t.getNode("halign", 1).setValue("left");
+            t.getNode("row", 1).setValue(row);
+            t.getNode("col", 1).setValue(0);
+            t.getNode("label", 1).setValue(item.getNode("name", 1).getValue());
+            
+            var values = item.getChildren("value");
+            
+            forindex (var v; values) {
+              var t = table.getChild("text", txtcount, 1);
+              txtcount += 1;
+              t.getNode("halign", 1).setValue("right");
+              t.getNode("row", 1).setValue(row);
+              if (v > 0) {
+                # The second row of values can overlap with the
+                # first column if required - helps keep the 
+                # checklist dialog as compact as possible
+                t.getNode("col", 1).setValue(0);
+                t.getNode("colspan", 1).setValue(2);
+              } else {
+                t.getNode("col", 1).setValue(1);
+              }
+                
+              t.getNode("label", 1).setValue(values[v].getValue());                
+              row = row + 1;              
+            }
+          }
+        }
+        
+        setprop("sim/gui/dialogs/checklist/selected-checklist", 
+                checklists[0].getNode("title").getValue());
+      } else {
+          var group = gui.findElementByName(dlgRoot, "checklist-table-group");
+          var table = group.getNode("text", 1);
+          table.getNode("row", 1).setValue(0);
+          table.getNode("col", 1).setValue(0);
+          table.getNode("default-padding", 1).setValue(4);
+          table.getNode("layout", 1).setValue("table");
+          table.getNode("valign", 1).setValue("top");
+          table.getNode("halign", 1).setValue("center");
+          table.getNode("label", 1).setValue("No checklists exist for this aircraft");
+      
+      }
+      
+      var setTransparency = func(updateDialog){
+          var alpha = (getprop("/sim/gui/dialogs/checklist/transparent") or 0);
+          dlgRoot.getNode("color/alpha").setValue(1-alpha*0.3);
+          dlgRoot.getNode("color/red").setValue(0.41-alpha*0.2);
+          dlgRoot.getNode("color/green").setValue(0.4-alpha*0.2);
+          dlgRoot.getNode("color/blue").setValue(0.42-alpha*0.2);
+          var n = props.Node.new({ "dialog-name": "checklist" });
+          if (updateDialog)
+          {
+              fgcommand("dialog-close", n);
+              fgcommand("dialog-show", n);
+          }
+      }
+      setTransparency(0);
+      
+    </open>
+  </nasal>
+
+  <group>
+    <layout>hbox</layout>
+    <empty><stretch>1</stretch></empty>
+
+    <text>
+      <label>Aircraft Checklists</label>
+    </text>
+
+    <empty><stretch>1</stretch></empty>
+
+    <button>
+      <pref-width>16</pref-width>
+      <pref-height>16</pref-height>
+      <legend></legend>
+      <keynum>27</keynum>
+      <border>2</border>
+      <binding>
+        <command>dialog-close</command>
+      </binding>
+    </button>
+  </group>
+
+  <hrule/>
+
+  <group>
+    <layout>hbox</layout>
+
+    <text>
+      <halign>right</halign>
+      <label>Checklist:</label>
+    </text>
+
+    <combo>
+      <name>checklist-combo</name>
+      <property>/sim/gui/dialogs/checklist/selected-checklist</property>
+      <editable>false</editable>
+      <pref-width>200</pref-width>
+      <halign>fill</halign>
+      <binding>
+        <command>dialog-apply</command>
+        <object-name>checklist-combo</object-name>
+      </binding>
+    </combo>
+    
+    <empty><stretch>true</stretch></empty>
+    
+    <checkbox>
+        <label>Transparent</label>
+        <pref-width>100</pref-width>
+        <property>/sim/gui/dialogs/checklist/transparent</property>
+        <live>true</live>
+        <halign>right</halign>
+        <binding>
+          <command>dialog-apply</command>
+        </binding>
+        <binding>
+          <command>property-toggle</command>
+        </binding>
+        <binding>
+            <command>nasal</command>
+            <script>setTransparency(1);</script>
+        </binding>
+    </checkbox>
+  </group>
+  
+  <hrule/>
+  
+  <group>
+    <default-padding>4</default-padding>
+    <halign>fill</halign>
+    <layout>table</layout>
+    <name>checklist-table-group</name>
+  </group>
+</PropertyList>
diff --git a/gui/menubar.xml b/gui/menubar.xml
index c6bdf4a69..aadd572fb 100644
--- a/gui/menubar.xml
+++ b/gui/menubar.xml
@@ -711,6 +711,14 @@
 				<script>gui.showHelpDialog("/sim/help")</script>
 			</binding>
 		</item>
+		
+		<item>
+			<name>aircraft-checklists</name>
+			<binding>
+				<command>dialog-show</command>
+				<dialog-name>checklist</dialog-name>
+			</binding>
+		</item>
 
 		<item>
 			<name>common-keys</name>

From d775c221b7debdf7c684306147d7df776c220969 Mon Sep 17 00:00:00 2001
From: Thomas Geymayer <tomgey@gmail.com>
Date: Tue, 18 Sep 2012 13:07:41 +0200
Subject: [PATCH 05/11] Move map helpers to canvas Nasal module

---
 Nasal/canvas/map.nas     | 169 +++++++++++++++++++++++++++++++++++++++
 gui/dialogs/airports.xml | 154 +----------------------------------
 2 files changed, 171 insertions(+), 152 deletions(-)
 create mode 100644 Nasal/canvas/map.nas

diff --git a/Nasal/canvas/map.nas b/Nasal/canvas/map.nas
new file mode 100644
index 000000000..a1c1293bb
--- /dev/null
+++ b/Nasal/canvas/map.nas
@@ -0,0 +1,169 @@
+# Runway
+#
+var Runway = {
+  # Create Runway from hash
+  #
+  # @param rwy  Hash containing runway data as returned from
+  #             airportinfo().runways[ <runway designator> ]
+  new: func(rwy)
+  {
+    return {
+      parents: [Runway],
+      rwy: rwy
+    };
+  },
+  # Get a point on the runway with the given offset
+  #
+  # @param pos  Position along the center line
+  # @param off  Offset perpendicular to the center line
+  pointOffCenterline: func(pos, off = 0)
+  {
+    var coord = geo.Coord.new();
+    coord.set_latlon(me.rwy.lat, me.rwy.lon);
+    coord.apply_course_distance(me.rwy.heading, pos - 0.5 * me.rwy.length);
+
+    if( off )
+      coord.apply_course_distance(me.rwy.heading + 90, off);
+
+    return ["N" ~ coord.lat(), "E" ~ coord.lon()];
+  }
+};
+
+# AirportMap
+#
+var AirportMap = {
+  # Create AirportMap from hash
+  #
+  # @param apt  Hash containing airport data as returned from airportinfo()
+  new: func(apt)
+  {
+    return {
+      parents: [AirportMap],
+      _apt: apt
+    };
+  },
+  # Build the graphical representation of the represented airport
+  #
+  # @param layer_runways  canvas.Group to attach airport map to
+  # @param selected       [optional] The name of a property containing the
+  #                       currently selected runway
+  build: func(layer_runways, selected = nil)
+  {
+    var rws_done = {};
+
+    me.grp_apt = layer_runways.createChild("group", "apt-" ~ me._apt.id);
+    var selected_rwy = (selected) ? getprop(selected) : nil;
+
+    foreach(var rw; keys(me._apt.runways))
+    {
+      var is_heli = substr(rw, 0, 1) == "H";
+      var rw_dir = is_heli ? nil : int(substr(rw, 0, 2));
+
+      var rw_rec = "";
+      var thresh_rec = 0;
+      if( rw_dir != nil )
+      {
+        rw_rec = sprintf("%02d", math.mod(rw_dir - 18, 36));
+        if( size(rw) == 3 )
+        {
+          var map_rec = {
+            "R": "L",
+            "L": "R",
+            "C": "C"
+          };
+          rw_rec ~= map_rec[substr(rw, 2)];
+        }
+
+        if( rws_done[rw_rec] != nil )
+          continue;
+
+        var rw_rec = me._apt.runways[rw_rec];
+        if( rw_rec != nil )
+          thresh_rec = rw_rec.threshold;
+      }
+
+      rws_done[rw] = 1;
+
+      rw = me._apt.runways[rw];
+      var icon_rw =
+        me.grp_apt.createChild("path", "runway")
+                  .setStrokeLineWidth(0.5)
+                  .setColor(1.0,1.0,1.0)
+                  .setColorFill(0.2, 0.2, 0.2);
+
+      var rwy = Runway.new(rw);
+      var beg_thr  = rwy.pointOffCenterline(rw.threshold);
+      var beg_thr1 = rwy.pointOffCenterline(rw.threshold,  0.5 * rw.width);
+      var beg_thr2 = rwy.pointOffCenterline(rw.threshold, -0.5 * rw.width);
+      var beg1 = rwy.pointOffCenterline(0,  0.5 * rw.width);
+      var beg2 = rwy.pointOffCenterline(0, -0.5 * rw.width);
+
+      var end_thr  = rwy.pointOffCenterline(rw.length - thresh_rec);
+      var end_thr1 = rwy.pointOffCenterline(rw.length - thresh_rec,  0.5 * rw.width);
+      var end_thr2 = rwy.pointOffCenterline(rw.length - thresh_rec, -0.5 * rw.width);
+      var end1 = rwy.pointOffCenterline(rw.length,  0.5 * rw.width);
+      var end2 = rwy.pointOffCenterline(rw.length, -0.5 * rw.width);
+
+      icon_rw.setDataGeo
+      (
+        [ canvas.Path.VG_MOVE_TO,
+          canvas.Path.VG_LINE_TO,
+          canvas.Path.VG_LINE_TO,
+          canvas.Path.VG_LINE_TO,
+          canvas.Path.VG_CLOSE_PATH ],
+        [ beg1[0], beg1[1],
+          beg2[0], beg2[1],
+          end2[0], end2[1],
+          end1[0], end1[1] ]
+      );
+
+      if( rw.length / rw.width > 3 and !is_heli )
+      {
+        # only runways which are much longer than wide are
+        # real runways, otherwise it's probably a heliport.
+        var icon_cl =
+          me.grp_apt.createChild("path", "centerline")
+                    .setStrokeLineWidth(0.5)
+                    .setColor(1,1,1)
+                    .setStrokeDashArray([15, 10]);
+
+        icon_cl.setDataGeo
+        (
+          [ canvas.Path.VG_MOVE_TO,
+            canvas.Path.VG_LINE_TO ],
+          [ beg_thr[0], beg_thr[1],
+            end_thr[0], end_thr[1] ]
+        );
+
+        var icon_thr =
+          me.grp_apt.createChild("path", "threshold")
+                    .setStrokeLineWidth(1.5)
+                    .setColor(1,1,1);
+
+        icon_thr.setDataGeo
+        (
+          [ canvas.Path.VG_MOVE_TO,
+            canvas.Path.VG_LINE_TO,
+            canvas.Path.VG_MOVE_TO,
+            canvas.Path.VG_LINE_TO ],
+          [ beg_thr1[0], beg_thr1[1],
+            beg_thr2[0], beg_thr2[1],
+            end_thr1[0], end_thr1[1],
+            end_thr2[0], end_thr2[1] ]
+        );
+      }
+    }
+
+    foreach(var park; me._apt.parking())
+    {
+      var icon_park =
+        me.grp_apt.createChild("text")
+                  .setDrawMode( canvas.Text.ALIGNMENT
+                              + canvas.Text.TEXT )
+                  .setText(park.name)
+                  .setFont("LiberationFonts/LiberationMono-Bold.ttf")
+                  .setGeoPosition(park.lat, park.lon)
+                  .setFontSize(15, 1.3);
+    }
+  }
+};
diff --git a/gui/dialogs/airports.xml b/gui/dialogs/airports.xml
index 2fce23517..25b6ad8d2 100644
--- a/gui/dialogs/airports.xml
+++ b/gui/dialogs/airports.xml
@@ -412,156 +412,6 @@
       
       
         <load><![CDATA[
-          var Runway = {
-            new: func(rwy)
-            {
-              return {
-                parents: [Runway],
-                rwy: rwy
-              };
-            },
-            pointOffCenterline: func(pos, off = 0)
-            {
-              var coord = geo.Coord.new();
-              coord.set_latlon(me.rwy.lat, me.rwy.lon);
-              coord.apply_course_distance(me.rwy.heading, pos - 0.5 * me.rwy.length);
-              
-              if( off )
-                coord.apply_course_distance(me.rwy.heading + 90, off);
-              
-              return ["N" ~ coord.lat(), "E" ~ coord.lon()];
-            }
-          };
-          
-          var AirportMap = {
-            new: func(apt)
-            {
-              return {
-                parents: [AirportMap],
-                _apt: apt
-              };
-            },
-            build: func(layer_runways)
-            {
-              var rws_done = {};
-
-              me.grp_apt = layer_runways.createChild("group", "apt-" ~ me._apt.id);
-              var selected_rwy = getprop("/sim/gui/dialogs/airports/selected-airport/rwy");          
-              
-              foreach(var rw; keys(me._apt.runways))
-              {
-                var is_heli = substr(rw, 0, 1) == "H";
-                var rw_dir = is_heli ? nil : int(substr(rw, 0, 2));
-                
-                var rw_rec = "";            
-                var thresh_rec = 0;
-                if( rw_dir != nil )
-                {
-                  rw_rec = sprintf("%02d", math.mod(rw_dir - 18, 36));
-                  if( size(rw) == 3 )
-                  {
-                    var map_rec = {
-                      "R": "L",
-                      "L": "R",
-                      "C": "C"
-                    };
-                    rw_rec ~= map_rec[substr(rw, 2)];
-                  }
-                  
-                  if( rws_done[rw_rec] != nil )
-                    continue;
-                  
-                  var rw_rec = me._apt.runways[rw_rec];
-                  if( rw_rec != nil )
-                    thresh_rec = rw_rec.threshold;
-                }
-
-                rws_done[rw] = 1; 
-
-                rw = me._apt.runways[rw];
-                var icon_rw =
-                  me.grp_apt.createChild("path", "runway")
-                            .setStrokeLineWidth(0.5)
-                            .setColor(1.0,1.0,1.0)
-                            .setColorFill(0.2, 0.2, 0.2);
-
-                var rwy = Runway.new(rw);
-                var beg_thr  = rwy.pointOffCenterline(rw.threshold);
-                var beg_thr1 = rwy.pointOffCenterline(rw.threshold,  0.5 * rw.width);
-                var beg_thr2 = rwy.pointOffCenterline(rw.threshold, -0.5 * rw.width);
-                var beg1 = rwy.pointOffCenterline(0,  0.5 * rw.width);
-                var beg2 = rwy.pointOffCenterline(0, -0.5 * rw.width);
-                
-                var end_thr  = rwy.pointOffCenterline(rw.length - thresh_rec);
-                var end_thr1 = rwy.pointOffCenterline(rw.length - thresh_rec,  0.5 * rw.width);
-                var end_thr2 = rwy.pointOffCenterline(rw.length - thresh_rec, -0.5 * rw.width);
-                var end1 = rwy.pointOffCenterline(rw.length,  0.5 * rw.width);
-                var end2 = rwy.pointOffCenterline(rw.length, -0.5 * rw.width);
-
-                icon_rw.setDataGeo
-                (
-                  [ canvas.Path.VG_MOVE_TO,
-                    canvas.Path.VG_LINE_TO,
-                    canvas.Path.VG_LINE_TO,
-                    canvas.Path.VG_LINE_TO,
-                    canvas.Path.VG_CLOSE_PATH ],
-                  [ beg1[0], beg1[1],
-                    beg2[0], beg2[1],
-                    end2[0], end2[1],
-                    end1[0], end1[1] ]
-                );
-                
-                if( rw.length / rw.width > 3 and !is_heli )
-                {
-                  # only runways which are much longer than wide are
-                  # real runways, otherwise it's probably a heliport.
-                  var icon_cl =
-                    me.grp_apt.createChild("path", "centerline")
-                              .setStrokeLineWidth(0.5)
-                              .setColor(1,1,1)
-                              .setStrokeDashArray([15, 10]);
-                  
-                  icon_cl.setDataGeo
-                  (
-                    [ canvas.Path.VG_MOVE_TO,
-                      canvas.Path.VG_LINE_TO ],
-                    [ beg_thr[0], beg_thr[1],
-                      end_thr[0], end_thr[1] ]
-                  );
-                  
-                  var icon_thr =
-                    me.grp_apt.createChild("path", "threshold")
-                              .setStrokeLineWidth(1.5)
-                              .setColor(1,1,1);
-                  
-                  icon_thr.setDataGeo
-                  (
-                    [ canvas.Path.VG_MOVE_TO,
-                      canvas.Path.VG_LINE_TO,
-                      canvas.Path.VG_MOVE_TO,
-                      canvas.Path.VG_LINE_TO ],
-                    [ beg_thr1[0], beg_thr1[1],
-                      beg_thr2[0], beg_thr2[1],
-                      end_thr1[0], end_thr1[1],
-                      end_thr2[0], end_thr2[1] ]
-                  );
-                }
-              }
-              
-              foreach(var park; me._apt.parking())
-              {
-                var icon_park =
-                  me.grp_apt.createChild("text")
-                            .setDrawMode( canvas.Text.ALIGNMENT
-                                        + canvas.Text.TEXT )
-                            .setText(park.name)
-                            .setFont("LiberationFonts/LiberationMono-Bold.ttf")
-                            .setGeoPosition(park.lat, park.lon)
-                            .setFontSize(15, 1.3);
-              }
-            }
-          };
-
           var my_canvas = canvas.get(cmdarg());
           my_canvas.setColorBackground(0.2, 0.5, 0.2, 0.5);
 
@@ -588,8 +438,8 @@
           
             if (id != "") {
               var apt = airportinfo(id);
-              var airport = AirportMap.new(apt);
-              airport.build(layer_runways);
+              var airport = canvas.AirportMap.new(apt);
+              airport.build(layer_runways, "/sim/gui/dialogs/airports/selected-airport/rwy" );
 
               var pos = apt.tower();
               icon_tower.setGeoPosition(pos.lat, pos.lon);

From 0fe2007cb536ebbb84553d59bd6e9c1f3c098669 Mon Sep 17 00:00:00 2001
From: Stuart Buchanan <stuart_d_buchanan@yahoo.co.uk>
Date: Tue, 18 Sep 2012 14:08:53 +0100
Subject: [PATCH 06/11] Check in c172 checklists - missing from previous
 commit.

---
 Aircraft/c172p/c172-checklists.xml | 444 +++++++++++++++++++++++++++++
 1 file changed, 444 insertions(+)
 create mode 100644 Aircraft/c172p/c172-checklists.xml

diff --git a/Aircraft/c172p/c172-checklists.xml b/Aircraft/c172p/c172-checklists.xml
new file mode 100644
index 000000000..646299de8
--- /dev/null
+++ b/Aircraft/c172p/c172-checklists.xml
@@ -0,0 +1,444 @@
+<PropertyList>
+  <checklist>  
+    <title>Before Starting Engine</title>
+    <item>
+      <name>Preflight Inspection</name>
+      <value>COMPLETE</value>
+    </item>
+    <item>
+      <name>Passenger</name>
+      <value>COMPLETE</value>
+    </item>
+    <item>
+      <name>Seats, Seat Belts, Shoulder Harnesses</name>
+      <value>ADJUST and LOCK</value>
+    </item>
+    <item>
+      <name>Brakes</name>
+      <value>TEST and SET (shift-B)</value>
+    </item>
+    <item>
+      <name>Avionics Power Switch</name>
+      <value>OFF</value>
+    </item>
+    <item>
+      <name>Circuit Breakers</name>
+      <value>CHECK IN</value>
+    </item>
+    <item>
+      <name>Electrical Equipment, Autopilot</name>
+      <value>OFF</value>
+    </item>
+    <item>
+      <name>Fuel Selector Valve</name>
+      <value>BOTH</value>
+    </item>
+  </checklist>
+  
+  
+  <checklist>
+    <title>Starting Engine</title>
+    <item>
+      <name>Prime</name>
+      <value>As Required - 2-6 strokes</value>
+    </item>
+    <item>
+      <name>Carburetor Heat</name>
+      <value>COLD</value>
+    </item>
+    <item>
+      <name>Throttle</name>
+      <value>OPEN 1/8 INCH</value>
+    </item>    
+    <item>
+      <name>Mixture</name>
+      <value>RICH</value>
+    </item>
+    <item>
+      <name>Propellor Area</name>
+      <value>CLEAR</value>
+    </item>
+    <item>
+      <name>Master Switch</name>
+      <value>ON</value>
+    </item>
+    <item>
+      <name>Magnetos</name>
+      <value>BOTH</value>
+      <value>(press } three times)</value>
+    </item>
+    <item>
+      <name>Ignition Switch</name>
+      <value>ON</value>
+      <value>(press s, release when engine starts)</value>
+    </item>
+    <item>
+      <name>Oil Pressure</name>
+      <value>CHECK</value>
+    </item>
+    <item>
+      <name>Avionics Power Switch</name>
+      <value>ON</value>
+    </item>
+    <item>
+      <name>Navigation Lights and Flashing Beacon</name>
+      <value>ON as required</value>
+    </item>
+    <item>
+      <name>Radios</name>
+      <value>ON</value>
+    </item>
+  </checklist>
+  
+  <checklist>
+    <title>Before Takeoff</title>
+    <item>
+      <name>Parking Brake</name>
+      <value>SET (shift-B)</value>
+    </item>
+    <item>
+      <name>Seats, Seat Belts, Shoulder Harnesses</name>
+      <value>CHECK SECURE</value>
+    </item>
+    <item>
+      <name>Cabin Doors</name>
+      <value>CLOSED and LOCKED</value>
+    </item>
+    <item>
+      <name>Flight Controls</name>
+      <value>FREE and CORRECT</value>
+    </item>
+    <item>
+      <name>Flight Instruments</name>
+      <value>CHECK and SET</value>
+    </item>
+    <item>
+      <name>Fuel Quantity</name>
+      <value>CHECK</value>
+    </item>
+    <item>
+      <name>Mixture</name>
+      <value>RICH</value>
+    </item>
+    <item>
+      <name>Fuel Selector Valve</name>
+      <value>RECHECK BOTH</value>
+    </item>
+    <item>
+      <name>Elevator Trim</name>
+      <value>SET for takeoff</value>
+    </item>
+    <item>
+      <name>Throttle</name>
+      <value>1700 RPM</value>
+    </item>
+    <item>
+      <name>Magnetos</name>
+      <value>CHECK RPM DROP</value>
+      <value>(125 rpm max)</value>
+    </item>
+    <item>
+      <name>Carburetor Heat</name>
+      <value>CHECK for RPM drop</value>
+    </item>
+    <item>
+      <name>Suction Gauge</name>
+      <value>CHECK</value>
+    </item>
+    <item>
+      <name>Engine Instruments and Ammeter</name>
+      <value>CHECK</value>
+    </item>
+    <item>
+      <name>Throttle</name>
+      <value>1000RPM or LESS</value>
+    </item>
+    <item>
+      <name>Throttle Friction Lock</name>
+      <value>ADJUST</value>
+    </item>
+    <item>
+      <name>Strobe Lights</name>
+      <value>AS DESIRED</value>
+    </item>
+    <item>
+      <name>Radios and Avionics</name>
+      <value>SET</value>
+    </item>
+    <item>
+      <name>Autopilot</name>
+      <value>OFF</value>
+    </item>
+    <item>
+      <name>Wing Flaps</name>
+      <value>SET for takeoff</value>
+    </item>
+    <item>
+      <name>Brakes</name>
+      <value>RELEASE</value>
+    </item>    
+  </checklist>
+  
+  <checklist>
+    <title>Normal Takeoff</title>  
+    <item>
+      <name>Wing Flaps</name>
+      <value>0 - 10 degrees</value>
+    </item>
+    <item>
+      <name>Carburetor Heat</name>
+      <value>COLD</value>
+    </item>
+    <item>
+      <name>Throttle</name>
+      <value>FULL OPEN</value>
+    </item>
+    <item>
+      <name>Elevator Control</name>
+      <value>LIFT NOSE WHEEL</value>
+      <value>(at 55 KIAS)</value>
+    </item>
+  </checklist>
+
+  <checklist>
+    <title>Short Field Takeoff</title>  
+    <item>
+      <name>Wing Flaps</name>
+      <value>10 degrees</value>
+    </item>
+    <item>
+      <name>Carburetor Heat</name>
+      <value>COLD</value>
+    </item>
+    <item>
+      <name>Brakes</name>
+      <value>APPLY</value>
+    </item>
+    <item>
+      <name>Throttle</name>
+      <value>FULL OPEN</value>
+    </item>
+    <item>
+      <name>Mixture</name>
+      <value>RICH</value>
+      <value>(above 3000ft, LEAN to obtain maximum RPM)</value>
+    </item>
+    <item>
+      <name>Brakes</name>
+      <value>RELEASE</value>
+    </item>
+    <item>
+      <name>Elevator Control</name>
+      <value>SLIGHTLY TAIL LOW</value>
+    </item>
+    <item>
+      <name>Climb Speed</name>
+      <value>56 KIAS</value>
+    </item>
+  </checklist>
+
+  <checklist>
+    <title>Enroute Climb</title>  
+    <item>
+      <name>Airspeed</name>
+      <value>70-85 KIAS</value>
+    </item>
+    <item>
+      <name>Throttle</name>
+      <value>FULL OPEN</value>
+    </item>
+    <item>
+      <name>Mixture</name>
+      <value>RICH</value>
+      <value>(above 3000ft, LEAN to obtain maximum RPM)</value>
+    </item>
+  </checklist>
+
+  <checklist>
+    <title>Cruise</title>  
+    <item>
+      <name>Power</name>
+      <value>2100-2700 RPM</value>
+      <value>(no more than 75% recommended)</value>
+    </item>
+    <item>
+      <name>Elevator Trim</name>
+      <value>ADJUST</value>
+    </item>
+    <item>
+      <name>Mixture</name>
+      <value>LEAN</value>
+    </item>
+  </checklist>
+
+  <checklist>
+    <title>Descent</title>  
+    <item>
+      <name>Fuel Selector Valve</name>
+      <value>BOTH</value>
+    </item>
+    <item>
+      <name>Power</name>
+      <value>AS DESIRED</value>
+    </item>
+    <item>
+      <name>Mixture</name>
+      <value>ADJUST for smooth operation</value>
+      <value>(full rich for idle power)</value>
+    </item>
+    <item>
+      <name>Carburetor Heat</name>
+      <value>FULL HEAT AS REQUIRED</value>
+      <value>(to prevent carburetor icing)</value>
+    </item>
+  </checklist>
+
+  <checklist>
+    <title>Before Landing</title>  
+    <item>
+      <name>Seats, Seat Belt, Shoulder Harnesses</name>
+      <value>SECURE</value>
+    </item>
+    <item>
+      <name>Fuel Selector Valve</name>
+      <value>BOTH</value>
+    </item>
+    <item>
+      <name>Mixture</name>
+      <value>RICH</value>
+    </item>
+    <item>
+      <name>Carburetor Heat</name>
+      <value>FULL HEAT</value>
+      <value>(apply full heat before reducing power)</value>
+    </item>
+    <item>
+      <name>Autopilot</name>
+      <value>OFF</value>
+    </item>
+  </checklist>
+
+  <checklist>
+    <title>Normal Landing</title>  
+    <item>
+      <name>Airspeed</name>
+      <value>65-75 KIAS (flaps UP)</value>
+    </item>
+    <item>
+      <name>Wing Flaps</name>
+      <value>AS DESIRED</value>
+      <value>(0 - 10 degrees below 110KIAS</value>
+      <value>10 - 30 degrees below 85KIAS</value>
+    </item>
+    <item>
+      <name>Airspeed</name>
+      <value>60-70 KIAS (flaps DOWN)</value>
+    </item>
+    <item>
+      <name>Touchdown</name>
+      <value>MAIN WHEELS FIRST</value>
+    </item>
+    <item>
+      <name>Landing Roll</name>
+      <value>LOWER NOSE WHEEL GENTLY</value>
+    </item>
+    <item>
+      <name>Braking</name>
+      <value>MINIMUM REQUIRED</value>
+    </item>
+  </checklist>
+
+  <checklist>
+    <title>Short Field Landing</title>  
+    <item>
+      <name>Airspeed</name>
+      <value>65-75 KIAS (flaps UP)</value>
+    </item>
+    <item>
+      <name>Wing Flaps</name>
+      <value>FULL DOWN (30 degrees)</value>
+    </item>
+    <item>
+      <name>Airspeed</name>
+      <value>61 KIAS (until flare)</value>
+    </item>
+    <item>
+      <name>Power</name>
+      <value>REDUCE to idle after clearing obstacle</value>
+    </item>
+    <item>
+      <name>Touchdown</name>
+      <value>MAIN WHEELS FIRST</value>
+    </item>
+    <item>
+      <name>Braking</name>
+      <value>APPLY HEAVILY</value>
+    </item>
+    <item>
+      <name>Wing Flaps</name>
+      <value>RETRACT</value>
+    </item>
+  </checklist>
+
+  <checklist>
+    <title>Aborted Landing</title>  
+    <item>
+      <name>Throttle</name>
+      <value>FULL OPEN</value>
+    </item>
+    <item>
+      <name>Carburetor Heat</name>
+      <value>COLD</value>
+    </item>
+    <item>
+      <name>Wing Flaps</name>
+      <value>20 degrees (immediately)</value>
+    </item>
+    <item>
+      <name>Climb Speed</name>
+      <value>55 KIAS</value>
+    </item>
+    <item>
+      <name>Wing Flaps</name>
+      <value>10 degrees (until obstacles are cleared)</value>
+      <value>RETRACT (after reaching safe altitude and 60 KIAS)</value>
+    </item>
+  </checklist>
+
+  <checklist>
+    <title>After Landing</title>  
+    <item>
+      <name>Carburetor Heat</name>
+      <value>COLD</value>
+    </item>
+    <item>
+      <name>Wing Flaps</name>
+      <value>UP</value>
+    </item>
+  </checklist>
+  
+  <checklist>
+    <title>Securing Airplane</title>  
+    <item>
+      <name>Parking Brake</name>
+      <value>SET</value>
+    </item>
+    <item>
+      <name>Avionics, Power, Electrical, Autopilot</name>
+      <value>OFF</value>
+    </item>
+    <item>
+      <name>Mixture</name>
+      <value>PULLED FULL OUT</value>
+    </item>
+    <item>
+      <name>Ignition Switch</name>
+      <value>OFF</value>
+    </item>
+    <item>
+      <name>Control Lock</name>
+      <value>INSTALL</value>
+    </item>
+  </checklist>
+  
+</PropertyList>

From 692f1be621782cf4156d6a4e49cfcd061b0488cd Mon Sep 17 00:00:00 2001
From: Stuart Buchanan <stuart_d_buchanan@yahoo.co.uk>
Date: Tue, 18 Sep 2012 15:48:50 +0100
Subject: [PATCH 07/11] Add additional information to the About dialog to help
 diagnostics, including the ability to copy/past key data.

---
 gui/dialogs/about.xml | 92 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/gui/dialogs/about.xml b/gui/dialogs/about.xml
index 0886cc404..bddef0a9f 100644
--- a/gui/dialogs/about.xml
+++ b/gui/dialogs/about.xml
@@ -113,6 +113,9 @@
     <empty>
       <stretch>true</stretch>
     </empty>
+    
+    <hrule/>
+    
 
     <text>
       <halign>center</halign>
@@ -166,7 +169,67 @@
         <format>Revision: %s</format>
         <property>/sim/version/revision</property>
       </text>
+    </group>
       
+    <empty>
+      <stretch>true</stretch>
+    </empty>
+
+    <hrule/>
+      
+    <text>
+      <halign>center</halign>
+      <label>Graphics/OpenGL Information</label>
+    </text>
+    
+    <group>
+      <layout>vbox</layout>
+      <border>10</border>
+      <halign>center</halign>
+      <default-padding>2</default-padding>
+    
+  
+      <text>
+        <halign>left</halign>
+        <label>MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM</label>
+        <format>OpenGL Vendor: %s</format>
+        <property>/sim/rendering/gl-vendor</property>
+      </text>
+
+      <text>
+        <halign>left</halign>
+        <label>MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM</label>
+        <format>OpenGL Renderer: %s</format>
+        <property>/sim/rendering/gl-renderer</property>
+      </text>
+
+      <text>
+        <halign>left</halign>
+        <label>MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM</label>
+        <format>OpenGL Version: %s</format>
+        <property>/sim/rendering/gl-version</property>
+      </text>
+   
+      <text>
+        <halign>left</halign>
+        <label>MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM</label>
+        <format>GLSL Version: %s</format>
+        <property>/sim/rendering/gl-shading-language-version</property>
+      </text>
+
+      <text>
+        <halign>left</halign>
+        <label>MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM</label>
+        <format>Max Texture Size: %s</format>
+        <property>/sim/rendering/max-texture-size</property>
+      </text>
+
+      <text>
+        <halign>left</halign>
+        <label>MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM</label>
+        <format>Depth Buffer Bits: %s</format>
+        <property>/sim/rendering/depth-buffer-bits</property>
+      </text>
     </group>
   </group>
   
@@ -188,6 +251,35 @@
       </binding>
     </button>
 
+    <button>
+      <legend>Take screen shot</legend>
+      <equal>true</equal>
+      <default>false</default>
+      <binding>
+        <command>nasal</command>
+   <script>fgcommand("screen-capture");</script>
+      </binding>
+    </button>
+
+    <button>
+      <legend>Copy to Clipboard</legend>
+      <equal>true</equal>
+      <default>false</default>
+      <binding>
+        <command>nasal</command>
+        <script><![CDATA[
+   var properties = ["gl-vendor","gl-version","gl-renderer", "gl-shading-language-version"];
+   var data = "";
+   var path = "/sim/rendering/";
+   foreach(var p; properties)
+      data ~= p ~":"~getprop(path~p) ~"\n";
+   clipboard.setText(data);
+   gui.popupTip("Copied version information to clipboard!");
+   ]]></script>
+      </binding>
+    </button>
+
+
     <empty><stretch>true</stretch></empty>
     
   </group>

From d214a6fcf805380f2ae6d8141dfebfb0c7af377c Mon Sep 17 00:00:00 2001
From: Stuart Buchanan <stuart_d_buchanan@yahoo.co.uk>
Date: Tue, 18 Sep 2012 19:28:56 +0100
Subject: [PATCH 08/11] Add highlighting of selected runway/parking position. 
 Move tower definition and placement to map.nas.

---
 Nasal/canvas/map.nas     | 25 ++++++++---
 gui/dialogs/airports.xml | 89 ++++++++++++++++++++++++++++++++--------
 2 files changed, 91 insertions(+), 23 deletions(-)

diff --git a/Nasal/canvas/map.nas b/Nasal/canvas/map.nas
index a1c1293bb..0e1196907 100644
--- a/Nasal/canvas/map.nas
+++ b/Nasal/canvas/map.nas
@@ -45,14 +45,11 @@ var AirportMap = {
   # Build the graphical representation of the represented airport
   #
   # @param layer_runways  canvas.Group to attach airport map to
-  # @param selected       [optional] The name of a property containing the
-  #                       currently selected runway
-  build: func(layer_runways, selected = nil)
+  build: func(layer_runways)
   {
     var rws_done = {};
 
     me.grp_apt = layer_runways.createChild("group", "apt-" ~ me._apt.id);
-    var selected_rwy = (selected) ? getprop(selected) : nil;
 
     foreach(var rw; keys(me._apt.runways))
     {
@@ -86,7 +83,7 @@ var AirportMap = {
 
       rw = me._apt.runways[rw];
       var icon_rw =
-        me.grp_apt.createChild("path", "runway")
+        me.grp_apt.createChild("path", "runway-" ~ rw.id)
                   .setStrokeLineWidth(0.5)
                   .setColor(1.0,1.0,1.0)
                   .setColorFill(0.2, 0.2, 0.2);
@@ -157,7 +154,7 @@ var AirportMap = {
     foreach(var park; me._apt.parking())
     {
       var icon_park =
-        me.grp_apt.createChild("text")
+        me.grp_apt.createChild("text", "parking-" ~ park.name)
                   .setDrawMode( canvas.Text.ALIGNMENT
                               + canvas.Text.TEXT )
                   .setText(park.name)
@@ -165,5 +162,21 @@ var AirportMap = {
                   .setGeoPosition(park.lat, park.lon)
                   .setFontSize(15, 1.3);
     }
+    
+    var icon_tower =
+            me.grp_apt.createChild("path", "tower")
+               .setStrokeLineWidth(1)
+               .setScale(1.5)
+               .setColor(0.2,0.2,1.0)
+               .moveTo(-3, 0)
+               .vert(-10)
+               .line(-3, -10)
+               .horiz(12)
+               .line(-3, 10)
+               .vert(10);
+               
+    var pos = me._apt.tower();
+    icon_tower.setGeoPosition(pos.lat, pos.lon);               
+    
   }
 };
diff --git a/gui/dialogs/airports.xml b/gui/dialogs/airports.xml
index 25b6ad8d2..a96032344 100644
--- a/gui/dialogs/airports.xml
+++ b/gui/dialogs/airports.xml
@@ -31,10 +31,11 @@
 
   <nasal>
     <open>
-      var airport_id = getprop("/sim/presets/airport-id");
       setprop("/sim/gui/dialogs/airports/selected-airport/rwy", "");
       setprop("/sim/gui/dialogs/airports/selected-airport/parkpos", "");
-
+      setprop("/sim/gui/dialogs/airports/list", "");
+      
+      var airport_id = getprop("/sim/presets/airport-id");
       if (airport_id == nil) { airport_id = "KSFO"; }
       
       var dlg = props.globals.getNode("/sim/gui/dialogs/airports", 1);
@@ -77,6 +78,8 @@
           setprop("/sim/gui/dialogs/airports/selected-airport/location", sprintf("%.3f / %.3f", info.lon, info.lat));
           setprop("/sim/gui/dialogs/airports/selected-airport/lon", info.lon);
           setprop("/sim/gui/dialogs/airports/selected-airport/elevation-ft", 3.28 * info.elevation);
+          setprop("/sim/gui/dialogs/airports/selected-airport/rwy", "");
+          setprop("/sim/gui/dialogs/airports/selected-airport/parkpos", "");
           
           var longest_runway = 0;
           var runway_string = "";
@@ -136,6 +139,9 @@
           }
          
       }    
+      
+      
+      update_info();
     </open>
   </nasal>
   
@@ -421,32 +427,23 @@
                         .setTranslation(300, 200);
           
           var layer_runways = map.createChild("group", "runways");
-          var icon_tower =
-            map.createChild("path", "tower")
-               .setStrokeLineWidth(1)
-               .setScale(1.5)
-               .setColor(0.2,0.2,1.0)
-               .moveTo(-3, 0)
-               .vert(-10)
-               .line(-3, -10)
-               .horiz(12)
-               .line(-3, 10)
-               .vert(10);
 
           var updateMap = func() {
             var id = getprop("/sim/gui/dialogs/airports/selected-airport/id");
           
             if (id != "") {
               var apt = airportinfo(id);
+              
+              #map.removeAllChildren();
+              #layer_runways = map.createChild("group", "runways");
+              
               var airport = canvas.AirportMap.new(apt);
-              airport.build(layer_runways, "/sim/gui/dialogs/airports/selected-airport/rwy" );
+              airport.build(layer_runways);
 
-              var pos = apt.tower();
-              icon_tower.setGeoPosition(pos.lat, pos.lon);
               map._node.getNode("ref-lat", 1).setDoubleValue(apt.lat);
               map._node.getNode("ref-lon", 1).setDoubleValue(apt.lon);
               map._node.getNode("hdg", 1).setDoubleValue(0.0);
-              }
+            }
           }
                 
           var ranges = [0.1, 0.25, 0.5, 1, 2.5, 5];
@@ -462,7 +459,63 @@
             settimer(updateZoom, 0.5, 1);
           };
           
+          var updateRunwayHighlight = func()
+          {
+            var selected_rwy = getprop("/sim/gui/dialogs/airports/selected-airport/rwy");
+            var selected_apt = getprop("/sim/gui/dialogs/airports/selected-airport/id");
+            
+            var is_heli = substr(selected_rwy, 0, 1) == "H";
+            var rw_dir = is_heli ? nil : int(substr(selected_rwy, 0, 2));
+            
+            var rw_rec = "";
+            if( rw_dir != nil ) {
+              rw_rec = sprintf("%02d", math.mod(rw_dir - 18, 36));
+              if( size(selected_rwy) == 3 ) {
+                var map_rec = {
+                  "R": "L",
+                  "L": "R",
+                  "C": "C"
+                };
+                rw_rec ~= map_rec[substr(selected_rwy, 2)];
+              }
+            }
+            
+            foreach (var apt; layer_runways.getChildren()) {
+              if (apt.get("id") == "apt-" ~ selected_apt) {
+                foreach (var rwy; apt.getChildren()) {
+                  if ((rwy.get("id") == "runway-" ~ selected_rwy) or 
+                      (rwy.get("id") == "runway-" ~ rw_rec)          ) 
+                  {
+                    rwy.setColor(1.0,0.0,0.0);
+                  } else { 
+                    rwy.setColor(1.0,1.0,1.0);                  
+                  }
+                }              
+              }            
+            }
+          }          
+
+          var updateParkingHighlight = func()
+          {
+            var selected_parkpos = getprop("/sim/gui/dialogs/airports/selected-airport/parkpos");          
+            var selected_apt = getprop("/sim/gui/dialogs/airports/selected-airport/id");
+            
+            foreach (var apt; layer_runways.getChildren()) {
+              if (apt.get("id") == "apt-" ~ selected_apt) {
+                foreach (var rwy; apt.getChildren()) {
+                  if (rwy.get("id") == "parking-" ~ selected_parkpos) {
+                    rwy.setColor(1.0,0.0,0.0);
+                  } else { 
+                    rwy.setColor(1.0,1.0,1.0);                  
+                  }
+                }              
+              }            
+            }
+          }          
+          
           var aptlistener = setlistener("/sim/gui/dialogs/airports/selected-airport/id", updateMap);
+          var rwylistener = setlistener("/sim/gui/dialogs/airports/selected-airport/rwy", updateRunwayHighlight);
+          var parkposlistener = setlistener("/sim/gui/dialogs/airports/selected-airport/parkpos", updateParkingHighlight);
           
           update_info();
           updateZoom();
@@ -470,6 +523,8 @@
           </load>
           <close>
             removelistener(aptlistener);      
+            removelistener(rwylistener);
+            removelistener(parkposlistener);
           </close>
         </nasal>
       </canvas>

From 900404006395d192e4565e60f2cae27b490d74d7 Mon Sep 17 00:00:00 2001
From: Thomas Geymayer <tomgey@gmail.com>
Date: Tue, 18 Sep 2012 23:38:53 +0200
Subject: [PATCH 09/11] Remove data of previous airport in Select Airport
 dialog

---
 gui/dialogs/airports.xml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/gui/dialogs/airports.xml b/gui/dialogs/airports.xml
index a96032344..6be2b6f15 100644
--- a/gui/dialogs/airports.xml
+++ b/gui/dialogs/airports.xml
@@ -434,8 +434,8 @@
             if (id != "") {
               var apt = airportinfo(id);
               
-              #map.removeAllChildren();
-              #layer_runways = map.createChild("group", "runways");
+              map.removeAllChildren();
+              layer_runways = map.createChild("group", "runways");
               
               var airport = canvas.AirportMap.new(apt);
               airport.build(layer_runways);

From 0ec46ba4a7a792e4871e130ba603a55846bd9748 Mon Sep 17 00:00:00 2001
From: Stuart Buchanan <stuart_d_buchanan@yahoo.co.uk>
Date: Wed, 19 Sep 2012 10:20:48 +0100
Subject: [PATCH 10/11] Add thrust reverser, prop beta and mixture cut-off to
 throttle quadrant.

---
 .../Saitek/Pro-Flight-Cessna-Yoke.xml         | 190 +++++++++++++++++-
 1 file changed, 189 insertions(+), 1 deletion(-)

diff --git a/Input/Joysticks/Saitek/Pro-Flight-Cessna-Yoke.xml b/Input/Joysticks/Saitek/Pro-Flight-Cessna-Yoke.xml
index 916dbb9cb..4545a393e 100644
--- a/Input/Joysticks/Saitek/Pro-Flight-Cessna-Yoke.xml
+++ b/Input/Joysticks/Saitek/Pro-Flight-Cessna-Yoke.xml
@@ -20,6 +20,9 @@
   Button 13/14 (left hand quadrant buttons): Flaps Up/Down
   Buttons 15/16 (middle quadrant buttons): Gear Up/Down
   Buttons 17/18 (right quandrant buttons): Spoilers Up/Down
+  Button 19 (Throttle < 0): Reverse Thrust
+  Button 20 (Prop < 0): Propellor Beta
+  Button 21 (Mixture <0) : Cut-off
   Buttons 23/24/25 (right hand selector switch): View direction Sensitivity
 
 -->
@@ -32,7 +35,7 @@
     <name>Pro Flight Cessna Yoke</name>
     
     <axis n="0">
-	<name>Yoke left/right</name>
+	<name>Yoke lepft/right</name>
         <desc>Aileron</desc>
         <binding>
             <command>property-scale</command>
@@ -379,6 +382,191 @@
             </binding>
         </mod-up>
     </button>
+
+    <button n="19"> <!-- Power < 0 -->
+	<name>Throttle pushed below 0</name>
+        <desc>Thrust reverser/beta</desc>
+        <repeatable>false</repeatable>
+        <binding>
+            <command>property-assign</command>
+            <property>/controls/engines/engine[0]/reverser</property>
+            <value>true</value>
+        </binding>
+        <binding>
+            <command>property-assign</command>
+            <property>/controls/engines/engine[1]/reverser</property>
+            <value>true</value>
+        </binding>
+        <binding>
+            <command>property-assign</command>
+            <property>/controls/engines/engine[2]/reverser</property>
+            <value>true</value>
+        </binding>
+        <binding>
+            <command>property-assign</command>
+            <property>/controls/engines/engine[3]/reverser</property>
+            <value>true</value>
+        </binding>
+	<binding>
+            <command>property-assign</command>
+            <property>/engines/engine[0]/reverse-thrust</property>
+            <value>1</value>
+        </binding>
+	<binding>
+            <command>property-assign</command>
+            <property>/engines/engine[1]/reverse-thrust</property>
+            <value>1</value>
+        </binding>
+	<binding>
+            <command>property-assign</command>
+            <property>/engines/engine[2]/reverse-thrust</property>
+            <value>1</value>
+        </binding>
+	<binding>
+            <command>property-assign</command>
+            <property>/engines/engine[3]/reverse-thrust</property>
+            <value>1</value>
+        </binding>
+        <mod-up>
+	        <binding>
+        	    <command>property-assign</command>
+	            <property>/controls/engines/engine[0]/reverser</property>
+        	    <value>false</value>
+	        </binding>
+	        <binding>
+        	    <command>property-assign</command>
+	            <property>/controls/engines/engine[1]/reverser</property>
+        	    <value>false</value>
+	        </binding>
+	        <binding>
+        	    <command>property-assign</command>
+	            <property>/controls/engines/engine[2]/reverser</property>
+        	    <value>false</value>
+	        </binding>
+	        <binding>
+        	    <command>property-assign</command>
+	            <property>/controls/engines/engine[3]/reverser</property>
+        	    <value>false</value>
+	        </binding>
+	        <binding>
+        	    <command>property-assign</command>
+	            <property>/engines/engine[0]/reverse-thrust</property>
+        	    <value>0</value>
+	        </binding>
+	        <binding>
+        	    <command>property-assign</command>
+	            <property>/engines/engine[1]/reverse-thrust</property>
+        	    <value>0</value>
+	        </binding>
+	        <binding>
+        	    <command>property-assign</command>
+	            <property>/engines/engine[2]/reverse-thrust</property>
+        	    <value>0</value>
+	        </binding>
+	        <binding>
+        	    <command>property-assign</command>
+	            <property>/engines/engine[3]/reverse-thrust</property>
+        	    <value>0</value>
+	        </binding>
+        </mod-up>
+    </button>
+
+    <button n="20"> <!-- Propeller < 0 -->
+	<name>Propeller pushed below 0</name>
+        <desc>Feather Prop</desc>
+        <repeatable>false</repeatable>
+        <binding>
+            <command>property-assign</command>
+            <property>/controls/engines/engine[0]/propeller-feather</property>
+            <value>true</value>
+        </binding>
+        <binding>
+            <command>property-assign</command>
+            <property>/controls/engines/engine[1]/propeller-feather</property>
+            <value>true</value>
+        </binding>
+        <binding>
+            <command>property-assign</command>
+            <property>/controls/engines/engine[2]/propeller-feather</property>
+            <value>true</value>
+        </binding>
+        <binding>
+            <command>property-assign</command>
+            <property>/controls/engines/engine[3]/propeller-feather</property>
+            <value>true</value>
+        </binding>
+        <mod-up>
+	        <binding>
+        	    <command>property-assign</command>
+	            <property>/controls/engines/engine[0]/propeller-feather</property>
+        	    <value>false</value>
+	        </binding>
+	        <binding>
+        	    <command>property-assign</command>
+	            <property>/controls/engines/engine[1]/propeller-feather</property>
+        	    <value>false</value>
+	        </binding>
+	        <binding>
+        	    <command>property-assign</command>
+	            <property>/controls/engines/engine[2]/propeller-feather</property>
+        	    <value>false</value>
+	        </binding>
+	        <binding>
+        	    <command>property-assign</command>
+	            <property>/controls/engines/engine[3]/propeller-feather</property>
+        	    <value>false</value>
+	        </binding>
+        </mod-up>
+    </button>
+
+    <button n="21"> <!-- Mixture < 0 -->
+	<name>Mixture pushed below 0</name>
+        <desc>Engine cut-off</desc>
+        <repeatable>false</repeatable>
+        <binding>
+            <command>property-assign</command>
+            <property>/controls/engines/engine[0]/cutoff</property>
+            <value>true</value>
+        </binding>
+        <binding>
+            <command>property-assign</command>
+            <property>/controls/engines/engine[1]/cutoff</property>
+            <value>true</value>
+        </binding>
+        <binding>
+            <command>property-assign</command>
+            <property>/controls/engines/engine[2]/cutoff</property>
+            <value>true</value>
+        </binding>
+        <binding>
+            <command>property-assign</command>
+            <property>/controls/engines/engine[3]/cutoff</property>
+            <value>true</value>
+        </binding>
+        <mod-up>
+	        <binding>
+        	    <command>property-assign</command>
+	            <property>/controls/engines/engine[0]/cutoff</property>
+        	    <value>false</value>
+	        </binding>
+	        <binding>
+        	    <command>property-assign</command>
+	            <property>/controls/engines/engine[1]/cutoff</property>
+        	    <value>false</value>
+	        </binding>
+	        <binding>
+        	    <command>property-assign</command>
+	            <property>/controls/engines/engine[2]/cutoff</property>
+        	    <value>false</value>
+	        </binding>
+	        <binding>
+        	    <command>property-assign</command>
+	            <property>/controls/engines/engine[3]/cutoff</property>
+        	    <value>false</value>
+	        </binding>
+        </mod-up>
+    </button>
+
     <button n="22">
 	<name>Yoke mode switch left</name>
         <desc>Coolie hat sensitivity low</desc>

From 92810259308ab96e2740be98b5aaa8a2ffcc68d3 Mon Sep 17 00:00:00 2001
From: Stuart Buchanan <stuart_d_buchanan@yahoo.co.uk>
Date: Wed, 19 Sep 2012 10:22:30 +0100
Subject: [PATCH 11/11] Clean up Environment Setting dialog.

---
 gui/dialogs/environment-settings.xml | 19 +------------------
 1 file changed, 1 insertion(+), 18 deletions(-)

diff --git a/gui/dialogs/environment-settings.xml b/gui/dialogs/environment-settings.xml
index de8c19c9a..4a19cd95e 100644
--- a/gui/dialogs/environment-settings.xml
+++ b/gui/dialogs/environment-settings.xml
@@ -17,7 +17,7 @@
     </empty>
 
     <text>
-      <label>Environmental Settings</label>
+      <label>Environment Settings</label>
     </text>
 
     <empty>
@@ -226,23 +226,6 @@
     </empty>
     <layout>hbox</layout>
 
-    <button>
-      <legend>OK</legend>
-      <binding>
-        <command>dialog-apply</command>
-      </binding>
-      <binding>
-        <command>dialog-close</command>
-      </binding>
-    </button>
-    
-    <button>
-      <legend>Apply</legend>
-      <binding>
-        <command>dialog-apply</command>
-      </binding>
-    </button>
-
     <button>
       <legend>Close</legend>
       <default>true</default>