Canvas widget matrix

From FlightGear wiki
Jump to navigation Jump to search
This article is a stub. You can help the wiki by expanding it.

1rightarrow.png See Howto:Processing legacy PUI dialogs using Canvas for the main article about this subject.

This is intended to become a table with existing Canvas widgets, as well as a side-by-side comparison with PUI widgets to list missing features, progress/completion status, including links to all relevant resources (docs, source code pointers)

Note  If you'd like to get involved in working on widgets or creating new ones, please get in touch via the devel-mailing list to coordinate related efforts with James Turner first.

The following tablet represents a list of Canvas GUI widgets, with the goal being to implement a sufficient number of widgets to re-implement/emulate basic PUI functionality by using the new fgdata/Nasal/gui/XMLDialog.nas module that translates existing PUI/XML dialogs into Canvas dialogs dynamically (i.e. at runtime). To learn more about the rationale, please see PUI#Replacement status, Unifying the 2D rendering backend via canvas and Hackathon Proposal:Canvas Widgets.

For a (somewhat outdated) overview of PUI widgets used by FlightGear, see $FG_ROOT/Docs/README.gui. To learn more about undocumented widgets, see: Template:PUI widget

For an authoritative list of PUI based widgets used by FlightGear, please refer to flightgear/flightgear/next/src/GUI/FGPUIDialog.cxx#l882.


Last updated: 10/2023

  • The upcoming Hackathon might provide another opportunity to revisit some Canvas todo items: Hackathon Proposal:Canvas Widgets
  • The lack of the menubar being implemented in Canvas was raised on the devel-list [1]
  • The Canvas GUI Camera needs additional work in Core Profile mode [2]
  • Implementation of missing widgets to emulate PUI 70}% completed (7/20 missing)
  • add the menubar to the widget factory dialog Done Done
  • Once the menubar widget is working properly and once we can parse/translate menubar.xml, we should consider using a separate dialog to show the fully translated menubar Not done Not done
  • Introduce a dialog to preview dialogs generated by XMLDialog.nas, so that more contributors can get involved in previewing/testing existing dialogs (including those outside fgdata) Not done Not done
  • C++ additions:
    • expose SG_LOG stream for the loglist widget Not done Not done
    • expose translations for the menubar Not done Not done
    • before porting the mapWidget (and before phasing it out), we need to revisit a long standing issue, i.e. not having back-ported the projection handling fix to the Canvas system: ticket #550 and ticket #454 (for details see Canvas_development#Projections and Howto:Adding new projections to Canvas Map) [3]
    • when opening 3+ concurrent instances of the new propertyTree dialog, fgfs will be massively slowed down, and that seems due to how labels are dynamically updated in Nasal space - we should probably extend label properties to optionally be based on on an sprintf-style string, and a list of properties to be read, and handle updates directly in C++ space rather than in Nasal space. Also, it might make sense to only update visible items? (for now, it's a really good stress test!)
    • there seems to be a rather serious memory leak when using the Canvas GUI subsystem: the number of refs/objs and the size of Nasal memory pools never reduces upon closing said dialogs/windows (unlike PUI!), this applies to any Canvas GUI dialog/window, including tooltips
  • Introduce meta information at the PropertyList/XML level to be able to version dialogs, for future changes to the underlying format
  • Clean up the existing UI:
    • especially the introduction of submenu support will make it possible to declutter the menubar (debug menu etc) Not done Not done
    • furthermore, introducing proper <tab> support will make it possible to simplify a few existing dialogs Not done Not done
  • Optimizing and simplifying existing dialogs by introducing new layouting/widget primitives Not done Not done


The majority of missing widgets can be implemented/approximated by using existing ones or adapting/extending those as needed. To get started with widget development, it's a good idea to look at some of the really simple ones first, and then take it from there - for instance, the Label widget is a comparatively simple widget:

Status PUI widget flightgear/flightgear/next/src/GUI/FGPUIDialog.cxx#l882 Complexity (0-10) Priority Canvas widget Remarks
Done Done <frame> 1 not critical fgdata/Nasal/canvas/gui/widgets/Frame.nas see FGData commit 459dea77e5ceac592d0d5d58a059ccad1fce6daa
Done Done <hrule>/<vrule> 1 not critical fgdata/Nasal/canvas/gui/widgets/Rule.nas FGData commit 459dea77e5ceac592d0d5d58a059ccad1fce6daa
Done Done <list> 5 high fgdata/Nasal/canvas/gui/widgets/List.nas list, combo and select should probably be tackled together, there's plenty of common/similar functionality - these could all be based on the same superclass internally, which should probably be structured so that specific list types (airport list, property list, waypoint list, log list) can be implemented on top of the existing list widget.
Not done Not done <airport-list> 5 Not implemented trivial using navdb APIs and ScrollArea with buttons/labels for each entry and a corresponding event handler Howto:Processing_legacy_PUI_dialogs_using_Canvas#Use_Case:_airports.xml
Done Done <property-list> 5 Not implemented Property Browser, rough prototype exists already, basically mapping 3 props.nas APIs to a ScrollArea with buttons for each property/node, allowing the tree to be travsersed interactively. Could be also implemented by using text labels and ASCII art, analogous to Nasal_Browser or using the new ListView widget
Not done Not done <waypointlist> 6 Not implemented trivial using navdb APIs and ScrollArea with buttons
Not done Not done <loglist> 4 Not implemented needs SG_LOG logstream exposed via Nasal/CppBind
Done Done <input> 3 LineEdit
Done Done <text> 6 Label
Done Done <checkbox> 4 Checkbox
Done Done <radio> 2 fgdata/Nasal/canvas/gui/widgets/RadioButton.nas
Done Done <button> 2 Button
Not done Not done <canvas> 4 should be implemented prior to <map> While we don't necessarily need a proper canvas widget, we need to map the PUI widget to a corresponding equivalent, i.e. an embedded Canvas with its own scripting block to animate the whole thing. The original pui2canvas parser simply set up an embedded Canvas via a Label with the raster image set up to show the Canvas instead: Howto:Processing_legacy_PUI_dialogs_using_Canvas#Embedded_Canvas
Not done Not done <map> 5 Not implemented, see also Canvas MapStructure 20}% completed Howto:Creating_a_Canvas_GUI_Widget#Implementing_a_Map_widget
Done Done <combo> 6 Not implemented list, combo and select can be unified
Not done Not done <select> 7 Not implemented list, combo and select can be unified
Done Done <slider> 4 Slider
Done Done <dial> 3 Dial
Done Done <textbox> 6 LineEdit and/or Label


