                                                                     Controlling
                                                                            User
                                                                           Input





         "I'm sick of writing documentation."              Bob Ainsbury







Introduction

         The Toolkit includes three major units to help you prompt the user for
         input: totIO1, totIO2 and totIO3. These units provide more than 20
         different input objects to accommodate all of your user input needs.
         Objects may be used individually to prompt a user for input, or
         combined together to build a powerful input form or dialog box.

         There are objects to prompt for strings, numbers, dates, word-wrapping
         memo fields, radio buttons, check boxes and lists. In the unlikely
         event that there is no object type to support your specific needs, you
         can create your own customized input objects.



Two Quick Examples

         The Toolkit form input facilities are powerful and extensive, but you
         don't need to understand every feature and facility to use them! Here
         are a couple of examples to prove the point.

         The following example, DEMIO1.PAS, is a simple program which prompts
         the user to enter a real number.

         program DemoIOOne;
         {demIO1 - single field input}

         Uses DOS, CRT,
              totFAST, totIO1, totIO2;

         Var
            Price: FixedRealIOOBJ;

         begin
            ClrScr;
            with Price do
            begin
               Init(35,5,8,2);
               SetLabel('How much was the doppleganger? ');
               SetValue(250.0);
               SetMinMax(0.1,12250.0);
               SetRules(EraseDefault);
               Activate;
               Writeln;writeln('You entered ',GetValue);

11-2                                                                User's Guide

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

               Done;
            end;
         end.


         Let's analyze the program. At the top of the program is the declaration
         of a variable called Price, which is of type FixedRealIOOBJ. All form
         input fields have object names ending in "IOOBJ", which stands for
         input-output object. The FixedRealIOOBJ object is for the input of real
         numbers which have a fixed number of decimal places.

         In the main part of the program, only the three bold statements are
         mandatory. The Init statement initializes the field. The four parame-
         ters represent the (X,Y) coordinate of the first character in the
         field, the number of whole digits, and the number of decimal places,
         respectively. In this example, the field will be located in column 35,
         row 5, with 8 significant digits, and 2 decimal places. The Activate
         command instructs the Toolkit to display the field and wait for user
         input. The Done method disposes of the object.

         The other statements are used to customize the field. Any input field
         can have a label, and usually, the label is displayed to the immediate
         left of the field. The SetLabel method assigns a label to the input
         field. By default, the field will have an initial value of zero. The
         SetValue method is used to assign an initial default value of 250.0. As
         you may have guessed, the SetMinMax method ensures that the user inputs
         a number within a specified range. Figure 11.1 shows the error message
         generated by the user when an invalid number is entered. The SetRules
         method instructs the Toolkit to erase the default value if the user
         first presses a non-editing key, e.g. a number.

         The function method GetValue returns the value entered by the user.



Figure 11.1                                                             [SCREEN]
Automatic Input
Validation



         The second example, DEMIO2.PAS, shows how to combine a number of fields
         into a full screen input form:

         program DemoIOTwo;
         {demIO2 - full field input}

         Uses DOS, CRT,
              totFAST, totIO1, totIO2;



