1  Introduction

Menus in dBASE IV 

J. Mike Hedblom

In previous versions of the dBASE product the only  menu style readily
available to programmers was a text-prompt menu.  Now we have the
ability to create six additional menu styles: bar, popup,  pick-list,
pull-down, cascading, and dialog.


2  Article

The main difference between the new menu styles and the text-prompt 
menu is the way the selection is specified.  Text-prompt menus are 
created by displaying the choices on the screen and activating an 
input prompt.  The user makes a selection by typing in the choice. 
The  new menus allow the user to make the choice by navigating to the
prompts  with the arrow keys and selecting them with Return.

The new menus are implemented with special menu structuring commands. 
To  create one of the new menus, you must first specify the type of
menu,  the elements of the menu, and the action to take when a
selection  is made.  To use a defined menu, you must activate it with
an ACTIVATE  command.  Once a menu is active, it is deactivated by
pressing Esc  or by issuing a command to deactivate it after a
selection is made.

BAR MENUS

Bar menus are a set of prompts (pads) that are typically made up of 
one or two words.  The pads are usually arranged horizontally at the 
top of the screen with spaces separating them.  When a bar menu is 
active, the pads are accessed with the left-arrow and right-arrow 
keys.  A common bar menu might look like Figure 1, below:



This menu is created with the following code:

DEFINE MENU Common      DEFINE PAD Add   OF Common PROMPT "Add"     
DEFINE PAD Edit  OF Common PROMPT "Edit"      DEFINE PAD Print OF
Common PROMPT "Print records"     DEFINE  PAD Done  OF Common PROMPT
"Exit"      ON SELECTION PAD Add   OF Common APPEND      ON SELECTION
PAD Edit  OF Common BROWSE      ON SELECTION PAD Print OF Common DO
Prt_recs      ON SELECTION PAD Done  OF Common DEACTIVATE MENU

The first line allocates a slot in memory for a bar menu called
Common.  The  DEFINE PAD commands assign prompts to Common.  Each pad
is given a  name and a prompt.  Pad names should be similar to the
prompt action  to make your code easier to read.  (The DEFINE MENU
command must be  issued before the DEFINE PAD commands.)  The ON
SELECTION statements  determine what action to take when a selection
is made.  For every  pad of a bar menu there must be a matching
action.  To activate Common,  issue the command

ACTIVATE MENU Common

Common will remain active until Exit is selected or Esc  is pressed to
terminate it.  The action for PAD Done is to DEACTIVATE  MENU.  Since
no other ON SELECTION statement contains a DEACTIVATE  MENU command,
all other menu selections will re-display Common when  they are
finished.  Once the menu is terminated, the next command  following
the ACTIVATE statement will be issued.  When Print is chosen,  the
routine Prt_recs is executed.  When Prt_recs terminates, Common  is
reactivated. However, if Prt_recs contains a DEACTIVATE MENU command 
and no other menus have been subsequently activated, Common will be 
deactivated and the next command after the command ACTIVATE MENU
Common  will execute when Prt_recs terminates.

When a menu is activated, the first pad is highlighted by default. 
To  have the cursor start on another pad when the menu is activated,
include  a PAD statement in your ACTIVATE command. For example, to
have PAD  Print highlighted when Common is activated, use the command

ACTIVATE MENU Common PAD Print

Placement of bar menus

By default, bar menus are placed at the top of the screen on row 0, 
column 0.  If you have many pads in a menu on row 0, your menu may 
become obscured by the scoreboard area (also on row 0).  To avoid 
having your menus covered by scoreboard information, SET SCOREBOARD 
OFF.  To place the menu on a different row or column, use the AT
option  of the DEFINE PAD command.  For example, to put MENU Common on
row  1 starting in the 3rd column, change the first PAD definition
statement  to

DEFINE PAD Add OF Common PROMPT "Add" AT 1,3    

