SML PROGRAMMING

Windows Extensions

Menus à la Win-Doze

Creating fancy menus with POPUP requires a lot of mucking about with SCREENSAVE, SCREENRESTORE, formatting, and positioning.

"It was great fun, but it was just one of those things...."

Anyway, by taking advantage of standard Windows calls, the WIN MENU command handles all of the necessary graphic functions; as a result, creating nifty menus is a piece of cake! And no matter what version of Windows you're running (3.x, 95, NT), the menus will be consistent with the look and feel of the operating system[1]. A simple menu-based application might be organized along the following lines:

&routine main

&value 51 WKSP

&rem **** create menu

&openw %51q_main.mnu
&write "POPUP &File"
&write "   MENUI &New Project,  NEW"
...
&write "POPEND"
&closew
DISPLAY 4 1 24
WIN MENU C %51q_main.mnu
& DEL %51q_main.mnu
WIN TITLE G 'QCHECK 1.0'

&rem **** menu response loop

&while &do

   &rem **** read response

   &run setmenu
   WIN MENU R %51t$menu.cmd
   &if &fn %51t$menu.cmd &do
      & DEL %51t$menu.cmd
   &end

   &rem **** process response

   &if &eq %1 NEW &do
      &run newp
   &elseif...
      etc. etc. etc.
   &elseif &eq %1 EXIT &do
      &run exit
   &end
&end
&return
The first step is to create a menu definition file; the menu is then generated using the "WIN MENU C" statement. The "WIN TITLE G" statement sets the title of the graphic window. Routine "setmenu" builds a command file which sets the status of menu entries (see Menu Commands below), and "WIN MENU R" returns the menu choice made by the user.

Menu Files

Menus are defined by menu files, which may be maintained independently or created on the fly. The following example is from QCHECK, an ARCPLOTW application which is now available at my Web page:

POPUP &File
   MENUI &New Project,  NEW
   MENUI &Open Project, OPEN
   MENUI &Save,         SAVE
   MENUI &Save As...,   SAVEAS
   SEP
   MENUI &Theme,        SETTHEME
   MENUI &Item,         SETITEM
   MENUI &Edit,         FORMS
   MENUI &Background,   SETBACK
   MENUI &Join,         JOIN
   MENUI Join O&ff,     JOINOFF
   SEP
   MENUI E&xit,         EXIT
POPEND
POPUP &Display
   MENUI Zoom &In,      ZOOMIN
   MENUI Zoom &Out,     ZOOMOUT
   MENUI &Pan,          PAN2
   MENUI Pre&vious,     PREV
   MENUI &Full,         FULL
   MENUI &Item Text,    TOGITEM
POPEND
POPUP &Tools
   MENUI &Theme Tools,  TTOOL
   MENUI &Display Tools, DTOOL
   SEP
   MENUI &Pin Mode,     PINMODE
POPEND
POPUP &Help
   MENUI &Contents,     HELP
   MENUI &About,        ABOUT
POPEND
A menu entry is indicated by the "MENUI" directive. The menu item, terminated by a comma, indicates the phrase to appear in the menu when created; the optional ampersand (&) defines an underlined shortcut (for example, pressing <Alt><F> and then <X> is equivalent to choosing the "File | Exit" menu item). Following the comma is a keyword (1-10 characters, no spaces) which will be returned when the menu item is chosen. Individual popup menus are delimited by the POPUP and POPEND directives, and the SEP directive defines a horizontal separator.

When created using "WIN MENU C", the menu looks like this:

Figure 1

The "Options" popup menu is always present in the DISPLAY 4 graphic window[2]; if DISPLAY is not active (e.g. in an ARCW shell), a graphic window will appear without the Options menu.

When the user clicks a popup entry, the contents of the popup menu appear:

Figure 2

Popup menus may be nested, as in this example from AESHELL:

