[comp.windows.open-look] Help! with scrolling lists and xv_create

sz@cci632.cci.com (Stephen Zehl) (05/25/91)

-

    I'm looking for a little help with scrolling lists under OpenWindows 
(XView).  I'm using DevGuide to generate C code stubs of scrolling lists, 
I'm having trouble getting the information into the lists.

    Volume Seven of the XView Programming Manual gives two examples of how
to hard code these choices into the code on pages 155 and 157.  As shown
below:

    xv_create(panel, PANEL_LIST, 
	PANEL_LIST_STRINGS,  "One", "Two", "Three", NULL,
	NULL);

	This is fine if you know what you want in the list ahead of time, but
what if you want to read in a list of files from a directory?  I figured I
could just substitute a pointer to an array of strings in place of the
strings themselves as shown below:

    static char	*mylist[3] = { "One", "Two", "Three" };

    xv_create(panel, PANEL_LIST, 
	PANEL_LIST_STRINGS,  *mylist, NULL,
	NULL);

	This will give me the first string in the list, but not the rest.
And if I tack the NULL onto the list itself and remove it from after *mylist,
I get a segmentation fault and a core in my lap.

	If anyone out there has worked on this, Please, Please send me some
e-mail with an explaination of how you did this.  I'd really appreciate it.

	Thanks again,
				Steve.

 CCCC  CCCC IIII     Stephen Zehl           Internet: sz@cci.com
CC    CC     II   Computer Consoles. Inc.     Usenet: uupsi!cci632!sz
CC    CC     II    Rochester, New York.         or  : uunet!ccicpg!cci632!sz
 CCCC  CCCC IIII       DISCLAIMER: I speak for myself, not for my employer.

	

brentb@montagne.Eng.Sun.COM (Brent Browning) (05/28/91)

In article <1991May24.211132.10282@cci632.cci.com> sz@cci632.cci.com (Stephen Zehl) writes:
>	This is fine if you know what you want in the list ahead of time, but
>what if you want to read in a list of files from a directory?  I figured I
>could just substitute a pointer to an array of strings in place of the
>strings themselves as shown below:
>
>    static char	*mylist[3] = { "One", "Two", "Three" };

   PANEL_LIST_STRINGS must *really* have a NULL terminated list
of strings, *not* a char ** pointing at a NULL terminated list
of strings.

   I've included a sample program that does just what you
need to do.  Type in a filename, then hit the load button.  It
will load that file into the scrolling list.  Hitting the
save button saves it out to a file.

   This particular example was written for someone else.  It
also saves the contents of the scrolling list when the application
is quit from the window menu.

Brent Browning			Internet: brentb@Eng.Sun.COM
Sun Microsystems, Inc		UUCP: ...!sun!brentb
2550 Garcia Ave. MTV 01-40	Phone: (415) 336-5573
Mountain View, CA 94043

--------8<--------8<---- Cut here ----8<--------8<--------
#include <stdio.h>
#include <sys/param.h>
#include <sys/types.h>
#include <xview/xview.h>
#include <xview/panel.h>

void		load_file();
void		save_file();
void		load_list_from_file();
void		save_list_to_file();
Notify_value	destroy_func();

Xv_opaque	File_name;
Xv_opaque	File_list;

