MouseTrap.mesa
Copyright Ó 1989, 1992 by Xerox Corporation. All rights reserved.
Ken Shoemake, May 16, 1989 3:10:38 am PDT
Jules Bloomenthal July 20, 1992 4:33 pm PDT
~
BEGIN
This interface defines procedures for trapping the mouse, that is, adjusting its position (and that of the cursor) depending on its location.
Type Declarations
Viewer: TYPE ~ ViewerClasses.Viewer;
Position:
TYPE ~
RECORD [x, y:
INTEGER];
MouseTrapSpecs:
TYPE ~
RECORD [
enabled: BOOL ¬ FALSE, -- TRUE if trapping desired
proc: MouseTrapProc ¬ NIL, -- proc to call with mouse coords
data: REF ANY ¬ NIL -- data to pass to proc
MouseTrapProc:
TYPE ~
PROC [mouse: Position, data:
REF
ANY]
RETURNS [changed: BOOL ¬ FALSE, mouseTo: Position];
Sets changed to TRUE and returns new coords if mouse needs to be moved to stay in trap.
Coords are hardware coords, so upper left of screen is [0, 0].
BoxTrapData: TYPE ~ REF BoxTrapDataRep;
BoxTrapDataRep:
TYPE ~
RECORD [
wrap: {no, x, yes, y} ¬ no, -- wrap mouse at edges, else stick
minCorner: Position ¬ [370, 270], -- smallest coordinates in box trap
maxCorner: Position ¬ [430, 330] -- largest coordinates in box trap
RoundTrapData: TYPE ~ REF RoundTrapDataRep;
RoundTrapDataRep:
TYPE ~
RECORD [
wrap: {no, yes} ¬ no, -- wrap mouse at edge, else stick
center: Position ¬ [400, 300], -- center of circular trap
radiusSquared: REAL ¬ 900 -- square of radius of circular trap
];
Wizard Control Procs
The following is a typical application to keep the mouse inside a viewer while dragging:
orgx, orgy, oppx, oppy: INTEGER;
data: MouseTrap.BoxTrapData;
[orgx, orgy] ← MouseTrap.UserToMouseCoords[self, 0, 0];
[oppx, oppy] ← MouseTrap.UserToMouseCoords[self, self.cw-1, self.ch-1];
IF oppx < orgx THEN {swap: INTEGER ← oppx; oppx ← orgx; orgx ← swap};
IF oppy < orgy THEN {swap: INTEGER ← oppy; oppy ← orgy; orgy ← swap};
data ← NEW[MouseTrap.BoxTrapDataRep ← [no, [orgx, orgy], [oppx, oppy]]];
[] ← MouseTrap.SetTrap[[enabled: TRUE, proc: MouseTrap.BoxTrap, data: data]];
To stop trapping, typically upon a mouse up, simply:
[] ← MouseTrap.UnsetTrap[];
An appropriate place for these calls is in the TIP NotifyProc. You may consider claiming a viewer lock so the column can't be rearranged out from under your trap by some independent process opening or closing a viewer. So that a mouse up is certain to be noticed, you may wish to call InputFocus.CaptureButtons, though that probably isn't necessary. Traps (such as BoxTrap and RoundTrap) that use MouseUpEscape will probably catch all mouse ups.
By supplying a custom trapping procedure the mouse may be confined to a fancier region than a rectangle or circle. Keep in mind that whatever you do should be done quickly!
UserToMouseCoords:
PROC [self: Viewer, vx, vy:
INTEGER ¬ 0]
RETURNS [Position];
Convert coordinates in viewer to hardware mouse coordinates (upper left is [0, 0]).
UserFromMouseCoords:
PROC [self: Viewer, mx, my:
INTEGER ¬ 0]
RETURNS [Position];
Convert hardware mouse coordinates (upper left is [0, 0]) to coordinates for viewer.
Note that mouse may be outside this viewer. Not recommended for use within
MouseTrapProc, where it's better to use only mouse coords to avoid overhead.
SetTrap:
PROC [newSpecs: MouseTrapSpecs]
RETURNS [MouseTrapSpecs];
Establish new mouse trap, not necessarily enabled. Returns old trap specifications.
GetTrap:
PROC
RETURNS [MouseTrapSpecs];
Get the specifications of the current mouse trap.
UnsetTrap:
PROC
RETURNS [MouseTrapSpecs];
Disable current mouse trap, without changing it otherwise. Returns old trap specifications.
StartWatchingMouseTrap:
PROC;
This is ordinarily called just once, when the Impl is run, to start background process.
StopWatchingMouseTrap:
PROC;
Kill the background process, after which no mice will be trapped.
Debug:
PROC [out:
IO.
STREAM];
Turn off debugging with out = NIL.