diff --git a/Nasal/autopilot.nas b/Nasal/autopilot.nas
deleted file mode 100644
index 651e5d386..000000000
--- a/Nasal/autopilot.nas
+++ /dev/null
@@ -1,83 +0,0 @@
-##
-## These are just GUI helper routines.  The autopilot itself is not a
-## Nasal module.
-##
-
-tagSettings =
-    {
-        "hdg-wing"     : ["/autopilot/locks/heading",  "wing-leveler"],
-        "hdg-bug"      : ["/autopilot/locks/heading",  "dg-heading-hold"],
-        "hdg-true"     : ["/autopilot/locks/heading",  "true-heading-hold"],
-        "hdg-nav"      : ["/autopilot/locks/heading",  "nav1-hold"],
-        "vel-throttle" : ["/autopilot/locks/speed",    "speed-with-throttle"],
-        "vel-pitch"    : ["/autopilot/locks/speed",    "speed-with-pitch-trim"],
-        "alt-vert"     : ["/autopilot/locks/altitude", "vertical-speed-hold"],
-        "alt-pitch"    : ["/autopilot/locks/altitude", "pitch-hold"],
-        "alt-aoa"      : ["/autopilot/locks/altitude", "aoa-hold"],
-        "alt-alt"      : ["/autopilot/locks/altitude", "altitude-hold"],
-        "alt-agl"      : ["/autopilot/locks/altitude", "agl-hold"],
-        "alt-gs"       : ["/autopilot/locks/altitude", "gs1-hold"]
-    };
-
-radioGroups = [["hdg-wing", "hdg-bug", "hdg-true", "hdg-nav"],
-               ["vel-throttle", "vel-pitch"],
-               ["alt-vert", "alt-pitch", "alt-aoa", "alt-alt",
-                "alt-agl", "alt-gs"]];
-
-# Initialize to get the types of the gui properties correct
-INIT = func {
-    guinode = props.globals.getNode("/autopilot/gui", 1);
-    foreach(tag; keys(tagSettings)) {
-        guinode.getNode(tag, 1).setBoolValue(0);
-    }
-    foreach(tag; ["hdg", "alt", "vel"]) {
-        guinode.getNode(tag ~ "-active", 1).setBoolValue(0);
-    }
-}
-settimer(INIT, 0);
-
-update = func {
-    # Suck out the values from the dialog
-    fgcommand("dialog-apply", props.Node.new());
-
-    # Sanitize the radio buttons such that only one is selected.  We are
-    # passed a tag indicating the one that was pressed.
-    if(size(arg) > 0) {
-        tag = arg[0];
-        foreach(group; radioGroups) {
-            for(i=0; i<size(group); i = i+1) {
-                if(tag == group[i]) {
-                    if(getprop("/autopilot/gui", tag)) {
-                        # The user just turned it on, turn the rest off...
-                        for(j=0; j<size(group); j=j+1) {
-                            if(j != i) {
-                                setprop("/autopilot/gui", group[j], 0);
-                            }
-                        }
-                    } else {
-                        # The user tried to turn off an active radio
-                        # button.  Turn it back on.
-                        setprop("/autopilot/gui", tag, 1);
-                    }
-                }
-            }
-        }
-    }
-
-    # Set the actual output properties for the autopilot system
-    foreach(tag; keys(tagSettings)) {
-        setting = tagSettings[tag];
-        if(getprop("/autopilot/gui", tag)) {
-            setprop(setting[0], setting[1]);
-        }
-    }
-    if(!getprop("/autopilot/gui/hdg-active")) {
-        setprop("/autopilot/locks/heading", ""); }
-    if(!getprop("/autopilot/gui/alt-active")) {
-        setprop("/autopilot/locks/altitude", ""); }
-    if(!getprop("/autopilot/gui/vel-active")) {
-        setprop("/autopilot/locks/speed", ""); }
-
-    # Push any changes back to the dialog
-    fgcommand("dialog-update", props.Node.new());
-}
diff --git a/gui/dialogs/autopilot.xml b/gui/dialogs/autopilot.xml
index 9b778fb06..1903a9893 100644
--- a/gui/dialogs/autopilot.xml
+++ b/gui/dialogs/autopilot.xml
@@ -21,160 +21,254 @@
 
   <hrule><dummy/></hrule>
 
