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:
- A function that receives a pointer to the entire list-data, and
returns a pointer to a specific object within the list.
- A function that generates the text to be drawn on one row. This
string is made up from the object returned from the above function.
- Normally you want your program to be notified if the user clicks on
a row. You must write a function that is called in such cases.
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:
- FONT *CGUI_list_font;
- int CGUI_list_row_delimiter_color;
- int CGUI_list_vspace;
- FONT *CGUI_list_row_font;
- int CGUI_list_row_f_color;
- int CGUI_list_row_b_color;
- int CGUI_list_column_delimiter_color;
- int CGUI_list_fixfont;
- int cgui_list_fix_digits;
- int cgui_list_no_multiple_row_selection;
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 - The font used for the lists. The default
value is CGUI's default font. Lists that are already existing will
not be affected by changes of CGUI_list_font.
- CGUI_list_row_font - The font used for the rows in the list. Changes
will only be notified if set by the list-row drawing function that
you have written. If that function does not assign the
CGUI_list_row_font the default font for the list will be used
instead (i.e. CGUI_list_font).
- CGUI_list_row_f_color - The default foreground colour of list rows
is black. If you want to change the foreground colour of some (or
all) rows you have to set CGUI_list_row_f_color, and it must be
set by the list-row drawing function. Rows with highlighted
background (i.e. they are blue because the user have selected
them) will not recognise any changes of colour.
- CGUI_list_row_b_color - The default background colour of list rows
is white. If you want to change the background colour of some (or
all) rows you have to set CGUI_list_row_b_color, and it must be
set by the list-row drawing function. Rows with highlighted
background (i.e. they are blue because the user have selected
them) will get a colour that differs from both the colour you set
and the default one (blue).
- CGUI_list_rowdelimitercolor - Between all rows there is an extra
pixel-line where no text is drawn. This may be drawn in a colour
different from the colour of the list (i.e. white) to make the rows
more outlined. e.g. if a list is drop-able, it may be useful to have
a black line between the rows to make more obvious for the user
which row he is really dropping on. Default value is white
(invisible).
- CGUI_list_vspace - Determines the height of the total height of the
list rows. The height of a row is the height of the font used + 1
(for the delimiter line) + CGUI_list_vspace. To make a list more
compact you may set a negative value (which may lead to some
characters overlapping). The default value is 0.
- CGUI_list_column_delimiter_color - if multiple columns has been
defined by a call to SetListColumns and delimiters where specified
in that call, then this variable controls the colour of the column
delimiters. If rowdelimiter colour is different columns will
override in the crossings.
- CGUI_list_fixfont - if 0, which is the default value, the text of
the rows in listboxes will be drawn directly by Allegro. If
non-zero, the value is used as the with of each character in the
used font. This may be set individually for each column/row.
This is a workaround to make it possible to draw fix fonts like
'Courier' as fix fonts. The only way to import fonts, as far
as I know, is the ttf2pcx tools program, and it seems to destroy the
fix-width properties of fix-fonts. In some applications fix-fonts
are very necessary.
- cgui_list_fix_digits - This is an alternative to CGUI_list_fixfont.
If non-0 all digits of the string will be drawn with the witdth of
the widest digit within the font and all other characters will be
drawn with their own width. This is useful if you know in advance
that the texts of all rows will contain only digits or digits with
predifined delimiters at certain positions.
This may be set individually for each column/row.
- cgui_list_no_multiple_row_selection - by default the "multiple
rows" property is enabled. If this flag is set this will be disabled
for all lists subsequently created.
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:
- x,y: The position of the object (or you can use "direction commands").
- listdata: may be a pointer to any application data, transparently
passed to the xxCreater-function specified by SetLinkedList or
SetIndexedList.
- n: is a pointer to an integer specifying the number of elements that
currently is in the `listdata' (i.e. the number of elements in your
array). This parameter is ignored if you will put the list box into
tree mode. The same applies also if your data to display is in a
linked list, or to be more precise: if you will call `SetIndexedList'.
In such cases you can just pass NULL.
- width: specifies the width in pixels of the list box rows (the frame
and the browsebar will be added to this)
- mousebt: specifies the mousebuttons to be handled when the user
clicks on a row.
- LEFT_MOUSE - Your function `Action' will be called when a row in the list
is clicked by the left mouse button.
- RIGHT_MOUSE - Your function `Action' will be called when a row in the list
is clicked by the right mouse button.
- LEFT_MOUSE+RIGHT_MOUSE - Your function `Action' will be called both when
a row in the list is clicked by the left and the right mouse button.
- 0 - `Action' will never be called.
- RowTextCreater: A call-back function written by you. This will be
called each time a list row has to be drawn. RowTextCreater will be
called with the actual object-pointer `data' (previously created by
the `index' or `next' function) for that row. Its purpose is to
create a the text to be displayed on the row.
Optionally it may also return any of the below attributes (they may
be ored) or return zero if none of them is wanted:
- ROW_STRIKE generataing a line striking trough the text
- ROW_UNDERLINE underlines that row
- ROW_CHECK puts a check-mark at the beginning of the row
- ROW_UNCHECK will reserve space at the beginning of the row
Useful to keep a stight column in a list with checked rows
(use ROW_UNCHECK for the unchecked rows).
Parameters to RowTextCreater:
- rowdata: the data created by your `IndexCreater'
or `NextCreater' function.
- s: Pointer to an array where `RowTextCreater' is supposed to put
a string to be displayed for the `rowdata'. The string may start
with an image name in which case the image will be diplayed to
the left fo the text. The form of an image name is the same as
for other objects, i.e. #imagename; where `imagename' is the
name of an registered image. See CguiLoadImage for details. There
may be spaces between the '#' and the imagename. To display a
leading '#' on a row you need to put '##' in the string.
- Action: A call-back function that will be called when a row in the
list-box was clicked by the user. If you don't want any action
performed if the user clickes on a row (i.e. if you specifies 0
for the mousebt parameter) then you can pass NULL for Action.
Parameters to Action:
- id: the id of the row-object and may e.g. be used as reference
to obtain information about which of the mouse buttons that
was pressed (in case both are allowed).
- rowdata: the data created by your function `IndexCreater'
or `NextCreater' function.
- norows: The number of rows to display at one time (i.e. the height
of the list expressed in rows instead of pixels).
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.
- FONT *CGUI_list_font;
- FONT *CGUI_list_row_font;
- int CGUI_list_row_f_color;
- int CGUI_list_row_b_color;
- int CGUI_list_rowdelimitercolor;
- int CGUI_list_vspace;
- int CGUI_list_column_delimiter_color;
Their usage are as follows:
- CGUI_list_font - will be snapped as the default font by the listbox
when it is created.
- CGUI_list_row_font - may be used to change the font for an
individual row. Only `RowTextCreater' can set this, and it will
only be used on that row.
- CGUI_list_row_f_color - may be used to make the text of a single row
to be drawn in a certain colour (default is black)
- CGUI_list_row_b_color - may be used to make the background of a
single row to be drawn in a certain colour (default is white)
- CGUI_list_rowdelimitercolor the color of a pixel line that delimits
the rows in the listbox (default is white)
- CGUI_list_vspace - signed integer specifying a number of extra
vertical pixels int the row height (default value is 0). The base height
of the rows are always the height of the list's default font.
- CGUI_list_column_delimiter_color - this will be the colour of the
column delimiter (only used if SetListColumns has been called, and
the proper flag was passed).
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:
- listid - the id of a list box (i.e. the value returned from `AddList').
- IndexCreater/NextCreater - This should be a pointer to a function that
you have written (an "iterator function"). The work that needs to be
done for the creator function is to create a pointer to some row data
object that is understood by your functions `RowTextCreater', `Action'
etc.
Parameters to these functions:
- The input `listdata' will be the pointer that you passed to `AddList'
as the `listdata' parameter.
- prev/i - In case your data is an array (i.e. function
SetIndexedList) then the `i' tells from which index in the array
the datapointer should be returned. In case your data is a linked list
(i.e. function SetLinkedList) then 'prev' tells which is your
previous element, and your function `NextCreater' should return
a pointer to the next element (or null if there are no more elements).
If there is no previous element (i.e. the first element is wanted)
then `prev' will be NULL.
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:
- listid: the id returned from `AddList'.
- level_width: the width each tree level will occupy on the screen.
Suitable value is 10 pixels or above (you should consider the
the width of your icons when choosing a value)
- IsLeaf: a pointer to a callback function that must return non-zero if
'rowobject' is a leaf and 0 if 'rowobject' is an internal node that
shall be possible to expand and collapse.
'rowobject' is the data returned by your 'IndexCreater' or 'NextCreater'
(installed by SetIndexedList or SetLinkedList).
- options: at present there is only one option:
- TR_HIDE_ROOT: This flag will cause the outermost tree root not to
be displayed (i.e. the leftmost view is a list of sons of the
tree root).
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.
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:
- id: a reference to a list, if id doesn't refer to a list, the
request will be ignored
- i: index to the data that shall be updated. If "i" is currently not
in the visible part of the list-box or if it is out of range, then
the request will be ignored.
See also:
Refresh.
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.
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:
- listid: a reference to a list
- button: specifies which mouse button(s) that are allowed for
gripping
- flags: see: SetObjectGrippable.
- Grip: a call-back function that will be called in the following
cases:
Grip will always be called when the mouse cursor goes over the row,
the "reason" will then be DD_OVER_GRIP. Grip must at this call
determine if it accepts to be gripped, and in that case return
1 otherwise 0. If returned 1 the object may later be gripped
(without notification) and possibly later on also be dropped.
If the "row was gripped" and later on dropped successfully on some
other object (must not necessarily be a list-row), then Grip will
be called a second time and the "reason" will now be DD_SUCCESS.
The return value of Grip will be ignored this time. The recipient
(the object on which was dropped) has already been called when Grip
is called.
The parameter "srcobj" is the object pointer of the gripped row,
i.e. the pointer created by the IndexCreater of the list of the
gripped row.
The parameter "srclist" to the call-back function will be the same
address as "list" (the pointer previously passed to the
AddList-function), "i" will be the index of the gripped object in
the "list"-data.
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:
- listid: a reference to a list. If there already exists more than one
list in a chain (i.e. this is second or more call to HookList) then
any of these listid's may be used as reference - the new one will
always be put to the right of the previously rightmost one.
- listdata, width, events, RowTextCreater, Action, label: see AddList
for info about these parameters.
See also:
AddList.
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:
- listid: a reference to a list (the return value from AddList shall
be used)
- CallBack: a pointer to a function that must be written by you.
This function will be called when the user wants to delete objects
from the list by pressing the Delete-key while the row is in focus.
The parameter "obj" is the address to the
object to delete (the address calculated by the function
"NextCreater/IndexCreater"). If there were multiple rows marked
"CallBack" will be called once for each marked row.
However 'CallBack' can alternatively call 'GetMarkedRows' to
get them all.
The parameter 'id' is a reference to the row object.
See also:
AddList,
GetMarkedRows.
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:
- listid: a reference to a list (the return value from AddList shall
be used)
- CallBack: a pointer to a function that must be written by you.
This function will be called when the user wants to insert a new
object into the list. The parameter "list" is the "list"-data item
specified when the list was created. "index" is the focused index
in "list" that currently in focus.
See also:
AddList.
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.
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:
- listid: must be a leagal id to a list
- CallBack: the pointer to a function written by you. This function
will be called each time a row gets focus (e.g. because the user
moves the "row-cursor" by use of arrows). Parameters in that call:
id is the id of the row-object. This may be used to e.g. get the
row-index by calling GetRowIndex; parameter 'rowobject' is the
pointer created by your list-index-function.
See also:
AddList.
Back to contents