                          Displaying Lists in Windows

                                       "He shall live and unto him shall
                                        be given of the gold of Arabia."
                                                      1662 Prayer Book

Introduction

          List, list, lists. Our lives and our software are often
     dominated by lists. Gold provides a family of flexible tools to
     help you manage software lists. (Your lives are your own
     responsibility!)

          In the last chapter you learned how data can be stored in
     single and double linked lists. In this chapter you will learn how
     the data in linked lists, as well as data stored in arrays and
     databases, can be displayed in list windows.

     Gold provides the following three categories of list window:

          Category            Description
          Quick List Windows  Many applications just want to pop-up a
                              simple (single column) list window and
                              allow the user to select one item. Gold
                              provides a simple but not very
                              customizable function RunListStrLL for
                              displaying quick and dirty lists.
          Browse Windows      As the name suggests, a browse window is
                              for browsing the contents of a list.
                              Unlike the other list catagories, a browse
                              window does not have a highlight bar --
                              there is no notion of a selected line or
                              item. The window can be scrolled
                              vertically and horizontally. Browse
                              windows are ideal for displaying file
                              contents, help text and the like.
          List Windows        List windows display data in single or
                              multiple columns, and one item in the list
                              is always highlighted, i.e. selected.The
                              user can (if the application permits it)
                              tag multiple items in the list. These
                              lists are ideal for displaying filenames,
                              or any list where the user needs to select
                              one (or more) items.
          Grid Windows        A grid window is similar to a list window
                              in as much as the user is presented with a
                              list and one item in the list is always
                              highlighted. A grid window is designed,
                              however, to provide a table or columnar
                              view of a record similar to the table
                              views in Paradox. A user can scroll right
                              and left one column at a time (as opposed
                              to one character at a time).


          In addition to providing list windows, Gold supports all these
     list types in user input forms, i.e. you can have a field on a form
     which is a browser, list or grid. These features are discussed in
     Chapter 16.

Quick and Dirty List Windows

          In the remainder of this chapter you will learn how to use the
     RunBrowse, RunList and RunGrid procedures to create flexible
     windows with a myriad of options. Before you explore these
     inticacies, you might want to consider using RunListStrLL (defined
     below) for your simple list windows.

     RunListStrLL(ListSource:StringLL;Tit:StrScreen):longint;

          Displays the contents of a stringLL in a list window. The
     function returns the number of the highlighted pick, or zero if the
     user escapes.

          This function uses the ListVars variables WX1, WY1, WX2, WY2
     and WStyle to determine the window coordinates. Sets these
     variables to appropriate values if the default window size is too
     large.

     Run the demo file DEMLIS5.PAS to see RunListStrLL in action.

Building a Flexible List Window -- A Crash Course

          No matter which type of list you are displaying, Gold needs to
     know the main properties of the data and the characteristics of the
     window in which the data will be displayed. For example, before a
     list window can be displayed, Gold needs to know some of the
     following information:

          What type of data is to be displayed, e.g. a single linked
     list, double linked list, array, etc.

          Where the data is stored, i.e. the name of the variable.
          The dimensions and style of the window.
          The window title.
          Any optional list headers and footers.
          What colors are to be used.
          Can the user tag more than one item.
          .... you get the idea.

          You define all these list characteristics by creating a
     variable (of type ListCfg, for list configuration), initializing
     the variable, and then setting various components of the variable
     to define your specific needs.

          In other words, to display a list in a window you need at
     least two variables: a list configuration variable, and a variable
     used to store the data.

          The following code (extracted from the demo file DEMLS1.PAS)
     shows a minimalist application which displays the contents of
     SingleLL in a list window:

          var
             Properties: ListCfg;
             GirlFriends: SingleLL;
             RetCode: integer;

          procedure BuildTheList;
          {}
          begin
             InitSLLStr(GirlFriends);
             SLLSetActiveList(GirlFriends);
             Retcode := SLLAddStr('Erica');
             inc(Retcode,SLLAddStr('Theresa'));
             inc(Retcode,SLLAddStr('Lynn'));
             inc(Retcode,SLLAddStr('Donna'));
             inc(Retcode,SLLAddStr('Godzilla'));
          end; { BuildTheList }

          procedure SetScreen;
          {Paints the background}
          begin
             Clear(WhiteOnBlack,'');
             ClearLine(1,YellowOnBlue);
             WriteCenter(1,UseTint,' A Simple List Window ');
             GotoXY(1,1);
          end; {SetScreen}

          begin
             BuildTheList;
             SetScreen;
             if RetCode <> 0 then
                PromptOK(' Error ','Unable to build the list')
             else
             begin
                InitListCfg(Properties);
                ListAssignSLL(Properties,Girlfriends);
                MouseShow(true);
                RunList(Properties,' My first list! ');
                MouseShow(false);
             end;
             SLLSetActiveList(GirlFriends);
             SLLDestroy;
          end. { DEMLS1 }

          In this example, the list configuration variable is named
     Properties, and the data is stored in a single linked list named
     Girlfriends. (If you are not familiar with linked lists, read the
     previous chapter before proceeding.)

          Apart from the code to paint the screen and populate the
     linked list, the list window can be displayed in just three lines
     of code:

     InitListCfg(Properties);

          Uses InitListCfg to initialize the Properties variable to
     default values.

     ListAssignSLL(Properties,Girlfriends);

          Uses ListAssignSLL to advise Properties of the data type
     (SingleLL) and location (the address of the variable Girlfriends)
     of the list data.

     RunList(Properties,' My first list! ');

     Calls RunList to display the list in a window.

          If you run DEMOLS1.PAS you will see that Gold creates a large
     list window. Since we didn't define any of the window properties,
     apart from the window title (in the call to RunList), Gold used
     some defaults.

          You can refine the list window in many ways. The following
     code fragment is an extract from DEMLS2.PAS which is the same code
     base as DEMLS1.PAS except that the window is customized to better
     fit the list of girlfriends!

          ListSetWin(Properties,25,5,55,11,1);