Furthermore, we need to replace the Menubar itself, which is also implemented via PUI - for that purpose, there are some special widgets needed:

Status Complexity (0-10) Priority Canvas widget Remarks
Done Done 3 10 fgdata/Nasal/canvas/gui/widgets/MenuBar.nas see FGData commit 459dea77e5ceac592d0d5d58a059ccad1fce6daa
Done Done 3 10 fgdata/Nasal/canvas/gui/widgets/PopupMenu.nas see Merge request:Implement canvas menus

see FGData commit 459dea77e5ceac592d0d5d58a059ccad1fce6daa [4][5][6]

Done Done 3 10 fgdata/Nasal/canvas/gui/widgets/MenuItem.nas the design goal of MenuItem is to allow both simple items (text) but also check-ables ones, and in the future, simple widgets to be inside an item (eg, a slider or +/- controls in a menu item, or a multi-state selector of a few choices)

So, the aim was to have a constructor taking either a text string, or a callback which creates the widget content on demand (when the menu is shown) [7] It's using an item-orientated approach, and the menu has an addItem method to add an arbitrary widget (in most cases this will be a MenuItem instance, but you could use a slider just as well) and a createItem method that takes a text and a callback and an optional icon, from which a new MenuItem is created.[8]

Done Done 10 fgdata/Nasal/canvas/gui/widgets/Menu.nas see FGData commit 459dea77e5ceac592d0d5d58a059ccad1fce6daa

In addition, there are some Canvas specific widgets that are not currently supported by PUI:

Complexity (0-10) Priority Canvas widget Remarks
6 ScrollArea serves as the generic building block for any PUI list-type (waypoints/airports) with labels/buttons added for each entry shown
4 TabWidget A tab widget as everyone knows it from their web browsr (pending review as of 12/2022 see Merge request:Canvas tab widget implementation)

General Improvements

With the new GUI system (!!) we could even do a mode which opens the property inspector at a particular branch of the property tree, and have a an option that reads "manually select loading settings [click here to edit values]" … to keep the power tweakers happy without having a custom dialog box for every set of properties. (We do need to ensure they get auto-saved though, for this UI flow to be non-annoying) [9]

