[comp.windows.x.motif] Aligning side-by-side RowColumn widgets

zjmw36@trc.amoco.com (Joe M. Wade) (01/10/91)

O.K., I admit defeat. I have been trying for much too long to get
fields in two side-by-side rowcolumn widgets inside a form dialog
to line up. What I'm trying to do is this:

label1     text
label2     text
label3     text
label4     text
label5     toggle
etc..

The problem arises from the fact that the text widgets are larger than
the label widgets. Using ATTACH_OPPOSITE_WIDGET on rowcol1 and rowcol2
didn't work appropriately, so I tried a new tack by computing the y
offset of each label in rowcol1 based on the size of its corresponding
entry in rowcol2. This works when packing is set to PACK_NONE, but I
would like my labels to be on the right hand side of rowcol1. Using
XmPACK_TIGHT breaks my horizontal layout even though the documentation
I have says, "Each entry's position in the major dimension is left 
unaltered (for example, XmNy is left unchanged when XmNorientation is
XmVertical); its position in the minor dimension is set to the same value
as the greatest entry in that particular row or column.

Am I missing something obvious? Below is a test program which I've been
using to work on this problem. Is this just a bug in RowColumn or am
I breaking (misinterpreting?) the rules ? Any help is more than 
appreciated. I may be willing to give up any future first-born male
children......

Try changing the packing between XmPACK_TIGHT and XmPACK_NONE and you'll
see my dilemma.

******** Warning: buggy code follows.....  **************************

#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <Xm/PushB.h>
#include <Xm/ToggleB.h>
#include <Xm/Text.h>
#include <Xm/Label.h>
#include <Xm/Form.h>
#include <Xm/RowColumn.h>

char *labels[] = { "labelA","labelB","labelC","labelD",
			"labelE - with this extra garbage" };
char *text[] = { "entryA","entryB","entryC","entryD" };

