/* TEACH GO_MOUSE_SENSITIVE                     Ben Rabau, 27th Aug 1993

This file contains examples of the two sensitive mixins defined in
LIB * GO_MOUSE_SENSITIVE and LIB * GO_KEY_SENSITIVE. These classes allow
behaviour to be attached to Graphical Objects.

For more general detailed information see

HELP * GO
REF * GO


         CONTENTS - (Use <ENTER> g to access required sections)

 -- Contents
 -- Introduction
 -- Small go_mouse_sensitive example

-- Introduction -------------------------------------------------------

The go_mouse_sensitive mixin attaches callbacks to an object which are
triggered when a mouse event such as a "left mouse button is down"
occurs. Three major events are captured:
    1. mouse button down,
    2. mouse button down while moving and
    3. mouse button up.

This is by default foreseen for three mouse-buttons. All events are
sent to the object under the mouse on the "mouse button down" event.

Note that on machines which only have two physical mouse buttons,
logical devices can exist. E.g. in the X-window system, the third
logical mouse button corresponds to "both physical buttons together"
on machines with only two physical mouse buttons.


The go_key_sensitive mixin attaches callbacks to an object to capture
the key strokes from the keyboard. These key strokes are sent to the
object currently under the mouse. Two events are captured:
    1. key down and
    2. key up.
Both events are sent to the object under the mouse on the "key down"
event.

The go_text_input class is a good example of the go_key_sensitive
mixin. A key input handler is available in LIB * GO_LABELLED (see
REF * GO_LABELLED/go_label_editing and REF * GO_TEXT_INPUT).


For both mixins the callbacks only are activated when the object is in
"live" mode. This can occur in two cases:
    1. When the whole pane is "live". E.g. with:
           true  -> go_live_mode( pane );
       or:
           false -> go_edit_mode( pane );
    2. When the object is made live regardless of the pane's mode with:
           true -> go_live_object( object );

See also HELP * GO_LIVE

In "edit" mode there also are a limited number of callbacks possible.
These events are however limited to the "down" events.

See HELP * GO_LIVE and REF * GO_XACTION


*/

/*
-- Small go_mouse_sensitive example -----------------------------------
 */

;;; This requires a go_pane to be active. For instance with:
go_init_rc();

;;; The example will use a sensitive rectangle:
uses go_rectangle;

define :class foo;
    isa go_mouse_sensitive go_rectangle;
enddefine;

;;; To create a sensitive rectangle on the screen, do:
vars rect = newfoo();
go_add_to( rect , go_default_pane );

;;; By default the pane is in "edit" mode (see TEACH * GO_EDIT).
;;; Since the default go_edit_left_action() method is to enable the
;;; object to be dragged (see REF * GO_XACTION/go_edit_left_action),
;;; This new rectangle can be moved to a convenient location.
;;; NOTE:
;;;       The first time one of the methods of this new class foo is
;;;       accessed, there is likely to be a delay caused by the need
;;;       to compile the methods (see REF * OBJECTCLASS).

;;; The object can become live with:
true -> go_live_object( rect );

;;; The rectangle can no longer be moved in this case!
;;; There is currently no behaviour attached to this object since
;;; the no_action procedure is currently attached to all posibble
;;; event hooks. Here are three examples, one for each button 1-3:

go_mouse_down_action( 1, rect ) =>
go_mouse_drag_action( 2, rect ) =>
go_mouse_up_action( 3, rect ) =>

;;; Procedures, or even better: methods, which take two arguments
;;; can be attached to these actions. The arguments represent the
;;; event_data and the object (hence a method will be triggered for
;;; the corresponding class).
;;; The event_data can be altered with the go_expand_event_data() method
;;; as explained in HELP * GO_LIVE.
;;; The default go_value is a vector which go_contains:
;;;           - the X position of the mouse
;;;           - the Y position of the mouse
;;;           - the Button Number
;;;           - the Button State ("down" or "up)
;;;           - the Window Pane in which the event occured

;;; The following methods will change the objects colour and linewidth:
define :method make_red( event_data, rect :foo );
lvars event_data, rect;
    'red' -> go_fgcolour( rect );
    1 -> go_linewidth( rect );
enddefine;

define :method make_green( event_data, rect :foo );
lvars event_data, rect;
    'aquamarine' -> go_fgcolour( rect );
    2 -> go_linewidth( rect );
enddefine;

define :method make_blue( event_data, rect :foo );
lvars event_data, rect;
    'slateblue' -> go_fgcolour( rect );
    3 -> go_linewidth( rect );
enddefine;

;;; To add them to the action hooks, do:
make_red   -> go_mouse_down_action( 1, rect );
make_green -> go_mouse_drag_action( 2, rect );
make_blue  -> go_mouse_up_action( 3, rect );

;;; Note that the make_red() method is activated on the button down event
;;; whereas the make_blue() method on the third button only gets activated
;;; when the button is released.
;;; Note also that even when the button is released outside the object,
;;; the method still gets fired. All methods are sent to the object of
;;; the start of the event (mouse down).
;;; Last but not least, note that the make_green() method is only fired
;;; when the mouse is moved, not when it is simply clicked.

;;; The following makes use of the event_data:
define :method show_position( event_data, rect :foo );
lvars event_data, rect;
    printf(' x = %p   y = %p \n', [% event_data(1), event_data(2) %] );
enddefine;

show_position -> go_mouse_drag_action( 1, rect );

;;; Note that the event can only be triggered by starting the drag
;;; operation in the rectangle.

;;; The following variant would move the object while dragging,
;;; however this is only provided as an example since there is a much
;;; optimised method available (REF *GO_SCREEN_OBJECT/go_drag_and_drop).

define :method move_position( event_data, rect :foo );
lvars event_data, rect;
    go_centre_to( event_data(1), event_data(2), rect );
enddefine;

move_position -> go_mouse_drag_action( 1, rect );

;;; The following will attach the optimised dragging method to the
;;; middle button to compare it with the above simple dragging:

define :method pick_up_for_dragging( event_data, rect :foo );
lvars event_data, rect;
    go_drag_and_drop( rect );
enddefine;

pick_up_for_dragging -> go_mouse_down_action( 2, rect );

;;; The same optimised dragging method can of course be attached to
;;; the drag action  (here for the third button):
pick_up_for_dragging -> go_mouse_drag_action( 3, rect );
;;; However if it is picked up rather fast, then it is possible to
;;; create a gap between the mouse and the object you have picked up...


;;; See HELP * GO_LIVE for explanations on how to convert the higher
;;; level go_select_action() and go_select() methods into these more
;;; powerfull methods.

--- C.all/lib/proto/go/teach/go_mouse_sensitive
--- Copyright University of Sussex 1993. All rights reserved.
