|
|
|
|
||
|
DEFINITION MODULE DMMenus; (******************************************************************* Module DMMenus ('Dialog Machine' DM_V3.0) Copyright (c) 1985-2006 by Andreas Fischlin, Alex Itten, Klara Vancso and ETH Zurich. Purpose Manages menus on behalf of a 'Dialog Machine' program. Remarks Menus allow the user to activate actions of an application program. A so-called menubar, which contains a list of pulldown menus which can be activated by clicking the mouse on the particular menu-title in the menubar, is always displayed. While keeping the mouse button pressed, a menu item may be selected by releasing the button over a particular item, i.e. the associated command is issued to the application program, which will respond with the appropriate action. Method: Commands associated with a procedure may be installed and associated with a particular item of a menu. Menus have to be installed one after the other from left to right (note, it is not possible to install a command in the apple menu, except for the so-called "About feature …"). They contain command items which have to be installed from top to bottom one after the other. The sequence in which menus and commands are installed determines their relative positions to each other and hence must be obeyed carefully: menu1, command 1 of menu 1, command 2 of menu 1 ..., menu 2, command 1 of menu 2, command 2 of menu 2 ... etc. Further facilities are provided for the definition, redefinition, as well as the usage of menus. This module belongs to the 'Dialog Machine'. Programming o Design Andreas Fischlin 22/11/1985 o Implementation Andreas Fischlin 22/11/1985 Alex Itten 22/12/1986 Klara Vancso 08/04/1987 ETH Zurich Systems Ecology CHN E 35.1 Universitaetstrasse 16 8092 Zurich SWITZERLAND URLs: <mailto:RAMSES@env.ethz.ch> <http://www.sysecol.ethz.ch> <http://www.sysecol.ethz.ch/SimSoftware/RAMSES> Last revision of definition: 23/11/1992 AF *******************************************************************) (*******************************************) (*##### Preparation of a menu bar #####*) (*******************************************) TYPE Menu; (*denotes a particular menu*) Command; (*denotes a particular command within a menu*) VAR MenusDone: BOOLEAN; (*indicates whether any of the following installation procedures has been called successfully*) notInstalledMenu: Menu; notInstalledCommand: Command; (* Read only variables which may be used for variables of type Menu resp. Command to denote that they have not yet been installed, i.e. neither InstallMenu nor InstallCommand have been called. It is a good programming practice to assign this value to all menu respectively command variables during the initialization phase. *) PROCEDURE InstallAbout(s: ARRAY OF CHAR; w,h: CARDINAL; p: PROC); (* Installs an about function in the apple menu informing the user about the running program. String s is installed as the first item(s) of the apple menu. In case more than one item (several lines of text) are to be installed, the various entries may be separated with "|". All entries will be associated with the same procedure p and this feature is most useful if p which makes no output at all. When p is called and w>0 and h>0, then the Dialog Machine will create in the middle of the screen an about window with width w and height h. This window is the current output window (see Module DMWindIO) and it is ready for any output made by procedures from DMWindIO. E.g. you may want to draw with a predefined picture, or draw an animation, or write into that window. In the centre of the lower portion of the window an ok button will be automatically installed. The whole window will be removed if user clicks the ok button. p must only consist of procedures offered by module DMWindIO. In case this procedure is never called, a default about procedure will be automatically installed by the "Dialog Machine" . Note that SetLanguage from module DMLanguage clears any eventually already installed about. Hence, call this procedure after DMLanguage.SetLanguage. *) PROCEDURE NoDeskAccessories; (* Has to be called if no desk accessories are to be listed in the apple menu. By default all currently available desk accessories will be installed in the apple menu. *) TYPE AccessStatus = (enabled, disabled); Marking = (checked, unchecked); PROCEDURE InstallMenu(VAR m: Menu; menuText: ARRAY OF CHAR; ast: AccessStatus); (* Install menu m with title menuText (shown in menu bar), and initial status ast. Calling this procedure enables the subsequent installation of commands belonging to this menu. *) PROCEDURE InstallSubMenu (inMenu: Menu; VAR subMenu: Menu; menuText: ARRAY OF CHAR; ast: AccessStatus); (* The same as the procedure InstallMenu except that the menu subm is installed as a submenu in menu inm instead of a command which would be installed by calling InstallCommand(inm,nextcmd...). The menuText will appear within the list of the menu inm where normally the command text of the command would have appeared. At this position a triangle will become visible to indicate that the command is not an ordinary command but has a submenu attached to it. Note that it is not possible to access this position like an ordinary menu command, it just functions as the menu text of the submenu. In particular note that there is no procedure attached to it, and it can't have a keyboard equivalent, nor can it be checked. Once the submenu is installed use it as any other menu by installing commands subc by means of procedure InstallCommand(subm,subc,... etc. *) PROCEDURE InstallCommand(m: Menu; VAR c: Command; cmdText: ARRAY OF CHAR; p: PROC; ast: AccessStatus; chm: Marking); (* Install command c in menu m with command text cmdText. The command text is displayed in a pull-down menu in case the mouse is clicked on the corresponding menu title within the menu bar. Procedure p will be associated with this command, i.e. a command may be issued by releasing the mouse button over a particular menu item or by typing the corresponding AliasChar (pressing Command key simultaneously with the key shown to the right of the menu item, just after the clover symbol (see procedure InstallAliasChar)) from the keyboard. Such a command activation results in a call to procedure p if the current activation status is enabled (otherwise no action takes place). The parameters ast (enabled/disabled) and chm (with/without check mark) determine the initial status of the command, which may be changed while the "Dialog Machine" is running by calling one of the procedures EnableCommand, DisableCommand, CheckCommand, UncheckCommand (There is always the same checking character used, the check mark; it is displayed to the left of the command text). The command text cmdText may also be changed while the "Dialog Machine" is running by calling procedure ChangeCommandText. *) PROCEDURE InstallAliasChar(m: Menu; c: Command; ch: CHAR); (* Install alternative keyboard activation for command c in menu m. Pressing the Command (clover-leaf) key together with ch results in the activation of the procedure which has been associated with this command (given the command is currently enabled). *) TYPE Separator = (line, blank); (*between commands of a menu*) PROCEDURE InstallSeparator(m: Menu; s: Separator); (* Install in menu m after the last command a separator, which may be either a blank or a dotted line. *) PROCEDURE SetCheckSym(m: Menu; c: Command; ch: CHAR); (* Use in the following the symbol ch as the check mark. The default check mark is ASCII dc2, i.e. 22C (decimal 18), the diamond symbol is ASCII dc3, i.e. 23C (decimal 19) and the apple symbol is ASCII dc4, i.e. 24C (decimal 20). (NOTE: Implementation restricition: only characters with ordinal number <= 128 (200C) can be used). *) TYPE QuitProc = PROCEDURE(VAR BOOLEAN); (* This Procedure will be called if the user select the quit command. Then it's possible to abort the quitting mechanism by returning FALSE in the VAR parameter. *) PROCEDURE InstallQuitCommand(s: ARRAY OF CHAR; p: QuitProc; aliasChar: CHAR); (* Install a quit command in the first menu to the right of the apple menu after the last previously installed command. In case this procedure is inadvertently not called, a default procedure will be installed automatically. Before the quit command there is also a separator inserted automatically, if the user has not already installed one himself. For the meaning of the aliasChar parameter see procedure InstallAliasChar. It is recommended to use only 'Q' or 0C (none) as the aliasChar for a quit command. Note: InstallQuitCommand will have no effect in case that HideSubQuit has been called on the current subprogram level. In contrast to most other menu commands the quit command text s, can not be changed via procedure ChangeCommandText. To change the text s of an already installed quit command, call InstallQuitCommand again; it will overwrite any eventually already installed command text. To change the aliasChar use procedure ChangeQuitAliasChar. *) PROCEDURE HideSubQuit(onLevel: CARDINAL); PROCEDURE ShowSubQuit(onLevel: CARDINAL); (* On subprogram levels, given the 'Dialog Machine' is already running on a lower subprogram level than 'onLevel', these procedures allow to prevent (HideSubQuit) respectively reallow (ShowSubQuit) the preceeding or any subsequent installation of quit commands on level 'onLevel'. *) PROCEDURE InstallPredefinedMenu (fileName: ARRAY OF CHAR; menuID: INTEGER; VAR m: Menu); PROCEDURE InstallPredefinedSubMenu (fileName: ARRAY OF CHAR; menuID: INTEGER; inMenu: Menu; VAR subMenu: Menu); PROCEDURE InstallPredefinedCommand (fileName: ARRAY OF CHAR; menuID, itemNr: INTEGER; m: Menu; VAR c: Command; p: PROC); PROCEDURE InstallPredefinedSeparator(fileName: ARRAY OF CHAR; menuID, itemNr: INTEGER; m: Menu); (* Instead of calling InstallMenu, InstallSubMenu, InstallCommand, or InstallSeparator it is possible to retrieve the menu and command attributes such as the texts, alias chars, checkmarks, enable/disable status etc. from predefined specifications contained in so-called menu resources. Such a resource is the standard Macintosh resource of the type "MENU" with ID = menuID contained in the resource fork of the file fileName. In the case that the fileName passed is empty, the default search strategy to find the resource is followed, i.e. attempts are made to find the resource first within the currently running application's resource fork, then if not found in the system file's resource fork (see also the description of the procedure DMStrings.LoadString). Commands, separators, and sub menu entries are numbered consecutively starting with number 1 from top of the menu. Note that separators as well as sub menu entries are also menu items are numbered the same as ordinary commands. Note also that alias chars are normally specified in the resources of the type "MENU", hence there is no need to call InstallAliasChar in addition to InstallPredefinedCommand. The latter will do it for you. Example of a typical usage: InstallPredefinedMenu ("MyMenu.R",128,myMenu); itemNr := 1; InstallPredefinedCommand ("MyMenu.R",128,itemNr,myMenu,myCmd1, Cmd1); INC(itemNr); InstallPredefinedSeparator("MyMenu.R",128,itemNr,myMenu); INC(itemNr); InstallPredefinedSubMenu("MyMenu.R",129,myMenu,mySubMenu); subItemNr := 1; INC(itemNr); InstallPredefinedCommand("MyMenu.R",129,subItemNr,mySubMenu,mySubCmd1, SubCmd1); INC(subItemNr); InstallPredefinedCommand("MyMenu.R",129,subItemNr,mySubMenu,mySubCmd2, SubCmd2); INC(subItemNr); InstallPredefinedCommand ("MyMenu.R",128,itemNr,myMenu,myCmd2, Cmd2); INC(itemNr); *) PROCEDURE SaveAsPredefinedMenu(fileName: ARRAY OF CHAR; menuID: INTEGER; m: Menu); PROCEDURE SaveAsPredefinedMenuSection (fileName: ARRAY OF CHAR; menuID: INTEGER; m: Menu; maxItemNr: INTEGER); (* These procedrues allow to save all current menu specifications, including all command texts, alias chars etc., including any eventual submenus, which belong to this menu to be saved as a resource of the type "MENU" with ID = menuID in the resource fork of the file fileName. Note that after program termination, any association of commands with procedures is lost and has to be reestablished if the resource is to be used during the next program execution. SaveAsPredefinedMenuSection stores menu items (they include not only commands but also separators) only up to maxItemNr. To read and use saved menu specifications, use the procedures InstallPredefinedMenu, InstallPredefinedSeparator, InstallPredefinedCommand etc. as described above. For the searching strategy of files see the description of the procedure DMStrings.StoreString. IMPORTANT NOTE: Due to some idiosynchracies in the format of the resources of type 'MENU' there hold some restrictions: First, you should make sure to call SaveAsPredefinedMenu first for all child submenus before saving any menus which are parent menus. Second, make sure that menuIDs are always > 128 and that no menuID > 255 is used for a submenu. Otherwise the connection between parent and child menus will not be properly saved and will have to be corrected manually, e.g. by means of the resource editor ResEdit. *) (*************************************************) (*##### Display and usage of a menu bar #####*) (*************************************************) PROCEDURE UseMenu(m: Menu); (* Displays the individual menu m within the menu bar and makes it immediately ready for subsequent usage by the "Dialog Machine". Calling this procedure disables all further installations of commands belonging to this menu. Typically this procedure is called after the additional installation of a menu, i.e. while the "Dialog Machine" is already running. It needs not to be called during the very first installation phase of the "Dialog Machine" (i.e. before calling procedure DMMaster.RunDialogMachine for the first time), since the "Dialog Machine" calls the procedure UseMenuBar automatically (see also procedures RemoveMenu, UseMenuBar, and RemoveMenuBar). *) PROCEDURE UseMenuBar; (* Rebuilds, displays, and activates the whole menu bar, containing all sofar defined menus, for subsequent usage by the "Dialog Machine". Calling this procedure disables all further installations of commands. Usually, an application does not call this procedure, since it is automatically called by the "Dialog Machine". However, typically this procedure is called after procedure RemoveMenuBar has been called. *) PROCEDURE EnableDeskAccessories; (*affects all desk acessories*) PROCEDURE DisableDeskAccessories; (*affects all desk acessories*) PROCEDURE EnableMenu(m: Menu); (*enable menu m*) PROCEDURE DisableMenu(m: Menu); (*disable menu m*) (* (Note: enabling or disabling a menu leaves the individual commands unaffected, e.g. enabling a menu does NOT enable all its commands at once, but just resumes the status for all commands as it was before disabling the menu the last time). *) (* Implementation restricition: Don't call the above procedures from another than a menu command procedure (directly or indirectly) such as from within a handler. Calling them via menu commands only will ensure an always correct display of the menu bar according to current status. *) (*Enable, disable, check, or uncheck command c in menu m: *) PROCEDURE EnableCommand(m: Menu; c: Command); PROCEDURE DisableCommand(m: Menu; c: Command); PROCEDURE CheckCommand(m: Menu; c: Command); PROCEDURE UncheckCommand(m: Menu; c: Command); PROCEDURE ChangeCommand(m: Menu; c: Command; p: PROC); (* Reconnects anew the procedure p with the command c in menu m. *) PROCEDURE ChangeCommandText(m: Menu; c: Command; newCmdText: ARRAY OF CHAR); PROCEDURE ChangeAliasChar(m: Menu; c: Command; newCh: CHAR); PROCEDURE ChangeQuitAliasChar(onLevel: CARDINAL; newAliasCh: CHAR); (* Change alias char of quit command on (sub)program level 'onLevel'. *) PROCEDURE ExecuteCommand(m: Menu; c: Command); (* Execute the command c from menu m by calling associated procedure p (see above under installation). NOTE: Typically this procedure is automatically called by module DMMaster and an application program should NOT call it. *) PROCEDURE ExecuteAbout; (* Execute the installed about procedure on the current sub program level of the Dialog Machine. *) (***************************************************) (*##### Removing menu bar or its elements #####*) (***************************************************) PROCEDURE RemoveMenu(VAR m: Menu); (* Removes individual menu m. Typically this procedure is called after the additional installation and activation of an individual menu (pairs up with procedure UseMenu) in order to remove just those menus, which have been installed while the "Dialog Machine" has been running, leaving the remaining menus intact. *) PROCEDURE RemoveCommand(m: Menu; VAR cmd: Command); (* Removes individual command cmd in menu m. Typically this procedure is called after the additional installation and activation of an individual command in a menu which is already in use. This allows to remove just those commands, which have been installed while the "Dialog Machine" has been running, leaving the menu as such intact. *) PROCEDURE RemoveSeparator(m: Menu; s: CARDINAL); (* Removes individual separator s in menu m. Separators are numbered within a menu starting with number 1 for the topmost separator and so on (Note that the number is NOT the position within the menu, but the number of the separator). *) TYPE SeparatorPosition = (beforeCmd, afterCmd); PROCEDURE RemoveSeparatorAtCommand(m: Menu; cmd: Command; sp: SeparatorPosition); (* Removes individual separator s in menu m before or after the command cmd. In case there should actually be no separator present right before or after cmd, the procedure will leave the menu untouched. In contrast to RemoveSeparator, this routine allows to remove separators relative to a command, without having to know the absolute position within the whole menu. *) PROCEDURE RemoveMenuBar; (* Removes the whole, current menu bar, i.e. all menus with all commands, including the items installed in the desk accessory (apple) menu by calling InstallAbout. Any installations are lost and an eventual subsequent usage of the menu bar requires new installations. IMPORTANT IMPLEMENTATION RESTRICTION: Using this procedure is dangerous, since it is a means to impair a basic functionality of the "Dialog Machine", i.e. to provide the user always with means to quit the "Dialog Machine" program. Consequently, once RemoveMenuBar has been called, it becomes the progammer's responsibility to reinstall menus and activating them by calling UseMenu, in particular also to call InstallQuitCommand. Of course an alternative is to call again simply UseMenuBar or RunDialogMachine to leave it to the "Dialog Machine" to provide this minimum functionality. *) (**************************************************************************) (*##### Accessing information stored in menu and command objects #####*) (**************************************************************************) PROCEDURE MenuExists(m: Menu): BOOLEAN; PROCEDURE CommandExists(m: Menu; c: Command): BOOLEAN; (* Return information whether the object Menu and/or Command are currently installed in the Dialog Machine *) PROCEDURE GetMenuAttributes(m: Menu; VAR menuNr: CARDINAL; VAR menuText: ARRAY OF CHAR; VAR ast: AccessStatus; VAR isSubMenu: BOOLEAN; VAR parentMenu: Menu); PROCEDURE GetCommandAttributes(m: Menu; c: Command; VAR cmdNr: CARDINAL; VAR cmdText: ARRAY OF CHAR; VAR p: PROC; VAR ast: AccessStatus; VAR chm: Marking; VAR chmCh, aliasCh: CHAR); PROCEDURE IsCommandChecked(m: Menu; c: Command): BOOLEAN; PROCEDURE MenuLevel(m: Menu): CARDINAL; PROCEDURE CommandLevel(m: Menu; c: Command): CARDINAL; (* Return the level of the sub-program on which the menu m respectively the command c have been created. If m resp. c do not exist DMSystem.startUpLevel-1, i.e. 0 is returned. *) END DMMenus.
|
||
|
|
|