POPUP &Edit
   ...
   POPUP Arc
      MENUI Split,         SPLIT
      MENUI Unsplit,       UNSPLIT
      MENUI Snap,          SNAP
      MENUI Flip,          FLIP
      MENUI Reshape,       RESHAPE
      MENUI Spline,        SPLINE
      MENUI Bisect,        BISECT
      MENUI Buffer,        BUFFER
      POPUP COGO
         MENUI Import,        GENCOGO
         MENUI Export,        UNCOGO
      POPEND
   POPEND
   ...
POPEND
Figure 3

Up to 10 levels of nesting are supported. Note that popup entries within a popup menu are indicated with an arrowhead.

Popup menus can have more than one column; the first menu item of the new column is indicated by the MENUB directive; the MENUBB directive acts in the same fashion, but adds a vertical separator between columns, for example:

POPUP &Edit
   MENUI &Feature,      SETFEAT
   MENUI Initialize,    NEWBUF
   MENUI &Add,          ADD
   SEP
   MENUI Cu&t,          FCUT
   MENUI &Copy,         FCOPY
   MENUI &Paste,        FPASTE
   MENUI Paste to &New, NPASTE
   MENUI &Delete,       DELETE
   MENUBB Move,          MOVE
   MENUI Nudge,         NUDGE
   MENUI Copy From/To,  COPY
   MENUI Rotate,        ROTATE
   SEP
   POPUP Arc
      ...
   POPEND
   POPUP Vertex
      ...
   POPEND
   POPUP Anno
      ...
   POPEND
   POPUP Tic
      ...
   POPEND
POPEND
Figure 4

Once a menu is created, it is idle until the "WIN MENU R" command is issued:

WIN MENU R [wksp]t$menu.cmd
The specified file, if it exists, is used to initialize the menu entries (see below). When the user picks a particular menu entry, its keyword is returned to SML variable 1[3]. At that point the application can process the response.

Only one menu system can exist at a time; however, menu structure may be altered at will by reissuing the WIN MENU C command. If desired, an existing menu may be removed via the WIN MENU D command; if DISPLAY is not active, execution of WIN MENU D will also hide the graphic window (Version 3.5 only).

Menu Commands

As was shown in some of the above screen captures, menu entries can be enabled or disabled (grayed); this is most useful for maintaining context sensitivity, i.e. only those menu entries applicable to a given situation will be choosable, helping to prevent the user from executing a bad command. For example, the "Cut" and "Copy" commands (among others) in the previously shown Edit menu require that features be selected; hence the following lines might be executed in building the command file:

&routine setmenu
&openw [wksp]t$menu.cmd
...
SHOW NUMBER SELECT [numsel]
&cv [temp] [numsel] abs
&if &ne [numsel] 0 &and &eq [numsel] [temp] &do
   &write "E FCUT"
   &write "E FCOPY"
   ...
&else
   &write "G FCUT"
   &write "G FCOPY"
   ...
&end
...
&closew
&return
Menu entries are referred to by their keywords (popup menus themselves cannot be disabled). Note that in the above example a positive value of [numsel] is required; if the value were negative, it would indicate that features had just been deleted (or the NEW command issued). One would, of course, structure the routine so that all menu entries affected by a particular logical condition are handled.

Menu entries may also be checked or unchecked. This is useful for entries that toggle a particular state, for example:

&if &eq [pinmode] YES &do
   &write "C PINMODE"
&else
   &write "U PINMODE"
&end
The following code would process the menu return[4]:

&elseif &eq %1 PINMODE &do
   &if &eq [pinmode] YES &do
      &sv [pinmode] NO
      WIN DB U
   &else
      &sv [pinmode] YES
      WIN DB P
   &end
If [pinmode] is initially NO, the entry would look like this prior to being picked:

Figure 5

after being chosen, the entry would look like this after the next "WIN MENU R %51t$menu.cmd":

Figure 6

Commands to initialize a menu may also be appended to a menu definition following an END directive:

&write "POPUP &File"
...
&write "POPEND"
&write "END"
&write "C PINMODE"
&closew

Positioning Windows

