home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / PROG / PASCAL / TOTDOC.ZIP / CHAPT9.TXT < prev    next >
Encoding:
Text File  |  1991-02-10  |  83.6 KB  |  2,168 lines

  1.                                                                         Managing
  2.                                                                            Lists
  3.  
  4.  
  5.  
  6.  
  7.          "Three questions are essential... What is the author's object? How far
  8.          has he accomplished it? How far is that object worthy of approbation?
  9.  
  10.                                                               Nathanial P Willis
  11.  
  12.  
  13.  
  14.  
  15. Introduction
  16.  
  17.          Lists, lists, lists. Our lives and our software are often dominated by
  18.          lists. The Toolkit provides three powerful units to help you manage
  19.          software lists. (Your lives are your own responsibility!)
  20.  
  21.          In this chapter, the totLINK and totLIST units are discussed in detail.
  22.          totLINK provides objects to help you maintain and sort large lists, and
  23.          totLIST provides objects for displaying lists and arrays in windows.
  24.  
  25.          A common form of software list is a file directory list. The Toolkit
  26.          provides two flexible directory displaying objects, and these are dis-
  27.          cussed in the next chapter.
  28.  
  29.  
  30.  
  31. Array and Linked List Theory
  32.  
  33.          One-dimensional arrays provide a very quick and convenient way of
  34.          managing lists. An array is a data structure designed to store data
  35.          about a fixed number of identical elements. For example, the following
  36.          variable could be used to store the address of my two sisters' and
  37.          three brothers' addresses:
  38.  
  39.                   Addresses: array [1..5] of string;
  40.  
  41.          Data in the array is accessed by specifying the element number. For
  42.          example, the following statement would update my second sister's
  43.          address:
  44.  
  45.                   Addresses[2] := "38 The Ridgeway, Friern Barnet, London"
  46.  
  47.  
  48.          Arrays are very easy to create, but suffer from two major weaknesses:
  49.  
  50.          q     The size of an array is fixed at compile time. In other words, in
  51.                your source code you must explicitly state the size (or bounds)
  52.                of the array. In our simple example, this was not a problem
  53.                because I have only five siblings. Imagine, however, that you
  54.                need to write a generic name and address program. You don't know
  55.                how many names and addresses will be required, but you must spec-
  56.                ify the number in your program. The typical solution is to choose
  57.                a large number of elements (e.g. 200) and hope that the user
  58.                doesn't need more. Not only does this set a limit on the pro-
  59.                gram's capacity, it also wastes memory if the maximum number of
  60.  
  61. 9-2                                                                 User's Guide
  62.  
  63. --------------------------------------------------------------------------------
  64.  
  65.                elements are not used. Turbo Pascal automatically allocates the
  66.                memory for the entire array regardless of how many elements are
  67.                actually used. Which leads us to the second shortcoming.
  68.  
  69.          q     The maximum size of a program's data segment in Turbo Pascal is
  70.                64k. This means that the sum of all the program's global vari-
  71.                ables cannot exceed 64k, and, therefore, no individual data
  72.                structure can exceed 64k. In our example, each element of the
  73.                array consumed 256 bytes, so 256 of these elements would consume
  74.                the entire data segment leaving no room for other global vari-
  75.                ables.
  76.  
  77.  
  78.  
  79.          Linked lists do not suffer from these shortcomings. With a linked list,
  80.          each element is stored independently. The first element in the list
  81.          includes a pointer indicating where the second element in the list is
  82.          stored. The second element in the list includes a pointer to the loca-
  83.          tion of the third element in the list, and so on. When you reach an
  84.          element in the list that points to NIL, you know you have reached the
  85.          end of the list. You do not need to fix the maximum number of elements
  86.          in the list at compile time. Furthermore, the data is stored on the
  87.          heap (not in the data segment) and so is not limited to 64k. The list
  88.          can use all of the available memory.
  89.  
  90.          Although linked lists are very flexible, they can prove complicated to
  91.          program and manage. Fortunately, the Toolkit provides a very powerful
  92.          object which makes managing linked lists a breeze.
  93.  
  94.  
  95.  
  96. Managing Linked Lists
  97.  
  98.          The totLINK unit includes the object DLLOBJ. This object provides a
  99.          variety of methods for creating and managing linked lists. If you are
  100.          interested, DLLOBJ actually maintains a doubly-linked list. Each ele-
  101.          ment in the list points to the next element and the previous element.
  102.          This is more efficient when you need to move up and down the list.
  103.  
  104.          The DLLOBJ object is designed to store raw data, i.e. untyped vari-
  105.          ables. This allows you to store literally any data in a DLLOBJ object.
  106.          It is important to note that DLLOBJ is an abstract object and you
  107.          should not create any instances of type DLLOBJ.
  108.  
  109.          In this chapter, we will concentrate on a descendant object, StrDLLOBJ,
  110.          designed specifically to manage lists of strings. If you want to create
  111.          objects which manage other data types, all you have to do is create an
  112.          object descended from DLLOBJ. In part 2: Extending the Toolkit, there
  113.          is a chapter describing how to create other descendants of DLLOBJ to
  114.          manage specific data types. By way of an example, it describes how to
  115.          create a linked list object for managing records.
  116.  
  117.  
  118.  
  119. Managing Lists                                                               9-3
  120.  
  121. --------------------------------------------------------------------------------
  122.  
  123.          Before exploring the StrDLLOBJ methods, you need to understand some
  124.          doubly-linked-list jargon. Each element in the list is referred to as a
  125.          node. Behind the scenes, the Toolkit keeps track of the location of the
  126.          first node in the list, the last node in the list, and the node that
  127.          was last accessed. The last-accessed node is referred to as the active
  128.          node.
  129.  
  130.  
  131.  
  132. Creating a List
  133.  
  134.          To create a linked list, you must declare an instance of type StrDLLOBJ
  135.          and then call the Init and Add methods. The syntax of these methods is
  136.          as follows:
  137.  
  138.  
  139.          Init;
  140.  
  141.          This method initializes the object and must be called before the other
  142.          methods.
  143.  
  144.  
  145.          Add(Str:string): integer;
  146.  
  147.          This function method creates a new node in the linked list and stores
  148.          it in the string Str. The node is actually created immediately follow-
  149.          ing the active node. Once the node has been added, the active node is
  150.          moved to point to it. The function returns an integer code - a 0
  151.          indicates success, a 1 indicates there was insufficient memory to
  152.          create the node, and a 2 indicates there was enough memory to create
  153.          the node, but too little memory to store the string.
  154.  
  155.  
  156.          Ordinarily, to populate a list, all you have to do is call Init, and
  157.          then make multiple calls to Add. Listed below is an extract of the demo
  158.          program, DEMLK1.PAS, which stores a list of names in a linked list.
  159.  
  160.          var
  161.            GirlFriends: StrDLLOBJ;
  162.            Retcode: integer;
  163.  
  164.          begin
  165.             with GirlFriends do
  166.             begin
  167.                Init;
  168.                Retcode := Add('Erica');
  169.                if Retcode <> 0 then exit;
  170.                Retcode := Add('Theresa');
  171.                if Retcode <> 0 then exit;
  172.                Retcode := Add('Lynn');
  173.                if Retcode <> 0 then exit;
  174.                Retcode := Add('Donna');
  175.                if Retcode <> 0 then exit;
  176.  
  177.  
  178.  
  179.  
  180. 9-4                                                                 User's Guide
  181.  
  182. --------------------------------------------------------------------------------
  183.  
  184.                Retcode := Add('Godzilla');
  185.                if Retcode <> 0 then exit;
  186.                {....}
  187.             end;
  188.          end.
  189.  
  190.  
  191.          To save checking the value of Retcode every time you add a node, you
  192.          might check that there is enough memory available for all the nodes,
  193.          and ignore the return code, as follows:
  194.  
  195.          var
  196.             GirlFriends: StrDLLOBJ;
  197.             Retcode: integer;
  198.  
  199.          begin
  200.             with GirlFriends do
  201.             begin
  202.                Init;
  203.                if maxavail > 200 then
  204.                begin
  205.                   Retcode := Add('Erica');
  206.                   Retcode := Add('Theresa');
  207.                   Retcode := Add('Lynn');
  208.                   Retcode := Add('Donna');
  209.                   Retcode := Add('Godzilla');
  210.                   {...}
  211.                end;
  212.             end;
  213.          end.
  214.  
  215.  
  216.          In fact, if you are using Turbo Pascal 6.0 and the extended compiler
  217.          directive {$X+} has been set, you can ignore the function return value,
  218.          as follows:
  219.  
  220.          {$X+}
  221.          var
  222.             GirlFriends: StrDLLOBJ;
  223.  
  224.          begin
  225.             with GirlFriends do
  226.             begin
  227.                Init;
  228.                if maxavail > 200 then
  229.                begin
  230.                   Add('Erica');
  231.                   Add('Theresa');
  232.                   Add('Lynn');
  233.                   Add('Donna');
  234.                   Add('Godzilla');
  235.  
  236.  
  237.  
  238. Managing Lists                                                               9-5
  239.  
  240. --------------------------------------------------------------------------------
  241.  
  242.                   {...}
  243.                end;
  244.             end;
  245.          end.
  246.  
  247.  
  248. Maintaining a List
  249.  
  250.          Once you have created a list, the following methods can be used to
  251.          navigate the list:
  252.  
  253.  
  254.          TotalNodes: longint;
  255.  
  256.          This function method returns a longint identifying the total number of
  257.          nodes in the list.
  258.  
  259.  
  260.          ActiveNodeNumber: longint;
  261.  
  262.          Returns the position of the active node.
  263.  
  264.  
  265.          Jump(NodeNumber: longint)
  266.  
  267.          This method moves the ActiveNodePtr to the specified node number. Add
  268.          inserts a node after the active node pointer. So, to insert a node
  269.          anywhere in the list, call the method Jump to move the active node
  270.          pointer and then call Add.
  271.  
  272.  
  273.          Advance(Amount: longint);
  274.  
  275.          Moves the active node down the list the specified number of nodes. If
  276.          there are insufficient nodes, the active node pointer is moved to the
  277.          end of the list.
  278.  
  279.  
  280.          Retreat(Amount: longint);
  281.  
  282.          Moves the active node up the list the specified number of nodes. If
  283.          there are too few nodes, the active node pointer is moved to the begin-
  284.          ning of the list.
  285.  
  286.  
  287.  
  288.  
  289. Advanced List Management
  290.  
  291.          In many programs, all you'll need to do is create a list, add items to
  292.          the list, and then display the list using one of the browse or list
  293.          displaying objects (discussed later). However, if you want to delete
  294.          items from the list, swap the positions of two items in the list, or
  295.          change an item in the list, you will need to access the nodes in the
  296.          list directly.
  297.  
  298.  
  299. 9-6                                                                 User's Guide
  300.  
  301. --------------------------------------------------------------------------------
  302.  
  303.          Each node in the list is actually a DLLNodeOBJ object, and many of the
  304.          list manipulation methods access a pointer to the node known as a
  305.          DLLNodePtr.
  306.  
  307.          Without worrying about the details, all you need to know is how to
  308.          determine the value of DLLNodePtr for any given node. The following
  309.          four function methods serve this purpose:
  310.  
  311.  
  312.          NodePtr(NodeNumber:longint): DLLNodePtr;
  313.  
  314.          Pass this function a node number, and it will return a pointer to the
  315.          node.
  316.  
  317.  
  318.          ActiveNodePtr: DLLNodePtr;
  319.  
  320.          Returns a pointer to the active node.
  321.  
  322.  
  323.          StartNodePtr: DLLNodePtr;
  324.  
  325.          Returns a pointer to the first node in the list.
  326.  
  327.  
  328.          EndNodePtr: DLLNodePtr;
  329.  
  330.          Returns a pointer to the last node in the list.
  331.  
  332.  
  333.          Having established the DLLNodePtr value, the following methods can be
  334.          used to manipulate the node data:
  335.  
  336.  
  337.          Change(Node:DLLNodePtr;Str:string):integer;
  338.  
  339.          Changes the value at the node to Str. This function method returns an
  340.          integer to indicate whether the change was a success: 0 indicates suc-
  341.          cess, 2 indicates insufficient memory for the data, and 3 indicates an
  342.          invalid node pointer.
  343.  
  344.  
  345.          DelNode(Node:DLLNodePtr);
  346.  
  347.          Deletes the node.
  348.  
  349.  
  350.          SwapNodes(Node1,Node2:DLLNodePtr);
  351.  
  352.          Swaps the data assigned to the two nodes.
  353.  
  354.  
  355.          InsertBefore(Node:DLLNodePtr; Str:string);
  356.  
  357.  
  358.  
  359.  
  360. Managing Lists                                                               9-7
  361.  
  362. --------------------------------------------------------------------------------
  363.  
  364.          Inserts a new node immediately before the specified node. (The Add
  365.          method inserts the data after the active node.) This method provides a
  366.          way of inserting a node at the very beginning of the list. After this
  367.          method has been called, the active node pointer is set to the first
  368.          node in the list.
  369.  
  370.  
  371.          GetStr(Node:DLLNodePtr; Start,Finish:longint): string;
  372.  
  373.          This function returns a sub-string of the data stored at the specified
  374.          node. The parameters Start and Finish indicate the starting and ending
  375.          characters to be extracted in the string. For example, values of 6 and
  376.          10 will return five characters commencing with the character in posi-
  377.          tion 6 of the string. Pass values of zero for the Start and Finish
  378.          parameters, if you want the entire string.
  379.  
  380.  
  381.          Sort(SortID: shortint; Ascending: boolean);
  382.  
  383.          This powerful method rearranges the order of all the nodes in a list,
  384.          i.e. it sorts the list. The sort routine is generic and can be utilized
  385.          by any descendant of the DLLOBJ object. In the case of StrDLLOBJ, the
  386.          first parameter has no meaning, and should be set to one. If you want
  387.          the list sorted in ascending order (i.e. lowest first), pass TRUE as
  388.          the second parameter, otherwise pass FALSE.
  389.  
  390.  
  391.          Listed below is the demo program DEMLK2.PAS which illustrates many of
  392.          the methods discussed thus far. Figure 9.1 shows the generated output.
  393.  
  394.          Program DemoLinkTwo;
  395.          {DEMLK2 - creating a linked list}
  396.  
  397.          Uses CRT,
  398.               totLink;
  399.  
  400.          var
  401.             GirlFriends: StrDLLOBJ;
  402.             Retcode: integer;
  403.             I : integer;
  404.  
  405.          begin
  406.             ClrScr;
  407.             with GirlFriends do
  408.             begin
  409.                Init;
  410.                if maxavail > 200 then
  411.                begin
  412.                   Retcode := Add('Erica');
  413.                   Retcode := Add('Theresa');
  414.                   Retcode := Add('Lynn');
  415.                   Retcode := Add('Donna');
  416.                   Retcode := Add('Godzilla');
  417.  
  418.  
  419. 9-8                                                                 User's Guide
  420.  
  421. --------------------------------------------------------------------------------
  422.  
  423.                   writeln('Total nodes: ',TotalNodes);
  424.                   writeln('Active node number: ',ActiveNodeNumber);
  425.                   for I := 1 to TotalNodes do
  426.                       writeln(GetStr(NodePtr(I),0,0));
  427.                   writeln;
  428.                   RetCode := InsertBefore(NodePtr(4),'Joyce');
  429.                   writeln('Total nodes: ',TotalNodes);
  430.                   writeln('Active node number: ',ActiveNodeNumber);
  431.                   SwapNodes(NodePtr(5),NodePtr(2));
  432.                   Retcode := Change(StartNodePtr,'Ekka');
  433.                   for I := 1 to TotalNodes do
  434.                       writeln(GetStr(NodePtr(I),0,0));
  435.                   writeln;
  436.                   writeln('Sorted:');
  437.                   Sort(1,true);
  438.                   for I := 1 to TotalNodes do
  439.                       writeln(GetStr(NodePtr(I),0,0));
  440.                end;
  441.             end;
  442.          end.
  443.  
  444.  
  445.  
  446. Figure 9.1                                                              [SCREEN]
  447. Using
  448. StrDLLOBJ
  449.  
  450.  
  451.  
  452. Removing a List
  453.  
  454.          Calling the method Done will always dispose of all the memory consumed
  455.          by a list. A list can also be emptied with the following method:
  456.  
  457.  
  458.          EmptyList;
  459.  
  460.          Removes all the memory allocated on the heap by chaining back through
  461.          the list and disposing of each node. The ActiveNodePtr, StartNodePtr
  462.          and EndNodePtr are set to nil, and TotalNodes is set to nil.
  463.  
  464.  
  465.  
  466. Comparing StrDLLOBJ to Arrays
  467.  
  468.          If you have never used linked lists before, but you have used arrays,
  469.          you might be interested in comparing array commands with StrDLLOBJ com-
  470.          mands. Table 9.1 compares the command syntax by manipulating a list of
  471.          5 names.
  472.  
  473.  
  474.                         StrDLLOBJ                        String Array
  475.  
  476.  
  477.  
  478. Managing Lists                                                               9-9
  479.  
  480. --------------------------------------------------------------------------------
  481.  
  482.            Declaring the Variable or Instance
  483.            var NameList: StrDLLOBJ;            var NameList: array[1..5] of
  484.                                                string;
  485.  
  486.            Initializing the List
  487.            NameList.Init;                      fillchar(NameList,sizeof(NameLis
  488.                                                t),#0);
  489.            Populating the List
  490.            with NameList do                    NameList[1] := 'Mark';
  491.            begin                               NameList[2] := 'Kirk';
  492.               Retcode := Add('Mark');          NameList[3] := 'Lloyd';
  493.               Retcode := Add('Kirk');          NameList[4] := 'Charles';
  494.               Retcode := Add('LLoyd');         NameList[5] := 'Keith';
  495.               Retcode := Add('Charles');
  496.               Retcode := Add('Keith');
  497.            end;
  498.  
  499.            Writing an item to the display
  500.            with NameList do                    writeln(NameList[3]);
  501.             writeln(GetStr(NodePtr(3),0,0));
  502.  
  503.            Swapping two items
  504.            with NameList do                    Temp := NameList[4];
  505.             SwapNodes(NodePtr(4),NodePtr(5));  NameList[4] := NameList[5];
  506.                                                NameList[5] := Temp;
  507.  
  508.            Sorting the List
  509.            NameList.Sort(1,true);              Ugh!
  510.  
  511.            Erasing the Entries
  512.            NameList.EmptyList;                 fillchar(NameList,sizeof(NameLis
  513.                                                t),#0);
  514.  
  515.  
  516.  
  517.  
  518.          Don't forget that the StrDLLOBJ is much more memory efficient, and is
  519.          not limited to a set number of elements.
  520.  
  521.          Much of the power of DLLOBJ is not realized until you create descendant
  522.          objects, customized for your specific needs. Refer to Part 2: Extending
  523.          The Toolkit for further details.
  524.  
  525.  
  526.  
  527. Browse Lists
  528.  
  529.          Whether your data is in a DLLOBJ (or descendant) object, or in a string
  530.          array, you will want to take advantage of the Toolkit's objects for
  531.  
  532.  
  533.  
  534. 9-10                                                                User's Guide
  535.  
  536. --------------------------------------------------------------------------------
  537.  
  538.          automatically displaying lists in windows. In this section, the Brow-
  539.          seOBJ family of objects will be discussed. These objects display lists
  540.          in a scrollable window.
  541.  
  542.  
  543.            Note that a browse window does not include a highlight bar. The
  544.            user browses the contents of the list, but does not select an
  545.            individual element. The ListOBJ family (discussed in the next sec-
  546.            tion) provides objects for highlighting individual elements in a
  547.            list.
  548.  
  549.  
  550.  
  551.  
  552.          Figure 9.2 shows the object hierarchy for the BrowseOBJ family. The
  553.          base object BrowseOBJ is abstract, and you should not create any
  554.          instances of this type. The BrowseArrayOBJ object displays the contents
  555.          of a string array, and the BrowseLinkOBJ displays the contents of an
  556.          object in the DLLOBJ family. Many programs need to display the contents
  557.          of ASCII files, and the object BrowseFileOBJ makes this a snap.
  558.  
  559.  
  560. Figure 9.2                                                             [PICTURE]
  561. BrowseOBJ
  562. Object Hierarchy
  563.  
  564.  
  565.  
  566.  
  567.  
  568. Common Methods
  569.  
  570.          The totLOOK unit includes an object LookTOT which is used to control
  571.          the overall look and feel of applications developed with the Toolkit.
  572.          Call the method LookTOT^.SetListKeys to change the keys which the user
  573.          can press to close the browse window. The defaults are [KEYCAP] and
  574.          [KEYCAP]. Refer to page 3-12 for further details.
  575.  
  576.          Because all the objects are derived from the BrowseOBJ, they share a
  577.          set of common methods. The following methods can be used with any of
  578.          the browse objects:
  579.  
  580.  
  581.          SetTopPick(TopPick: longint);
  582.  
  583.          This method identifies the node number of the first node that will be
  584.          displayed in the list window.
  585.  
  586.  
  587.          SetStartCol(Column: longint);
  588.  
  589.          This method identifies the character position of the first character of
  590.          the string which is visible in the list window.
  591.  
  592.  
  593.  
  594.  
  595. Managing Lists                                                              9-11
  596.  
  597. --------------------------------------------------------------------------------
  598.  
  599.          SetEndCol(Column: longint);
  600.  
  601.          This method sets the maximum lateral scrolling by identifying the last
  602.          column which will be displayed when the window is scrolled to the right
  603.          maximum. All lateral scrolling can be disabled by calling the Stretch-
  604.          WinOBJ method SetScrollable (discussed later).
  605.  
  606.  
  607.          Show;
  608.  
  609.          This method displays the list and immediately returns control back to
  610.          the calling procedure, i.e. the Toolkit does not wait for user input.
  611.          This option is useful if you want to display the list on the screen,
  612.          but not activate it.
  613.  
  614.  
  615.          Go;
  616.  
  617.          This method is the main "do it" method. If the list is not on display,
  618.          it is drawn. The Toolkit then processes user input until an end key is
  619.          pressed.
  620.  
  621.  
  622.          LastKey:word;
  623.  
  624.          LastKey returns the key code of the key the user pressed to end the
  625.          browse session. This is used if you need to know whether the user
  626.          escaped or pressed the finish key.
  627.  
  628.  
  629.          Done;
  630.  
  631.          As always, Done disposes of the Browse window object, and should always
  632.          be called when the object is no longer required.
  633.  
  634.  
  635.  
  636. Modifying the Window Characteristics
  637.  
  638.          The list data is displayed in a window of type StretchWinOBJ. You can
  639.          modify any window attribute by directly calling the StretchWinOBJ meth-
  640.          ods. BrowseOBJ includes a function method, Win, which returns a pointer
  641.          to the StretchWinOBJ instance. To modify the window, call the
  642.          appropriate StretchWinOBJ method using the following syntax:
  643.  
  644.                   [BrowseOBJInstance].Win^.method
  645.  
  646.          For example, the following statements would change the default window
  647.          size, style and title:
  648.  
  649.                   var MyBrowser: BrowseLinkOBJ;
  650.  
  651.                   begin
  652.                      with MyBrowser do
  653.                      begin
  654.  
  655.  
  656. 9-12                                                                User's Guide
  657.  
  658. --------------------------------------------------------------------------------
  659.  
  660.                         Init;
  661.                         Win^.SetSize(1,1,50,20,3);
  662.                         Win^.SetTitle('My Browser');
  663.                      end;
  664.                   end.
  665.  
  666.  
  667.          All the display colors used by the browse objects are controlled by the
  668.          underlying window attributes. To change the browse display colors call
  669.          the window method SetColors, e.g.
  670.  
  671.                   Win^.SetColors(23,23,31,30);
  672.  
  673.  
  674.          Call Win^ methods to set all the browse window characteristics, e.g.
  675.          colors, title, remove status, boundaries, etc. Refer to chapter 7:
  676.          Using Windows for a thorough discussion of the StretchWinOBJ methods.
  677.  
  678.  
  679.  
  680. Browsing Arrays
  681.  
  682.          The BrowseArrayOBJ object provides a very simple way to browse the
  683.          contents of a string array. In addition to the common methods just
  684.          described, there is another method as follows:
  685.  
  686.  
  687.          AssignList(var StrArray; Total:longint; StrLength:byte);
  688.  
  689.          AssignList identifies the string array that will be displayed. The
  690.          three parameters are the string array, the total number of elements in
  691.          the array, and the length of each string in the array. The string
  692.          length parameter must reflect the string length of the array when it
  693.          was declared, not the maximum length of any string assigned to the
  694.          array.
  695.  
  696.  
  697.          For example, if a string array was declared as follows:
  698.  
  699.                   MyGirls: array[1..54] of string;
  700.  
  701.          then the list is assigned with the following calls:
  702.  
  703.                   with MyBrowser do
  704.                   begin
  705.                      Init;
  706.                      AssignList(MyGirls,54,255);
  707.                      {...}
  708.                   end;
  709.  
  710.  
  711.  
  712. Managing Lists                                                              9-13
  713.  
  714. --------------------------------------------------------------------------------
  715.  
  716.          Having assigned the list, all you need to do is call Show and the
  717.          browse window will pop onto the display. Listed below is a the demo
  718.          program DEMBR1, followed by figure 9.3 illustrating the resultant dis-
  719.          play.
  720.  
  721.          Program DemoBrowseArrayOne;
  722.          {SEMBR1}
  723.  
  724.          Uses DOS,CRT,
  725.               totINPUT, totFAST,totLIST, totSTR;
  726.  
  727.          var
  728.             BWin: BrowseArrayOBJ;
  729.             StringList: array[1..26] of string[100];
  730.             I : integer;
  731.  
  732.          begin
  733.             for I := 1 to 26 do  {first assign something to the string array}
  734.                StringList[I] := 'Line '+
  735.                                 IntToStr(I)+': '+
  736.                                 replicate(80,char(I+64));
  737.             Screen.Clear(white,'░'); {paint the screen}
  738.             Key.SetFast;
  739.             Key.SetClick(true);
  740.             with BWin do
  741.             begin
  742.                Init;
  743.                AssignList(StringList,26,100);
  744.                Go;
  745.                Done;
  746.             end;
  747.          end.
  748.  
  749.  
  750. Figure 9.3                                                              [SCREEN]
  751. Browsing an
  752. Array
  753.  
  754.  
  755.  
  756.          The demo program DEMBR2.PAS, listed below, is very similar to
  757.          DEMBR1.PAS. The only difference is that two Win^ methods are called to
  758.          modify the default window settings. Figure 9.4 shows the impact on the
  759.          display.
  760.  
  761.          Program DemoBrowseArray;
  762.  
  763.          Uses DOS,CRT,
  764.               totFAST,totLIST, totSTR;
  765.  
  766.  
  767.  
  768. 9-14                                                                User's Guide
  769.  
  770. --------------------------------------------------------------------------------
  771.  
  772.          var
  773.             BWin: BrowseArrayOBJ;
  774.             StringList: array[1..26] of string[100];
  775.             I : integer;
  776.          begin
  777.             for I := 1 to 26 do  {first assign something to the string array}
  778.                StringList[I] := 'Line '+
  779.                                 IntToStr(I)+': '
  780.                                 +replicate(80,char(I+64));
  781.             Screen.Clear(white,'░'); {paint the screen}
  782.             with BWin do
  783.             begin
  784.                Init;
  785.                AssignList(StringList,26,100);
  786.                Win^.SetSize(30,5,50,15,2);
  787.                Win^.SetTitle('Array Browse Demo');
  788.                Go;
  789.                Done;
  790.             end;
  791.          end.
  792.  
  793.  
  794. Figure 9.4                                                              [SCREEN]
  795. Modifying the
  796. Browse Window
  797.  
  798. Browsing Linked Lists
  799.  
  800.          The BrowseLinkOBJ is very similar to the BrowseArrayOBJ, the primary
  801.          difference being that BrowseLinkOBJ displays the data stored in a
  802.          DLLOBJ object rather than in an array.
  803.  
  804.          In addition to the common methods described, there are two additional
  805.          methods as follows:
  806.  
  807.  
  808.          AssignList(Var LinkList: DLLOBJ);
  809.  
  810.          This method is passed a DLLOBJ instance, or any instance of an object
  811.          derived from DLLOBJ, e.g. StrDLLOBJ.
  812.  
  813.  
  814.          ListPtr: DLLPtr;
  815.  
  816.          This method returns a pointer to the DLLOBJ used to create the list.
  817.          You can access the linked list by using the syntax MyBrow-
  818.          ser.ListPtr^.method.
  819.  
  820.  
  821.          Listed below is the program DEMBR3.PAS, which illustrates how to build
  822.          a large list of 500 items and display it in a browse window. Figure 9.5
  823.          shows the browse display.
  824.  
  825.  
  826.  
  827. Managing Lists                                                              9-15
  828.  
  829. --------------------------------------------------------------------------------
  830.  
  831.          Program DemoBrowseList;
  832.  
  833.          Uses DOS,CRT,
  834.               totFAST, totLINK, totLIST, totSTR;
  835.  
  836.          var
  837.             BWin: BrowseLinkOBJ;
  838.             LL : StrDLLOBJ;
  839.  
  840.          procedure CreateLinkedList;
  841.          {}
  842.          var
  843.            I, Retcode : integer;
  844.          begin
  845.             with LL do
  846.             begin
  847.                Init;
  848.                for I := 1 to 500 do
  849.                   Retcode := Add('This is line '+IntToStr(I)+
  850.                              ': '+replicate(200,char(random(255))));
  851.             end; {with}
  852.          end; {CreateLinkedList}
  853.  
  854.          begin
  855.             Screen.Clear(white,'░'); {paint the screen}
  856.             CreateLinkedList;
  857.             with BWin do
  858.             begin
  859.                Init;
  860.                AssignList(LL);
  861.                Win^.SetTitle('List Browse Demo');
  862.                Go;
  863.                Done;
  864.             end;
  865.             LL.Done
  866.          end.
  867.  
  868.  
  869. Figure 9.5                                                              [SCREEN]
  870. Browsing a
  871. StrDLLOBJ
  872.  
  873.  
  874.  
  875. Browsing Files
  876.  
  877.          The BrowseFileOBJ object makes browsing ASCII text files easy. Browse-
  878.          FileOBJ is descended from BrowseOBJ and inherits all the associated
  879.          methods. In addition, the following method AssignFile is used to
  880.          instruct the object on which file to display:
  881.  
  882.  
  883.  
  884. 9-16                                                                User's Guide
  885.  
  886. --------------------------------------------------------------------------------
  887.  
  888.          AssignFile(Filename:string): integer;
  889.  
  890.          This function method is passed a string indicating the name of the file
  891.          to be browsed. Behind the scenes, this function loads the file from
  892.          disk into a temporary StrDLLOBJ object. The function will return a 0 if
  893.          the file was successfully loaded. A return value of 1 indicates that
  894.          the file was not found, and so cannot be displayed. A return value of 2
  895.          indicates that there wasn't enough memory to load the entire file. In
  896.          such an instance you may want to use a MessageOBJ to advise the user
  897.          that only part of the file can be browsed.
  898.  
  899.  
  900.          That's all there is to it! Just declare a BrowseFileOBJ instance and
  901.          call the methods Init, AssignFile and Go:
  902.  
  903.                   var FileWin: BrowseFileOBJ;
  904.                   begin
  905.                      with FileWin do
  906.                      begin
  907.                         Init;
  908.                         if AssignFile('Help.TXT') = 0 then
  909.                            Go;
  910.                         Done;
  911.                      end;
  912.                   end.
  913.  
  914.  
  915.          The following method can be used to directly access the linked list
  916.          created by the BrowseFileOBJ instance:
  917.  
  918.  
  919.          ListPtr: StrDLLPtr;
  920.  
  921.          This method returns a pointer to the StrDLLOBJ used to create the list.
  922.          You can access the linked list by using the syntax MyFile.ListPtr^.me-
  923.          thod.
  924.  
  925.  
  926.          Listed below is the example program, DEMBR4.PAS. This small program
  927.          will display the contents of either a file specified on the command
  928.          line when the program was executed, or (if no parameters were speci-
  929.          fied) the contents of c:\autoexec.bat.
  930.  
  931.  
  932.  
  933.          Program DemoBrowseFile;
  934.  
  935.          Uses DOS,CRT,
  936.               totFAST, totINPUT, totLINK, totLIST, totSTR;
  937.          const
  938.             DefaultFile = '\autoexec.bat';
  939.          var
  940.  
  941.  
  942.  
  943. Managing Lists                                                              9-17
  944.  
  945. --------------------------------------------------------------------------------
  946.  
  947.             BWin: BrowseFileOBJ;
  948.             RetCode: integer;
  949.             Filename: string;
  950.  
  951.          begin
  952.             Screen.Clear(white,'░'); {paint the screen}
  953.             if ParamCount = 0 then
  954.                FileName := DefaultFile
  955.             else
  956.                FileName := ParamStr(1);
  957.             with BWin do
  958.             begin
  959.                Init;
  960.                Retcode := AssignFile(Filename);
  961.                if Retcode in [0,2] then
  962.                   Go
  963.                else
  964.                   Writeln('Unable to load file: ',Filename,'.');
  965.                   Key.DelayKey(2000);
  966.                Done;
  967.             end;
  968.          end.
  969.  
  970.  
  971.  
  972. 9-18                                                                User's Guide
  973.  
  974. --------------------------------------------------------------------------------
  975.  
  976. Selection Lists
  977.  
  978.          So far, this chapter has focused on browse windows, where the user can
  979.          simply scroll data vertically and horizontally. By contrast, a list
  980.          window is designed to display selectable items, much like a menu. One
  981.          of the items within the list window is always highlighted, and the list
  982.          may be organized into single or multiple columns. The scroll bars are
  983.          used to move the item highlight bar. The list is removed when the user
  984.          presses an end key such as [KEYCAP] or [KEYCAP], when the user presses
  985.          [KEYCAP], or when the user double-clicks the mouse on an item.
  986.  
  987.          When appropriate, users may even select, or tag, multiple items from
  988.          the list, and each selected item is marked with a special character.
  989.          The tag status of the highlighted option can be toggled by hitting the
  990.          [KEYCAP]. All items can be tagged or untagged at once by pressing [KEY-
  991.          CAP] and [KEYCAP], respectively.
  992.  
  993.          Figure 9.6 shows a typical list window.
  994.  
  995.  
  996. Figure 9.6                                                              [SCREEN]
  997. A Typical List
  998. Window
  999.  
  1000.  
  1001.          By default, a list window is stretchable, and if the user changes the
  1002.          dimensions, the Toolkit adjusts the displayed columns and rows. Figure
  1003.          9.7 is the same List window as shown in figure 9.6, after the user has
  1004.          stretched the window.
  1005.  
  1006.  
  1007. Figure 9.7                                                              [SCREEN]
  1008. A Stretched List
  1009. Window
  1010.  
  1011.  
  1012.  
  1013.          The primary Toolkit object for displaying lists in a window is ListOBJ,
  1014.          but this is an abstract object which should not be instanciated. Lis-
  1015.          tOBJ has a number of descendants designed to display different data
  1016.          types in lists. Figure 9.8 illustrates the ListOBJ object hierarchy.
  1017.  
  1018.          The object hierarchy is similar in principle to the BrowseOBJ hierar-
  1019.          chy, with the following main objects:
  1020.  
  1021.          ListArrayOBJ    Displays a list derived from a string array.
  1022.  
  1023.          ListLinkOBJ     Displays a list derived from any DLLOBJ object or
  1024.                          descendant.
  1025.  
  1026.          ListDirOBJ &    These two objects are used for displaying directories
  1027.          ListDirSortOBJ  in a list window and are discussed in the next chapter.
  1028.  
  1029.  
  1030.  
  1031. Managing Lists                                                              9-19
  1032.  
  1033. --------------------------------------------------------------------------------
  1034.  
  1035. Figure 9.8                                                             [PICTURE]
  1036. ListOBJ
  1037. Object Hierarchy
  1038.  
  1039.  
  1040.  
  1041. Common Methods
  1042.  
  1043.          LookTOT (in the unit totLook) is used to control the overall look and
  1044.          feel of applications developed with the Toolkit. As well as the window-
  1045.          related methods, the following two LookTOT methods impact all list
  1046.          objects:
  1047.  
  1048.          SetListKeys     Identifies the keys to globally tag or untag windows,
  1049.                          and close the list display.
  1050.  
  1051.          SetListChars    Identifies the characters which will highlight the
  1052.                          active item, as well as the characters which identify
  1053.                          the tagged and non-tagged items.
  1054.  
  1055.          Refer to page 3-12 for further details.
  1056.  
  1057.  
  1058.          Because all the list objects are derived from the ListOBJ, they share a
  1059.          set of common methods. The following methods can be used with any of
  1060.          the list objects:
  1061.  
  1062.  
  1063.          SetTopPick(TopPick: longint);
  1064.  
  1065.          This method identifies the node number of the first node that will be
  1066.          displayed in the list window, i.e. the first visible item in the list.
  1067.          By default, this is the first item in the list.
  1068.  
  1069.  
  1070.          SetActivePick(ThePick:longint);
  1071.  
  1072.          The highlighted item is referred to as the active pick. This procedure
  1073.          is used to set which item (or pick) will be highlighted when the list
  1074.          is first displayed. The passed parameter represents the number of the
  1075.          item in the visible window, with the top left item having a value of
  1076.          one. For example, if the top pick (the first visible pick) was item
  1077.          number 12 and you wanted to highlight the 15th item, pass a value of
  1078.          four. This will instruct the Toolkit to highlight the fourth visible
  1079.          pick. The default is the top pick. If an invalid value is used, e.g.
  1080.          the value is greater than the number of visible picks, the value is set
  1081.          to the top pick.
  1082.  
  1083.  
  1084.          SetTagging(On:boolean);
  1085.  
  1086.          This method is used to identify whether the user will be allowed to tag
  1087.          and untag items. Pass true to enable item tagging.
  1088.  
  1089.  
  1090.  
  1091.  
  1092. 9-20                                                                User's Guide
  1093.  
  1094. --------------------------------------------------------------------------------
  1095.  
  1096.          SetColWidth(Wid:byte);
  1097.  
  1098.          This sets the width of each column in characters. If the column width
  1099.          is set to zero, the list will be displayed in a single column only, and
  1100.          the column width will be as wide as the window. When setting the column
  1101.          width, remember to allow for the additional characters used to high-
  1102.          light the active pick, and to signify tagged and non-tagged items.
  1103.  
  1104.  
  1105.          Show;
  1106.  
  1107.          This method displays the list and immediately returns control to the
  1108.          calling procedure, i.e. the Toolkit does not wait for user input. This
  1109.          option is useful if you want to display the list on the screen, but not
  1110.          activate it.
  1111.  
  1112.  
  1113.          Go;
  1114.  
  1115.          This method is the main "do it" method. If the list is not on display,
  1116.          it is drawn. The Toolkit then processes user input until an end key is
  1117.          pressed.
  1118.  
  1119.  
  1120.          GetHiString:string;
  1121.  
  1122.          This function returns a string representing the highlighted item's
  1123.          data.
  1124.  
  1125.  
  1126.          LastKey:word;
  1127.  
  1128.          LastKey returns the key code of the key the user pressed to end the
  1129.          browse session. This is used if you need to know whether the user
  1130.          escaped or pressed the done key.
  1131.  
  1132.  
  1133.          Done;
  1134.  
  1135.          As always, Done disposes of the Browse window object, and should always
  1136.          be called when the object is no longer required.
  1137.  
  1138.  
  1139.  
  1140. Modifying Window Characteristics
  1141.  
  1142.          Like BrowseOBJ, the list data is displayed in a window of type Stretch-
  1143.          WinOBJ. You can modify any window attribute by directly calling the
  1144.          StretchWinOBJ methods.  ListOBJ includes a function method, Win, which
  1145.          returns a pointer to the StretchWinOBJ instance. To modify the window,
  1146.          call the appropriate StretchWinOBJ method using the following syntax:
  1147.  
  1148.                   [ListOBJInstance].Win^.method
  1149.  
  1150.          For example, the following statements would change the default window
  1151.          size, style and title:
  1152.  
  1153. Managing Lists                                                              9-21
  1154.  
  1155. --------------------------------------------------------------------------------
  1156.  
  1157.                   var MyLister: ListLinkOBJ;
  1158.  
  1159.                   begin
  1160.                      with MyList do
  1161.                      begin
  1162.                         Init;
  1163.                         Win^.SetSize(1,1,50,20,3);
  1164.                         Win^.SetTitle('My Lister');
  1165.                      end;
  1166.                   end.
  1167.  
  1168.  
  1169.          Call Win^ methods to set the list window characteristics, e.g. colors,
  1170.          title, remove status, boundaries, etc. Refer to chapter 7: Using Win-
  1171.          dows for a thorough discussion of the StretchWinOBJ methods.
  1172.  
  1173.  
  1174.  
  1175.  
  1176.            Note: the display colors used in list objects are controlled by
  1177.            two different methods. The attributes of the list window perime-
  1178.            ter, i.e. box, title, scroll bars and icons, are set using the
  1179.            method:
  1180.                             Win^.SetColors.
  1181.            The display attributes for the body of the window, i.e. the items
  1182.            in the list, are controlled using the ListOBJ method SetColors,
  1183.            which is discussed later in this section.
  1184.  
  1185.  
  1186.  
  1187.  
  1188. Listing Arrays
  1189.  
  1190.          The ListArrayOBJ object provides an easy way to display a list based on
  1191.          the contents of a string array. In addition to the common methods just
  1192.          described, there is the following method:
  1193.  
  1194.  
  1195.          AssignList(var StrArray;Total:longint;
  1196.                     StrLength:byte;Taggable:boolean);
  1197.  
  1198.          AssignList identifies the string array that will be displayed. The four
  1199.          parameters are the string array, the total number of elements in the
  1200.          array, the length of each string in the array, and a boolean to indi-
  1201.          cate whether individual items can be tagged. The string length parame-
  1202.          ter must reflect the string length of the array when it was declared,
  1203.          not the maximum length of any string assigned to the array.
  1204.  
  1205.  
  1206.          Having assigned the list, all you need to do is call Show, and the
  1207.          browse window will pop onto the display. Listed below is the demo pro-
  1208.          gram DEMLS1.PAS.
  1209.  
  1210.  
  1211.  
  1212. 9-22                                                                User's Guide
  1213.  
  1214. --------------------------------------------------------------------------------
  1215.  
  1216.          program DemoList1;
  1217.          {demls1}
  1218.  
  1219.          Uses DOS, CRT,
  1220.               totFAST, totLIST;
  1221.  
  1222.          Var
  1223.             Items : array [1..20] of string[30];
  1224.             ListWin:  ListArrayObj;
  1225.  
  1226.          procedure FillArray;
  1227.          {}
  1228.          begin
  1229.             Items[1] := 'One';
  1230.             Items[2] := 'Two';
  1231.             Items[3] := 'Three';
  1232.             Items[4] := 'Four';
  1233.             Items[5] := 'Five';
  1234.             Items[6] := 'Six';
  1235.             Items[7] := 'Seven';
  1236.             Items[8] := 'Eight';
  1237.             Items[9] := 'Nine';
  1238.             Items[10] := 'Ten';
  1239.             Items[11] := 'Eleven';
  1240.             Items[12] := 'Twelve';
  1241.             Items[13] := 'Thirteen';
  1242.             Items[14] := 'Fourteen';
  1243.             Items[15] := 'Fifteen';
  1244.             Items[16] := 'Sixteen';
  1245.             Items[17] := 'Seventeen';
  1246.             Items[18] := 'Eighteen';
  1247.             Items[19] := 'Nineteen';
  1248.             Items[20] := 'Twenty';
  1249.          end; {FillArray}
  1250.  
  1251.          begin
  1252.             Screen.Clear(white,'░'); {paint the screen}
  1253.             FillArray;
  1254.             with ListWin do
  1255.             begin
  1256.                Init;
  1257.                AssignList(Items,20,30,true);
  1258.                Go;
  1259.                Done;
  1260.             end;
  1261.          end.
  1262.  
  1263.  
  1264.          This is a very basic list which uses all the default settings. Figure
  1265.          9.9 illustrates the resultant display.
  1266.  
  1267.  
  1268.  
  1269. Managing Lists                                                              9-23
  1270.  
  1271. --------------------------------------------------------------------------------
  1272.  
  1273. Figure 9.9                                                              [SCREEN]
  1274. A Basic List
  1275. Window
  1276.  
  1277.          The following few statements are an extract from the demo file
  1278.          DEMLS2.PAS which is very similar to the previous demo, except that the
  1279.          list window has been customized somewhat:
  1280.  
  1281.             with ListWin do
  1282.             begin
  1283.                Init;
  1284.                AssignList(Items,20,30,true);
  1285.                SetColWidth(15);
  1286.                Win^.SetTitle(' Pick a number! ');
  1287.                Win^.SetSize(24,7,55,18,2);
  1288.                Go;
  1289.                Done;
  1290.             end;
  1291.  
  1292.  
  1293.          By calling the SetColWidth method, the list has been transformed from a
  1294.          single list to a multi-column list. Refer back to figure 9.7 to see the
  1295.          output generated from DEMLS2.PAS.
  1296.  
  1297.          The program DEMLS3.PAS is yet another refinement of the array list
  1298.          demo. In this on-disk file, the following statement is added to change
  1299.          the list tagging and highlighting characters:
  1300.  
  1301.                LookTOT^.SetListChars(chr(16),chr(17),chr(14),chr(32));
  1302.  
  1303.  
  1304.  
  1305. Listing Linked Lists
  1306.  
  1307.          The ListLinkOBJ is very similar to the ListArrayOBJ. The primary dif-
  1308.          ference is that ListLinkOBJ displays the data stored in a DLLOBJ object
  1309.          rather than in an array.
  1310.  
  1311.          In addition to the common methods described earlier, there are the
  1312.          following two methods:
  1313.  
  1314.  
  1315.          AssignList(var LinkList: DLLOBJ);
  1316.  
  1317.          This method is passed a DLLOBJ instance, or any instance of an object
  1318.          derived from DLLOBJ, e.g. StrDLLOBJ.
  1319.  
  1320.  
  1321.          ListPtr: DLLPtr;
  1322.  
  1323.          This method returns a pointer to the DLLOBJ used to create the list.
  1324.          You can access the linked list by using the syntax MyList.ListPtr^.me-
  1325.          thod.
  1326.  
  1327.  
  1328.  
  1329.  
  1330. 9-24                                                                User's Guide
  1331.  
  1332. --------------------------------------------------------------------------------
  1333.  
  1334.          The demo program DEMLS4.PAS (listed below) shows how well StrDLLOBJ and
  1335.          ListLinkOBJ work together. This small demo program creates an StrDLLOBJ
  1336.          instance called ItemList. The list is populated by reading the contents
  1337.          of an ASCII file. The ListLinkOBJ instance ListWin is then used to
  1338.          display the file contents in a window. Figure 9.10 shows the generated
  1339.          screen display.
  1340.  
  1341.          program DemoList4;
  1342.          {demls4 - reading a list from a text file}
  1343.  
  1344.          Uses DOS, CRT,
  1345.               totFAST, totLINK, totLIST;
  1346.  
  1347.          Var
  1348.             ListWin:  ListLinkObj;
  1349.             ItemList: StrDLLOBJ;
  1350.             FileOK: boolean;
  1351.  
  1352.          procedure LoadLinkedList;
  1353.          {}
  1354.          var
  1355.            F: text;
  1356.            Line:string;
  1357.            Result: integer;
  1358.          begin
  1359.             with ItemList do
  1360.             begin
  1361.                Init;
  1362.                {$I-}
  1363.                Assign(F,'demls4.txt');
  1364.                Reset(F);
  1365.                {$I+}
  1366.                FileOK := (IOResult = 0);
  1367.                if not FileOK then
  1368.                   Result := Add('File not found')
  1369.                else
  1370.                begin
  1371.                   while not eof(F) do
  1372.                   begin
  1373.                      Readln(F,Line);
  1374.                      Result := Add(Line);
  1375.                   end;
  1376.                   close(F);
  1377.                end;
  1378.             end;
  1379.          end; {LoadLinkedList}
  1380.  
  1381.  
  1382.  
  1383. Managing Lists                                                              9-25
  1384.  
  1385. --------------------------------------------------------------------------------
  1386.  
  1387.          begin
  1388.             Screen.Clear(white,'░'); {paint the screen}
  1389.             LoadLinkedList;
  1390.             with ListWin do
  1391.             begin
  1392.                Init;
  1393.                AssignList(ItemList);
  1394.                SetColWidth(15);
  1395.                Win^.SetTitle(' Items from file DEMLS4.TXT ');
  1396.                Win^.SetSize(20,5,60,20,1);
  1397.                if not FileOk then
  1398.                   SetTagging(false);
  1399.                Go;
  1400.                Done;
  1401.             end;
  1402.             ItemList.Done;
  1403.          end.
  1404.  
  1405.  
  1406. Figure 9.10                                                             [SCREEN]
  1407. Display a List
  1408. From a File
  1409.  
  1410.  
  1411.  
  1412. Determining Which Items are Tagged
  1413.  
  1414.          Earlier you learned that by calling the method SetTagging(true), you
  1415.          could allow the user to tag and untag items. The Toolkit provides the
  1416.          method SetStatus to allow you to pre-tag (or, indeed, pre-untag!) items
  1417.          before the list is displayed. Similarly, the method GetStatus is used
  1418.          to determine the status of any item in the list.
  1419.  
  1420.          Before explaining the syntax of these methods, we need to take a little
  1421.          peek behind the scenes. The Toolkit stores eight different flags for
  1422.          each item in the list. These flags are numbered 0 through 7.  Flag 0 is
  1423.          used to determine whether the user has tagged the item. Flag 1 indi-
  1424.          cates which color to use in dual color mode (discussed later). The
  1425.          remaining flags are not used and can be customized for descendant
  1426.          objects. Refer to Part 2: Extending the Toolkit for more information.
  1427.  
  1428.          The syntax of the SetStatus method is as follows:
  1429.  
  1430.  
  1431.          SetStatus(Pick:longint; BitPos: byte; On:boolean);
  1432.  
  1433.          To pre-tag an item, call the SetStatus method and pass three parame-
  1434.          ters. The first parameter specifies the item to be modified, the second
  1435.          parameter is the flag number (and this should be set to 0 (zero) to
  1436.          modify the tag flag), and the third boolean parameter should be set to
  1437.          True to tag the item, or False to un-tag it.
  1438.  
  1439.  
  1440.  
  1441. 9-26                                                                User's Guide
  1442.  
  1443. --------------------------------------------------------------------------------
  1444.  
  1445.          After the user has removed the list window, and before the Done method
  1446.          is called, the GetStatus method can be called to see which selections
  1447.          the user made. The syntax of GetStatus is as follows:
  1448.  
  1449.  
  1450.          GetStatus(Pick:longint; BitPos: byte): boolean;
  1451.  
  1452.          This function method returns true if the identified item flag is set
  1453.          on. The first parameter identifies the item number, and the second
  1454.          parameter should be set to 0 (zero) to get the status of the tag flag.
  1455.  
  1456.  
  1457.          The following demo program, DEMLS5.PAS, shows how to check for all the
  1458.          tagged items. The program writes a list of all the tagged items.
  1459.  
  1460.          program DemoList5;
  1461.          {demls5 - selecting all tagged items}
  1462.  
  1463.          Uses DOS, CRT,
  1464.               totFAST, totLINK, totLIST;
  1465.  
  1466.          Var
  1467.             ListWin:  ListLinkObj;
  1468.             ItemList: StrDLLOBJ;
  1469.             FileOK: boolean;
  1470.             L,Total: longint;
  1471.  
  1472.          procedure LoadLinkedList;
  1473.          {}
  1474.          var
  1475.            F: text;
  1476.            Line:string;
  1477.            Result: integer;
  1478.          begin
  1479.             with ItemList do
  1480.             begin
  1481.                Init;
  1482.                {$I-}
  1483.                Assign(F,'demls4.txt');
  1484.                Reset(F);
  1485.                {$I+}
  1486.                FileOK := (IOResult = 0);
  1487.                if not FileOK then
  1488.                   Result := Add('File not found')
  1489.                else
  1490.                begin
  1491.                   while not eof(F) do
  1492.                   begin
  1493.                      Readln(F,Line);
  1494.                      Result := Add(Line);
  1495.                   end;
  1496.                   close(F);
  1497.  
  1498.  
  1499. Managing Lists                                                              9-27
  1500.  
  1501. --------------------------------------------------------------------------------
  1502.  
  1503.                end;
  1504.             end;
  1505.          end; {LoadLinkedList}
  1506.  
  1507.          begin
  1508.             Screen.Clear(white,'░'); {paint the screen}
  1509.             LoadLinkedList;
  1510.             with ListWin do
  1511.             begin
  1512.                Init;
  1513.                AssignList(ItemList);
  1514.                SetColWidth(15);
  1515.                Win^.SetTitle(' Items from file DEMLS4.TXT ');
  1516.                Win^.SetSize(20,5,60,20,1);
  1517.                if not FileOk then
  1518.                   SetTagging(false);
  1519.                Go;
  1520.                Remove;
  1521.                Total := ItemList.TotalNodes;
  1522.                clrscr;
  1523.                for L := 1 to Total do
  1524.                   if GetStatus(L,0) then
  1525.                      Writeln('Selected: ',GetString(L,0,0));
  1526.                Done;
  1527.             end;
  1528.             ItemList.Done;
  1529.          end.
  1530.  
  1531.  
  1532.          In a real application, you might call a procedure to process the tagged
  1533.          items, rather than simply write a list of all tagged items.
  1534.  
  1535.          If you are displaying a linked list, you can take advantage of the
  1536.          DLLOBJ method DelAllStatus. This method is used to automatically remove
  1537.          entries from the list which have one of the status flags set in a
  1538.          specified state. The syntax of the DLLOBJ method is as follows:
  1539.  
  1540.  
  1541.          DelAllStatus(BitPos:byte; On:boolean);
  1542.  
  1543.          This method removes all entries from the linked list which have the
  1544.          specified flag set in the specified state. The first parameter indi-
  1545.          cates the flag number, in the range 0 to 7. The second parameter deter-
  1546.          mines whether all the flags set to True or False will be deleted. For
  1547.          example, to remove all tagged entries in a linked list you would call
  1548.          the method DelAllStatus(0,true);.
  1549.  
  1550.  
  1551.  
  1552. 9-28                                                                User's Guide
  1553.  
  1554. --------------------------------------------------------------------------------
  1555.  
  1556. Displaying Dual Colored Lists
  1557.  
  1558.          All list objects are capable of displaying each item in one of two
  1559.          color combinations. This facility is put to good effect in the ListDi-
  1560.          rOBJ object (discussed in the next chapter), where the files are dis-
  1561.          played in one color, and the subdirectories in another. The following
  1562.          two methods impact the list display colors:
  1563.  
  1564.  
  1565.          SetColors(HAttr,NAttr,SAttr: byte);
  1566.  
  1567.          This method sets the display attributes for the items in the list. The
  1568.          first parameter specifies the attribute of the active pick. The other
  1569.          two attributes specify the attributes for the normal items. If the
  1570.          status (discussed below) of the normal item is set to high, the SAttr
  1571.          attribute will be used, otherwise the NAttr will be used.
  1572.  
  1573.  
  1574.          SetDualColors(On:boolean);
  1575.  
  1576.          If you want to exploit the dual color capabilities of the list objects,
  1577.          pass True. Passing a False will force all the items to display in the
  1578.          same color.
  1579.  
  1580.  
  1581.          The Toolkit has to have some way of identifying the status of each
  1582.          item, i.e. in which attribute the color should be displayed. The second
  1583.          of the status flags, i.e. flag 1, is designated as the color flag. The
  1584.          SetStatus and GetStatus flags are used to control the color feature, as
  1585.          follows:
  1586.  
  1587.  
  1588.          SetStatus(Pick:longint; BitPos: byte; On:boolean);
  1589.  
  1590.          This method is used to set the status of any item in the list. The
  1591.          first parameter identifies the number of the item to be set. The second
  1592.          parameter should be set to 1 (one) to indicate that the color status
  1593.          flag is being set. The final parameter is a boolean to indicate whether
  1594.          status is on (True) or off (False).
  1595.  
  1596.  
  1597.  
  1598.          GetStatus(Pick:longint; BitPos: byte): boolean;
  1599.  
  1600.          This function method returns true if the identified item flag is set
  1601.          on. The first parameter identifies the item number, and the second
  1602.          parameter should be set to 1 (one) to determine the status of the dual
  1603.          color flag.
  1604.  
  1605.          An example of the dual color facility is included in the DEMLS7.PAS,
  1606.          discussed in the Character Hook section at the end of the chapter.
  1607.  
  1608.  
  1609.  
  1610. Managing Lists                                                              9-29
  1611.  
  1612. --------------------------------------------------------------------------------
  1613.  
  1614. Displaying Messages about the Highlighted Pick
  1615.  
  1616.          The ListOBJ object family supports the optional display of a message at
  1617.          the bottom of the list window. This message is normally related to the
  1618.          currently highlighted pick. The message might be a long description of
  1619.          a terse pick, or some other information about the highlighted pick.
  1620.  
  1621.          There are two different ways to instruct the Toolkit to display a mes-
  1622.          sage. The no-fuss way is to write a special procedure (called a message
  1623.          hook) and instruct the Toolkit to call this procedure every time a pick
  1624.          is highlighted. The alternative is to take advantage of an OOP feature
  1625.          known as Polymorphism.
  1626.  
  1627.          Once a message displaying routine has been implemented, it can be dis-
  1628.          abled and enabled using the following method:
  1629.  
  1630.  
  1631.          SetMsgState(On:boolean);
  1632.  
  1633.          Pass True to activate the message display, or False to deactivate it.
  1634.  
  1635.  
  1636.  
  1637. Using a Message Hook
  1638.  
  1639.          A message hook is an external function which is called every time a new
  1640.          pick is highlighted. To utilize the message hook facility, all you have
  1641.          to do is create a function following some specific rules, and then call
  1642.          the method SetMsgHook to instruct the Toolkit to use your function.
  1643.  
  1644.          For a function to be eligible as a message hook it must adhere to the
  1645.          following rules:
  1646.  
  1647.          Rule 1     The function must be declared as a FAR function. This can be
  1648.                     achieved by preceding the function with a {$F+} compiler
  1649.                     directive, and following the function with a {$F-} direc-
  1650.                     tive. Alternatively, Turbo 6 users can use the new keyword
  1651.                     FAR following the function statement.
  1652.  
  1653.          Rule 2     The function must be declared with one passed parameter of
  1654.                     type longint. This parameter indicates the highlighted item
  1655.                     number.
  1656.  
  1657.          Rule 3     The function must return a value of type string. This return
  1658.                     value is the actual text to be displayed in the message area
  1659.                     of the window display.
  1660.  
  1661.          Rule 4     The function must be at the root level, i.e. the function
  1662.                     cannot be nested within another procedure or function.
  1663.  
  1664.          The following function declaration follows these rules:
  1665.  
  1666.  
  1667.  
  1668. 9-30                                                                User's Guide
  1669.  
  1670. --------------------------------------------------------------------------------
  1671.  
  1672.                   {$F+}
  1673.                   function MyMessageHook(HiPick:longint): string;
  1674.                   begin
  1675.                   ...{function statements}
  1676.                      MyMessageHook := 'something!';
  1677.                   end;
  1678.                   {$F-}
  1679.  
  1680.  
  1681.          The following method SetMsgHook is then called to instruct the Toolkit
  1682.          to call your function every time a new item is highlighted:
  1683.  
  1684.  
  1685.          SetMsgHook(Func:ListMsgFunc);
  1686.  
  1687.          This method is passed the function name of a function declared using
  1688.          the rules outlined above, e.g. SetMsgHook(MyMessageHook);
  1689.  
  1690.  
  1691.  
  1692.          The demo program DEMLS6 (listed below) implements a message hook. In
  1693.          this case the message is simply a phrase stating which topic is high-
  1694.          lighted. I hope your applications are a little more useful! Figure 9.11
  1695.          illustrates the resultant output.
  1696.  
  1697.  
  1698.  
  1699.          program DemoList6;
  1700.          {demls6 - displaying a list message}
  1701.  
  1702.          Uses DOS, CRT,
  1703.               totFAST, totLINK, totLIST, totSTR, totMSG;
  1704.  
  1705.          Var
  1706.             ListWin:  ListLinkObj;
  1707.             ItemList: StrDLLOBJ;
  1708.             FileOK: boolean;
  1709.  
  1710.          {$F+}
  1711.          function MsgHook(HiPick:longint):string;
  1712.          {}
  1713.          begin
  1714.             MsgHook := 'The Hi Pick is '+IntToStr(HiPick);
  1715.          end; {MsgHook}
  1716.          {$F-}
  1717.  
  1718.          procedure LoadLinkedList;
  1719.          {}
  1720.          var
  1721.            F: text;
  1722.            Line:string;
  1723.            Result: integer;
  1724.          begin
  1725.             with ItemList do
  1726.  
  1727.  
  1728.  
  1729. Managing Lists                                                              9-31
  1730.  
  1731. --------------------------------------------------------------------------------
  1732.  
  1733.             begin
  1734.                Init;
  1735.                {$I-}
  1736.                Assign(F,'demls4.txt');
  1737.                Reset(F);
  1738.                {$I+}
  1739.                FileOK := (IOResult = 0);
  1740.                if not FileOK then
  1741.                   Result := Add('File not found')
  1742.                else
  1743.                begin
  1744.                   while not eof(F) do
  1745.                   begin
  1746.                      Readln(F,Line);
  1747.                      Result := Add(Line);
  1748.                   end;
  1749.                   close(F);
  1750.                end;
  1751.             end;
  1752.          end; {LoadLinkedList}
  1753.  
  1754.          begin
  1755.             Screen.Clear(white,'░'); {paint the screen}
  1756.             LoadLinkedList;
  1757.             with ListWin do
  1758.             begin
  1759.                Init;
  1760.                AssignList(ItemList);
  1761.                SetColWidth(15);
  1762.                SetMsgHook(MsgHook);
  1763.                Win^.SetTitle(' A List With Messages ');
  1764.                Win^.SetSize(20,5,60,20,2);
  1765.                Win^.SetMinSize(20,7);
  1766.                if not FileOk then
  1767.                   SetTagging(false);
  1768.                Go;
  1769.                Done;
  1770.             end;
  1771.             ItemList.Done;
  1772.          end.
  1773.  
  1774.  
  1775. Figure 9.11                                                             [SCREEN]
  1776. A List with a Mes-
  1777. sage
  1778.  
  1779.  
  1780.  
  1781. 9-32                                                                User's Guide
  1782.  
  1783. --------------------------------------------------------------------------------
  1784.  
  1785. Creating a Descendant Object
  1786.  
  1787.          By design, most of the documentation on customizing the Toolkit with
  1788.          object oriented techniques is to be found in Part 2: Extending the
  1789.          Toolkit. However, as an appetizer, this section explains how to take
  1790.          advantage of OOP to implement your own message method, without needing
  1791.          to pass a procedure as a parameter. The message hook procedure
  1792.          described in the previous section is perfectly adequate and acceptable,
  1793.          but it isn't OOP! If you want to learn a few OOP tidbits, read on,
  1794.          otherwise be content with the message hook and skip to the next sec-
  1795.          tion.
  1796.  
  1797.          Usually, to customize a Toolkit object to better meet your needs, you
  1798.          create a descendant object. For illustration, we will modify the List-
  1799.          LinkOBJ object. Whenever you create a descendant object, you should
  1800.          study the parent object's methods and decide which ones to replace or
  1801.          modify.
  1802.  
  1803.          A descendant object contains all the data and methods of its parent. As
  1804.          a bare minimum, you should always define new Init and Done methods, and
  1805.          then replace any other methods that you wish to improve or modify. (You
  1806.          can also add new methods, but we'll leave that to Part 2!).
  1807.  
  1808.          The ListLinkOBJ method includes the following virtual method:
  1809.  
  1810.          function MessageTask(HiPick:longint):string;   VIRTUAL;
  1811.  
  1812.          This method is called every time a new topic is highlighted, and it
  1813.          returns the text to be displayed. Since this method is declared VIR-
  1814.          TUAL, we can replace the method in a descendant object, and other
  1815.          methods will use the newly defined version of MessageTask.
  1816.  
  1817.          The objective is to create a new object descendant from ListLinkOBJ,
  1818.          and replace the MessageTask method with a new routine. The syntax for
  1819.          declaring the new object type is as follows:
  1820.  
  1821.          Type
  1822.          NewListLinkOBJ = object (ListLinkOBJ)
  1823.            constructor Init;
  1824.            function    MessageTask(HiPick:longint):string;   VIRTUAL;
  1825.            destructor  Done;                                 VIRTUAL;
  1826.          end; {NewListLinkOBJ}
  1827.  
  1828.  
  1829.          The descendant object will be called NewListLinkOBJ. Notice that the
  1830.          special constructor and destructor procedures Init and Done are
  1831.          declared, as well as the new MessageTask function. The constructor and
  1832.          destructor methods are required when an object includes virtual meth-
  1833.          ods, as it instructs Turbo Pascal to manage procedure calls differ-
  1834.          ently. The keywords constructor and destructor are simply used as
  1835.          replacements for procedure. The de facto OOP standard is to name the
  1836.          constructor INIT and the destructor DONE.
  1837.  
  1838.  
  1839.  
  1840. Managing Lists                                                              9-33
  1841.  
  1842. --------------------------------------------------------------------------------
  1843.  
  1844.          If the ancestor method is declared VIRTUAL, the descendant method must
  1845.          also be declared virtual. Furthermore, when you substitute virtual
  1846.          methods in a descendant object, the declaration of the method must be
  1847.          exactly the same as the ancestor. For this reason, MessageTask and Done
  1848.          are both declared virtual, with the same parameters as ListLinkOBJ.
  1849.  
  1850.          Having declared a new type NewListLinkOBJ, you must write the actual
  1851.          object methods in the body of your program or unit. In this case, Turbo
  1852.          Pascal expects the three object methods Init, MessageTask and Done.
  1853.          Listed below is an example of how these methods might be written.
  1854.  
  1855.          constructor NewListLinkOBJ.Init;
  1856.          {}
  1857.          begin
  1858.             ListLinkOBJ.Init;
  1859.             vMsgActive := true;
  1860.          end; {NewListLinkOBJ.Init}
  1861.  
  1862.          function NewListLinkOBJ.MessageTask(HiPick:longint):string;
  1863.          {}
  1864.          begin
  1865.             MessageTask := 'The Hi Pick is '+IntToStr(HiPick);
  1866.          end; {NewListLinkOBJ.MessageTask}
  1867.  
  1868.          destructor NewListLinkOBJ.Done;
  1869.          {}
  1870.          begin
  1871.             ListLinkOBJ.Done;
  1872.          end; {NewListLinkOBJ.Done}
  1873.  
  1874.          Notice that each method starts with the object name followed by a
  1875.          period followed by the method identifier. Whenever you declare an Init
  1876.          or Done method, you should always call the ancestors Init or Done --
  1877.          very often, this ancestor method performs important data initialization
  1878.          tasks, and let's not forget that a descendant object assumes all the
  1879.          data of its ancestor.
  1880.  
  1881.          In the new Init method, the variable vMsgActive is set to true. (All
  1882.          object variables in the Toolkit commence with the letter "v".) This
  1883.          variable indicates that the object should always call the message dis-
  1884.          play method when the active topic is changed. In the LinkListOBJ, this
  1885.          variable defaults to false, and is changed to true when the method
  1886.          SetMsgHook is called. The main purpose of this descendant object is to
  1887.          replace the old MessageTask method with a new one. In the new method,
  1888.          the string value returned is just the statement identifying the high-
  1889.          lighted topic.
  1890.  
  1891.          That's it. Any instance of NewListLinkOBJ will automatically display
  1892.          the string returned by the new MessageTask method. Listed below is the
  1893.          example DEMLS7.PAS which shows the example in its entirety.
  1894.  
  1895.  
  1896.  
  1897. 9-34                                                                User's Guide
  1898.  
  1899. --------------------------------------------------------------------------------
  1900.  
  1901.          program DemoList7;
  1902.          {demls7 - creating a descendant ListObject}
  1903.  
  1904.          Uses DOS, CRT,
  1905.               totFAST, totLINK, totLIST, totSTR, totMSG;
  1906.  
  1907.          Type
  1908.            NewListLinkOBJ = object (ListLinkOBJ)
  1909.               {Methods...}
  1910.               Constructor Init;
  1911.               function    MessageTask(HiPick:longint):string;   VIRTUAL;
  1912.               destructor  Done;                                 VIRTUAL;
  1913.            end; {NewListLinkOBJ}
  1914.  
  1915.          Var
  1916.             ListWin:  NewListLinkObj;
  1917.             ItemList: StrDLLOBJ;
  1918.             FileOK: boolean;
  1919.  
  1920.          {+++++new object methods+++++}
  1921.          constructor NewListLinkOBJ.Init;
  1922.          {}
  1923.          begin
  1924.             ListLinkOBJ.Init;
  1925.             vMsgActive := true;
  1926.          end; {NewListLinkOBJ.Init}
  1927.  
  1928.          function  NewListLinkOBJ.MessageTask(HiPick:longint):string;
  1929.          {}
  1930.          begin
  1931.             MessageTask := 'The Hi Pick is '+IntToStr(HiPick);
  1932.          end; {NewListLinkOBJ.MessageTask}
  1933.  
  1934.          destructor NewListLinkOBJ.Done;
  1935.          {}
  1936.          begin
  1937.             ListLinkOBJ.Done;
  1938.          end; {NewListLinkOBJ.Done}
  1939.          {+++++end of new object methods+++++}
  1940.  
  1941.          procedure LoadLinkedList;
  1942.          {}
  1943.          var
  1944.            F: text;
  1945.            Line:string;
  1946.            Result: integer;
  1947.          begin
  1948.             with ItemList do
  1949.             begin
  1950.                Init;
  1951.                {$I-}
  1952.  
  1953.  
  1954.  
  1955. Managing Lists                                                              9-35
  1956.  
  1957. --------------------------------------------------------------------------------
  1958.  
  1959.                Assign(F,'demls4.txt');
  1960.                Reset(F);
  1961.                {$I+}
  1962.                FileOK := (IOResult = 0);
  1963.                if not FileOK then
  1964.                   Result := Add('File not found')
  1965.                else
  1966.                begin
  1967.                   while not eof(F) do
  1968.                   begin
  1969.                      Readln(F,Line);
  1970.                      Result := Add(Line);
  1971.                   end;
  1972.                   close(F);
  1973.                end;
  1974.             end;
  1975.          end; {LoadLinkedList}
  1976.  
  1977.          begin
  1978.             Screen.Clear(white,'░'); {paint the screen}
  1979.             LoadLinkedList;
  1980.             with ListWin do
  1981.             begin
  1982.                Init;
  1983.                AssignList(ItemList);
  1984.                SetColWidth(15);
  1985.                Win^.SetTitle(' A List With Messages ');
  1986.                Win^.SetSize(20,5,60,20,2);
  1987.                Win^.SetMinSize(20,7);
  1988.                if not FileOk then
  1989.                   SetTagging(false);
  1990.                Go;
  1991.                Done;
  1992.             end;
  1993.             ItemList.Done;
  1994.          end.
  1995.  
  1996.  
  1997.          This example works just like DEMLS6.PAS, but a descendant object was
  1998.          created rather than passing a procedure. I know what you are thinking
  1999.          "It's a damn sight easier to pass a procedure!". That's true, and that
  2000.          is precisely why the Toolkit includes the procedure passing alterna-
  2001.          tive. By design, this first taste of OOP was a little simple. If your
  2002.          curiosity has been piqued, review the source code in the unit
  2003.          TOTLIST.PAS. You will see how the base object ListOBJ does all the
  2004.          work, and how the descendant objects ListArrayOBJ and ListLinkOBJ make
  2005.          the objects work for string arrays and linked lists. The totDIR unit
  2006.          discussed in the next chapter extends the ListLinkOBJ and customizes it
  2007.          specifically for displaying files and directories.
  2008.  
  2009.  
  2010.  
  2011. 9-36                                                                User's Guide
  2012.  
  2013. --------------------------------------------------------------------------------
  2014.  
  2015. Character Hooks
  2016.  
  2017.          The ListOBJ object family provides ways to intercept every key pressed
  2018.          by the user. This allows you to implement your own special hotkeys.
  2019.  
  2020.          Like the Message facility described earlier, there are two different
  2021.          ways to instruct the Toolkit to call a procedure every time a key is
  2022.          pressed -- by passing a procedure, or by creating a descendant object.
  2023.  
  2024.  
  2025.  
  2026. Using a Character Hook
  2027.  
  2028.          A character hook is an external procedure which is called every time a
  2029.          key or mouse button is pressed. To utilize the character hook facility,
  2030.          all you have to do is create a function following some specific rules,
  2031.          and then call the method SetCharHook to instruct the Toolkit to use
  2032.          your function.
  2033.  
  2034.          For a function to be eligible as a character hook it must adhere to the
  2035.          following rules:
  2036.  
  2037.          Rule 1     The function must be declared as a FAR function. This can be
  2038.                     achieved by preceding the function with a {$F+} compiler
  2039.                     directive, and following the function with a {$F-} direc-
  2040.                     tive. Alternatively, Turbo 6 users can use the new keyword
  2041.                     FAR following the function statement.
  2042.  
  2043.          Rule 2     The function must be declared with four (count 'em) passed
  2044.                     parameters. Parameter one must be a variable parameter of
  2045.                     type word. This parameter indicates which key the user just
  2046.                     pressed, and you may change the value of this parameter to
  2047.                     substitute a different key. The second and third parameters
  2048.                     must be variable parameters of type byte, and they represent
  2049.                     the X and Y coordinates of the mouse at the time the key was
  2050.                     pressed. The fourth parameter is non-variable, and must be
  2051.                     of type longint. This parameter indicates the highlighted
  2052.                     item number.
  2053.  
  2054.          Rule 3     The function must return a value of type tListAction. This
  2055.                     is an enumerated type which indicates to the Toolkit how to
  2056.                     proceed. The members of the enumerated type are: Finish,
  2057.                     Refresh and None. If you want the list window to terminate,
  2058.                     return Finish. If you have changed, inserted, or deleted any
  2059.                     items in the visible list, return Refresh. The Toolkit will
  2060.                     then re-display the entire window contents. Normally, how-
  2061.                     ever, you will just return None.
  2062.  
  2063.          Rule 4     The function must be at the root level, i.e. the function
  2064.                     cannot be nested within another procedure or function.
  2065.  
  2066.          The following function declaration follows these rules:
  2067.  
  2068.  
  2069.  
  2070. Managing Lists                                                              9-37
  2071.  
  2072. --------------------------------------------------------------------------------
  2073.  
  2074.                   {$F+}
  2075.                   function MyCharHook(var K:word;
  2076.                                          var X,Y: byte;
  2077.                                          HiPick:longint): tListAction;
  2078.                   begin
  2079.                   ...{function statements}
  2080.                      MyCharHook := None;
  2081.                   end;
  2082.                   {$F-}
  2083.  
  2084.  
  2085.          The following method SetCharHook is then called to instruct the Toolkit
  2086.          to call your function every time a key is pressed:
  2087.  
  2088.  
  2089.          SetCharHook(Func:ListCharFunc);
  2090.  
  2091.          This method is passed the function name of a function declared using
  2092.          the rules outlined above, e.g. SetCharHook(MyCharHook);.
  2093.  
  2094.  
  2095.          The demo program DEMLS8.PAS, listed below, implements both a message
  2096.          hook and a character hook. The character hook is checking for two spe-
  2097.          cial keys. If [KEYCAP] is pressed, a simple help screen is displayed,
  2098.          and if [KEYCAP] is pressed, the topic is changed to the alternative
  2099.          color.
  2100.  
  2101.          program DemoList8;
  2102.          {demls8 - using Message and Character hooks}
  2103.  
  2104.          Uses DOS, CRT,
  2105.               totFAST, totLINK, totLIST, totSTR, totMSG;
  2106.  
  2107.          Var
  2108.             ListWin:  ListLinkObj;
  2109.             ItemList: StrDLLOBJ;
  2110.             FileOK: boolean;
  2111.  
  2112.          {$F+}
  2113.          function HelpHook(var K:word; var X,Y: byte; HiPick:longint): tListAc-
  2114.          tion;
  2115.          {}
  2116.          var MsgWin: MessageOBJ;
  2117.          begin
  2118.             HelpHook := None;
  2119.             if K = 315 then
  2120.             begin
  2121.                with MsgWin do
  2122.                begin
  2123.                   Init(6,'Kinda Help');
  2124.                   AddLine('');
  2125.                   AddLine('In a real application, this would');
  2126.  
  2127.  
  2128.  
  2129. 9-38                                                                User's Guide
  2130.  
  2131. --------------------------------------------------------------------------------
  2132.  
  2133.                   AddLine('be a help screen, and it would give');
  2134.                   AddLine('help related to item '+IntToStr(HiPick)+'!');
  2135.                   AddLine('');
  2136.                   Show;
  2137.                   Done;
  2138.                end;
  2139.                K := 0;
  2140.             end
  2141.             else if K = 316 then {F2 so swap colors}
  2142.             begin
  2143.                ListWin.SetStatus(HiPick,1,not ListWin.GetStatus(HiPick,1));
  2144.                K := 336; {emulate down cursor}
  2145.             end;
  2146.          end; {HelpHook}
  2147.  
  2148.          function MsgHook(HiPick:longint):string;
  2149.          {}
  2150.          begin
  2151.             MsgHook := 'The Hi Pick is '+IntToStr(HiPick);
  2152.          end; {MsgHook}
  2153.          {$F-}
  2154.  
  2155.          procedure LoadLinkedList;
  2156.          {}
  2157.          var
  2158.            F: text;
  2159.            Line:string;
  2160.            Result: integer;
  2161.          begin
  2162.             with ItemList do
  2163.             begin
  2164.                Init;
  2165.                {$I-}
  2166.                Assign(F,'demls4.txt');
  2167.                Reset(F);
  2168.                {$I+}
  2169.                FileOK := (IOResult = 0);
  2170.                if not FileOK then
  2171.                   Result := Add('File not found')
  2172.                else
  2173.                begin
  2174.                   while not eof(F) do
  2175.                   begin
  2176.                      Readln(F,Line);
  2177.                      Result := Add(Line);
  2178.                   end;
  2179.                   close(F);
  2180.  
  2181.  
  2182.  
  2183. Managing Lists                                                              9-39
  2184.  
  2185. --------------------------------------------------------------------------------
  2186.  
  2187.                end;
  2188.             end;
  2189.          end; {LoadLinkedList}
  2190.  
  2191.          begin
  2192.             Screen.Clear(white,'░'); {paint the screen}
  2193.             Screen.WriteCenter(25,white,'  F1 Help   F2 Toggle Color!   [Space]
  2194.          Toggle Tag  ');
  2195.             LoadLinkedList;
  2196.             with ListWin do
  2197.             begin
  2198.                Init;
  2199.                AssignList(ItemList);
  2200.                SetColWidth(15);
  2201.                SetCharHook(HelpHook);
  2202.                SetMsgHook(MsgHook);
  2203.                SetDualColors(true);
  2204.                Win^.SetTitle(' A Multi-Colored List ');
  2205.                Win^.SetSize(20,5,60,20,2);
  2206.                Win^.SetMinSize(20,7);
  2207.                if not FileOk then
  2208.                   SetTagging(false);
  2209.                Go;
  2210.                Done;
  2211.             end;
  2212.             ItemList.Done;
  2213.          end.
  2214.  
  2215.  
  2216. Figure 9.12                                                             [SCREEN]
  2217. Using a
  2218. Character Hook
  2219.  
  2220. Creating a Descendant Object
  2221.  
  2222.          I think we've had enough OOP for one chapter. Suffice it to say that
  2223.          just like the message hook, the character hook can be implemented by
  2224.          creating a descendant object and replacing a ListLinkOBJ method called
  2225.          CharTask.
  2226.  
  2227.          The demo file DEMLS9.PAS (listed below) shows how to replace both the
  2228.          character hook and the message hook by creating a new descendant
  2229.          object.
  2230.  
  2231.          program DemoListNine;
  2232.          {demls9 - extending the LinkListOBJ object}
  2233.  
  2234.          Uses DOS, CRT,
  2235.               totFAST, totLINK, totLIST, totSTR, totMSG;
  2236.  
  2237.  
  2238.  
  2239. 9-40                                                                User's Guide
  2240.  
  2241. --------------------------------------------------------------------------------
  2242.  
  2243.          Type
  2244.            NewListLinkOBJ = object (ListLinkOBJ)
  2245.               {Methods...}
  2246.               Constructor Init;
  2247.               function    MessageTask(HiPick:longint):string;       VIRTUAL;
  2248.               function    CharTask(var K:word; var X,Y: byte;
  2249.                                    HiPick:longint): tListAction;    VIRTUAL;
  2250.               destructor  Done;                                     VIRTUAL;
  2251.            end; {NewListLinkOBJ}
  2252.  
  2253.          Var
  2254.             ListWin:  NewListLinkObj;
  2255.             ItemList: StrDLLOBJ;
  2256.             FileOK: boolean;
  2257.  
  2258.          {+++++new object methods+++++}
  2259.          constructor NewListLinkOBJ.Init;
  2260.          {}
  2261.          begin
  2262.             ListLinkOBJ.Init;
  2263.             vMsgActive := true;
  2264.          end; {NewListLinkOBJ.Init}
  2265.  
  2266.          function  NewListLinkOBJ.MessageTask(HiPick:longint):string;
  2267.          {}
  2268.          begin
  2269.             MessageTask := 'The Hi Pick is '+IntToStr(HiPick);
  2270.          end; {NewListLinkOBJ.MessageTask}
  2271.  
  2272.          function NewListLinkOBJ.CharTask(var K:word; var X,Y: byte;
  2273.                                           HiPick:longint): tListAction;
  2274.          {}
  2275.          var MsgWin: MessageOBJ;
  2276.          begin
  2277.             CharTask := none;
  2278.             if K = 315 then
  2279.             begin
  2280.                with MsgWin do
  2281.                begin
  2282.                   Init(6,'Kinda Help');
  2283.                   AddLine('');
  2284.                   AddLine('In a real application, this would');
  2285.                   AddLine('be a help screen, and it would give');
  2286.                   AddLine('help related to item '+IntToStr(HiPick)+'!');
  2287.                   AddLine('');
  2288.                   Show;
  2289.                   Done;
  2290.                end;
  2291.                K := 0;
  2292.  
  2293.  
  2294.  
  2295. Managing Lists                                                              9-41
  2296.  
  2297. --------------------------------------------------------------------------------
  2298.  
  2299.             end
  2300.             else if K = 316 then {F2 so swap colors}
  2301.             begin
  2302.                ListWin.SetStatus(HiPick,1,not ListWin.GetStatus(HiPick,1));
  2303.                K := 336; {emulate down cursor}
  2304.             end;
  2305.          end; {NewListLinkOBJ.CharTask}
  2306.  
  2307.          destructor NewListLinkOBJ.Done;
  2308.          {}
  2309.          begin
  2310.             ListLinkOBJ.Done;
  2311.          end; {NewListLinkOBJ.Done}
  2312.          {+++++end of new object methods+++++}
  2313.  
  2314.          procedure LoadLinkedList;
  2315.          {}
  2316.          var
  2317.            F: text;
  2318.            Line:string;
  2319.            Result: integer;
  2320.          begin
  2321.             with ItemList do
  2322.             begin
  2323.                Init;
  2324.                {$I-}
  2325.                Assign(F,'demls4.txt');
  2326.                Reset(F);
  2327.                {$I+}
  2328.                FileOK := (IOResult = 0);
  2329.                if not FileOK then
  2330.                   Result := Add('File not found')
  2331.                else
  2332.                begin
  2333.                   while not eof(F) do
  2334.                   begin
  2335.                      Readln(F,Line);
  2336.                      Result := Add(Line);
  2337.                   end;
  2338.                   close(F);
  2339.                end;
  2340.             end;
  2341.          end; {LoadLinkedList}
  2342.  
  2343.          begin
  2344.             Screen.Clear(white,'░'); {paint the screen}
  2345.             Screen.WriteCenter(25,white,'  F1 Help   F2 Toggle Color!   [Space]
  2346.          Toggle Tag  ');
  2347.             LoadLinkedList;
  2348.  
  2349.  
  2350.  
  2351. 9-42                                                                User's Guide
  2352.  
  2353. --------------------------------------------------------------------------------
  2354.  
  2355.             with ListWin do
  2356.             begin
  2357.                Init;
  2358.                AssignList(ItemList);
  2359.                SetColWidth(15);
  2360.                SetDualColors(true);
  2361.                Win^.SetTitle(' A Multi-Colored List ');
  2362.                Win^.SetSize(20,5,60,20,2);
  2363.                Win^.SetMinSize(20,7);
  2364.                if not FileOk then
  2365.                   SetTagging(false);
  2366.                Go;
  2367.                Done;
  2368.             end;
  2369.             ItemList.Done;
  2370.          end.
  2371.