And that is something that we talked about and actually previously experimented with with Florent when the Addon system was being developed: There are some things in fgfs that don't really have a proper "config dialog" (yet) - but the property tree holds almost sufficient information to procedurally create a corresponding UI merely by doing a foreach(var node; tree) and by traversing a node to procedurally build a simple UI.

Having some sort of "overlay mode" for property-based dialogs would seem like a straightforward thing to do - we can easily support 3-5 optional attributes per node, and even recognize those dynamically inside the property browser, to provide this sort of "view" - and we could even register such nodes via a dedicated "hash" to make these available in a more direct fashion via the menubar.

The idea we had back then was to use optional XML/node attributes to add meta-info to such nodes, that way a "label" or "tooltip" attribute could be added, and even a "ui-type" node, so that such a loop could serve as a simple dialog builder for such annotated property nodes:

FlightGear Draw masks GUI dialog procedurally created by the Canvas system.s

I guess you can see just how simple but powerful this idea is: as long as we add such meta information to certain properties, a simple loop could procedurally generate simple dialogs, without having to use separate files.

To prototype/test this sort of idea, we could use your tab widget inside the new property tree widget, and support a different sort of "view" for such nodes - basically like an "overlay", where such properties are dynamically interpreted to provide a simple UI without having to view/edit raw property values.

We could then annotate relevant property trees using optional attributes like:

  • ui:label
  • ui:tooltip
  • ui:help (help string, could be shown via '?' button rendered next to each of these widgets)
  • ui:type [toggle, checkbox, slider etc]
  • ui:index (to influence in what order/manner such properties are mapped to widgets)
  • ui:validate (to select applicable validation)

This sort of markup would make it very easy for fgdata/aircraft developers to create UIs without ever having to create a single dialog, just by providing sufficient meta information so that the Canvas GUI system could automatically create basic, but working, dialogs.

Imagine, a property tree node having optional attributes, e.g. along the lines of:

<!-- Nodes that are annotated like this could be easily re-interpreted to provide an alternate view/interface without having to code up dialogs from scratch -->

    <hostname type="string" ui:type="textbox" ui:label="Host name" ui:tooltip="enter a hostname" ui:validate:""/>

We could then use a wrapper Class to map props.Node hierarchies to such dialogs using the equivalent of an PropsOverlayBuilder helper - the idea being to provide a UI overlay for nodes with rich meta info.

This sort of approach would also allow us to easily configure whether we want these settings to be stored with the userarchive flag set or not, or to save/load custom defaults via $FG_HOME/Export


Fahim was also working on an alternate style since James wants to ensure we have correct model-view separation between the core widgets (which is the public API) and the style code that builds the visual appearance.

In general, help with making the styling parts is the piece I am slowest with though, so any help, especially creating border-images (scale9) that work as the backgrounds / frames for the various elements would be lovely.[10]


We need to figure out the split of DefaultStyle.nas, but James is very keen to ensure we add a second style alongside the default, before we change much here.

Regarding styling, James is worried about us ending up putting code into the wrong side of the widget / Style split, if we don’t have a second alternative style implementation to ‘keep us honest’[12]

We really have two kinds of ’styles’

  • tweaking margins, font sizes, colours etc should indeed be done in XML as you wrote : this is also analogous to styles in the PUI sense
  • making radically different ways of presenting the same logical widgets: eg text label of checkbox in a different position relative to the button (of Surface vs Material vs iOS style, if you know web/mobile UIs)

For the second kind we would use a different Nasal style implementation and that’s the abstraction James thinks it is very important to maintain.

It of course going to be a lot of work to make additional styles this way but it’s a very valuable feature to keep the possiblity, since it enables alternate UIs for user accessibility or different presentation modes such as VR.

What James doesn't want to do is add lots of widgets assuming we only care about DefaultStyle.nas, and then have an impossible mountain to climb when someone needs an alternate Nasal style. We don’t have to make a complete alternate style now, but I don’t want to take shortcuts the make it impossible in the future. So James wants to really think carefully about what is widget code and what is style code. [13]

