In addition to speeding up the prototyping of interfaces, GUITOOL provides an additional level of structure to the application code. This not only cosmetic: as I've said in the past, the better your structure, the easier the debugging.
The real beauty of the GUITOOL approach is that you can begin with a basic, operational framework and add functionality as you go along.
POPUP Cover
MENUI Open..., SETCOV
MENUI Save, SAVE
POPEND
POPUP Edit
MENUI Feature..., SETFEAT
MENUI Add, ADD
MENUI Delete, DELETE
MENUI Move, MOVE
MENUI Copy, COPY
SEP
POPUP Arc
MENUI Split, SPLIT
MENUI Unsplit, UNSPLIT
MENUI Reshape, RESHAPE
MENUI Spline, SPLINE
MENUI Flip, FLIP
POPEND
POPUP Vertex
MENUI Draw, VDRAW
MENUI Move, VMOVE
MENUI Add, VADD
MENUI Delete, VDEL
POPEND
POPUP Anno
MENUI Adjust, REPOS
MENUI Text..., ANNOTEXT
MENUI Set Arrow, SETARROW
MENUI Del Arrow, DELARROW
POPEND
POPEND
POPUP Select
MENUI One, SELONE
MENUI Many, SELMANY
MENUI Box, SELBOX
MENUI Dangle, SELDANGLE
MENUI All, SELALL
MENUI None, SELNONE
POPEND
POPUP Tools
MENUI Edit, EDITTOOL
MENUI Select, SELTOOL
MENUI Command, COMTOOL
SEP
MENUI Pin Mode, PIN
POPEND
MENUI Quit, QUIT
The following code in ETOOL.GUI will allow us to examine all of the menu
widgets and yet exit when "Quit" is clicked:
*AUTHOR My Name *ROUTINE etool e_main.mnu 0 *OPEN e_main.mnu *PICK QUIT *CLOSEThe *AUTHOR directive allows GUITOOL to place the author's name in the header remarks for each routine. The *ROUTINE directive begins each routine in the application. Immediately after the *ROUTINE directive, any nonmodal menus or dialog boxes which will be present during the routine are declared (the "0" indicates a menu—any other numeral indicates the dialog box number to be assigned); this allows GUITOOL to create code to handle all of the possible return widgets which will be encountered. The list is terminated by a blank line.
The *OPEN directive tells GUITOOL to open and read the menu. By default, GUITOOL creates a read loop which echoes a message for each return widget picked. The *PICK directive allows you to assign a block of code to a particular widget or set of widgets. In the above example, the *CLOSE directive, which closes the menu and exits the loop, is assigned to widget QUIT.
Now let's run GUITOOL at the DOS prompt as follows:[2]
guitool etool etoolThe output routine file, ETOOL.R, has some notable features intended to make life easier for the application developer.
&ROUTINE ETOOL ... &include ETOOL.INC &define winrtn 1 &var Holds WIN command return codes. &define winfile -20 &var WIN command communication file. &REM Set up winfile name &value [winfile] wksp &sv [winfile] [winfile]t$ETOOLEach routine automatically begins with an &include directive (how many of us out there keep forgetting to add one to a new routine?). If the include file, named after the output routine file, is not present, a blank one is automatically created. Two dedicated aliases are also set up: [winrtn] and [winfile]; these provide the programmer with a simple, consistent way to deal with WIN return values and command files.
&REM *OPEN E_MAIN.MNU
&r E_MAIN
GUITOOL builds a routine for each menu or dialog box in order to create
it; thus it is important that no menu or dialog file has the same name
as another routine in the application. The advantages of this approach
are two-fold: 1) menus and dialog boxes are automatically embedded in
the final code, and 2) menus and dialog boxes may readily be edited
during the development phase without repeatedly stripping and replacing
&write directives.
&REM Message loop
&while &do
win menu r [winfile]
&if &fn [winfile] &do
& del [winfile]
&end
&LABEL EDITBOX2
&if &eq [winrtn] -1 &do
&REM Window closed, get out of loop.
&break
&elseif &eq [winrtn] QUIT &do
&REM Menu Choice QUIT
&REM *CLOSE
win menu d
&break
...
&elseif &eq [winrtn] SPLIT &do
&REM Menu Choice SPLIT
&type "Menu SPLIT picked."
...
&end
&end
&REM End of message loop
The WIN MENU R loop checks for the [winfile] command file and deletes it
afterwards if it exists. Code is created for each possible return
value: the close widget value (-1) exits the loop, and values not
covered by *PICK directives are simply &typed out. Thus if you
were to pick "Edit|Arc|Split":

