[comp.windows.x.motif] Stretchable List

rick@pcrat.uucp (Rick Richardson) (07/17/90)

I'm trying to make a Form that contains some buttons at the
top, and a scrollable list of things at the bottom.

If the User resizes the form, I want the scrollable list to change
size so that it fills the form completely, except for the area
occupied by the buttons at the top. E.G. I want the form to look
like this no matter how big or small the window is:

	+-------------------------+
	|	Button		  |
	+-------------------------+
	| Item N		^ |
	| Item N+1		| |
	| Item N+2		| |
	| Item N+3		v |
	| <-------------------->  |
	+-------------------------+

I've tried a couple things.  If I use a SelectionBox, the
list portion stretches automatically in the horizontal direction,
but not vertically.  Plus, I just want the list portion, anyhow.
If I used the SelectionBox, I'd want to tell it (somehow) to
make visibleItems variable, and forget the Text area and Buttons.

Using a ScrolledList, I can't get either dimension to stretch
with the form.  I fooled around alot with the policies.
PLUS, the widget positions itself *under* the button, as if
the button had 0 height, even though the attachment constraints
are the same as for the SelectionBox I tried.  That might be a bug.

Perhaps these widgets just aren't appropriate.  Perhaps I need
to use some callbacks.  Any suggestions will be gratefully
received.  I'm enclosing the (bare minimum) .uil file so you
can better see what I've tried.

All this is using Motif 1.0.

-Rick Richardson

module prototype
    version = 'v1.0'
    names = case_sensitive
    include file 'XmAppl.uil';

object ft_main : XmForm {
	controls {
		XmPushButton	button1;
		!
		! Comment out one or the other
		!
		XmSelectionBox	try_sel;
		! XmScrolledList	try_list;
	};
	arguments {
		XmNwidth = 300;
		XmNheight = 300;
	};
};

object button1 : XmPushButton {
	arguments { 
		XmNtopAttachment = XmATTACH_FORM;
		XmNleftAttachment = XmATTACH_FORM;
		XmNrightAttachment = XmATTACH_FORM;
	};
};

object try_selbox : XmSelectionBox {
	arguments { 
		XmNtopAttachment = XmATTACH_WIDGET;
		XmNtopWidget = XmPushButton button1;
		XmNleftAttachment = XmATTACH_FORM;
		XmNrightAttachment = XmATTACH_FORM;
		XmNbottomAttachment = XmATTACH_FORM;

		XmNlistVisibleItemCount = 5;
	};
};

object try_list : XmScrolledList {
	arguments { 
		XmNtopAttachment = XmATTACH_WIDGET;
		XmNtopWidget = XmPushButton button1;
		XmNleftAttachment = XmATTACH_FORM;
		XmNrightAttachment = XmATTACH_FORM;
		XmNbottomAttachment = XmATTACH_FORM;

		XmNvisibleItemCount = 5;
		XmNscrollBarDisplayPolicy = XmSTATIC;
		XmNlistSizePolicy = XmCONSTANT;
		XmNvisualPolicy = XmCONSTANT;
	};
};

end module;
-- 
Rick Richardson - PC Research, Inc., uunet!pcrat!rick, (201) 389-8963

rick@pcrat.uucp (Rick Richardson) (07/17/90)

In article <1990Jul16.172955.11321@pcrat.uucp> rick@pcrat.uucp (Rick Richardson) writes:
>I'm trying to make a Form that contains some buttons at the
>top, and a scrollable list of things at the bottom.

I think I've answered my own question.  I gave up on using the
widget with the enticing name ScrolledList.  Instead, I used
the raw ScrolledWindow, at first with a List inside it, then
with a Form inside it.  The Form contains a Label and a List,
which is better for what I wanted to do, anyway.

I did run into what I'd consider another bug, which you can read
about in the UIL comments.

Thanks to all those people who I'm sure were ready to point me
in the right direction.  If you still want to, feel free to
comment on my use of UIL (modulo bracing and indenting).

