-20 -20 nasal-console vbox hbox 1 1 editfield fill 450 200 20 true /sim/gui/dialogs/nasal-console/edit dialog-apply editfield nasal hbox fill 4 1 fill 20 20 0 1 ## 1 ## ## /sim/gui/dialogs/nasal-console/tab-down[1] ## dialog-apply editfield nasal dialog-update editfield hbox 4 1 var dlg = props.globals.getNode("/sim/gui/dialogs/nasal-console"); 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 tag = "<nasal-console>"; 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); if (size(err)) { printf("%s at %s line %d", err[0], err[1], err[2]); for (var i = 3; i < size(err); i += 2) { printf(" called from %s line %d", err[i], err[i + 1]); } } } 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(screen.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);