A space is automatically added to the beginning and end of each pad. 
Unless otherwise specified, all pads are placed on the same row with 
a space separating them.  This means that by default, the text of  the
pads are displayed with three spaces between them.  To display  Common
with only two spaces between each prompt, override the default 
positions by adding AT statements to each DEFINE PAD command to
explicitly  position the prompts:

DEFINE PAD Add   OF Common PROMPT "Add"  AT 1,3 DEFINE PAD Edit  OF
Common PROMPT "Edit" AT 1,8 DEFINE PAD Print OF Common PROMPT "Print
records" AT 1,14 DEFINE PAD Done  OF Common PROMPT "Exit" AT 1,29

Common will now look like Figure 2, below:

Message information

The MESSAGE option of DEFINE PAD allows you to display some
context-sensitive  information about the currently selected prompt. 
The message is displayed  centered at the bottom of the screen.  For
example,

DEFINE PAD Add OF Common PROMPT "Add" ;

  MESSAGE "Create new entries"

One message can be displayed for all menu pads by using the MESSAGE 
option of DEFINE MENU.

Managing bar menus

In complex applications, it's real easy to get lost when trying to 
follow the program flow through several routines.  When using menus 
to call routines that, in turn, may call other menus, program flow 
becomes very hard to trace.  Add to this the fact that Esc will 
deactivate the current menu (and possibly throw the program pointer 
back to the last active menu several routines above the current
routine),  managing large applications with menus can be difficult. 
There are  two things you can do to make application management
reasonable: keep  Esc from terminating menus inadvertently and
deactivate menus  not being used.  

To keep Esc from terminating menus inadvertently, use the following 
routine:

DO WHILE .T.
        *--- Display the menu.
        ACTIVATE MENU Common
        *--- Keep Esc from terminating this menu.
        IF LASTKEY()<> 27
                *--- The key used to terminate Common was not Esc.
                EXIT
        ENDIF ENDDO

This endless loop can only be terminated if the key pressed to exit 
the menu was not Esc.  If Esc is pressed, the menu is  deactivated,
but the EXIT is not executed and Common is reactivated.

When a menu remains active it is more overhead to maintain and
performance  can be slowed.  Also, as mentioned above, program flow
can be very  hard to maintain.  Unless absolutely necessary, menus
should be deactivated  when not needed.  (The disadvantage of
deactivating menus is that  normally when the menu is re-displayed
after the action completes,  the selected prompt remains highlighted. 
When activated fresh, the  first prompt is highlighted by default.) 
To make program flow easy  to maintain, deactivate menus when a
selection is made, and then,  proceed to the action by evaluating the
selection.

Two functions have been added to perform bar menu selection
evaluation,  PAD() and MENU().  PAD() returns the pad name selected
and, likewise,  MENU() returns the menu name.  By storing the values
of PAD() and  MENU() to memory variables, the selection can be saved
and evaluated  later.  To demonstrate this, the following routine,
Main, evaluates  the selection from the menu Common and branches
accordingly.  All  four of the ON SELECTION commands have been changed
to execute the  procedure Menu_out.  Menu_out stores the values of
PAD() and MENU()  to PUBLIC memory variables and deactivates Common.

PROCEDURE Main PUBLIC gc_pad, gc_menu DO WHILE .T.
        ACTIVATE MENU Common
        IF LASTKEY() = 27
                *--- Terminated with Esc, re-activate menu
                LOOP
        ENDIF
        *--- Evaluate selection
        DO CASE
                CASE gc_pad = "ADD"
                        *--- Add prompt
                        APPEND
                CASE gc_pad = "EDIT"
                        *--- Edit prompt
                        BROWSE
                CASE gc_pad = "PRINT"
                        *--- Print records prompt
                        DO Prt_recs
                CASE gc_pad = "DONE"
                        *--- Exit prompt
                        EXIT
        ENDCASE ENDDO RETURN


PROCEDURE Menu_out *--- Save current menu selection and deactivate the
menu gc_pad = PAD() gc_menu = MENU() DEACTIVATE MENU RETURN

