Hi fellow wiki editors!

To help newly registered users get more familiar with the wiki (and maybe older users too) there is now a {{Welcome to the wiki}} template. Have a look at it and feel free to add it to new users discussion pages (and perhaps your own).

I have tried to keep the template short, but meaningful. /Johan G

Howto:Creating a custom waypointlist pendant using Canvas

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


The issue is that even on the larger screens, you can't get the entire list of SIDS or STARs displayed when there are too many.[1]

The route manager dialog.

Status / Todo

  • Add simple helper function for creating tables consisting of vbox/hbox layouts, so that the current appearance can be emulated.
  • for each row, add 3 buttons using a common callback handler

XML Markup



Dialog Builder


C++ Widget Code


The Route Manager

Nasal APIs

Canvas Code (proof-of-concept)

Screenshot showing a Canvas GUI dialog with a table layout to emulate the built-in (hard-coded) PUI waypointlist widget
WIP.png Work in progress
This article or section will be worked on in the upcoming hours or days.
See history for the latest developments.

For the sake of rapid prototyping, the following snippet of code is to be executed/tested using the built-in Nasal Console:

The Nasal console in FG 3.0 with copy/paste buttons

# for faster testing, let's use a vector with dummy data to be shown matching the columns of the hard-coded widget:
var dummyData = [
 {target: 0, latitude:0, longitude:0, ETA:0},

var (width,height) = (320,160);
var title = 'pui2canvas - waypointlist demo';

# create a new window, dimensions are WIDTH x HEIGHT, using the dialog decoration (i.e. titlebar)
var window = canvas.Window.new([width,height],"dialog").set('title',title);

# the del() function is the destructor of the Window
# which will be called upon termination (dialog closing)
# you can use this to do resource management (clean up timers, listeners or background threads)
window.del = func()
  print("Cleaning up window:",title,"\n");
# explanation for the call() technique at: http://wiki.flightgear.org/Object_oriented_programming_in_Nasal#Making_safer_base-class_calls
  call(canvas.Window.del, [], me);

# adding a canvas to the new window and setting up background colors/transparency
var myCanvas = window.createCanvas().set("background", canvas.style.getColor("bg_color"));

# creating the top-level/root group which will contain all other elements/group
var root = myCanvas.createGroup();

var vbox = canvas.VBoxLayout.new();

 var scroll = canvas.gui.widgets.ScrollArea.new(root, canvas.style, {size: [96, 128]}).move(20, 100);
 vbox.addItem(scroll, 1);

var scrollContent =
            .set("font", "LiberationFonts/LiberationSans-Bold.ttf")
            .set("character-size", 16)
            .set("alignment", "left-center");

var list = canvas.VBoxLayout.new();

var addTable = func(scrollContent, list) {

var dummyData = [
{target:'foo1', latitude:'lat1', longitude:'lon1', eta:'eta1'},
{target:'foo2', latitude:'lat2', longitude:'lon2', eta:'eta2'},
{target:'foo3', latitude:'lat3', longitude:'lon3', eta:'eta3'},
{target:'foo4', latitude:'lat4', longitude:'lon4', eta:'eta4'}, 
{target:'foo5', latitude:'lat', longitude:'lon', eta:'eta'}, 
{target:'foo6', latitude:'lat', longitude:'lon', eta:'eta'}, 
{target:'foo7', latitude:'lat', longitude:'lon', eta:'eta'}, 
{target:'foo8', latitude:'lat', longitude:'lon', eta:'eta'}, 
{target:'foo9', latitude:'lat', longitude:'lon', eta:'eta'}, 
{target:'foo10', latitude:'lat', longitude:'lon', eta:'eta'}, 


foreach(var wpt; dummyData) {
 var newRow = canvas.HBoxLayout.new();
 var targetBtn = canvas.gui.widgets.Button.new(scrollContent, canvas.style, {wordWrap:0})
 .setFixedSize(75, 25);
 var latitudeBtn =  canvas.gui.widgets.Button.new(scrollContent, canvas.style, {wordWrap:0})
 .setFixedSize(75, 25);
 var longitudeBtn =  canvas.gui.widgets.Button.new(scrollContent, canvas.style, {wordWrap:0})
 .setFixedSize(75, 25);
var ETABtn =  canvas.gui.widgets.Button.new(scrollContent, canvas.style, {wordWrap:0})
 .setFixedSize(75, 25);
 newRow.addItem( latitudeBtn );
 newRow.addItem( longitudeBtn );
 newRow.addItem( ETABtn );

 list.addItem( newRow );

} # foreach waypoint

} # addTable()

addTable(scrollContent, list);