                                                                           Menus
                                                                           Menus
                                                                           Menus





         "Ninety-eight percent of the adults in this country are decent, hard-
         working Americans. It's the other lousy two percent that get all the
         publicity. But then we elected them."

                                                                     Lily Tomlin







Introduction

         You want menus, we got menus!

         The Toolkit includes three main menu types: pop-up menus, Lotus-style
         menu bars and pull-down menus. All the menus can be nested many levels
         deep, i.e. when the user selects an item from a menu, another menu can
         be automatically displayed. You may optionally specify a description
         for any menu item, and when the user highlights the item, the descrip-
         tive text is automatically displayed. All the menus provide full mouse
         support, and if the mouse cursor drifts across a specific item, it is
         automatically highlighted. Menu items can also be selected with the
         cursor keys or by pressing a menu item hotkey.

         The object hierarchy includes a number of abstract objects, as illus-
         trated in figure 12.1. You should never declare an instance of type
         BaseMenuOBJ, WinMenuOBJ, BarMenuOBJ or KwikPullOBJ, as these are
         abstract. Use one of the following objects to display a menu:

         MenuOBJ            This object displays a simple menu in a window. This
                            object is commonly used for a program's main menu
                            which is displayed when the program starts.

         MoveMenuOBJ        This object is similar to MenuOBJ, except that the
                            user can drag the menu around the screen to view the
                            contents of the screen below.

         LotusMenuOBJ       The LotusMenuOBJ provides a 1-2-3 (or Paradox!)
                            style menu bar. The user scrolls left and right
                            along the menu bar.

         PullMenuOBJ        This is an "IDE-like" pull-down menu which supports
                            multiple levels of sub-menus.

         EZPullArrayOBJ     This objects provides a quick and easy way of
                            creating a sophisticated pull-down menu. All you
                            have to do is update a string array with the
                            individual item details, and instruct the Toolkit to
                            display the menu.

12-2                                                                User's Guide

--------------------------------------------------------------------------------

         EZPullLinkOBJ      This object is similar to the EZPullArrayOBJ, except
                            that the menu item details are added to a linked
                            list (of type DLLOBJ or descendant).



Figure 12.1                                                            [PICTURE]
Menu
Object Hierarchy



Common Methods

         All menus contain items, hotkeys, descriptions, and the like. The Tool-
         kit's varied menu objects share a variety of common methods which are
         used to construct the menu details and characteristics.



Adding Menu Item Details

         The following methods are used to set the individual menu details:


         Init;

         The Init method is passed no parameters, and should be called before
         any other menu method.


         AddItem(Txt:StrVisible);

         This method is used to add an item to the menu. The method is passed
         one parameter identifying the menu text to be displayed. The item
         string may include embedded highlight characters to indicate that a
         specific character is designated as a hot key -- refer to the WriteHi
         method on page 5-3 for further information. Special strings can be
         passed to force blanks or lines in the menu item list - see the note at
         the end of this section.


         The following methods may be called to further define the settings for
         each item. Note, however, that the item must have been added with AddI-
         tem (or AddFullItem) before these additional settings can be specified.


         SetHK(Item:byte; HK:word);

         Any item can be assigned a hotkey, which provides a way for the user to
         select the item without scrolling to the item. All the user does is
         press the hotkey. The de facto standard is to use normal alphabet char-
         acters as the hotkeys. (Lotus and pull-down menus support additional
         hotkeys which can be pressed even when the appropriate menu is not on
         display -- this subject is discussed in detail later).


Menus Menus Menus                                                           12-3

--------------------------------------------------------------------------------

         SetMessage(Item:byte; Msg:StrVisible);

         The SetMessage method is used to define a message for an item. When the
         item is highlighted, the message will be automatically displayed, and
         when the user moves to a different item, the message is removed. The
         Toolkit does not save the contents of the screen where the message is
         displayed.


         SetID(Item:byte; ID:word);

         In a menu system, which includes sub-menus, this method can be used to
         assign each topic in the menu a unique ID. The method is passed two
         parameters; the item number and the item ID. This ID is of type word,
         and will be returned by the menu method Activate if the item is
         selected by the user. Note that you should not use IDs greater than
         65000, because some of these IDs are used internally by the Toolkit.


         SetStatus(Item:byte, On:boolean);

         Sometimes, certain menu items will not be selectable. For example, a
         File Save option may not be operative until a file has been loaded or
         created. The SetStatus method is used to control whether an option is
         selectable. The method is passed two parameters; the item number and a
         boolean parameter. Set the boolean to TRUE to enable the item and FALSE
         to disable it.


         SetSubMenu(Item:byte; SubMenu:BaseMenuPtr);

         This method is used to indicate that another menu should be displayed,
         if the item is selected by the user. The Toolkit will automatically
         display the new menu below and to the right of the active menu. The
         method is passed two parameters; the item number and the address of the
         sub-menu object. Normally, you will call another menu instance of the
         same type as the parent, e.g. if the parent menu is of type MenuOBJ,
         then the sub-menu is usually of type MenuOBJ. This, however, is not
         mandatory, and any menu item can display a sub-menu of any type in the
         menu object hierarchy. Note that the second parameter is the address of
         the sub-menu, and is normally specified by preceding the menu object
         with the Turbo Pascal "@" address symbol. For example:

                     SetSubMenu(5,@FileMenu);


         When you want to specify all the menu item details, e.g. message, HK,
         sub-menu, etc., you can use the following all-in-one method:


         AddFullItem(Txt:StrVisible;ID,Hk:word; Msg:StrVisible; SubM:Baseme-
         nuPtr);



12-4                                                                User's Guide