Notice that the CASE statements evaluate the pad names as uppercase. 
This  is because PAD() (and all dBASE object name functions) returns
values  in uppercase, regardless of how they were specified in the
DEFINE  PAD statement.

POPUP MENUS

Popup menus are a set of prompts (bars) usually of one to four words 
arranged vertically and typically enclosed in a border. When the
popup  menu is active, you can navigate to the bars with the up-arrow 
and down-arrow keys.  A popup menu like Figure 3 is defined with  this
code:

DEFINE POPUP Print FROM 1,13 DEFINE BAR 1 OF Print PROMPT "Name
report" DEFINE BAR 2 OF Print PROMPT "Mailing labels" DEFINE BAR 3 OF
Print PROMPT REPLICATE(CHR(196),14) SKIP DEFINE BAR 4 OF Print PROMPT
"Eject page" ;
        SKIP FOR .NOT. PRINTSTATUS() ON SELECTION POPUP Print
DEACTIVATE POPUP     

The DEFINE POPUP statement is used to designate the name of the popup 
menu and its upper left coordinates.  Other options can additionally 
declare lower right coordinates, special types of popup menus, and  a
message to be displayed when the menu is activated.  By default, 
popup menus have a single line border. To change the border, issue  a
SET BORDER TO command prior to the DEFINE POPUP command.  If the 
optional lower right coordinates are not specified, default values 
are assigned that will accommodate the longest prompt and the maximum 
number of lines.  If coordinates are set such that not all the
prompts  will fit in the header, the additional prompts can be seen by
vertically  scrolling within the border window.  In addition to the
arrow keys,  popup prompts can be accessed by typing the first
character of the  prompt.

The prompts for popup menus are declared with the DEFINE BAR
commands.  Each  bar is identified with a number indicating its offset
from the top  of the menu.  (If you skip a row number when defining
the bars, that  row is left blank and is not accessible to the
cursor.)  To intentionally  keep a bar from being selected, include a
SKIP option in the definition  statement.  In bar 3 on the previous
page, a separation line is defined  by declaring the prompt as 14
horizontal line characters.  The line  cannot be selected because of
the imperative SKIP.

Bars can be conditionally skipped by including a SKIP FOR argument. 
When  a SKIP FOR argument is included, the condition is evaluated when
the  popup is activated and every time a navigation key is pressed. 
In  this way, the user can be kept from attempting to perform an
action  that is not valid at the time.  In bar 4 the Eject page
prompt  is not available when the print device is not ready.

Unlike bar menus where the select-action is defined for each prompt, 
the action for popups is the same for the entire menu. The
select-action  for popup menus is determined with the ON SELECTION
POPUP command.  In  the last example, the menu is deactivated when a
selection is made.

Popup menus are activated with the ACTIVATE POPUP command.  The first 
selectable prompt at the top of the menu is highlighted when the menu 
is activated.  There is no way to specify which bar to highlight when 
the menu is activated.

Message information

The MESSAGE option of DEFINE BAR allows you to display some
context-sensitive  information about the currently selected prompt. 
The message is displayed  centered at the bottom of the screen.  For
example,

DEFINE BAR 1 OF Print PROMPT "Name report" ;
        MESSAGE "Lists all clients by last name"

To display the same message for all prompts, use the MESSAGE option 
of DEFINE POPUP.  (DEFINE BAR messages override DEFINE POPUP
messages.)  For  example, to display a message showing the navigation
and selection  keys,

DEFINE POPUP Print FROM 2,14 MESSAGE ;
        'Position: '+CHR(25)+CHR(24)+;
        '  Select: '+CHR(17)+CHR(196)+CHR(217)

Managing popup menus

