Menus.mesa; Written by Randy Pausch
Menus are collections of entries. Entries are selectable regions at the top of viewers that can cause TIP-like actions to be passed to notifyProcs. Menus are useful for manipulating sets of entries as a group. Menus can be created and registered with the viewers package (after which they are refered to by their unique rope "name"), and then attached to viewers. Each viewer has a list of menus associated with it, and at any given time each of them may be "active" in that viewer (visible to the user and ready to have its entries selected), or "inactive", in which case it exists in the viewer's list of menus but is currently not displayed to the user. For example, the standard Tioga viewer has three menus, the "main" one, which is initiallly active, and the "Levels" and "Places" menus, which are initially inactive.
Last Edited by: Pausch, August 26, 1983 10:18 am
DIRECTORY
Imager USING [Context],
Rope USING [ROPE],
ViewerClasses USING [MenuEntryDisplayOp, NotifyProc, Viewer];
Menus: CEDAR DEFINITIONS = BEGIN
Viewer: TYPE = ViewerClasses.Viewer;
ROPE: TYPE = Rope.ROPE;
MenuEntryTrigger: TYPE =
{leftup, middleup, rightup, shiftleftup, shiftmiddleup, shiftrightup, all, notrigger};
all: LIST OF MenuEntryTrigger = LIST[leftup, middleup, rightup, shiftleftup, shiftmiddleupup, shiftrightup];
notrigger: LIST OF MenuEntryTrigger = LIST[];
Menu entries may specify different user actions as their triggers. Depending on the state of the shift key and which mouse button was used, different results may be obtained from bugging a menu entry. In addition, there is a standard way (holding control down and bugging) for users to request a list of all possible functions for a menu entry. This data type specifies all possible triggers; 'notrigger' means that the function may only be accessed through the general list, 'all' means that all possi ble triggers will produce the action.
targetNotFound: SIGNAL;
Some calls require locating entries by their names, a signal is raised if they don't exist:
Menu: TYPE = RECORD[
A 'menu' is a set of entries defined and manipulated as a group. A menu is uniquely identified by its name after it is registered with the viewers package. This is all designed for ease in 'passively' describing menus as data structures. If beginsActive is TRUE, the menu will be accessable to the user when the menu is added to a viewer. Each viewer has a list of menus associated with it, and they are "laid out" like text, as many as will fit onto a line. breakBefore and breakAfter can be used to force "line breaks" in the menus. 'notify' is the procedure to call with the input actions for the entries in the menu, when the menu entries are bugged by the user.
name: ROPE,
beginsActive: BOOLEANTRUE,
breakBefore: BOOLEANTRUE,
breakAfter: BOOLEANTRUE,
notify: ViewerClasses.NotifyProc ← NIL,
entries: LIST OF Entry ← NIL
];
Entry: TYPE = RECORD[
Menu entries are uniquely identified by name. 'guarded' indicates if the user will have to bug the entry twice in a small period of time to actually cause action to occur. If something other than the name of the entry should be displayed, this can be done by making 'displayData' either a Rope.ROPE (which will be displayed instead of the name), or a REF DrawingRec, which will draw the entry itself.
name: ROPE,
guarded: BOOLEANFALSE,
displayData: REF ANYNIL, -- must narrow to Rope.ROPE or DrawingRec
actions: LIST OF EntryNotifyRecord ← NIL
];
EntryNotifyRecord: TYPE = RECORD[
Menus may have more than one action associated with them. Each action has a record with the trigger(s) that causes the action, what to pass to the notify proc, and a ROPE to describe the action for use in the user interface. 'guardResponse' is used after the first mouse hit; the rope associated with the trigger is shown in the message window, or the indicated procedure is called. 'makeActive', 'makeInActive', and 'Toggle' specifiy the menus to affect when the trigger is handled, this makes it easy to describe typical menu actions in the data structure, rather than writing code to handle making menus active and inactive.
trigger: LIST OF MenuEntryTrigger ← NIL,
notifyData: LIST OF REF ANYNIL,
popupDoc: ROPE ← NIL,
guardResponse: REF ANYNIL, -- must narrow to Rope.ROPE or REF UnGuardRec
makeActive: LIST OF ROPENIL,
makeInActive: LIST OF ROPENIL,
toggle: LIST OF ROPENIL
];
DrawingRec: TYPE = RECORD [
proc: DrawingProc, -- procedure to call to do the drawing
data: REF ANYNIL -- will be passed as the 'clientData' parm to the procedure
];
UnGuardRec: TYPE = RECORD [
proc: UnGuardProc, -- procedure to call when menu becomes unguarded
data: REF ANYNIL -- will be passed as the 'clientData' parm to the procedure
];
DrawingProc: TYPE = PROC [op: ViewerClasses.MenuEntryDisplayOp, ctx: Imager.Context ← NIL, clientData: REF ANYNIL] RETURNS[width: INTEGER ← 64];
UnGuardProc: TYPE = PROC [clientData: REF ANYNIL];
operations to register menus with the viewers package:
RegisterMenu: PROC [menu: Menu];
The menu data is recorded by the viewers package and associated with the name in the record. All future references may be made through the name alone.
AlreadyRegistered: PROC [name: ROPE] RETURNS [registered: BOOLEAN];
returns TRUE iff a menu with the given name has been registered.
ReRegisterMenu: PROC [menu: Menu, paint: BOOLTRUE];
The previous definition of the menu is forgotten, and the new one takes its place. If 'paint' is true, all viewers containing the menu will be found and repainted with hint=menu.
GetRegisteredMenu: PROC [name: ROPE] RETURNS [menu: Menu];
The definition for the menu is returned
operations to attach menus to viewers:
ClearMenus: PROC [viewer: Viewer, paint: BOOLTRUE];
Any menus that had been associated with the viewer are no longer attached to the viewer. They are still registered with the viewers package, however. If 'paint' is true, the equivalent of a 'PaintViewer[viewer,hint=caption] will be done.
AddMenu: PROC [viewer: Viewer, name: ROPE, paint: BOOLTRUE, addBefore: ROPENIL];
The menu registered under the name 'name' is added to the viewer's list of menus. If 'addBefore' is non-NIL, the new menu will be added in the list before the menu with name 'addBefore'. If 'paint' is true, the equivalent of a 'PaintViewer[viewer,hint=caption] will be done.
MakeActive: PROC [viewer: Viewer, menu: ROPE, paint: BOOLTRUE];
'menu' is made accessable to the human user.
MakeInActive: PROC [viewer: Viewer, menu: ROPE, paint: BOOLTRUE];
'menu' is made inaccessable to the human user.
Toggle: PROC [viewer: Viewer, menu: ROPE, paint: BOOLTRUE];
If 'menu' is currently active, it is made inactive. Otherwise, it is made active.
MenuInViewer: PROC [viewer: Viewer, menu: ROPE] RETURNS [exists: BOOLEAN];
TRUE is returned if the menu already exists in the menu, FALSE otherwise.
operations to parse menu descriptions:
ParseDescription: PROC [def: Rope.ROPE, prevlist: LIST OF Menu ← NIL, errorFile: Rope.ROPE ← NIL] RETURNS [LIST OF Menu];
the rope is parsed for multiple menu descriptions, as laid out in MenuBNF.tioga. Any errors are written to "errorFile." If 'prevlist' is Non-nil, the returned list will be added to and "layered" on top of 'prevlist'. If 'errorFile' is NIL, errors will be written to "menus.errlog". If any errors are found, NIL will be returned.
END.