--------------------------------------------------------------------------------

         As you may have guessed, this method is used to add a new item and
         specify its settings in one heavy statement! This method is a single
         replacement for five of the previous six methods. The only method that
         is not accommodated by AddFullItem is SetStatus, and the Status is set
         to true by default. Use one of the following values to suppress the
         setting of one or more of the item elements:

              No ID                  0
              No hotkey              0
              No message             ''
              No sub-menu            nil

         Listed below are two code fragments, both of which define the same
         three-item menu. The first code block uses the individual methods, and
         the second block takes advantage of AddFullItem. It doesn't matter
         which technique you use, so use the one which seems easiest to you.

         with MainMenu do
         begin
            Init;
            AddItem(' ~L~oad file ')
            SetID(1,1);
            SetHK(1,76);
            SetMessage(1,'Load a database file from disk');
            AddItem(' ~S~ave file ');
            SetID(2,2);
            SetHK(83);
            SetMessage(2,'Save the current database to disk');
            AddItem(' ~Q~uit ');
            SetID(3,99);
            SetHK(3,81);
            Setmessage(3,'Let''s party!');
            ...
         end;


         with MainMenu do
         begin
            Init;
            AddFullItem(' ~L~oad file ',1,76,'Load a database file from disk',-
         nil);
            AddFullItem(' ~S~ave file ',2,83,'Save the current database to
         disk',nil);
            AddFullItem(' ~Q~uit ',99,81,'Let''s party!',nil);
            ...
         end;


         Having created a menu, the following methods can be used to display,
         start, remove and dispose of the menu.



Menus Menus Menus                                                           12-5

--------------------------------------------------------------------------------

         Draw;

         This method instructs the object to draw itself. As soon as the menu is
         drawn, the method returns control back to your program, i.e. the object
         does not process any user input.


         Activate: word;

         This is the main "DO-IT!" method. If the menu is not already visible,
         the menu is drawn, and then the Toolkit processes user input until the
         user selects a menu item or ESCapes (if ESC is enabled). The function
         method returns the ID of the selected item. If the ID was never speci-
         fied, i.e. it is set to zero, the Toolkit will return the actual item
         number. Note, however, that this number is the item number in the
         currently displayed menu. In a system with sub-menus you will not know
         which sub-menu was on display. In a system with sub-menus, you should
         therefore always assign a unique ID to each selectable item. A zero is
         returned if the user escaped.


         Remove;

         This methods removes the menu. If the menu is of type MenuOBJ or Move-
         MenuOBJ, the underlying screen contents are restored. All other menu
         objects do not restore any underlying screen contents -- they simply
         erase the menu text.


         Done;

         When the menu is no longer required, call this method to dispose of the
         memory used internally by the menu.




Changing Menu Characteristics

         The following methods are used to control the general display charac-
         teristics of the menu:


         SetGap(G:byte);

         This method is used to create a space (or gap) to the left and right of
         each menu item. In a pop-up menu, this can be used to create a space
         between the menu border and the menu text. With Lotus and pull-down
         menus, this method creates a space between each item along the top menu
         bar. The method is passed one parameter; a byte representing the number
         of characters space to allow on either side of each menu item.


         SetMenuXY(X,Y: byte);



12-6                                                                User's Guide

--------------------------------------------------------------------------------

         This method is used to set the specific location of the menu on the
         screen. The method is passed two byte parameters representing the (X,Y)
         coordinate of the top left corner of the menu. With pop-up menus, the
         menu will be centered laterally and vertically if the X or Y parameter
         is set to zero.


         SetMesssageXY(X,Y:byte);

         This method is used to specify the location of the optional message
         which is displayed when a topic is highlighted. The method is passed
         two parameters representing the (X,Y) coordinate of the first character
         in the message.


         SetAllowEsc(On:boolean);

         This method is used to control whether the user may escape from the
         menu. It is passed a single boolean parameter, which should be set to
         TRUE to enable escape (the default), or FALSE to disable it.


         SetActiveItem(Item:byte);

         Normally, the first item in a menu is highlighted when the menu is
         first displayed. If this item is non-selectable, or if you want to
         highlight a different item, use the method SetActiveItem. The method is
         passed one byte parameter identifying the topic number of the item to
         be highlighted.


         The display colors are controlled by the menu item colors, and (in the
         case of pop-up and pull-down menus) the window display colors. All the
         colors default to values established by LookTOT. To change the look and
         feel of your menus, you should assign new default values to LookTOT.
         Refer to page 3-12 for a description of how to control the LookTOT
         defaults. The following two methods can be used to control the display
         colors of any individual menu:


         SetColors(HiHot,HoNorm,LoHot,LoNorm,Off:byte);

         This method changes the display colors of the individual menu items.
         The procedure is passed five byte parameters: the first two parameters
         control the display color of the menu highlight bar -- the first param-
         eter is the attribute of any highlighted text, e.g. the 'Q' in
         '~Q~uit', and the second parameter is the standard display color, e.g.
         the 'uit' part. The third and fourth parameters are the display attrib-
         utes for the un-selected (or normal) menu items, and the fifth parame-
         ter is the display attribute of inactive items. Note that this method
         automatically sets the window body display color to the parameter
         LoNorm.



Menus Menus Menus                                                           12-7

--------------------------------------------------------------------------------

         Win^.SetColors(Border,Body,Title,Icons: byte);

         In the case of pop-up and pull-down menus, this method sets the colors
         of the underlying window. Refer to page 7-6 for a general description
         of this window method.



Adding Lines and Gaps

         Sometimes, you may want to display a menu with some items separated
         from others. By specifying special item text, you instruct the Toolkit
         to draw special lines, or leave a gap. The following item text should
         be used:

         ''    A null string creates a gap in the menu.

         '-'   A string comprising entirely of the minus sign will result in a
               single horizontal line being drawn from the left to the right of
               the menu.

         '='   A string comprising entirely of the equals sign will result in a
               double horizontal line being drawn from the left to the right of
               the menu.

         For example, the following code fragment will force a blank line
         between the third and fourth selectable items, and draws a single line
         between the last two picks:

                  AddItem('Whips');
                  AddItem('Chains');
                  Additem('Rubber');
                  AddItem('');
                  AddItem('Hard Disks');
                  AddItem('Floppies');
                  AddItem('-');
                  AddItem('Quit');




           Note: even non-selectable menu items are recognized as items in
           the menu list. When you use one of the Set methods (described
           earlier), be sure to include the non-selectable items in the list.
           For example, in the above code fragment, the "Quit" item is item
           number 8 (not 6), and its hotkey could be set to "Q" with the
           following method call:

                              SetHK(8,ord('Q'));



12-8                                                                User's Guide

--------------------------------------------------------------------------------

Examples

         Listed below is the demo file DEMMN1.PAS, which illustrates how to
         create a simple menu using some of the methods already described. Fig-
         ure 12.2 illustrates the resultant display.

         program DemoMenuOne;
         {DEMMN1 - a basic menu}

         USES  DOS, CRT,
               totMENU, totFAST;

         var
           Main: MenuOBJ;
           Choice: byte;
         begin
            Screen.Clear(white,''); {paint the screen}
            with Main do
            begin
               Init;
               AddItem('');
               AddItem(' Load a file          ');
               AddItem(' Edit Date            ');
               AddItem(' Save the file        ');
               AddItem(' Change configuration ');
               AddItem('-');
               AddItem(' Quit                 ');
               SetStyleTitle(1,' Main Menu ');
               SetActiveItem(2);
               Choice := Activate;
               Done;
            end;
            if Choice = 0 then
               Writeln('You escaped')
            else
               Writeln('You selected menu item ',Choice);
         end.


Figure 12.2                                                             [SCREEN]
A Simple Menu



Creating Pop-Up Menus

         totMENU provides two objects for creating pop-up menus: MenuOBJ and
         MoveMenuOBJ. Both these objects create menus which are displayed in a
         window, the only difference being that MoveMenuOBJ creates moveable
         menus, i.e. menus that the user can drag around the screen.



Menus Menus Menus                                                           12-9

--------------------------------------------------------------------------------

         Both objects are descendant from BaseMenuOBJ and inherit the following,
         previously described, methods:

         Init;
         AddItem(Txt:StrVisible);
         SetHK(Item:byte; HK:word);
         SetMessage(Item:byte; Msg:StrVisible);
         SetID(Item:byte; ID:word);
         SetStatus(Item:byte, On:boolean);
         SetSubMenu(Item:byte; SubMenu:BaseMenuPtr);
         AddFullItem(Txt:StrVisible;ID,Hk:word; Msg:StrVisible; SubM:Baseme-
         nuPtr);
         Draw;
         Activate: word;
         Remove;
         SetGap(G:byte);
         SetMenuXY(X,Y: byte);
         SetMessageXY(X,Y:byte);
         SetAllowEsc(On:boolean);
         SetActiveItem(Item:byte);
         SetColors(HiHot,HoNorm,LoHot,LoNorm,Off:byte);
         Done;


         The menu is drawn on a window, and the following function methods can
         be used to called any of the window methods:


         Win: WinPtr;
         Win: MoveWinPtr;

         This function returns a pointer to the menu on which the menu is drawn.
         For MenuOBJ instances the method returns a pointer to WinOBJ, and for
         MoveWinOBJ it returns a pointer to MoveWinOBJ. Using the syntax
         Win^.method you may call any of the window methods.


         The menu window dimensions are automatically calculated from the width
         and number of menu items. You should therefore avoid calling the window
         method SetSize. As a convenience, the following method provides an easy
         way to change the menu style and title.


         SetStyleTitle(Style:byte; Tit:StrVisible);

         This method sets the style and title of the menu window. The style
         parameter is the same as the box style parameter discussed on page 5-7,
         and the title supports the special title characters discussed on page
         5-8.



12-10                                                               User's Guide

--------------------------------------------------------------------------------

         The first example shown at the end of the previous section illustrated
         how to create a MenuOBJ menu. The on-disk demo file DEMMN2.PAS shows
         how to create a moveable menu and control the display colors. Listed
         below is the demo file DEMMN3.PAS, which illustrates how to create a
         nested menu system. Figure 12.3 shows the generated menu.

         program DemoMenuThree;
         {DEMMN3 - nested pop-up menus}

         USES  DOS, CRT,
               totMENU, totFAST, totLOOK, totSYS;

         var
           Main,
           Load: MenuOBJ;
           Choice: byte;

         begin
            Screen.PartClear(1,1,80,24,white,''); {paint the screen}
            Screen.PartClear(1,24,80,25,30,' ');
            with Load do
            begin
               Init;
               AddItem('');
               AddFullItem(' ~1~  Accounts Payable    ',11,49,
                           'Load database ACTP1',nil);
               AddFullItem(' ~2~  Accounts Receivable ',12,50,
                           'Load database ACTR7',nil);
               AddFullItem(' ~3~  Net Assets Employed ',13,51,
                           'Load the ledger file',nil);
               AddFullItem(' ~4~  Net Cash Flow       ',14,52,
                           'Load the cash file',nil);
               SetStyleTitle(6,'Load Menu');
               SetActiveItem(2);
               SetMessageXY(25,25);
               SetGap(1);
               Win^.SetClose(False);
            end;
            with Main do
            begin
               Init;
               AddItem('');
               AddFullItem(' ~1~   Load a file         ',1,49,
                           'Loads a new database file',@Load);
               AddFullItem(' ~2~   Edit Date            ',2,50,
                           'Full screen editing of data base entries',nil);
               AddFullItem(' ~3~   Save the file        ',3,51,
                           'Save database file to disk',nil);
               AddFullItem(' ~4~   Change configuration ',4,52,
                           'Modify colors and defaults',nil);



Menus Menus Menus                                                          12-11

--------------------------------------------------------------------------------

               AddItem('');
               AddFullItem(' ~Q~   Quit                 ',99,81,
                           'Exit system and return to DOS',nil);
               SetStyleTitle(6,'Main Menu');
               SetActiveItem(2);
               SetMenuXY(0,4);
               SetMessageXY(25,25);
               SetGap(1);
               Win^.SetClose(False);
               Choice := Activate;
               Done;
               Load.Done;
            end;
            if Choice = 0 then
               Writeln('You escaped')
            else
               Writeln('You selected menu item ',Choice);
         end.


Figure 12.3                                                             [SCREEN]
Nested Pop-Up
Menus



Creating Lotus-style Menus

         Lotus-style menus are menu bars which occupy a single line, and the
         user scrolls left and right through the items. An optional description
         of the highlighted item is usually displayed on the line immediately
         below the menu bar.

         The LotusMenuOBJ object makes building Lotus-style menus easy. LotusMe-
         nuOBJ is descendant from BaseMenuOBJ, and inherits the following, pre-
         viously described, methods:

         Init;
         AddItem(Txt:StrVisible);
         SetHK(Item:byte; HK:word);
         SetMessage(Item:byte; Msg:StrVisible);
         SetID(Item:byte; ID:word);
         SetStatus(Item:byte, On:boolean);
         SetSubMenu(Item:byte; SubMenu:BaseMenuPtr);
         AddFullItem(Txt:StrVisible;ID,Hk:word; Msg:StrVisible; SubM:Baseme-
         nuPtr);
         Draw;
         Activate: word;
         Remove;
         SetGap(G:byte);
         SetMenuXY(X,Y: byte);


12-12                                                               User's Guide

--------------------------------------------------------------------------------

         SetMessageXY(X,Y:byte);
         SetAllowEsc(On:boolean);
         SetActiveItem(Item:byte);
         SetColors(HiHot,HoNorm,LoHot,LoNorm,Off:byte);
         Done;


         Listed below are the contents of the file DEMMN4.PAS, which uses these
         basic methods to build a simple single-level Lotus menu. Figure 12.4
         shows the resultant menu display.

         program DemoMenuFour;
         {DEMMN1 - a simple lotus menu}

         USES  DOS, CRT,
               totMENU, totFAST;

         var
           P: LotusMenuOBJ;
           Choice: byte;
         begin
            Screen.Clear(white,''); {paint the screen}
            with P do
            begin
               Init;
               AddItem('Worksheet');
               AddItem('Range');
               AddItem('Copy');
               AddItem('Move');
               AddItem('File');
               AddItem('Print');
               AddItem('Graph');
               AddItem('Data');
               AddItem('System');
               AddItem('Quit');
               SetActiveItem(1);
               SetGap(1);
               Choice := Activate;
               Done;
            end;
            GotoXY(1,5);
            if Choice = 0 then
               Writeln('You escaped')
            else
               Writeln('You selected menu item ',Choice);
         end.


Figure 12.4                                                             [SCREEN]
A Simple Lotus
Menu


Menus Menus Menus                                                          12-13

--------------------------------------------------------------------------------

         If the user is using a mouse to select an item, the item is selected
         when the user lets go of the mouse button. If the user holds down the
         mouse button, and drifts away from the menu surface, none of the items
         will be highlighted. If the user then releases the mouse button (while
         the mouse cursor is not over the menu surface), a special ID DriftID is
         returned by Activate. DriftID is declared as a constant in the totMENU
         unit. To recap, if the ID 0 is returned, the user escaped, and if
         DriftID is returned, the user drifted off the menu and selected no
         item. All other values indicate that the user chose a specific item
         from the menu.

         In addition to the inherited methods, LotusMenuOBJ objects support the
         following methods:


         SetSpecialKey(HK:word; ID:word);

         The hotkeys which are defined for each menu item allow the user to
         select the item by pressing the appropriate hotkey. However, only the
         hotkeys for the currently displayed menu are recognized. In a nested
         menu system, the SetSpecialKey method can be used to define hotkeys
         which will be recognized regardless of which menu level is being dis-
         played. The method is passed two parameters; the keycode of the hotkey
         and the ID which will be returned when the user presses this special
         key. Special hotkeys can be added in any order, and they do not have to
         correspond to any of the actual menu items. For example, you could add
         an [KEYCAP] key to return the value of 1000 with the following state-
         ment:

                  SetSpecialKey(301,1000);

         If the menu is active, and the user presses [KEYCAP], the menu will
         immediately end and return a value of 1000.


         Menukey(K:word; X,Y: byte): boolean;

         This method is passed three parameters defining the details of a key-
         press, i.e. the keycode, and the (X,Y) coordinate of the mouse when the
         key was pressed. The function method returns TRUE if the key's details
         are recognized by the menu, i.e. if the details represent a menu
         hotkey, or a mouse click on the menu surface.


         Push(K:word; X,Y: byte);

         The Activate method is used to start the menu and wait for user input.
         The Push method is similar to activate, except that the procedure is
         passed the key details for the first input to be processed. This method
         can be used in conjunction with MenuKey to test for a menu key and then



12-14                                                               User's Guide

--------------------------------------------------------------------------------

         process it. For example, the following code fragment prompts the user
         for input. If it is related to the menu, the menu is invoked, otherwise
         SomeOtherTask is called:

         var
           Lmenu: LotusMenuOBJ;
           K: word;
           X,Y: byte;
           Choice: word;

           procedure SetUpLMenu;
           {}
           begin
            with Lmenu do
            begin
               Init;
               {...}
               end;
           end;

           procedure SomeOtherTask(K:word;X,Y:byte);
           {}
           begin
              {...}
           end; {SomeOtherTask)}

         begin
            Screen.Clear(white,''); {paint the screen}
            SetUpLmenu;
            Choice := 0;
            Lmenu.Draw;
            Mouse.Show;
            Repeat
               K := Key.Getkey;
               X := Key.LastX;
               Y := Key.LastY;
               if Lmenu.Menukey(K,X,Y) then
                  Choice := Lmenu.Push(K,X,Y)
               else
                  SomeOtherTask(K,X,Y);
            Until (Choice <> 0) and (Choice <> DriftID);
            Mouse.Hide;
            writeln(Choice);
         end.


         Lotus menus can be nested many levels deep. Listed below is the demo
         file DEMMN5.PAS, which shows how to create nested menus. Figure 12.5
         shows the resultant display.



