                        Grumpfish Library Version 4.1
                       Copyright (c) 1994 Greg Lief
                           [recompiled 3/21/94]


Greetings
---------

Please accept our sincere congratulations and heartfelt gratitude on
finding and reading this very important file!  Despite our insistence in
the printed manual that the reader seek out a README.1ST file, most
people do not follow these instructions and thus miss out on the
extremely important information herein.  Fortunately, you have proven
yourself NOT to be one of those people, so you will benefit greatly from
having the most up-to-the-minute information on Grumpfish Library, the
award-winning add-on for CA-Clipper.  For best results, print this file
and read it carefully.


Why a README.1ST file??
-----------------------

The mark of good software is that it usually contains features that are
not in the printed documentation.  Printing manuals involves an
unavoidable lag time, during which the software is often still being
improved upon.  Additionally, we continue to enhance Grumpfish Library
based on user feedback long after its initial release, and it is simply
not feasible to reprint our entire stock of manuals every time that such
enhancements take place.


Use the Norton Guide!
---------------------

Before proceeding, bear in mind that everything you are about to read is
covered in the Norton Guides file.  Therefore, we highly recommend that
you refer to that whenever and wherever possible.


Summer '87 Support
------------------

We no longer ship the Summer '87 version of Grumpfish Library, because
it has not been updated since July 1991.  However, it is available free
of charge for the asking.  If you need it, simply contact Grumpfish,
Inc. and have your registration number on hand.


Important Mouse Support Details
-------------------------------

Grumpfish Library version 4.1 features full mouse support for CA-Clipper
5.01 and 5.2.  We are very proud of our implementation, which is unique
in that WE USE THE MOUSE DRIVER BUILT INTO CA-CLIPPER 5!  Yes,
CA-Clipper 5 includes a mouse driver which was not brought to the
surface, but we have been able to take advantage of it.  This is great
news for you because it means that the chances for annoying hardware
conflicts are thus greatly reduced (especially when your CA-Clipper
application crashes unexpectedly).

Rather than maintain two separate versions of the CA-Clipper source
code, we have delimited all mouse-specific logic with the "#ifdef MOUSE"
preprocessor directive.  You are therefore free to recompile any of the
Grumpfish Library source code without fear of adding mouse overhead
(unless you specifically request it, of course).

If you intend to make use of a mouse in your applications, please follow
these steps:

  1) Be sure to #include the GRUMP.CH header file in your program.

  2) Compile your source code with the "/dMOUSE" compile switch. This
     switch should also be used in the event that you need to make
     changes to (and thus recompile) any of the Grumpfish Library
     CA-Clipper source code.  If you are using CA-Clipper 5.2, you
     should also use the "/dCLIPPER52" compile switch.

  3) Link your applications with either GRUMPM.LIB (for CA-Clipper 5.01)
     or GRUMP52M.LIB (for CA-Clipper 5.2).  If you are linking with
     Blinker or other dynamic overlay linkers, all of Grumpfish Library
     can be overlaid with one notable exception: the EVE (5.01) or EVE52
     (5.2) module.  You should include the following statement somewhere
     in your link script outside your BEGINAREA..ENDAREA sequence:

     MODULE eve      # for CA-Clipper 5.01
     - or -
     MODULE eve52    # for CA-Clipper 5.2

     Failure to do so will generally cause your machine to lock up when
     running the application.

  4) Finally, and this may be stating the obvious, be sure that a mouse
     driver is installed prior to running your CA-Clipper application!

The CA-Clipper mouse driver includes a number of functions, which we
have brought to the surface for your usage.  In order to call any of
these functions, you must #include the GRUMP.CH header file and compile
your source code with the "/dMOUSE" switch (as noted above).  The
functions are as follows:

ShowMouseCursor()        turns on mouse cursor at its current location

HideMouseCursor()        turns off mouse cursor

SetMousePos(<r>, <c>)    sets mouse cursor to specified row & column

GetMousePos()            returns an array containing { <row>, <col> }

