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.