Menu Management with Pascal
by William B. Busby
Even though Personal Pascal (PP) generally provides easy access to the features of GEM, some assistance is needed beyond the manual to begin writing applications that run under GEM. This article will discuss one of those GEM topics: the construction and management of menu bars within PP.
The largest job we're faced with when building our menu is planning. Several considerations must be observed. The total width of the menu titles must not exceed the width of the resolution in which our application will run. If our application is to run in all resolutions, we must limit ourselves to 40 characters, including the "DESK" title provided by GEM, to fit the width of the low-resolution screen. This width restriction also applies to the menu items found under the titles, or our menu items will wrap around the screen when the menu is activated.
Applications designed for medium and high resolution can use the full 80-column width of the screen. It is usually recommended that a space be placed on each side of a menu title. When planning the items that will be found under each title, be careful to group them logically. For example, if you have a title called "FILE," place all disk functions under that title, including the option to exit the application. It would probably be wise to review several commercial applications which you find easy to use and observe how the menus are constructed. We are limited to 24 items per title and/or less than 25% of the total screen area. GEM maintains a buffer of up to 25% of the screen area, which is used to redraw the screen when the drop-down menu is removed from the screen and when alert boxes disappear.
To build a menu with PP, the following steps must be taken:
- Use New__Menu to reserve menu space and obtain a pointer to the menu tree.
- Add all titles to the menu with Add__MTitle.
- Add the items found under the titles with Add__MItem in the same order the titles were added. Add all items to the first title before adding any items to the second, etc. Unexpected results may occur if this caution is not observed. If any of the items are to be preceded by a check mark, all items should be preceded by two spaces. All items under a title should be the same length. Shorter items should be padded with blanks to make their lengths equal to the longest found under any one title.
After our menu structure is defined in memory we probably need to do some touch-up work before we actually show it to the user. Seldom are all options in an application available to the user at the same time. It is standard practice, and common sense, to use the menu to show the options currently active with check marks and to disable any options not available at any given time.
The procedure Menu__Check is used to show or remove check marks preceding items. The procedure Menu__Disable will make each disabled item show up in half-intensity, and mouse clicks on these disabled items won't cause menu events to be placed in the event queue. When all the preparation has been done, we're ready to show the results of our efforts to the user with a call to Draw__Menu.
With the menu on the screen, the user could take several actions. He could press a key, choose a menu item, move the mouse to another portion of the screen or manipulate any displayed windows or icons. GEM provides a central procedure to monitor these events. In PP, this call is implemented in the function Get__Event, which returns an integer defining the event(s) and any data associated with the event in the parameter definitions. GEM applications are designed to monitor this event call and take actions based on the events detected. Through a call to Get__Event, we can detect keyboard events, mouse-button events, mouse-pointer events, timer events and messages. Messages can be further broken down into menu events and window events.
That's a lot of stuff for anyone to keep track of. Fortunately, we can tell GEM to notify us of only certain events, making our application more selective and simplifying our task. In the sample program, we requested only message events by passing the event mask parameter as E__Message. We then went a little farther and acted only on the MN_Selected message (menu item selected). When the function returns, we will find the title and item indexes in message-buffer elements 3 and 4, respectively.
From there, managing our menu is simply a matter of passing these indexes to our Do__Menu procedure and testing them. The first thing we want to determine is if the Desk_Title has been selected. If so, we need to show the information about our application. Typically, we would display a dialog box describing our application. In the sample program, I just slipped an alert box in here.
If the Desk__Title wasn't selected, we need to test the item numbers to determine which was selected. Since each menu item is assigned a unique integer number, we don't need to concern ourselves with the title, but the title number is there if we choose to use it.
Depending on the item chosen, we will probably want to make changes to the status of our menu. Fortunately, PP has provided some comprehensive procedures to keep the menu properly updated. The usage of each of these is documented in our application and for the most part covered well in the manual. The following procedures are available.
Menu__Check. This procedure will place or remove a check mark, which precedes the item text. You should place two spaces in front of the text to make room for this check mark or the first character of the item text will be overwritten. No error will result from removing a check mark that doesn't exist or from checking an item that is already checked.
Menu__Enable. This procedure will display the menu item in full-intensity and allow menu-selected events to occur when the item is chosen. It is not an error to enable items already enabled.
Menu__Disable. This procedure will display the menu item in half-intensity and prevent any menu-selected event from occurring when it is chosen. It is not an error to disable items already disabled.
Menu__Text. This procedure is used to change the text of a menu item. The text overwrites any text previously in the menu item and thus must be the same length. Part of planning a menu is to determine the maximum length string that may be placed in a menu item and ensuring enough space is reserved for it when the item is initially defined. A caution is required here: Menu__Text may not work on your system, depending on the version of GEMSUBS.PAS you have. Some versions had an error in the Menu__Text declaration within GEMSUBS.PAS. However, it is easy to fix. Examine your GEMSUBS.PAS file. If the last parameter of Menu__Text, the parameter for the new text, is declared a VAR parameter, remove the word "VAR." Leave all else alone. Menu__Text should then work as advertised in the manual. My thanks goes to the ICD team for assisting in tracking down this error. It has been corrected in the latest version of PP, version 2.02.
Menu__Normal. After the action requested by the user has been performed, it will be necessary for us to return the menu title to normal video. When a menu is activated, GEM draws the title in reverse video. Since GEM has no means of determining when we are done performing the menu action, it leaves it up to the application to return the title to its original appearance.
Using these routines, we should have no trouble keeping our menus current and easing the task of the user when our application is used. After our application has performed its task and the user tells us he wants to get out, we must call Erase__Menu to remove the menu from the screen before exiting to the desktop. Actually, Erase__Menu could be used in conjunction with Draw__Menu to display several menus within an application. The spreadsheet Masterplan uses this technique effectively. Choosing one option brings up another menu with additional options, and so forth.
A final procedure available is Delete__Menu, which is used to release the memory consumed by our menu tree back to the operating system. This call is not normally needed since exiting the application releases all our memory back to the operating system. If you find a need for it, you must ensure the menu has been erased from the screen before calling Delete__Menu or some strange menus will be displayed. Try it sometime for a laugh, but be prepared to reset your computer.
I've included a short program, MENUS.PRG, which demonstrates the techniques presented in this article. It shows both the correct way to construct menus and some of the common errors made. The source code, MENUS.PAS, is liberally commented and should be easy to follow.
William Busby is currently serving in the Air Force at Arnold AFB, TN. His spare time is spent studying for a degree in electronics engineering and playing with his one-year-old daughter, Brittany.