SetMouseDoubleClick(<m>) allows you to set double-click sensitivity. By
                         default, this sensitivity level is 500
                         milliseconds, which is too slow for our taste.
                         If you find that your independent mouse clicks
                         are being mistaken for a double-click, we
                         suggest that you use this function and pass
                         something in the range of 200-250.

The MouseInit() and MouseExit() functions allow CA-Clipper's run-time
system to load and unload the mouse driver.  We strongly suggest that
you DO NOT CALL THESE DIRECTLY!  We have taken care of that for you by
calling them automatically at application startup and exit.

The GINKEYM() function mentioned in the printed manual has been
eliminated because it is unnecessary.

The GRUMP.CH header file contains the following mouse-related manifest
constants for your usage.

#define  K_LEFT_DOWN       433
#define  K_LEFT_DBLCLICK   434
#define  K_LEFT_UP         435
#define  K_RIGHT_DOWN      449
#define  K_RIGHT_DBLCLICK  450
#define  K_RIGHT_UP        451

The CA-Clipper MEMOEDIT() function is a tricky beast in that it is a
closed-off system.  However, because our mouse driver places events in
CA-Clipper's internal queue, you can check for mouse clicks as easily as
keypresses.  The following example demonstrates how to write a user
function that allows the right mouse click to exit the memo.  It also
demonstrates how to test for the left mouse click and determine the
position of the mouse cursor.  This information may be useful to you.

memoedit(memo, nTop, nLeft, nBottom, nRight, .t., 'KeyFunc')
...
function KeyFunc(stat, line, col)
local ret_val := ME_DEFAULT
local nKey := lastkey()
local nMouseRow, nMouseCol
if ( nKey == K_ESC .or. nKey == K_RIGHT_DOWN )
   waiton('MEMO NOT UPDATED')
   inkey(2)
   waitoff()
   ret_val := K_ESC
elseif nKey == K_LEFT_DOWN
   nMouseRow := lastrow()
   nMouseCol := lastcol()
endif
return ret_val

If you are not using a keytest function with MEMOEDIT(), the next
example shows how you can temporarily remap the right mouse click
to emulate ESC.

#define MOUSE
#include 'grump.ch'

setkey(K_RIGHT_DOWN, { || StuffKey(chr(K_ESC)) } )
memoedit(memo, nTop, nLeft, nBottom, nRight, .t.)
setkey(K_RIGHT_DOWN, NIL)

CAVEAT: We suggest that you always hide the mouse cursor prior to doing
any screen writes or screen captures. This will minimize the possibility
of "mouse turds".  When in doubt, feel free to insert a call to
HideMouseCursor().  The performance hit for this function is absolutely
negligible.

CAVEAT: The CA-Clipper debugger does not recognize mouse drivers. This
may occasionally lead to erratic behavior when debugging an application
with a live mouse driver.  If you should experience problems in the
debugger, such as lock-ups, we suggest that you consider debugging your
applications you do so with the non-mouseable libraries (GRUMP.LIB or
GRUMP52.LIB).  You can add the mouse support afterwards.  The use of the
MOUSE manifest constant means that you should not have to spend any time
changing your source code to switch back and forth between the two
versions.


If You Can't Stand Mice
-----------------------

We'll send you our trained feline, who will hunt down and eradicate any
pesky rodents that may be lurking in your home or office.  Seriously
though, if you do not need mouse support, you should follow these two
simple steps:

  1) Compile your source code without using the "/dMOUSE" compile
     switch.

  2) Link your applications using either GRUMP.LIB (for CA-Clipper 5.01)
     or GRUMP52.LIB (for CA-Clipper 5.2). These two library files are
     completely devoid of mouse logic, which means that your run-time
     performance will be maximized.


Other New Functions
-------------------

The first two functions listed below are written in C and Assembler by
Ted Means.  They mark a break from tradition for Grumpfish Library,
which has historically been written entirely in Clipper.  However, we
felt that these functions would be very useful to you, so we took the
liberty of stepping outside the abovementioned self-constraint.

1. BackPrint()

This function allows you to print in the background.  It is
tremendously useful in that the user can run a report and continue
to work while the report prints.  It makes use of CA-Clipper's
internal event loop, so it does not use interrupts and thus
minimizes the potential for conflicts.

