
The following is a description of the routines written to implement mouse
support within Clipper's(tm) Get/Read system. The basis of the system is
the set of routines in the Nanforum Toolkit for mouse functions (maintained
in Library 7).


Some basic features of the system are:

1. The mouse can be used to select a field by placing the cursor on the field
   and clicking the left button.
2. The cursor can be moved within a field by placing the cursor in the desired
   position and clicking the right button.
3. Multiple levels of READs are handled. One can click on a lower level field
   and the active GET is set to the desired field by exiting upper level GETs.
4. One can designate portions of the screen or the entire screen of lower level
   GETs from being accessible. (One can also remove mouse support for the
   current level if one wishes.)
5. Portions of the screen can be used to execute code blocks with the code
   block receiving the button clicked. Maximum repetition rate of a held button
   can be set as well as requiring button release. The button required to
   execute the code block can be designated.


The main routine is MOUSEREAD() which replaces ReadModal(). If one wishes to
place a line at the beginning of your program or in STD.CH or equivalent to 
call this instead of ReadModal() one can place the lines:

                     #command READ => MouseRead(GetList); GetList:={}
                     #command READ SAVE => MouseRead(GetList)

Alternatively, one can place the above two lines in an include file and
"include" it in any file which does a READ. MOUSEGET.CH is provided for
this purpose.

If one does not wish to take advantage of several options such as numbers
4 and 5 above, the above changes to STD.CH is all that one needs to take
advantage of the mouse.

Please direct any questions to:
			Leo Letendre
			CIS: 73607,233

Please report any bugs as there will probably be a few (at least). Also
I am sure there are some oversights in the capabilities. Please pass any
positive or negative comments along. Please note that I have only tried
these routines with a genuine Microsoft mouse so I don't know how well
they work with a three button mouse or other drivers. Anyone who tries
them with another mouse please pass on your comments.

If anyone wishes to use these routines, permission to use the changes to 
Readmodal and the supporting routines is granted for use in any finished 
program, commercial or otherwise. However, permission is not granted to
include these routines in third party commercial or shareware libraries.

A demonstration program is included (rather crude I admit). The source is
in GETDEMO.PRG and it contains examples of some of the things one can do with
the mouse. To load using RTLINK use GETDEMO.LNK.

Basic Description of system:

The major difference between the traditional READ system and this mouse
inclusive one is the interjection of polling the mouse along with the keyboard.
When either input is received action is take; keyboard input causes the 
standard action to be taken while mouse input causes a search for actions 
based upon the location of GET fields and screen "hot spots". Immediately after
detecting a mouse button press, the internal button press counters are cleared.
subsequent calls to FT_MBUTPRS() can be used to determine double clicks
for example. Three sets of screen coordinates are maintained.

I. The coordinates of each GET field is determine and stored prior to 
actually initiating the READ. 

II. The programmer can designate screen coordinates within which any GET field 
at the current or lower level of READs is inactive. This is useful if you are 
doing a GET/READ from within a VALID or WHEN clause or SET KEY routine and you 
must place the latest GET on top of previously active GETs. By doing this, the 
user will not be able to accidentally click on a GET that is below a dialog 
box containing the latest GET. 

III. The programmer can also designate a set of coordinates and associated 
code blocks which will cause the program to execute the code block when the 
mouse is clicked within the coordinates. The code block is executed with four 
arguments passed: button number, row coordinate of mouse cursor, column 
coordinate of mouse cursor and the system time when the mouse button press was 
detected (Value returned by SECONDS()). Thus to use all four arguments a 
code block of the form:

   {|nButton,nRow,nColumn,nTime| MyFunc(nButton,nRow,nColumn,nTime)}

would be passed along with the coordinates which define the activation spot
on the screen. (Note: you must worry about having the mouse event span midnight
when the clock goes back to 0. See SLEEP in MOUSEGET.PRG for a way to handle
it.) You can also temporarily deactivate the hot spot by calling RDCoolSpot(id)
with the id number of the hot spot to deactivate (cool off). One can then
reactivate it by calling RDWarmSpot(id) with the id number of the hot spot
to reactivate (warm back up).

Options are available for setting delays between the successive actions when
a mouse button is held down or to require the release of the button. If you are
worried about .exe size, only the following NANFOR.LIB routines are used:

		FT_MSHOWCRS()		FT_MGETPOS()		FT_MBUTPRS()
		FT_MHIDECRS()		FT_MBUTREL()		FT_MRESET()
		FT_MSETPOS()		FT_INT86()

One additional mouse function is included in MOUSFUNC.PRG. FT_MINIT is a
routine which I have submitted to the Nanforum Toolkit for the next
release (v 3.0). When it appears, you should remove it from MOUSFUNC.PRG
as you will receive a linking warning about duplicate symbols.