+  <nasal>
+    <open>
+      # manage one AP property group with checkbox and radio buttons
+      #
+      Group = {
+          new : func(name, options) {
+              var m = { parents: [Group] };
+              m.name = name;
+              m.enabled = 0;
+              m.mode = options[0];
+              m.options = [];
+              var node = props.globals.getNode("/autopilot/locks");
+              if (node.getNode(name) == nil or node.getNode(name, 1).getValue() == nil) {
+                  node.getNode(name, 1).setValue("");
+              }
+              m.active = dlg.getNode(name ~ "-active", 1);
+              foreach (var o; options) {
+                  node = dlg.getNode(o);
+                  if (node == nil) {
+                      node = dlg.getNode(o, 1);
+                      node.setBoolValue(0);
+                  }
+                  append(m.options, node);
+              }
+              return m;
+          },
+
+          # handle checkbox
+          #
+          enable : func {
+              me.enabled = me.active.getBoolValue();
+              setprop("/autopilot/locks/" ~ me.name, me.enabled ? me.mode : "");
+          },
+
+          # handle radiobuttons
+          #
+          set : func(mode) {
+              me.mode = mode;
+              foreach (var o; me.options) {
+                  o.setBoolValue(o.getName() == mode);
+              }
+              if (me.enabled) {
+                  setprop("/autopilot/locks/" ~ me.name, mode);
+              }
+          },
+
+          # update checkboxes/radiobuttons state from the AP (listener callback)
+          #
+          update : func(mode) {
+              me.enabled = (mode != "");
+              me.active.setBoolValue(me.enabled);
+              if (mode == "") {
+                  mode = me.mode;
+              }
+              foreach (var o; me.options) {
+                  o.setBoolValue(o.getName() == mode);
+              }
+          },
+      };
+
+      var dlg = props.globals.getNode("/sim/gui/dialogs/autopilot", 1);
+
+      # - first entry ("heading" etc.) is the target property in /autopilot/locks/ *and*
+      #   the checkbox state property name (with "-active" appended);
+      # - second entry is a list of available options for the /autopilot/locks/* property
+      #   and used as radio button state property; the first list entry is used as default
+      #
+      var hdg = Group.new("heading",  ["dg-heading-hold", "wing-leveler", "true-heading-hold", "nav1-hold"]);
+      var vel = Group.new("speed",    ["speed-with-throttle", "speed-with-pitch-trim"]);
+      var alt = Group.new("altitude", ["altitude-hold", "vertical-speed-hold", "pitch-hold",
+                                       "aoa-hold", "agl-hold", "gs1-hold"]);
+
+      var lst = [
+          setlistener("/autopilot/locks/heading",  func { hdg.update(cmdarg().getValue()) }, 1),
+          setlistener("/autopilot/locks/speed",    func { vel.update(cmdarg().getValue()) }, 1),
+          setlistener("/autopilot/locks/altitude", func { alt.update(cmdarg().getValue()) }, 1),
+      ];
+    </open>
+
+    <close>
+      foreach (var l; lst) {
+          removelistener(l);
+      }
+    </close>
+  </nasal>
+
   <group>
     <layout>hbox</layout>
     <default-padding>8</default-padding>
-    
-    <group> <!-- Pitch/Altitude -->
+
+    <group> <!-- Heading -->
       <layout>vbox</layout>
       <group>
-	<layout>hbox</layout>
-	<checkbox>
-	  <label>Heading Control</label>
-	  <halign>fill</halign>
-	  <property>/autopilot/gui/hdg-active</property>
-	  <binding>
-	    <command>dialog-apply</command>
-	  </binding>
-	  <binding>
-	    <command>nasal</command>
-	    <script>autopilot.update()</script>
-	  </binding>
-	</checkbox>
+        <layout>hbox</layout>
+        <checkbox>
+          <label>Heading Control</label>
+          <halign>fill</halign>
+          <property>/sim/gui/dialogs/autopilot/heading-active</property>
+          <live>true</live>
+          <binding>
+            <command>dialog-apply</command>
+          </binding>
+          <binding>
+            <command>nasal</command>
+            <script>hdg.enable()</script>
+          </binding>
+        </checkbox>
       </group>
 
       <group>