-Rick

P.S. Filling in the list creation C code, and the pushbutton callback
is an exercise for the reader.  If you haven't used UIL before, snag
the fairly generic hellomotif.c scaffold from /usr/lib/X11/examples.

I think the theory is that a Human Factors person is supposed to be
able to write UIL and run it against the scaffold.  When the whole
interface is fleshed out, it becomes the input to a programmer who
writes the C code to make it really do that, using most of the UIL
as supplied from Human Factors.  Of course, the UIL manual isn't
written to be readable by those folks, and is barely readable by a
programmer, so the theory may be shot full of holes.  Specific
complaint: dump the BNF into an appendix, and replace with examples.
OSF: Feel free to use this one.

!
!	Sample UIL specification of a stretchable list, with header
!
module fr
	version = 'v1.0'
	names = case_sensitive
	include file 'XmAppl.uil';

object ft_main : XmForm {
	controls {
		XmPushButton		kill_button;
		XmScrolledWindow	scroll_window;
	};
	arguments {
		XmNheight = 200;
		XmNwidth = 300;
 	};
};

object kill_button : XmPushButton {
	arguments { 
		XmNtopAttachment = XmATTACH_FORM;
		XmNleftAttachment = XmATTACH_FORM;
		XmNrightAttachment = XmATTACH_FORM;
		XmNlabelString = "Select a Process to Kill, Then Push Me";
	};
};

object scroll_window : XmScrolledWindow {
	controls {
		XmForm	scroll_form;
	};
	arguments { 
		XmNtopAttachment = XmATTACH_WIDGET;
		XmNtopWidget = XmPushButton kill_button;
		XmNleftAttachment = XmATTACH_FORM;
		XmNrightAttachment = XmATTACH_FORM;
		XmNbottomAttachment = XmATTACH_FORM;

		XmNscrollingPolicy = XmAUTOMATIC;
		XmNvisualPolicy = XmCONSTANT;
		XmNworkWindow = XmForm scroll_form;
	};
};

object scroll_form : XmForm {
	controls {
		XmLabel			scroll_header;
		XmList			scroll_list;
	};
};

!
!	Although it is tempting to put ???Attachment constraints
!	on scroll_header and scroll_list, don't do it.  It triggers
!	some kind of bug in Motif, and the scroll_list gets trashed.
!	It seems to do 'the right thing' without them (luckily).
!

object scroll_header : XmLabel {
	arguments { 
		XmNlabelString =
		"     UID   PID  PPID  C    STIME TTY      TIME COMMAND    ";
		! XmNtopAttachment = XmATTACH_FORM;
		! XmNleftAttachment = XmATTACH_FORM;
	};
};

value scroll_list_items : exported string_table (
"    root     0     0  0  Jul 10  ?        0:03 sched",
"    root     1     0  0  Jul 10  ?        3:50 /etc/init ",
"    root     2     0  0  Jul 10  ?        4:08 vhand",
"    root     3     0  0  Jul 10  ?        3:21 bdflush",
"    root    97     1  0  Jul 10  console  0:01 /etc/getty console console ",
"    rick   101     1  0  Jul 10  vt01     0:19 -ksh ",
"    root  9124     1  0 16:43:46 ttyp0    0:01 /etc/faxsrv ",
"    root  9125  9124  0 16:43:46 ttyp0    0:01 faxrun1 -Tjfax -D/dev/jfax0",
"    root  9126  9124  0 16:43:46 ttyp0    0:01 faxrun2 -Tbfax -D/dev/bfax0",
"    root  9127  9124  0 16:43:47 ttyp0    0:01 faxrun3 -Tbfax -D/dev/bfax1",
"    root  9128  9124  0 16:43:47 ttyp0    0:03 faxrun4 -Tefax -D/dev/tty00",
"    root  9129  9124  0 16:43:48 ttyp0    0:03 faxrun5 -Tefax -D/dev/tty01",
"    root    75     1  0  Jul 10  ?        0:21 /etc/cron ",
"    root    79     1  0  Jul 10  ?        0:38 /usr/lib/lpsched ",
"    root  6242     1  0  Jul 14  vt02     0:00 /etc/getty /dev/vt02 vt02 ",
"    root  6243     1  0  Jul 14  vt03     0:00 /etc/getty /dev/vt03 vt03 ",
"    root  6244     1  0  Jul 14  vt04     0:00 /etc/getty /dev/vt04 vt04 ",
"    rick  8300   101  0 23:42:07 vt01     0:00 xinit ",
"    rick  8301  8300  9 23:42:07 vt05     7:05 X :0 ",
"    rick  8302  8300  3 23:42:13 ?        1:27 xterm -geometry 80x24+0+0",
"    rick  8303  8302  0 23:42:14 ?        0:23 /usr3/bin/X11/uwm ",
"    rick  8304  8302  1 23:42:19 ttyp0    0:09 ksh "
);

