Listboxes

A list-box is a node that contains a number of row-objects. If necessary there will be a "browse-handle" and two scroll-buttons beside the listbox (they will appear when the list contains more objects than there are rows).

You must write at least 2 functions (normally 3). You must make 2 function calls (e.g. `AddList' and `SetIndexedList').

The functions you have to write is:

This maybe sounds more tricky than it really is, here is an example:
   int row_text(void *rowdata, char *s)
   {
      int *row=rowdata;
      sprintf(s, "Data is %d", *row);
      return 0;
   }

   void *index_creater(void *listdata, int i)
   {
        int *arr=listdata;
        return &arr[i];
   }

   void foo(int id, void *rowdata)
   {
      /* Do something */
   }

   void make_dialog_with_list(void)
   {
        /*array and n must be static or dynamic memory, not normal local
        variables!*/
        static int array[100]={1,2,3,4,5}, n=5, id;
        MkDialogue(ADAPTIVE, "Test-window", 0);
         /* add more objects here ... */
        AddList(TOPLEFT, array, &n, 60, LEFT_MOUSE, row_text, foo, 10);
        SetIndexedList(id, index_creater);
         /* ...or here if you need */
        DisplayWin();
   }
   
The list properties in CGUI is controlled by the following global variables: It works like this: Each time a list-box is created, CGUI will use the values of these variables. If you use several list-boxes in your application and for instance want one of these to use a fix font you have to set CGUI_list_font to the fix font you have loaded, and then restore the origin font after the list was created.
The meaning of the variables: CGUI_list_font, CGUI_list_column_delimiter_color and CGUI_list_rowdelimitercolor will be reset next time calling InitCgui.
See also: Windows, Menus, Containers, Tabwindows, Objects.
int AddList(int x, int y, void *listdata, int *n, int width, int mousebt, int (*RowTextCreater)(void *rowdata, char *s), void (*Action)(int id, void *rowdata), int norows);

Creates a list box. NOTE! The list-box is not finished until you have also called either `SetLinkedList' or `SetIndexedList' (which both requires a pointer to a function that you have written). To make a list box work you will need to write a least one more small function (yet more may be needed, depending on how you configure the list). This second "small function" is one that calculates which string that shall be drawn provided some data element.
Parameters: There are lots of options to configure a list box to fit your taste, here are some global variables that affect the apperance of lists. Their usage are as follows: See also the links for functions to configure list boxes.

The return value is the id of the list box.

See also: ListTreeView, Refresh, BrowseTo, RefreshListRow, SetIndexedList, SetListGrippable, NotifyFocusMove, SetDeleteHandler, SetInsertHandler, HookList, Listboxes, SetListColumns, CguiLoadImage.
int SetIndexedList(int listid, void *(*IndexCreater)(void *listdata, int i));

int SetLinkedList(int listid, void *(*NextCreater)(void *listdata, void *prev));

You have to use one (and only one) of these functions to tell the list box which function to call when a data item for a row is needed. (this will happen e.g. when drawing a row or when the user clicks or drags a list row or some other event that the list box is responsible for). If the data that you want to display in the list box is stored as a linked list, then the function `SetLinkedList' is to prefer. Otherwise (if it is an array) then the function `SetIndexedList' is to prefer.
Parameters to these functions: A typical function for array data may look something like:
   void *my_index_creater(void *listdata, int i)
   {
      struct MYDATA *d=listdata;
      return &d[i];
   }
   
A typical function for linked lists may look something like below. Note that if prev is set to NULL then the function is supposed to extract a pointer to the first element using the listdata pointer.
   void *my_next_creater(void *listdata, void *prev)
   {
     /* Here we assume that a pointer to the list head was passed to AddList */
     struct MYDATA **m=listdata;
     struct MYDATA *p=prev;
     if (p==NULL)
       return *m;
     else
       return p->next;
   }
   
Both functions may of course use whatever methods to calculate the data to return (e.g. the "data" pointer may be a pointer to any structure which contains a pointer to the head/array, the array may be an array of pointers etc.). Just another example for linked lists:
   void *my_next_creater(void *listdata, void *prev)
   {
     /* Here we assume that a pointer to the an empty head record was passed to AddList */
     struct MYDATA *m=listdata;
     struct MYDATA *p=prev;
     if (p==NULL)
       return m->next;
     else
       return p->next;
   }
   
And yet a (maybe more practical) example:
   void *my_next_creater(void *listdata, void *prev)
   {
     /* Here we assume that a pointer to some other struct was passed to AddList */
     struct MYDATA_MAIN *m=listdata;
     struct MYLINK *p=prev;
     if (p==NULL)
       return m->list_head;
     else
       return p->next;
   }
   
The return value from SetIndexedList is 1 if a listid is a valid id of a list, else 0.
See also: MkDialogue, DisplayWin, AddList.
int ListTreeView(int listid, int level_width, int (*IsLeaf)(void *rowobject), int options);

This function will turn a ormal list box into a tree viewer. In most respects it is just an ordinary list, however special list facilites like list columns and "hooked lists" are not supposed to work.
Note that if you use arrays for your tree (i.e. used SetIndexedList to install an IndexCreater, rather than SetLinkedList), then IndexCreater should be prepared to be called with any size of the 'index' parameter and return NULL if the index is too big (the list box will use that to make some conclusions about the number of nodes at that level).
Notable is also that for a tree viewer the number of list items has no meaning (i.e. the 4:th parameter, 'n', passed to AddList), so it will be fine if you just pass NULL to AddList.
The tree view section of the list box is a part of the rows in the list so if you want to let the user expand and collaps nodes in the tree you need to at least pass LEFT_MOUSE for the 'mousebuttons' parameter to AddList.
The list box itself will manage the expanding and collapsing of tree nodes.
Parameters: The return value is 1 if a listid is a valid id of a list, else 0.


int SetListColumns(int listid, int (*RowTextCreater)(void *rowdata, char *s, int colnr), int *widths, int n, int options, char **labels, void (*CallBack)(void *data, int id, int i), void *data);

This function partitions the list into `n' columns. Note that this `RowTextCreater' will replace the one previously passed in the call to AddList, so you may as well just pass NULL when adding the list to the window. Texts longer than specified column will be clipped.

Parameters:

See also: AddList.
int RefreshListRow(int id, int i);

If you only need to update one row of a list, and know the index of your data, a call to "RefreshListRow" will do that for you. UpdateListRow will not update the scroll-buttons or the browse-bar.

Returns 0 if id is not a list reference otherwise 1

Parameters:

See also: Refresh.
int BrowseToF(int id, int i);

The data with the index 'i' will be selected (highlighted) and viewed as the first (top) row of the list-box. If 'i' is out of range then either index 0 or the highest possible index will be chosen instead.

If the list exists returns 1 else returns 0. If `id' refers to list within a chain of lists, the browsing will affect all the lists in chain where "listid" exists.

See also: AddList, RefreshListRow, BrowseTo, BrowseToL, Refresh.
int BrowseToL(int id, int i);

The data with the index 'i' will be selected (highlighted) and viewed as the last (bottom) row of the list-box (or as the last row of the list if the list contains less data items than there are rows in the list). If 'i' is out of range then either index 0 or the highest possible index will be chosen instead.

If the list exists returns 1 else returns 0. If `id' refers to list within a chain of lists, the browsing will affect all the lists in chain where "listid" exists.

See also: AddList, RefreshListRow, BrowseTo, BrowseToF, Refresh.
int BrowseTo(int id, int i, int uncond);

The data with the index 'i' will be selected (highlighted) and the list will, if necessary, be browsed to make i come in view.

If 'i' was "above the top" of the list-box prior to the call then it will be the top row after.

If 'i' was "below the bottom" of the list-box prior to the call then it will be the bottom row after.

If 'i' is already viewed in the list-box, then it will just be focused. In this case you maybe want the entire list-box to be unconditionally re-drawn (e.g. to make sure that some of your re-sorting or other updates are correctly reflected), then set 'uncond' to true.

If the list exists returns 1 else returns 0.

This function may be used not only for browsing, but also for re-selecting or pre-selecting a specific row in a list that you want to set focus on. If 'id' refers to list within a chain of lists, the browsing will affect all the lists in chain where "listid" exists.

See also: AddList, BrowseToL, BrowseToF, RefreshListRow, Refresh.
int SetListGrippable(int listid, int (*Grip)(void *srcobj, int reason, void *srclist, int i), int flags, int buttons);

Defines the list-rows in a list to be Grippable.

Parameters:

See also: SetListDroppable, SetObjectGrippable, AddList.
int SetListDroppable(int listid, int (*Drop)(void *destobj, int reason, void *srcobj, void *destlist, int i, int flags), int flags);

Defines the list-rows in a list-box to be drop-able. The "button" parameter specifies if left or right button is allowed for dropping. The parameter "flags" see: SetObjectGrippable. The specified call-back function "Drop" will be called in the following cases:

Drop will always be called when the mouse cursor goes over the row with a gripped object, the "reason" will then be DD_OVER_DROP. Drop must at this call determine if it accepts to be dropped on, and in that case return 1 otherwise 0. If returned 0 there will be no more call until next time the mouse goes over the edge of the object.

If the object from the latest grip has been successfully dropped, Drop will be called a second time and the "reason" will now be DD_SUCCESS. The return value will be ignored this time. The gripped object will be notified later on about the successful drop.

The parameter "destlist" passed to Drop will be the same address as "list" (the pointer previously passed to the list-creation function), "i" will be the index in the list and reason will be either of DD_SUCCESS or DD_OVER_DROP.

The parameter "srcobj" is the source (the gripped) object, just transferred from a Grip-function. This must not necessarily be an object in another list.

The parameter "flags" passed to Drop is the "and"-ed result of the flags for the gripped and dropped object. This has already been examined and will always be non-0, i.e. the drag-drop operation is legal according to your specification. The flag-variable is only passed as an extra info.

The parameter "destobj" is the object pointer of the dropped row, i.e. the pointer created by the IndexCreater of the list dropped on.

See also: SetObjectDroppable, SetListGrippable.
int SetListDoubleClick(int listid, void (*AppDouble)(int id, void *data, int i), int button);

Sets a list to double-clickable. Another call-back, different from the single-click call-back, may be installed to receive double-click events. See also SetObjectDouble for details.

Call-back is analogous to "Action" in AddList

See also: SetObjectDouble, AddList.
int HookList(int listid, void *listdata, int *n, int width, int events, int (*RowTextCreater)(void *data, char *s), void (*Action)(int,void*));

Lists may be chained together. This means that they are controlled by one common browse-bar and common scroll-buttons. This is useful when displaying lists containing records with different items and the different items need to be individually selectable.
This function hooks a new list to the right of another list. The first list must be created with a call to AddList.
The creation of list is not finished until a call to either NextCreater or IndexCreater is done, see AddList for info about these functions.
Returns the id of the new listbox if listid is valid otherwise 0.
Parameters:
See also: AddList.
int SetDeleteHandler(int listid, void (*CallBack)(int rowid, void *object));

Associates DELETE-key presses to the list "listid". The list will only recognise the key-press if is active (in focus).

Returns 1 if listid refers to a list, otherwise 0.

Parameters:

See also: AddList, GetMarkedRows.
int SetInsertHandler(int listid, void (*CallBack)(void *list, int index));

Associates INSERT-key presses to the list "listid". The list will only recognise the key-press if is active (in focus).

Returns 1 if listid refers to a list, otherwise 0.

Parameters:

See also: AddList.
void **GetMarkedRows(int listid, int *n);

This function returns a pointer to an array of list-object pointer, those that for the moment are marked (blue).
This may typically be of interest in e.g. a callback installed by `SetDeleteHandler'. If the user has made a multi-row selection and wants to have them all removed it may be nicer to give a message like "Remove all this 17 ...?" rather than 17 requests like "Remove this..." .
If it fails or if there are no selected items the return value will be NULL and the value pointed to by `n' will be set to 0. The returned pointer points to dynamic allocated memory, which the caller has the responsibility to free when no longer used.
See also: AddList, SetDeleteHandler.
int GetListIndex(int rowid);

This function returns the index of a certain row in a list. 'id' must refer to an row-object of a list-box (and will be passed to the callback- function of the list-box).

If id do not refer to a list-row it will fail and return -1

See also: AddList.
int NotifyFocusMove(int listid, void (*CallBack)(int id, void *rowobject));

This functions makes an initialisation so that your program will be notified by a call to `CallBack' when a row in a list gets focus.

Return value: 1 if successful else 0 (no good listid)

Parameters:

See also: AddList.

Back to contents