Defining the List Configuration

          The key to displaying list/browse/grid windows is to declare a
     variable of type ListCfg, and then call Gold functions to set
     ListCfg to meet your specific needs.

Initializing ListCfg

          Always, always, always call InitListCfg to initialize the
     ListCfg variable before calling the other list procedures and
     functions.

     InitListCFG(var ListDetails: ListCfg);

     Initializes a list configuration variable.

Assigning the Data Source

          Having initialized the ListCfg variable (I promise I won't
     repeat the fact that it must be initialized) you then need to
     update the variable with information about the list data source.
     Gold can display the contents of a SingleLL, DoubleLL, array or a
     custom data source where you supply a function to feed the list
     engine with the necessary strings. Depending on your data source,
     you would call one of the following procedures to update the
     ListCfg variable with the data source details:

     ListAssignSLL(var ListDetails: ListCfg; var TheList:SingleLL);

          Sets the ListCfg variable data source as a single linked list
     stored in the variable TheList.

     ListAssignDLL(var ListDetails: ListCfg; var TheList:DoubleLL);

          Sets the ListCfg variable data source as a double linked list
     stored in the variable TheList.

     ListAssignArray(var ListDetails: ListCfg; var ListSource;
                         StrLen:Byte;ArrayElements:byte);

          Sets the ListCfg variable data source as a string array stored
     in the variable ListSource. The last two parameters define the
     length of each string in the array, and the number of elements in
     the array, respectively.

          The ListAssignCustom procedure is discussed later in the
     section Using a Custom Data Source.

Setting Window Properties

          When the ListCfg variable is initialized, the window
     properties (such as the window position and dimensions) are set to
     some standard defaults. If these defaults are not appropriate, you
     can customize them with the following two procedures:

     ListSetWin(var ListDetails: ListCfg; X1,Y1,X2,Y2:integer;
                                              Style:byte);

          Defines the upper left and lower right corners of the window
     along with the window style. (Refer to Chapter 4 for a discussion
     of window styles.)

     ListSetGaps(var ListDetails:ListCfg;LeftGap,RightGap,
                                             BotGap,TopGap: byte);

          This procedure allows you to set the gap or whitespace area
     around the list body. The list/browse/grid data does not need to
     fill the entire window.


          If you want to change the window defaults, update the
     following variables: ListVars.X1, ListVars.Y1, ListVars.X2,
     ListVars.Y2, and ListVars.WinStyle.

Multi-Column Lists

          A list window displayed with RunList (but not RunBrowse or
     RunGrid) can display a list in multiple columns. By default, a list
     is displayed in a single column that is the width of the window,
     but the following function can be used to change the default column
     width to a fixed value:

     ListSetColWidth(var ListDetails: ListCfg; Width: byte);

          Specifies the width of each column in the list (when the list
     is displayed with RunList).

          If the column width is set to zero, or the specified column
     width is wider than the window, Gold will display the list in a
     single column.