object scroll_list : XmList {
	arguments { 
		! XmNtopAttachment = XmATTACH_WIDGET;
		! XmNtopWidget = XmLabel scroll_header;
		! XmNleftAttachment = XmATTACH_FORM;
		! XmNrightAttachment = XmATTACH_FORM;
		! XmNbottomAttachment = XmATTACH_FORM;

		XmNitems = scroll_list_items;
		XmNitemCount = 22;
		XmNvisibleItemCount = 22;
	};
};

end module;

-- 
Rick Richardson | Looking for FAX software for UNIX/386 ??? Ask About: |Mention
PC Research,Inc.| FaxiX - UNIX Facsimile System (tm)                   |FAX# for
uunet!pcrat!rick| FaxJet - HP LJ PCL to FAX (Send WP,Word,Pagemaker...)|Sample
(201) 389-8963  | JetRoff - troff postprocessor for HP LaserJet and FAX|Output

rick@pcrat.uucp (Rick Richardson) (07/17/90)

In article <1990Jul16.223021.11654@pcrat.uucp> rick@pcrat.UUCP (Rick Richardson) writes:

>I think I've answered my own question.

Actually, what I thought was fixed is really still broken.

It seems the /etc/sched List entry was hiding behind the header
Label.  So, it looks like I'm damned if I do, and damned if I don't.

That is, with the attachments specified for the children of
the scroll Form I get complete trash displayed for the List.
If the attachments are left off, then the header Label child
and the List child are overlaid on the form.

I got one piece of advice that said that a workaround is to add
the bottom and right attachments after the Form widget has been
realized.  That, of course, must be done from C.  Making the
utility of UIL less worthwhile.

I think the solution is to toss the Form widget and get something
else (Table was mentioned).  Form seems to be terribly broken.

On the bright side, if I keep tossing widgets, I'll eventually
get back to just Xlib, and my apps will be relatively small. :-)

-Rick

P.S. If you aren't following this, see the 2nd referenced posting.
-- 
Rick Richardson - PC Research, Inc., uunet!pcrat!rick, (201) 389-8963

rick@pcrat.UUCP (Rick Richardson) (07/21/90)

In article <1990Jul17.014256.11899@pcrat.uucp> rick@pcrat.UUCP (Rick Richardson) writes:

>Actually, what I thought was fixed is really still broken.

>I think the solution is to toss the Form widget and get something
>else (Table was mentioned).  Form seems to be terribly broken.

I got the Table widget from the Widget Creation Library, and
nazgul@alphalpha.com (Kee Hinckley) sent me the patches to make
it Motif-ized.  I then recoded my example in C, and included a
command line option to use the Table widget instead of the Form
widget as the inner widget container.

It all works as expected using the Table widget.  I've appended
the C version in a SHAR file for those who care to try this
themselves.  Also, the comments indicate the various effects I
discovered when trying to use the Form.  If the OSF is listening,
I now consider the Form to be a broken widget that needs fixing.

