SML PROGRAMMING

Fun with Widgets

Check Boxes and Radio Buttons

Check boxes and radio buttons provide a nice way to format choices in dialog boxes. Any text assigned to those widgets, however, cannot be returned or modified. Thus it may be desirable instead to maintain a parallel set of text widgets[1]. In the following example for ARCEDITW, text widgets are used to store the item names of the current edit feature:

&routine getitems
&rem arg1 = C or R (check box or radio button)
&rem arg2 = title for dialog box
&rem **** define variable names
&define arg1 -1 &var
&define arg2 -2 &var
&define wksp -3 &var
&define resp -4 &var
&define i -11 &var
&define wtype -12 &var
&define title -13 &var
&define wid -14 &var
&define row -15 &var
&define text -16 &var
&define temp -19 &var
&define winrtn 1 &var
&rem **** generate item widget list
&value [wtype] [arg1]
&value [title] [arg2]
&value [wksp] WKSP
&openw [wksp]t$temp1.lis
ITEMS LIST
&closew
&open [wksp]t$temp1.lis error
&openw [wksp]t$temp2.lis
&sv [wid] 100
&sv [row] 0
&sv [text] 200
&while &do
   &read [temp] [break]
   &inc [wid]
   &inc [row]
   &inc [text]
   &if &eq [wtype] C &do
      &write "CBOX [wid] [row] 1.5 1 1.5 v"
      &write "LTEXT [text] [row] 4 1 12 v [temp]"
   &else
      &write "RBUT [wid] [row] 1.5 1 1.5 v"
      &write "LTEXT [text] [row] 4 1 12 v [temp]"
   &end
&end
&close
&closew
&if &eq [row] 0 &do
   WIN MB 1 'No attributes.'
   &sv [resp] CANCEL
   &return [resp]
&end
&rem **** generate dialog box
&openw [wksp]t$items.dlg
&write "BEGIN     0  5  5  %<[row] + 4> 18 v [title]"
&if &eq [wtype] R &do
   &write "GBOX    100  0  1 %<[row] + 1.5> 16 v"
&end
&closew
& TYPE [wksp]t$temp2.lis >>[wksp]t$items.dlg
&openw [wksp]t$items.dlg A
&write "PBUT   -98 %<[row] + 2>  1  1.5 8 v OK"
&write "PBUT   -99 %<[row] + 2>  9  1.5 8 v Cancel"
&write "END"
&closew
WIN DB C [wksp]t$items.dlg
WIN DB R
&sv [temp] [winrtn]
WIN DB D
& DEL [wksp]t$items.dlg
& DEL [wksp]t$temp*.lis
&rem **** evaluate response
&if &eq [temp] -1 &do
   &sv [resp] CANCEL
&elseif &eq [temp] 49 &do
   &sv [resp] CANCEL
&elseif &eq [temp] 99 &do
   &sv [resp] CANCEL
&else
   &rem **** build list of items
   &sv [resp]
   &sv [i] 1
   &while &rn [i] 1 [row] &do
      &value [wid] %<[i] + 100>
      &if &eq [wid] 1 &do
         &value [text] %<[i] + 200>
         &sv [resp] "[resp] [text],"
      &end
      &inc [i]
   &end
&end
&return "[resp]"
&rem **** I/O error trap
&label error
&type "I/O Error"
&sv [resp] CANCEL
&return [resp]
Initially, the output of the ITEMS LIST command is captured and the item names copied over to widget definitions. This file is appended to a dialog file containing the BEGIN header, and then OK and CANCEL push buttons are appended. Finally, the widget list is scanned for checks and the appropriate text appended to the response variable. Note that the list of selected items cannot exceed 80 characters or it will be cropped, and that if no items are checked, a null string is returned to the parent routine.

The "R" (radio button) option is used for single picks, as for a JOIN command. If executed as follows:

&r getitems R "Join Item"
&rv -5
Figure 1