As a rule of thumb, if a menu does not need to be active or
displayed,  don't keep it active.  Occasionally you may want to
display a menu  without having it active.  To just display a popup
menu, use the SHOW  POPUP command.  SHOW POPUP displays the menu with
the initial selectable  bars showing, but with no bars highlighted. 
Sometimes you want to  display a menu leaving the last selected item
highlighted.  In this  case, SHOW POPUP will not work and the menu
must remain active.

To keep a menu active while a routine is processing, execute the
routine  with the ON SELECTION POPUP command.  The following uses the
Print  popup menu:

ON SELECTION POPUP Print DO Prt_choice ACTIVATE POPUP Print RETURN 

PROCEDURE Prt_choice DO CASE
        CASE BAR() = 1
                *--- Names report
                SET ORDER TO TAG Lastname
                REPORT FORM Names TO PRINT
        CASE BAR() = 2
                *--- Mailing labels
                SET ORDER TO TAG Zip_code
                LABEL FORM General TO PRINT
        CASE BAR() = 4
                *--- Eject page
                EJECT ENDCASE RETURN

In this example, Print will remain active (with the prompts
non-selectable)  throughout the execution of Prt_choice.  (To
deactivate Print, Esc  must be pressed when prompts are selectable.) 
The action taken in  Prt_choice is determined in the DO CASE
structure.  The CASE conditions  evaluate the bar number selected with
the BAR() function.  An alternate  method would have been to use the
PROMPT() function to return the  PROMPT of the bar selected; however,
BAR() is easier to work with  and there is less chance of making a
typing error.

Popup menus can be terminated with Esc, left-arrow or right-arrow. 
To  keep left-arrow and right-arrow from terminating popup menus, use 
the following routine:

DO WHILE .T.
        *--- Display the menu
        ACTIVATE POPUP Print
        *--- Keep left arrow and right arrow from terminating
        IF LASTKEY() <> 19 .AND. LASTKEY() <> 4
                EXIT
        ENDIF ENDDO

This endless loop can only be terminated if the key pressed to exit 
the menu was not left-arrow or right-arrow.  If either key is pressed 
the menu is deactivated but the EXIT is not executed and Print is 
reactivated.

PICK-LIST

A menu is a set of prompts that, when chosen, determine an action  to
take.  A pick-list has a single action, to return the selected  prompt
as a value.  A pick-list is a special kind of popup menu.  An 
advantage of pick-lists is the ability to navigate to prompts by
typing  the first characters in the prompt.  This is especially useful
in  long lists where arrow and page keys may take several keystrokes
to  get to the desired location.  For example, in a pick-list of last 
names, typing smi would probably navigate to Smith.  There are three 
types of pick-lists available: field values, file names, and current 
fields list.

In a pick-list of field values, the prompts are the values of the 
specified field and each bar is a different record.  The order the 
bars are displayed in is determined by the current database file
order.  (Note:  After the popup is activated, RECNO() is set to the
last record in  the current order.)  Field value pick-lists are
defined with the PROMPT  FIELD option of DEFINE POPUP.  The field name
argument must be a field  in the current field list when the menu is
activated.  The field name  may not be a calculated field or an
expression.  (To display multiple  fields in a pick-list, use a BROWSE
table in a window.)



To have a pick-list of states, the code might look like this:



USE States ORDER State DEFINE POPUP States FROM 4,70 TO 16,74 PROMPT
FIELD State ON SELECTION POPUP States DEACTIVATE POPUP ACTIVATE POPUP
States mstate = PROMPT() ? "The chosen state is ", mstate
    

Since the action of a pick-list is to return the value of the prompt, 
the PROMPT() function is almost always associated with pick-list
code.  In  most pick-lists, the BAR() value has little meaning because
it represents  the position of the prompt from the top of the list of
prompts.

A pick-list of file names is defined with the PROMPT FILES option  of
DEFINE POPUP.  When the PROMPT FILES option is used, all files  in the
current directory (or catalog if one is active) are displayed  in the
popup window.  To filter the choice of filenames to a specified  set,
use the LIKE option.  For example, to display all of the .fro 
(compiled .frm) files,<ESO>