Setting the Window Colors

          As always, the default colors are defined in the TINT
     structure, and the following elements pertain to list windows:

          ListHi1
          ListHi2
          ListNorm1
          ListNorm2
          ListMarkers
          ListScrollbarHi
          ListScrollbarNorm
          ListBorder1
          ListBorder2
          ListBorderOff
          ListTitle
          ListHeaders
          ListIcons

          You can modify the defaults (used by any new list windows
     initialized after the modification) by using the standard
     GoldSetColor procedure.

          You can modify the colors of a specific list window by using
     the following function:

     ListSetColor(var ListDetails: ListCfg; A:TintElement; C:byte);

     Sets the color of one of the elements of a list window.

          The following code is an extract from DEMLS3.PAS which
     customizes the list display colors:

          procedure CustomizeColors;
          {}
          begin
             ListSetColor(Prop,ListHi1,BlackonGreen);
             ListSetColor(Prop,ListHi2,YellowOnGreen);
             ListSetColor(Prop,ListNorm1,YellowOnMagenta);
             ListSetColor(Prop,ListNorm2,WhiteOnMagenta);
             ListSetColor(Prop,ListMarkers,LightgrayonMagenta);
             ListSetColor(Prop,ListScrollbarHi,WhiteOnMagenta);
             ListSetColor(Prop,ListScrollbarNorm,WhiteOnMagenta);
             ListSetColor(Prop,ListBorder1,YellowOnMagenta);
             ListSetColor(Prop,ListBorder2,YellowOnMagenta);
             ListSetColor(Prop,ListBorderOff,BlackOnMagenta);
             ListSetColor(Prop,ListTitle,WhiteOnMagenta);
             ListSetColor(Prop,ListHeaders,GreenOnMagenta);
             ListSetColor(Prop,ListIcons,LightCyanOnMagenta);
          end; { CustomizeColors }

Controlling Item Tagging

          List and grid windows (but not browse windows) support item
     tagging whereby a user can select or tag more than one item in a
     list. You might use this for marking items in a database to print,
     or tag files to be deleted, etc.

          Tagging is only supported in lists that have a data source of
     SingleLL or DoubleLL.

          By default a list does not support tagging. However, you can
     use the following procedure to control tagging:

     ListSetTagging(var ListDetails: ListCfg; On:boolean);

          Sets the taggability state of a list or grid. Pass a TRUE to
     allow tagging and a FALSE to disable it.

          When an item is tagged, Gold accesses the appropriate node of
     the list and updates one of the bit flags. The Gold constant TagBit
     identifies the bit flag that is set when the item is tagged.

          When the user has completed the tagging operation, you can use
     the function SLLGetBit or DLLGetBit to test the bit status of each
     item in the list.

          The demo file DEMLS4.PAS displays a list of taggable files in
     a multiple column window. The following code fragment is extracted
     from DEMLS4.PAS and shows how to test whether the items in the list
     are tagged:

           for I := 1 to Properties.TotalNodes do
           begin
              if DLLGetBit(DLLNodePtr(I),TagBit) then
              begin
                 writeln(DLLGetStr(I));
                 inc(Counter);
              end;
           end;


          Notice that the ListCfg element TotalNodes is used to
     determine how many nodes were displayed in the list window, i.e.
     Properties.TotalNodes.


Dual Colored Lists

          SingleLL- and DoubleLL-based lists support dual colored lists,
     i.e. some items are displayed in one color and other items are
     displayed in a different color. To enable dual colored lists, use
     the following function:

     ListSetTwoColors(var ListDetails: ListCfg; On:boolean);

          Pass TRUE to enable two colored lists, or FALSE for single
     colored lists.

          Having enabled the two colors, you need to mark those items in
     the list that you want displayed in the secondary color. Gold
     checks the bit named ColBit at the node to decide which color set
     to use. To force a node to be displayed in a secondary color, you
     need to set the ColBit on.

          The following code is an extract from DEMBR4.PAS which
     displays lines that contain the words procedure and function in the
     secondary color.

          NodePtr := DLL.StartNodePtr;
          while NodePtr <> nil do
          begin
             TempStr := DLLGetNodeStr(NodePtr,0,0);
             if CaseSens then
                P := pos(Str,TempStr)
             else
                P := pos(SetUpper(Str),SetUpper(TempStr));
             if P > 0 then
                DLLSetBit(NodePtr,Colbit,true);
             NodePtr := NodePtr^.NextPtr;
          end;

          If you want to synchronize the tag and color features so that
     all tagged items appear in a different color, Gold will do the work
     for you. All you have to do is use the following procedure:

     ListSetTagColor(var ListDetails: ListCfg; On:boolean);

          Pass TRUE to have tagged items appear in the secondary color,
     or FALSE to have tagged and untagged items appear in the same
     color.