Contents of this package:

MOUSEGET.TXT      This file
MOUSEGET.PRG      Replacement for GETSYS.PRG
MOUSEGET.CH       Include file for running gets with mouse
MOUSFUNC.PRG      Common functions for get/read and browse systems
LOGEXAM.PRG       Example WHEN/VALID routine for changing logical with mouse
GETEXIT.CH        Updated version that includes a mouse state
GETDEMO.PRG       An example program
GETDEMO.RMK       An RMAKE link script
GETDEMO.LNK       An RTLINK link script

The API:

The following are the headers from the routines which are callable from the
Clipper code. Hopefully there is enough information in them to get one using
them. If there is not, I didn't do an adequate job of documention. They are
not quite in the form I normally use but I was also taught to follow the
norms established in any routine one is modifying. Good Luck.

*****************************************************************************
******
*
* MOUSEREAD()
*
* This routine calls all of the appropriate routines to do a read using the
* mouse for field selection
*
* Calling Parameters:
*                     aGetList - input - The list of gets normally passed to
*                                readmodal
*
* Returns: Whatever ReadModal returns
*
*****************************************************************************
*******
** RdMouseLvl()
*
* this procedure sets the flag which controls which levels of READS
* are accesable to the mouse. If the calling  argument is missing then 
* it just returns the current setting.
*
* Calling parameters:
*                     nLevel - integer value of the level of READs below which
*                              the mouse is inactive. READs are numbered in 
*                              order of execution starting at 1.
*
* Returns:
*          current status
* Notes:
*         To get the current level of read use RDCurLevel().
*
*         Is usually called prior to READ but could be called from within
*         a WHEN clause.

*****************************************************************************
*******
** RDMouseOn()
*
* this procedure sets the flag which controls whether the mouse is active for
* the current read. If the calling argument is missing then it just returns 
* the current setting.
*
* Calling parameters:
*                     lOn - Logical = .T. for mouse being active
*                                   = .F. for mouse being off
*
* Returns:
*          current status = .T. or .F.
* Notes:
*         This routine does not signal an error if an incorrect calling
*         parameter is passed. In this case it acks as if the caller passed
*         none.
*
*         This routine should not normally need to be called but is included
*         on the off chance that it will be.

*****************************************************************************
******
*
* RDExclMouse()
*
* This routine allows the caller to exclude gets in an area of the screen from
* being selected at the current and all lower levels.
*
* Calling Parameters:
*                     nTopRow - the top row of the area to exclude
*                     nLeftCol - the left column of the area
*                     nBotRow - the bottom row of the area to exclude
*                     nRightCol - the right column of the area to exclude
*
* Returns: nID which is an ID number identifying the region so that the
*              region may be restored to active status with a call to
*              RDRemExcl(ID)
*

*****************************************************************************
******
*
* RDRemExcl()
*
* This subroutine clears the excluded region set by ExcludeMouse for the
* currently active READ
*
* Calling Parameters : nID - which is the ID number of the region to place
*                            back to active duty. It is given by ExcludeMouse.
*
* Returns: NIL
*

*****************************************************************************
******
*
* RDHotSpot()
*
* This function allows the caller to define a location on the screen which
* if clicked on with the mouse will cause an action to take place.
*
* Calling parameters:
*                     nTopRow - the top row of the area 
*                     nLeftCol - the left column of the area
*                     nBotRow - the bottom row of the area
*                     nRightCol - the right column of the area 
*                     bAction - Code block which will be executed when
*                              mouse is clicked in the area
*                     nButton - Optional button number for action to occur. IF
*                              equal to 0 or NIL, the action occurs on 
*                              clicking anybutton (the code block can decide 
*                              what to do with based upon the button). If equal
*                              to 1, code block executes only on left click,
*                              if equal to 2 only on right click and if equal
*                              to 4(?) then the middle button.
*                     nSleep - Optional value of a minimum time (in seconds) to
*                              wait between servicing multiple button presses. 
*                              Prevents routine from operating too quickly and 
*                              reading the press of a button multiple times 
*                              when not intended. If =NIL then the default value
*                              is used (see MDefaultSleep()).
*                      lRelease - Optional Logical Value. If set to .T. the
*                              servicing routine will pause after the completion
*                              of bAction for the release of the mouse button(s)
*                              Useful for guaranteeing no multiple hits on
*                              an area. If =NIL then the default is used (see
*                              MDefaultRelease())
*
* Returns: nId which is an ID to be used to remove the area with a call
*              to RemHotSpot(nId)
*
* Note: The code block bAction is called with four arguments:
*
*                 nButNum: the number of the button pressed with
*                          1=left, 2=right, 4=middle(?).
*                 nRow: The row that the mouse cursor was in when it
*                       was clicked
*                 nCol: The column that the mouse cursor was in when it
*                       was clicked
*                 nTime: The time returned by SECOND() shortly after the
*                       button was clicked.
*
*        Thus the code block should have a form similar to the following
*        if one wishes to use the button/cursor information:
*
*               {|nButNum, nRow, nCol, nTime| MyFunc(NButNum,nRow,nCol,nTime)}

