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>