Syntax

BackPrint( <cFile>, <cDevice>, <nBuffSize> )

<cFile> is the file to be printed.

<cDevice> is the device upon which to print.

<nBuffSize> is the number of bytes to send to the printer each time.
You should experiment with this setting based on whatever is occurring
in the foreground.  For example, if you are doing heavy-duty
calculations, you may wish to keep this number small (e.g., under 128).
On the other hand, if the foreground is a data entry screen which
typically involves a lot of idle time, try a higher number (e.g., 512 or
above).

All parameters are required.

Return Value

True (.T.) if both <cFile> and <cDevice> can be opened, or
False (.F.) if either cannot be opened or if another background
process is currently printing

Notes

You can check whether another background print process is still
active by calling the IsPrinting() function.  IsPrinting()
returns True (.T.) if another process is still active or False (.F.)
if the "coast is clear".  See the discussion below on the GFPQ() and
GFPQAddJob() functions.

Sample Usage

set printer to temp.txt
set device to print
// code to print report
set device to screen
set printer to
if ! IsPrinting()
   BackPrint('temp.txt', 'lpt1', 128)
endif

2. GFOnTick()

This function enables you to call a function every ## number of clock
ticks.  It makes use of CA-Clipper's internal event loop, so it does not
use interrupts and thus minimizes the potential for conflicts.

Syntax

GFOnTick( <cFunction> [, <nTicks> ] )

<cFunction> is the name of the function to be called.  Do not include
parentheses!  IMPORTANT: This function cannot be scoped as STATIC!

Optional parameter <nTicks> allows you to alter the frequency with which
<cFunction> gets called.  By default, <cFunction> will be called every
clock tick.  One second equals approximately 18.2 clock ticks.

Return Value

None

Notes

To stop a function from being called, you can either call GFOnTick()
with no parameters or with a null string as the name of the function.
Also, if the function that you wish to use is not already part of your
application (i.e., a library function such as GFCLOCK()), you must
declare it EXTERNAL (5.01) or REQUEST it (5.2).

Sample Usage

external gfclock           // use REQUEST for CA-Clipper 5.2
gfontick("gfclock", 18.2)  // call GFCLOCK() every second
//
gfontick()                 // de-activate


3. GFPQAddJob()

This function lets you add a file to the background printing
queue.  It must be used in conjunction with the GFPQ() function,
which is described below.

Syntax

GFPQAddJob( <cFile> [, <cPort> ] [, <nBuffSize> ] )

Required Parameter

<cFile> is the file to be printed.

Optional Parameters

<cPort> is the printer port to be used.  If not specified, this will
default to LPT1.

<nBuffSize> is the number of bytes to send to the printer each time. You
should experiment with this setting based on whatever is occurring in
the foreground.  For example, if you are doing heavy-duty calculations,
you may wish to keep this number small (e.g., under 128). On the other
hand, if the foreground is a data entry screen which typically involves
a lot of idle time, try a higher number (e.g., 512 or above).

Return Value

None

Sample Usage

function test
gfontick("gfpq", 90)   // check the print queue every 5 seconds
//ÄÄÄÄÄ add three files to print queue
GFPQAddJob("file1")
GFPQAddJob("file2")
GFPQAddJob("file3")
//
// main body of program
//
return nil

4. GFPQ()

The GFPQ() function should be called automatically by GFONTICK(). There
is no point in calling it directly!  It checks the print queue to see if
it can send another file to the printer.

Syntax

GFPQ()

Parameters/Return Value

None

Sample Usage

function test
gfontick("gfpq", 90)   // check the print queue every 5 seconds
//ÄÄÄÄÄ add three files to print queue
GFPQAddJob("file1")
GFPQAddJob("file2")
GFPQAddJob("file3")
//
// main body of program
//
return nil

5. GFPQCurrJob()

This function works in conjunction with GFPQ() and GFPQAddJob().
It returns the name of the file currently being printed.

Syntax

GFPQCurrJob()

