Howto:Editing and creating GUI dialogs in FlightGear

From FlightGear wiki
Jump to navigation Jump to search
This article is a stub. You can help the wiki by expanding it.
Note  In its current form, this section/article is largely based on quotes collected from various related discussions/channels (devel list, forum etc) using the Instant-Cquotes script. Wiki users and other contributors are encouraged to help rewrite/edit contents accordingly to help get rid of unnecessary quoting (i.e. while the wiki is not intended to be a collection of quotes, quotes are sometimes the best/easiest way to bootstrap new articles, while also providing a good way to link back to related discussions in the archives).

While rewriting usually only entails changing first person speech to 3rd person. However, please try to retain references/links to the original discussion whenever possible.

Background

The effort to add a simple dialog option is about the effort to make a mockup of it in gimp - you copy/paste the line above, then alter what you want to alter. Usually no Nasal is involved at all, you're just describing what the thing does.

The learning effort is considerably less than the effort required to learn the graphics program you need to create the mockup, so if you'd start with nothing, you'd have the real dialog well before you'd have the mockup. To cast this as a fearsome hurdle is really doing a disservice, regardless of whether you want to call this coding or not (in a sense, you're also applying logic and rules when using gimp or photoshop, so is this coding as well?)

If you don't feel uncomfortable creating/editing an XML file (which is really just a fancy name for a plain text file with a certain structure), we can probably walk you through the whole thing within a few minutes (10-20).

When it comes to modifying dialogs or creating new ones, you usually only need to adapt existing dialogs slightly and/or copy and paste useful stuff from other dialogs.

GUI Dialogs in FlightGear

The absolute majority of GUI dialogs in FlightGear are all made up of XML files following a FlightGear-specific format that is called "PropertyList", this is because all XML files using this structure can directly be processed by the FlightGear property tree.

There is usually no coding involved to modify dialogs like this, see $FG_ROOT/Docs/README.gui and refer to examples in $FG_ROOT/gui/dialogs It's all just XML and properties

This is possible, and it may not even involve much in terms of programming.

The references/pointers I posted previously, would still be applicable. First of all, you need to understand where to find the FG base package:

Our dialogs are invoked via fgdata/gui/menubar.xml

Property tree and xml

you need to understand the relationship between properties and XML, for example: /alpha/bravo/charlie You can imagine this like a property tree representing a tree hierarchy (with branches), similar to a file system where you may have C:\directory1\directory2\file1 next, you need to understand how this translates to the corresponding XML markup representing this "property tree". The most basic XML file is this:

<?xml version="1.0" encoding="UTF-8"?>
 
<PropertyList>
</PropertyList>

This can be considered to be the "boilerplate" (scaffolding) for most FG XML files.

Anything that is relevant to FG will be put in between the PropertyList tags.

You also need to understand that in XML, there is a parity between OPENING and CLOSING tags, i.e. a closing tag is one with a forward slash prepended to the name of the opening tag. So whenever you want to add a new tag, you also need to add a closing tag.

The short-hand for that is adding an opening tag with a forward slash appended to the end of the tag:

<dilbert>
</dilbert>

is equivalent to this:

<dilbert/> Thus:

<dilbert>
 <pets>
 <dog>1</dog>
 </pets>
</dilbert>

is XML markup for the following property tree:

/dilbert/pets/dog=1 With this background knowledge, you may want to revisit the wiki resources I suggested previously: PropertyList XML files#Minimal example In general, it makes sense to create a few XML files first and load those into FG and inspect the FG property tree using the property browser - e.g. by changing/adding translations, and checking the results in the global tree.

In fact, you can add arbitrary stuff to the translation - such as by going to $FG_ROOT/Translations/en/menu.xml and editing/changing things there. one of the most insightful things you could do while reading through those article is editing $FG_ROOT/preferences.xml and adding something to the top of it, right after the initial <PropertyList> tag, you could for example add the snippet I posted previously:

<dilbert>
  <pets>
    <dog>1</dog>
  </pets>
</dilbert>

(see the linked image) When I edit preferences.xml and save the file, and then start up FG.

I can see those changes by opening the property browser (see the debug menu): Property browser see the new "dilbert" entry below:

(see the linked image) And here's what you will see once opening each "directory" (dilbert/pets):

(see the linked image)

Dialogs ...

Dialogs themselves reside in the base package, stored in fgdata/gui/dialogs

Often, you will want to look for dialogs which are already similar to what you want to create, or those containing useful widgets that you may need in your new dialog.

You can look up the dialog that you are interested in via menubar.xml (e.g. radios.xml) and open that using a text editor by navigating to $FG_ROOT/gui/dialogs.