Using Headers and Footers

          All three list window types (browse, list and grid) support
     multi-line headers and footers. Out of the box, Gold limits the
     number of heading lines and footer lines to 4, but you can change
     the number by assigning a different value to the constants
     ListMaxHeaders and ListMaxFooters declared in GOLDLIST.

          To minimize memory usage, all headers and footers must be
     stored as string variables in your program. (Gold simply stores a
     pointer to the variable.)

          The following six procedures can be used to manage the headers
     and footers:

     ListAssignHeader(var ListDetails: ListCfg; Line:byte; var
                                                       Heading:string);

          Sets the list configuration variable to display a string as a
     header. A string variable must be passed -- a string literal will
     not be accepted. The line must be a value in the range 1 to
     ListMaxHeaders (which defaults to 4).

     ListAssignFooter(var ListDetails: ListCfg; Line:byte; var
                                                       Footnote:string);

          Sets the list configuration variable to display a string as a
     footer. A string variable must be passed -- a string literal will
     not be accepted. The line must be a value in the range 1 to
     ListMaxFooters (which defaults to 4).

     ListSetHeaderOff(var ListDetails: ListCfg; Line:byte);

          Removes a header line which was previously assigned with
     ListAssignHeader.

     ListSetFooterOff(var ListDetails: ListCfg; Line:byte);

          Removes a header line which was previously assigned with
     ListAssignFooter.

     ListScrollHeader(var ListDetails: ListCfg; On:boolean);

          Pass TRUE if the headings should be scrolled right and left
     when the user scrolls the list body right and left, or FALSE if the
     header should remain fixed.

     ListScrollFooter(var ListDetails: ListCfg; On:boolean);

          Pass TRUE if the headings should be scrolled right and left
     when the user scrolls the list body right and left, or FALSE if the
     header should remain fixed.

          You can automatically canter a header or footer by prefixing
     the string with the ^ character.

          The following code is an extract from the demo file DEMLS5.PAS
     which shows how to add headers and footers to a list window:

          InitListCfg(Settings);
          ListAssignDLL(Settings,DLL);
          ListSetWin(Settings,1,2,80,24,1);
          ListSetTwoColors(Settings,True);
          Header1 := 'This is a header';
          Header2 := 'This is a second header';
          Footer := 'This is a footer';
          ListAssignHeader(Settings,1,Header1);
          ListAssignHeader(Settings,2,Header2);
          ListAssignFooter(Settings,1,Footer);
          CursorOff;
          RunBrowse(Settings,' Browsing '+FileName);
          CursorOn;

          Refer to the section Displaying Grid Windows for more
     information on setting headers from grid windows.

Displaying Browse Windows

          Browse windows are designed for displaying lists without a
     highlight bar. Browse windows are ideal for displaying the contents
     of text files, and displaying help text.

Browsing Files

          Normally, to display a browse window, you must create a
     ListCfg variable, set this variable as desired using the functions
     described in the last section, and populate a data variable.
     However, if you want to display the contents of a file, you can
     skip this whole process or just call the following procedure:

     RunBrowseFile(Fname:PathStr;Tit:StrScreen);

          Displays the specified file in a list window with the
     specified title.

          If the file cannot be displayed, Gold sets an error in
     GOLDLIST. Always call LastListError to check whether the call to
     RunBrowseFile was successful.

     Run the demo file DEMBRS1.PAS to see RunBrowseFile in action.

          The RunBrowseFile procedure provides a quick and dirty way to
     browse a file. You can set the window dimensions prior to calling
     the display procedure by accessing the ListVars elements WX1, WY1,
     WX2, WY2, and WinStyle. If you want more control over the display
     format, you should create a ListCfg variable, populate a DLL or SLL
     with the file contents, and use the RunBrowse procedure discussed
     below. The demo file DEMBRS2.PAS illustrates this technique.

