# CHAPTER 5: Lists

## 5.1 Introduction to Lists

Lists are used to display an array or arrays of data. An application can display items in the list, delete items from the list, select an item or multiple items from the list, call actions on the selection, and scroll through the list. In Empress GUI Builder, two types of lists are available:

1. Lists which can only have one column
2. Multilists which can have one or more columns

A multilist with one column is not the same as a list, although in practice, they are treated as equivalent.

The Empress GUI Builder C API offers two methods for list scrolling: automatic and user controlled. This chapter discusses both methods, the advantages of one over another and C API functions to perform automatic and user controlled scrolling with relevant examples.

## 5.2 Automatic Scrolling

With automatic scrolling, Empress GUI Builder handles the details of scrolling. All that the user's application needs to do is to store all the elements of data in the appropriate arrays. The application has to know in advance the number of items of data to be able to allocate the arrays. The main disadvantage of automatic scrolling is that the entire array has to be allocated and filled with data before any data can be displayed in the list. For large arrays, this is impractical, as large amount of memory has to be allocated for the arrays, and the scrolling is slower. The advantage of automatic scrolling is simplicity: the application does not need to be concerned with the intricate details of accessing data and passing it to C API functions at the right moment as in the case of user controlled scrolling.

Empress GUI Builder provides these two functions for automatic scrolling:

    gui_status empgui_c_list_set_items (listobj, num, listval, {listval,}

            (char **)0 )

where:

`> object listobj` | `list or multilist object`
`> int num` | `number of elements in the listval arrays`
`> char **listval` | `array of strings`

">" means input parameters
"<" means output parameters

    gui_status empgui_c_list_set_array ( listobj, num, listvals )

where:

`> object listobj` | `list or multilist object`
`> int num` | `number of elements in the arrays that make up listvals`
`> char ***listvals` | `array of array of strings for the columns of the list`

">" means input parameters
"<" means output parameters

Both of the above functions can effectively be used for automatic scrolling. They work both for a list and a multilist. In the first function, `empgui_c_list_set_items`, the number of `listval` variables has to be known before hand while in the second function,`empgui_c_list_set_array`, the number of elements in the `listvals` array can be dynamically controlled.

Example

For an application that has a multilist called `"mlist`" with two columns in the main window, the variable declaration could be as follows:

`object mainwin, mlistobj;`
`char *objname = "mlist";`
`gui_status status;`
`register int i;`
`char *listval1[100];`
`char *listval2[100];`
`char **listvals[3];`

To get the object for this multilist:

    status = empgui_c_obj_get_by_name (mainwin, objname, &mlistobj);

(Assuming `mainwin` has already been initialized)

Allocating memory for each of the strings in `listval1` array:

    for (i=0; i < 100; i++)

            listval1[i] = (char *) malloc(80*sizeof(unsigned char));

Allocating memory for each of the strings in `listval2` array:

    for (i=0; i < 100; i++)

            listval2[i] = (char *) malloc(80*sizeof(unsigned char));

Putting data in the `listval1` array:

    for (i=0; i < 100; i++)

            sprintf(listval1[i],"item_%d",i+1);

Putting data in the `listval2` array:

    for (i=0; i < 100; i++)

            sprintf(listval2[i],"data_%d",i+1);

    /* typically, the arrays will be assigned values from a database */

To set up the array `listvals`:

`listvals[0] = (char **) listval1;`
`listvals[1] = (char **) listval2;`
`listvals[2] = (char **) 0;`

The call to this function to set items in the multilist would be:

    status = empgui_c_list_set_array (mlistobj, 100, listvals);

## 5.3 User Controlled Scrolling

User controlled scrolling gives the application flexibility in controlling the display of data for a list and a multilist. The application does not need to allocate memory for large arrays of data. It can control the display of a list through a very small array, which would usually contain as many elements as the number of viewable rows of a list or a multilist. As the user scrolls through the list, the array needs to be updated with the right elements of data. This functionality has to be coded by the user in a scrolling function.

Empress GUI Builder provides these four functions for user controlled scrolling:

    gui_status empgui_c_list_scroll_set_items (listobj, toprow, num,

            numexprows, listval, { listval, } (char **) 0 )

where:

`> object listobj` | list or multilist object
`> int toprow` | item number of the row to be displayed at top of the list display
`> int num` | number of rows to be displayed in the list
`> int numexprows` | total expected number of items to be displayed in the list, or 0 if unknown
`> char **listval` | array of strings

">" means input parameters
"<" means output parameters

    gui_status empgui_c_list_scroll_set_array ( listobj, toprow, num,

            numexprows, listvals )

where:

`> object listobj` | list or multilist object
`> int toprow` | item number of the row to be displayed at top of the list display
`> int num` | number of rows to be displayed in the list
`> int numexprows` | total expected number of items to be displayed in the list, or 0 if unknown
`> char ***listvals` | array of array of strings for the columns of the list

">" means input parameters
"<" means output parameters

    gui_status empgui_c_list_get_num_viewrows (listobj, &num)

where:

`> object listobj` | list or multilist object
`< int num` | number of viewable rows in a list or multilist

">" means input parameters
"<" means output parameters

    gui_status empgui_c_list_scroll_set_func (listobj, scroll_func)

where:

`> object listobj` | list or multilist object
`> void (*scroll_func)` | scroll function

">" means input parameters
"<" means output parameters

