"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 &returnThe 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.
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 POPENDA 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:
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:
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
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
Once a menu is created, it is idle until the "WIN MENU R" command is issued:
WIN MENU R [wksp]t$menu.cmdThe 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).
&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 &returnMenu 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" &endThe 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 &endIf [pinmode] is initially NO, the entry would look like this prior to being picked:
after being chosen, the entry would look like this after the next "WIN MENU R %51t$menu.cmd":
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
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
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
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):
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 principlethe 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'
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
[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.