home *** CD-ROM | disk | FTP | other *** search
/ Stars of Shareware: Programmierung / SOURCE.mdf / programm / msdos / pascal / totdoc11 / chapt9.txt < prev    next >
Text File  |  1991-02-11  |  86KB  |  2,168 lines

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