Return Value

A character string containing the name of the file being printed,
or NIL if no file is currently being printed.

6. GFAlert()

The GFALERT() function is a straight replacement for CA-Clipper's
ALERT() function.  The only difference is that GFAlert() is mouse-aware,
whereas ALERT() is blissfully unaware of rodents.

Syntax

GFALERT( <cMessage> [, <aOptions> ] )

Required Parameter

<cMessage> is the message to be displayed.

Optional Parameter

<aOptions> contains the options to be displayed for selection.  If
not passed, the only option will be "OK".

Return Value

A numeric indicating which option was chosen, or zero if the user
presses ESC.

Sample Usage

n := gfalert("Catastrophe...", { "Abort", "Reboot", "Shutdown" }
do case
   case n == 1
      // abort
   case n == 2
      // reboot
   case n == 3
      // shutdown
endcase


Enhancements to Documented Functions
------------------------------------

1. GETDATE() -- Suppressing Display of Holidays (CA-Clipper 5.x only)

   If you do not want the GETDATE() function to show holidays, simply
   pass a logical False (.F.) as the fifth parameter.

2. HELPDEV() -- Importing existing .TXT files (CA-Clipper 5.x only)

   If you have prepared your help text in advance, you can import it
   into your Grumpfish help screens.  Simply press F10 during entry of
   the help text.  Note that your help text must be stored in a file
   with the extension .TXT.  It does not, however, have to be in the
   same directory as your .EXE file.

3. GRUMPBROW() -- screen painter mouse support (CA-Clipper 5.x only)

   If you are using the GRUMPBROW() screen painter, we encourage you to
   take advantage of the mouse support.  It makes the entire process far
   more intuitive.

   To move fields, simply click on them and start dragging.  To delete a
   field or box, double-click on it.  To move the screen cursor, click
   on any screen location. The screen cursor determines where boxes
   and/or new fields will be placed.

   You will find push buttons for box drawing, changing color, field
   insertion, erase mode, and code generation on the bottom row.
   When drawing or resizing a box, hold down the left mouse button
   and slide the mouse around until you are satisfied with its size.

   Erase mode enables you to remove a chunk of text at one fell swoop.
   Position the screen cursor at the top left corner of the region that
   you wish to erase.  Then press Alt-E or click on the "Erase" button.
   Hold down the left mouse button to highlight the screen region to be
   erased.  Note that this applies only to text -- boxes and fields must
   be deleted individually by double-clicking on them.

4. AMT2CHR() -- German-specific changes

   In German, rather than saying, for example, "eighty-eight", it is
   customary to say "eight and eighty".  To accommodate this type of
   output in AMT2CHR(), please make the following changes:

   Summer 87 version:

   line 59/60: remove leading spaces from ' million' and ' thousand'.

   Logic starting at line 100 (just after "case mnum > 19") should
   be replaced by:

        mstring = mstring + the_words[namount % 10] + 'und' + ;
                  the_words[int(namount / 10) + 18]

   Clipper 5.0 version:

   line 19: remove leading spaces from ' million' and ' thousand'.

   Logic starting at line 63 (just after "case namount > 19") should
   be replaced by:

         cstring += words[namount % 10] + 'und' + ;
                    words[int(namount / 10) + 18]


Free Bonus Error Logger
-----------------------

The CA-Clipper 5.x version of the Grumpfish Library source code includes
the file ERRORLOG.PRG, which contains a comprehensive CA-Clipper 5.x
run-time error-logger. Whenever a run-time error occurs, all relevant
information concerning said error will be written to a text file. This
information includes: the values of the PATH, COMSPEC, and CLIPPER
environment variables (and this is easily expandable); available memory
at the time of the error; last key pressed; the values of all instance
variables of the Error object; time and date of the error; and a screen
shot. Obviously this is far more reliable than trusting the end user to
give you information about the error.

ERRORLOG.PRG also includes a special function for handling printer-related 
errors. In order to best make use of this, you should consider wrapping 
any print logic in a BEGIN SEQUENCE ... END SEQUENCE construction.

***** end of file README.1ST
