
This article is reprinted from the January 1991 edition of
TechNotes/dBASE IV.  Due to the limitations of this media, certain
graphic elements such as screen shots, illustrations and some tables
have been omitted.  Where possible, reference to such items has been
deleted.  As a result, continuity may be compromised.  

TechNotes is a monthly publication from the Ashton-Tate Software
Support Center.  For subscription information, call 800-545-9364.

Look and Feel Appeal

 The UDFs this month focus on what you can do in your program to
enhance the "look and feel" of your applications.   The first three
are from Dan Madoni.  IsOn() was created by Roland Bouchereau.  An
additional UDF, Nbrs() can be found in the Q&A section. 

ShdoBox()

Syntax:

ShdoBox(<row1>,<col1>,<row2>,<col2>,<border>,<color>,<shadow>)

row1/col1               = Upper left coordinates
row2/col2               = Lower right coordinates
border                          = "SINGLE", "DOUBLE", "NONE"
color                           = Color of box using dBASE IV color codes
shadow                          = "SHADOW", "NONE"

This UDF draws an expanding box on the screen with an optional
shadowing effect.  Although it requires a higher than average number
of parameters passed (seven, to be exact), ShdoBox() can practically
take the place of the @..TO command.  The usage of @..TO, however, is
a good way to describe the usage of ShdoBox() as shown in the
comparison below.  Two lines of dBASE code are required to draw a box
and then fill it with red box with a bright white double line
surrounding the border.

@ 5,5 TO 10,75 DOUBLE COLOR w+/r
@ 5,5 FILL TO 10,75 COLOR w+/r

Using the ShdoBox() function below will draw an expanding red box with
a bright white double line surrounding the border plus a shadow to
give it a more 3D effect.

?? ShdoBox(5,5,10,75,"DOUBLE","W+/R","SHADOW")

FUNCTION ShdoBox
                PARAMETERS
BFrom1,BFrom2,BTo1,BTo2,BrdrType,BlowColor,BlowShd              
                BlenOfBox = ABS((BTo2 - BFrom2) / 2)
                BDrawHere = BFrom2 + BlenOfBox
                BlowCSav = SET("Attribute")
                BCntr1 = 0      
                SET COLOR TO &BlowColor
                DO WHILE BCntr1 < (BlenOfBox - 1)
                        BCntr1 = BCntr1 + 1
                        IF UPPER(BlowShd) = "SHADOW"
                                @ (BFrom1 + 1),((BDrawHere + 1) - BCntr1) FILL
TO;
                                        (BTo1 + 1),((BDrawHere + 1) + BCntr1)
COLOR W/N
                        ENDIF
                        @ BFrom1,(BDrawHere - BCntr1) CLEAR TO BTo1,;
                                (BDrawHere + BCntr1)    
                        DO CASE 
                                CASE UPPER(BrdrType) = "DOUBLE"
                                        @ BFrom1,(BDrawHere - BCntr1) TO
BTo1,;
                                                (BDrawHere + BCntr1) DOUBLE
                                CASE UPPER(BrdrType) = "SINGLE"
                                        @ BFrom1,(BDrawHere - BCntr1) TO
BTo1,;
                                                (BDrawHere + BCntr1)
                        ENDCASE
                ENDDO   
                IF UPPER(BlowShd) = "SHADOW"
                        @ (BFrom1 + 1),(BFrom2 + 1) FILL TO (BTo1 + 1),;
                                (BTo2 + 1) COLOR W/N
                ENDIF
                @ BFrom1,BFrom2 CLEAR TO BTo1,BTo2      
                DO CASE
                        CASE UPPER(BrdrType) = "DOUBLE"
                                @ BFrom1,BFrom2 TO BTo1,BTo2 DOUBLE
                        CASE UPPER(BrdrType) = "SINGLE"
                                @ BFrom1,BFrom2 TO BTo1,BTo2
                ENDCASE
                SET COLOR TO &BlowCSav  
RETURN ""


Msg()

Syntax:

Msg(<ExpC>)

This function is what I typically will use in place of a WAIT command
in dBASE IV.  Msg() draws an expanding shadowed box on the
lower-center portion of the screen, displays the specified message,
and returns the ASCII value of the key pressed in response to the
message.  I have chosen red for the interior color of the box but that
can be easily modified by changing the /r parameters in the ??
ShdoBox() statement and corresponding @.SAY statement.

Speaking of ShdoBox(), you'll notice that it's incorporated into this
function, giving you an idea of one method of application.  Consider
the following examples using the traditional WAIT and then the Msg()
function:


WAIT "Do you wish to continue? Y/N" TO response
IF UPPER(response) <> "Y"
   RETURN
ENDIF
IF UPPER(CHR(Msg("Do you wish to continue? Y/N"))) <> "Y"
   RETURN
ENDIF

Msg() needs ShdoBox() in order to do it's job.  Make sure both UDFs
exist in your library or in your directory before trying to use
Msg().  