void popup(widget,client_data,call_data)
Widget widget;
caddr_t client_data;
caddr_t call_data;
{
	XtManageChild((Widget)client_data);
}
void popdown(widget,client_data,call_data)
Widget widget;
caddr_t client_data;
caddr_t call_data;
{
	XtUnmanageChild((Widget)client_data);
}
void killit(widget,client_data,call_data)
Widget widget;
caddr_t client_data;
caddr_t call_data;
{
	exit(0);
}
main (argc,argv)
int argc;
char *argv[];
{
	Arg args[5];
	Widget root,trigger,dismiss,quit;
	Widget form,rowcol1,rowcol2,label_widget[5],text_widget[4],toggle;
	int i,nargs,spacing,height[5],y_offset;
	XmString item_label;

	root = XtInitialize(NULL, "TEst", NULL, 0, &argc, argv);

	trigger = XmCreatePushButton(root,"trigger",NULL,0);
	XtManageChild(trigger);

	nargs = 0;
	XtSetArg(args[nargs],XmNmappedWhenManaged,FALSE);	nargs++;
	form = XmCreateFormDialog(root,"form",args,nargs);

	XtAddCallback(trigger, XmNactivateCallback, popup, (caddr_t) form);

	nargs = 0;

/* According to documentation, this should work with PACK_TIGHT */
	XtSetArg(args[nargs],XmNpacking,XmPACK_TIGHT);		nargs++;

/* Vertical spacing is correct with PACK_TIGHT; labels get hosed horizontally
	XtSetArg(args[nargs],XmNpacking,XmPACK_NONE);		nargs++;
*/
	XtSetArg(args[nargs],XmNorientation,XmVERTICAL);	nargs++;
	XtSetArg(args[nargs],XmNentryAlignment,XmALIGNMENT_END); nargs++;
	XtSetArg(args[nargs],XmNisAligned,TRUE);		nargs++;
	rowcol1 = XmCreateRowColumn(form,"rowcol1",args,nargs);

	nargs = 0;
	XtSetArg(args[nargs],XmNleftAttachment,XmATTACH_WIDGET); nargs++;
	XtSetArg(args[nargs],XmNleftWidget,rowcol1);		nargs++;
	rowcol2 = XmCreateRowColumn(form,"rowcol1",args,nargs);

	for (i=0; i<4; i++) {
	  nargs = 0;
	  XtSetArg(args[nargs],XmNvalue,text[i]);		nargs++;
	  text_widget[i] = XmCreateText(rowcol2,text[i],args,nargs);
	  XtManageChild(text_widget[i]);
	  }

        nargs = 0;
        item_label = XmStringCreateLtoR("Yes",XmSTRING_DEFAULT_CHARSET);
        XtSetArg(args[nargs],XmNlabelString,item_label);	nargs++;
	XtSetArg(args[nargs],XmNset,TRUE);			nargs++;
	toggle = XmCreateToggleButton(rowcol2,"toggle",args,nargs);
	XtManageChild(toggle);
	XtManageChild(rowcol2);

	nargs = 0;
	XtSetArg(args[nargs],XmNmappedWhenManaged,TRUE);	nargs++;
	XtSetValues(form,args,nargs);

	nargs = 0;
	XtSetArg(args[nargs],XmNspacing,&spacing);		nargs++;
	XtGetValues(rowcol2,args,nargs);

	y_offset = spacing;

	for (i=0; i<4; i++) {
	  nargs = 0;
	  XtSetArg(args[nargs],XmNheight,&height[i]);		nargs++;
	  XtGetValues(text_widget[i],args,nargs);
	  }

	nargs = 0;
	XtSetArg(args[nargs],XmNheight,&height[i]);		nargs++;
	XtGetValues(toggle,args,nargs);

	for (i=0; i<5; i++) {
	  nargs = 0;
	  item_label = XmStringCreateLtoR(labels[i],XmSTRING_DEFAULT_CHARSET);
	  XtSetArg(args[nargs],XmNlabelString,item_label); 	nargs++;
	  XtSetArg(args[nargs],XmNy,y_offset);			nargs++;
	  XtSetArg(args[nargs],XmNheight,height[i]);		nargs++;
	  XtSetArg(args[nargs],XmNborderWidth,1);		nargs++;
	  label_widget[i] = XmCreateLabel(rowcol1,labels[i],args,nargs);
	  XtManageChild(label_widget[i]);
	  y_offset = y_offset + spacing + height[i];
	  }

	XtManageChild(rowcol1);

	nargs = 0;
	XtSetArg(args[nargs],XmNtopAttachment,XmATTACH_WIDGET);	nargs++;
	XtSetArg(args[nargs],XmNtopWidget,rowcol2);		nargs++;
	dismiss = XmCreatePushButton(form,"dismiss",args,nargs);

	XtAddCallback(dismiss, XmNactivateCallback, popdown, (caddr_t) form);
	XtManageChild(dismiss);

	nargs = 0;
	XtSetArg(args[nargs],XmNtopAttachment,XmATTACH_WIDGET);	nargs++;
	XtSetArg(args[nargs],XmNtopWidget,rowcol2);		nargs++;
	XtSetArg(args[nargs],XmNleftAttachment,XmATTACH_WIDGET);	nargs++;
	XtSetArg(args[nargs],XmNleftWidget,dismiss);		nargs++;
	quit = XmCreatePushButton(form,"quit",args,nargs);

	XtAddCallback(quit, XmNactivateCallback, killit, NULL);
	XtManageChild(quit);

	XtRealizeWidget(root);
	XtMainLoop();
}
-- 
*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *
*  Joe M. Wade (jwade@trc.amoco.com)         (918) 660-4387    *
*  Amoco Research Center * 4502 E. 41st St. * Tulsa, OK  74102 *
*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *

gstiehl@convex.com (Greg Stiehl) (01/10/91)

> O.K., I admit defeat. I have been trying for much too long to get
> fields in two side-by-side rowcolumn widgets inside a form dialog
> to line up. What I'm trying to do is this:
> 
> label1     text
> label2     text
> label3     text
> label4     text
> label5     toggle
> etc..

Welcome to the club.  My office mate and I are constantly banging
our heads against this wall.  Although I don't see any feasible way
for two RowColumn widgets to line up elements, it does seem reasonable
to use one RowColumn, set XmNnumColumns = 2 (in this case), and
XmNpacking = XmPACK_TIGHT.

Of course this doesn't work because XmNnumColumns is only meaningful
when XmNpacking is set to XmPACK_COLUMN.  But XmPACK_COLUMN makes
all entries the same size, which is obviously not what you want.