DEFINE POPUP Reports FROM 5,5 PROMPT FILES LIKE *.fro ON SELECTION
POPUP Reports DEACTIVATE POPUP ACTIVATE POPUP Reports filename =
PROMPT() IF "" <> filename
        REPORT FORM (filename) TO PRINT ELSE
        ? "No report was selected." ENDIF

     

Notice the test for an empty selection.  If the pick-list is
terminated  with Esc instead of Return, PROMPT() will return a null 
value and BAR() will return a 0.  To keep Esc from terminating  the
pick-list, surround the ACTIVATE POPUP statement with a loop that 
tests for an Esc exit key (see "Managing bar menus").

When the FILES option is used, additional bars are automatically
added  to the top of the pick-list.  These bars allow the user to
select  another drive or directory.  You cannot suppress these
additional  items.  Do not use the FILES option if you want to keep
the user in  the current directory only.

A fields list pick-list is most commonly used to allow the user to 
specify the fields to use for some operation.  To indicate that the 
pick-list is the current field list, use the PROMPT STRUCTURE option. 
The  following example builds a user definable fields list for use in
a  later command:

DEFINE POPUP Flds FROM 3,30 PROMPT STRUCTURE MESSAGE ;
        "Select with Return, finish with Esc" ON SELECTION POPUP Flds
fld_lst = Build_lst() fld_lst = ""  ACTIVATE POPUP Flds *--- Activate
the field list. SET FIELDS TO &fld_lst. BROWSE SET FIELDS TO RETURN


FUNCTION Build_lst *--- Add the selected field to memory variable
fld_list. fld = PROMPT() IF .NOT. fld $ fld_lst
        *--- If the field is not already in the list, add it.
        IF "" = fld_lst
                fld_lst = fld
        ELSE
                fld_lst = fld_lst + "," + fld
        ENDIF ENDIF RETURN fld_lst


In this example, every time a selection is made from Flds, it is
added  to the field list stored in the memory variable fld_lst. When
the  field list is complete, the pick-list is terminated with Esc  and
the field list is activated with a SET FIELDS TO command.<ES>

Pick-list field entry

By using some of these special features, an entry field on a form  can
be defined as a pick-list.  For example, suppose you want to provide 
all of the inventory items in a pick-list when the user selects a 
field called Item.  Additionally, this field on the form looks
identical  to the other fields until you navigate to it.  This is
performed with  the following code:

DEFINE POPUP Getitem FROM 6,6 PROMPT FIELD Part_name ON SELECTION
POPUP Getitem DEACTIVATE POPUP USE Parts ORDER Part_name USE Orders IN
SELECT()

SELECT Orders

APPEND BLANK @ 5, 3 SAY "Customer" GET Customer @ 7, 3 SAY "Item" @ 7,
8 GET Item WHEN Got_item() READ RETURN


FUNCTION Got_item *--- Display a part names pick-list and save the
choice SELECT Parts ACTIVATE POPUP Getitem *--- PROMPT() is the
Part_name chosen mitem = PROMPT() SELECT Orders REPLACE Item WITH
mitem @ 7,8 SAY Item RETURN .F.


When the user navigates to the Item field, Getitem is activated and 
provides the pick-list.  After the selection is made, Getitem is
deactivated,  the selection is saved, the display is updated, and the
cursor moves  to the next entry field.  This code works because the
WHEN option  of @...GET is a preprocessor; the GET condition must be
met before  the user is allowed to edit the entry field.  When the
user navigates  to Item, Got_item() is executed to determine if the
user will be allowed  to edit the field.  Got_item() activates the
pick-list of the Part_name  field, REPLACEs the chosen item into the
Orders database file, displays  the chosen value on the screen, and
returns a logical false.  By returning  false, the WHEN option is not
satisfied, thereby keeping the user  from editing the selection made.

PULL-DOWN MENUS

