[comp.windows.x] scrolling lists in XView - a file dialog

kneller@dufy.mmwb.ucsf.edu (Don Kneller) (06/27/90)

Here seems like an easy project:

	Create a file open dialog that shows the contents of the current
	directory and allows selection of a file or directory. If a
	directory is chosen, show the contents of that directory. If a
	file is chosen, make it the selected file.


I'm trying to use the XView Scrolling List (aka PANEL_LIST panel item)
as documented in section 7.9 of the XView programming manual.

I'm having the following problems with setting the elements in the list:

	1) using xv_set, it is possible to either set a fixed number of
	   strings for the list, or set an indexed string for the list.
	   What I need is a variable number of strings. Something like
	   **argv would have done the trick.

	   To get a variable number of strings, it is necessary to insert
	   one entry for each string. This is painfully slow and causes
	   unnecessary flashing on the screen. Moreover, it is not possible
	   to start with an empty list of entries --- there must be at least
	   one or PANEL_LIST_INSERT dumps core.

		xv_set(thing, PANEL_LIST_STRINGS, "", (char *) NULL, 0);
		xv_set(thing, PANEL_LIST_INSERT, i
			      PANEL_LIST_STRING, i, newvalue,
			      0);


	2) to change the entries, it is not possible to change all of them
	   at once. I would have hoped something like:

		xv_set(thing, PANEL_LIST_STRINGS, (char *) NULL, 0);

	   would have done the trick. Instead it is necessary to delete
	   them one at a time:

		xv_set(thing, PANEL_DELETE_STRING, i, 0);

	   Again, painfully slow and causes unnecessary screen updates.


Surely (you don't mind if I call you "Shirley?") this has been done before.
Any help would be appreciated.

- don

kneller@dufy.mmwb.ucsf.edu (Don Kneller) (06/29/90)

kneller@dufy.mmwb.ucsf.edu (Don Kneller) writes:

>Here seems like an easy project:

>	Create a file open dialog using scrolling lists.

>I'm having the following problems with setting the elements in the list:

>	1) using xv_set, it is possible to either set a fixed number of
>	   strings for the list, or set an indexed string for the list.
>	   What I need is a variable number of strings. Something like
>	   **argv would have done the trick.


Thanks to everyone that responsed to my posting.

It turns out that it is possible to pass argv-style attributes with the
ATTR_LIST attribute and an attribute-value list (avlist) which is
NULL-terminated. If I have strings STRING_1 through STRING_N which
I want to be the strings in the scrolling list, I set up an avlist with
the following:

	argv[0] = PANEL_LIST_STRINGS;
	argv[1] = STRING_1;
	...
	argv[N] = STRING_N;
	argv[N+1] = NULL;		/* NULL-terminate the strings */
	argv[N+2] = NULL;		/* NULL-terminate the avlist */

Setting this scrolling-list's set of strings is done with one call to xv_set:

	xv_set(thing, ATTR_LIST, argv, NULL);

In what I consider an XView bug, if you use this to try to change the
strings to a different set, and the new set has fewer members than the
old set, the extra members from the old set will remain. Thus it is
necessary to delete the extra members. Again, an avlist can be used to
reduce the calls to xv_set().

NOTE: A SunView programmer has told me that there is a limit on the length
of the avlist of about (I think) 250 elements. I don't know if that is the
case with XView.

Here is the routine I use to update a scrolling list:


/*
 * scrolling_list_update:
 *
 *	Given a scrolling list and an argv-style array of strings,
 *	update the contents of the scrolling list.
 */
scrolling_list_update(list, argc, argv)
Xv_opaque	list;
int		argc;
char		**argv;
{
	register int	i, j;
	char		**avlist;
	int		rows = xv_get(list, PANEL_LIST_NROWS);

	/*
	 * Copy the string information to an avlist.
	 */
	if (argc > 0) {

		/*
		 * Allocate memory for the list and fill it in.
		 */
		avlist = (char **) emalloc((argc + 3) * sizeof (char *));
		avlist[0] = (char *) PANEL_LIST_STRINGS;
		for (i = 0; i < argc; i++)
			avlist[i + 1] = argv[i];
		avlist[++i] = (char *) NULL;	/* NULL-terminate strings */
		avlist[++i] = (char *) NULL;	/* NULL-terminate avlist */

		/*
		 * Set the scrolling list and free the avlist.
		 */
		xv_set(list, ATTR_LIST, avlist, NULL);
		free((char *) avlist);
	}


	/*
	 * This should not be necessary, but ... clear any entries
	 * in excess of the new entries.
	 */
	if (rows > argc) {

		/*
		 * Set up an avlist with PANEL_LIST_DELETE,index pairs. The
		 * panel entries are deleted from bottom (high index) to
		 * top (low index) which might reduce copying of entries.
		 */
		avlist = (char **) emalloc(((rows-argc)*2+1) * sizeof (char *));
		for (j = 0, i = rows - 1; i >= argc; i--) {
			avlist[j++] = (char *) PANEL_LIST_DELETE;
			avlist[j++] = (char *) i;
		}
		avlist[j] = (char *) NULL;	/* NULL-terminate avlist */

		/*
		 * Delete the excess entries and free the avlist.
		 */
		xv_set(list, ATTR_LIST, avlist, NULL);
		free((char *) avlist);
	}
}