Also, I couldn't find VARARGS versions of XtCreateManagedWidget()
and XtSetValues() in my X11R3 libXt.a, so I've included my own
versions of vXtCreateManagedWidget() and vXtSetValues() as well.
The method used in all the books is so utterly ugly I couldn't stand it.

-Rick Richardson

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	ftm.c
# This archive created: Sat Jul 21 11:52:09 1990
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'ftm.c'
then
	echo shar: "will not over-write existing file 'ftm.c'"
else
sed 's/^X//' << \SHAR_EOF > 'ftm.c'
X/*
X * ftm.c
X *	Test Program for Stretchable List (C version, taken from UIL version)
X *
X * $ ftm 0	# the children of ScrollForm are not constrained
X * $ ftm 1	# the children of ScrollForm are constrained
X * $ ftm 2	# Use the PD Table widget instead of a Form for ScrollForm
X *
X * In the first invocation, everything comes up looking normal, except that
X * the first line of the ScrollList is buried under the ScrollHdr.
X *
X * In the second invocation, the vertical ScrollBar of the List is missing,
X * and only about 50% of the first line of the ScrollList is displayed. E.G.
X * the letters are clipped.
X *
X * In the third invocation, everything works.  Obviously, Table has much
X * better (i.e. working) geometry management for its children.
X *
X * I would expect the second case to be the proper way to code this, but
X * it sure doesn't work right on this system, ISC Motif 1.0, X11R3.
X *
X * If you don't have the PD Table widget, #define NO_TABLE_WIDGET.
X * In that case, ftm 2 (the invocation that works) won't be available.
X *		
X * Rick Richardson, uunet!pcrat!rick, rick@pcrat.pcr.com
X */
X#include <stdio.h>
X#include <varargs.h>
X#include <X11/StringDefs.h>
X#include <X11/Intrinsic.h>
X#include <Xm/Xm.h>
X#include <Xm/Form.h>
X#include <Xm/PushB.h>
X#include <Xm/Label.h>
X#include <Xm/ScrolledW.h>
X#include <Xm/List.h>
X
X#ifndef NO_TABLE_WIDGET
X#include "Table.h"
X#endif
X
X/*
X *	Convenience functions
X */
Xextern	Widget		vXtCreateManagedWidget();
Xextern	void		vXtSetValues();
X#define	ASIZEOF(ARRAY)	(sizeof(ARRAY)/sizeof(ARRAY[0]))
X#define	AV		(XtArgVal)
X#define	XMSC(S)		XmStringCreate(S, XmSTRING_DEFAULT_CHARSET)
X
X/*
X *	Widget Heirarchy
X */
XWidget	Top;						/* Shell */
XWidget		OuterForm;				/* Form */
XWidget			KillButton;			/* PushButton */
XWidget			ScrollWindow;			/* ScrolledWindow */
XWidget				ScrollForm;		/* Form or Table */
XWidget					ScrollHdr;	/* Label */
XWidget					ScrollList;	/* List */
X
X/*
X *	Strings to use for labels and list
X */
X#define	KILL_LABEL	"Select a Process to Kill and Push Me"
X#define	SCROLL_HDR \
X	"     UID   PID  PPID  C    STIME TTY      TIME COMMAND    "
X
Xstatic char	*ListItems[] =
X{
X"    root     0     0  0  Jul 10  ?        0:03 sched",
X"    root     1     0  0  Jul 10  ?        3:50 /etc/init ",
X"    root     2     0  0  Jul 10  ?        4:08 vhand",
X"    root     3     0  0  Jul 10  ?        3:21 bdflush",
X"    root    97     1  0  Jul 10  console  0:01 /etc/getty console console ",
X"    rick   101     1  0  Jul 10  vt01     0:19 -ksh ",
X"    root  9124     1  0 16:43:46 ttyp0    0:01 /etc/faxsrv ",
X"    root  9125  9124  0 16:43:46 ttyp0    0:01 faxrun1 -Tjfax -D/dev/jfax0",
X"    root  9126  9124  0 16:43:46 ttyp0    0:01 faxrun2 -Tbfax -D/dev/bfax0",
X"    root  9127  9124  0 16:43:47 ttyp0    0:01 faxrun3 -Tbfax -D/dev/bfax1",
X"    root  9128  9124  0 16:43:47 ttyp0    0:03 faxrun4 -Tefax -D/dev/tty00",
X"    root  9129  9124  0 16:43:48 ttyp0    0:03 faxrun5 -Tefax -D/dev/tty01",
X"    root    75     1  0  Jul 10  ?        0:21 /etc/cron ",
X"    root    79     1  0  Jul 10  ?        0:38 /usr/lib/lpsched ",
X"    root  6242     1  0  Jul 14  vt02     0:00 /etc/getty /dev/vt02 vt02 ",
X"    root  6243     1  0  Jul 14  vt03     0:00 /etc/getty /dev/vt03 vt03 ",
X"    root  6244     1  0  Jul 14  vt04     0:00 /etc/getty /dev/vt04 vt04 ",
X"    rick  8300   101  0 23:42:07 vt01     0:00 xinit ",
X"    rick  8301  8300  9 23:42:07 vt05     7:05 X :0 ",
X"    rick  8302  8300  3 23:42:13 ?        1:27 xterm -geometry 80x24+0+0",
X"    rick  8303  8302  0 23:42:14 ?        0:23 /usr3/bin/X11/uwm ",
X"    rick  8304  8302  1 23:42:19 ttyp0    0:09 ksh "
X};
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X	XmString	*litems;
X	register int	i;
X	int		mode = 0;
X
X	/*
X	 *	Convert Strings to Motif format
X	 */
X	litems = (XmString *) XtMalloc(ASIZEOF(ListItems) * sizeof(XmString));
X	for (i = 0; i < ASIZEOF(ListItems); ++i)
X		litems[i] = XMSC(ListItems[i]);
X
X	/*
X	 *	Create the Widget Heirarchy
X	 */
X	Top = XtInitialize(argv[0], argv[0], NULL, 0, &argc, argv);
X
X	if (argc > 1) mode = atoi(argv[1]);
X	else {fprintf(stderr, "Usage: ftm [0|1|2]\n"); exit(1);}
X
X	OuterForm = vXtCreateManagedWidget("OuterForm",
X				xmFormWidgetClass, Top,
X				XtNwidth,	AV 300,
X				XtNheight,	AV 200,
X				(String) NULL);
X
X	    KillButton = vXtCreateManagedWidget("KillButton",
X				xmPushButtonWidgetClass, OuterForm,
X				XmNtopAttachment, AV XmATTACH_FORM,
X				XmNleftAttachment, AV XmATTACH_FORM,
X				XmNrightAttachment, AV XmATTACH_FORM,
X				XmNlabelString, AV XMSC(KILL_LABEL),
X				(String) NULL);
X
X	    ScrollWindow = vXtCreateManagedWidget("ScrollWindow",
X				xmScrolledWindowWidgetClass, OuterForm,
X				XmNtopAttachment, AV XmATTACH_WIDGET,
X				XmNtopWidget, AV KillButton,
X				XmNleftAttachment, AV XmATTACH_FORM,
X				XmNrightAttachment, AV XmATTACH_FORM,
X				XmNbottomAttachment, AV XmATTACH_FORM,
X				XmNscrollingPolicy, AV XmAUTOMATIC,
X				XmNvisualPolicy, AV XmCONSTANT,
X				/* XmNworkWindow, AV scroll_form,*/
X				(String) NULL);
X
X#ifndef NO_TABLE_WIDGET
Xif (mode==2)
X		ScrollForm = vXtCreateManagedWidget("table",
X				tableWidgetClass, ScrollWindow,
X				(String) NULL);
Xelse
X#endif
X		ScrollForm = vXtCreateManagedWidget("ScrollForm",
X				xmFormWidgetClass, ScrollWindow,
X				(String) NULL);
X
X		    ScrollHdr = vXtCreateManagedWidget("ScrollHdr",
X				xmLabelWidgetClass, ScrollForm,
X				XmNlabelString, AV XMSC(SCROLL_HDR),
X				mode == 1 ?
X					XmNtopAttachment : (String) NULL,
X							AV XmATTACH_FORM,
X				XmNleftAttachment, AV XmATTACH_FORM,
X				(String) NULL);
X
X		    ScrollList = vXtCreateManagedWidget("ScrollList",
X				xmListWidgetClass, ScrollForm,
X				XmNitems, AV litems,
X				XmNitemCount, AV ASIZEOF(ListItems),
X				XmNvisibleItemCount, AV ASIZEOF(ListItems),
X				mode == 1 ?
X					XmNtopAttachment : (String) NULL,
X							AV XmATTACH_WIDGET,
X				XmNtopWidget, AV ScrollHdr,
X				XmNleftAttachment, AV XmATTACH_FORM,
X				XmNrightAttachment, AV XmATTACH_FORM,
X				XmNbottomAttachment, AV XmATTACH_FORM,
X				(String) NULL);
X
X	/*
X	 * Now fix up stuff we couldn't specify before
X	 */
X	vXtSetValues(ScrollWindow, XmNworkWindow, AV ScrollForm, (String) NULL);
X#	ifndef NO_TABLE_WIDGET
X		if (mode == 2)
X		{
X			XtTblConfig(ScrollHdr,
X				/* pos */	0, 0,
X				/* span*/	1, 1,
X						TBL_SM_HEIGHT);
X			XtTblConfig(ScrollList,
X				/* pos */	0, 1,
X				/* span*/	1, 1,
X						TBL_DEF_OPT);
X		}
X#	endif
X
X	XtRealizeWidget(Top);
X	XtMainLoop();
X}
X
X/*
X *	Variable arg list version of XtCreateManagedWidget
X */
X/* VARARGS */
XWidget
XvXtCreateManagedWidget(va_alist)
Xva_dcl
X{
X	va_list		args;
X
X	String		name;
X	String		class;
X	Widget		parent;
X
X#	define		NXARGS	100
X	Arg		xargs[NXARGS];
X	register int	i;
X
X	va_start(args);
X	name = va_arg(args, String);
X	class = va_arg(args, String);
X	parent = va_arg(args, Widget);
X
X	for (i = 0; i < NXARGS; ++i)
X	{
X		xargs[i].name = va_arg(args, String);
X		if (xargs[i].name == NULL) break;
X		xargs[i].value = va_arg(args, XtArgVal);
X	}
X	va_end(args);
X	return (XtCreateManagedWidget(name, class, parent, xargs, i));
X#	undef		NXARGS
X}
X
X/* VARARGS */
Xvoid
XvXtSetValues(va_alist)
Xva_dcl
X{
X	va_list		args;
X
X	Widget		w;
X
X#	define		NXARGS	100
X	Arg		xargs[NXARGS];
X	register int	i;
X
X	va_start(args);
X	w = va_arg(args, Widget);
X
X	for (i = 0; i < NXARGS; ++i)
X	{
X		xargs[i].name = va_arg(args, String);
X		if (xargs[i].name == NULL) break;
X		xargs[i].value = va_arg(args, XtArgVal);
X	}
X	va_end(args);
X	XtSetValues(w, xargs, i);
X#	undef		NXARGS
X}
SHAR_EOF
fi
exit 0
#	End of shell archive
-- 
Rick Richardson | Looking for FAX software for UNIX/386 ??? Ask About: |Mention
PC Research,Inc.| FaxiX - UNIX Facsimile System (tm)                   |FAX# for
uunet!pcrat!rick| FaxJet - HP LJ PCL to FAX (Send WP,Word,Pagemaker...)|Sample
(201) 389-8963  | JetRoff - troff postprocessor for HP LaserJet and FAX|Output