Howto:Prototyping a new NavDisplay Style: Difference between revisions

Jump to navigation Jump to search
m (→‎Ideas: https://forum.flightgear.org/viewtopic.php?f=4&p=297433#p297424)
Line 42: Line 42:


This is primarily useful for rapid prototyping ("RAD"), i.e. quickly testing additions and changes without having to exit/restart fgfs and without having a full aircraft developed yet.
This is primarily useful for rapid prototyping ("RAD"), i.e. quickly testing additions and changes without having to exit/restart fgfs and without having a full aircraft developed yet.
== Implementation ==
The long/proper answer is that the "dialog" has become more sophisticated than originally planned.
In general, all PUI/XML dialogs should be using the markup for the widgets, and layouting directives, detailed in $FG_ROOT/Docs/README.gui and README.layout.
In addition to the features mentioned in those files there are some undocumented features, which can be found in the dialog building routines.
Internally, a dialog is just a property tree - it is read and loaded into the/a property tree and then further processed.
This is accomplished using so called "fgcommands", which is the stuff that you'd typically add to menubar.xml to make a new dialog item known to the GUI.
Some of the more typical GUI related fgcommands are:
* dialog-show
* dialog-close
Now, what is taking place internally is that dialogs may not only contain the known XML markup, but may also contain embedded Nasal code blocks.
There are really only two main ways to embed such code: at the dialog-level using nasal/open tags for code that is executed prior to showing a dialog that is already loaded from disk, and nasal/load blocks loaded per Canvas widget (the black area showing the ND texture).
To be fair, there also is a nasal/close tag to do some housekeeping/cleanup.
Anyway, what is so powerful about Nasal embedded in dialog files is that the code is typically executed prior to the creation/display of the dialog, and the Nasal code gets a handle to the property tree representation of the dialog markup (processed aready by the XML parser).
This "handle" is not just read-only, i.e. you get a mutable handy, which means you can traverse the tree and query it (e.g. to locate certain elements) and then freely add/remove or rename/duplicate elements, using the exact same APIs used to manipulate the global proeprty tree (e.g. props.nas).
And that is basically answering your question: The XML file posted in the wiki is incomplete - it would not make any sense at all without the embedded Nasal portions, but it contains a few redundant nodes that are not recognied by the existing GUI engine.
However, nasal/open block will specifically look for these redundant blocks and treat those as "templates" for certain widgets, e.g. those requiring dynamic contents (think a list of known styles, which cannot be hard-coded, think a list of MAP modes, ranges etc).
Internally, the Nasal code will then locate a handful of useful blocks, instantiate (copy/rename, and customize them) and insert them into the appropriate locations in the dialog/property tree.
This is why we may have only a single combo/select or "button" element in the XML markup, despite having possibly dozens of buttons: The code gets a copy to the dialog's property tree, and then duplicates useful/required nodes and customizes/renames them.
What you have now found are leftovers from one of my debugging sessions - basically, all these strings are irrelevant placeholders, because they get overridden anyway. However, at some point, the code wasn't working properly, so that I added strings like "unchanged mode" to the XML - this was so that I could tell immediately which routine would fail replacing those placeholders, because that would show up prominently in a dump of the "procedurally created dialog".
And that sums up the whole approach pretty well: The dialog only contains a subset of the required widgets/data, but it's using ~200 LOC to procedurally reuse those and replace those placeholders with more appropriate contents/variables.
Anyway, like I said, none of this should be relevant as long as you really only want to use the dialog. As a matter of fact, I don't think that there are many other dialogs making such elaborate use of this templating technique, but it is this that makes it possible to instantiate an arbitrary number of NDs using different resolutions - because what is really taking place is that the corresponding settings are written into the global property tree, and then the dialog is closed, the GUI subsystem reset and the same dialog opened, this time picking up the defaults you set up using the previously closed dialog.
I realize that this may sound complicated - but once you understand README.gui, README.layout and how embedded Nasal blocks work, and how those can manipulate the dialog before it is shown, it actually all makes sense, and isn't much unlike JavaScript/DOM traversal (akin to jQuery even).<ref>{{cite web
  |url    =  https://forum.flightgear.org/viewtopic.php?p=297505#p297505
  |title  =  <nowiki> Re: Canvas ND on another aircraft than Boeing and Airbus </nowiki>
  |author =  <nowiki> Hooray </nowiki>
  |date  =  Oct 26th, 2016
  |added  =  Oct 26th, 2016
  |script_version = 0.40
  }}</ref>


== Goals ==
== Goals ==

Navigation menu