-	<layout>table</layout>
-	<text>
-	  <label>Wings Level</label>
-	  <halign>right</halign>
-	  <row>0</row><col>0</col>
-	</text>
-	<radio>
-	  <row>0</row><col>1</col>
-	  <property>/autopilot/gui/hdg-wing</property>
-	  <binding>
-	    <command>nasal</command>
-	    <script>autopilot.update("hdg-wing")</script>
-	  </binding>
-	</radio>
+        <layout>table</layout>
+        <text>
+          <label>Wings Level</label>
+          <halign>right</halign>
+          <row>0</row><col>0</col>
+        </text>
+        <radio>
+          <row>0</row><col>1</col>
+          <property>/sim/gui/dialogs/autopilot/wing-leveler</property>
+          <live>true</live>
+          <binding>
+            <command>nasal</command>
+            <script>hdg.set("wing-leveler")</script>
+          </binding>
+        </radio>
 
-	<text>
-	  <label>Heading Bug</label>
-	  <halign>right</halign>
-	  <row>1</row><col>0</col>
-	</text>
-	<radio>
-	  <row>1</row><col>1</col>
-	  <property>/autopilot/gui/hdg-bug</property>
-	  <binding>
-	    <command>nasal</command>
-	    <script>autopilot.update("hdg-bug")</script>
-	  </binding>
-	</radio>
-	<input>
-	  <row>1</row><col>2</col>
-	  <name>hdg-bug</name>
-	  <property>/autopilot/settings/heading-bug-deg</property>
-	  <binding>
-	    <command>dialog-apply</command>
-	  </binding>
-	</input>
+        <text>
+          <label>Heading Bug</label>
+          <halign>right</halign>
+          <row>1</row><col>0</col>
+        </text>
+        <radio>
+          <row>1</row><col>1</col>
+          <property>/sim/gui/dialogs/autopilot/dg-heading-hold</property>
+          <live>true</live>
+          <binding>
+            <command>nasal</command>
+            <script>hdg.set("dg-heading-hold")</script>
+          </binding>
+        </radio>
+        <input>
+          <row>1</row><col>2</col>
+          <property>/autopilot/settings/heading-bug-deg</property>
+          <live>true</live>
+          <binding>
+            <command>dialog-apply</command>
+          </binding>
+        </input>
 
-	<text>
-	  <label>True Heading</label>
-	  <halign>right</halign>
-	  <row>2</row><col>0</col>
-	</text>
-	<radio>
-	  <row>2</row><col>1</col>
-	  <property>/autopilot/gui/hdg-true</property>
-	  <binding>
-	    <command>nasal</command>
-	    <script>autopilot.update("hdg-true")</script>
-	  </binding>
-	</radio>
-	<input>
-	  <row>2</row><col>2</col>
-	  <name>hdg-true</name>
-	  <property>/autopilot/settings/true-heading-deg</property>
-	  <binding>
-	    <command>dialog-apply</command>
-	  </binding>
-	</input>
+        <text>
+          <label>True Heading</label>
+          <halign>right</halign>
+          <row>2</row><col>0</col>
+        </text>
+        <radio>
+          <row>2</row><col>1</col>
+          <property>/sim/gui/dialogs/autopilot/true-heading-hold</property>
+          <live>true</live>
+          <binding>
+            <command>nasal</command>
+            <script>hdg.set("true-heading-hold")</script>
+          </binding>
+        </radio>
+        <input>
+          <row>2</row><col>2</col>
+          <property>/autopilot/settings/true-heading-deg</property>
+          <live>true</live>
+          <binding>
+            <command>dialog-apply</command>
+          </binding>
+        </input>
 
-	<text>
-	  <label>NAV1 CDI Course</label>
-	  <halign>right</halign>
-	  <row>3</row><col>0</col>
-	</text>
-	<radio>
-	  <row>3</row><col>1</col>
-	  <property>/autopilot/gui/hdg-nav</property>
-	  <binding>
-	    <command>nasal</command>
-	    <script>autopilot.update("hdg-nav")</script>
-	  </binding>
-	</radio>
+        <text>
+          <label>NAV1 CDI Course</label>
+          <halign>right</halign>
+          <row>3</row><col>0</col>
+        </text>
+        <radio>
+          <row>3</row><col>1</col>
+          <property>/sim/gui/dialogs/autopilot/nav1-hold</property>
+          <live>true</live>
+          <binding>
+            <command>nasal</command>
+            <script>hdg.set("nav1-hold")</script>
+          </binding>
+        </radio>
       </group>
 
       <hrule><dummy/></hrule>
 
       <group>