FUNCTION Msg
                PARAMETERS ShowMsg
                CLEAR TYPEAHEAD
                SAVE SCREEN TO MsgScr
                ?? ShdoBox(15,10,17,70,"DOUBLE","gr+/r","SHADOW")
                @ 16,12 SAY ShowMsg COLOR w+/r
                ?? CHR(7)
                MsgWait = INKEY(0)
                RESTORE SCREEN FROM MsgScr
                RELEASE SCREEN MsgScr
RETURN MsgWait


Currency()

Syntax:

Currency(ExpN)

Usage:

@ 5,5 SAY Currency(1387.65)

I recently wrote a checkbook program for a project I was working on. 
As part of the program, I wanted the amount of the check that the user
would enter to pop up on the screen spelled out.  In other words, if I
entered 1387.65 in the amount area of the check on the screen, I
wanted it to appear on the line below the number as:

One Thousand Eighty Seven and 65/100

That's exactly what this function does  you give it a number, and it
gives you the number back spelled out.

This function currently accepts a number no greater than 9999.99. 
With a little modification, it could be suitable for Wall Street types
who deal in figures a little higher than the average bougeoise
types.  


FUNCTION Currency

                PARAMETERS InCurr
                RetCurr = ""
                InCurr = RTRIM(LTRIM(STR(InCurr * 100)))
                Ones = "One  Two  ThreeFour Five Six  SevenEightNine      "
                Tens =  "Ten    Twenty Thirty Forty  Fifty  Sixty 
SeventyEighty Ninety"
                LastPart = " and " + RIGHT(InCurr,2) + "/100"
                InCurr = LEFT(InCurr,(LEN(InCurr) - 2))

                IF LEN(InCurr) > 4
                RETURN  ""      && prevents numbers greater than 9999.99
                ENDIF           && remove or modify when increasing capacity

                STORE "" to CTemp, CTemp2, CTemp3, CTemp4
                IF LEN(InCurr) > 0
                        CTemp = RTRIM(SUBSTR(Ones,VAL(Right(InCurr, 1)) * 5 -
4, 5))
                ENDIF
                IF LEN(InCurr) > 1
                        CTemp2 = VAL(SUBSTR(InCurr, LEN(InCurr) - 1, 1))
                        CTemp2 = IIF(CTemp2 > 1 .AND. CTemp2 < 10, ;
                        RTRIM(SUBSTR(Tens, CTemp2 * 7 - 6, 7)),"")
                ENDIF
                IF LEN(InCurr) > 2
                        CTemp3 = RTRIM(SUBSTR(Ones, ;
                                VAL(SUBSTR(InCurr, LEN(InCurr) - 2, 1))* 5 -
4, 5)) + " Hundred"
                ENDIF
                IF LEN(InCurr) > 3
                        CTemp4 = RTRIM(SUBSTR(Ones,;
                                VAL(SUBSTR(InCurr,LEN(InCurr) - 3,1))* 5 -
4,5)) + " Thousand" 
                ENDIF

RETURN CTemp4 + " " + CTemp3 + " " + CTemp2 + " " + CTemp + LastPart


IsOn()

Syntax:

ISON(ExpC)

ExpC is a character expression resulting in the name (or the first
four characters of) a setting with an ON/OFF return status.

The SET() function in dBASE IV has changed the way that dBASE programs
are written.  SET() gives you a means of determining many
environmental conditions, particularly those indicating ON/OFF
statuses.  Being able to determine current environment settings allows
the programmer to track these conditions at program entry and to
restore them prior to program exit.  The following code illustrates
this technique. 

statuswas = SET("STATUS")
confirmwas = SET("CONFIRM")
.
* Processing.
.
SET CONFIRM &confirmwas
SET STATUS &statuswas

This works very well and as expected.  But sometimes it may not be to
your advantage to use macros.  Why?  Because,  macro substitution
slows down program execution (say that three times fast).  When dBASE
IV encounters a macro operator, it first locates the memory variable
indicated after the ampersand (&).  Then dBASE IV recompiles the whole
command internally and then finally executes the command.  The whole
process doesn't take long, but much longer than the immediate
execution of a command.  Consequently, I've implemented a UDF to
attach a logical value to the ON/OFF settings in dBASE IV.  The UDF is
called IsOn() and it requires one character argument that is the text
expression of "STATUS" or "CONFIRM" for example.  It returns a logical
true (.T.) for an "ON" setting, false (.F.) otherwise. The code for
IsOn() follows. 

FUNCTION IsOn
                PARAMETER flag_
                IF TYPE("flag_") = "C"
                        IF TYPE("SET(flag_)") = "C"
                                RETURN SET(flag_) = "ON"
                        ENDIF
                ENDIF
RETURN .F.

Now the previous code example may be written like this:

statuswas = IsOn("STATUS")
confirmwas = IsOn("CONFIRM")
.
*Do some processing here.
.
IF statuswas
                SET CONFIRM ON
ELSE
                SET CONFIRM OFF
ENDIF
IF confirmwas
                SET STATUS ON
ELSE
                SET STATUS OFF
ENDIF

Although it's longer, this code runs faster and now I have a good
alternative and if speed becomes a critical factor, this method just
may be preferable. 