The message:
Menu SPLIT picked.would be typed.
E_SETEC.DLG:
BEGIN 0 10.00 5.00 4.50 24.00 v Edit Coverage EBOX 101 0.50 1.00 1.50 20.00 v PBUT -102 0.50 21.50 1.50 1.50 v » PBUT -103 2.50 1.00 1.50 8.00 v OK PBUT -104 2.50 9.00 1.50 8.00 v CancelE_SETEF.DLG:
BEGIN 0 5.00 5.00 9.00 16.00 v Edit Feature GBOX 0 0.00 1.00 6.50 14.00 v RBUT 101 1.00 2.00 1.00 8.00 v ARC RBUT 102 2.00 2.00 1.00 8.00 v LABEL RBUT 103 3.00 2.00 1.00 8.00 v NODE RBUT 104 4.00 2.00 1.00 8.00 v TIC RBUT 105 5.00 2.00 1.00 8.00 v ANNO PBUT -106 7.00 1.00 1.50 7.00 v OK PBUT -107 7.00 8.00 1.50 7.00 v Cancel ENDE_SEL.DLG:
BEGIN 0 5.00 22.00 4.50 16.00 v Select PBUT -131 0.00 0.00 1.50 8.00 v One PBUT -132 0.00 8.00 1.50 8.00 v Many PBUT -133 1.50 0.00 1.50 8.00 v Box PBUT -134 1.50 8.00 1.50 8.00 v Dangle PBUT -135 3.00 0.00 1.50 8.00 v All PBUT -136 3.00 8.00 1.50 8.00 v NoneE_COM.DLG:
BEGIN 0 17.50 5.00 4.50 42.00 v Command Tool EBOX 141 0.50 1.00 1.50 40.00 v PBUT -142 2.50 1.00 1.50 8.00 v ApplyBecause the edit feature toolboxes depend on the edit feature, I'll need to write a bit of code to support them. ETOOL.GUI is now as follows:
*AUTHOR My Name
*ROUTINE etool
e_main.mnu 0
e_edit.dlg 15
e_arc.dlg 14
e_anno.dlg 14
e_vrtx.dlg 13
e_sel.dlg 12
e_com.dlg 11
&define editcov -11 &var
&define editfeat -12 &var
&define pin -13 &var
&define temp -19 &var
*REM **** set display and turn pin mode off
&r disp
WIN DB U
&sv [pin] U
DRAWE ARC LABEL NODE ERRORS TIC IDS
*OPEN e_main.mnu
*REM **** the following statement is executed
*REM **** before the loop begins
&type "Ok."
*PICK SETCOV SETFEAT 106
&sv [temp] .TRUE.
&if &eq [winrtn] SETCOV &do
*OPEN seteditc H
&rv [editcov]
&if &eq "x[editcov]" "x" &do
&sv [temp] .FALSE.
&else
EDITC [editcov]
DRAW
&end
&end
&if &eq [temp] .TRUE. &do
*REM **** Set edit feature
*OPEN seteditf H [editfeat]
&rv [temp]
&if &eq [temp] CANCEL &do
&sv [temp] .FALSE.
&else
&sv [editfeat] [temp]
&sv [temp] .TRUE.
&end
&end
&if &eq [temp] .TRUE. &do
*REM **** Set appropriate toolbox(es)
&if &ne [editfeat] NONE &do
*OPEN e_edit.dlg N
*OPEN e_sel.dlg N
&openw [winfile]
&r setefw
&closew
&end
&if &eq [editfeat] ARC &do
*OPEN e_arc.dlg N
*OPEN e_vrtx.dlg N
&elseif &eq [editfeat] ANNOTATION &do
*OPEN e_anno.dlg N
*CLOSE e_vrtx.dlg
&else
*CLOSE e_arc.dlg
*CLOSE e_vrtx.dlg
&end
&end
*PICK 105
&if &eq [editfeat] ARC &do
*OPEN e_arc.dlg N
&else
*OPEN e_anno.dlg N
&end
*PICK 116
*OPEN e_vrtx.dlg N
*PICK 142
%141
*PICK EDITTOOL
&openw [winfile]
&r setefw
&closew
*OPEN e_edit.dlg N
*PICK SELTOOL
*OPEN e_sel.dlg N
*PICK COMTOOL
*OPEN e_com.dlg N
*PICK PIN
&openw [winfile]
&if &eq [pin] U &do
WIN DB P
*W C PIN
&else
WIN DB U
*W U PIN
&end
&closew
*PICK QUIT
*CLOSE
*ENDPICK ALL
*REM &openw [winfile] A
*REM &r setmenu
*REM &closew
&type "Ok."
*ENDPICK
&r Q
Note that I've assigned the same dialog box number to E_ARC.DLG and
E_ANNO.DLG; that is permissible only because they are mutually
exclusive. When pin mode is active (or the box hasn't been moved), the
effect will be that of a single dialog box which changes its
structure.In routines ETOOL and SETEDITC, I introduce the remaining GUITOOL directives. "*OPEN dialog_file N" opens a nonmodal dialog file that has been declared in the *ROUTINE list. "*OPEN routine H/I" opens a routine modally, creating a new dialog box group using WIN DB BH/BI (discussed in the last article). *W is a shortcut for &write that automatically adds quotes. *ENDPICK allows the developer to insert code to be executed after the read loop is terminated. *ENDPICK ALL allows the insertion of code to be executed after each pick in the read loop (e.g. to gray or enable menu widgets).
DISP and Q are external routines that set the graphic display (see ARC Utilities). Routine SETEDITC, which invokes a dialog box to set the edit cover, is simplicity itself:
*ROUTINE seteditc e_setec.dlg 1 *REM **** Get edit cover *OPEN e_setec.dlg *PICK 102 *FILE 101 C * 'Enter coverage' *PICK 103 &sv -1 %101 *CLOSE *PICK 104 *CLOSE *ENDPICK &return %-1

Note the use of the *FILE directive, which invokes the file picker and assigns the return value to the specified widget. Thus when the ">>" button is clicked and a coverage picked, that value is returned to the dialog box.
Routine SETEDITF sets the edit feature:
*ROUTINE seteditf
e_setef.dlg 1
*REM **** Get edit feature
&openw [winfile]
&if &eq %-1 LABEL &do
*W C 102
&elseif &eq %-1 NODE &do
*W C 103
&elseif &eq %-1 TIC &do
*W C 104
&elseif &eq %-1 ANNOTATION &do
*W C 105
&else
*W C 101
&end
&closew
*OPEN e_setef.dlg
*PICK 50 106
&if &eq %101 1 &do
EDITF ARC
&elseif &eq %102 1 &do
EDITF LABEL
&elseif &eq %103 1 &do
EDITF NODE
&elseif &eq %104 1 &do
EDITF TIC
&else
EDITF ANNOTATION
&end
*CLOSE
*PICK 49 107
*CLOSE
*ENDPICK
SHOW EDITFEATURE -1
&return %-1

One the edit feature is picked, the appropriate toolboxes are opened:

Routine SETEFW sets the feature button for E_EDIT.DLG:
*ROUTINE setefw *REM **** Set editf button value &define editfeat -1 &var SHOW EDITFEATURE [editfeat] &if &eq [editfeat] ARC &do &sv -2 ARC... &sv -3 E &elseif &eq [editfeat] ANNOTATION &do &sv -2 ANNO... &sv -3 E &else &sv -2 [editfeat] &sv -3 G &end *W S 105 %-2 *W %-3 105At this point, the only widgets which are enabled are those which set the edit cover, set the edit feature, invoke dialog boxes, toggle pin mode, execute a command in the command tool, or exit the application. The command tool is invoked by picking "Tools|Command":

Assuming that the GUI is set up to our satisfaction, we can start plugging in more code. Most of the picks are easy:
*PICK SPLIT 111 SPLITbut more advanced functionality will require some coding. Nonetheless, GUITOOL simplifies just about any programming centered around dialog boxes.
Although GUITOOL is a powerful application development system, it does have its limitations. For example, you cannot use a separate routine to add nonmodal dialog boxes to the current list: the routine will have its own read loop that will not terminate until the boxes you add are closed.
Also, GUITOOL is geared more towards static interfaces; if you have a menu or dialog box that cannot be represented by a static file, you must do one of two things: 1) embed the necessary code in a standard routine, or 2) redesign it.
In the next article, I'll show an example of redesigning a dialog box to make it more GUITOOL-friendly.
[2]GUITOOL.EXE should be copied to a directory somewhere in your path, such as the %ARC%\CMD directory:
copy %arc%\examples\guitool.exe %arc%\cmd
Return to ArcTips page