Menus Menus Menus                                                          12-15

--------------------------------------------------------------------------------

         program DemoMenuFive;
         {DEMMN5 - a nested Lotus menu}

         USES  DOS, CRT,
               totMENU, totFAST;

         var
           Main,
           Worksheet,
           Range: LotusMenuOBJ;
           Choice: word;

         procedure Pretend;
         begin
            Screen.Clear(31,' '); {paint the screen}
            Screen.WriteAt(1,4,48,replicate(80,' '));
            Screen.WriteCenter(4,48,'Not 1-2-3!');
            Screen.PartClear(1,5,4,25,48,' ');
         end; {Pretend}

         begin
            Pretend;
            with Worksheet do
            begin
               Init;
               AddFullItem('~G~lobal',100,71,'Global stuff',nil);
               AddFullItem('~I~nsert',101,73,'Insert stuff',nil);
               AddFullItem('~D~elete',102,68,'Delete stuff',nil);
               AddFullItem('~C~olumn',103,67,'Column stuff',nil);
               AddFullItem('~E~rase',104,69,'Erase stuff',nil);
               AddFullItem('~T~itles',105,84,'Titles stuff',nil);
               AddFullItem('~W~indow',106,87,'Window stuff',nil);
               AddFullItem('~S~tatus',107,83,'Status stuff',nil);
               AddFullItem('~P~age',108,80,'Page stuff',nil);
               AddFullItem('~H~ide',109,72,'Hide things',nil);
               SetActiveItem(1);
               SetGap(1);
            end;
            with Range do
            begin
               Init;
               AddFullItem('~F~ormat',200,70,'Format stuff',nil);
               AddFullItem('~L~abel',201,76,'Label stuff',nil);
               AddFullItem('~E~rase',202,69,'Erase stuff',nil);
               AddFullItem('~N~ame',203,78,'Name stuff',nil);
               AddFullItem('~J~ustify',204,74,'Justify stuff',nil);
               AddFullItem('~P~rot',205,80,'Protect stuff',nil);
               AddFullItem('~U~nprot',206,85,'Unprotect stuff',nil);
               AddFullItem('~I~nput',207,73,'Input stuff',nil);
               AddFullItem('~V~alue',208,86,'Value stuff',nil);



