Contents page

Lists


    Many programs need to display a list of information that the user can scroll through and select items from. An obvious example would be the list of names in a file requester.

    Most lists tend to be similar in format. They are arranged vertically and have a scroll bar and incremental click gadgets on the right. When the user clicks on an item in the list, it becomes highlighted.

    InovaTools 1 provides a quick method for handling such vertical, one dimensional lists. There are routines to create, display, insert into, delete from, and scroll lists. The lists can be dynamically resized in height, should the user adjust the window size.

    If you need to display a one dimensional linked list of data items, here's how you go about it:

    The ListInfo Structure

    This carries all the information about your list display.

        struct ListInfo{
            USHORT LeftEdge, TopEdge, Width, Height;
            USHORT ItemHeight;
            USHORT ScrollID, ListID, ClickUpID, ClickDownID;
            USHORT BorderPen, FillPen;
            struct ListItem *TopItem, *TopDisplayItem, *ActiveItem;
            struct Window *Window;
            struct Gadget *ScrollGadget, *ListGadget,
                          *ClickUpGadget, *ClickDownGadget;
            void (*DrawRoutine)();
            USHORT OldL, OldT, OldW, OldH
    
        };
        

    As you probably noticed, there was reference to a ListItem structure. As seen by the list handling routines, the ListItem structure is simply:

        struct ListItem {
            struct ListItem *Next;
            }
        

    Each item that you present to the list handler must have a pointer to the next item as its first field. You might accomplish this by embedding the ListItem structure in your structure declaration. For example:

        struct Bologna {
              struct ListItem listitem;
              int granola;
              }
        

    Or, you might say

        struct Bologna {
              struct Bologna *next;
              int granola;
              }
        
    Either way comes out the same. All the list routines need to know is that the first field points to the next item. The size of the item is no issue, since you do the allocating and freeing yourself.

    Using Lists

    You install your list with a call to InitListInfo(); Prior to doing so, you must prepare the following fields in you ListInfo structure:

    LeftEdge indicates the left boundary of the list box.
    TopEdge indicates the top boundary of the list box.
    Width indicates the width of the list box.
    Height indicates the height of the list box.
    ItemHeight specifies how tall each item is. This is divided into Height to determine how many items are displayed at once.
    ScrollID This is the GadgetID number you would like the scroll bar to have. A scroll gadget will be created with this number in its GadgetID field. Later, when your program receives GADGETUP events with this GadgetID, call ScrollList to scroll the display.
    ListID This is the GadgetID number for the area comprising the list display. Later, when your program receives a GADGETUP event with this GadgetID, this will indicate the user is clicking on an item in the list, so call GetListItem which will highlight that item and return a pointer to it.
    ClickUpID Yet another GadgetID number, this is for the arrow gadget at the top of the scroll bar, indicating the user wants to scroll the display down one. When you receive a GADGETUP event with this id, you call the routine ClickList.
    ClickDownID The last GadgetID number, this is for the down arrow below the scroll bar. This is also used to call ClickList.
    BorderPen The pen number for the border of the box that surrounds the list.
    FillPen The pen number for the inside of the list box.
    TopItem If you have a list of items to work with, put the pointer to the top one here. If not, this must be NULL.
    TopDisplay This is a pointer to the first item that should be displayed. Item This might be the top item, or it could be somewhere in the middle of the list. If there is no list, make this NULL. When the list is scrolled, this is changed by InovaTools to point to the new top of display.
    ActiveItem This is the currently highlighted item. If there is none, make it NULL.
    Window You must provide a pointer to the window this list is being displayed in.
    DrawRoutine This is a pointer to a routine that you provide to display information about an item. InovaTools will call this routine to display an item in the list box. The parameters that are passed to this routine are:
    InovaTools draws the list by calling this routine for each of the items that are displayed, giving each a different Y coordinate as it runs down the list.

    Your routine is responsible for clipping. What it draws should not be wider than the ListInfo Width parameter, nor taller than the ListInfo ItemHeight parameter.

    RastPort The rastport to draw in.
    Listltem A pointer to the item to display.
    XPos X coordinate for drawing.
    YPos Y coordinate for drawing.
    HighLight A flag that is set to
    • TRUE if this is to be highlighted,
    • FALSE if not.
    How you go about highlighting is up to you.

    The remaining parameters should be left alone.

    Having initialised your ListInfo structure, call InitListInfo(ListInfo) just after opening your window and it will install the list in the window, allocate the four gadgets, and display the list.

    The list will generate the four gadget events. The ListGadget, ClickUpGadget and ClickDownGadget should all be dealt with when they produce GADGETDOWN events, while the ScrollGadget should be handled on GADGETUP.

    When the List gadget is clicked, the user is selecting a list item. Call GetListItem (ListInfo). It will highlight the selected item and return a pointer to it.

    When the ClickUp gadget is selected, the user is requesting that the list display move up one notch. Call ClickList(ListInfo,ClickUpID) to instruct it to move the list up one. ClickList will wait for the user to let up on the button. If that doesn't happen for a while, the list will scroll automatically.

    When the ClickDown gadget is selected, call ClickList (ListInfo, CliekDownID). When the Scroll gadget is selected, the display needs to be scrolled to the new position. Call ScrollList(ListInfo) and it will take care of it.

    At some point, you may wish to enter a new item in the list. InsertListItem(ListInfo,ListItem) will stick the item in the list just prior to the currently selected item.

    If the user wishes to delete the currently highlighted item, a call to RemoveListItem(ListInfo) will talke the highlighted item out of the list and highlight the one that precedes it. RemoveListItem returns a pointer to the removed item. You must then dispose of the removed item yourself.

    Should you need to redisplay the list, call SizeList(ListInfo). If you change the list size information (in particular, the Height), it will be updated appropriately (after erasing the old list..) This is handy if the user sizes the window. On NEWSIZE events, adjust the Height field appropriately and call SizeList.

    When you are done and it is time to close the window, call RemoveListInfo (ListInfo) first. It will deallocate the four gadgets. Then, call CloseWindow to close the window.

    There is a set of list manipulation routines provided in the library. You can use these to work with your linked lists. Note that these linked lists are all singly linked, rather than doubly linked. The Amiga's Exec list structures are doubly linked.

    The list routines are:

    List_Len Returns the length of the list.
    List_Position Returns the integer position of an item in the list.
    List_Pred Returns the item in the list preceding the given item.
    List_Index Returns the item at the given integer position in the list.
    List_Insert Inserts the item at the given integer position in the list.
    List_Remove Removes the item at the given integer position from the list.
    List_Cat Concatanates two lists into one.

    These routines fall under the heading List Functions in the routine summaries.

    Any linked list that puts a pointer to the next item in the first field of each structure can use these. For example, Intuition Gadgets have a pointer to the next gadget in the NextGadget field which is the first item in the Gadget structure. So, you can manipulate your gadget list with these functions.