Version 3.5 has a new command, WIN POS, which allows an application to read and set the graphic and text window positions. For example, an initialization routine might contain the following lines:

WIN POS R G
&value 2 1
WIN POS R T
&openw t$win.sml
&write "WIN POS W G %2"
&write "WIN POS W T %1"
&closew

&rem **** 1024x768 window settings

WIN POS W T 0 578 500 190
WIN POS W G 0 0 753 576

&rem **** VGA window settings

&rem WIN POS W T 0 361 477 119
&rem WIN POS W G 0 0 465 360

DISPLAY 4 1 24
WIN POS W G 0 0 753 576
&rem WIN POS W G 0 0 465 360
WIN TITLE G 'QCHECK 1.0'
The original window settings are saved as an SML file to be executed upon quitting the application. The second "WIN POS W G" statement is there because "DISPLAY 4 1" wants to stretch the graphic window out a little beyond the actual draw region. To restore the original window settings, the application's exit routine would include the following lines:

DISP 0
DIALOGCLEAR
&run t$win.sml
& DEL t$win.sml
QUIT

The File Picker

The WIN FILE command invokes the Windows file picker, allowing the user to specify a new and/or existing file. The basic options are as follows:

1 = File must exist
2 = File must not exist
3 = File may or may not exist

In the following example, option 1 is used to load an existing project file; files having a ".QCP" extension will be displayed by the picker:

WIN PATH [curdir]
WIN FILE 1 qcp 'Load Project'
&if &eq "x%1" "x" &do
   &return
&end
Figure 7

Note that if the "Cancel" button is pressed, variable 1 will be empty. The WIN PATH command sets the default search path for the file picker (in this case, the contents of variable [curdir]). In version 3.5, WIN FILE allows specification of more than one extension:

WIN FILE 1 CML+SML 'Execute a Macro'
Version 3.5 also introduces a number of extra options to the WIN FILE command:

I = Existing table
G = New table
D = Directory
C = Any existing coverage
S = Existing coverage with ADDRESS attributes
A = Existing coverare with ARC attributes
P = Existing coverage with POLY attributes
X = Existing coverage with POINT attributes
N = New coverage
M = Existing map composition

Option "I" (as well as "G") allows a suffix specification, which is especially useful for picking symbol tables:

&value 51 ARC
WIN PATH %51\symbols
WIN FILE I SHD 'Choose Shadeset'
&extract [file] 1 1
WIN PATH [curdir]
Note that the response is assigned to a variable before resetting the WIN PATH; otherwise, the contents of variable 1 will be nuked. In this example, the file picker takes on a new appearance, displaying item definitions for a file entry that is picked (this holds true for any picker operation involving a table):

Figure 8

Unfortunately, the resulting value of variable [file], "PLOTTER\SHD", is not recognized by the SHADESET command, and so the following work-up is required:

&sv [temp] .
&value [file] [temp] 1 1 %<lpos \ [file]> %<lpos \ [file]>
For better or worse, the coverage options operate on the same principle—the user picks not the coverage name (which would cause the picker to jump to that subdirectory) but rather a table which is present in the coverage:

WIN PATH [curdir]
WIN FILE C * 'Choose Coverage'
Figure 9

Although the table extension is stripped from the return value, it still will not necessarily be consistent with, say, the SHOW EDITCOV command (i.e. upper case, full pathname); the following code rectifies that problem (assuming that [curdir] is also in upper case):

&extract [cover] 1 1
&if &nc "[cover]" ":" &do
   &if &eq %<lpos "\" "[curdir]"> %<len "[curdir]"> &do
      &sv [cover] [curdir][cover]
   &else
      &sv [cover] [curdir]\[cover]
   &end
&end

Next: WIN Dialog Boxes


[1]All of my examples are executed in Win 95.

[2]Discussion of the Options menu is beyond the scope of this article, though I may get into it a bit when I discuss the WIN EXEC command.

[3]All WIN commands which return a value assign it to variable 1.

[4]The WIN DB P and WIN DB U commands will be discussed in a future article.


Return to ArcTips page