Howto:Creating a custom waypointlist pendant using Canvas

From FlightGear wiki
Jump to navigation Jump to 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 =[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:
  call(canvas.Window.del, [], me);

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

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

var vbox =;

 var scroll =,, {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 =;

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 =;
 var targetBtn =,, {wordWrap:0})
 .setFixedSize(75, 25);
 var latitudeBtn =,, {wordWrap:0})
 .setFixedSize(75, 25);
 var longitudeBtn =,, {wordWrap:0})
 .setFixedSize(75, 25);
var ETABtn =,, {wordWrap:0})
 .setFixedSize(75, 25);
 newRow.addItem( latitudeBtn );
 newRow.addItem( longitudeBtn );
 newRow.addItem( ETABtn );

 list.addItem( newRow );

} # foreach waypoint

} # addTable()

addTable(scrollContent, list);