Example

For an application that has a multilist called "`mlist`" with two columns in the main window, the variable declaration could be as follows:

`object mainwin, mlistobj;`
`char *objname = "mlist";`
`gui_status status;`
`int i;`
`int nviewrows;`
`int tn_rec;`
`char **listval1;`
`char **listval2;`
`char **listvals[3];`
`int size;`

This declaration has to be global so that the scroll function can access `listval1`, `listval2` and `listvals` array.

All of the code below can be part of the enter action for the module. Here, the list is set up and the scroll function is defined.

To get the object for this multilist:

    status = empgui_c_obj_get_by_name (mainwin, objname, &mlistobj);

(Assuming `mainwin` has already been initialized)

Finding the number of viewable rows in the multilist:

    status = empgui_c_list_get_num_viewrows (mlistobj, &nviewrows);

Number of elements in the `listval1` and `listval2` arrays can now be allocated depending on the number of viewable rows of the multilist:

`size = ( nviewrows + 1 ) * sizeof (char **);`
`listval1 = (char **) malloc ( size );`
`listval2 = (char **) malloc ( size );`

The extra element is used for null terminating the array, which is useful for freeing it up later on in the scroll function.

Assuming the data fields are less than 80 characters long, allocating memory for each of the elements in the `listval1` array:

    for (i=0; i < nviewrows; i++)

            listval1[i] = (char *) malloc(80*sizeof(unsigned char));

Allocating memory for each of the elements in the `listval2` array:

    for (i=0; i < nviewrows; i++)

            listval2[i] = (char *) malloc(80*sizeof(unsigned char));

Null terminating both arrays:

    listval1[nviewrows] = (char *) 0;

    listval2[nviewrows] = (char *) 0;

Putting data in the `listval1` array:

    for (i=0; *(listval1 + i) != 0; i++)

            sprintf(*(listval1 + i),"item_%d",i+1);

Putting data in the `listval2` array:

    for (i=0; *(listval2 + i) != 0; i++)

            sprintf(*(listval2 + i),"data_%d",i+1);

    /* typically, the arrays will be assigned values from a database */

To set up the array `listvals`:

`listvals[0] = (char **) listval1;`
`listvals[1] = (char **) listval2;`
`listvals[2] = (char **) 0;`

If an estimate of the total number of records is available, then this value is useful for Empress GUI Builder to set the size and position of the list's scroll bar properly. If the total number of records is unknown, then set the estimate to zero.

    tn_rec = 100;

The call to the function to set items in the multilist would be:

    status = empgui_c_list_scroll_set_array (mlistobj, 1, nviewrows,

            tn_rec, listvals);

Initially, the top row would normally be 1. To specify which function is called when the user moves the scroll bar:

    status = empgui_c_list_scroll_set_func (mlistobj, scroll_func );

The scrolling function, `scroll_func`, would be defined as follows:

`void scroll_func ( mlistobj, toprow, nrows, at_bottom )`
`object mlistobj;`
`int toprow;`
`int nrows;`
`boolean at_bottom;`

These variables are passed by Empress GUI Builder to the scrolling function. `toprow` specifies which item number is now at top of the list display. `nrows` is the current number of viewable rows. `at_bottom` is a flag to indicate that the bottom of the list is reached. This flag is not very useful in the case of the application knowing the total number of expected elements to be displayed in the list.

`{`
`int i;`

Free the `listval1` and `listval2` arrays, so that they can be reallocated according to the new number of viewable rows:

`for (i=0; *(listval1 + i) != 0; i++)`
`free ( *(listval1 + i ));`
`for (i=0; *(listval2 + i) != 0; i++)`
`free ( *(listval2 + i ));`
`free ( listval1 );`
`free ( listval2 );`

Number of elements in the `listval1` and `listval2` arrays can now be allocated depending on the new number of viewable rows of the multilist:

`size = ( nrows + 1 ) * sizeof(char **);`
`listval1 = (char **) malloc ( size );`
`listval2 = (char **) malloc ( size );`

Assuming the data fields are less than 80 characters long, allocating memory for each of the elements in the `listval1` array:

`for (i=0; i < nrows; i++)`
`listval1[i] = (char *) malloc(80*sizeof(unsigned char));`

Allocating memory for each of the elements in the `listval2` array:

`for (i=0; i < nrows; i++)`
`listval2[i] = (char *) malloc(80*sizeof(unsigned char));`

Null terminating both arrays:

`listval1[nrows] = (char *) 0;`
`listval2[nrows] = (char *) 0;`

Putting data in the `listval1` array:

`for (i=0; *(listval1 + i) != 0; i++)`
`sprintf(*(listval1 + i),"item_%d",toprow+i);`

Putting data in the listval2 array

`for (i=0; *(listval2 + i) != 0; i++)`
`sprintf(*(listval2 + i),"data_%d",toprow+i);`

This updating of `listval1` and `listval2` is very important. Both of these arrays need nrows records. These records are usually fetched from a database. However, fetching from the database should not start at the first record. It should start at the record whose number is specified by `toprow`. For the purpose of this example, these arrays will simply be assigned strings. For a detailed example, read Chapter 7 - "Example 4".

The call to the function to set items in the multilist would be:

`status = empgui_c_list_scroll_set_array (mlistobj, toprow, nrows,`
`tn_rec, listvals);`
`}`