[PREVIOUS] [NEXT] [UP]

Using the mouse

This chapter will explain how to use the mouse pointer. You will learn

How to query the mouse cursor position

The mouse_xy unit provides access to the mouse cursor position and button states. An instance of the mouse_xy unit is always bound to a particular NST window, whose window title has to be specified when you create the mouse_xy instance (if you wish to query several windows, you need a separate mouse_xy instance for each). The fixed binding to a NST window allows the mouse unit to take care of any coordinate scalings that may be in effect for "its" window. Therefore, when you create the instance with option "Autoscaling" on, output connector 0 of the mouse_xy unit will provide the mouse pointer position already scaled to the data coordinates (x,y) of the associated window (e.g., if this is a plot_xy unit, the position values will correspond to the axis labels). Output connector 1 provides the "raw" pixel coordinates (with (0,0) denoting the lowest left pixel of the window).

How to evaluate button settings

Finally, output connector 2 provides at its three pins the current mouse button states (0=off, 1=on for buttons 0,1,2).

Example#1 illustrates a simple use of the mouse unit within a loop. In this case the mouse unit has been set up in "Wait mode" (inspect the parameter window). Whenever execution comes to the mouse unit, it will block until a mouse button is pressed, after which the output connectors will become updated with the current mouse pointer position and button states. When the right mouse button (Pin 2 on the lowest output connector) was pressed, the break_unit leaves the loop.
 

How to use the mouse pointer in an interactive loop

More interactive applications might need to use the mouse in NoWait mode (e.g., you might wish to "drag" an object). For such cases, a "busy loop" is not the recommended technique. Instead, the mouse_xy unit offers, similarly as already explained for the input_window, the possibility of setting up callbacks. To bind callbacks to the mouse unit requires to create it in "autoloop" mode.
To this end, you must specify (in the options field of the create dialog window) the "autoloop" option %L (autoloop persists until the mouse cursor leaves the window) or %iL (autoloop persists until button i is pressed; i=0,1 or 2).

While the autoloop of a mouse unit is active, mouse events can be used to trigger the execution of named NST units. Each binding is specified as an additional option in the mouse unit option field, using the following syntax:

      %!foo1,foo2           execute units foo1 and foo2 once when the autoloop starts
      %!!foo1,foo2         execute foo1, foo2 continuously while the autoloop is active
      %!!!foo1,foo2       execute foo1, foo2 once when the autoloop ends

With similar options, the named units can also be bound to actions of a mouse button i=0,1 or 2:

      %i!foo1,foo2           execute units foo1 and foo2 once when button i goes down
      %i!!foo1,foo2         execute foo1, foo2 continuously while button i is down
      %i!!!foo1,foo2       execute foo1, foo2 once when button i goes up

Example#2 illustrates how to use these possibilities to drag a square with the mouse.

How to make mouse button actions context dependent

Further flexibility becomes possible by specifying each of the above options with a second (usually integer) argument j, e.g,

   %i:j!foo1,foo2           execute units foo1 and foo2 once when button i goes down and control input equals j.

This is the same as %i!foo1,foo2, but restricted to the case that the control input connector (the last input connector of the mouse_xy unit with a single scalar pin) has input value j!=0  (a control input of 0 always disables all actions of the mouse_xy unit). In this way, the set of actions bound to a particular mouse button can be made to depend on the control input, so that the function of each mouse button can be made context dependent (this may even change an already started callback sequence, e.g., when in the above case execution of foo1 changes the control input from j to a different value, foo2 will not be executed anymore).

We postpone an example of this feature until a later lesson.

How to implement mouse callbacks with the prog unit

Often, there are several mouse actions that all refer to the same data structure. In this case, it is convenient to implement each action a public method of a named prog_unit. As explained earlier, the presence of one or several public methods makes a prog_unit into a class container in which each public method is accessible as a named subunit. Since each subunit is implemented by a subroutine in the prog_unit it can easily share global variables of the prog_unit with the other subunits, making the implementation of a set of related mouse actions very convenient (note also that the prog_unit code can itself trigger further callbacks, using its exec_opnd() function).

Example#3 illustrates this technique. Here, button 0 and 2 allow to add or delete a point from a dynamic list. The points in the list are displayed as markers in a two-dimensional coordinate frame, so each button is bound to two actions: the action that changes the list and an additional call that updates the graphical display. The actions that change the list are implemented as the two public methods add_pnt and del_pnt of a prog_unit named prog. The list is implemented as a dynamic array of (x,y) coordinate pairs and is accessible at an output connector of the prog unit. Thus, the drawing can be done by a simple plot_xy unit. The following mouse unit options establish a mouse_xy autoloop with the middle mouse unit button 1 as the exit button and the above actions bound to buttons 0 and 2:

   %1L
   %0!prog:add_pnt,plot_xy
   %2!prog:del_pnt,plot_xy

The first method, prog:add_pnt, adds a point (with coordinates given by the input to the prog_unit) to a dynamic array that is available at the output connector of the prog_unit. The second method, prog:del_pnt, deletes the closest point to the cursor, when it is within a "picking distance limit". Each of the two options also calls the plot_xy unit to show the new set of points after an action. An additional %!!printvec in the mouse_xy option field executes the print_vec unit to show the mouse pointer coordinates while the loop is active.
 


[PREVIOUS] [NEXT] [UP]