12-16                                                               User's Guide

--------------------------------------------------------------------------------

               AddFullItem('~T~rans',209,84,'Transpose stuff',nil);
               AddFullItem('~S~earch',209,83,'Search for things',nil);
               SetActiveItem(1);
               SetGap(1);
            end;
            with Main do
            begin
               Init;
               AddFullItem('~W~orksheet',1,87,
                           'Worksheet and global operations',@Worksheet);
               AddFullItem('~R~ange',2,82,
                           'Commands for manipulating data ranges',@Range);
               AddFullItem('~C~opy',3,67,
                           'Cell and range copying commands',nil);
               AddFullItem('~M~ove',4,77,'Cell and range moving commands',nil);
               AddFullItem('~F~ile',5,70,'File loading and saving operation-
         s',nil);
               AddFullItem('~P~rint',6,80,'Graph and spreadsheet printing',nil);
               AddFullItem('~G~raph',7,71,'Spreadsheet charting',nil);
               AddFullItem('~D~ata',8,68,'Database operations',nil);
               AddFullItem('~S~ystem',9,83,'Drop to the Operating System',nil);
               AddFullItem('~Q~uit',99,81,'Miller Time!',nil);
               SetActiveItem(1);
               SetGap(1);
               Choice := Activate;
               Done;
               Worksheet.Done;
               Range.Done;
            end;
            gotoxy(1,5);
            if Choice = 0 then
               Writeln('You escaped')
            else
               Writeln('You selected menu item ',Choice);
         end.




Figure 12.5                                                             [SCREEN]
Nested Lotus
Menus



Pull Down Menus

         The totMENU unit provides a number of objects to help you create pull-
         down menus like the one used in the Turbo Pascal integrated environ-
         ment. The main pull-down menu object is PullMenuOBJ, and it is a



Menus Menus Menus                                                          12-17

--------------------------------------------------------------------------------

         descendant of LotusMenuOBJ -- a pull-down menu is really a Lotus menu
         which calls pop-up menus when an item is selected from the main menu
         bar. The other pull-down menus are EZPullArrayOBJ and EZPullLinkOBJ,
         which allow you to quickly create a pull-down menu based on the con-
         tents of a string array or linked list, respectively. Hence the prefix,
         EZ!



PullMenuOBJ

         99% of Toolkit users will use the EZ objects, but before moving on to
         explain such shortcuts, the PullMenuOBJ object needs to be described in
         detail.

         PullMenuOBJ supports the following, previously described, methods:

         Init;
         AddItem(Txt:StrVisible);
         SetHK(Item:byte; HK:word);
         SetMessage(Item:byte; Msg:StrVisible);
         SetID(Item:byte; ID:word);
         SetStatus(Item:byte, On:boolean);
         SetSubMenu(Item:byte; SubMenu:BaseMenuPtr);
         AddFullItem(Txt:StrVisible;ID,Hk:word; Msg:StrVisible; SubM:Baseme-
         nuPtr);
         Draw;
         Activate: word;
         Remove;
         SetGap(G:byte);
         SetMenuXY(X,Y: byte);
         SetMessageXY(X,Y:byte);
         SetAllowEsc(On:boolean);
         SetActiveItem(Item:byte);
         SetColors(HiHot,HoNorm,LoHot,LoNorm,Off:byte);
         SetSpecialKey(HK:word; ID:word);
         Menukey(K:word; X,Y: byte): boolean;
         Push(K:word; X,Y: byte);
         Done;


         To build a pull-down menu using PullMenuOBJ, you create an object of
         type PullMenuOBJ, and one MenuOBJ object for each pull-down menu panel.
         When you add the items to PullMenuOBJ, the sub-menu parameter should be
         a pointer to the appropriate MenuOBJ instance. Listed below is the demo
         program DEMMN6.PAS, followed by figure 12.6 showing the display.

         program DemoMenuSix;
         {DEMMN6 - a simple pullmenu}
         USES  DOS, CRT,
               totMENU, totFAST;



12-18                                                               User's Guide

--------------------------------------------------------------------------------

         var
           Fmenu,
           Emenu: MenuOBJ;
           Pmenu: PullMenuOBJ;
           Choice: word;

         procedure InitSubmenus;
         {}
         begin
            with Fmenu do
            begin
               Init;
               AddFullItem(' ~O~pen...       ',101,79,'',nil);
               AddFullItem(' ~N~ew           ',102,78,'',nil);
               AddFullItem(' ~S~ave...       ',103,83,'',nil);
               AddFullItem(' S~a~ve as       ',104,65,'',nil);
               AddFullItem(' Save a~l~l      ',105,79,'',nil);
               AddItem('-');
               AddFullItem(' ~C~hange dir ...',106,67,'',nil);
               AddFullItem(' ~P~rint         ',107,80,'',nil);
               AddFullItem(' ~G~et info...   ',108,71,'',nil);
               AddFullItem(' ~D~OS shell     ',109,68,'',nil);
               AddFullItem(' E~x~it          ',110,88,'',nil);
               SetForPull;
            end;
            with Emenu do
            begin
               Init;
               AddFullItem(' ~R~estore line   ',201,82,'',nil);
               AddItem('-');
               AddFullItem(' Cu~t~            ',202,84,'',nil);
               AddFullItem(' ~C~opy           ',203,67,'',nil);
               AddFullItem(' ~P~aste          ',204,80,'',nil);
               AddFullItem(' Copy ~E~xample   ',205,69,'',nil);
               SetStatus(6,false);
               AddFullItem(' ~S~how clipboard ',206,83,'',nil);
               AddItem('-');
               AddFullItem(' C~l~ear          ',207,76,'',nil);
               SetForPull;
            end;
         end; {InitSubMenus}

         begin
            Screen.Clear(white,''); {paint the screen}
            Screen.PartClear(1,1,80,1,31,' ');
            InitSubMenus;
            with Pmenu do
            begin
               Init;



Menus Menus Menus                                                          12-19

--------------------------------------------------------------------------------

               AddFullItem('   ~F~ile   ',1,70,'',@Fmenu);
               AddFullItem('   ~E~dit   ',2,69,'',@Emenu);
               AddFullItem('   ~R~un    ',3,82,'',nil);
               SetID(3,3);
               Choice := Activate;
               Done;
            end;
            GotoXY(25,15);
            if Choice = 0 then
               Writeln('You escaped')
            else
               Writeln('You selected menu item ',Choice);
         end.




Figure 12.6                                                             [SCREEN]
A Simple Pull-down
Menu



         The demo program creates a pull-down menu with three elements on the
         menu bar: File, Edit and Run. A sub-menu is displayed when either of
         the first two items is selected. The program therefore requires three
         menu objects: a PullMenuOBJ to define the main menu bar, and two
         MenuOBJ objects to define the pull-down elements. Notice the method
         call SetForPull in both the MenuOBJ set-up routines. This method sets
         the characteristics of the MenuOBJ objects to fit in a pull-down menu
         environment, e.g. the border is set to 1, any titles are removed, etc.

         Also, notice that each selectable item is assigned a unique ID. When
         the user chooses an Item (which doesn't call a sub-menu), the item ID
         is returned by the method Activate or Push.

         If you want to add more sub-sub-menus, simply create additional MenuOBJ
         objects, and set a menu item to point to the sub-menu instance. For
         example, the following code fragment will result in a sub-menu being
         displayed when the Print option is selected from the file menu (it is
         assumed that PrintMenu is an instance of MenuOBJ):

               AddFullItem(' ~P~rint         ',106,80,'',@PrintMenu);

         As demonstrated by the third item "Run", items on the main menu bar do
         not have to call sub-menus. If the user selects Run from the main menu,
         an ID of three is returned.



12-20                                                               User's Guide

--------------------------------------------------------------------------------

EZ Pull-Down Menus

         The objects EZPullArrayOBJ and EZPullLinkOBJ provide a quick and easy
         way of building powerful pull-down menus. The basic principle of the EZ
         objects is that you define all the components of each menu item in a
         string, and then instruct the Toolkit to build a pull-down menu from
         the strings. The strings can either be stored in an array or in a
         linked list.

         Each string can have between one and four elements, with each element
         being separated by a double-quote ("). The first element is the menu
         item text, the second element is the message or menu description, the
         third element is the item ID, and the fourth element is an optional
         special hotkey which can be pressed anywhere in the menu hierarchy to
         select the item. The syntax of the string is as follows:

                     'menu text"description"ID"SpecialHK'

         For example, the following string declares the menu item "Open..." :

         ' ~O~pen...       "Locate and open a file in an edit window"201"316'

         You do not need to specify all four elements. For example, if the item
         does not have a special hotkey, omit the fourth part. If the item text
         includes a highlighted character, e.g. ~O~, the Toolkit will automati-
         cally assign that letter as the standard item hotkey.

         The strings in the array or list must be specified in the order that
         the picks will appear in the menu, and strings representing a main menu
         item must begin with the backslash character. If you want a topic to be
         non-selectable, start the string with an underscore, '_'. For example,
         the following strings could be used to create a menu similar to the
         DEMMN6.PAS program described earlier:

          '\ ~F~ile   ';
          ' ~O~pen...       "101'
          ' ~N~ew           "102'
          ' ~S~ave...       "103'
          ' S~a~ve as       "104'
          ' Save a~l~l      "105'
          '-'
          ' ~C~hange dir ..."106'
          ' ~P~rint         "107'
          ' ~G~et info...   "108'
          ' ~D~OS shell     "109'
          ' E~x~it          "110'
          '\  ~E~dit   '
          ' ~R~estore line  "201'
          '-'
          ' Cu~t~           "202'
          ' ~C~opy          "203'
          ' ~P~aste         "204'



Menus Menus Menus                                                          12-21

--------------------------------------------------------------------------------

          '_Copy ~E~xample   "205'
          ' ~S~how clipboard "206'
          '-'
          ' C~l~ear          "207'
          '\  ~R~un    "3'



           Note: the EZ objects can only be used to create a single-level
           pull-down menu. Refer to the section Adding Sub-Menus to see how
           to customize an EZ pull-down menu with sub-menus.


         The EZ pull object dynamically creates an instance of PullMenuOBJ, and
         as many MenuOBJ instances as needed to create the menu. The EZ pull
         objects include the following two function methods which allow you to
         directly access the internal PullMenuOBJ and MenuOBJ instances:


         MainMenu: PullMenuPtr;

         This function returns a pointer to the PullMenuOBJ instance used by the
         EZ object. You may change the characteristics settings of the instance
         by using the syntax Mainmenu^.method. For example, the following method
         will draw the main menu bar: Mainmenu^.Draw.


         SubMenu(MenuNumber: byte): SubMenuPtr;

         This function returns a pointer to one of the MenuOBJ instances, i.e.
         one of the first-level menu panels. You may change the characteristics
         of the instance by using the syntax Submenu(num)^.method.



EZPullArrayOBJ

         The EZPullArrayOBJ builds and displays a pull-down menu based on the
         contents of a string array. After calling Init, the following method
         should be called to pass the menu details to the object:


         AssignList(var StrArray; Total:longint; StrLength:byte);

         AssignList identifies the string array which contains the menu struc-
         ture. The method is passed three parameters; the string array, the
         total number of elements in the array, and the defined string length of
         each array element.


         Unlike other Toolkit objects such as List and Browse, the EZPullArray-
         OBJ copies the data from the string array. This means that, after
         assignment, you can dispose of the string array. The partial listing of




12-22                                                               User's Guide

--------------------------------------------------------------------------------

         the demo file DEMMN7.PAS (listed below), illustrates this technique.
         The string array is created locally in the procedure CreateMenu, and is
         automatically disposed of when the CreateMenu procedure finishes.

         The demo program is a mock-up of Turbo Pascal's own IDE menu (see
         Figure 12.7)

         program DemoMenuSeven;
         {DEMMN7 - using EZPull objects}
         USES  DOS, CRT,
               totMENU, totFAST;

         var
           Menu: EZPullArrayOBJ;
           Choice: word;

         procedure CreateMenu;
         {}
         var
           Mtxt: Array[1..84] of string[90];
         begin
            MTxt[1] := '\ p "System Commands';
            MTxt[2] := ' ~A~bout...  "Show version and copyright information-
         "100';
            MTxt[3] := ' ~R~efresh display "Redraw the screen"101';
            MTxt[4] := ' ~C~lear desktop   "Close all windows on the desktop,
         clear history lists"102';
            MTxt[5] := '\ ~F~ile "File management commands (Open, New, Save,
         etc.)';
            MTxt[6] := ' ~O~pen...       "Locate and open a file in an edit
         window"201';
            {...}
            MTxt[84] := ' ~H~elp on Help   "How to use online Help"1005';
            with Menu do
            begin
               Init;
               AssignList(MTxt,84,90);
            end;
         end; {CreateMenu}

         begin
            Screen.PartClear(1,2,80,24,white,''); {paint the screen}
            Screen.PartClear(1,1,80,1,31,' ');
            Screen.PartClear(1,25,80,25,31,' ');
            Screen.WritePlain(9,25,'');
            CreateMenu;
            with Menu do
            begin
               Choice := Push(13,0,0);   {Pass Enter to make menu pull down}
               Done;
            end;


Menus Menus Menus                                                          12-23

--------------------------------------------------------------------------------

            GotoXY(25,15);
            if Choice = 0 then
               Writeln('You escaped')
            else
               Writeln('You selected menu item ',Choice);
         end.



Figure 12.7                                                             [SCREEN]
An EZ Pull-down
Menu



EZPullLinkOBJ

         The EZPullLinkOBJ reads the menu definition from a linked list, i.e.
         from an instance of DLLOBJ or one of its descendants. After calling
         Init, the following method should be called to pass the menu details to
         the object:


         AssignList(var LinkList DLLOBJ);

         AssignList identifies the linked list which contains the menu defini-
         tion. The method is passed one parameter; an instance of DLLOBJ or a
         descendant, e.g. StrDLLOBJ.


         As with EZPullArrayOBJ, the data is copied from the linked list to the
         internal menu objects. Listed below is the demo program DEMMN8.PAS,
         which shows how EZPullLinkOBJ can be used to read a menu from disk.

         program DemoMenuEight;
         {DEMMN8 - reading a menu from disk}
         USES  DOS, CRT,
               totMENU, totFAST, totLINK;

         var
           Menu: EZPullLinkOBJ;
           Choice: word;

         procedure CreateMenu;
         {}
         var
           FileList: StrDLLOBJ;
           Retcode: integer;
           F: text;
           Line:string;
         begin
            assign(F,'DEMMN8.TXT');
            {$I-}




12-24                                                               User's Guide

--------------------------------------------------------------------------------

            reset(F);
            {$I+}
            if ioresult <> 0 then
            begin
               Writeln('Error: the file DEMMN8.TXT must be in the default
         directory!');
               halt(1);
            end;
            with FileList do
            begin
               Init;
               Retcode := 0;
               ReadLn(F,Line);
               while not eof(F) and (Retcode = 0) do
               begin
                  Readln(F,Line);
                  Retcode := Add(Line);
               end;
               close(F);
            end;
            with Menu do
            begin
               Init;
               AssignList(FileList);
               FileList.Done;
            end;
         end; {CreateMenu}

         begin
            Screen.PartClear(1,2,80,24,white,''); {paint the screen}
            Screen.PartClear(1,1,80,1,31,' ');
            Screen.PartClear(1,25,80,25,31,' ');
            Screen.WritePlain(9,25,'');
            CreateMenu;
            with Menu do
            begin
               Choice := Push(13,0,0);   {Pass Enter to make menu pull down}
               Done;
            end;
            GotoXY(25,15);
            if Choice = 0 then
               Writeln('You escaped')
            else
               Writeln('You selected menu item ',Choice);
         end.



Menus Menus Menus                                                          12-25

--------------------------------------------------------------------------------

Adding Sub-Menus

         The EZ objects provide a quick way of building a single level pull-down
         menu. If you want to have some sub-menus, you can still use the EZ
         objects. First call the AssignList method to create the main pull-down
         menu objects, and then create as many MenuOBJ instances as needed.
         Finally, use the SubMenu function method to access individual menu ele-
         ments and assign your own MenuOBJ instances to the appropriate menu
         item.

         Listed below is an extract of the demo file DEMMN9.PAS, which illus-
         trates this technique:

         program DemoMenuNine;
         {DEMMN9 - using a EZPull object with sub menus and hotkeys}
         USES  DOS, CRT,
               totMENU, totFAST;

         var
           Env,Watch: MenuOBJ;
           Menu: EZPullArrayOBJ;
           Choice: word;

         procedure CreateSubMenus;
         {}
         begin
            with Env do
            begin
               Init;
               SetForPull;
               AddFullItem(' ~P~references... ',8061,80,
                           'Specify desktop settings',nil);
               AddFullItem(' ~E~ditor...      ',8062,69,
                           'Specify editor settings',nil);
               AddFullItem(' ~M~ouse...       ',8063,77,
                           'Specify mouse settings',nil);
               AddFullItem(' ~S~tartup...     ',8064,83,
                           'Permanently change default startup options',nil);
               AddFullItem(' ~C~olors...      ',8065,67,
                           'Customize IDE colors for windows, menus, etc.',nil);
            end;
            with Watch do
            begin
               Init;
               SetForPull;
               AddFullItem(' ~A~dd watch...       ',7021,65,
                   'Insert a watch expression into the Watch window',nil);
               AddFullItem(' ~D~elete watch       ',7022,68,
                   'Remove the current watch expression from the Watch window',-
         nil);
               AddFullItem(' ~E~dit watch...      ',7023,69,


12-26                                                               User's Guide

--------------------------------------------------------------------------------

                   'Edit the current watch expression in the Watch window',nil);
               AddFullItem(' ~R~emove all watches ',7024,82,
                   'Delete all watch expressions from the Watch window',nil);
            end;
         end; {CreateSubMenus}

         procedure CreateMenu;
         {}
         var
           Mtxt: Array[1..84] of string[100];
         begin
            MTxt[1] := '\ p "System Commands';
            {...}
            MTxt[84] := ' ~H~elp on Help       "How to use online Help"1005';
            with Menu do
            begin
               Init;
               AssignList(MTxt,84,100);
            end;
         end; {CreateMenu}

         begin
            Screen.PartClear(1,2,80,24,white,''); {paint the screen}
            Screen.PartClear(1,1,80,1,31,' ');
            Screen.PartClear(1,25,80,25,31,' ');
            Screen.WritePlain(9,25,'');
            CreateMenu;
            CreateSubMenus;
            with Menu do
            begin
               SubMenu(7)^.SetSubMenu(2,@Watch);
               SubMenu(8)^.SetSubMenu(7,@Env);
               Choice := Activate
               Done;
               Env.Done;
               Watch.Done;
            end;
            GotoXY(25,15);
            if Choice = 0 then
               Writeln('You escaped')
            else
               Writeln('You selected menu item ',Choice);
         end.



Figure 12.8                                                             [SCREEN]
Nested Pull-down
Menus



Menus Menus Menus                                                          12-27

--------------------------------------------------------------------------------

Adding Help

         Adding help to menu objects is very similar to the ways described for
         other objects like DirWinOBJ. To add a help facility to any menu
         object, all you have to do is create a procedure following some spe-
         cific rules, and then call the menu method SetHelpHook to instruct the
         Toolkit to use your procedure.

         For a procedure to be eligible as a help hook, it must adhere to the
         following rules:

         Rule 1     The procedure must be declared as a FAR procedure. This can
                    be achieved by preceding the procedure with a {$F+} compiler
                    directive, and following the procedure with a {$F-} direc-
                    tive. Alternatively, Turbo 6 users can use the new keyword
                    FAR following the procedure statement.

         Rule 2     The procedure must be declared with one passed parameter of
                    type word. This parameter indicates the ID of the high-
                    lighted item at the time the user requested help.

         Rule 3     The procedure must be at the root level, i.e. the procedure
                    cannot be nested within another procedure.

         The following procedure declaration follows these rules:

                  {$F+}
                  procedure MyHelpHook(ID:word);
                  .....{procedure statements}
                  end;
                  {$F-}


         The following method SetHelpHook is then called to instruct the Toolkit
         to call your procedure when the user asks for help:


         SetHelpHook(PassedProc:HelpProc);

         This method is passed the procedure name of a procedure declared using
         the rules outlined above.


         Remember that if you are using an EZ object, you must access the Pull-
         MenuOBJ using the following statement:

                  Mainmenu^.SetHelpHook(YourProc);