General Browsing

          You can browse the contents of a string array, a single linked
     list, a double linked list or a custom data source. To do so, you
     must create a variable of type ListCfg, initialize the variable
     with InitListCfg and then set the variable using the Listxxx
     functions described in the last few sections. (If you have been
     User Guide surfing and are reading this section without reading the
     earlier material in this chapter, catch a wave to the beginning of
     the chapter!)

          Having set the ListCfg variable to meet your needs, just call
     RunBrowse as follows:

     RunBrowse(var ListDetails: ListCfg;Tit:StrScreen);

     Displays the data identified in ListDetails in a browse window.


          Listed below is an extract from DEMBRS3.PAS which displays the
     contents of an SLL in a window:

        InitSLLStr(SLL);
        SLLSetActiveList(SLL);
        PopulateTheList;
        InitListCfg(Settings);
        ListAssignSLL(Settings,SLL);
        ListSetWin(Settings,28,3,52,22,1);
        CursorOff;
        RunBrowse(Settings,' Browsing ');
        SLLDestroy;
        ResetStartUpMode;


Displaying List Windows

          Having read this far (you did read this far, right?), you know
     all there is to know about displaying lists in a window. To recap,
     initialize a ListCfg variable, assign a data source, and call
     RunList as follows:

     RunList(var ListDetails: ListCfg;Tit:StrScreen);

          Displays the data identified in ListDetails in a list window.

          Back on page 15-3 there is a listing of DEMLS1.PAS which shows
     how easy it is to create and display a list.

Determining the Highlighted Pick

          The ListCfg variable includes the field ActiveNode, which is
     of type longint. This variable always reflects the number of the
     node which contains the highlight bar.

Controlling List Display Characters and Hotkeys

          The ListVars variable includes the following three fields
     which control characters used to indicate the higlighted pick
     (ListLeft and ListRight) and tagged items (ListTag):

           ListLeft: string[1];
           ListRight: string[1];
           ListTag: string[1];

          You can customize the appearance of the list by assigning new
     characters to these variables.

          The keystrokes which control item tagging are stored in the
     following ListVars variables:

           ToggleKey: word;
           TagKey: word;
           UnTagKey: word;
           TagAllKey: word;
           UnTagAllKey: word;

Determining the User's Last Action

          The ListCfg variable includes the field LastAction of type
     gAction. Gold updates this variable to indicate how the user ended
     the list session. For example, if the user pressed Esc it would be
     set to Escaped.

Displaying Grid Windows

          A grid window is designed to provide a table or columnar view
     of a record and is ideal for database applications (see figure
     14.1).

          In most respects, the way to display a grid, using RunGrid, is
     identical with the way to display a list. A grid, however, needs
     additional information about the columnar aspects of the grid --
     remember that a grid scrolls left and right by column rather than
     by character, and Gold needs to know the logical column widths, or
     tabs.

          In the example, when the user presses the right cursor (or
     clicks the mouse on the horizontal scroll bar), the display will
     shift about 10 characters to the right so that the first visible
     column is Street and the second column is City.

          You inform Gold of the column widths by creating an array of
     integers to represent the starting character number of each column
     in the width. Figure 14.1 was generated from the demo file
     DEMGRD1.PAS which included the following code to define the column
     widths:

          var
             SourceList: SingleLL;
             GridLayout: ListCfg;
             GridHeading: string;
             TabStops: array[1..5] of integer;

          begin
             TabStops[1] := 1;
             TabStops[2] := 18;
             TabStops[3] := 39;
             TabStops[4] := 53;
             TabStops[5] := 57;
             ...
             GridAssignTabs(GridLayout,@TabStops,5);

          Each element of the integer array identifies the position of
     the starting character of a column. In this example, the first
     column starts at character 1, the second column starts at character
     18, the third column starts at character 39, and so on. When the
     user scrolls rightward from the name column, Gold will display the
     list starting at the 18th character.


     Figure 14.1
     A Grid Window


          Having assigned each integer element of the array with the
     appropriate column setting, the procedure GridAssignTabs is used to
     instruct Gold to use the column (or tab) settings, as follows:

     GridAssignTabs(var ListDetails: ListCfg; TA:pGridTabArray;
                                                      Dim:integer);

          Sets the ListCfg variable ready for displaying a grid. The
     integer array identifies the starting character of each column. The
     third parameter identifies the total number of elements (i.e.
     columns) defined in the array.

     Always set the first integer in the array to a value of 1.

Grid Headings and Footers

          Grid windows support up to 4 headers and 4 footers, and the
     procedures, ListAssignHeader and ListAssignFooter, are used just
     like list and browse titles. In fact, the use of non-scrolling
     headers and footers behave exactly the same for grid windows as for
     list and browse windows.

          Because of a grids columnar scrolling support, however, the
     scrollable titles behave a little differently. Gold needs to know
     the headings (or footers) for each column. Gold searches the
     strings for the split bar character "|" and uses this to separate
     each columns heading. Listed below are the heading statements used
     in generate the headings displayed in figure 14.1:

          var
             GridHeading: string;

          begin
             ...
             Gridheading := 'Name|Street|City|ST|Zip';
             ListAssignHeader(GridLayout,1,GridHeading);
             ...
          end;

          This technique of embedding the column delimiter must be used
     on all header and footer strings which are defined as scrollable.

          Review the demo file DEMGRD1.PAS to see columns and headings
     in action.