Enough bitching, here are a couple work arounds:

    1. Use a Form.
       a. Connect the top of the first widget in each column
	  to the FORM and subsequent widgets to the previous widget in
	  that column.
       b. Connect the left of each widget in the first column to the FORM.
       c. Connect the right of each widget in the last column to the FORM.
       c. Connect the bottom of each widget to POSITION and set the
	  bottomPosition to I, where I is it's position in the column 
	  (1 = the first element).  Setting XmNfractionBase to the
	  Number of rows.
       d. How you connect the widgets to each other depends on what you
	  want.  The about example would probally want to just attach
	  the text widget to the label widget.
       This is good in that it allows you to leave all the positioning
       up to Motif, but all those attachments can get pretty gross.  It
       is fairly easy to add things to the bottom.  Just remember the last
       row of elements, so attach the new widgets to them.  And increment
       the XmNfractionBase.  It would be a pain to add things in the
       middle.
    2. Use a RowColumn of RowColumns
       This approach uses a lot of widgets, but it makes it easy to
       add things in the middle (as well as the bottom).  On the down
       side, it breaks up the logical grouping of columns of data.
    3. Use a bulletinBoard.
       You basicall have to do all your own placement calculations.  Very
       brute force.  easy to add things at the bottom.  Not a very good
       approach, unless you just can't use any of the above approaches.

I have C source for the first two ways of doing this.  Send me mail if you
want them.  If anyone has a better way, I would be very interested.

-----------
Greg Stiehl (gstiehl@convex.com)
Convex Computer Corporation

baer@adobe.com (Larry Baer) (01/11/91)

Joe M. Wade writes:

   >.... What I'm trying to do is this:
   >
   >label1     text
   >label2     text
   >label3     text
   >label4     text
   >label5     toggle
   >etc..
   >
   >The problem arises from the fact that the text widgets are larger than
   >the label widgets. ...

My approach to this has been to make sure that both RowColumns have
the same margins and spacing, and that the corresponding widgets in each
RowColumn have the same total height, figuring in margins, shadows, fontheight,
etc.  Then let the RowColumns do the positioning by themselves, and everything
lines up.

I've appended below a modified version of Mr. Wade's original program,
together with a couple of choices of resource specifications that give the
desired result.  This appears to work in Motif 1.0 and Motif 1.1.

I use XmPACK_TIGHT on rowcol1, to force all labels to be full-width, so that
entryAlignment of XmALIGNMENT_END is meaningful.

I am interested in hearing criticism of this approach, and other ways of
achieving the effect.

--Larry Baer (baer@adobe.com)
  Adobe Systems Incorporated

==========================Test.c=========================================

#include <Xm/Xm.h>
#include <Xm/Form.h>
#include <Xm/PushB.h>
#include <Xm/ToggleB.h>
#include <Xm/Text.h>
#include <Xm/Label.h>
#include <Xm/Form.h>
#include <Xm/RowColumn.h>

char *labels[] = { "labelA","labelB","labelC","labelD",
			"labelE - with this extra garbage" };
char *text[] = { "entryA","entryB","entryC","entryD" };

