20,741
edits
m (→Code: cleaning up things) |
|||
Line 366: | Line 366: | ||
}} | }} | ||
<syntaxhighlight lang="xml"><?xml version="1.0"?> | <syntaxhighlight lang="xml"><?xml version="1.0"?><?xml version="1.0"?> | ||
<PropertyList> | <PropertyList> | ||
<name>canvas-nd</name> | <name>canvas-nd</name> | ||
Line 376: | Line 376: | ||
<widget-templates> | <widget-templates> | ||
<!-- | |||
The following markup is processed by the dialog's nasal/open block to instantiate independent ND instances, including widgets to control them | |||
--> | |||
<nd-checkbox> | <nd-checkbox> | ||
<name>checkbox-template</name> | <name>checkbox-template</name> | ||
Line 404: | Line 406: | ||
<name>canvas-mfd</name> | <name>canvas-mfd</name> | ||
<!-- | |||
<group> | <group> | ||
<layout>vbox</layout> | <layout>vbox</layout> | ||
<name>mfd-controls2</name> | |||
<checkbox> | |||
<pref-width>30</pref-width> | |||
<pref-height>22</pref-height> | |||
<label>Test</label> | |||
<halign>left</halign> | |||
<property>/sim/none/foo</property> | |||
</checkbox> | |||
</group> | |||
--> | |||
<frame> | |||
<layout>vbox</layout> | |||
<padding>30</padding> | |||
<stretch>true</stretch> | |||
<!-- style selector (property will be overridden) --> | <!-- style selector (property will be overridden) --> | ||
< | <combo> | ||
<label>Style</label> | <label>Style</label> | ||
<name>unchanged</name> | <name>unchanged</name> | ||
Line 417: | Line 439: | ||
<object-name>unchanged</object-name> | <object-name>unchanged</object-name> | ||
</binding> | </binding> | ||
<!-- This actually works but triggers a Canvas related segfault if we don't use the timer --> | |||
<binding> | |||
<command>nasal</command> | |||
<script> | |||
fgcommand("dialog-close", props.Node.new({"dialog-name": "canvas-nd"})); | |||
settimer(func fgcommand("dialog-show", props.Node.new({"dialog-name": "canvas-nd"})), 0); | |||
</script> | |||
</binding> | |||
</ | </combo> | ||
<!-- this is where our checkboxes end up TODO: should be moved somewhere else and become a vbox--> | |||
<group> | <group> | ||
<layout>hbox</layout> | <layout>hbox</layout> | ||
<name>mfd-controls</name> | <name>mfd-controls</name> | ||
</group> | </group> | ||
<canvas> | <canvas> | ||
<name></name> | <name></name> | ||
<!-- | |||
<valign>fill</valign> | <valign>fill</valign> | ||
<halign>fill</halign> | <halign>fill</halign> | ||
<stretch> | <stretch>false</stretch> | ||
--> | |||
<!-- reducing the dimensions even more will look weird due to layouting issues, given the number of hbox aligned checkbox widgets --> | <!-- reducing the dimensions even more will look weird due to layouting issues, given the number of hbox aligned checkbox widgets --> | ||
<pref-width>400</pref-width> | <pref-width>400</pref-width> | ||
Line 443: | Line 478: | ||
<group> <!-- move this down for better layout --> | <group> <!-- move this down for better layout --> | ||
<layout>hbox</layout> | <layout>hbox</layout> | ||
<combo> | |||
<label>Mode</label> | <label>Mode</label> | ||
<name>unchanged mode!!!</name> | <name>unchanged mode!!!</name> | ||
Line 465: | Line 488: | ||
<object-name>unchanged mode !!!</object-name> | <object-name>unchanged mode !!!</object-name> | ||
</binding> | </binding> | ||
</ | </combo> | ||
<combo> | |||
<label> | <label></label> | ||
<name> | <name></name> | ||
<property> | <property></property> | ||
<binding> | <binding> | ||
<command>dialog-apply</command> | <command>dialog-apply</command> | ||
<object-name> | <object-name></object-name> | ||
</binding> | </binding> | ||
</ | </combo> | ||
<combo> | |||
<name>unchanged range</name> | <name>unchanged range</name> | ||
<label>nm</label> | <label>nm</label> | ||
Line 491: | Line 508: | ||
<object-name>unchanged range</object-name> | <object-name>unchanged range</object-name> | ||
</binding> | </binding> | ||
</ | </combo> | ||
<combo> | |||
<label></label> | |||
<name></name> | |||
<property></property> | |||
<binding> | <binding> | ||
<command>dialog-apply</command> | <command>dialog-apply</command> | ||
<object-name> | <object-name></object-name> | ||
</binding> | </binding> | ||
</ | </combo> | ||
</group> | </group> | ||
</ | </frame> | ||
</canvas-widget> | </canvas-widget> | ||
</widget-templates> | </widget-templates> | ||
<nasal> | <nasal> | ||
<open><![CDATA[ | <open><![CDATA[ | ||
var getWidgetTemplate = func(root, identifier) { | |||
var getWidgetTemplate = func(identifier) { | |||
var target = globals.gui.findElementByName(root, identifier ); | var target = globals.gui.findElementByName(root, identifier ); | ||
if(target == nil) die("Target node not found for identifier:"~identifier); | if(target == nil) die("Target node not found for identifier:"~identifier); | ||
Line 538: | Line 537: | ||
var populateSelectWidget = func(widget, label, attribute, index, property, values) { | var populateSelectWidget = func(widget, label, attribute, index, property, values) { | ||
# make up an identifier to be used for the object-name (fgcommands dialog-apply and -update) | # make up an identifier to be used for the object-name (fgcommands dialog-apply and -update) | ||
# | # format: ND[x].attribute | ||
var objectName = "ND["~index~"]."~attribute; # attribute~index; | var objectName = "ND["~index~"]."~attribute; # attribute~index; | ||
widget.getNode("label",1).setValue(label); | widget.getNode("label",1).setValue(label); | ||
widget.getNode("name",1).setValue(objectName); | widget.getNode("name",1).setValue(objectName); | ||
widget.getNode("binding/object-name",1).setValue(objectName); | widget.getNode("binding/object-name",1).setValue(objectName); | ||
forindex(var c; | var list = nil; | ||
widget.getChild("value",c,1).setValue( | |||
if (typeof(values) == 'hash') { | |||
# we have a hash with key/value pairs | |||
list = keys(values); | |||
print("FIXME: key/value mapping missing for value hash map:", attribute); | |||
# widget.getNode("property",1).setValue(property~"value-to-key"); | |||
} | |||
else { | |||
list = values; | |||
widget.getNode("property",1).setValue(property); | |||
} | |||
# for vectors with values | |||
forindex(var c; list) { | |||
widget.getChild("value",c,1).setValue(list[c]); | |||
} | } | ||
}; | }; | ||
### | ### | ||
# locate required templates | # locate required templates | ||
var | var WidgetTemplates = {}; | ||
# populate a hash with templates that we will need later on | |||
foreach(var t; ['canvas-placeholder', 'canvas-mfd', 'checkbox-template']) { | |||
WidgetTemplates[t]=getWidgetTemplate(root:cmdarg(), identifier: t); | |||
#print("Dump:\n"); | |||
#props.dump( WidgetTemplates[t] ); | |||
} | |||
var initialize_nd = func(index) { | var initialize_nd = func(index) { | ||
# print("running init nd"); | # print("running init nd"); | ||
my_canvas = canvas.get( cmdarg() ); | my_canvas = canvas.get( cmdarg() ); | ||
# FIXME: use the proper root here | |||
var myND = setupND(mfd_root: "/instrumentation/efis["~index~"]", my_canvas: my_canvas, index:index); | var myND = setupND(mfd_root: "/instrumentation/efis["~index~"]", my_canvas: my_canvas, index:index); | ||
}; | }; | ||
# not currently used, but could be used for validating the mfd/styles files before using them | # not currently used, but could be used for validating the mfd/styles files before using them | ||
Line 618: | Line 590: | ||
# call(func[, args[, me[, locals[, error]]]); | # call(func[, args[, me[, locals[, error]]]); | ||
# call( | # call( | ||
# actually include the navdisplay.mfd file so that this gets reloaded whenever the dialog is closed/reopened | |||
io.include('Nasal/canvas/map/navdisplay.mfd'); | io.include('Nasal/canvas/map/navdisplay.mfd'); | ||
#, nil, closure(initialize_nd), var errors=[]); | #, nil, closure(initialize_nd), var errors=[]); | ||
Line 631: | Line 604: | ||
} | } | ||
var ND = NavDisplay; | |||
# TODO: this info could also be added to the GUI dialog | # TODO: this info could also be added to the GUI dialog | ||
print("Number of ND Styles found:", size(keys(NDStyles))); | print("Number of ND Styles found:", size(keys(NDStyles))); | ||
# to be used for shutting down each created instance upon closing the dialog (see the close block below) | |||
var MFDInstances = {}; | |||
# http://wiki.flightgear.org/Canvas_ND_Framework#Cockpit_switches | # http://wiki.flightgear.org/Canvas_ND_Framework#Cockpit_switches | ||
Line 673: | Line 619: | ||
} | } | ||
var getSwitchesForND = func(index) { | |||
var | |||
var style_property = "/gui/dialogs/canvas-nd/nd["~index~"]/selected-style"; | |||
var style = getprop(style_property); | |||
# make sure that the style is exposed via the property tree | |||
if (style == nil) { | |||
style = 'Boeing'; # our default style | |||
setprop(style_property, style); | |||
} | |||
var switches = NDStyles[style].default_switches; | |||
print(" | print("Using ND style/switches:", style); | ||
if (switches == nil) print("Unknown ND style: ", style); | |||
return switches; | |||
} | |||
var setupND = func(mfd_root, my_canvas, index) { | |||
var style = getprop("/gui/dialogs/canvas-nd/nd["~index~"]/selected-style") or 'Boeing'; | |||
## | ## | ||
# set up a new ND instance, under mfd_root and use the | # set up a new ND instance, under mfd_root and use the | ||
# myCockpit_switches hash to map ND specific control properties | # myCockpit_switches hash to map ND specific control properties | ||
var myND= ND.new(mfd_root, | var switches = getSwitchesForND(index); | ||
var myND= ND.new(mfd_root, switches, style); | |||
var group = my_canvas.createGroup(); | var group = my_canvas.createGroup(); | ||
myND.newMFD(group, my_canvas); | myND.newMFD(group, my_canvas); | ||
myND.update(); | myND.update(); | ||
# store the instance for later cleanup | # store the new instance for later cleanup | ||
var handle = "ND["~index~"]"; | |||
MFDInstances[handle] = myND; | |||
# print("ND setup completed"); | # print("ND setup completed"); | ||
return {nd: myND, property_root: mfd_root}; | return {nd: myND, property_root: mfd_root}; | ||
Line 705: | Line 658: | ||
# this determines how many NDs will be added to the dialog, and where their controls live in the property tree | # this determines how many NDs will be added to the dialog, and where their controls live in the property tree | ||
# TODO: support default style per ND, different dimensions ? | |||
var canvas_areas = [ | var canvas_areas = [ | ||
{name: 'captain.ND', property_root:'/instrumentation/efis[0]',}, | {name: 'captain.ND', property_root:'/instrumentation/efis[0]',}, | ||
Line 712: | Line 666: | ||
]; | ]; | ||
# procedurally add one canvas for each ND to be shown (requires less code/maintenance) | # procedurally add one canvas for each ND to be shown (requires less code/maintenance, aka DRY) | ||
var index=0; | var index=0; | ||
foreach(var c; canvas_areas) { | foreach(var c; canvas_areas) { | ||
var switches = getSwitchesForND(index); | |||
# next, create a new symbol named canvasWidget, create child in target, with the index specified (idx) | # next, create a new symbol named canvasWidget, create child in target, with the index specified (idx) | ||
var canvasWidget = | var canvasWidget = WidgetTemplates['canvas-placeholder'].getChild("frame", index, 1); | ||
# now, copy our template stuff into the new tree | # now, copy our template stuff into the new tree | ||
props.copy( | props.copy(WidgetTemplates['canvas-mfd'].getChild("frame"), canvasWidget); | ||
# customize the subtree and override a few things | # customize the subtree and override a few things | ||
Line 728: | Line 681: | ||
canvasWidget.getNode("canvas/name").setValue(c.name); | canvasWidget.getNode("canvas/name").setValue(c.name); | ||
var | # instantiate and populate combo widgets | ||
var selectWidgets= [ | |||
populateSelectWidget( | {node: 'combo', label:'Style', attribute: 'Style', property:'/gui/dialogs/canvas-nd/nd['~index~']/selected-style', values:keys(NDStyles) }, | ||
{node: 'group[1]/combo[2]', label:'nm', attribute: 'RangeNm', property:c.property_root~switches['toggle_range'].path, values:switches['toggle_range'].values }, | |||
{node: 'group[1]/combo', label:'', attribute: 'ndMode', property:c.property_root~switches['toggle_display_mode'].path, values:switches['toggle_display_mode'].values }, | |||
]; | |||
foreach(var s; selectWidgets) { | |||
populateSelectWidget(canvasWidget.getNode(s.node), s.label, s.attribute, index, s.property, s.values); | |||
} | |||
# add a single line of code to each canvas/nasal section setting up the ND instance | # add a single line of code to each canvas/nasal section setting up the ND instance | ||
canvasWidget.getNode("canvas/nasal/load").setValue("initialize_nd(index:"~index~");"); | canvasWidget.getNode("canvas/nasal/load").setValue("initialize_nd(index:"~index~");"); | ||
var | # --------------- This whole thing can be simplified by putting it into the previous foreach loop | ||
# TODO: this should be using VOR/OFF/ADF instead of the numerical values ... | |||
var leftVORADFSelector = canvasWidget.getNode("group[1]/combo[1]"); | |||
# | # FIXME: shouldn't hard-code this here ... | ||
var | var keyValueMap = [1,0,-1]; # switches['toggle_lh_vor_adf'].values; # myCockpit_switches['toggle_lh_vor_adf'].values; | ||
populateSelectWidget( | # FIXME look up the proper lh/rh values here | ||
populateSelectWidget(leftVORADFSelector, "", "VOR/ADF(l)", index, "/instrumentation/efis["~index~"]/inputs/lh-vor-adf", keyValueMap); | |||
var rightVORADFSelector = canvasWidget.getNode("group[1]/combo[3]"); | |||
populateSelectWidget(rightVORADFSelector, "", "VOR/ADF(r)",index, "/instrumentation/efis["~index~"]/inputs/rh-vor-adf", keyValueMap); | |||
# --------------- | |||
var checkboxArea = getWidgetTemplate(root:canvasWidget, identifier:'mfd-controls'); | var checkboxArea = getWidgetTemplate(root:canvasWidget, identifier:'mfd-controls'); | ||
Line 748: | Line 712: | ||
# add checkboxes for each boolean switch | # add checkboxes for each boolean switch | ||
# TODO: customize this for style-specific switches ! | # TODO: customize this for style-specific switches ! | ||
# HACK: get rid of this, it's just an alias for now | |||
var myCockpit_switches = getSwitchesForND(index); # FIXME: should be using index instead of 0 | |||
foreach(var s; keys(myCockpit_switches)) { | foreach(var s; keys(myCockpit_switches)) { | ||
var switch = s; | var switch = s; | ||
Line 753: | Line 720: | ||
var checkbox = checkboxArea.getChild("checkbox",cb_index, 1); | var checkbox = checkboxArea.getChild("checkbox",cb_index, 1); | ||
props.copy( | props.copy(WidgetTemplates['checkbox-template'].getChild("checkbox"), checkbox); | ||
cb_index+=1; | cb_index+=1; | ||
checkbox.getNode("label").setValue(myCockpit_switches[switch].legend); | checkbox.getNode("label").setValue(myCockpit_switches[switch].legend); | ||
checkbox.getNode("property").setValue(c.property_root ~ myCockpit_switches[switch].path); | checkbox.getNode("property").setValue(c.property_root ~ myCockpit_switches[switch].path); | ||
var object_name = myCockpit_switches[switch].legend~ | # FIXME: use notation ND[x].attribute.toggle | ||
var object_name = "checkbox["~cb_index~"]("~myCockpit_switches[switch].legend~")"; | |||
checkbox.getNode("name",1).setValue(object_name); | checkbox.getNode("name",1).setValue(object_name); | ||
checkbox.getNode("binding/object-name",1).setValue(object_name); | checkbox.getNode("binding/object-name",1).setValue(object_name); | ||
} # add checkboxes for each boolean ND switch | } # add checkboxes for each boolean ND switch | ||
Line 768: | Line 735: | ||
#print("Complete dialog is:"); | #print("Complete dialog is:"); | ||
#props.dump( | #props.dump( WidgetTemplates['canvas-placeholder'] ); | ||
]]> | ]]> | ||
</open> | </open> | ||
<close><![CDATA[ | <close><![CDATA[ | ||
print("nasal/ | print("invoking nasal/close block canvas-nd.xml"); | ||
foreach(var mfd; MFDInstances) { | foreach(var mfd; keys(MFDInstances) ) { | ||
mfd.del(); | MFDInstances[mfd].del(); | ||
} | } | ||
]]> | ]]> | ||
Line 786: | Line 753: | ||
<name>canvas-placeholder</name> | <name>canvas-placeholder</name> | ||
<!-- this will be populated dynamically when the dialog is opened --> | <!-- this will be populated dynamically when the dialog is opened --> | ||
</group> | |||
<group> | <group> | ||
<layout>hbox</layout> | <layout>hbox</layout> | ||
<button> | <button> | ||
<legend>Exit</legend> | <legend>Exit</legend> | ||
Line 827: | Line 768: | ||
</PropertyList> | </PropertyList> | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== References == | == References == | ||
{{Appendix}} | {{Appendix}} |