Pull-down menus are popup menus that are linked to bar menu pads. 
When you navigate to the menu pad, the associated popup menu is
automatically  activated.  Usually, the popup menu is directly below
the menu pad  giving them the appearance of being one item.  Pull-down
menus are  used to logically group menu selections.  (The menus in the
Control  Center are pull-down menus.)  Figure 5 is an example of a
pull-down  menu.

Definition and use

Pull-down menus are declared by defining a bar menu and a popup menu 
for each pull-down.  This example of the Print pull-down in Figure  5
uses the code examples from the bar menu and popup menu discussions. 
However,  instead of issuing ON SELECTION PAD commands for each bar
menu item,  an ON PAD command is used to activate the pull-down.  The
Print pull-down  is linked to the Print pad with the command:

ON PAD Print OF Common ACTIVATE POPUP Print

The ON PAD command defines an action to take when the menu pad is 
selected.  In this case, the Print popup is activated.

Managing pull-down menus

Pull-down menus are activated when the MENU is activated.  Pressing 
Esc on any pull-down will deactivate the entire pull-down menu 
structure.  To keep Esc from deactivating the structure, use  the
routine in the "Managing bar menus" section earlier in this article.

Navigation within the pull-down is achieved with up-arrow and
down-arrow.  Navigation  between pull-downs is accomplished with
left-arrow and right-arrow.  (This  is why left-arrow and right-arrow
deactivate popups.)

There are two methods to determine the action to take when a
pull-down  menu item is selected.  One method is to branch to an
evaluation routine  for each pull-down.  In this case, the code would
be identical to  the code for a popup menu (see "Managing popup menus"
for more information).  The  other method is to have one large
evaluation routine.  By having one  routine handle the evaluation for
all pull-down items, your program  will be easier to read and
maintain.  To have one evaluation routine,  all ON SELECTION POPUP
statements must include the same action.  

Whether you deactivate the menu and then evaluate or branch to an 
evaluation routine while leaving the menu active, the evaluation
logic  is the same.  In the evaluation routine, your program must
first determine  which pull-down was selected before the action can be
evaluated.  This  can be accomplished with either the PAD() or POPUP()
functions.  POPUP()  returns the name of the popup menu.

The code to evaluate the pull-down menu structure in Figure 5 might 
look like this:

DO CASE
        CASE PAD() = "EXIT"
                *--- Exit pad was selected.
                *    (Exit does not have an associated pull-down.)
                QUIT

        CASE POPUP() = "PRINT"
                *--- Print records pull-down menu
                DO CASE
                        CASE BAR() = 1
                                *--- Names report
                                SET ORDER TO TAG Lastname
                                REPORT FORM Names TO PRINT


                        CASE BAR() = 2
                                *--- Mailing labels
                                SET ORDER TO TAG Zip_code
                                LABEL FORM General TO PRINT
                        CASE BAR() = 4
                                *--- Eject page
                                EJECT
                ENDCASE
        CASE PAD() = "ADD"
                *--- Add menu
                DO Add_prg
        CASE PAD() = "EDIT"
                *--- Edit menu
                DO Edit_prg ENDCASE


By nesting DO CASE structures, your code will be easy to read and 
debug.

CASCADING MENUS

A cascading menu (also known as hierarchical or fan-out) is a popup 
menu displayed on top of, or next to, a pull-down or popup menu.  The 
information on a cascading menu is generally a subgroup of the parent 
menu item.  Figure 6 is an example.

In this variation of the Print popup menu, when Mailing labels  is
selected, a cascading menu is displayed to determine the sort order 
for  the labels.  Notice the  character next to the Mailing labels 
prompt [CHR(16)].  This is used to indicate that this item has a
cascading  menu attached to it.  (Instead of using a CHR(16) you may
wish to  use some other symbol, like CHR(62), the greater-than symbol
[">"].)  Having  additional characters in front of the bar label does
not affect the  ability to select bars by the prompt initial unless
the character  is one of the alpha-numeric characters.  In other
words, pressing  M would still select the Mailing labels prompt.