Locking Rows and Columns

          One or more columns and one or more rows can be locked so that
     the locked area remains visible as the user scrolls around the
     grid. Use the GridSetLocks procedure to lock columns and rows as
     follows:

     GridSetLocks(var ListDetails: ListCfg;LCol,LRow:byte);

          Locks columns and rows so that they are always visible. Lcol
     identfies the number of columns (not characters) to lock, and LRow
     identifies the number of rows to lock.

          Listed below is an extract from DEMGRD2.PAS which uses the
     column locking facility to keep the name column always visible:

          procedure SetGridLayout;
          {}
          begin
             Gridheading := 'Name|Street|City|ST|Zip';
             GridFootnote := 'The name column is locked';
             TabStops[1] := 1;
             TabStops[2] := 18;
             TabStops[3] := 39;
             TabStops[4] := 53;
             TabStops[5] := 57;
             InitListCfg(GridLayout);
             ListAssignSLL(GridLayout,SourceList);
             ListAssignHeader(GridLayout,1,GridHeading);
             ListAssignFooter(GridLayout,1,GridFootnote);
             ListScrollFooter(GridLayout,false);
             ListSetWin(GridLayout,15,5,65,15,7);
             ListSetGaps(GridLayout,1,0,0,1);
             GridAssignTabs(GridLayout,@TabStops,5);
             GridSetLocks(GridLayout,1,0);
          end; { SetGridLayout }

Determining the Highlighted Pick

          The ListCfg variable includes the field ActiveNode, which is
     of type longint. This variable always reflects the number of the
     node which contains the highlight bar.

Controlling Grid Display Characters

          The ListVars variable includes the following three fields
     which control characters used to indicate the higlighted pick
     (GridLeft and GridRight) and tagged items (gridTag):

        GridLeft: string[1];
        GridRight: string[1];
        GridTag: string[1];

          You can customize the appearance of the list by assigning new
     characters to these variables.

          The keystrokes which control item tagging are stored in the
     following ListVars variables:

           ToggleKey: word;
           TagKey: word;
           UnTagKey: word;
           TagAllKey: word;
           UnTagAllKey: word;

Determining the User's Last Action

          The ListCfg variable includes the field LastAction of type
     gAction. Gold updates this variable to indicate how the user ended
     the list session. For example, if the user pressed Esc it would be
     set to Escaped.

Using a Custom Data Source

          In all the examples so far, you have seen how to display lists
     of strings from linked lists or string arrays. You may recall that
     one of the procedures ListAssignArray, ListAssignSLL or
     ListAssignSLL is used to inform Gold about the data source. This
     approach requires all the data to be in memory at once, and for the
     majority of applications, that is not a problem.

          There are, however, some situations where there is too much
     data to load into memory at once. You might be trying to list
     10,000 records from a database, for example. For situations such as
     this, Gold allows you to assign a custom list data source using the
     procedure ListAssignCustom which is defined as follows:

     ListAssignCustom(var ListDetails: ListCfg; Total:longint;
                                            CustomFunc:ListGetStrFunc);

          Sets the ListCfg variable data source as custom. The procedure
     is passed the total number of entries in the custom data source
     along with a function which Gold will call every time it needs a
     string from the custom source.

          Every time Gold needs to display a string in a browse, list or
     grid window, the CustomFunc function will be called. For a function
     to be eligible as a custom list function it must adhere to the
     following rules:

          The procedure must be declared as a far procedure at the root
          level. Refer to the section Understanding Hooks in Chapter 3
          for further information.

          The function  must be declared with four passed parameters.
          The first parameter is a pointer, and the last three
          parameters are longints.

     The following procedure declaration follows these rules:

          {$F+}
          function GetStrfromDB(P:pointer; Element,Start,Finish:
                                                      longint): string;
          {}
          begin
           ....
          end; { GetStrfromDB }
          {$F-}

          When the procedure is called Gold actually passes a pointer to
     the ListCfg variable as the first parameter. In most situations you
     will not need to take advantage of this parameter. The second
     parameter is the node or item number for which Gold needs the
     string. The third and fourth parameters represent the starting and
     ending character positions of the (sub) string which will be
     visible.

          In the case of a database list, the custom function would load
     the database record, access the data in the fields, and then return
     the requested sub-string. Review the demo file DEMGRD3.PAS to see
     this technique in action.