Controlling User Input                                                      11-3

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

         Var
            Name: LateralIOOBJ;
            Phone: PictureIOOBJ;
            Price: FixedRealIOOBJ;
            Keys: ControlkeysIOOBJ;
            Manager: FormOBJ;
            Result: tAction;

         procedure InitVars;
         {}
         begin
            with Name do
            begin
               Init(35,5,20,40);
               SetLabel('Vendor Name');
            end;
            with Phone do
            begin
               Init(35,7,'(###) ###-####');
               SetLabel('Tel');
            end;
            with Price do
            begin
               Init(35,9,8,2);
               SetLabel('Unit Price');
               SetValue(250.0);
               SetMinMax(0.1,12250.0);
               SetRules(EraseDefault);
            end;
            Keys.Init;
         end; {InitVars}

         begin
            ClrScr;
            Screen.TitledBox(15,3,65,11,76,79,78,2,' Quicky Input Demo ');
            Screen.WriteCenter(25,white,'Press TAB to switch fields and
                                         press ESC or F10 to end');
            InitVars;
            with Manager do
            begin
               Init;
               AddItem(Keys);
               AddItem(Name);
               AddItem(Phone);
               AddItem(Price);
               Result := Go;
               if Result = Finished then
                  {update the database..}
               else



11-4                                                                User's Guide

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

                  {call Esc routine};
            end;
         end.


         In this example, there are three input fields which prompt the user to
         input a name, a telephone number and a unit price. The object Keys, of
         type ControlKeysIOOBJ, is used to control which keys allow the user to
         switch between fields and terminate the input session. By default, the
         following keys are supported [KEYCAP], [KEYCAP], [KEYCAP] and [KEYCAP].

         Every full screen input form must be controlled by a form manager of
         type FormOBJ. In the example, the instance Manager is used.

         The procedure InitVars is called to initialize all the input fields
         using methods similar to the ones used in the previous example. In the
         body of the main program, the Manager instance is initialized, and each
         of the IO objects is included in the form by calling the method AddI-
         tem. Finally, the function method Go is called to instruct the Toolkit
         to process user input. The method returns a member of the enumerated
         type tAction, which indicates whether the user escaped or ended nor-
         mally - in this case by pressing [KEYCAP].

         Figure 11.2 illustrates the output generated by this program. Note that
         the first field can literally scroll, allowing the user to input data
         which is longer than the visible field.



Figure 11.2                                                             [SCREEN]
Full Screen
Input



The Object Hierarchy

         The totIO units make extensive use of inheritance and polymorphism, and
         this is reflected in the object hierarchy (see figure 11.3).



Controlling User Input                                                      11-5

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

Figure 11.3
totIO
Object Hierarchy



11-6                                                                User's Guide

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

         At first, the object hierarchy may seem daunting, but there really
         isn't much to it. Many of the objects are abstract, and these are
         shaded gray in the figure. Remember that you should not create
         instances of abstract objects -- use a descendant.

         All you have to decide is which object fits your input needs, and then
         create an instance. For example, if you want to prompt a user for a
         date, use the DateIOOBJ, or if you want to prompt for a number, choose
         RealIOOBJ, FixedRealIOOBJ, or IntIOOBJ.

         It is often difficult to determine which methods are applicable to
         which objects, especially with a deeply structured object hierarchy.
         Part 3: Flash Cards lists, in one place, all the methods available for
         each object in the IO hierarchy.

         Listed below is a brief description of each input object:

         StringIOOBJ       Basic string input. Provides methods to force the
                           case of text, and to justify text when the user moves
                           to another field.

         PictureIOOBJ      String input which supports a special field mask or
                           picture to control input. The following special
                           format characters govern input:

                           !          Forces letters to upper case
                           #          Only accepts numbers
                           @          Only accepts letters and punctuation
                           *          Accepts any character

                           For example, the field mask '(###) ###-####' is ideal
                           for US telephone numbers.

         LateralIOOBJ      String input which supports lateral scrolling. For
                           example, the field width can be set to 20 characters
                           wide, but the user might be allowed to enter up to 40
                           characters.

         DateIOOBJ         Input of dates. The Toolkit supports eight different
                           date formats, and this field will automatically
                           verify that the date entered is valid, and, option-
                           ally, within a specified range.

         IntIOOBJ          Whole number input. Use this object when you want to
                           obtain a whole number, i.e. shortint, byte, integer,
                           word, longint. Provides methods to ensure input is
                           within a specified range.

         RealIOOBJ         Real number input. By using Toolkit compiler direc-
                           tives (discussed on page 3.9), this object can get
                           input of single, double, extended, and comp reals.
                           Provides methods to ensure input is within a speci-
                           fied range.




Controlling User Input                                                      11-7

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

         FixedRealIOOBJ    Like RealIOOBJ, this object is for the input of real
                           numbers. The object is similar to contemporary data-
                           base packages - there are a fixed number of decimal
                           places, and when the user presses [KEYCAP] the cursor
                           jumps to the right of the decimal place.

         HexIOOBJ          Just for the engineers, this accepts the input of
                           hexadecimal numbers!

         WWArrayIOOBJ      A multi-line word-wrapping field. A one-dimensional
                           string array is assigned to the field. The contents
                           of the array are updated with the user's input.

         WWLinkIOOBJ       Also a multi-line word-wrapping field. A DLLOBJ
                           instance is assigned to the field. The linked list is
                           updated with the user's input.

         ArrayIOOBJ        A scrollable list of options from which the user may
                           select one. The displayed list is based on the
                           contents of a one-dimensional string array.

         LinkIOOBJ         A scrollable list based on the contents of a DLLOBJ
                           instance.

         CheckIOOBJ        A check box field, where the user can check any item
                           in the list.

         RadioIOOBJ        A radio button field where the user can select any
                           one item in the list.

         StripIOOBJ        A "Turbo 6.0 like" button which the user can select,
                           e.g. buttons for Edit, Save, Cancel, etc.

         Strip3dIOOBJ      The same as StripIOOBJ, except that a small 3-D
                           shadow is drawn behind the strip.

         ButttonIOOBJ      A "Norton Utilities-like" box button.

         HotKeyIOOBJ       HotkeyIOOBJ are invisible fields, used to trap for
                           special keys. For example, the key [KEYCAP] might
                           terminate the input session.

         ControlKeysIOOBJ  Defines which keys are used to move between fields,
                           and which keys terminate the input session.



         Figure 11.4 shows a not-so-useful screen which uses every input type!
         The on-disk demo file DEMIO3.PAS created the display.




           Note: All the display colors used by the input objects are con-
           trolled by the global instance pointer IOTOT. IOTOT controls all
           the common display characteristics for input fields. This makes it

11-8                                                                User's Guide

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

           easy to change the overall look and feel of your program, by just
           changing the IOTOT values. IOTOT will be discussed in detail later
           in the chapter (page 11-40).


Figure 11.4                                                             [SCREEN]
Every Field
Type



Common Field Methods

         All the Toolkit IO objects are derived from the base object ItemIOOBJ.
         This abstract object defines the following fundamental methods which
         are shared by all the objects:


         SetActiveStatus(Selectable:boolean);

         The Toolkit allows you to display fields in a form which are not always
         accessible, i.e. the user cannot land the cursor on the field. Fields
         which are displayed, but cannot be highlighted, are referred to as
         inactive fields. By default, all fields are active, but the method
         SetActiveStatus can be used to control activity status. Pass True to
         activate the field, or False to deactivate it.


         SetHotkey(HK:word);

         Every field can be optionally selected by pressing a Hotkey. You can
         assign a hotkey to any field with the method SetHotKey. The passed
         parameter is the Toolkit key code (refer to the table on page 6-3) that
         represents the key which will activate the field. For example, the
         statement SetHotKey(305) assigns the key [KEYCAP] to the object. When
         the user presses [KEYCAP], the cursor will jump to this field. Be sure
         to assign different hotkeys to each field. To inform the user of the
         hotkey, you can use the SetLabel method with the embedded character '~'
         to highlight the key, e.g. SetLabel('~N~ame');.


         SetID(ID:word);

         By default, every field has an ID of zero. You can assign each field a
         different ID with the SetID method. This ID is used to indicate the
         highlighted field when a user presses a help function, or when a field
         raises a signal to indicate that other fields need to be refreshed. The
         topics of Help and Signals are discussed later.


         In addition to these basic methods, all visible fields share the fol-
         lowing two methods:



Controlling User Input                                                      11-9

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

         SetLabel(Lbl:string);

         Every visible field can have a label. The label is usually displayed to
         the immediate left of the input field. When the field is highlighted,
         the label is drawn in a different color to signify that the field is
         active. Use the SetLabel command to specify a string label for any
         field. Note that the use of the embedded control character '~' is sup-
         ported. Refer to the discussion of the Screen.WriteHi method on page
         5-3 for further information.


         SetMessage(X,Y:byte; Msg:string);

         The Toolkit can display an optional message at some location on the
         screen when the field is highlighted. When the user leaves the field,
         the message is erased. (Note: the old screen contents which were cov-
         ered by the message are not restored.) Use the SetMessage method to
         identify the location of the message and the message text.


         Listed below is the demo program DEMIO4.PAS, which is a variation on
         the program DEMIO2.PAS, discussed earlier. The usability has been
         enhanced by adding informative (!) messages, and the user can jump to
         the various fields by pressing hotkeys. Figure 11.5 shows the resultant
         display.

         program DemoIOFour;
         {demIO4 - using hotkeys, labels, and messages}

         Uses DOS, CRT,
              totFAST, totIO1, totIO2;

         Var
            Name: LateralIOOBJ;
            Phone: PictureIOOBJ;
            Price: FixedRealIOOBJ;
            Keys: ControlkeysIOOBJ;
            Manager: FormOBJ;
            Result: tAction;

         procedure InitVars;
         {}
         begin
            with Name do
            begin
               Init(35,5,20,40);
               SetLabel('Vendor ~N~ame');
               SetHotkey(305); {Alt-N}
               SetMessage(22,11,'Enter the vendor''s name, 40 chars Max');
            end;
            with Phone do
            begin



11-10                                                               User's Guide

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

               Init(35,7,'(###) ###-####');
               SetLabel('~T~el');
               SetHotkey(276); {Alt-T}
               SetMessage(22,11,'Enter the vendor''s phone number');
            end;
            with Price do
            begin
               Init(35,9,8,2);
               SetLabel('Unit ~P~rice');
               SetHotKey(281); {Alt-P}
               SetMessage(22,11,'Enter the unit price in dollars');
            end;
            Keys.Init;
         end; {InitVars}

         begin
            ClrScr;
            Screen.TitledBox(15,3,65,12,76,79,78,2,' Quicky Input Demo ');
            Screen.WriteCenter(25,white,'Press TAB to switched fields and press
         ESC or F10 to end');
            InitVars;
            with Manager do
            begin
               Init;
               AddItem(Keys);
               AddItem(Name);
               AddItem(Phone);
               AddItem(Price);
               Result := Go;
               if Result = Finished then
                  {update the database..}
               else
                  {call Esc routine};
            end;
         end.




Figure 11.5                                                             [SCREEN]
Using Labels &
Messages



Field Types

         The Object hierarchy illustrates the interrelated nature of the totIO
         objects. The objects are loosely organized into the following groups:



Controlling User Input                                                     11-11

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

                String       StringIOOBJ        (totIO2)
                             PictureIOOBJ       (totIO2)
                             LateralIOOBJ       (totIO2)

                Number       IntIOOBJ           (totIO2)
                             RealIOOBJ          (totIO2)
                             FixedRealIOOBJ     (totIO2)
                             HexIOOBJ           (totIO2)

                Date         DateIOOBJ          (totIO2)

                Check/Radio  CheckIOOBJ         (totIO1)
                             RadioIOOBJ         (totIO1)

                Lists        ArrayIOOBJ         (totIO2)
                             LinkIOOBJ          (totIO2)

                Wordwrap     WWArrayIOOBJ       (totIO3)
                             WWLinkIOOBJ        (totIO3)

                Buttons      StripIOOBJ         (totIO1)
                             Strip3dIOOBJ       (totIO1)
                             ButtonIOOBJ        (totIO1)

                Hotkeys      HotkeyIOOBJ        (totIO1)
                             ControlKeysIOOBJ   (totIO1)



         The objects which fall into the category of single line objects are the
         String, Number and Date object groups. These objects are similar in
         nature, and share the following common methods:


         SetIns(InsOn: boolean);

         Pass True to set the field initially in insert mode, or False to be in
         overtype mode.


         SetRules(Rules:byte);

         The rules control some of the field's editing properties. The following
         constants are declared in the totIO1 unit:

         NoRules         This is the default state, with no editing rules
                         active.

         AllowNull       Use this rule to instruct the Toolkit to accept an
                         empty or null number field, even though the SetMinMax
                         method has been used to confine the acceptable input
                         within a range.

         SuppressZero    This rule suppresses the display of the default field
                         value in number fields, when the value is zero, i.e.
                         the field is empty, rather than showing "0" or "0.0".

11-12                                                               User's Guide

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

         EraseDefault    When active, this rule forces the emptying of the
                         field's default value, when a user highlights the field
                         and presses a non-editing key.

         JumpIfFull      This rule forces the user to the next field, as soon as
                         the current field is filled.

         To specify multiple rules, simply sum the rules. For example, the
         following statement will enforce three of the rules:

               SetRules(AllowNull+EraseDefault+JumpIfFull);


         SetDispChar(Ch:char);

         Normally, the key pressed by the user is displayed in the input field.
         However, for security, you may want to echo a different character to
         the screen. Use this method to suppress the display of the typed char-
         acters. The Toolkit will use the character Ch to identify that a char-
         acter has been pressed. This method is ideal for password fields. Note
         that the field stores the actual typed characters, as this method only
         affects the way the display is updated. Pass a character of ' ' (space)
         to instruct the Toolkit to echo the typed characters.


         SetPadChar(Pad:char);

         This method controls which character is used to pad out the empty part
         of the input field. By default, the character used is defined in the
         IOTOT object (discussed later).


         With the exception of the FixedRealIOOBJ, the single line input fields
         also share the following two methods:


         SetJust(Just:tJust);

         When the user leaves the current field, the Toolkit can automatically
         justify the field data. This method controls the justification. The
         totSTR unit includes the declaration of an enumerated type tJust, which
         has the following members:  JustLeft, JustCenter and JustRight. (Sounds
         like a good name for a breakfast cereal!) By default, fields are left
         justified.


         SetCursor(Curs:tCursPos);

         Every time the user jumps to a new field, the Toolkit has to decide
         where to position the cursor. This method controls the cursor position-
         ing for each field. The totIO1 unit includes the declaration of an
         enumerated type tJust, which has the following members: CursLeft,
         CursRight and CursPrev. Use CursLeft and CursRight to force the cursor




Controlling User Input                                                     11-13

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

         to the leftmost or rightmost character position respectively. The Cur-
         sPrev setting (default) instructs the Toolkit to position the cursor
         where it was the last time the field was edited.



String Fields

         The three string field objects (StringIOOBJ, PictureIOOBJ and Lateral-
         IOOBJ) are all located in the totIO2 unit. All these objects are
         descended from the abstract object VisibleIOOBJ, and share the
         following methods, which were described earlier:

                  SetActiveStatus(Selectable:boolean);
                  SetHotkey(HK:word);
                  SetID(ID:word);
                  SetLabel(Lbl:string);
                  SetMessage(X,Y:byte;Msg:string);
                  Activate;

         In addition, the following methods are shared by all three objects:


         SetCase(Cas:tCase);

         The totSTR unit includes the declaration of an enumerated type tCase
         which has the following members: Lower, Upper, Proper and Leave. This
         method can be used to control whether the Toolkit automatically adjusts
         the case field string when the user leaves the field. Set the case to
         Leave if you want the string to remain the same case as when it was
         entered.


         SetForceCase(On:boolean);

         The SetForceCase method is used to control whether the case of the
         string input is adjusted while the user is typing in the string. Pass a
         True parameter to force the case adjustment (as specified with the
         method SetCase) every time a character is pressed. Pass a False parame-
         ter if you want the string to be adjusted only when the user moves to
         another field.


         SetValue(Str:string);

         This method assigns a default value to the field. This value will be
         displayed when the field is first displayed.


         GetValue: string;

         This method should be called (after the user has completed the input
         session) to determine which string was entered.




11-14                                                               User's Guide

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

         Done;

         This method disposes of the memory consumed by the object, and should
         be called after all user input is completed.



StringIOOBJ

         The StringIOOBJ is used to obtain string input from the user. The user
         may enter any alphanumeric character, including upper ASCII and inter-
         national characters. The only method specific to StringIOOBJ is the
         important Init method. The syntax of Init is as follows:


         Init(X,Y,FieldLen:byte);

         This method must be called first. The first two parameters indicate the
         (X,Y) coordinate of the first character in the field. The third parame-
         ter specifies the field length.



LateralIOOBJ

         The LateralIOOBJ object is very similar to StringIOOBJ, except that the
         field can scroll horizontally, allowing the user to input more charac-
         ters than are visible in the field. LateralIOOBJ has its own Init
         method as follows:


         Init(X,Y,Fieldlen,MaxLen:byte);

         This method must be called first. The first two parameters indicate the
         (X,Y) coordinate of the first character in the field, the third parame-
         ter specifies the visible field length, and the fourth parameter speci-
         fies the maximum length of the input string, i.e. the scrollable field
         length.



PictureIOOBJ

         The PictureIOOBJ object gives you character by character control of the
         input data, and allows you to embed non-editable characters into the
         field.

         When you initialize the object using the Init method (discussed later),
         you must specify a string which represents the field picture. The pic-
         ture is comprised of non-editable characters and the following four,
         pre-defined, format characters:

            #     Allows the input of the characters (0-9 . -) and indicates
                  that only numbers may be input.



Controlling User Input                                                     11-15

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

            @     Allows only letters of the English alphabet and punctuation
                  characters.

            *     Allows any character the user can find.

            !     Converts all alphabetical characters to upper case.

         Any other characters embedded in the picture are treated as fixed and
         for display only.

         For example, the picture '(###) ###-####' would be used for the input
         of US telephone numbers, and the picture '@@@####' might be used for a
         seven character part number which comprises three letters and four dig-
         its.

         The field picture is specified in the Init method as follows:


         Init(X,Y:byte; Picture:string);

         This method must be called first. The first two parameters indicate the
         (X,Y) coordinate of the first character in the field, and the third
         parameter specifies the field picture.


         Two other methods are provided to give even more control over which
         characters can be input. You can either specify the characters which
         are allowable, or the characters which are not allowable. The following
         two methods serve this purpose:


         SetDisAllowChar(Str:string);

         When this method is used, the Toolkit will not allow the user to input
         any of the characters specified in the Str. For example, SetDisAllow-
         Char('\:'); will not allow the user to input a backslash or colon,
         regardless of the field picture.


         SetAllowChar(Str:string);

         This method is the opposite of the previous one, and it is used to
         identify all the characters which the Toolkit will allow the user to
         enter. For example, SetAllowChar('AaBbCc0123456789'); will only allow
         the user to input numbers, or the characters A, B and C.


         Only use one or the other of these methods. If you only want to stop
         the user from entering a few specific characters, use SetDisAllowChar.
         On the other hand, if you only want to allow a few characters to be
         input, use the SetAllowChar method.



11-16                                                               User's Guide

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

         The function method GetValue will return the condensed string excluding
         the format characters. For example, a telephone number would be
         returned as 10 digits with no brackets or spaces. The following method
         will return the fully formatted string, including all embedded format
         characters:


         GetPicValue:string;

         Returns the string entered by the user, including all formatting char-
         acters.




           Note: the totStr unit includes the function PicFormat which
           returns a formatted string. Refer to chapter 14: String Handling
           for further information.




String Field Examples

         Listed below is an extract of the demo program DEMIO5, which focuses on
         string fields. Figure 11.6 shows an example of the display generated by
         the full program.

         procedure InitVars;
         {}
         begin
            with Field1 do
            begin
               Init(40,3,10);
               SetLabel('Field 1  (StringIOOBJ)');
            end;
            with Field2 do
            begin
               Init(40,5,10);
               SetLabel('Field 2  (StringIOOBJ)');
               SetCase(upper);
               SetValue('hello');
               SetRules(EraseDefault+JumpIfFull);
            end;
            with Field3 do
            begin
               Init(40,7,15,30);
               SetLabel('Field 3 (LateralIOOBJ)');
            end;
            with Field4 do
            begin
               Init(40,9,15,30);


Controlling User Input                                                     11-17

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

               SetLabel('Field 4 (LateralIOOBJ)');
               SetCase(Upper);
               SetForcecase(True);
               SetCursor(CursLeft);
            end;
            with Field5 do
            begin
               Init(40,11,'(###) ###-####');
               SetLabel('Field 5 (PictureIOOBJ)');
            end;
            with Field6 do
            begin
               Init(40,13,'!!!***@@@###');
               SetLabel('Field 6 (PictureIOOBJ)');
               SetDisAllowChar('aAbBcC123@!');
               SetRules(EraseDefault);
            end;
            with Field7 do
            begin
               Init(40,15,10);
               SetLabel('Field 7  (StringIOOBJ)');
               SetDispChar('#');
            end;
         end; {InitVars}


Figure 11.6                                                             [SCREEN]
Using String
Fields



         Don't forget that IO objects can be used individually, to prompt the
         user with a single field. Listed below is the demo program DEMIO6.PAS,
         which prompts the user to enter a string.

         program DemoIOSix;
         {demIO6 - single string field input}

         Uses DOS, CRT,
              totFAST, totIO1, totIO2, totSTR;

         var
           Field: StringIOOBJ;

         begin
            with Field do
            begin
               Init(40,5,10);
               SetLabel('Field (StringIOOBJ)');
               SetCase(upper);
               SetValue('hello');


11-18                                                               User's Guide

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

               SetRules(EraseDefault+JumpIfFull);
               clrscr;
               Activate;
               writeln;writeln('You entered ',GetValue);
               Done;
            end;
         end.




Number Fields

         The totIO2 unit includes the following four objects for creating number
         fields: IntIOOBJ, RealIOOBJ, FixedRealIOOBJ and HEXIOOBJ. All these
         objects are descended from the abstract object CharIOOBJ, and share the
         following methods which were described earlier:

                  SetActiveStatus(Selectable:boolean);
                  SetHotkey(HK:word);
                  SetID(ID:word);
                  SetLabel(Lbl:string);
                  SetMessage(X,Y:byte;Msg:string);
                  SetIns(InsOn:boolean);
                  SetRules(Rules:byte);
                  SetDispChar(Ch:char);
                  SetPadChar(Pad:char);
                  Activate;
                  Done;


         Except for FixedRealIOOBJ, the number fields also support the following
         two methods:

                  SetJust(Just:tJust);
                  SetCursor(Curs:tCursPos);



IntIOOBJ

         The IntIOOBJ object should be used to prompt for whole numbers, i.e.
         with a type of byte, word, shortint, integer and longint. The following
         additional methods are supported by IntIOOBJ objects:


         Init(X,Y,Len:byte);

         This method must be called first. The first two parameters indicate the
         (X,Y) coordinate of the first character in the field. The third parame-
         ter specifies the field length.


         SetMinMax(Min,Max:longint);



Controlling User Input                                                     11-19

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

         The Toolkit can automatically ensure that the user input falls within a
         specified range. Use the method SetMinMax to set an input range. Pass
         two zeros to turn off input validation. If the user tries to input an
         invalid value, the Toolkit displays a pop-up message explaining the
         problem (see figure 11.1), and forces the user to input a valid number.


         SetValue(Val:longint);

         Use this method to set an initial or default value in the field.


         GetValue: longint;

         This function method returns the value input by the user.



RealIOOBJ

         This object is very similar to IntIOOBJ, except that it is designed for
         the input of real numbers, i.e. numbers with one or more decimal
         places.


           Note: The Toolkit supports all the real types, i.e. real, single,
           double, extended and comp. By default, all these types are mapped
           to the base type REAL. In other words, if you declare a variable
           of type EXTENDED, the Toolkit re-maps it so that Turbo Pascal
           treats it like a basic REAL. If you do want to support all the
           additional precision reals, edit the file TOTFLAGS.INC and adjust
           the conditional defines FLOAT and FLOATEM.  Refer to page 3-9 for
           further information.


         In addition to the common methods, the following methods are supported
         by RealIOOBJ objects:


         Init(X,Y,Len:byte);

         This method must be called first. The first two parameters indicate the
         (X,Y) coordinate of the first character in the field. The third parame-
         ter specifies the field length.


         SetMinMax(Min,Max:extended);

         The Toolkit can automatically ensure that the user input falls within a
         specified range. Use the method SetMinMax to set an input range. Pass
         two zeros to suppress input validation. If the user tries to input an
         invalid value, the Toolkit displays a pop-up message explaining the
         problem (see figure 11.1), and forces the user to input a valid number.




11-20                                                               User's Guide

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

         SetValue(Val:extended);

         Use this method to set an initial or default value in the field.


         SetENotation(On:boolean);

         This method controls whether the user is allowed to enter the number in
         E-notation, e.g. 4.435623E+12. Pass True to allow the user to input
         E-notation, or False to disallow it.


         GetValue: extended;

         This function method returns the value input by the user.



FixedRealIOOBJ

         You may have used some commercial database or financial software pro-
         grams which provide special cursor control when the user is inputting
         real numbers. For example, when the user presses [KEYCAP], the cursor
         automatically jumps to the right of the fixed decimal place. The Fixe-
         dRealIOOBJ object brings this capability to the Toolkit. (The cursor
         and key reactions emulate the FoxPro database package - we liked it, so
         we copied it!)

         FixedRealIOOBJ objects provide the following additional methods:


         Init(X,Y,Whole,DP:byte);

         This method must be called first. The first two parameters indicate the
         (X,Y) coordinate of the first character in the field. The third parame-
         ter specifies the maximum number of whole numbers, and the last parame-
         ter specifies the maximum number of decimal places.


         SetMinMax(Min,Max:extended);

         The Toolkit can automatically ensure that the user input falls within a
         specified range. Use the method SetMinMax to set an input range. Pass
         two zeros to suppress input validation. If the user tries to input an
         invalid value, the Toolkit displays a pop-up message explaining the
         problem (see figure 11.1), and forces the user to input a valid number.


         SetValue(Val:extended);

         Use this method to set an initial or default value in the field.


         GetValue: extended;

         This function method returns the value input by the user.

Controlling User Input                                                     11-21

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

HEXIOOBJ

         If you want a user to enter HEX numbers, HEXIOOBJ is the object for
         you. HEXIOOBJ is very similar to IntIOOBJ, with the main difference
         that HEX allows the user to input numbers and the letters A, B, C, D, E
         and F.

         As well as the common number methods, HEXIOOBJ supports the following
         methods:


         Init(X,Y,Len:byte);

         This method must be called first. The first two parameters indicate the
         (X,Y) coordinate of the first character in the field. The third parame-
         ter specifies the field length.


         SetMinMax(Min,Max:longint);

         The Toolkit can automatically ensure that the user input falls within a
         specified range. Use the method SetMinMax to set an input range. Pass
         two zeros to turn off input validation.


         SetValue(Val:longint);

         Use this method to set an initial or default value in the field.


         GetValue: longint;

         This function method returns the value input by the user.




           Note: in Turbo Pascal HEX numbers are preceded by a '$' character.
           For example, the following method calls have the same effect:
                              SetValue($FF);
                              SetValue(255);




Formatting Number Fields

         The objects IntIOOBJ, RealIOOBJ and FixedREALIOOBJ all provide optional
         formatting capabilities, which can be used to control the format of the
         displayed number when the user leaves the field, i.e. when the user is
         editing, the number is unformatted, but when the user exits the field,
         the number can be formatted in a variety of styles. For example, the
         number -123456.78 might be formatted as $123,456.78 CR.

         If you want formatted number fields, you must call the following
         method:

11-22                                                               User's Guide

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

         InitFormat;

         This method instructs the object to format the field when the user
         leaves the field.


         The totSTR unit includes the object FmtNumberOBJ, which is designed to
         format numbers. The FmtNumber object includes the following methods:

                  SetPrefixSuffix(P,S:char);
                  SetSign(S:tSign);
                  SetSeparators(P,T,D:char);
                  SetJustification(J:tJust);


         These methods are described in detail in chapter 14: String Handling.
         Refer to this chapter for further information.

         Behind the scenes, when the number method InitFormat is called, the
         Toolkit creates a private FmtNumberOBJ instance. The number method For-
         matPtr can be used to access the FmtNumberOBJ instance using the fol-
         lowing syntax:

                  FormatPtr^.[method]

         For example, the following code fragment formats an integer field with
         a '$' prefix and embedded commas.

                  var
                    Field: IntIOOBJ;

                  begin
                     with Field do
                     begin
                        Init;
                        InitFormat;
                        FormatPtr^.SetPrefixSuffix('$',#0);
                        FormatPtr^.SetSeparators(' ',',','.');
                        {...}
                     end;
                  end.




Setting the Default Format

         The totIO2 unit includes FmtNumberTOT, a pointer to an object instance
         of type FmtNumberOBJ. This instance defines the default formatting that
         will be applied to real and integer fields during full-screen input.
         Whenever a number field object's method InitFormat is called, the
         field's initial formats are copied from FmtNumberTOT.



Controlling User Input                                                     11-23

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

         You can control each field's default value by setting FmtNumberTOT to
         specifically meet your needs, before you call the InitFormat method.
         For example, if you want all your number fields to be formatted with a
         suffix of FR, set the default with the following statement:

                  FmtNumberTOT.SetPrefixSuffix('','FR');

         All number objects initialized after this statement will assume the FR
         suffix.



Number Field Examples

         Back on the first page of this chapter you saw an example of how to
         prompt the user for a real number using FixedRealIOOBJ. Take another
         look at page 11.1 and see if the statements make more sense now!

         Listed below is an extract of the demo program DEMIO8.PAS which illus-
         trates how to use many of the methods discussed in this section. Figure
         11.7 shows an example of the display generated by the full program.

         procedure InitVars;
         {}
         begin
            with Field1 do
            begin
               Init(40,3,5);
               SetLabel('Field 1  (IntIOOBJ)');
            end;
            with Field2 do
            begin
               Init(40,5,5);
               InitFormat;
               SetLabel('Field 2  (IntIOOBJ)');
               SetValue(69);
               SetRules(EraseDefault+JumpIfFull);
            end;
            with Field3 do
            begin
               Init(40,7,10);
               SetLabel('Field 3 (RealIOOBJ)');
            end;
            with Field4 do
            begin
               Init(40,9,15);
               InitFormat;
               FormatPtr^.SetSeparators('*',',','.');
               FormatPtr^.SetPrefixSuffix('','FR');
               FormatPtr^.SetJustification(JustRight);
               SetLabel('Field 4 (RealIOOBJ)');


11-24                                                               User's Guide

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

               SetCursor(CursLeft);
            end;
            with Field5 do
            begin
               Init(40,11,8,2);
               SetLabel('Field 5 (FixedRealIOOBJ)');
            end;
            with Field6 do
            begin
               Init(40,13,5);
               SetLabel('Field 6  (HEXIOOBJ)');
            end;
            Keys.Init;
         end; {InitVars}



Figure 11.7                                                             [SCREEN]
Using Number
Fields



Date Fields

         The DateIOOBJ object is used to prompt the user to input a date. The
         Toolkit supports eight different date formats. The totDATE unit
         includes an enumerated type tDate which has the following members:
         MMDDYY, MMDDYYY, MMYY, MMYYYY, DDMMYY, DDMMYYYY, YYMMDD, YYYYMMDD.
         Whenever you work with dates, you must identify the desired date for-
         mat.

         Refer to chapter 13: Managing Dates for a full description of all the
         date manipulation routines which complement DateIOOBJ. There are a
         wealth of functions to convert dates to and from Julian, Gregorian and
         string formats. For example, the JultoStr and StrtoJul functions con-
         vert between Julian and string formats.

         DateIOOBJ is a descendant of CharIOOBJ, and inherits the following,
         previously described, methods:

                  SetActiveStatus(Selectable:boolean);
                  SetHotkey(HK:word);
                  SetID(ID:word);
                  SetLabel(Lbl:string);
                  SetMessage(X,Y:byte;Msg:string);
                  SetIns(InsOn:boolean);
                  SetRules(Rules:byte);
                  SetDispChar(Ch:char);
                  SetPadChar(Pad:char);
                  Activate;
                  Done;


Controlling User Input                                                     11-25

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

         The DateIOOBJ object manipulates dates in Julian format, where dates
         are specified as longints. DateIOOBJ includes the following methods:


         Init(X,Y:byte; DateFmt:tDate);

         This method must be called first. The first two parameters indicate the
         (X,Y) coordinate of the first character in the field. The third parame-
         ter is a member of the enumerated type tDate, and indicates which for-
         mat of date is to be input, e.g. MMDDYY or DDMMYY.


         SetMinMax(Min,Max:longint);

         The Toolkit will automatically verify if proper dates are entered, i.e.
         that the month is between 1 and 12, and the days are valid for the
         specified month. The method SetMinMax can also be used to specify a
         date range. Pass two zeros to turn off input validation. If the user
         tries to input an invalid date or an out of range date, the Toolkit
         displays a pop-up message explaining the problem (see figure 11.8), and
         forces the user to input a valid number.


         SetValue(Date: longint);

         Use this method to set an initial or default value in the field. The
         date is passed as a Julian (longint) value.


         GetValue:longint;

         This function method returns the Julian date value input by the user.



         Listed below is the demo program DEMIO9.PAS which prompts the user for
         the input of a single date. Figure 11.8 is an example of the date
         validation performed by the Toolkit.

         program DemoIONine;
         {demIO9 - single date field input}

         Uses DOS, CRT,
              totIO1, totIO2, totDate;

         Var
            Birthday: DateIOOBJ;

         begin
            ClrScr;
            with Birthday do
            begin
               Init(35,5,MMDDYY);
               SetLabel('When is your next birthday? ');
               Activate;


11-26                                                               User's Guide

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

               Writeln;
               writeln('You entered the Julian date',GetValue);
               writeln('i.e. ',JultoStr(GetValue,MMDDYY));
               Done;
            end;
         end.


Figure 11.8                                                             [SCREEN]
Single Date
Input



         Listed below is an extract of the demo program DEMIO10.PAS which illus-
         trates how to use many of the methods discussed in this section. Figure
         11.9 shows an example of the display generated by the full program.

         procedure InitVars;
         {}
         begin
            with Field1 do
            begin
               Init(40,3,MMDDYY);
               SetLabel('Field 1   (MMDDYY)');
            end;
            with Field2 do
            begin
               Init(40,5,MMDDYY);
               SetLabel('Field 2   (MMDDYY)');
               SetValue(TodayInJul);
               SetRules(EraseDefault+JumpIfFull);
            end;
            with Field3 do
            begin
               Init(40,7,DDMMYYYY);
               SetLabel('Field 3 (DDMMYYYY)');
             end;
            with Field4 do
            begin
               Init(40,9,DDMMYYYY);
               SetLabel('Field 4 (DDMMYYYY)');
               SetMinMax(GregtoJul(3,1,1992),GregtoJul(3,31,1992));
               SetCursor(CursLeft);
             end;
            Keys.Init;
         end; {InitVars}



Controlling User Input                                                     11-27

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

Figure 11.9                                                             [SCREEN]
Using Date
Fields



Check Boxes and Radio Buttons

         Two common elements of contemporary input forms are check boxes and
         radio buttons. Both these objects provide ways of choosing items from
         lists of options. Figure 11.10 (listed later in the section) illus-
         trates both types of objects.

         A check box object provides a list of options with each item having its
         own check box displayed to the left of the item, e.g. [X] Toast. Any
         number of items in the list can be selected. An item's selection status
         is toggled by hitting the [KEYCAP] or by clicking the mouse cursor on
         it. Selected items have an X in the adjacent check box.

         Radio buttons are similar to check boxes, except that only one item can
         be selected. When an item is selected, the previously selected item is
         deselected. The selected item has a dot in the "button" next to it,
         e.g. (.) Ham Sandwich.

         The Toolkit objects CheckIOOBJ and RadioIOOBJ are located in the totIO1
         unit, and are descended from VisibleIOOBJ. Both objects, therefore,
         inherit the following, previously described, methods:

                  SetActiveStatus(Selectable:boolean);
                  SetHotkey(HK:word);
                  SetID(ID:word);
                  SetLabel(Lbl:string);
                  SetMessage(X,Y:byte;Msg:string);
                  Activate;
                  Done;


         The objects are part of the MultLineIOOBJ object family and also
         inherit the following method:


         SetBoxOn(On:boolean);

         All multi-line objects can be optionally displayed in a box. By
         default, the objects are not displayed in a box. To activate the box
         display, pass a True parameter.


         Both objects share the following common methods:


         Init(X1,Y1,width,depth:byte; Title:string);



11-28                                                               User's Guide

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

         This method should be called first. The first two parameters specify
         the (X,Y) coordinate of the top left of the object. The third and
         fourth parameters specify the width and depth of the object in charac-
         ters. The width should be large enough to accommodate the longest item,
         and leave room for the box, if the box is active. The depth should be
         large enough to accommodate the title, all the items and, optionally,
         the box.


         AddItem(Str:string; HK:word; Selected:boolean);

         This method adds an item to the list. The first parameter specifies the
         text to be displayed - don't forget that embedded '~' characters can be
         used to highlight text (see page 5-3 for further information). The
         second parameter is an optional hot key code, which the user can press
         to jump to this item and automatically select/deselect it. Pass a value
         of zero if you don't want to specify a hotkey. The third parameter
         indicates whether the item is selected or not. You can add as many
         items as will fit in the object's initialized dimensions.




           Note: the generic method SetHotKey is used to specify the hotkey
           for the entire object. If the user presses the generic hotkey, the
           object will be selected, and the last active item will be high-
           lighted. The individual item hotkeys allow the user to both select
           the object, and immediately activate the specific item. The demo
           program DEMIO12.PAS, discussed later, illustrates hotkeys.




CheckIOOBJ

         CheckIOOBJ provides the following two methods for setting and checking
         the status of each item:


         SetValue(Item:byte; selected:boolean);

         This method is used to change the selection status of an item after it
         has been added with AddItem. The first parameter specifies the item
         number, and the second boolean parameter should be set to True to
         select the item, or false to deselect it.


         GetValue(Item:byte):boolean;

         This boolean function method returns True if the specified item is
         selected.



Controlling User Input                                                     11-29

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

RadioIOOBJ

         RadioIOOBJ has the following methods for setting and checking which
         item is selected:


         SetValue(Item:byte);

         Only one item in a radio button object can be selected. Use this method
         (after you have added all the items) to specify which item is selected.


         GetValue:byte;

         This function returns the number of the selected item.



Examples

         Listed below is the demo program DEMIO11.PAS illustrating a single
         radio button field.

         program DemoIOEleven;
         {demIO11 - single Radio Button input}

         Uses DOS, CRT,
              totFAST, totINPUT, totIO1, totIO2;

         Var
            Bool: RadioIOOBJ;

         begin
            ClrScr;
            with Bool do
            begin
               Init(35,12,20,5,'Sex?');
               SetBoxOn(True);
               AddItem('~M~ale',77,true);
               AddItem('~F~emale',70,false);
               Mouse.Show;
               Activate;
               Mouse.Hide;
               gotoxy(1,20);
               if GetValue = 1 then
                  writeln('You are male!')
               else
                  writeln('Hi, I''m Bob.');
               Done;
            end;
         end.



11-30                                                               User's Guide

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

         Listed below is an extract of the demo program DEMIO12.PAS, which
         illustrates how to combine mulitiple fields in a dialog box. Figure
         11.10 shows an example of the display generated by the full program.

         procedure InitVars;
         {}
         begin
            with Field1 do
            begin
               Init(17,5,25,4,'Options');
               AddItem('~C~ase sensitive',67,false);
               AddItem('~W~hole words only',87,false);
               AddItem('~R~egular expression',82,false);
            end;
            with Field2 do
            begin
               Init(17,10,25,3,'Scope');
               AddItem('~G~lobal',71,true);
               AddItem('~S~elected text',83,false);
            end;
            with Field3 do
            begin
               Init(45,5,17,3,'Direction');
               AddItem('Forwar~d~',68,true);
               AddItem('~B~ackward',66,false);
            end;
            with Field4 do
            begin
               Init(45,10,17,3,'Origin');
               AddItem('~F~rom cursor',70,false);
               AddItem('~E~ntire scope',69,true);
            end;
            Keys.Init;
         end; {InitVars}


Figure 11.10                                                            [SCREEN]
A Custom
Dialog Box



List Fields

         Radio buttons allow the user to select a single item from a list.
         Sometimes, however, you may have too many items in the list to display
         all together. The ListOOBJ object family can be used to display scroll-
         able lists, and these are located in the totIO2 unit.



Controlling User Input                                                     11-31

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

         ListIOOBJ is an abstract object, and you should only use the descen-
         dants ArrayIOOBJ and LinkIOOBJ. These objects display the contents of a
         string array and a DLLOBJ linked list, respectively. Both these objects
         are descendant from MultiLineIOOBJ, and inherit the following, pre-
         viously discussed, methods:

                  SetActiveStatus(Selectable:boolean);
                  SetHotkey(HK:word);
                  SetID(ID:word);
                  SetLabel(Lbl:string);
                  SetMessage(X,Y:byte;Msg:string);
                  SetBoxOn(On:boolean);
                  Activate;
                  Done;


         Both items share the following common Init method:


         Init(X1,Y1,width,depth:byte; Title:string);

         This method should be called first. The first two parameters specify
         the (X,Y) coordinate of the top left of the object. The third and
         fourth parameters specify the width and depth of the object in charac-
         ters. The width should be large enough to accommodate the longest item,
         a scroll bar (if there are too many items to display at once) and leave
         room for the box (if the box is active). The depth should be large
         enough to accommodate the title, at least one item and, optionally, the
         box.


         Having initialized the object, the next task is to call the AssignList
         method. AssignList instructs the Toolkit where to locate the data for
         the items in the list. Each object has its own AssignList method.



ArrayIOOBJ

         The Toolkit gets the contents of the list from a string array, which
         you must create separately. Having created the array, you must call the
         following method:


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

         AssignList identifies the string array that will be displayed. The four
         parameters are the string array, the total number of elements in the
         array, and the length of each string in the array. The string length
         parameter must reflect the string length of the array when it was
         declared, not the maximum length of any string assigned to the array.



11-32                                                               User's Guide

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

         Listed below is the demo program DEMIO13.PAS, which illustrates how to
         build an ArrayIOOBJ field.

         program DemoIOThirteen;
         {demIO13 - single ArrayIOOBJ input}

         Uses DOS, CRT,
              totFAST, totIO1, totIO2;

         Var
            MyList: array[1..10] of string[20];
            ListField: ArrayIOOBJ;

         procedure FillArray;
         {}
         begin
            MyList[1] := 'Monitor';
            MyList[2] := 'Keyboard';
            MyList[3] := 'Mouse';
            MyList[4] := 'Light Pen';
            MyList[5] := 'Microphone';
            MyList[6] := 'LCD O/H Panel';
            MyList[7] := 'Modem';
            MyList[8] := 'Printer';
            MyList[9] := 'CD Rom';
            MyList[10] := 'Toolkit';
         end; {FillArray}

         begin
            ClrScr;
            FillArray;
            with ListField do
            begin
               Init(35,5,15,6,'Peripherals');
               AssignList(MyList,10,20);
               Activate;
               gotoxy(1,20);
               writeln('You chose item: ',GetValue,' - ',MyList[GetValue]);
               Done;
            end;
         end.




LinkIOOBJ

         This object accesses a DLLOBJ object, to determine which items to dis-
         play in the list. You must create a DLLOBJ instance, populate the list,
         and then call the following AssignList method:



Controlling User Input                                                     11-33

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

         AssignList(var LinkList: DLLOBJ);

         This method is passed a DLLOBJ instance, or any instance of an object
         descended from DLLOBJ, e.g. StrDLLOBJ.


         Listed below is the demo program DEMIO14.PAS, which illustrates how to
         build a LinkIOOBJ field.

         program DemoIOFourteen;
         {demIO14 - single LinkIOOBJ input}

         Uses DOS, CRT,
              totFAST, totIO1, totIO2, totLINK;

         Var
            MyList: StrDLLOBJ;
            ListField: LinkIOOBJ;

         procedure FillList;
         {}
         var Retcode: integer;
         begin
            with MyList do
            begin
               Init;
               Retcode := Add('Monitor');
               Retcode := Add('Keyboard');
               Retcode := Add('Mouse');
               Retcode := Add('Light Pen');
               Retcode := Add('Microphone');
               Retcode := Add('LCD O/H Panel');
               Retcode := Add('Modem');
               Retcode := Add('Printer');
               Retcode := Add('CD Rom');
               Retcode := Add('Toolkit');
            end;
         end; {FillList}

         begin
            ClrScr;
            FillList;
            with ListField do
            begin
               Init(35,5,15,6,'Peripherals');
               AssignList(MyList);
               Activate;
               gotoxy(1,20);
               writeln('You chose item: ',GetValue,' - ',
                       MyList.GetStr(MyList.NodePtr(GetValue),0,0));
               Done;



11-34                                                               User's Guide

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

               MyList.Done;
            end;
         end.




         Both the examples produce identical displays, see figure 11.11 below.



Figure 11.11                                                            [SCREEN]
Displaying
a List



Word Wrapping Fields

         Some of the most powerful, but easy to use, form objects are the Word-
         WrapIOOBJ objects. These objects can be used to display scrollable memo
         fields. The user can type in multiple lines of text with full editing,
         and the object provides automatic word wrapping.

         WordWrapIOOBJ is an abstract object, and you should only use the
         descendants WWArrayIOOBJ and WWLinkIOOBJ. Like the List objects
         described in the last section, these objects display the contents of a
         string array and a DLLOBJ linked list, respectively. Both objects are
         descendant from MultiLineIOOBJ, and inherit the following, previously
         discussed, methods:

                  SetActiveStatus(Selectable:boolean);
                  SetHotkey(HK:word);
                  SetID(ID:word);
                  SetLabel(Lbl:string);
                  SetMessage(X,Y:byte;Msg:string);
                  SetBoxOn(On:boolean);
                  SetIns(InsOn:boolean);
                  Activate;
                  Done;


         Both items share the following common Init method:


         Init(X1,Y1,width,lines:byte; Title:string);

         This method should be called first. The first two parameters specify
         the (X,Y) coordinate of the top left of the object. The third parameter
         specifies the width of the object in characters, and the fourth parame-
         ter specifies the number of lines of text to display. The last parame-
         ter is an optional title.



Controlling User Input                                                     11-35

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

         Having initialized the object, the next task is to call the AssignList
         method. AssignList instructs the Toolkit where to locate the data for
         the text. Each object has its own AssignList method, and these are
         explained in a later section.

         If you want to pre-load the field with some text, you can take advan-
         tage of the following auto-word wrapping method:


         WrapFull;

         This method adjusts the contents of the source data structure, i.e. the
         string array or linked list, by word wrapping the existing text. When
         you add text to the data structures you do not need to accurately word
         wrap the text, but you should make sure that there is always one space
         at the end of the line. This space separates the last word on one line
         from the first word on the next line.


         Sometimes, you may want to display a word wrap field, but not allow the
         user to edit the text. The following method controls whether editing is
         allowed:


         SetAllowEdit(On:Boolean);

         Pass true to enable editing (default). When editing is disabled, the
         user may still scroll the text, but it cannot be changed.


         When the word wrap fields are used on their own, i.e. by calling acti-
         vate rather than as part of a form, the user can end the input by
         pressing F10. This "end edit" key can be assigned to another key using
         the following method:


         SetEndKey(K:word);

         Specifies the key which will end the input session when the field is
         used individually rather than as part of a form. The default is F10.



WWArrayIOOBJ

         The Toolkit gets the text contents from a string array, which you must
         create separately. Having created the array, you must call the follow-
         ing method:


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



11-36                                                               User's Guide

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

         AssignList identifies the string array that will be displayed. The
         three parameters are the string array, the total number of elements in
         the array, and the length of each string in the array. The string
         length parameter must reflect the string length of the array when it
         was declared, not the maximum length of any string assigned to the
         array.



           Note: the Toolkit is unable to extend the size of the array. You
           must, therefore, ensure the array is large enough to accommodate
           all the text the user is allowed to enter. If you want an unlim-
           ited number of lines, or you want the Toolkit to extend the lines
           used, take advantage of the WWlinkOBJ described next.




         Listed below is the demo program DEMIO15.PAS, which illustrates how to
         build an WWArrayIOOBJ field.

         program DemoIOFifteen;
         {demIO15 - single WWArrayIOOBJ input}
         Uses DOS, CRT,
              totFAST, totIO1, totIO3, totINPUT;

         Var
            MyList: array[1..10] of string[60];
            WWField: WWArrayIOOBJ;

         procedure FillArray;
         {}
         begin
            FillChar(MyList,sizeof(MyList),#0);
            MyList[1] := 'It seems like we have to work at innocence ';
            MyList[2] := 'and being pure, and at the same time we have ';
            MyList[3] := 'to work at being successful so that we have ';
            MyList[4] := 'an understanding as to what the rest of the ';
            MyList[5] := 'world is up to.';
            MyList[6] := '';
            MyList[7] := 'Brother Anthony Fiore';
         end; {FillArray}

         begin
            ClrScr;
            Screen.WriteCenter(1,15,'Press F10 to finish');
            FillArray;
            Mouse.Show;
            with WWField do
            begin
               Init(5,7,65,7,'A Quote');
               AssignList(MyList,10,60);


Controlling User Input                                                     11-37

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

               WrapFull;
               Activate;
               gotoxy(1,20);
               Done;
            end;
            Mouse.Hide;
         end.



WWLinkIOOBJ

         This object accesses a DLLOBJ object to determine which items to dis-
         play in the list. You must create a DLLOBJ instance, populate the list,
         and then call the following AssignList method:


         AssignList(var LinkList: DLLOBJ; Max:integer);

         This method is passed a DLLOBJ instance, or any instance of an object
         descended from DLLOBJ, e.g. StrDLLOBJ. Max specifies the maximum number
         of lines by which the Toolkit can extend the list.


         Listed below is the demo program DEMIO16.PAS, which illustrates how to
         build a WWLinkIOOBJ field.

         program DemoIOSixteen;
         {demIO16 - single WWLinkIOOBJ input}
         Uses DOS, CRT,
              totFAST, totIO1, totIO3, totINPUT, totLINK;

         Var
            MyList: StrDLLOBJ;
            WWField: WWLinkIOOBJ;

         procedure FillList;
         {}
         var Retcode: integer;
         begin
            with MyList do
            begin
               init;
               Retcode := Add('It seems like we have to work at innocence ');
               Retcode := Add('and being pure, and at the same time we have ');
               Retcode := Add('to work at being successful so that we have ');
               Retcode := Add('an understanding as to what the rest of the ');
               Retcode := Add('world is up to.');
               Retcode := Add('');
               Retcode := Add('Brother Anthony Fiore');
            end;
         end; {FillList}



11-38                                                               User's Guide

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

         begin
            ClrScr;
            Screen.WriteCenter(1,15,'Press F10 to finish');
            FillList;
            Mouse.Show;
            with WWField do
            begin
               Init(5,7,65,7,'A Quote');
               AssignList(MyList,40);
               WrapFull;
               Activate;
               gotoxy(1,20);
               MyList.Done;
               Done;
            end;
            Mouse.Hide;
         end.



         The display generated by both of the demo programs is identical, and is
         illustrated in figure 11.12.



Figure 11.12                                                            [SCREEN]
A Word Wrap
Field



Button Fields

         Buttons are for use with full screen input forms. They provide a way
         for the user to invoke an event. For example, an input form may have a
         SAVE button and a CANCEL button. A button can be selected by tabbing to
         the button and pressing [KEYCAP], pressing the button hotkey, or by
         clicking the mouse cursor on the button.

         The Toolkit provides three button objects in the totIO1 unit: Stri-
         pIOOBJ, Strip3dIOOBJ, and ButtonIOOBJ. All three objects function iden-
         tically, and the differences are purely cosmetic. The StripIOOBJ object
         provides a single-line button, Strip3dIOOBJ is a single line button
         with a black shadow, and ButtonIOOBJ displays the button text sur-
         rounded by a box. Refer back to figure 11.4 (on page 11-8) for examples
         of each button type.

         All three button objects are descended from VisibleIOOBJ and share the
         following, previously described, methods:



Controlling User Input                                                     11-39

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

                  SetActiveStatus(Selectable:boolean);
                  SetHotkey(HK:word);
                  SetID(ID:word);
                  SetLabel(Lbl:string);
                  SetMessage(X,Y:byte;Msg:string);
                  Done;


         While the SetLabel method is technically available, it is not normally
         used, because the button text acts as a label.

         The totIO1 unit includes the declaration of the enumerated type tAc-
         tion, which has the following members: None, NextField, PrevField, Fin-
         ished, Escaped, Refresh, Signal, Enter, Help, Stop1..Stop9. All these
         members are used internally by the Toolkit to control events during
         full screen input. The following members should be used with buttons:

              Finished       Use with buttons to indicate a standard end of a
                             form editing session, e.g. buttons like "OK",
                             "Done", "Proceed", "Save".

              Escaped        Use with buttons that allow the user to exit
                             without processing the edited data, e.g. buttons
                             like "Cancel", "Abort".

              Help           Use with a "Help" button. When selected, the
                             Toolkit will automatically invoke a context sensi-
                             tive help system (discussed later).

              Stop1..Stop9   These buttons function like Finished. They should
                             be used to successfully end the form edit session.
                             They are provided so that you may provide multiple
                             finished buttons. Based on which button is
                             selected, you may process the edited data differ-
                             ently. For example, you may create the following
                             three buttons:
                                      "Save & Quit"  -  Finished
                                      "Save & Edit Next" - Stop1
                                      "Save & Backup File" - Stop2
                             Whichever button is selected, the edit session will
                             end, and the FormOBJ (discussed later) will return
                             the tAction member selected.


         All three buttons share the following method:


         Init(X,Y:byte;Tit:string;Act:tAction);



11-40                                                               User's Guide

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

         This method initializes the button and must be called first. The first
         two parameters specify the upper left (X,Y) coordinate of the button.
         The third parameter is the title which will be displayed in the button.
         The title may include embedded highlight ('~') characters. The fourth
         parameter is a member of the enumerated type tAction, which indicates
         what action to take when the button is selected.


         Listed below is an extract of the program DEMIO17.PAS. This program is
         an enhancement to DEMIO12.PAS. Two buttons have been added to the dia-
         log box. Compare the display of the new program, shown in figure 11.13,
         with the button-less version in figure 11.10 (page 11-30).

         procedure InitVars;
         {}
         begin
            {...}
            OK.Init(23,14,'   ~O~K   ',Finished);
            OK.SetHotkey(79);
            Cancel.Init(36,14,' C~a~ncel ',Escaped);
            Cancel.SetHotkey(65);
            {...}
         end; {InitVars}




Figure 11.13                                                            [SCREEN]
3D Strip
Buttons



Controlling Defaults with IOTOT

         One of the basic approaches in the Toolkit is to default as much as
         possible! This saves you the chore of setting dozens of parameters like
         display colors every time you want to perform a simple task. You can,
         of course, change any of the default values to meet your specific
         needs.

         All the colors and default settings for user input are established by
         the instance IOTOT^. IOTOT is a pointer to an object of type InputOBJ
         and is designed specifically to give you control of the input defaults.
         There are methods for setting display colors, field rules, the case of
         string input, whether the fields are initially in insert mode, and so
         on.

         To modify the defaults, all you have to do is call one of the IOTOT^
         methods. Before analyzing the detailed method syntax, you need to be
         aware of the wealth of colors used by the Toolkit. Most display set-
         tings require four different color attributes to be specified. The



Controlling User Input                                                     11-41

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

         first two attributes are used when the field is highlighted, i.e. when
         the user is editing the field, and the second two attributes are used
         when the field is not highlighted. You may recall that the Toolkit can
         display any string in two colors using the method WriteHi (discussed on
         page 5-3). Many of the strings in the IO objects also support the two
         colors capability, e.g. field labels, button text, and check boxes.
         That is why the color setting methods need to use two colors when the
         field is highlighted, and two colors when it isn't, making a total of
         four colors for each category.




           Don't forget that the Toolkit uses a combined foreground/back-
           ground attribute to define each color. Refer to page 3.11 for
           further information.


         The following methods can be used to change the Toolkit IO defaults:


         SetColLabel(Off,OffHot,On,OnHot:byte);

         Specifies the display attributes for labels. The first two parameters
         specify the display attributes when the field is not highlighted. The
         first parameter is the normal attribute, and the second attribute is
         the color used after the embedded highlight character, e.g. ~. The
         third and fourth parameters specify the attributes to use when the
         field is highlighted.


         SetColButton(Off,OffHot,On,OnHot:byte);

         Specifies the four display attributes for button text.


         SetColGroup(Off,OffHot,On,OnHot:byte);

         Specifies the four color attributes to use with radio button and check
         box fields.


         SetColList(Off,OffHot,On,OnHot:byte);

         Specifies the four colors to use for list fields.


         SetColField(Off,On,Mask,Inactive:byte);

         Specifies the colors to use with standard string fields. The first
         parameter is the display color when the field is not highlighted, the
         second parameter is the color when the field is highlighted, the third
         parameter is the color to display formatting characters in PictureIOOBJ
         fields, and the fourth parameter is the default display color for any
         inactive (i.e. non-selectable) field.


11-42                                                               User's Guide

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

           Note: For consistency, the Toolkit does not allow you to change
           the display attributes of an individual field on an input form.
           The attributes are always derived from IOTOT at display time. You
           must use the methods SetColLabel, SetColButton, SetColGroup, Set-
           ColList, and SetColField to change the display attributes of all
           the field types in the relevant category.





         SetColMsg(Col:byte);

         Sets the color of the message which is displayed when the field is
         highlighted. Specify an attribute of zero, if you want the current
         display attribute to be used.


         SetIns(On:boolean);

         Controls whether the input fields are initially in insert (True) or
         overtype (False) mode.


         SetRules(Rules:byte);

         Sets the default field rules (refer to page 11-12 for further informa-
         tion).


         SetPadChar(Pad:char);

         When a field value does not entirely fill the allotted field, the
         unused characters are represented by displaying a pad character. By
         default, this value is set to a dot (ASCII characters 250). This method
         is used to change the pad character, and one of the most common alter-
         natives is a space, e.g. IOTOT^.SetPadChar(' ');.


         SetJust(Just:tJust);

         This method is used to set the default justification of the string
         fields (see page 11.13).


         SetCursor(Curs: tCursPos);

         This method controls where the cursor is positioned when an input field
         is highlighted (see page 11.13).


         SetCase(Cas:tCase);

         This method can be used to control whether the Toolkit automatically
         adjusts the case of any of the string field objects, when the user
         leaves the field (see page 11.13).

Controlling User Input                                                     11-43

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

         SetForceCase(On:boolean);

         The SetForceCase method is used to control whether the case of the
         string input is adjusted while the user is typing in the string. Pass a
         True parameter to force the case adjustment (as specified with the
         method SetCase) every time a character is pressed. Pass a False parame-
         ter if you want the string to be adjusted only when the user moves to
         another field.


         The following function methods return information about the current
         default settings:


         LabelCol(Element:byte): byte;

         This function method returns the current attribute for displaying field
         labels. Pass a parameter with a value between 1 and 4 to indicate which
         attribute you want to determine. The parameter values represent the
         following colors:

              1     Not highlighted normal attribute.
              2     Not highlighted high attribute.
              3     Highlighted normal attribute.
              4     Highlighted high attribute.


         ButtonCol(Element:byte): byte;

         Returns the attribute byte of the Button text.


         GroupCol(Element: byte): byte;

         Returns the attribute byte of radio button and check box fields.


         ListCol(Element:byte): byte;

         Returns the attribute byte of the list fields.


         FieldCol(Element:byte): byte;

         Returns the attribute byte of the string fields. Pass a parameter with
         a value between 1 and 4 to indicate which attribute you want to deter-
         mine. The parameter values represent the following colors:

              1     Highlighted attribute.
              2     Not highlighted attribute.
              3     Attribute of mask character in picture fields.
              4     Attribute of inactive (non-selectable) fields.


         MessageCol: byte;


11-44                                                               User's Guide

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

         Returns the attribute used for writing the highlighted field's message.


         InputPadChar: char;

         Returns that character which is used to fill a field when the input is
         shorter than the field length.


         InputJust: tJust;

         Returns the default string justification (see page 11-13)


         InputCursorLoc: tCursPos;

         Returns the default cursor position (see page 11-13).


         InputCase: tCase;

         Returns the default case setting for string fields (see page 11-13).


         InputForceCase: boolean;

         Returns true if user input is forced to a specific case when each
         character is input.


         If you want to reset all the IOTOT settings back to the original Tool-
         kit defaults, all you have to do is call the SetDefaults method as
         follows:

                  IOTOT^.SetDefaults;

         By looking at the actual Toolkit code for the SetDefaults method, you
         can quickly determine the default values.

         procedure InputOBJ.SetDefaults;
         {}
         begin
            if Monitor^.ColorOn then {color System}
            begin
               SetColLabel(78,76,79,76);
               SetColButton(32,46,47,46);
               SetColGroup(48,62,63,62);
               SetColList(48,62,31,30);
               SetColField(48,31,23,71);
            end
            else
            begin
               SetColLabel(112,126,127,126);
               SetColButton(32,46,47,46);
               SetColGroup(48,62,63,62);


Controlling User Input                                                     11-45

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

               SetColList(48,62,31,30);
               SetColField(48,31,23,24);
            end;
            SetColMsg(0);
            vInputPad := chr(250);
            vCase := Leave;
            vForceCase := false;
            vInputJust :=  JustLeft;
            vCursorLoc := CursPrev;
            vInsert := false;
            vRules :=  AllowNull;
         end; {InputOBJ.SetDefaults}



Form Management

         In this section, the various techniques for combining a collection of
         fields into a form will be explained. You have already learned the
         complicated stuff! All you have to do is create a FormOBJ instance and
         tell it which field object to include in the form.

         FormOBJ is the form manager and is located in the totIO1 unit. To build
         a form, initialize the FormOBJ instance, add the fields that will
         create the form, and instruct the Toolkit to process the user input.
         The following FormOBJ methods perform these services:


         Init;

         This method initializes the FormOBJ instance, and should always be
         called first.


         AddItem(var NewItem: ItemIOOBJ);

         This method should be called once for every field on the form. The only
         passed parameter is an object descended from ItemIOOBJ, i.e. any of the
         objects discussed so far in this chapter.


         Go:tAction;

         Having added all the items, call the function method Go to activate the
         form, and process the user's input. The function returns one of the
         following members of the enumerated type tAction: Finished, Escaped,
         Stop1 through Stop9. The value returned will depend on which button or
         key the user pressed. Based on the return value, you can decide how to
         process the user-entered data.



11-46                                                               User's Guide

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

         In addition to the standard user input fields, the totIO1 unit includes
         a special object, ControlKeysIOOBJ, which is used to control how the
         user moves between fields and terminates input. Every form you create
         should include a ControlKeysIOOBJ instance. ControlKeysIOOBJ objects
         provide the following three methods:


         Init;

         This method initializes the object and must be called first. The object
         actually provides the Toolkit with four special keys: the key to move
         on to the next field, the key to move back to the previous field, the
         key to finish the edit session, and the key to abort the edit session.
         When the ControlIOOBJ object is initialized, these keys are set to
         [KEYCAP], [KEYCAP], [KEYCAP] and [KEYCAP], respectively.


         SetKeys(Next,Prev,Fin,Esc:word);

         This method is used to override the default keys. The method is passed
         the four key codes which represent the keys for moving to the next
         field, moving back to the previous field, to finish editing, and to
         abort editing. For example, the statement

                 SetKeys(336,328,335,27);

         will set the keys to [KEYCAP], [KEYCAP], [KEYCAP] and [KEYCAP]. Be
         careful which keys you select. For example, if you have a word wrap
         field, you probably don't want to use the up and down arrows. Each time
         the user presses the down arrow to edit the next line, he/she will jump
         to the next field!


         Done;

         This should be called to dispose of the object when it is no longer
         required.




         Listed below is the example DEMIO2.PAS, which was first introduced at
         the beginning of the chapter. It shows how to use some of these basic
         FormOBJ methods. Refer back to figure 11.2 on page 11-4 to see the
         resultant output.

         program DemoIOTwo;
         {demIO2 - full field input}

         Uses DOS, CRT,
              totFAST, totIO1, totIO2;



Controlling User Input                                                     11-47

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

         Var
            Name: LateralIOOBJ;
            Phone: PictureIOOBJ;
            Price: FixedRealIOOBJ;
            Keys: ControlkeysIOOBJ;
            Manager: FormOBJ;
            Result: tAction;

         procedure InitVars;
         {}
         begin
            with Name do
            begin
               Init(35,5,20,40);
               SetLabel('Vendor Name');
            end;
            with Phone do
            begin
               Init(35,7,'(###) ###-####');
               SetLabel('Tel');
            end;
            with Price do
            begin
               Init(35,9,8,2);
               SetLabel('Unit Price');
               SetValue(250.0);
               SetMinMax(0.1,12250.0);
               SetRules(EraseDefault);
            end;
            Keys.Init;
         end; {InitVars}

         begin
            ClrScr;
            Screen.TitledBox(15,3,65,11,76,79,78,2,' Quicky Input Demo ');
            Screen.WriteCenter(25,white,'Press TAB to switched fields and
                                         press ESC or F10 to end');
            InitVars;
            with Manager do
            begin
               Init;
               AddItem(Keys);
               AddItem(Name);
               AddItem(Phone);
               AddItem(Price);
               Result := Go;
               if Result = Finished then
                  {update the database..}
               else



11-48                                                               User's Guide

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

                  {call Esc routine};
            end;
         end.




         The order in which the fields are added using AddItem will be the order
         in which the user will jump from field to field. The following FormOBJ
         method can be used to control which field is highlighted when the Go
         method is called:


         SetActiveItem(ID:word);

         This method instructs the Toolkit on which field to highlight first.
         The only parameter is the field ID of the field to be highlighted.
         Don't forget that any field can have a unique ID by calling the method
         SetID. By default, all fields have an ID of zero.



Hotkey Fields

         By now, you should know that any field can have a hotkey assigned with
         the method SetHotKey. There is one remaining type of field that has not
         yet been discussed. Namely, HotkeyIOOBJ objects. These fields are "in-
         visible" and are used to add special Hotkeys to the form.

         HotkeyIOBJ objects only have the following two methods:


         Init(HK:word;Act:tAction);

         A HotkeyIOOBJ object has only two properties. It has a keycode, which
         represents the key that must be pressed to invoke it, and it has an
         action code of type tAction, i.e. None, NextField, PrevField, Finished,
         Escaped, Refresh, Signal, Enter, Help, Stop1..Stop9. Whenever the user
         presses the assigned hotkey, the specified action is invoked. For exam-
         ple, if you want to assign the key [KEYCAP] (in addition to [KEYCAP])
         to end the edit session, you would initialize a HotkeyIOOBJ instance as
         follows: Init(301,Finished);


         Done;

         This disposes of the object.




Moveable Forms

         The object WinFormOBJ is a descendant of FormOBJ, and provides the same
         services with one important enhancement. WinFormOBJ manages an input


Controlling User Input                                                     11-49

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

         form on a moveable window. It is ideal for creating moveable dialog
         boxes. The Toolkit itself takes advantage of WinFormOBJ to create the
         pop-up message objects and the moveable directory dialog box.

         WinFormOBJ inherits the following methods from FormOBJ:

                  Init;
                  AddItem(var NewItem: ItemIOOBJ);
                  Done;

         Additionally, WinFormOBJ has a function method Win which returns a
         pointer to the MoveWinOBJ instance on which the form is built. To
         modify the window size and other properties, just call Win^.method,
         where method is any MoveWinOBJ instance.

         If you are going to create a window-based form using WinFormOBJ, be
         sure to create each individual field objects with relative (X,Y) coor-
         dinates. In other words, the top left of the form window will be at
         coordinates (1,1).

         Important Note: before calling the method Go, call the method Draw.
         This instructs the WinFormOBJ object to display the window and save the
         underlying screen contents.

         Refer to the on-disk example DEMIO18.PAS for a full example illustrat-
         ing the WinFormOBJ object. DEMIO18.PAS is actually an enhancement to
         the program DEMIO17.PAS, creating a text-search dialog box.



Determining User Input

         When the user has edited the form, you probably want to know what data
         was entered! First, be sure to check the tAction code returned by the
         FormOBJ method Go. This will indicate whether the user escaped, or
         really wanted the data processed.

         The only form input objects which update the original data source are
         the word wrapping objects WWArrayIOOBJ and WWLinkIOOBJ. The Toolkit
         automatically modifies the data passed to these objects. In all other
         cases, you should call each individual object's GetValue method to
         determine the user's input.

         Review the demo programs DEMIO5,8,10,13,14 to see examples of how to
         determine user input. Also, the demo programs in the last section More
         Examples! provide still further examples.



11-50                                                               User's Guide

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

Advanced Techniques

         For the majority of situations, you have learned all you need to know
         to master form input. However, the Toolkit provides another level of
         sophistication for developers who really want to customize their input
         forms. Although this section is called Advanced Features, it does not
         mean that these features are complicated. The only reason for separa-
         ting them into a special section is because you will probably use them
         less frequently.

         There follows descriptions of how to intercept every character that is
         pressed, how to validate individual fields before allowing the user to
         leave, and how to implement a help system. The concept of raising sig-
         nals between dependent fields is also introduced.



Intercepting Every Character Press

         Many of the Toolkit's units include character hooks, which provide a
         way for you to nominate a procedure or function to be called every time
         a character is pressed. This allows you to intercept each character and
         if appropriate, invoke a special routine. You can even change the value
         of the character pressed. The FormOBJ and WinFormOBJ objects also pro-
         vide a character hook facility.

         A character hook is an external procedure which is called every time a
         key or mouse button is pressed. To utilize the character hook facility,
         all you have to do is create a function following some specific rules,
         and then call the FormOBJ method SetCharHook to instruct the Toolkit to
         use your function.

         For a function to be eligible as a character hook it must adhere to the
         following rules:

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

         Rule 2     The function must be declared with four passed parameters.
                    Parameter one must be a variable parameter of type word.
                    This parameter indicates which key the user just pressed,
                    and you may change the value of this parameter to return a
                    different key. The second and third parameters must be
                    variable parameters of type byte, and they represent the X
                    and Y coordinates of the mouse at the time the key was
                    pressed. The fourth parameter is a variable, and must be of
                    type word. This parameter indicates the field ID of the
                    currently active field. This field can be changed to another
                    ID if you want the user to jump to a different field.



Controlling User Input                                                     11-51

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

         Rule 3     The function must return a value of type tAction. This is an
                    enumerated type which indicates to the Toolkit how to
                    proceed. The members of the enumerated type are: None,
                    NextField, PrevField, Finished, Escaped, Refresh, Signal,
                    Enter, Help, Stop1..Stop9. If you want the edit session to
                    terminate, return Finished, Escaped, or Stop1 through Stop9.
                    If you have changed, inserted, or deleted any items in the
                    visible list, return Refresh. The Toolkit will then re-
                    display the entire form contents.

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

         The following function declaration follows these rules:

                  {$F+}
                  function MyCharHook(var K:word;
                                      var X,Y: byte;
                                      var FieldID:word): tAction;
                  begin
                  ...{function statements}
                     MyCharHook := NextField;
                  end;
                  {$F-}


         The following method SetCharHook is then called to instruct the Toolkit
         to call your function every time a key is pressed:


         SetCharHook(Func:CharFunc);

         This method is passed the function name of a function declared using
         the rules outlined above, e.g. SetCharHook(MyCharHook);.


         Listed below is an extract from the demo program DEMIO19.PAS. This file
         is a variation on our old favorite DEMIO2.PAS. In this case, a charac-
         ter hook has been added to intercept the key [KEYCAP]. If this key is
         pressed, a message showing the current time is displayed. Notice that
         if [KEYCAP] is pressed, the hook function replaces the actual key with
         a value of 0. This stops the active field from trying to process the
         key - a zero key is ignored by the Toolkit. Finally, the hook function
         returns a value of None, indicating that the form manager does not need
         to take special action.

         {$F+}
         function ShowTime(var K:word; var X,Y:byte; var ID:word):tAction;
         {}
         var Msg:  MessageOBJ;
         begin
            if K = 276 then {Alt-T}




11-52                                                               User's Guide

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

            begin
               with Msg do
               begin
                  Init(1,'The Time M''Lord');
                  Addline('');
                  AddLine(padcenter(CurrentTime,25,' '));
                  AddLine('');
                  Show;
                  Done;
               end;
               K := 0;
            end;
            ShowTime := none;
         end; {ShowTime}
         {$F-}

         begin
            {...}
            with Manager do
            begin
               Init;
               AddItem(Keys);
               AddItem(Name);
               AddItem(Phone);
               AddItem(Price);
               SetCharHook(ShowTime);
               Result := Go;
               {...}
            end;
         end.



Validating Input

         As well as a character hook, the FormOBJ objects provide leave field
         and enter field hooks. These functions are called when the user tries
         to leave a field, and when the user tries to enter a field. The leave
         field hook provides a way to ensure the contents of a field are valid
         before moving to another field. The enter field hook can be used to
         take some action before entering a field, e.g. display a warning mes-
         sage, or move the user to another field if a specific condition is not
         met.

         Like the character hook, both field hooks must adhere to the following
         common rules:

         Rule 1     The function must be declared as a FAR function.



Controlling User Input                                                     11-53

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

         Rule 2     The function must return a value of type tAction. This is an
                    enumerated type, which indicates to the Toolkit how to
                    proceed.

         Rule 3     The function must be at the root level.



         The hooked procedure's passed parameters are different for each hook
         type, as follows:

         Leave      The function must be declared with one variable passed
                    parameter of type word. This parameter represents the field
                    ID of the field the user is leaving. This parameter can be
                    changed to another field to instruct the Toolkit to jump to
                    a different field.

         Enter      The function must be declared with two passed parameters.
                    The first parameter is a variable parameter of type word.
                    This parameter identifies the ID of the field the user is
                    about to enter. This parameter may be modified, to instruct
                    the Toolkit to jump to a different field. The second parame-
                    ter is of type word, and it represents the ID of the field
                    the user just left.

         Listed below are two code sample procedures which adhere to the rules
         for leave and enter field hooks.

                  {$F+}
                  function MyEnterHook(var NewID:word; LastID: word):tAction
                  begin
                  ...{function statements}
                     MyEnterHook := none;
                  end;
                  {$F-}

                  {$F+}
                  function MyLeaveHook(var LastID: word):tAction
                  begin
                  ...{function statements}
                     MyLeaveHook := none;
                  end;
                  {$F-}


         The FormOBJ methods SetLeaveHook or SetEnterHook can then be called to
         instruct the Toolkit to call the specified function whenever a user
         tries to leave or enter a field.



11-54                                                               User's Guide

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

Context Sensitive Help

         The fourth category of FormOBJ user hooks is the Help hook. The Help
         hook provides a way of implementing context sensitive help into your
         form.

         To implement a help hook, all you have to do is create a procedure
         following some specific rules, and then call the FormOBJ method SetHel-
         pHook to instruct the Toolkit to use your function.

         For a function to be eligible as a character hook it must adhere to the
         following rules:

         Rule 1     The procedure must be declared as a FAR procedure.

         Rule 2     The procedure must be declared with a single passed parame-
                    ter of type word. This parameter identifies the ID of the
                    highlighted field at the time the user requested help.

         Rule 3     The procedure must be at the root level.

         The following code fragment shows a procedure which adheres to these
         rules.

                  {$F+}
                  function MyHelpHook(LastID: word);
                  begin
                  ...{help display statements}
                  end;
                  {$F-}


         If you go to the trouble of creating a help system, you ought to give
         the user some way of requesting help! The two best ways to add help are
         with a hotkey and with a help button. Either way is easy, and you ought
         to consider using both. The following code fragment shows how to imple-
         ment them:

         var
           HelpBut: Strip3dIOOBJ;
           F1key: HotkeyIOOBJ;

         begin
            {...}
            HelpBut.Init(34,12,'  ~H~elp  ',Help);
            HelpBut.SetHotkey(291);
            HelpBut.SetID(HelpID);
            F1Key.Init(315,Help);
            {...}
         end.



Controlling User Input                                                     11-55

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

         Notice that the help button is assigned an ID of HelpID. HelpID is a
         constant defined in the totIO1 unit. The likelihood is that the user
         wants help on the highlighted field, and doesn't actually want to move
         to the help button. By assigning an object an ID of HelpID, the Toolkit
         knows not to swap to it when it is selected with a mouse button or
         hotkey.

         Refer to the demo program DEMIO20.PAS for a full example of how to
         implement a help system. This program is a further enhancement to the
         search dialog box demo program discussed earlier. Figure 11.14 illus-
         trates the display generated when the user asks for help.



Figure 11.14                                                            [SCREEN]
Add a Help
System



Creating Descendant Objects

         The FormOBJ object provides four different hooks for customizing the
         form input to meet your specific needs. If you think there may be an
         OOP way to achieve the same results you are right. You can create a
         descendent object from either FormOBJ or WinFormOBJ, and replace the
         following virtual methods:

         function CharTask(var K:word; var X,Y:byte;var FieldID:word):tAction;
         function LeaveTask(var FieldID:word):tAction;
         function EnterTask(var NewID:word; OldID;word):tAction;
         procedure HelpTask(ID:word);

         The passed parameters to these virtual methods are exactly the same as
         the ones described earlier for the hooks.

         Refer to chapter 9: Managing Lists page 9-32 for a comparison of hooks
         and virtual methods.



         In some special circumstances you will want to create fields which
         interact. A good example can be found in the Toolkit object DirWinOBJ
         (discussed in chapter 10). This object has three main fields -  a
         filename input field, a list of matching files, and a list of directo-
         ries and drives. If the user enters a new file mask, the file list
         needs to be refreshed. Similarly, if the user changes directories, the
         file list and the directory list need to be updated.

         The solution is for the modified field to raise a signal when changes
         need to be made to other fields. When a field raises a signal, the
         Toolkit passes the signal to every other field in turn, and each of
         these fields may itself raise signals. Every input field object has the
         following virtual methods:



11-56                                                               User's Guide

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

         procedure RaiseSignal(var TheSig:tSignal);
         procedure HandleSignal(var BaseSig:tSignal; var NewSig:tSignal);
         procedure ShutDownSignal(var BaseSig:tSignal);

         Refer to Part 2: Extending the Toolkit for further information about
         creating input objects which raise and handle signals.



More Examples!

         There are several additional on-disk examples included in the Toolkit.
         These examples combine many of the features described in this chapter
         to provide powerful input routines. For example, IODEM21.PAS shows how
         you might use the objects to create a database access program, and
         IODEM22.PAS illustrates how you can use PgUp and PgDn to implement a
         double input screen.