main(argc, argv)
	int	argc;
	char	**argv;
{
	Xv_opaque	frame;
	Xv_opaque	panel;

	xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, NULL);
	
	frame = xv_create(NULL, FRAME, NULL);
	notify_interpose_destroy_func(frame, destroy_func);

	panel = xv_create(frame, PANEL,
		PANEL_LAYOUT, PANEL_VERTICAL,
		NULL);

	File_name = xv_create(panel, PANEL_TEXT,
		PANEL_VALUE_DISPLAY_LENGTH, 30,
		PANEL_VALUE_STORED_LENGTH, 80,
		PANEL_LABEL_STRING, "File:",
		PANEL_VALUE, "TEST",
		NULL);
	
	File_list = xv_create(panel, PANEL_LIST,
		PANEL_LIST_WIDTH, 250,
		PANEL_LIST_DISPLAY_ROWS, 10,
		PANEL_CHOOSE_ONE, TRUE,
		PANEL_CHOOSE_NONE, FALSE,
		NULL);

	xv_set(panel, PANEL_LAYOUT, PANEL_HORIZONTAL, NULL);

	xv_create(panel, PANEL_BUTTON,
		PANEL_NEXT_ROW, -1,
		PANEL_LABEL_STRING, "Load From File",
		PANEL_NOTIFY_PROC, load_file,
		NULL);

	xv_create(panel, PANEL_BUTTON,
		PANEL_LABEL_STRING, "Save To File",
		PANEL_NOTIFY_PROC, save_file,
		NULL);

	window_fit(panel);
	window_fit(frame);
	xv_main_loop(frame);
}

void
load_file(item, event)
	Panel_item	item;
	Event		*event;
{
	load_list_from_file();
}

void
save_file(item, event)
	Panel_item	item;
	Event		*event;
{
	save_list_to_file();
}

Notify_value
destroy_func(frame, status)
	Frame		frame;
	Destroy_status	status;
{
	if (status == DESTROY_CLEANUP)
		save_list_to_file();

	return notify_next_destroy_func(frame, status);
}

void
load_list_from_file()
{
	int	i = 0;
	FILE	*fp;
	char	buf[MAXPATHLEN];
	char	*file = (char *)xv_get(File_name, PANEL_VALUE);

	if ((fp = fopen(file, "r")) == NULL) {
		perror(file);
		return;
	}

	for (i = 0; fgets(buf, MAXPATHLEN, fp); i++) {
		buf[strlen(buf)-1] = '\0';

		xv_set(File_list, PANEL_LIST_INSERT, i,
				  PANEL_LIST_STRING, i, buf,
				  NULL);
	}

	fclose(fp);
}

void
save_list_to_file()
{
	int	i;
	int	n;
	FILE	*fp;
	char	*file = (char *)xv_get(File_name, PANEL_VALUE);

	if ((fp = fopen(file, "w")) == NULL) {
		perror(file);
		return;
	}

	n = xv_get(File_list, PANEL_LIST_NROWS);

	for (i = 0; i < n; i++) {
		fprintf(fp, "%s\n",
			(char *)xv_get(File_list, PANEL_LIST_STRING, i));
	}

	fclose(fp);
}

--
Brent Browning			Internet: brentb@Eng.Sun.COM
Sun Microsystems, Inc		UUCP: ...!sun!brentb
2550 Garcia Ave. MTV 01-40	Phone: (415) 336-5573
Mountain View, CA 94043

nicolas@bmsr9.usc.edu (Nicolas Rouquette) (05/29/91)

In article <14063@exodus.Eng.Sun.COM> brentb@montagne.Eng.Sun.COM (Brent Browning) writes:

      I've included a sample program that does just what you
   need to do.  Type in a filename, then hit the load button.  It
   will load that file into the scrolling list.  Hitting the
   save button saves it out to a file.

      This particular example was written for someone else.  It
   also saves the contents of the scrolling list when the application
   is quit from the window menu.

Can someone post a an example of code to use PANEL_LIST_INSERT &
PANEL_LIST_DELETE? There are two problems: 1) intense flashing
and 2) after using PANEL_LIST_DELETE in descending order as suggested 
in O'Reilly, I get bus errors.

If there is a bug with no practical workaround until OW3, is it safe
to delete the list instance and create a fresh new one?



--
Nicolas Rouquette		email: nrouquet@pollux.usc.edu
Computer Science Department
Los Angeles, CA 90089-0782
-- 
Nicolas Rouquette		email: nrouquet@pollux.usc.edu
Computer Science Department
Los Angeles, CA 90089-0782

paccini@uni2a.unige.ch (05/29/91)