void popup(widget,client_data,call_data)
Widget widget;
caddr_t client_data;
caddr_t call_data;
{
	XtManageChild((Widget)client_data);
}
void popdown(widget,client_data,call_data)
Widget widget;
caddr_t client_data;
caddr_t call_data;
{
	XtUnmanageChild((Widget)client_data);
}
void killit(widget,client_data,call_data)
Widget widget;
caddr_t client_data;
caddr_t call_data;
{
	exit(0);
}
main (argc,argv)
int argc;
char *argv[];
{
	Arg args[5];
	Widget root,trigger,dismiss,quit;
	Widget form,rowcol1,rowcol2,label_widget[5],text_widget[4],toggle;
	int i,nargs,spacing,height[5],y_offset;
	XmString item_label;

	root = XtInitialize(NULL, "Test", NULL, 0, &argc, argv);

	trigger = XmCreatePushButton(root,"trigger",NULL,0);
	XtManageChild(trigger);

	nargs = 0;
	XtSetArg(args[nargs],XmNmappedWhenManaged,FALSE);	nargs++;
	form = XmCreateFormDialog(root,"form",args,nargs);

	XtAddCallback(trigger, XmNactivateCallback, popup, (caddr_t) form);

	nargs = 0;

        XtSetArg(args[nargs],XmNpacking, XmPACK_TIGHT); nargs++;

	XtSetArg(args[nargs],XmNorientation,XmVERTICAL);	nargs++;
	XtSetArg(args[nargs],XmNentryAlignment,XmALIGNMENT_END); nargs++;
	XtSetArg(args[nargs],XmNisAligned,TRUE);		nargs++;
	rowcol1 = XmCreateRowColumn(form,"rowcol1",args,nargs);

	nargs = 0;
	XtSetArg(args[nargs],XmNleftAttachment,XmATTACH_WIDGET); nargs++;
	XtSetArg(args[nargs],XmNleftWidget,rowcol1);		nargs++;
	rowcol2 = XmCreateRowColumn(form,"rowcol2",args,nargs);

	for (i=0; i<4; i++) {
	  nargs = 0;
	  XtSetArg(args[nargs],XmNvalue,text[i]);		nargs++;
	  text_widget[i] = XmCreateText(rowcol2,text[i],args,nargs);
	  }
        XtManageChildren(text_widget, 4);

        nargs = 0;
        item_label = XmStringCreateLtoR("Yes",XmSTRING_DEFAULT_CHARSET);
        XtSetArg(args[nargs],XmNlabelString,item_label);	nargs++;
	XtSetArg(args[nargs],XmNset,TRUE);			nargs++;
	toggle = XmCreateToggleButton(rowcol2,"toggle",args,nargs);
	XtManageChild(toggle);
	XtManageChild(rowcol2);

	nargs = 0;
	XtSetArg(args[nargs],XmNmappedWhenManaged,TRUE);	nargs++;
	XtSetValues(form,args,nargs);

	for (i=0; i<5; i++) {
	  nargs = 0;
	  item_label = XmStringCreateLtoR(labels[i],XmSTRING_DEFAULT_CHARSET);
	  XtSetArg(args[nargs],XmNlabelString,item_label); 	nargs++;
	  label_widget[i] = XmCreateLabel(rowcol1,labels[i],args,nargs);
	  }
        XtManageChildren(label_widget, 5);

	XtManageChild(rowcol1);

	nargs = 0;
	XtSetArg(args[nargs],XmNtopAttachment,XmATTACH_WIDGET);	nargs++;
	XtSetArg(args[nargs],XmNtopWidget,rowcol2);		nargs++;
	dismiss = XmCreatePushButton(form,"dismiss",args,nargs);

	XtAddCallback(dismiss, XmNactivateCallback, popdown, (caddr_t) form);
	XtManageChild(dismiss);

	nargs = 0;
	XtSetArg(args[nargs],XmNtopAttachment,XmATTACH_WIDGET);	nargs++;
	XtSetArg(args[nargs],XmNtopWidget,rowcol2);		nargs++;
	XtSetArg(args[nargs],XmNleftAttachment,XmATTACH_WIDGET);	nargs++;
	XtSetArg(args[nargs],XmNleftWidget,dismiss);		nargs++;
	quit = XmCreatePushButton(form,"quit",args,nargs);

	XtAddCallback(quit, XmNactivateCallback, killit, NULL);
	XtManageChild(quit);

	XtRealizeWidget(root);
	XtMainLoop();
}

====================Resource Sample 1====================================
!! Height of XmLabel == fontHeight + 2 * (  borderWidth
!!                                        + highlightThickness
!!                                        + shadowThickness
!!                                        + marginHeight
!!                                       )
!! Height of XmText == fontHeight + 2 * (  borderWidth
!!                                        + highlightThickness
!!                                        + shadowThickness
!!                                        + marginHeight
!!                                       )
!! Height of XmToggle == max(fontHeight, indicatorSize) + 2 * (  borderWidth
!!                                        + highlightThickness
!!                                        + shadowThickness
!!                                        + marginHeight
!!                                       )
Test*traversalOn: true
Test*XmLabel.borderWidth: 0
Test*XmLabel.highlightThickness: 0
Test*XmLabel.shadowThickness: 0
Test*XmLabel.marginHeight: 9