What you will see, is an XML document, this can be edited/extended by adding widgets to it, as per $FG_ROOT/Docs/README.gui, with layouting directives being documented in $FG_ROOT/Docs/README.layout and available commands in $FG_ROOT/Docs/README.commands

Starting simple

FlightGear GUI dialog (exit.xml)stored in $FG_ROOT/gui/dialogs

Admittedly, all that may seem a little overwhelming at first glance - which is why we suggest to start with a simple dialog like the "exit" dialog and take it from there, because that is fairly self-contained and straightforward to extend, especially compared to dialogs containing embedded Nasal script code (=actual programs).

Just navigate to $FG_ROOT/gui/dialogs/exit.xml and open it in a text/xml editor.

Then see if it's making sense to you.

If it doesn't, because of the XML syntax, refer to $FG_ROOT/Docs/README.xmlsyntax

For starters, you could open $FG_ROOT/gui/dialogs/exit.xml and see if that makes sense to you or not.

Next, you could copy exit.xml to a new file, and rename the whole thing to frequency-convert.xml

Now, you have a new file containing the exit dialog. So, you only need to make this known to FG by adding it to the menubar. For that, open $FG_ROOT/gui/menubar.xml

Navigate to the "exit" entry, copy that to a new location (menubar).

Change "exit" to the new file name

This should already work.

Next, you would want to change the menubar entry itself by editing $FG_ROOT/Translations (default-en) and add "VOR/TACAN convert" there. Once this works, you can simply open the new dialog and customie it according to your needs.

For that, you can review other dialogs in $FG_ROOT/gui/dialogs and/or review the documentation: $FG_ROOT/Docs/README.gui You will probably want to add two text boxes and two labels, and 2 buttons.

Once you have got that working, we can post more instructions for hooking up those buttons with functionality for converting stuff.


If you don't know what properties are, refer to $FG_ROOT/Docs/README.properties To see, what GUI specific tags are supported there, see $FG_ROOT/Docs/README.gui This may sound like a ton of stuff, but adding a widget is trivial, because it does not involve any Nasal/coding at all - the first step is making the widget show up using the correct widget name (README.gui), the next step is hooking that up to the corresponding property. There's more to it, e.g. layouting ($FG_ROOT/Docs/README.layout) - but in general, you will only need to know a tiny subset of these things to make simple changes - and in fact, you often don't even need to look at these files, because it will suffice to just look at other dialogs and copy/paste stuff from them. Regarding the patch that Necolatis created, my suggestion would be to turn this into a tutorial for the wiki, which illustrates how to go about making similarly straightforward changes.


<?xml version="1.0"?>
<PropertyList>
  <name>exit</name>
  <modal>false</modal>
  <layout>vbox</layout>

  <text>
    <label>Exit FlightGear?</label>
  </text>

  <group>
    <layout>hbox</layout>
    <halign>fill</halign>
    <default-padding>10</default-padding>
    <empty><stretch>true</stretch></empty>

    <button>
      <legend>Exit</legend>
      <default>true</default>
      <equal>true</equal>
      <binding>
        <command>exit</command>
      </binding>
      <binding>
        <command>dialog-close</command>
      </binding>
    </button>

    <empty><stretch>true</stretch></empty>

    <button>
      <legend>Cancel</legend>
      <equal>true</equal>
      <key>Esc</key>
      <binding>
        <command>dialog-close</command>
      </binding>
    </button>

    <empty><stretch>true</stretch></empty>
  </group>
</PropertyList>


FOO

using the XML-configurable GUI system is now generally considered the preferred route, simply because the majority of GUI dialogs are kept in $FG_ROOT/GUI/dialogs You can invoke Nasal scripts from these dialog files, and you can trigger fgcommands.

If you are serious about this, but are feeling a little overwhelmed given all the tutorials, readme files and new concepts, I suggest to take it more slowly by looking at the wiki, which has some fairly good/accessible tutorials to help lower the barrier to entry:

These article should give you a good idea about the property tree and how it relates to XML files, which are used for representing dialogs in FG.

FlightGear XML files (all those PropertyLists) will usually become properties that can be seen in the FG property tree (using the browser available in the debug menu). Once you understand how this works, you can better understand the tutorials on the wiki, and start making working changes to different files - not just preferences.xml, but also translations (e.g. by renaming menu items), or by adding new menu items - as well as new/modified dialogs