In article <NICOLAS.91May28132821@bmsr9.usc.edu>, nicolas@bmsr9.usc.edu (Nicolas Rouquette) writes:
> 
> In article <14063@exodus.Eng.Sun.COM> brentb@montagne.Eng.Sun.COM (Brent Browning) writes:
>
> Can someone post a an example of code to use PANEL_LIST_INSERT &
> PANEL_LIST_DELETE? There are two problems: 1) intense flashing
> and 2) after using PANEL_LIST_DELETE in descending order as suggested 
> in O'Reilly, I get bus errors.

A simple way to avoid the flashing is to hide the panel list by
using the XV_SHOW attribute:

	xv_set( panel, XV_SHOW, FALSE, NULL);
	<delete items...>
	xv_set( panel, XV_SHOW, TRUE, NULL);

This works pretty well with OW 2.0 and gives a very clean behaviour.

------------------------------------------------------------------------------
Jean-Francois Paccini 			paccini@cui.unige.ch
University of Geneva
Switzerland

brentb@montagne.Eng.Sun.COM (Brent Browning) (05/30/91)

In article <NICOLAS.91May28132821@bmsr9.usc.edu> you write:
>
>Can someone post a an example of code to use PANEL_LIST_INSERT &
>PANEL_LIST_DELETE? There are two problems: 1) intense flashing
>and 2) after using PANEL_LIST_DELETE in descending order as suggested 
>in O'Reilly, I get bus errors.

   It sure would have been nice to have some sort of batching
for scrolling lists - eh?  XView doesn't really provide any
support for this.  The recommended way to do this is to set XV_SHOW
to FALSE on the list, then do the update, the set XV_SHOW to TRUE.

   There are times that it is faster to just destroy the old
list and then recreate it again.  If you are using the instance
pointers provided by gxv make sure you store the new handle 
back in the instance pointer.

   We do our batching as follows.  We call a routine "list_add"
that stores the string in a large dynamically allocated array.  Then
when we really want to do the list update we destroy the
old list, create a new one (calling ..._list_create), then do
the batch update in chunks with attr lists.  Here's our function:

char	**String_list;		/* Dynamically allocated array of strings */

/*
 * Insert internal list into scrolling list in chunks.
 */
void
list_batch_insert(ip)
	..._window_objects	*ip;
{
	int	i = 0;
	void	*attr_array[ATTR_STANDARD_SIZE];
	void	**attr_ptr;
	void	**attr_end;

	/*
	 * Destroy old list (faster than delete all entries) then
	 * create a fresh one.
	 */
	xv_set(ip->list, XV_SHOW, FALSE, NULL);
	xv_destroy_safe(ip->list);
	ip->list = ..._window_list_create(ip, ip->controls);
	xv_set(ip->list, XV_SHOW, FALSE, NULL);

	attr_ptr = attr_array;
	attr_end = &attr_array[ATTR_STANDARD_SIZE - 20];

	for (i = 0; i < Gfm_list_count; i++) {
		*attr_ptr++ = (void *) PANEL_LIST_INSERT;
		*attr_ptr++ = (void *) i;

		*attr_ptr++ = (void *) PANEL_LIST_STRING;
		*attr_ptr++ = (void *) i;
		*attr_ptr++ = (void *) String_list[i];

		/*
		 * Check for overflow or completion, if full terminate
		 * the ATTR_LIST and set it on the scrolling list.
		 */
		if (attr_ptr >= attr_end || i >= Gfm_list_count - 1) {
			*attr_ptr = (void *) 0;
			xv_set(ip->list, ATTR_LIST, attr_array, NULL);
			attr_ptr = attr_array;
		}
	}

	/*
	 * Select first item and make list visible
	 */
	xv_set(ip->list,
		PANEL_LIST_SELECT, 0,	TRUE,
		XV_SHOW,		TRUE,
		NULL);
}

--
Brent Browning			Internet: brentb@Eng.Sun.COM
Sun Microsystems, Inc		UUCP: ...!sun!brentb
2550 Garcia Ave. MTV 01-40	Phone: (415) 336-5573
Mountain View, CA 94043

toone@looney.Corp.Sun.COM (Nolan Toone) (05/31/91)

