Canvas event handling: Difference between revisions

From FlightGear wiki
Jump to navigation Jump to search
Line 93: Line 93:


= Example Code =
= Example Code =
For the latest examples, please refer to [https://gitorious.org/~tomprogs/fg/toms-fgdata/commits/canvas-gui-demo Tom's canvas-gui-demo branch on gitorious]. This is also where you can find the following code in $FG_ROOT/Nasal/canvas/gui.nas (note that this example makes use of advanced Nasal concepts, such as anonymous functions and lots of embedded/inline code):
For the latest examples, please refer to [https://gitorious.org/~tomprogs/fg/toms-fgdata/commits/canvas-gui-demo Tom's canvas-gui-demo branch on gitorious]. This is also where you can find the following code in $FG_ROOT/Nasal/canvas/gui.nas (note that this example makes use of advanced Nasal concepts, such as anonymous functions, method chaining and lots of embedded/inline code):
<syntaxhighlight lang="php"># Canvas GUI demo
<syntaxhighlight lang="php"># Canvas GUI demo
#
#

Revision as of 16:00, 22 May 2013


The Canvas event handling system is heavily inspired by the DOM Event Model. If you have already worked with events in HTML and JavaScript most concepts of the Canvas event system should be already familiar to you.

Listen for events

To receive events callback function can be added to elements on a Canvas as well as to the Canvas itself:

canvas.addEventListener("<type>", <func>);
canvas_element.addEventListener("<type>", <func>);

For each placement of a Canvas handling events can be enabled or disabled. A Canvas placed in a PUI widget or as standalone GUI window receives events by default, whereas Canvases placed onto the aircraft model or in the scenery do not receive any events by default.

For standalone GUI windows setting capture-events to 0 or 1 enables or disables handling of events respectively. For a Canvas placed onto a 3d model, setting capture-events inside the placement can be used to activate event handling:

var dlg = canvas.Window.new([152,74]);

# Disable event handling for this window. Events will pass through
# and can reach any window or also object covered by the window.
dlg.setBool("capture-events", 0);

# Place the canvas onto the PFD and enable receiving events
my_canvas.addPlacement({"node": "PFD-Screen", "capture-events": 1});

Event classes

var Event = {
  # Name of event type [read-only]
  type: <typename>,

  # Target element [read-only]
  target: <target-element>,

  # Stop further propagation of event (stop
  # bubbling up to its parents)
  stopPropagation: func()
};

var MouseEvent = {
  parents: [Event],

  # Position in screen coordinates [read-only]
  screenX: <screen-x>,
  screenY: <screen-y>,

  # Position in window/canvas coordinates [read-only]
  clientX: <client-x>,
  clientY: <client-y>,

  # Distance to position of previous event [read-only]
  deltaX: <delta-x>,
  deltaY: <delta-y>,

  # Current click count (number of clicks within a certain
  # time limit. max. 3) [read-only]
  click_count: <click-count>
};

Event types

Type Description DOM equivalent event Notes
mousedown Mouse button pressed mousedown
mouseup Mouse button released mouseup
click mousedown + mouseup have been triggered for this element without moving more than a certain maximum distance click
dblclick Two click events have been triggered for this element without moving more than a certain maximum distance and time limit dblclick
drag The mouse has been moved with a button down. After dragging has started above an element, all consecutive drag events are sent to this element even if the mouse leaves its area
wheel Mouse wheel rotated (see deltaY for direction) wheel
mouseover TODO mouseover
mouseout TODO mouseout
mouseleave TODO mouseleave

Example Code

For the latest examples, please refer to Tom's canvas-gui-demo branch on gitorious. This is also where you can find the following code in $FG_ROOT/Nasal/canvas/gui.nas (note that this example makes use of advanced Nasal concepts, such as anonymous functions, method chaining and lots of embedded/inline code):

# Canvas GUI demo
#
#  Shows an icon in the top-right corner which upon click opens a simple window
#
(func {
var init_gui = setlistener("/nasal/std/loaded", func() {
  removelistener(init_gui);
  var dlg = canvas.Window.new([32,32]);
  dlg.setInt("y", 4)
     .setInt("right", 4);
	var my_canvas = dlg.createCanvas()
                     .setColorBackground(0,0,0,0);
	var root = my_canvas.createGroup();
  canvas.parsesvg(root, "gui/dialogs/images/icon-aircraft.svg");

  my_canvas.addEventListener("mouseover", func(event)
	{
	  debug.dump( props.wrapNode(event.target._node_ghost) );
	});
  my_canvas.addEventListener("click", func
  {
		var dlg = canvas.Window.new([400,300]);
		var my_canvas = dlg.createCanvas()
		                   .setColorBackground(0,0,0,0);
		var root = my_canvas.createGroup();
		root.addEventListener("click", func(e) { printf("click: screen(%.1f|%.1f) client(%.1f|%.1f) click count = %d", e.screenX, e.screenY, e.clientX, e.clientY, e.click_count); });
		root.addEventListener("dblclick", func(e) { printf("dblclick: screen(%.1f|%.1f) client(%.1f|%.1f)", e.screenX, e.screenY, e.clientX, e.clientY); });
		root.addEventListener("wheel", func(e) { printf("wheel: screen(%.1f|%.1f) client(%.1f|%.1f) %.1f", e.screenX, e.screenY, e.clientX, e.clientY, e.deltaY); });
		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("Aircraft Help")
		    .setTranslation(x + w + 8, 4)
		    .setAlignment("left-top")
		    .setFontSize(14)
		    .setFont("LiberationFonts/LiberationSans-Bold.ttf")
		    .setColor(1,1,1);
		var text = root.createChild("text")
		    .setText("This could be used for building an 'Aircraft Help' dialog.\nYou can also use it to play around with the new Canvas system :). β")
		    .setTranslation(10, 30)
		    .setAlignment("left-top")
		    .setFontSize(14)
		    .setFont("LiberationFonts/LiberationSans-Regular.ttf")
		    .set("max-width", 380)
		    .setColor(0,0,0);
		var text_move =
		  root.createChild("text")
		    .setText("Mouse moved over text...")
		    .set("character-size", 15)
		    .set("font", "LiberationFonts/LiberationSans-Bold.ttf")
		    .set("alignment", "left-center")
		    .setTranslation(20, 200)
		    .set("fill", "#ff0000")
		    .hide();
		var visible_count = 0;
		text.addEventListener("mouseover", func text_move.show());
		text.addEventListener("mouseout", func text_move.hide());
		text.addEventListener("click", func canvas.Dialog.new([240,135]).draw());
  });
});
})();