(******************************************************************************)
(*                                                                            *)
(*    The global constants and variables defined in this module are optional: *)
(* if you don't want to access their features, you needn't import them into   *)
(* your program. The variables in the parameter lists of the procedures are   *)
(* the only variables you are required to supply.                             *)
(*    When describing the order in which certain routines are called, I have  *)
(* adopted the curly-bracket notation of EBNF: routines in curly brackets {}  *)
(* may be called an arbitrary number of times (0 to n). A, {B}, {C, {D}} thus *)
(* implies that A is called once, followed by an arbitrary number of calls to *)
(* to B, followed by an arbitrary number of calls to C. Each of the calls to  *)
(* C may be followed by an arbitrary number of calls to D. Likewise, {{C},{D}}*)
(* implies an arbitrary number of calls to C and D in any order.              *)
(*                                                                            *)
(******************************************************************************)
(*                                                                            *)
(*  Version 1.00a.002 (Beta) :   March 2, 1988                                *)
(*                                                                            *)
(*    These procedures were originally written under version 1.20 of the TDI  *)
(* Modula-2 compiler. I have rewritten this module to operate under the v2.00 *)
(* compiler. However, should you find any problem or inconsistency with the   *)
(* functionality of this code, please contact me at the following address:    *)
(*                                                                            *)
(*                               Jerry Mack                                   *)
(*                               23 Prospect Hill Ave.                        *)
(*                               Waltham, MA   02154                          *)
(*                                                                            *)
(*    Check the module MenuUtils for TDI's (considerably less powerful) ver-  *)
(* sions of my Menu and IntuitionText procedures. The modules GadgetUtils and *)
(* EasyGadgets should also be of great help.                                  *)
(*                                                                            *)
(******************************************************************************)
(*                                                                            *)
(*    The source code to MenuTools is in the public domain. You may do with   *)
(* it as you please.                                                          *)
(*                                                                            *)
(******************************************************************************)

DEFINITION MODULE MenuTools;

FROM Intuition       IMPORT WindowPtr, MenuPtr, MenuFlags, MenuFlagSet,
                            MenuItemPtr, ItemFlags, ItemFlagSet, 
                            IntuitionTextPtr;
FROM Menus           IMPORT HighComp;
FROM Strings         IMPORT String;


CONST                  (* set Commandkey to this if you do not want a    *)
   NoKey  = " ";       (* key-equivalent for the current Item or SubItem *)

                    (* common assignments for ItemSetting & MenuSetting: *)
CONST
   Checkable = ItemFlagSet{CheckIt, MenuToggle};
   CheckNow  = ItemFlagSet{Checked};              (* requires Checkable  *)
   ItemOn    = ItemFlagSet{ItemEnabled} + HighComp;
   ItemOff   = ItemFlagSet{};
   MenuOn    = MenuFlagSet{MenuEnabled}; (* default value of MenuSetting *)
   MenuOff   = MenuFlagSet{};

VAR
   FirstMenu       : MenuPtr;        (* pointer to first Menu in Menu bar *)
   CurrentMenu     : MenuPtr;        (* current Menu    in Menu bar       *)
   CurrentItem     : MenuItemPtr;    (* current Item    in Menu bar       *)
   CurrentSubItem  : MenuItemPtr;    (* current SubItem in Menu bar       *)
   ItemPen         : INTEGER;        (* color of current  Item or SubItem *)
   ItemSelectPen   : INTEGER;        (* color of selected Item or SubItem *)
   LoneMenuStrip   : MenuPtr;        (* unattached, DISPOSEable MenuStrip *)
   SelectText      : String;         (* (Sub)Item text shown if selected  *)
   VerPixPerChar   : CARDINAL;       (* vertical   pixels per character   *)
   HorPixPerChar   : CARDINAL;       (* horizontal pixels per character   *)
   MenuSetting     : MenuFlagSet;    (* characteristics of current Menu   *)
   HiResScreen     : BOOLEAN;        (* high resolution screen?           *)
   AutoIndent      : BOOLEAN;        (* shift (Sub)Items to right?        *)
   RightJustify    : BOOLEAN;        (* extend select boxes to right?     *)
   Left, Top       : INTEGER;        (* left & top location and width &   *)
   Wide, High      : INTEGER;        (* height of current Menu, (Sub)Item *)
   NewItemColumn   : BOOLEAN;        (* flag: start new (Sub)Item column? *)

                                    (* all of these parameters are inputs *)
   PROCEDURE InitializeMenuStrip;

   PROCEDURE AddMenu    (MenuBarText : String);

   PROCEDURE AddItem    (ItemText    : String;
                         Commandkey  : CHAR;
                         ItemSetting : ItemFlagSet;
                         Exclusion   : LONGINT);
 
   PROCEDURE AddSubItem (SubItemText : String;
                         Commandkey  : CHAR;
                         ItemSetting : ItemFlagSet;
                         Exclusion   : LONGINT);

   PROCEDURE DestroyMenuStrip (WindowPointer : WindowPtr);


         (* Variables reset in PROCEDURE InitializeMenuStrip : *)
 
         (* CurrentMenu = NULL    MenuSetting   = MenuON       *)
         (* FirstMenu   = NULL    AutoIndent    = FALSE        *)
         (* SelectText  = NoText  HorPixPerChar = 8            *)
         (* MenuLeft    = 0       VerPixPerChar = 8            *)
         (* HiResScreen = FALSE   RightJustify  = TRUE         *)

 (* ItemSetting := Checkable + CheckNow --> this (Sub)Item can be and is  *)
 (* now checked; the routines above automatically set the ItemText flag.  *)

 (* Left, Top, Wide & High are recalculated in each subroutine to yield   *)
 (* a pleasing MenuStrip; if you dislike it, you may change them prior to *)
 (* calling AddMenu, AddItem and/or AddSubItem; also, Left & Wide affect  *)
 (* the placement of text in AddMenu but affect the placement and size    *)
 (* of the select boxes in AddItem and AddSubItem;                        *)

 (* To what are Left, Top, Wide and High measured relative? For Menus,    *)
 (* they are relative to the upper-left corner of the Screen. For Items,  *)
 (* they are relative to the lower-left corner of the Menu. For SubItems, *)
 (* they are relative to the lower-left corner of the Item.               *) 

 (* If AutoIndent = TRUE, all Items under the CurrentMenu (or all SubItems*)
 (* under the CurrentItem) will be shifted to the right to allow for a    *)
 (* checkmark. If AutoIndent = FALSE, then only those (Sub)Items which    *)
 (* request a checkmark in ItemSetting will be shifted to the right. The  *)
 (* amount of space added to the left of the select box depends upon the  *)
 (* value of HiresScreen.                                                 *)

 (* If RightJustify is TRUE, then the right edge of each Item extends to  *)
 (* the edge of its Menu. Otherwise, the right edge of each Item is deter-*)
 (* mined by the width of the longest Item in the current Item-column.    *)
 (* This is of most use when multiple Item-columns are desired: setting   *)
 (* RightJustify to TRUE ensures that the first column of Items isn't ex- *)
 (* cessively wide.                                                       *)
 
 (* If CommandKey <> NoKey, then space will be added to the right of the  *)
 (* (Sub)Item's select box according to the value of HiresScreen.         *)
 
 (* In addition, TextFlag is included in all Itemsetting values above,    *)
 (* since these routines are designed to create text Menus and (Sub)Items.*)

 (* HorPixPerChar and VerPixPerChar are used to determine the width and   *)
 (* height of the Menus, Items and SubItems. You may change these values  *)
 (* to quickly obtain larger select boxes.                                *)

 (* SelectText allows you to specify a different text be displayed when   *)
 (* the (Sub)Item is chosen, though it prevents use of other highlighting.*)
 (* SelectText = NoText upon exit from each of the above four procedures. *)
 (* As stated above, Left, Wide, Top and High are reset or recalculated   *)
 (* prior to exit from the above four routines. Don't change these values *)
 (* unless you know where you want a specific Menu or (Sub)Item placed.   *)
  
 (* CurrentMenu, CurrentItem and CurrentSubItem point to the Menu, Item   *)
 (* or SubItem, respectively, which was just added to the MenuStrip. Thus,*)
 (* if you require access to a particular node in the MenuStrip, you may  *)
 (* copy these pointers as needed following the call to AddMenu, AddItem  *)
 (* or AddSubItem.                                                        *)
 
 (* DestroyMenuStrip is designed to remove a MenuStrip from a Window and  *)
 (* DISPOSE of its Menus, Items and SubItems, as well as the IntuitionText*)
 (* structures to which they point. ANY non-NULL pointer in the MenuStrip *)
 (* has its contents DISPOSED. If you wish only to DISPOSE of a MenuStrip *)
 (* (one that is not attached to a Window), then set WindowPointer to NULL*)
 (* and assign LoneMenuStrip to the MenuStrip of which to DISPOSE. Just   *)
 (* prior to exit, DestroyMenuStrip calls InitializeMenuStrip. Thus, you  *)
 (* need only call InitializeMenuStrip for the first MenuStrip and if you *)
 (* want multiple MenuStrips defined at one time. I didn't call the pro-  *)
 (* cedure in the module body because it looked unusual to call it for the*)
 (* second and subsequent concurrent MenuStrips but not the first.        *)
 
 (* You can easily create multiple MenuStrips by calling InitializeMenu-  *)
 (* Strip once for each MenuStrip. Be sure to save the value of FirstMenu *)
 (* prior to the call, as that is the pointer to the first Menu of the    *)
 (* current MenuStrip.                                                    *)

 (* Since the IntuiText routines above are used to create the Intuition-  *)
 (* Text structures for the MenuStrip, you may change the values of the   *)
 (* global variables associated with those routines to obtain different   *)
 (* text attributes (color, font, etc.) for your MenuStrip.               *)
 
 (* The colors of Items and SubItems can be changed by varying ItemPen and*)
 (* ItemSelectPen. ItemPen assigns the foreground color of the (Sub)Item  *)
 (* as it normally appears; ItemSelectPen assigns the foreground color it *)
 (* assumes when selected.                                                *)
  
 (* Be sure to add at least one Item to each Menu to prevent a crash.     *)
 
 (* In case you haven't figured it out, the order in which you call these *)
 (* routines is as follows:  InitializeMenuStrip, {AddMenu,  AddItem,     *)
 (* {AddSubItem}, {AddItem, {AddSubItem}}}, DestroyMenuStrip.             *)

 
END MenuTools.
