Using listeners and signals with Nasal: Difference between revisions

Jump to navigation Jump to search
m
Link to special directory articles
m (Link to special directory articles)
Line 2: Line 2:


== Listeners and Signals ==
== Listeners and Signals ==
The important thing to keep in mind is that custom listeners are generally not about loading or running Nasal files, most of the Nasal files are loaded and executed implictly during startup. Only the Nasal sub modules (i.e. inside their own $FG_ROOT/Nasal/ directory) are dynamically loaded using a listener). So listeners are really just a simple way to talk to the property tree:
The important thing to keep in mind is that custom listeners are generally not about loading or running Nasal files, most of the Nasal files are loaded and executed implictly during startup. Only the Nasal sub modules (i.e. inside their own [[$FG_ROOT]]/Nasal/ directory) are dynamically loaded using a listener). So listeners are really just a simple way to talk to the property tree:
'''Hey property tree, would you please be so kind to call this Nasal function whenever this property is modified?'''
'''Hey property tree, would you please be so kind to call this Nasal function whenever this property is modified?'''


Line 10: Line 10:


===setlistener() vs. _setlistener() ===
===setlistener() vs. _setlistener() ===
You are requested *not* to use the raw _setlistener() function, except in files in $FG_ROOT/Nasal/ when they are
You are requested *not* to use the raw _setlistener() function, except in files in [[$FG_ROOT]]/Nasal/ when they are
needed immediately. Only then the raw function is required, as it doesn't rely on props.nas.
needed immediately. Only then the raw function is required, as it doesn't rely on props.nas.


Line 35: Line 35:
  var listener_id = setlistener(<property>, <function> [, <startup=0> [, <runtime=1>]]);
  var listener_id = setlistener(<property>, <function> [, <startup=0> [, <runtime=1>]]);


The first argument is a property node object (<tt>props.Node()</tt> hash) or a property path. Because the node hash depends on the props.nas module being loaded, <tt>setlistener()</tt> calls need to be deferred when used in an $FG_ROOT/Nasal/*.nas file, usually by calling them in a <tt>settimer(func {}, 0)</tt> construction. To avoid that, one can use the raw <tt>_setlistener()</tt> function directly, for which <tt>setlistener()</tt> is a wrapper. The raw function does only accept node paths (e.g. "/sim/menubar/visibility"), but not props.Node() objects.
The first argument is a property node object (<tt>props.Node()</tt> hash) or a property path. Because the node hash depends on the props.nas module being loaded, <tt>setlistener()</tt> calls need to be deferred when used in an [[$FG_ROOT]]/Nasal/*.nas file, usually by calling them in a <tt>settimer(func {}, 0)</tt> construction. To avoid that, one can use the raw <tt>_setlistener()</tt> function directly, for which <tt>setlistener()</tt> is a wrapper. The raw function does only accept node paths (e.g. "/sim/menubar/visibility"), but not props.Node() objects.


The second argument is a function object (not a function call!). The <tt>func</tt> keyword turns code into a function object.
The second argument is a function object (not a function call!). The <tt>func</tt> keyword turns code into a function object.
Line 158: Line 158:
* <tt>/sim/signals/click</tt> ... set to "true" after a mouse click at the terrain. Hint that the geo coords for the click spot were updated and can be retrieved from /sim/input/click/{longitude-deg,latitude-deg,elevation-ft,elevation-m}
* <tt>/sim/signals/click</tt> ... set to "true" after a mouse click at the terrain. Hint that the geo coords for the click spot were updated and can be retrieved from /sim/input/click/{longitude-deg,latitude-deg,elevation-ft,elevation-m}
* <tt>/sim/signals/screenshot</tt> ... set to "true" right before the screenshot is taken, and set to "false" after it. Can be used to hide and reveal dialogs etc.
* <tt>/sim/signals/screenshot</tt> ... set to "true" right before the screenshot is taken, and set to "false" after it. Can be used to hide and reveal dialogs etc.
* <tt>/sim/signals/nasal-dir-initialized</tt> ... set to "true" after all Nasal "library" files in $FG_ROOT/Nasal/ were loaded and executed. It is only set once and can only be used to trigger listener functions that were defined in one of the Nasal files in that directory. After that signal was set Nasal starts loading and executing aircraft Nasal files, and only later are <tt>settimer()</tt> functions called and the next signal is set:
* <tt>/sim/signals/nasal-dir-initialized</tt> ... set to "true" after all Nasal "library" files in [[$FG_ROOT]]/Nasal/ were loaded and executed. It is only set once and can only be used to trigger listener functions that were defined in one of the Nasal files in that directory. After that signal was set Nasal starts loading and executing aircraft Nasal files, and only later are <tt>settimer()</tt> functions called and the next signal is set:
* <tt>/sim/signals/fdm-initialized</tt> ... set to "true" when then FDM has just finished its initialization
* <tt>/sim/signals/fdm-initialized</tt> ... set to "true" when then FDM has just finished its initialization
* <tt>/sim/signals/reinit-gui</tt> ... set to "true" when the GUI has just been reset (e.g. via Help menu). This is used by the gui.Dialog class to reload Nasal-loaded XML dialogs.
* <tt>/sim/signals/reinit-gui</tt> ... set to "true" when the GUI has just been reset (e.g. via Help menu). This is used by the gui.Dialog class to reload Nasal-loaded XML dialogs.
* <tt>/sim/signals/frame</tt> ... triggered at the beginning of each iteration of the main loop (a.k.a. "frame"). This is meant for debugging purposes. Normally, one would just use a settimer() with interval 0 for the same effect. The difference is that the signal is guaranteed to be raised at a defined moment, while the timer call may change when subsystems are re-ordered.
* <tt>/sim/signals/frame</tt> ... triggered at the beginning of each iteration of the main loop (a.k.a. "frame"). This is meant for debugging purposes. Normally, one would just use a settimer() with interval 0 for the same effect. The difference is that the signal is guaranteed to be raised at a defined moment, while the timer call may change when subsystems are re-ordered.

Navigation menu