the value " TYPE," is returned to variable -5 (the JOIN command ignores the comma). The "C" (check box) option is used for multiple picks, as for a LIST command. If executed as follows:

&r getitems C "List Item(s)"
&rv -5
Figure 2

the value " TYPE, NAME, #ACRES," is returned to variable -5.

In dedicated applications, item descriptions may be displayed, with the actual item names hidden beyond the width of the text widget (in this example, columns 30-36):

BEGIN   0 5 5.0 10.0 20.0 v Modify:
CBOX  101 1 1.5  1.0  1.5 v
LTEXT 201 1 4.0  1.0 15.0 v
CBOX  102 2 1.5  1.0  1.5 v
LTEXT 202 2 4.0  1.0 15.0 v
CBOX  103 3 1.5  1.0  1.5 v
LTEXT 203 3 4.0  1.0 15.0 v
CBOX  104 4 1.5  1.0  1.5 v
LTEXT 204 4 4.0  1.0 15.0 v
CBOX  105 5 1.5  1.0  1.5 v
LTEXT 205 5 4.0  1.0 15.0 v
CBOX  106 6 1.5  1.0  1.5 v
LTEXT 206 6 4.0  1.0 15.0 v
PBUT  -98 8 1.0  1.5  8.0 v OK
PBUT  -99 8 9.0  1.5  8.0 v Cancel
END
S 201 Vegetation Class       VEG
S 202 Signature Index        INDEX
S 203 Data Source            SOURCE
S 204 Catalog Number         CATALOG
S 205 Resolution             RES
S 206 Reference Date         REF_DAT
Figure 3

Note the use of the S dialog command to set the values of the text widgets. The desired item name would be extracted as follows:

&value [text] %<[i] + 200> 30 36

List Boxes

List boxes are often preferable to check boxes or radio buttons for selecting from a list of values, because:

Because up to 5000 lines are supported, list boxes may be used to display moderate-sized text files, as shown in the following example[2]:

&routine popup
&rem Argument = text file
&rem **** define variable names
&define arg1 -1 &var
&define pin -2 &var
&define file -11 &var
&define wksp -12 &var
&define size -13 &var
&define winrtn 1 &var
&rem **** generate command file
&sv [file] [arg1]
&value [wksp] WKSP
&sv [size] 40
&openw [wksp]t$popup.cmd
&write "L 101 |EOL|"
&closew
& TYPE [file] >>[wksp]t$popup.cmd
&openw [wksp]t$popup.cmd A
&write "|EOL|"
&closew
&rem **** generate dialog box
&r genpopup [size]
WIN DB P
&value [pin] [winrtn]
&while &do
   WIN DB R [wksp]t$popup.cmd
   &rem **** process response
   &if &eq [winrtn] 103 &do
      WIN CB W '%101'
   &elseif &eq [winrtn] 104 &do
      WIN FILE 2 * 'Enter Save File'
      &if &ne "x[winrtn]" "x" &do
         & COPY [file] [winrtn]
      &end
   &elseif &eq [winrtn] 105 &do
      &cv [size] [size] - 20
      &r genpopup [size]
   &elseif &eq [winrtn] 106 &do
      &cv [size] [size] + 20
      &r genpopup [size]
   &else
      &goto [break]
   &end
&end
WIN DB D
& DEL [wksp]t$popup.cmd
&if &eq [pin] U &do
   WIN DB U
&end
&return

&routine genpopup
&define size -1 &var
&define wksp -2 &var
&value [wksp] WKSP
&openw [wksp]t$popup.dlg
&write "BEGIN 0  5  5 16 %<[size] + 2> v Text"
&write "LBOX   101  1  1 12.0 [size] f"
&write "PBUT   102 14  1  1.5  8 v OK"
&write "PBUT   103 14  9  1.5  8 v Copy"
&write "PBUT   104 14 17  1.5  8 v Save"
&write "PBUT   105 14 25  1.5  4 v <<"
&write "PBUT   106 14 29  1.5  4 v >>"
&write "END"
&if &eq [size] 40 &do
   &write "G 105"