-	<layout>hbox</layout>
-	<checkbox>
-	  <label>Velocity Control</label>
-	  <halign>fill</halign>
-	  <property>/autopilot/gui/vel-active</property>
-	  <binding>
-	    <command>dialog-apply</command>
-	  </binding>
-	  <binding>
-	    <command>nasal</command>
-	    <script>autopilot.update()</script>
-	  </binding>
-	</checkbox>
+        <layout>hbox</layout>
+        <checkbox>
+          <label>Velocity Control</label>
+          <halign>fill</halign>
+          <property>/sim/gui/dialogs/autopilot/speed-active</property>
+          <live>true</live>
+          <binding>
+            <command>dialog-apply</command>
+          </binding>
+          <binding>
+            <command>nasal</command>
+            <script>vel.enable()</script>
+          </binding>
+        </checkbox>
       </group>
 
       <group>
-	<layout>table</layout>
-	<text>
-	  <label>Speed with Throttle</label>
-	  <halign>right</halign>
-	  <row>0</row><col>0</col>
-	</text>
-	<radio>
-	  <row>0</row><col>1</col>
-	  <property>/autopilot/gui/vel-throttle</property>
-	  <binding>
-	    <command>nasal</command>
-	    <script>autopilot.update("vel-throttle")</script>
-	  </binding>
-	</radio>
-	<input>
-	  <row>0</row><col>2</col>
-	  <rowspan>2</rowspan>
-	  <name>vel-throttle</name>
-	  <property>/autopilot/settings/target-speed-kt</property>
-	  <binding>
-	    <command>dialog-apply</command>
-	  </binding>
-	</input>
+        <layout>table</layout>
+        <text>
+          <label>Speed with Throttle</label>
+          <halign>right</halign>
+          <row>0</row><col>0</col>
+        </text>
+        <radio>
+          <row>0</row><col>1</col>
+          <property>/sim/gui/dialogs/autopilot/speed-with-throttle</property>
+          <live>true</live>
+          <binding>
+            <command>nasal</command>
+            <script>vel.set("speed-with-throttle")</script>
+          </binding>
+        </radio>
+        <input>
+          <row>0</row><col>2</col>
+          <rowspan>2</rowspan>
+          <property>/autopilot/settings/target-speed-kt</property>
+          <live>true</live>
+          <binding>
+            <command>dialog-apply</command>
+          </binding>
+        </input>
+
+        <text>
+          <label>Speed with Pitch</label>
+          <halign>right</halign>
+          <row>1</row><col>0</col>
+        </text>
+        <radio>
+          <row>1</row><col>1</col>
+          <property>/sim/gui/dialogs/autopilot/speed-with-pitch-trim</property>
+          <live>true</live>
+          <binding>
+            <command>nasal</command>
+            <script>vel.set("speed-with-pitch-trim")</script>
+          </binding>
+        </radio>
 
-	<text>
-	  <label>Speed with Pitch</label>
-	  <halign>right</halign>
-	  <row>1</row><col>0</col>
-	</text>
-	<radio>
-	  <row>1</row><col>1</col>
-	  <property>/autopilot/gui/vel-pitch</property>
-	  <binding>
-	    <command>nasal</command>
-	    <script>autopilot.update("vel-pitch")</script>
-	  </binding>
-	</radio>
-	
       </group>
     </group> <!-- End of Heading/Speed -->
 
@@ -185,146 +279,153 @@
     <group> <!-- Pitch/Altitude -->
       <layout>vbox</layout>
       <group>
