Howto:Canvas applications as Nasal submodules

From FlightGear wiki
Jump to: navigation, search


Note: This tutorial makes use of features that are only available in FlightGear versions >= 2.11 !

Here's some boilerplate code to get you started creating a simple Nasal submodule that shows a Canvas window during startup. This can be used to develop tool windows/dialogs or even dedicated applications like "FGPlot", all working directly inside FlightGear and without having any 3rd party dependencies. You only need to follow these installation instructions:

  • come up with a module name, for example "test"
  • create a new folder in $FG_ROOT/Nasal, named "test": $FG_ROOT/Nasal/test (this will be the sub module name and namespace)
  • next, add a new Nasal file to the folder $FG_ROOT/Nasal/test with a name that ends in .nas (here, we are simply using test.nas)
  • finally, adapt the module_name variable at the top of the snippet to reflect your changes
  • to add your own changes, you only need to implement the setup() function, e.g. to add event handlers (Canvas - Event Handling)
var module_name = "test";# should be saved in $FG_ROOT/Nasal/test/test.nas
var width = 400; 
var height = 300;

# you can add your own code/event handlers here
# it will be called at the end of the init() routine
var setup = func( root ) {
 print("setup() is still empty and not yet implemented!");
}

##
# this is the init routine that will be invoked by the listener once the submodule has been loaded
# it sets up a simple canvas window with a caption, dragging support and a close button
# events are registered via the .addEventListener() method
# the window itself is 100% custom drawn using OpenVG primitives
var init = func() {
                removelistener( listener_id );
		var dlg = canvas.Window.new([width, height]);
		var my_canvas = dlg.createCanvas()
		                   .setColorBackground(0,0,0,0);
		var root = my_canvas.createGroup();
		var title_bar = root.createChild("group");
		title_bar.addEventListener("drag", func(e) { dlg.move(e.deltaX, e.deltaY); });
		var x = 0;
		var y = 0;
		var rx = 8;
		var ry = 8;
		var w = 400;
		var h = 20;
		title_bar.createChild("path")
		    .moveTo(x + w - rx, y)
		    .arcSmallCWTo(rx, ry, 0, x + w, y + ry)
		    .vertTo(y + h)
		    .horizTo(x)
		    .vertTo(y + ry)
		    .arcSmallCWTo(rx, ry, 0, x + rx, y)
		    .close()
		    .setColorFill(0.25,0.24,0.22)
		    .setStrokeLineWidth(0);
		y = 20;
		h = 280;
		root.createChild("path")
		    .moveTo(x + w, y)
		    .vertTo(y + h)
		    .horizTo(x)
		    .vertTo(y)
		    .setColorFill(1,1,1)
		    .setColor(0,0,0);
		x = 8;
		y = 5;
		w = 10;
		h = 10;
		title_bar.createChild("path", "icon-close")
		    .moveTo(x, y)
		    .lineTo(x + w, y + h)
		    .moveTo(x + w, y)
		    .lineTo(x, y + h)
		    .setColor(1,0,0)
		    .setStrokeLineWidth(3)
		    .addEventListener("click", func dlg.del());
		title_bar.createChild("text", "dialog-caption")
		    .setText( module_name )
		    .setTranslation(x + w + 8, 4)
		    .setAlignment("left-top")
		    .setFontSize(14)
		    .setFont("LiberationFonts/LiberationSans-Bold.ttf")
		    .setColor(1,1,1);

                 # add your own code here (event handlers etc)
                 setup( root ); # pass the canvas root to the setup routine
}

var listener_id = _setlistener("/nasal/"~module_name~"/loaded", init );

This is will just show a simple canvas window during startup, you will probably want to use a listener or menu item to show/hide the dialog instead. To add event handling support, see: Canvas - Event Handling.