&end
&closew
WIN DB C [wksp]t$popup.dlg
& DEL [wksp]t$popup.dlg
&return
Figure 4

Note the use of the L dialog command to populate the list box. The "Copy" push button uses the WIN CB W command to write the text of a selected list entry to the Windows clipboard. The "Save" push button uses the WIN FILE command to allow the user to save to a new file (generally used when capturing output to a temporary file). Because a list box cannot scroll horizontally, the "<<" and ">>" push buttons allow the user to expand or contract the dialog box width by 20 column increments:

Figure 5

Also note the use of the WIN DB P command. This sets what is known as "pin mode", which prevents the position of the dialog box from being reset to the BEGIN values when it is recreated (which is undesirable if the dialog box has been moved by the user). If pin mode is not active at the time the WIN DB P command is issued, the value "U" is returned to variable 1. The value is stored in variable [pin] and examined at the end of the routine to see if pin mode needs to be turned off again using WIN DB U. (More about these commands when we get to nonmodal dialog boxes.)

Routines "getitems" and "popup" may be combined to construct a simple LIST routine for ARCEDITW:

&routine list
&r getitems C "List Item(s)"
&rv -1
&if &ne "%-1" "CANCEL" &do
   &value -2 WKSP
   &openw %-2t$temp.lis
   LIST %-1
   &closew
   &r popup %-2t$temp.lis
   & DEL %-2t$temp.lis
&end
&return
Of course, an even simpler (but not as fun) alternative is to use the WIN RUN command to bring up a text editor instead of using the popup routine:

&routine list
&r getitems C "List Item(s)"
&rv -1
&if &ne "%-1" "CANCEL" &do
   &value -2 WKSP
   &openw %-2t$temp.lis
   LIST %-1
   &closew
   WIN RUN notepad %-2t$temp.lis
&end
&return
The chief disadvantage of a list box widget is that more than one entry cannot be selected[3]. One way to work around this is to maintain two lists and transfer entries between them. The following example is useful in situations involving large numbers of attribute items:

&routine getitem2
&rem **** define variable names
&define resp -1 &var
&define wksp -2 &var
&define num_in -3 &var
&define num_out -4 &var
&define i -11 &var
&define shift -12 &var
&define temp -19 &var
&define winrtn 1 &var
&rem **** generate item list
&value [wksp] WKSP
&sv [num_in] 0
&sv [num_out] 0
&openw [wksp]t$temp1.lis
ITEMS LIST
&closew
&open [wksp]t$temp1.lis error
&while &do
   &read [temp] [break]
   &inc [num_in]
   &value %<1000 + [num_in]> [temp]
&end
&close
&if &eq [num_in] 0 &do
   WIN MB 1 'No attributes.'
   &sv [resp] CANCEL
   &return [resp]
