Window Menus
Volume Number: 4
Issue Number: 11
Column Tag: Programmer's Workshop
Menus In Windows 
By James Matthews, Hanover, NH
[Jim Matthews is a software developer at Dartmouth, working on network
applications. He has done maintenance work on DarTerminal, an AppleTalk terminal
emulator, and has worked on developing a Macintosh mail system. He started
programming in high school on an IBM 360 with core memory but slowly moved to
smaller, newer machines. In college, he helped develop MacFunction, a
three-dimensional graphing program that is currently marketed by True Basic, Inc.]
Menus in Windows
by Jim Matthews, Dartmouth College
One of the critical elements of the Macintosh user interface is the menu bar. It
relieves the user of the need for memorizing command names and gives easy access to a
large number of operations in a small amount of space. Nonetheless, the limitations of
the standard Macintosh menu bar have become increasingly evident. Large screens
make the fixed position of the menu bar less convenient, and large programs present
users with an overwhelming number of available commands. Desk accessories have
never been able to use the menu bar fully, limiting their potential. Both Apple and
third parties have developed workarounds to the limitations of the menu bar.
Hierarchical and pop-up menus, implemented in System 4.1, provide alternate ways
of structuring menu commands. The tear-off palettes used in HyperCard and MacPaint
2.0 add a new dimension to menus, as do the tear-off menus provided with Radius
displays.
Still, I recently felt the need to extend the menu bar concept by another step.
While developing a program with a large number of commands, I decided that what I
wanted was a different menu bar for each window. It would have been possible to
change the menu bar depending on which window was in front, but the commands needed
by each window were so different that the user would never know what to expect when
he pulled down a menu. Furthermore, I wanted to leave open the possibility of turning
the program into a desk accessory, and I could not fit all my commands into one menu.
So I re-implemented part of the Menu Manager to provide for window-specific menu
bars. The code itself is not very complicated -- I was fortunate to be preceded by Mike
Schuster, whose December, 1985 article on pop-up menus provided a wealth of useful
information. The routines I produced met my needs admirably, but like any extension
to the standard interface they also raised some tricky issues.
Figure 1. Edit Menu
The wMenu Manager Routines
Because I wanted to produce menu bars that function exactly like the one at the
top of the screen, I implemented the window menus by imitating eight standard Menu
Manager routines. They all operate on a wMenuBar data structure which is roughly
comparable to a MenuList.
wMenuRec = record
mh : MenuHandle;
titleRect : Rect;
end;
wMenuBar = record
numMenus : integer;
hilited : integer;
gp : GrafPtr;
wMenus : array [0..0] of wMenuRec;
end;
The wMenuBar stores the number of menus in a menu bar, which one is hilited
(if any), and the GrafPort in which the menu bar is drawn. In addition, it stores a
menu handle and a rectangle for each menu that has been inserted. The rectangle
specifies the coordinates of the menu title; i.e. the area that is inverted when a menu is
selected. This is a bit wasteful, since two of the rectangle’s coordinates are always the
same, but it makes the code simpler. The wMenuBar record is created by a call to
wInitMenus, which allocates the storage and returns a wMenuBarHandle. The rest of
the routines accept the same arguments as their Menu Manager equivalents, with the
addition of a wMenuBarHandle to specify the menu bar being altered. The routines are
wInsertMenu and wDeleteMenu, to add and remove menus from the menu bar;
wClearMenuBar to delete all the menus; wDrawMenuBar to redraw the menu bar;
wMenuSelect and wMenuKey to respond to mouse and key events, respectively; and
finally, wHiliteMenu to highlight a menu’s title.
Implementation Issues
There are a few subtle points in the implementation of the wMenu Manager. The
System 4.2 menu definition procedure has a bug that is fixed by initializing the low
memory global TopMenuItem in wInitMenus. Calls to the menu definition procedure
are implemented using inline machine code, since Pascal doesn’t provide a standard
way to call a routine based on its address. WMenuKey walks down a menu’s data
looking for a certain command key equivalent, and the dynamic nature of the data
structure requires some ugly code. GetNextEvent and SystemTask are called in the
inner loop of the menu selection code: this means that keyDown events are swallowed
while the user is holding down a menu, but it provides the ability to produce screen
dumps and keeps desk accessories updated. With the standard menu bar it is
impossible for the user to drag the mouse above the top of the menus, but with window
menus it was necessary to deal with this case. I decided to have the displayed menu