ETHZ_Logo RAMSES_Logo_Right   RAMSES   RAMSES_Logo_Left Systems Ecology  
Start    search button      Modules:   A-Z   Function   Layer        QuickRefs:   DM   AuxLib   AuxLibE   SciLib   EasyMW   MW   ISIS   RMSLib

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.

  Contact RAMSES@env.ethz.ch Last updated: 25-Jul-2011 [Top of page]