Also, it is worth nothing that treating DefaultStyle.nas that way, is a straightforward mechanism to allow aircraft developers to customize their own styling for all sort of MFD purposes, without having to create complete widget sets from scratch - this is how Tom originally designed the whole thing, for his C130J.

Widget Validation

At some point in the future, we may want to introduce support for optional constraints/restrictions for certain types of widgets (think headings/bearings/courses, frequencies, latitude/longitude, date/time, navaids, airports, file path, property path, metar string etc):

Things like password entry mode, restrictions on permitted characters (eg onl allowing numbers or an IP address), max number of characters entered, etc would all be config options as we add those kind of things gradually. That’s why I like it as an API: it avoids an explosion of setters for rarely used things, and it can be passed into the Style implementation ‘as is’ without each possible option needing to be explicitly handed over.[14]

Cleaning up dialogs

Once the PUI/XML widget set is fully supported by the XMLDialog parser, it will make sense to review existing dialogs to identify opportunities to introduce new widgets and simplify existing dialogs. As a matter of fact, a number of PUI/XML dialogs are currently working around PUI limitations by using awkward hacks to implement custom widgets. These show up by making excessive use of Nasal blobs as well as usage of the cmdarg() API, and they're a pain to maintain:

Introducing new Widgets

There is great scope to make /better/ Nasal APIs for items such as combo-boxes and pickers, especially ICAO and radio frequency pickers, but that's all 'improving the GUI' work than can happen once we've ditched PLIB and have something hackable.[15]

It's been repeatedly pointed out by a number of contributors, that the sheer amount of Nasal blobs embedded in PUI/XML dialogs is making UI development quite a hassle (especially those outside bindings, i.e. inside open/close blocks and the canvas load equivalent). Thus, it will make sense to review which new widgets could be introduced to get rid of these Nasal blobs:

Status Complexity (0-10) Priority Canvas widget Remarks
Not done Not done 4 low AirportView this would help simplify airports.xml
Not done Not done 4 low ChecklistWidget this would help simplify checklists.xml
Not done Not done 4 low PilotList pilot list dialog
Not done Not done 4 low SubsystemList performance monitor

Meta info for dialogs

These changes will also simplify development of the Phi/mongoose based UI, because we would be introducting dedicated widgets, which could just as well be implemented in JavaScript. However, for these changes to be introduced, we need to make some additions to the PropertyList/XML format used by GUI/XML files, namely:

  • introducing a version attribute for the <PropertyList> root
  • introducing a <FileType> node to specify that the file is a GUI/XML description: <FileType>GUI</FileType>
  • introducing a <version> node to be able to make breaking changes in the future

This way, we can easily update widgets/layouting primitives or introduce new ones, without having to be concerned about existing UI resources.

For instance, here's $FG_ROOT/gui/dialogs/scenery_loaded.xml with additional meta information, so that we can safely make changes in the future:

<?xml version="1.0"?>
<PropertyList version="1.0">
    <label>Scenery Loading...</label>


Once our existing PUI widgets and dialogs are fully emulated, and dialogs have become better optimized (=less Nasal blobs). It will be a good idea to revisit some concerns and ideas expressed by Torsten D. based on his experience creating Phi:

Torsten once stated rightly that it would be benefical for any new UI to separate the logic included in most dialogs from the presentation anyway to make it reusable. His vision was to have some kind of service implemented in FlightGear that wraps all complex tasks into service calls and responses. The command system is a good start to trigger something, but it does not yet return anything.

Currently, all dialogs are a mixture of calling fg-commands and setting properties directly.

Phi already has some basic support for aircraft specific elements. [16]

We should discuss and prototype a new type of asynchronous fgcommand layer that may also return properties/values, this could benefit both: The Canvas UI, but also Phi. In the future, Canvas UI dialogs may thus also use these same fgcommands which would be running asynchronously (possibly over the same/existing non-blocking HTTP back-end already used by Phi).

At that point it will become increasingly feasible to also provide a module for Phi to interpret these new PUI/XML dialogs, because these would be primarily XML-based, should contain zero (or very little) code. And the new could be that Nasal code that still needs to stay inside such dialogs, will always need to be registered with the SGCommandMgr via the addCommand() API - that way, both front-ends would be able to interpret/execute such dialogs, which would mean that aircraft developers would not need to port/maintain two different sets of dialogs to support both front-ends.

Also, future updates to the UI will become tremendously easier once our dialogs are purely declarative/XML.