-	<layout>hbox</layout>
-	<checkbox>
-	  <label>Pitch/Altitude Control</label>
-	  <halign>fill</halign>
-	  <property>/autopilot/gui/alt-active</property>
-	  <binding>
-	    <command>dialog-apply</command>
-	  </binding>
-	  <binding>
-	    <command>nasal</command>
-	    <script>autopilot.update()</script>
-	  </binding>
-	</checkbox>
+        <layout>hbox</layout>
+        <checkbox>
+          <label>Pitch/Altitude Control</label>
+          <halign>fill</halign>
+          <property>/sim/gui/dialogs/autopilot/altitude-active</property>
+          <live>true</live>
+          <binding>
+            <command>dialog-apply</command>
+          </binding>
+          <binding>
+            <command>nasal</command>
+            <script>alt.enable()</script>
+          </binding>
+        </checkbox>
       </group>
 
       <group>
-	<layout>table</layout>
-	<text>
-	  <label>Vertical Speed</label>
-	  <halign>right</halign>
-	  <row>0</row><col>0</col>
-	</text>
-	<radio>
-	  <row>0</row><col>1</col>
-	  <property>/autopilot/gui/alt-vert</property>
-	  <binding>
-	    <command>nasal</command>
-	    <script>autopilot.update("alt-vert")</script>
-	  </binding>
-	</radio>
-	<input>
-	  <row>0</row><col>2</col>
-	  <name>alt-vert</name>
-	  <property>/autopilot/settings/vertical-speed-fpm</property>
-	  <binding>
-	    <command>dialog-apply</command>
-	  </binding>
-	</input>
+        <layout>table</layout>
+        <text>
+          <label>Vertical Speed</label>
+          <halign>right</halign>
+          <row>0</row><col>0</col>
+        </text>
+        <radio>
+          <row>0</row><col>1</col>
+          <property>/sim/gui/dialogs/autopilot/vertical-speed-hold</property>
+          <live>true</live>
+          <binding>
+            <command>nasal</command>
+            <script>alt.set("vertical-speed-hold")</script>
+          </binding>
+        </radio>
+        <input>
+          <row>0</row><col>2</col>
+          <property>/autopilot/settings/vertical-speed-fpm</property>
+          <live>true</live>
+          <binding>
+            <command>dialog-apply</command>
+          </binding>
+        </input>
 
-	<text>
-	  <label>Pitch Hold</label>
-	  <halign>right</halign>
-	  <row>1</row><col>0</col>
-	</text>
-	<radio>
-	  <row>1</row><col>1</col>
-	  <property>/autopilot/gui/alt-pitch</property>
-	  <binding>
-	    <command>nasal</command>
-	    <script>autopilot.update("alt-pitch")</script>
-	  </binding>
-	</radio>
-	<input>
-	  <row>1</row><col>2</col>
-	  <name>alt-pitch</name>
-	  <property>/autopilot/settings/target-pitch-deg</property>
-	  <binding>
-	    <command>dialog-apply</command>
-	  </binding>
-	</input>
+        <text>
+          <label>Pitch Hold</label>
+          <halign>right</halign>
+          <row>1</row><col>0</col>
+        </text>
+        <radio>
+          <row>1</row><col>1</col>
+          <property>/sim/gui/dialogs/autopilot/pitch-hold</property>
+          <live>true</live>
+          <binding>
+            <command>nasal</command>
+            <script>alt.set("pitch-hold")</script>
+          </binding>
+        </radio>
+        <input>
+          <row>1</row><col>2</col>
+          <property>/autopilot/settings/target-pitch-deg</property>
+          <live>true</live>
+          <binding>
+            <command>dialog-apply</command>
+          </binding>
+        </input>
 
-	<text>
-	  <label>AoA Hold</label>
-	  <halign>right</halign>
-	  <row>2</row><col>0</col>
-	</text>
-	<radio>
-	  <row>2</row><col>1</col>
-	  <property>/autopilot/gui/alt-aoa</property>
-	  <binding>
-	    <command>nasal</command>
-	    <script>autopilot.update("alt-aoa")</script>
-	  </binding>
-	</radio>
-	<input>
-	  <row>2</row><col>2</col>
-	  <name>alt-aoa</name>
-	  <property>/autopilot/settings/target-aoa-deg</property>
-	  <binding>
-	    <command>dialog-apply</command>
-	  </binding>
-	</input>
+        <text>
+          <label>AoA Hold</label>
+          <halign>right</halign>
+          <row>2</row><col>0</col>
+        </text>
+        <radio>
+          <row>2</row><col>1</col>
+          <property>/sim/gui/dialogs/autopilot/aoa-hold</property>
+          <live>true</live>
+          <binding>
+            <command>nasal</command>
+            <script>alt.set("aoa-hold")</script>
+          </binding>
+        </radio>
+        <input>
+          <row>2</row><col>2</col>
+          <property>/autopilot/settings/target-aoa-deg</property>
+          <live>true</live>
+          <binding>
+            <command>dialog-apply</command>
+          </binding>
+        </input>
 
