<?xml version="1.0"?> <PropertyList> <x>-20</x> <y>-20</y> <name>nasal-console</name> <layout>vbox</layout> <group> <layout>hbox</layout> <empty><stretch>1</stretch></empty> <text> <label>Nasal Console</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/> <textbox> <name>editfield</name> <halign>fill</halign> <pref-width>450</pref-width> <pref-height>200</pref-height> <slider>20</slider> <editable>true</editable> <property>/sim/gui/dialogs/nasal-console/edit</property> <binding> <command>dialog-apply</command> <object-name>editfield</object-name> </binding> <binding> <command>nasal</command> <script>select(active)</script> </binding> </textbox> <group> <layout>hbox</layout> <halign>fill</halign> <default-padding>4</default-padding> <button-template> <hide>1</hide> <halign>fill</halign> <pref-width>20</pref-width> <pref-height>20</pref-height> <one-shot>0</one-shot> <live>1</live> <legend>## 1 ##</legend> <property>## /sim/gui/dialogs/nasal-console/tab-down[1] ##</property> <binding> <command>dialog-apply</command> <object-name>editfield</object-name> </binding> <binding> <command>nasal</command> <script>## select(1) ##</script> </binding> <binding> <command>dialog-update</command> <object-name>editfield</object-name> </binding> </button-template> </group> <hrule/> <group> <layout>hbox</layout> <default-padding>4</default-padding> <button> <legend>?</legend> <pref-width>30</pref-width> <binding> <command>nasal</command> <script>help()</script> </binding> <binding> <command>dialog-update</command> <object-name>editfield</object-name> </binding> </button> <empty><stretch>1</stretch></empty> <button> <legend>Clear</legend> <key>Ctrl-c</key> <equal>true</equal> <binding> <command>nasal</command> <script>active and clear()</script> </binding> <binding> <command>dialog-update</command> <object-name>editfield</object-name> </binding> </button> <button> <legend>Dump</legend> <key>Ctrl-d</key> <equal>true</equal> <binding> <command>dialog-apply</command> <object-name>editfield</object-name> </binding> <binding> <command>nasal</command> <script>active and dump()</script> </binding> </button> <button> <legend>Execute</legend> <default>true</default> <equal>true</equal> <binding> <command>dialog-apply</command> <object-name>editfield</object-name> </binding> <binding> <command>nasal</command> <script>active and execute()</script> </binding> </button> </group> <nasal> <open> var dlg = props.globals.getNode("/sim/gui/dialogs/nasal-console", 1); var kbdctrl = props.globals.getNode("/devices/status/keyboard/ctrl", 1); var printf = func { print(call(sprintf, arg)) } var edit = dlg.getNode("edit", 1); if (!contains(globals, "__nasal_console")) globals["__nasal_console"] = {}; var locals = globals["__nasal_console"]; var numtabs = size(dlg.getChildren("code")); if (!numtabs) numtabs = 10; var dump = func { gui.dialog_apply("nasal-console", "editfield"); select(active); rule = "--------------------------------------------------------------------------------"; print(rule ~ "\n"); print(edit.getValue()); print(rule); } var clear = func { edit.setValue(""); select(active); } var execute = func(what = nil) { var num = what != nil ? what.getIndex() : active; var tag = "<nasal-console/#" ~ num ~ ">"; var err = []; if (what == nil) what = edit; var f = call(func { compile(what.getValue(), tag) }, nil, nil, nil, err); if (size(err)) { print(tag ~ ": " ~ err[0]); return; } f = bind(f, globals); call(f, nil, nil, locals, err); debug.printerror(err); } var tabs = cmdarg().getNode("group[1]"); var select = func(which, init = 0) { if (active) { # false in help mode dlg.getNode("active").setIntValue(active); if (!init) dlg.getChild("code", active).setValue(string.trim(edit.getValue())); } if (kbdctrl.getValue()) { execute(dlg.getChild("code", which)); return; } active = which; foreach (var c; dlg.getChildren("tab-down")) c.setBoolValue(c.getIndex() == active); dlg.getNode("active").setIntValue(active = which); edit.setValue(dlg.getChild("code", active).getValue()); } var help = func { active = 0; foreach (var c; dlg.getChildren("tab-down")) c.setBoolValue(0); edit.setValue("Keys:\n" ~ " tab ... leave edit mode (visible text cursor)\n" ~ " return ... execute active code\n" ~ " ctrl-c ... clear input field\n" ~ " ctrl-d ... dump input field contents to terminal\n" ~ " esc ... close dialog\n\n" ~ "Ctrl-click on tab buttons executes code without switching to the tab.\n" ~ "Add more <code> properties in ~/.fgfs/autosave.xml for more tab buttons."); } # setup tab buttons and properties from the template tabs.removeChildren("button"); var template = tabs.getNode("button-template"); var d = dlg.getPath(); for (var i = 1; i <= numtabs; i += 1) { var button = tabs.getChild("button", i, 1); var state = dlg.getChild("tab-down", i, 1); state.setBoolValue(0); props.copy(template, button); button.getNode("hide").setValue(0); button.getNode("legend").setIntValue(i); button.getNode("binding[1]/script").setValue("select(" ~ i ~ ")"); button.getNode("property").setValue(state.getPath()); var c = dlg.getChild("code", i); if (c == nil or c.getType() == "NONE") { c = dlg.getChild("code", i, 1); c.setValue(""); c.setAttribute("userarchive", 1); } } edit.setValue(""); var active = dlg.getNode("active", 1).getValue(); if (active == nil) active = 1; select(active, 1); </open> </nasal> </PropertyList>