&end
&rem **** generate dialog box
&openw [wksp]t$items.dlg
&write "BEGIN    0  5.0  5 16.0 42 v List Item(s)"
&write "LTEXT    0  0.5  1  1.0 18 v Available Items"
&write "LBOX  -1101 1.5  1 12.0 18 v "
&write "LTEXT    0  0.5 23  1.0 18 v List Item(s)"
&write "LBOX  -1102 1.5 23 12.0 18 v "
&write "PBUT  -103  5.0 20  1.5  2 v >"
&write "PBUT  -104  7.5 20  1.5  2 v <"
&write "PBUT  -105 14.0  1  1.5  8 v OK"
&write "PBUT  -106 14.0  9  1.5  8 v Cancel"
&write "PBUT  -107 14.0 17  1.5  8 v Clear"
&write "END"
&rem **** generate command file
&openw [wksp]t$items.cmd
&r genlist 101 1000 [num_in]
&write "G 104"
&closew
&rem **** open dialog and process
response
WIN DB C [wksp]t$items.dlg
&while &do
   WIN DB R [wksp]t$items.cmd
   &if &fn [wksp]t$items.cmd &do
      & DEL [wksp]t$items.cmd
   &end
   &if &eq [winrtn] 101 &or &eq [winrtn] 103 &do
      &rem **** add entry to 102
      &if &ne "x%101" "x" &do
         &inc [num_out]
         &value %<[num_out] + 2000> 101
         &openw [wksp]t$items.cmd
         &r genlist 102 2000 [num_out]
         &write "E 104"
         &closew
      &end
   &elseif &eq [winrtn] 102 &or &eq [winrtn] 104 &do
      &rem **** remove entry from 102
      &if &ne "x%102" "x" &do
        &sv [i] 1
         &sv [shift] FALSE
         &dec [num_out]
         &while &rn [i] 1 [num_out] &do
            &value [temp] %<[i] + 2000>
            &if &eq "x[temp]" "x%102" &do
               &sv [shift] TRUE
            &end
            &if &eq [shift] TRUE &do
               &value %<[i] + 2000> %<[i] + 2001>
            &end
            &inc [i]
         &end
         &openw [wksp]t$items.cmd
         &r genlist 102 2000 [num_out]
         &if &eq [num_out] 0 &do
            &write "G 104"
         &end
         &closew
      &end
   &elseif &eq [winrtn] 105 &or &eq [winrtn] 50 &do
      &rem **** build item list
      &sv [resp]
      &sv [i] 1
      &while &rn [i] 1 [num_out] &do
         &value [temp] %<[i] + 2000>
         &sv [resp] "[resp] [temp],"
         &inc [i]
      &end
      &goto [break]
   &elseif &eq [winrtn] 107 &do
      &rem **** clear 102
      &sv [num_out] 0
      &openw [wksp]t$items.cmd
      &r genlist 102 2000 [num_out]
      &write "G 104"
      &closew
   &else
      &sv [resp] CANCEL
      &goto [break]
   &end
&end
WIN DB D
&return "[resp]"
&rem **** I/O error trap
&label error
&type "I/O Error"
&sv [resp] CANCEL
&return [resp]

&routine genlist
&rem **** populate lists
&define i -11 &var
&define temp -19 &var
&write "L %-1 |EOF|"
&sv [i] 1
&while &rn [i] 1 %-3 &do
   &value [temp] %<[i] + %-2>
   &write "[temp]"
   &inc [i]
&end
&write "|EOF|"
&return
Figure 6

Note that the LBOX widgets are assigned IDs of -1101 and -1102: assigning a negative ID and adding -1000 causes a list box to act as a return widget if an entry is double-clicked. For example, should a user double-click an available item entry, the value returned to variable 1 would be "101" and the contents of that entry would be assigned to variable 101.

In the above example, the user could also select an available item and click the ">" button to add it to the second list. Similarly, the user could remove an item from the second list either by double-clicking the entry or selecting the entry and clicking the "<" button. Clicking the "Clear" button clears the second list; note that a list box may be emptied by following the L dialog command immediately with the {EOF} line.

One feature of list boxes to beware of: the S dialog command will select the first entry of the list box that begins with the value. For example, if list box 101 contains:

PARCELS_I
BOOK
MAP
PARCEL
and the command "S 101 PARCEL" is issued, PARCELS_I will be selected.

Finally, as was noted for text widgets above, verbose descriptions may be stored in the visible portion of list box entries, with system values hidden beyond.

Next: Handling Coordinates


[1]The disadvantage of this technique is that you cannot click on the text itself to check or uncheck a widget.

[2]The path to the file must stated fully or relative to the current directory.

[3]A list box supporting multiple selects would make a very tasty future SML enhancement. MBOX and SMBOX statements could specify a starting ID, and selected entries would map to corresponding variables (the remainder in the range being assigned blank values).


Return to ArcTips page