-	<text>
-	  <label>Altitude Hold</label>
-	  <halign>right</halign>
-	  <row>3</row><col>0</col>
-	</text>
-	<radio>
-	  <row>3</row><col>1</col>
-	  <property>/autopilot/gui/alt-alt</property>
-	  <binding>
-	    <command>nasal</command>
-	    <script>autopilot.update("alt-alt")</script>
-	  </binding>
-	</radio>
-	<input>
-	  <row>3</row><col>2</col>
-	  <name>alt-alt</name>
-	  <property>/autopilot/settings/target-altitude-ft</property>
-	  <binding>
-	    <command>dialog-apply</command>
-	  </binding>
-	</input>
+        <text>
+          <label>Altitude Hold</label>
+          <halign>right</halign>
+          <row>3</row><col>0</col>
+        </text>
+        <radio>
+          <row>3</row><col>1</col>
+          <property>/sim/gui/dialogs/autopilot/altitude-hold</property>
+          <live>true</live>
+          <binding>
+            <command>nasal</command>
+            <script>alt.set("altitude-hold")</script>
+          </binding>
+        </radio>
+        <input>
+          <row>3</row><col>2</col>
+          <property>/autopilot/settings/target-altitude-ft</property>
+          <live>true</live>
+          <binding>
+            <command>dialog-apply</command>
+          </binding>
+        </input>
 
-	<text>
-	  <label>AGL Hold</label>
-	  <halign>right</halign>
-	  <row>4</row><col>0</col>
-	</text>
-	<radio>
-	  <row>4</row><col>1</col>
-	  <property>/autopilot/gui/alt-agl</property>
-	  <binding>
-	    <command>nasal</command>
-	    <script>autopilot.update("alt-agl")</script>
-	  </binding>
-	</radio>
-	<input>
-	  <row>4</row><col>2</col>
-	  <name>alt-agl</name>
-	  <property>/autopilot/settings/target-agl-ft</property>
-	  <binding>
-	    <command>dialog-apply</command>
-	  </binding>
-	</input>
+        <text>
+          <label>AGL Hold</label>
+          <halign>right</halign>
+          <row>4</row><col>0</col>
+        </text>
+        <radio>
+          <row>4</row><col>1</col>
+          <property>/sim/gui/dialogs/autopilot/agl-hold</property>
+          <live>true</live>
+          <binding>
+            <command>nasal</command>
+            <script>alt.set("agl-hold")</script>
+          </binding>
+        </radio>
+        <input>
+          <row>4</row><col>2</col>
+          <property>/autopilot/settings/target-agl-ft</property>
+          <live>true</live>
+          <binding>
+            <command>dialog-apply</command>
+          </binding>
+        </input>
 
-	<text>
-	  <label>NAV1 Glideslope</label>
-	  <halign>right</halign>
-	  <row>5</row><col>0</col>
-	</text>
-	<radio>
-	  <row>5</row><col>1</col>
-	  <property>/autopilot/gui/alt-gs</property>
-	  <binding>
-	    <command>nasal</command>
-	    <script>autopilot.update("alt-gs")</script>
-	  </binding>
-	</radio>
+        <text>
+          <label>NAV1 Glideslope</label>
+          <halign>right</halign>
+          <row>5</row><col>0</col>
+        </text>
+        <radio>
+          <row>5</row><col>1</col>
+          <property>/sim/gui/dialogs/autopilot/gs1-hold</property>
+          <live>true</live>
+          <binding>
+            <command>nasal</command>
+            <script>alt.set("gs1-hold")</script>
+          </binding>
+        </radio>
       </group>
 
       <empty><stretch>true</stretch></empty>