Using Hooks to Fine Tune Lists

          Even with all this flexibility built into the list facility,
     there may still be occasions when you want to add some custom
     functionality. As always, Gold has a set of hooks where you can
     fine tune the behavior of the application.

          Gold provides four different hooks for customizing browse,
     list and grid windows.

The Character Hook

          A character hook is a procedure which is called every time a
     key is pressed or a mouse button is clicked while a list window has
     focus. The hooked procedure is called before the key is processed
     by Gold. The hook is particularly useful for trapping special keys
     like F1 for help, or Alt-S to search.

          All you have to do is create a procedure following some
     specific rules, and then call the ListAssignCharHook procedure to
     instruct Gold to call your procedure every time a key is pressed.

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

          The procedure must be declared as a far procedure at the root
          level. Refer to the section Understanding Hooks in Chapter 3
          for further information.

          The procedure must be declared with one variable parameter of
          type word, and two variable parameters of type byte. These
          parameters identify the user input, i.e. the Key, X and Y.

     The following procedure declaration follows these rules:

          {$F+}
          procedure MyCharHook(var Code:word;var X,Y:byte);
          begin
             {some code}
          end; {MyCharHook}
          {$F-}

          The following procedure is then called to instruct Gold to
     call your procedure after each input:

     ListAssignCharHook(var ListDetails: ListCfg; Proc:KeyPressedHook);

          Instructs Gold to call the specified procedure before
     processing each user input to a list window.

          If, subsequently, you want to remove the character hook,
     execute the following procedure:

     ListRemoveCharHook(var ListDetails:ListCfg);

          Removes a list character which was previously assigned with
     ListAssignCharHook.

The Hind Hook

          A list hind hook is similar to a character hook, except the
     hook is called after an input has been processed by Gold. If you
     want to write some additional information to the screen based on
     the active list item, you should take advantage of the hind hook.

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

          The procedure must be declared as a far procedure at the root
          level. Refer to the section Understanding Hooks in Chapter 3
          for further information.

          The procedure must be declared with one parameter of type
          ListCfgPtr.

     The following procedure declaration follows these rules:

          {$F+}
          procedure MyHineyHook(ListDetailsPtr:ListCfgPtr);
          begin
             {some code}
          end; {MyHineyHook}
          {$F-}

          The following procedure is then called to instruct Gold to
     call your procedure after each input:

     ListAssignHindHook(var ListDetails: ListCfg; Proc:ListHindHook);

          Instructs Gold to call the specified procedure after
     processing each user input to a list window, and once when the
     window is first displayed.

          The variable parameter which is passed to the procedure is
     actually a pointer to the ListCfg variable which is being used by
     the list. You can de-reference the pointer to access the variable,
     for example:

          Total := ListDetails^.TotalNodes

          If, subsequently, you want to remove the hind hook, execute
     the following procedure:

     ListRemoveHindHook(var ListDetails:ListCfg);

          Removes a list hind which was previously assigned with
     ListAssignHindHook.

The Color Hook

          The color hook provides a really easy way to go beyond the
     standard two colors supported by the primary list code. For
     example, you might want every tenth item in a list to be displayed
     in a different color, or all items with a quantity field greater
     than 5000 to be displayed in a different color.

          A color hook is called every time Gold wants to display a line
     of text in a browse, list or grid window. For a procedure to be
     eligible as a color hook it must adhere to the following rules:

          The procedure must be declared as a far procedure at the root
          level. Refer to the section Understanding Hooks in Chapter 3
          for further information.

          The procedure must be declared with three parameters. The
          first parameter is a longint which indicates the node or item
          number of the item that is about to be written to the window.
          The second parameter is a boolean which will be set to TRUE if
          the pick is the highlighted pick. The third parameter is a
          variable parameter of type byte which represents the default
          color that will be used -- this parameter should be updated by
          the hook if a custom color is to be used.

     The following procedure declaration follows these rules:

          {$F+}
          procedure MyColorHook(Pick:longint;Hi:boolean;
                                                     var Attr:byte);
          begin
             {some code}
          end; {MyColorHook}
          {$F-}

          The following procedure is then called to instruct Gold to
     call your procedure after each input:

     ListAssignColorHook(var ListDetails: ListCfg; Proc:ListColorHook);

          Instructs Gold to call the specified procedure before writing
     the item to the list window. The hook can modify the item's display
     color.

          If, subsequently, you want to remove the color hook, execute
     the following procedure:

     ListRemoveColorHook(var ListDetails:ListCfg);

          Removes a list color which was previously assigned with
     ListAssignSelectHook.