For example, by taking an existing XML file, copying/renaming that, and editing it according to the instructions I posted. We do have pretty good docs covering almost 99% of what you need to do. And most of this doesn't even involve any "coding". It is just about taking an existing file, copying and modifying that, based on instructions posted on the forum/wiki, and some 1:1 help provided by us. A good way for getting started would be reading the "Property Tree" docs on the wiki, or even just browsing through your local $FG_ROOT folder, specifically:

  • README.introduction
  • README.xmlsyntax
  • README.gui
  • README.commands

As I mentioned before, you should probably start with a simple dialog like exit.xml, and refer to that while reading those docs. Subsequently, you could take a look at some of the other dialogs to copy useful stuff and adapt that according to your needs. For editing an XML file, you can use a conventional text editor like wordpad on windows The wiki does have some additional docs:

Alternatively, if you should prefer Nasal over XML, we can also provide a few Nasal snippets to create such a dialog procedurally:

Canvas Snippets

Snippets-canvas-input-dialog.png

See also: Howto:Creating a Canvas GUI dialog file

Widgets

For example, to save textbox stuff in a property, you will want to look at $FG_ROOT/Docs/README.gui. Basically, you can add a new input tag and add a child node (property) and come up with your own property for it.

In one of the bindings, you can execute arbitrary fgcommands ($FG_ROOT/Docs/README.commands), but also actual code in the form of Nasal code blocks. In other words, you could have something like this:

<input>
  <width>250</width>
  <height>25</height>
  <label>What is your dog's name:</label>
  <property>/dilbert/pets/dog/name</property>
</input>

Which can be interpreted as follows:

  1. create a new input widget (taking text input)
  2. make it a certain width/height
  3. add a label to it
  4. store the value of the textbox (user input) in the property specified

If you want to see some other property changed, you would need to change the property path - i.e. by looking at similar/related dialogs For instance, opening radios.xml and looking for "standby" in it, it seems that the properties for saving the standby frequencies are these: /instrumentation/comm[0]/frequencies/standby-mh

/instrumentation/comm[1]/frequencies/standby-mhz with 0 and 1 being the index of otherwise identically-named properties (variables). Imagine it like having identical directories (locations), that need to be distinguished by appending an index (in square brackets) to it - because you can have two standby frequencies at the same time.

Menubar and translations

Cquote1.png next you can basically add the new dialog to the menubar by opening/editing that file and duplicating/renaming the section referencing the exit dialog, you would want to rename the exit entry to use TRexit instead, and maybe edit TRexit.xml to change something in the dialog, e.g. the label of a button - so that you can tell if you were successful.

Next, you would open the Translations folder to add a translated entry for your new "converter" dialog Background info:

Menubar

Howto:Translate FlightGear
— Hooray (Oct 7th, 2015). Re: VOR to .
(powered by Instant-Cquotes)
Cquote2.png

Good to know

via nasal

If you don't like using XML for creating the dialog, you can also directly use a Nasal script to specify the dialog - after all the structure needs to end up in the property tree anyhow, there are various helpers available in $FG_ROOT/Nasal/gui.nas So it would be possible to specify the dialog as a nested Nasal hash and turn it into a property tree structure. The function showWeightDialog() in $FG_ROOT/Nasal/gui.nas is one example that illustrates how to go about creating a somewhat more complex dialog dynamically from a Nasal script. There are other examples such as gui.showHelpDialog() available. Just keep in mind that the symbols mentioned in $FG_ROOT/Docs/README.gui are still important - but instead of using them in tags, you'd directly use them to populate the property tree from Nasal.


Nasal has a relatively rich library of functions that are supported by default, in addition you can FlightGear specific extension functions and FlightGear-specific helper modules from $FG_ROOT/Nasal - such as code from gui.nas or io.nas To get started easily you could look around for a GUI dialog that is using the widgets that you need, you can then locate the file in $FG_ROOT/gui/dialogs and open it in a plain text editor. You could also use a validating XML editor instead if you want to make sure that your XML is valid. You could save a copy of the file under a different file name, such as "config-gui.xml" and add a new entry to $FG_ROOT/gui/menubar.xml to add a new menubar entry for showing your dialog. You could then -step by step- modify your dialog so that it can be used for configuring the controls and saving everything to a new XML file. If you already know C++, it should be easy for you to understand the Nasal part - and XML is just a markup language. Not all features of the underlying GUI library are currently exposed, but it is relatively easy to add support for new widgets. The C++ source that turns the PropertyList GUI dialog files into PUI/PLIB dialogs is located in $FG_SRC/src/GUI/dialog.cxx. The PLIB PUI library is documented here: http://plib.sourceforge.net/pui/index.html So if you should find the need to add new widgets or features to the GUI bindings, it would not be too difficult to do - as you'll surely see.