The Sort_by cascading menu was created with the following
code:          

DEFINE POPUP Print FROM 2,14 TO 7,35 DEFINE BAR 1 OF Print PROMPT "  
Names report" DEFINE BAR 2 OF Print PROMPT " "+CHR(16)+" Mailing
labels" DEFINE BAR 3 OF Print PROMPT REPLICATE(CHR(196),20) SKIP
DEFINE BAR 4 OF Print PROMPT "   Eject page" ;
        SKIP FOR .NOT. PRINTSTATUS() ON SELECTION POPUP Print DO
Prt_eval

DEFINE POPUP Sort_by FROM 3,33 DEFINE BAR 1 OF Sort_by PROMPT "Sort
by..." SKIP DEFINE BAR 2 OF Sort_by PROMPT "Company"  DEFINE BAR 3 OF
Sort_by PROMPT "Lastname" DEFINE BAR 4 OF Sort_by PROMPT "Zip code" ON
SELECTION POPUP Sort_by DO Sort_eval


PROCEDURE Prt_eval *--- Evaluate the Print popup menu. DO CASE
        CASE BAR() = 1
                *--- Names report     
        CASE BAR() = 2
                *--- Mailing label          
                ACTIVATE POPUP Sort_by     
        CASE BAR() = 4
                *--- Eject page
                EJECT ENDCASE RETURN


PROCEDURE Sort_eval *--- Evaluate the Sort_by cascading menu      DO
CASE
        CASE BAR() = 2
                *--- Company
                SET ORDER TO TAG Company
        CASE BAR() = 3 
                *--- Lastname
                SET ORDER TO TAG Lastname
        CASE BAR() = 4
                *--- Zip code 
                SET ORDER TO TAG Zipcode ENDCASE *--- Print the labels
LABEL FORM Mail_lbl TO PRINT *--- Deactivate the Sort_by cascading
menu      DEACTIVATE POPUP SET ORDER TO RETURN

DIALOG MENUS

Dialog menus are a mixture of textual information and a prompt
(sometimes  called a button) within a window.  (dBASE IV error
messages and  prompts usually appear in dialog menus.)  A dialog menu
may look like  the one in Figure 7.

When this menu is displayed, the user has the choice of selecting  Yes
or No.  The Yes/No prompt is achieved with a bar menu.  The  border is
determined by a window.  By using the windowing commands,  all screen
activity can be confined to the area within the border  displayed. 
The windowing commands allow you to cover the text already  on the
screen without destroying it.  If the user chooses the No  button, the
window is deactivated and the text that was under the  window remains
undisturbed.

To use a dialog menu, you must first define the window and the prompt 
menu.  The Quit_ok menu above is defined with the following code:

DEFINE WINDOW Quit_ok FROM 8, 24 TO 14, 56 DOUBLE DEFINE MENU YesNo
DEFINE PAD Yes OF YesNo PROMPT "Yes" AT 3, 7 DEFINE PAD No  OF YesNO
PROMPT "No"  AT 3, 15 ON SELECTION PAD Yes OF YesNo DEACTIVATE MENU ON
SELECTION PAD No  OF YesNo DEACTIVATE MENU


*--- Display and activate the Quit_ok dialog menu ACTIVATE  WINDOW
Quit_ok @ 0,2 SAY "Do you really want to leave" @ 1,2 SAY "the Whoopie
application?" DO WHILE .T.
        ACTIVATE MENU YesNo
        *--- Keep Esc from terminating this menu
        IF LASTKEY() <> 27
                EXIT
        ENDIF ENDDO DEACTIVATE WINDOW Quit_ok


*--- Determine the action IF PAD() = "YES"
        QUIT ENDIF RETURN


Conclusion

In this article we've demonstrated using the menu functions in dBASE 
IV to create six different types of menus.  Menus will make it easier 
for the  people using your program to get around.  They can also add 
a lot of flash to your program.
                                                                                   