brentb@montagne.Eng.Sun.COM (Brent Browning) writes:
> In article <1991May24.211132.10282@cci632.cci.com> sz@cci632.cci.com (Stephen Zehl) writes:
> >	This is fine if you know what you want in the list ahead of time, but
> >what if you want to read in a list of files from a directory?  I figured I
> >could just substitute a pointer to an array of strings in place of the
> >strings themselves as shown below:
> >
> >    static char	*mylist[3] = { "One", "Two", "Three" };
> 
>    PANEL_LIST_STRINGS must *really* have a NULL terminated list
> of strings, *not* a char ** pointing at a NULL terminated list
> of strings.
> 
>    I've included a sample program that does just what you
> need to do.  Type in a filename, then hit the load button.  It
> will load that file into the scrolling list.  Hitting the
> save button saves it out to a file.
> 


The way Brent indicated is probably the best for this example, but just FYI:

Another way is to use ATTR_LIST. This allows you to create a list of char ** and pass
them to xv_{create/set}. The one thing to watch for is that you MUST include the
ATTRIBUTE in the array as well as the NULL termiator and the max size for the list
is 256. For example:

if the array were:
	char	*list[10];

	list[0] = (char *)PANEL_LIST_STRINGS;
	list[1] = "item 1";
	list[2] = "item 2";
	list[3] = "item 3";
	list[4] = "item 4";
	list[5] = "item 5";
	list[6] = "item 6";
	list[7] = "item 7";
	list[8] = (char *)NULL;
	list[9] = (char *)NULL;

The first NULL to termiate PANEL_LIST_STRINGS the second to termiate the attribute list.

Then you could use the above list in:

	xv_create(panel, PANEL_LIST,
		ATTR_LIST, list,
		NULL);

which is the the same as:

	xv_create(panel, PANEL_LIST,
		PANEL_LIST_STRINGS, 	"item 1", 
				"item 2", 
				"item 3", 
				"item 4", 
				"item 5", 
				"item 6", 
				"item 7",
				NULL,
		NULL);

		Regards,

     /\
    \\ \	Nolan C. Toone, ISV Engineering
   \ \\ /	Sun Microsystems 
  / \/ / / 	MailStop PAL1-316
 / /   \//\ 	2550 Garcia Avenue
 \//\   / / 	Mountain View, California  94043
  / / /\ /  	
   / \\ \	Phone:  415-336-0391
    \ \\ 	EMail:	toone@Corp.Sun.Com
     \/

ed@Canada.Sun.COM (Edward Lycklama - KL Group Inc.) (06/04/91)

> 
> In article <NICOLAS.91May28132821@bmsr9.usc.edu> you write:
> >
> >Can someone post a an example of code to use PANEL_LIST_INSERT &
> >PANEL_LIST_DELETE? There are two problems: 1) intense flashing
> >and 2) after using PANEL_LIST_DELETE in descending order as suggested 
> >in O'Reilly, I get bus errors.
> 
>    It sure would have been nice to have some sort of batching
> for scrolling lists - eh?  XView doesn't really provide any
> support for this.  The recommended way to do this is to set XV_SHOW
> to FALSE on the list, then do the update, the set XV_SHOW to TRUE.
> 
> Brent Browning			Internet: brentb@Eng.Sun.COM
> Sun Microsystems, Inc		UUCP: ...!sun!brentb
> 2550 Garcia Ave. MTV 01-40	Phone: (415) 336-5573
> Mountain View, CA 94043
> 

Actually, there is a way to batch request to scrolling lists; just set PANEL_PAINT
to PANEL_NONE while inserting/deleting, and no updates occur.  When you are done,
set PANEL_PAINT to PANEL_CLEAR, and the new list is drawn.


Ed Lycklama

KL Group Inc.                       | Phone: (416) 594-1026 Ext. 22
134 Adelaide St. E, Suite 204       | Fax:   (416) 594-1919
Toronto, Ontario, M5C 1K9           | UUCP:  sun!suncan!klg!ed
CANADA