*****************************************************************************
******
*
* RDRemHotSpot()
*
* This subroutine clears the excluded region set by ExcludeMouse for the
* currently active READ
*
* Calling Parameters : nID - which is the ID number of the region to remove
*                            from active duty. It is given by AddHotSpot.
*
* Returns: NIL
*

*****************************************************************************
******
*
* RDCoolSpot()
*
* This subroutine deactivates the specified HotSpot without deleting it
*
* Calling Parameters : nID - which is the ID number of the region to remove
*                            from active duty. It is given by AddHotSpot.
*
* Returns: NIL
*

*****************************************************************************
******
*
* RDWarmSpot()
*
* This subroutine reactivates the specified HotSpot which was deactivated
* by RDCoolSpot
*
* Calling Parameters : nID - which is the ID number of the region to return 
*                            to active duty. It is given by AddHotSpot.
*
* Returns: NIL
*

*****************************************************************************
*****
*
*  RDDefSleep()
*
* This routine sets the default minimum time between servicing the mouse
* button when on a "hot spot". Useful for slowing things down.
*
* Calling Paramters: nDefSleep - Number of second for the default interval
*                                If absent no change made.
*
* Returns: current setting
*
* Note: the default time within the system is 0.2 seconds
*****************************************************************************
*****
*
*  RDDefRelease()
*
* This routine sets the default logical value controling if the program
* waits for the release of the mouse button before continuing when it is in
* a "Hot Spot"
*
* Calling Paramters: lDefRelease - If present will set the default action
*                                  on releasing the mouse button before
*                                  continuing when servicing a "Hot Spot"
*                                  If absent no change made. .T. causes
*                                  a wait for release.
*
* Returns: current setting
*
*
* Note: The default release action is not to require a release (= .F.)
*****************************************************************************
******
*
* RDCurLevel()
*
* This routine will return the current level of READs
*
* Modification History:
*        Version    Date      Who       Notes
*         V1.00     4/25/91   LJL       Initial Version
*
* Calling parameters: None
*
* Returns:
*          The current level of READs currently functioning. The level number
*          is the current count of nested READs starting at 1.
*

*****************************************************************************
******
*
* FUNCTION sleep(nSeconds,nInitial)
*
* Purpose: wait for a given period of time
*
* Modification History:
*        Version    Date      Who       Notes
*         V1.00     4/20/91   LJL       Initial Version
*
* Calling parameters: nSeconds - Input the number of seconds to waste
*                     nInitial - Optional input - the clock value (from
*                                a call to SECONDS()) from which the
*                                nSeconds seconds are to elapse. Useful
*                                for setting a minimum time between the
*                                start of events which could take a variable
*                                amount of time.
*
* Returns: NIL
*
* Notes: This gives the best guess based upon speed of the machine.
*        Don't use for more than 24 hours
*

*****************************************************************************

******
*
*   RDDescend()
*
* Purpose: This routine returns a logical indicating if the GET/READ system is
* descending to a lower level read based upon a request by the mouse system
*
* Calling Parameters: None
*
* Returns: .T. if the GET/READ system will descend to a lower level than
*           the current one
*          .F. if it will stay at the same level.
*
* Notes: This routine can be useful when a READ is performed in a VALID clause.
*        It is the equivalent to LASTKEY()=K_ESC.

*****************************************************************************
*****
*
* function RDIgnoreMouse()
*
* Purpose: force the routines to ignore the mouse and perform the overhead
*          necessary for mouse support
*
* Calling Parameters: lIgnore - logical for ignoring mouse .T. = act as if
*                               mouse is not present. If absent just returns
*                               current setting
*
* Returns: setting in effect prior to call
*
*****************************************************************************

******
*
* function RDCancelDescend()
*
* Purpose: to cancel the effect of a mouse click on a lower level GET
*
* Calling Parameters: None
*
* Returns: NIL
*
* Notes: At times it may be useful to cancel the effect of the mouse causing
* a run down to a lower level read. This function will provide that effect.

*****************************************************************************

(This file last updated 8/30/91)