Test*XmToggleButton.borderWidth: 0
Test*XmToggleButton.highlightThickness: 2
Test*XmToggleButton.shadowThickness: 0
Test*XmToggleButton.marginHeight: 7

Test*XmText.borderWidth: 0
Test*XmText.highlightThickness: 2
Test*XmText.shadowThickness: 2
Test*XmText.marginHeight: 5


====================Resource Sample 2====================================
! Labels get big font, texts get smaller font
Test*fontList: fg-22

Test*traversalOn: true
Test*XmLabel.borderWidth: 0
Test*XmLabel.highlightThickness: 0
Test*XmLabel.shadowThickness: 0
Test*XmLabel.marginHeight: 6

Test*XmToggleButton.borderWidth: 0
Test*XmToggleButton.highlightThickness: 2
Test*XmToggleButton.shadowThickness: 0
Test*XmToggleButton.marginHeight: 4

Test*XmText.borderWidth: 0
Test*XmText.highlightThickness: 2
Test*XmText.shadowThickness: 2
Test*XmText.marginHeight: 5
Test*XmText.fontList: fg-16

====================Resource Sample 3====================================
! draw thin boxes around lables
Test*traversalOn: true
Test*XmLabel.borderWidth: 1
Test*XmLabel.highlightThickness: 0
Test*XmLabel.shadowThickness: 0
Test*XmLabel.marginHeight: 8

Test*XmToggleButton.borderWidth: 0
Test*XmToggleButton.highlightThickness: 2
Test*XmToggleButton.shadowThickness: 0
Test*XmToggleButton.marginHeight: 7

Test*XmText.borderWidth: 0
Test*XmText.highlightThickness: 2
Test*XmText.shadowThickness: 2
Test*XmText.marginHeight: 5

====================Resource Sample 4====================================
! Make ALL widgets have a shadow thickness of 2 (including XmLabels and
! XmToggleButtons.  Make ALL widgets have topShadowColor of white and
! bottomShadowColor of black.  With Motif 1.0, XmLabel's shadows are
! invisible, but geometry is correct.  With Motif 1.1, XmLabel's shadows
! are invisible and XmToggleButton appears too large.  I think this is
! a Motif bug.
Test*traversalOn: true
Test*shadowThickness: 2
Test*topShadowColor: white
Test*bottomShadowColor: black

Test*XmLabel.borderWidth: 1
Test*XmLabel.highlightThickness: 0
Test*XmLabel.marginHeight: 8

Test*XmToggleButton.borderWidth: 0
Test*XmToggleButton.highlightThickness: 2
Test*XmToggleButton.marginHeight: 7

Test*XmText.borderWidth: 0
Test*XmText.highlightThickness: 2
Test*XmText.marginHeight: 5

marbru@attc.UUCP (Martin Brunecky) (01/12/91)

In article <1991Jan10.153947.20059@convex.com> gstiehl@convex.com (Greg Stiehl) writes:
>
>> O.K., I admit defeat. I have been trying for much too long to get
>> fields in two side-by-side rowcolumn widgets inside a form dialog
>> to line up. What I'm trying to do is this:
>> 
......
>
>Welcome to the club.  My office mate and I are constantly banging
>our heads against this wall.  Although I don't see any feasible way

   I wrote my WsMatrixBox widget to do this sort of things (and
    many, many many more ). You can just say 2 columns, and it
   will give you ...8 rows, or you can ask for 8 rows and get 2
   columns - or you may let the user resize it and get 4x4 layout.

   I promise I will struggle hard to get permition to make this
   widget public domain, or some kind of Motif contrib. Yes, it is
   fully Motif compliant, you may have even 2 column pulldown full
   of gadgets -).

   In the menatime, you may try to look at Wcl distribution, which
   contains Motifized Tab widget, which will most likely do the job
   as well (I have no experience, using my animal all over the place).

But, at any rate. Welcome to the club.

-- Martin



-- 
=*= Opinions presented here are solely of my own and not those of Auto-trol =*=
Martin Brunecky                           {...}sunpeaks!auto-trol!marbru
(303) 252-2499                        (sometimes also:  marbru@auto-trol.COM )
Auto-trol Technology Corp. 12500 North Washington St., Denver, CO 80241-2404