
Annotation parameters are contained in variables 41-46. Note the use of FORTRAN formatting to preserve constant box width. Also note the use of "%%" so that the variable references for the edit boxes are written literally to the menu file. When invoked with ARCEDIT defaults, the menu looks like this (converted to grayscale):

The dialog box contains five buttons and three edit boxes[2]; the values within the drop-list boxes are disabled by preceding them with acute grave ("`") characters. To activate a drop-list the user picks one of the down-arrow buttons, which return either "V1", "V2", or "V3" (the numeric identifiers are rendered invisible by a color escape sequence with identical foreground and background colors). With all that in mind, let's take a look at the parent routine:
&routine setanno
SHOW ANNOTYPE 41
SHOW ANNOPOSITION 42
SHOW ANNOFIT 43
SHOW ANNOLEVEL 44
SHOW ANNOSIZE 45
SHOW ANNOITEM 46
&run annogen
&sv 11
SCREENSAVE t$anno.ras POPUP 8 10 16 29
&while &ne %11 EXIT &do
POPUP t$anno.mnu 11 2 8 10 16 29 NONE %11
&if &eq %11 V1 &do
&openw t$anno2.mnu
&write "Ē06 POINT1"
&write " POINT2"
&write " LINE"
&closew
POPUP t$anno2.mnu 12 1 14 11 3 7 RESET %41
& DEL t$anno2.mnu
&if &ne %12 EXIT &do
&sv 41 %12
&run annogen
&end
&elseif &eq %11 V2 &do
&openw t$anno2.mnu
&write "Ē06 LL"
&write " LC"
&write " LR"
&write " CL"
&write " CC"
&write " CR"
&write " UL"
&write " UC"
&write " UR"
&closew
POPUP t$anno2.mnu 12 1 14 23 9 4 RESET %42
& DEL t$anno2.mnu
&if &ne %12 EXIT &do
&sv 42 %12
&run annogen
&end
&elseif &eq %11 V3 &do
&openw t$anno2.mnu
&write "Ē06 ON"
&write " OFF"
&closew
POPUP t$anno2.mnu 12 1 14 31 2 4 RESET %43
& DEL t$anno2.mnu
&if &ne %12 EXIT &do
&sv 43 %12
&run annogen
&end
&elseif &eq %11 OK &do
ANNOTYPE %41
ANNOPOSITION %42
ANNOFIT %43
ANNOLEVEL %44
ANNOSIZE %45
ANNOITEM %46
&sv 11 EXIT
&else
&sv 11 EXIT
&end
&end
SCREENRESTORE t$anno.ras
& DEL t$anno.mnu
& DEL t$anno.ras
&return
In the above text I substitute "Ē" for ASCII 274[3]. When the response is "V1", a POPUP dialog
box containing the three ANNOTYPE options is invoked directly below the
appropriate box:

The cursor position is set to the current value. At this point the user can click on a value or escape by pressing the <`> key. If a value is chosen, variable 41 is updated and the main dialog file is regenerated. Once the "OK" button is pressed, the annotation edit parameters are updated with the contents of variables 41-46.
&routine getitem
&include getitem.inc
&openw t$temp.lis
ITEMS LIST
&closew
&open t$temp.lis error
&sv [numitems] 0
&sv [c_index] 100
&sv [i_index] 200
&while &do
&read [temp] [break]
&inc [numitems]
&inc [c_index]
&inc [i_index]
&delim * *
&sv %*c_index* "[`]"
&delim [ ]
&sv %[i_index] [temp]
&end
&close
& DEL t$temp.lis
&cv [rows] [numitems] + 7
&if &nr [rows] 1 20 &do
&sv [rows] 20
&end
SCREENSAVE t$item.ras POPUP 8 10 [rows] 17
&sv [cursor]
&sv [dialog]
&while &ne [dialog] EXIT &do
&run genitm
POPUP t$item.mnu [dialog] 2 8 10 [rows] 17 NONE [cursor]
&sv [cursor] [dialog]
&if &eq [dialog] OK &do
&sv [resp]
&sv [i] 1
&while &rn [i] 1 [numitems] &do
&cv [c_index] 100 + [i]
&cv [i_index] 200 + [i]
&value [temp] %[c_index]
&delim * *
&if &eq "*temp*" "[X]" &do
&value *temp* %*i_index*
&sv *resp* "*resp* *temp*"
&end
&delim [ ]
&inc [i]
&end
&sv [dialog] EXIT
&elseif &eq [dialog] CANCEL &do
&sv [resp] CANCEL
&sv [dialog] EXIT
&elseif &eq [dialog] EXIT &do
&sv [resp] CANCEL
&else
&sv [i] 1
&while &rn [i] 1 [numitems] &do
&cv [c_index] 100 + [i]
&cv [i_index] 200 + [i]
&value [temp] %[i_index]
&if &eq [temp] [dialog] &do
&value [temp] %[c_index]
&delim * *
&if &eq "*temp*" "[`]" &do
&sv %*c_index* "[X]"
&else
&sv %*c_index* "[`]"
&end
&delim [ ]
&end
&inc [i]
&end
&end
&end
SCREENRESTORE t$item.ras
& DEL t$item.ras
& DEL t$item.mnu
&return
&label error
&type "Error opening t$temp.lis"
&return
The include file "getitem.inc", which merely contains named variable
assignments, is left out for brevity. In the first part of the routine,
the output of the ITEMS LIST command is written to a temporary file; the
file is then read and each entry loaded into an SML variable starting at
201. A corresponding empty check box "[`]" is assigned starting at
variable 101 (note the use of &delim to prevent COMPSML from
bombing). Then the appropriate number of rows for the dialog box is
determined (maximum 20) and we're ready to crank it out. Routine
"genitem" is as follows:

When the user hits one of the entry buttons, the parent routine sets the corresponding checkbox variable to "[X]" or "[`]" as appropriate. Depending on the coverage, the dialog box looks something like this:

If the number of items causes the total dialog box rows to exceed 20, a "PgDn" button will appear to scroll to the remainder of the box[4].

When the user hits the "OK" button, the routine looks through the checkbox variables, and upon finding one that's checked appends the corresponding entry to the response variable [resp]. Note that in this example the total length of the picked items plus spaces cannot exceed 80 characters or the response will be cropped.

Note that when "CURSOR" is checked, the "DIGITIZER" options are disabled and grayed out:

The options are enabled when "DIGITIZER" is checked:

The parent routine simply sets the appropriate radio button variables to "(*)" or "(`)" based on the current SHOW COORDINATE value and resets them appropriately for each option that is checked:
&routine coo
SCREENSAVE t$coo.ras POPUP 8 10 15 17
SHOW COORDINATE 1
&sv 10
&while &ne %10 EXIT &do
&if &eq %1 CURSOR &do
&sv 41 "(*)"
&sv 42 "(`)"
&sv 43 "(`)"
&sv 44 "(`)"
&sv 45 "(`)"
&elseif &eq %1 DIGITIZER &do
&sv 41 "(`)"
&sv 42 "(*)"
&sv 43 "(*)"
&sv 44 "(`)"
&sv 45 "(`)"
&elseif &eq %1 NONE &do
&sv 43 "(*)"
&sv 44 "(`)"
&sv 45 "(`)"
&elseif &eq %1 DEFAULT &do
&sv 43 "(`)"
&sv 44 "(*)"
&sv 45 "(`)"
&elseif &eq %1 COVERAGE &do
&sv 43 "(`)"
&sv 44 "(`)"
&sv 45 "(*)"
&else
&sv 10 EXIT
&end
&if &ne %10 EXIT &do
&run gencoo
POPUP t$coo.mnu 1 2 8 10 15 17 NONE %1
&end
&end
SCREENRESTORE t$coo.ras
& DEL t$coo.ras
& DEL t$coo.mnu
&rem Process response...
&return
Now wouldn't it be neat, should the user select the "DIGITIZER COVERAGE"
option, to bring up a coverage picker? Sure it would! Which brings us
to:

Basically, an embedded, scrollable list box is a set of buttons representing a subset of a list of values stored in SML variables; arrow buttons are used to page up or down through that list. In this example it only picks existing coverages, but could be expanded to ask the user to input a nonexistent coverage name, e.g. for ARCEDIT's CREATECOVERAGE command.
@PICK is intended to be incorporated into a larger application, e.g. an ARCEDIT or ARCPLOT shell, with DISP 4 active. The usage is as follows:
&run pick [target]where [target] is the desired variable to contain the response, which will either be the name of a coverage, including its full path, or "CANCEL". @PICK consists of four routines ("pick", "genplis", "genpdlg", and "sysdir") and an include file ("pick.inc"). The include file merely defines the named variables used in the routines:
&define i 9 &var &define resp 10 &var &define cover 11 &var &define curdir 12 &var &define home 13 &var &define wksp 14 &var &define exit 15 &var &define i_cov 16 &var &define i_dir 17 &var &define numcov 18 &var &define numdir 19 &var &define temp1 20 &var &define temp2 21 &var &define entry1 22 &var &define entry2 23 &var &define var 24 &varThe numeric assignments are arbitrary, and may be reassigned to accommodate other routines, as long as they don't collide with the edit box variables (41 and 42 in this example, but they in turn may be reassigned to different variables); the only reserved variable is 1, the argument variable.
One of the first steps in generating list boxes is to load in list values: routine "genplis" reads in coverage values and transfers them to SML variables beginning at 101, while directories begin at variable 201:
&routine genplis &include pick.inc &type "Retrieving directory information..." &sv [cover] &sv [i_cov] 1 &sv [numcov] 0 &sv [i_dir] 1 &sv [numdir] 0 & LQ C | SORT >[wksp]t$cov.lis & LQ D | SORT >[wksp]t$dir.lis &sv [i] 100 &open [wksp]t$cov.lis error &while &do &read [temp1] [break] &inc [i] &sv %[i] [temp1] &inc [numcov] &end &close &sv [i] 200 &open [wksp]t$dir.lis error &while &do &read [temp1] [break] &inc [i] &sv %[i] [temp1] &inc [numdir] &end &close &return &label error &type "GENPLIS: I/O error" &returnNote the two lines which execute LQ, a 3.4.2 utility. Version 3.4D+ users could substitute the following code:
& L -CHLC >[wksp]t$cov.lis &length [temp1] [curdir] &value [temp2] [curdir] [temp1] [temp1] &if &ne [temp2] \ &do &openw [wksp]t$dir.lis &write ".." &closew & L -CHLD >>[wksp]t$dir.lis &else & L -CHLD >[wksp]t$dir.lis &endThe disadvantage of using L is that the directory list includes coverages, and drives are not listed[5]. Routine "genpdlg" creates the actual dialog box:

In any given instance, the dialog box will contain two edit boxes and six buttons (plus any list box entries). Both list boxes are set to six rows. Index variables [i_cov] and [i_dir] show the routine where to start generating the entries for the respective list boxes, and variables [numcov] and [numdir] indicate whether the end of a list is passed, in which case the rest of the list box is padded with blank entries.
The parent routine is as follows:
&routine pick
&include pick.inc
&value [var] 1
&run sysdir [curdir]
&value [home] [curdir]
&value [wksp] WKSP
&run genplis
&run genpdlg
SCREENSAVE [wksp]t$pick.ras POPUP 8 10 18 40
&sv [resp]
&sv [exit]
&while &ne [exit] EXIT &do
POPUP [wksp]t$pick.mnu [resp] 2 8 10 18 40 NONE [resp]
&if &cn "[resp]" < &do
&if &eq [resp] ^< &do
&if &ne [i_cov] 1 &do
&cv [i_cov] [i_cov] - 6
&run genpdlg
&end
&elseif &eq [resp] V< &do
&cv [temp1] [i_cov] + 6
&if &rn [temp1] [i_cov] [numcov] &do
&sv [i_cov] [temp1]
&run genpdlg
&end
&else
&length [temp1] "[resp]"
&value [temp2] [resp] 2 [temp1]
&if &ne [temp2] [cover] &do
&sv [cover] [temp2]
&run genpdlg
&end
&end
&elseif &cn "[resp]" > &do
&if &eq [resp] ^> &do
&if &ne [i_dir] 1 &do
&cv [i_dir] [i_dir] - 6
&run genpdlg
&end
&elseif &eq [resp] V> &do
&cv [temp1] [i_dir] + 6
&if &rn [temp1] [i_dir] [numdir] &do
&sv [i_dir] [temp1]
&run genpdlg
&end
&else
&length [temp1] [resp]
&value [temp2] [resp] 2 [temp1]
&if &cn [temp2] : &do
&value [temp2] [temp2] 2 4
& A [temp2]
&else
& CD [temp2]
&end
&run sysdir [curdir]
&run genplis
&run genpdlg
&end
&elseif &eq "[resp]" "þ41" &do
&if &fn "%41\tic.dbf" &do
&sv [cover] %41
&else
&sv 41 [cover]
&end
&elseif &eq "[resp]" "þ42" &do
&if &fn "%42" &do
& A %42
&run sysdir [curdir]
&run genplis
&run genpdlg
&else
&sv 42 [curdir]
&end
&elseif &eq "[resp]" "OK" &do
&if &eq "x[cover]" "x" &do
&sv [resp] CANCEL
&else
&length [temp1] [curdir]
&value [temp2] [curdir] [temp1] [temp1]
&if &eq [temp2] \ &do
&sv [resp] [curdir][cover]
&else
&sv [resp] [curdir]\[cover]
&end
&end
&sv [exit] EXIT
&elseif &eq "[resp]" "CANCEL" &do
&sv [exit] EXIT
&else
&sv [resp] CANCEL
&sv [exit] EXIT
&end
&end
SCREENRESTORE [wksp]t$pick.ras
& A [home]
& DEL [wksp]t$pick.ras
& DEL [wksp]t$pick.mnu
& DEL [wksp]t$cov.lis
& DEL [wksp]t$dir.lis
&value %[var] [resp]
&return
In the above text, the edit box field validation character (ASCII 254)
is represented by þ. When an up or down arrow is returned, the
appropriate index variable is incremented or decremented by the number
of rows in the list box; routine "genpdlg" takes care of regenerating
the respective list box. When an entry in a list box is pressed, the
appropriate edit box is updated; if a directory is changed, the coverage
and directory lists are regenerated. A value entered in an edit box is
checked for validity. If a new directory is entered, the lists are
regenerated and the full path of the new directory is placed in the edit
box; note that relative paths (e.g. "..\test1") may be entered.
Finally, if "OK" is pressed, the path and coverage name are combined and
assigned to the response variable.Routine "sysdir", which retrieves the current directory, is taken from the "SML Developer's Toolkit":
&routine sysdir &type "Getting current directory..." & CD >t$temp.lis &open t$temp.lis error &read 2 error &close & DEL t$temp.lis &value %1 2 &return &label error &type "SYSDIR: I/O error" &return
[2]For reasons of brevity I have omitted field validation, also discussed in my previous article.
[3]One of the major disadvantages of Windows fonts is their inability to represent many DOS characters. That is why I capture POPUP definition code as a bitmap whenever feasible.
[4]A fancier version could limit the number of checkboxes, scrolling any overflow as one would with a list box.
[5]Unless I am mistaken, L's "LR" option did not appear until version 3.4.2. LQ also has an option to list only tables; thus @PICK could easily be expanded to pick either coverages or tables.
Return to ArcTips page