The Selection Hook

          A selection hook is called every time the user takes an action
     which might be construed as the conclusion of the list session.
     Specifically, a list selection hook is called when the user clicks
     on the close icon, double clicks on a list item, presses Esc or
     presses Enter.

          By default, Gold will end the input session and close the list
     window when any of these actions are taken by the user. In some
     situations, however, you may want to override this default behavior
     using a selection hook.

          For a procedure to be eligible as a list selection hook it
     must adhere to the following rules:

          The procedure must be declared as a far procedure at the root
          level. Refer to the section Understanding Hooks in Chapter 3
          for further information.

          The procedure must be declared with one parameter of type
          ListCfgPtr.

     The following procedure declaration follows these rules:

          {$F+}
          function MySelectHook(var Listdetails):gAction;begin
             {some code}
          end; {MySelectHook}
          {$F-}

          The following procedure is then called to instruct Gold to
     call your procedure after each input:

     ListAssignSelectHook(var ListDetails: ListCfg;
                                                Proc:ListSelectHook);

          Instructs Gold to call the specified procedure when the user
     selects a list item by pressing Enter or double clicking on the
     item, or when the user tries to escape by pressing Esc or clicking
     on the window's close icon.

          The variable parameter which is passed to the procedure is
     actually a pointer to the ListCfg variable which is being used by
     the list. You can dereference the pointer to access the variable,
     for example:

          Total := ListDetails^.TotalNodes

          The function returns a value of type gAction (declared in
     GOLDIO) which indicates how Gold should proceed. For example, an
     action code of Refresh will instruct Gold to repaint the window's
     client area, and an action code of Finished will instruct Gold to
     close the list window.

          If, subsequently, you want to remove the select hook, execute
     the following procedure:

     ListRemoveSelectHook(var ListDetails:ListCfg);

          Removes a list selection hook which was previously assigned
     with ListAssignSelectHook, and instructs Gold to use the default
     hook.


          The demo file DEMGRD4.PAS takes advantage of the selection
     hook to add a record editor to a database browser. Check it out!

Launching Windows on the Desktop

          The three primary functions RunBrowse, RunList and RunGrid
     have the following counterparts for displaying windows on a desktop
     application:

     LaunchBrowse(var ListDetails: ListCfg;Tit:StrScreen;
                                          CloseProc:ListCloseProc):byte;

          Launches a browser for viewing the contents of an array or
     linked list. The function returns the number (or handle) of the
     newly created window.

     LaunchList(var ListDetails: ListCfg;Tit:StrScreen;
                                         CloseProc:ListCloseProc): byte;

          Adds a list window to the desktop. The function returns the
     number (or handle) of the newly created window.

     LaunchGrid(var ListDetails: ListCfg;Tit:StrScreen;
                                         CloseProc:ListCloseProc): byte;

          Adds a grid window to the desktop. The function returns the
     number (or handle) of the newly created window.

          Like their Run counterparts, the Launch functions are passed a
     ListCfg variable and a title. Additionally, the Launch functions
     are passed a close function as a third parameter. This close
     function is called whenever the user tries to close the window on
     the desktop, and it provides you with an opportunity to do any
     housekeeping (such as disposing of linked lists) before the window
     is closed.

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

          The function must be declared as a far function at the root
          level. Refer to the section Understanding Hooks in Chapter 3
          for further information.

          The function must be declared with one parameter of type
          ListCfgPtr, and one integer. The function must return a
          boolean value.

     The following procedure declaration follows these rules:

          {$F+}
          function GoodbyeList(var LDP: ListCfgPtr; Handle:integer):
                                                              boolean;
          {}
          begin
             PopUpSetActive(ListMenu,201,true);
             SLLDestroy;
             GoodbyeList := true;
          end; { GoodbyeList }
          {$F-}

          If the function returns false, the window will not be closed.
     The first parameter passed to the function is a pointer to the
     ListCfg variable used to display the list. You can dereference this
     pointer to access the variable, for example:

          Total := ListDetails^.ActiveNode

     The demo file DEMDESK5.PAS shows the LaunchList function in action.

Handling Errors

          The list displaying functions and the header and footer
     assignment functions have the potential to fail. Be sure to check
     the error code by calling the LastListError and LastGridError
     functions.

