summaryrefslogtreecommitdiff
path: root/src/Layout.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/Layout.c')
-rw-r--r--src/Layout.c1049
1 files changed, 1049 insertions, 0 deletions
diff --git a/src/Layout.c b/src/Layout.c
new file mode 100644
index 0000000..44d391a
--- /dev/null
+++ b/src/Layout.c
@@ -0,0 +1,1049 @@
+/*
+ * $XConsortium: Layout.c,v 1.1 91/09/13 18:51:44 keith Exp $
+ *
+ * Copyright 1991 Massachusetts Institute of Technology
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. M.I.T. makes no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
+ * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: Keith Packard, MIT X Consortium
+ */
+
+#include <X11/IntrinsicP.h>
+#include <X11/StringDefs.h>
+
+#include <X11/Xmu/Misc.h>
+#include <X11/Xmu/Converters.h>
+
+#ifdef MOTIF
+# include <Xm/XmP.h>
+#endif
+
+#if defined(LAYOUT)
+# include "LayoutP.h"
+#else
+# include <X11/Xaw3d/LayoutP.h>
+#endif
+
+#include <ctype.h>
+#include <stdio.h>
+
+#undef DEBUG
+#ifdef DEBUG
+static char *DBUG_currentproc, *DBUG_lastproc;
+static int DBUG_level = 0;
+# define DBUG_ENTER(s) \
+ {DBUG_lastproc=DBUG_currentproc;DBUG_currentproc=s;\
+ fprintf(stderr,"begin: (%d) %s\n",++DBUG_level,s);}
+# define DBUG_VOID_RETURN \
+ {fprintf(stderr,"end: (%d) %s\n",DBUG_level--,DBUG_currentproc); \
+ DBUG_currentproc=DBUG_lastproc;return;}
+# define DBUG_RETURN(f,v) \
+ {fprintf(stderr,"return (%d) %s (",DBUG_level--,DBUG_currentproc); \
+ fprintf(stderr,(f),(v)); \
+ fprintf(stderr,")\n"); DBUG_currentproc=DBUG_lastproc;return (v);}
+# define DBUG_PRINT(f,s) \
+ {fprintf(stderr," (%d) %s:",DBUG_level, DBUG_currentproc); \
+ fprintf(stderr,f,s);fprintf(stderr,"\n");}
+#else
+# define DBUG_ENTER(s)
+# define DBUG_VOID_RETURN return
+# define DBUG_PRINT(f,s)
+# define DBUG_RETURN(f,v) return(v)
+#endif
+
+/*****************************************************************************
+ *
+ * Full instance record declaration
+ *
+ ****************************************************************************/
+
+#define offset(field) XtOffsetOf(LayoutRec, layout.field)
+
+static XtResource resources[] = {
+ {XtNlayout, XtCLayout, XtRLayout, sizeof (BoxPtr),
+ offset(layout), XtRLayout, NULL },
+ {XtNdebug, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ offset(debug), XtRImmediate, (XtPointer) FALSE},
+};
+
+#undef offset
+
+static void ClassInitialize(), Initialize();
+static void Resize();
+static Boolean SetValues();
+static XtGeometryResult GeometryManager();
+static void ChangeManaged();
+static void InsertChild();
+static XtGeometryResult QueryGeometry ();
+static void GetDesiredSize ();
+#ifdef MOTIF
+static void Redisplay ();
+#endif
+
+static void LayoutLayout ();
+static void LayoutGetNaturalSize ();
+static void LayoutFreeLayout ();
+
+extern void LayYYsetsource(), LayYYsetdest();
+extern int LayYYparse();
+
+#ifdef MOTIF
+#define SuperClass ((ConstraintWidgetClass)&xmManagerClassRec)
+#else
+#define SuperClass ((ConstraintWidgetClass)&constraintClassRec)
+#endif
+
+LayoutClassRec layoutClassRec = {
+ {
+/* core class fields */
+ /* superclass */ (WidgetClass) SuperClass,
+ /* class name */ "Layout",
+ /* size */ sizeof(LayoutRec),
+ /* class_initialize */ ClassInitialize,
+ /* class_part init */ NULL,
+ /* class_inited */ FALSE,
+ /* initialize */ Initialize,
+ /* initialize_hook */ NULL,
+ /* realize */ XtInheritRealize,
+ /* actions */ NULL,
+ /* num_actions */ 0,
+ /* resources */ resources,
+ /* resource_count */ XtNumber(resources),
+ /* xrm_class */ NULLQUARK,
+ /* compress_motion */ FALSE,
+ /* compress_exposure */ 0,
+ /* compress_enterleave*/ FALSE,
+ /* visible_interest */ FALSE,
+ /* destroy */ NULL,
+ /* resize */ Resize,
+#ifdef MOTIF
+ /* expose */ Redisplay,
+#else
+ /* expose */ NULL,
+#endif
+ /* set_values */ SetValues,
+ /* set_values_hook */ NULL,
+ /* set_values_almost */ XtInheritSetValuesAlmost,
+ /* get_values_hook */ NULL,
+ /* accept_focus */ NULL,
+ /* version */ XtVersion,
+ /* callback_private */ NULL,
+#ifdef MOTIF
+ /* tm_table */ XtInheritTranslations,
+#else
+ /* tm_table */ NULL,
+#endif
+ /* query_geometry */ QueryGeometry,
+ /* display_accelerator*/ XtInheritDisplayAccelerator,
+ /* extension */ NULL
+ }, {
+/* composite class fields */
+ /* geometry_manager */ GeometryManager,
+ /* change_managed */ ChangeManaged,
+ /* insert_child */ InsertChild,
+ /* delete_child */ XtInheritDeleteChild,
+ /* extension */ NULL
+ }, {
+/* constraint class fields */
+ /* subresources */ NULL,
+ /* subresource_count */ 0,
+ /* constraint_size */ sizeof(LayoutConstraintsRec),
+ /* initialize */ NULL,
+ /* destroy */ NULL,
+ /* set_values */ NULL,
+ /* extension */ NULL
+ },
+#ifdef MOTIF
+ {
+ /* manager class */
+ XtInheritTranslations, /* translations */
+ NULL, /* syn resources */
+ 0, /* num syn_resources */
+ NULL, /* get_cont_resources */
+ 0, /* num_get_cont_resources */
+ XmInheritParentProcess, /* parent_process */
+ NULL, /* extension */
+ },
+#endif
+ { /* layout_class fields */
+ 0
+ }
+};
+
+WidgetClass layoutWidgetClass = (WidgetClass) &layoutClassRec;
+
+#define ForAllChildren(pw, childP) \
+ for ( (childP) = (pw)->composite.children ; \
+ (childP) < (pw)->composite.children + (pw)->composite.num_children ; \
+ (childP)++ ) if (!XtIsManaged(*childP)) ; else
+
+/************************************************************
+ *
+ * Semi-public routines.
+ *
+ ************************************************************/
+
+/* Function Name: ClassInitialize
+ * Description: The Layout widgets class initialization proc.
+ * Arguments: none.
+ * Returns: none.
+ */
+
+/*ARGSUSED*/
+static Boolean
+CvtStringToLayout (dpy, args, num_args, from, to, converter_data)
+ Display *dpy;
+ XrmValue *args;
+ Cardinal *num_args;
+ XrmValue *from, *to;
+ XtPointer *converter_data;
+{
+ static BoxPtr tmp;
+
+ LayYYsetsource ((char *) from->addr);
+ if (!to->addr) to->addr = (XtPointer)&tmp;
+ LayYYsetdest ((BoxPtr *) to->addr);
+ to->size = sizeof (BoxPtr *);
+ return LayYYparse() ? FALSE : TRUE;
+}
+
+/*ARGSUSED*/
+static void
+DisposeLayout (app, to, data, args, num_args)
+ XtAppContext app;
+ XrmValue *to;
+ XtPointer data;
+ XrmValuePtr args;
+ Cardinal *num_args;
+{
+ LayoutFreeLayout (* (LayoutPtr *) to->addr);
+}
+
+static void
+ClassInitialize()
+{
+ XtSetTypeConverter ( XtRString, XtRLayout, CvtStringToLayout,
+ (XtConvertArgList)NULL, (Cardinal)0, XtCacheNone,
+ DisposeLayout );
+}
+
+#ifdef MOTIF
+static void Redisplay ( gw, event, region )
+Widget gw;
+XEvent *event;
+Region region;
+{
+ /*
+ * If the Layout widget is visible, redraw gadgets.
+ */
+
+ if ( XtIsRealized ( gw ) && gw->core.visible )
+ {
+ _XmRedisplayGadgets ( gw, event, region );
+ }
+ /* ChangeManaged(gw);*/
+}
+#endif
+
+/*ARGSUSED*/
+static XtGeometryResult GeometryManager(child, request, reply)
+ Widget child;
+ XtWidgetGeometry *request, *reply;
+{
+ LayoutWidget w = (LayoutWidget) XtParent(child);
+ SubInfoPtr p = SubInfo(child);
+ int bw;
+ Bool changed, bwChanged;
+
+ bw = p->naturalBw;
+ changed = FALSE;
+ bwChanged = FALSE;
+ if (request->request_mode & CWBorderWidth &&
+ request->border_width != child->core.border_width)
+ {
+ p->naturalBw = bw;
+ bw = request->border_width;
+ changed = TRUE;
+ bwChanged = TRUE;
+ }
+ if (bwChanged || ((request->request_mode & CWWidth) &&
+ request->width != child->core.width))
+ {
+ p->naturalSize[LayoutHorizontal] = request->width + bw * 2;
+ changed = TRUE;
+ }
+ if (bwChanged || ((request->request_mode & CWHeight) &&
+ request->height != child->core.height))
+ {
+ p->naturalSize[LayoutVertical] = request->height + bw * 2;
+ changed = TRUE;
+ }
+ if (changed)
+ LayoutLayout (w, TRUE);
+ return XtGeometryDone;
+}
+
+/* ARGSUSED */
+static void Initialize(request, new, args, num_args)
+Widget request, new;
+ArgList args;
+Cardinal *num_args;
+{
+/* LayoutWidget w = (LayoutWidget)new; */
+}
+
+static void ChangeManaged(gw)
+ Widget gw;
+{
+ LayoutWidget w = (LayoutWidget) gw;
+ Widget *children;
+
+ DBUG_ENTER("changeManaged");
+
+ ForAllChildren (w, children)
+ GetDesiredSize (*children);
+ LayoutLayout ((LayoutWidget) w, TRUE);
+#ifdef MOTIF
+ _XmNavigChangeManaged ( gw );
+#endif
+ DBUG_VOID_RETURN;
+}
+
+static void
+GetDesiredSize (child)
+ Widget child;
+{
+ XtWidgetGeometry desired;
+ SubInfoPtr p;
+
+ XtQueryGeometry (child, (XtWidgetGeometry *) NULL, &desired);
+ p = SubInfo (child);
+ p->naturalBw = desired.border_width;
+ p->naturalSize[LayoutHorizontal] = desired.width + desired.border_width * 2;
+ p->naturalSize[LayoutVertical] = desired.height + desired.border_width * 2;
+}
+
+static void InsertChild (child)
+ Widget child;
+{
+ (*SuperClass->composite_class.insert_child) (child);
+ GetDesiredSize (child);
+}
+
+static void
+Resize(gw)
+ Widget gw;
+{
+ LayoutLayout ((LayoutWidget) gw, FALSE);
+}
+
+/* ARGSUSED */
+static Boolean
+SetValues(gold, greq, gnew, args, num_args)
+ Widget gold, greq, gnew;
+ ArgList args;
+ Cardinal *num_args;
+{
+ LayoutWidget old = (LayoutWidget) gold,
+ new = (LayoutWidget) gnew;
+
+ if (old->layout.layout != new->layout.layout)
+ LayoutLayout (new, TRUE);
+ return FALSE;
+} /* SetValues */
+
+static XtGeometryResult
+QueryGeometry (gw, request, prefered_return)
+ Widget gw;
+ XtWidgetGeometry *request, *prefered_return;
+{
+ LayoutWidget w = (LayoutWidget) gw;
+ XtGeometryResult result;
+ XtWidgetGeometry prefered_size;
+
+ if (request && !(request->request_mode & (CWWidth|CWHeight)))
+ return XtGeometryYes;
+ LayoutGetNaturalSize (w, &prefered_size.width, &prefered_size.height);
+ prefered_return->request_mode = 0;
+ result = XtGeometryYes;
+ if (!request) {
+ prefered_return->width = prefered_size.width;
+ prefered_return->height= prefered_size.height;
+ if (prefered_size.width != w->core.width) {
+ prefered_return->request_mode |= CWWidth;
+ result = XtGeometryAlmost;
+ }
+ if (prefered_size.height != w->core.height) {
+ prefered_return->request_mode |= CWHeight;
+ result = XtGeometryAlmost;
+ }
+ } else {
+ if (request->request_mode & CWWidth) {
+ if (prefered_size.width > request->width)
+ {
+ if (prefered_size.width == w->core.width)
+ result = XtGeometryNo;
+ else if (result != XtGeometryNo) {
+ result = XtGeometryAlmost;
+ prefered_return->request_mode |= CWWidth;
+ prefered_return->width = prefered_size.width;
+ }
+ }
+ }
+ if (request->request_mode & CWHeight) {
+ if (prefered_size.height > request->height)
+ {
+ if (prefered_size.height == w->core.height)
+ result = XtGeometryNo;
+ else if (result != XtGeometryNo) {
+ result = XtGeometryAlmost;
+ prefered_return->request_mode |= CWHeight;
+ prefered_return->height = prefered_size.height;
+ }
+ }
+ }
+ }
+ return result;
+}
+
+/*
+ * Layout section. Exports LayoutGetNaturalSize and
+ * LayoutLayout to above section
+ */
+
+static void
+PrintGlue (g)
+ GlueRec g;
+{
+ if (g.order == 0 || g.value != 1.0)
+ (void) printf ("%g", g.value);
+ if (g.order > 0)
+ {
+ (void) printf ("%s", " inf");
+ if (g.order > 1)
+ (void) printf (" %d", g.order);
+ }
+}
+
+static void
+PrintDirection (dir)
+ LayoutDirection dir;
+{
+ switch (dir) {
+ case LayoutHorizontal:
+ (void) printf ("%s", "horizontal");
+ break;
+ case LayoutVertical:
+ (void) printf ("%s", "vertical");
+ break;
+ default:
+ (void) printf ("Unknown layout direction %d\n", dir);
+ break;
+
+ }
+}
+
+static void
+TabTo(level)
+ int level;
+{
+ while (level--)
+ (void) printf ("%s", " ");
+}
+
+static void
+PrintBox (box, level)
+ BoxPtr box;
+ int level;
+{
+ BoxPtr child;
+
+ TabTo (level);
+ (void) printf ("%s", "< ");
+ (void) printf ("%s", " + ");
+ PrintGlue (box->params.stretch[LayoutHorizontal]);
+ (void) printf ("%s", " - ");
+ PrintGlue (box->params.shrink[LayoutHorizontal]);
+ (void) printf ("%s", " * ");
+ (void) printf ("%s", " + ");
+ PrintGlue (box->params.stretch[LayoutVertical]);
+ (void) printf ("%s", " - ");
+ PrintGlue (box->params.shrink[LayoutVertical]);
+ (void) printf ("%s", " >");
+ (void) printf (" size: %d x %d", box->size[0], box->size[1]);
+ (void) printf (" natural: %d x %d ", box->natural[0], box->natural[1]);
+ switch (box->type) {
+ case BoxBox:
+ PrintDirection (box->u.box.dir);
+ (void) printf ("%s\n", "");
+ for (child = box->u.box.firstChild; child; child = child->nextSibling)
+ PrintBox (child, level+1);
+ break;
+ case WidgetBox:
+ (void) printf (" %s\n", XrmQuarkToString (box->u.widget.quark));
+ break;
+ case GlueBox:
+ (void) printf ("%s\n", " glue");
+ break;
+ case VariableBox:
+ (void) printf (" variable %s\n", XrmQuarkToString (box->u.variable.quark));
+ break;
+ }
+}
+
+static ExprPtr
+LookupVariable (child, quark)
+ BoxPtr child;
+ XrmQuark quark;
+{
+ BoxPtr parent, box;
+
+ DBUG_ENTER("LookupVariable");
+ DBUG_PRINT("name = <%s>",XrmQuarkToString(quark));
+ DBUG_PRINT("child = %p",child);
+ while ((parent = child->parent))
+ {
+ for (box = parent->u.box.firstChild;
+ box != child;
+ box = box->nextSibling)
+ {
+ if (box->type == VariableBox && box->u.variable.quark == quark)
+ DBUG_RETURN("%p", box->u.variable.expr);
+ }
+ child = parent;
+ }
+ DBUG_RETURN("failure -> %d",0);
+}
+
+static double
+Evaluate (l, box, expr, natural)
+ LayoutWidget l;
+ BoxPtr box;
+ ExprPtr expr;
+ double natural;
+{
+ double left, right, down;
+ Widget widget;
+ SubInfoPtr info;
+
+ DBUG_PRINT("Evaluate %d", expr->type);
+ switch (expr->type) {
+ case Constant:
+ return expr->u.constant;
+ case Binary:
+ left = Evaluate (l, box, expr->u.binary.left, natural);
+ right = Evaluate (l, box, expr->u.binary.right, natural);
+ switch (expr->u.binary.op) {
+ case Plus:
+ return left + right;
+ case Minus:
+ return left - right;
+ case Times:
+ return left * right;
+ case Divide:
+ return left / right;
+ case Percent:
+ return right * left / 100.0;
+ }
+ case Unary:
+ down = Evaluate (l, box, expr->u.unary.down, natural);
+ switch (expr->u.unary.op) {
+ case Percent:
+ return natural * down / 100.0;
+ case Minus:
+ return -down;
+ case Plus:
+ case Times:
+ case Divide:
+ break;
+ }
+ case Width:
+ widget = QuarkToWidget (l, expr->u.width);
+ if (!widget)
+ return 0;
+ info = SubInfo (widget);
+ return info->naturalSize[LayoutHorizontal];
+ case Height:
+ widget = QuarkToWidget (l, expr->u.height);
+ if (!widget)
+ return 0;
+ info = SubInfo (widget);
+ return info->naturalSize[LayoutVertical];
+ case Variable:
+ {
+ /* in the original code there was no nexpr,
+ expr was overwritten by LookupVariable and
+ the expression "expr->u.variable" to obtain the
+ variable name for the errormessage cause a segmentation
+ violation */
+ ExprPtr nexpr;
+ nexpr = LookupVariable (box, expr->u.variable);
+ if (!nexpr)
+ {
+ char buf[256];
+ (void) sprintf (buf, "Layout: undefined variable %s\n",
+ XrmQuarkToString (expr->u.variable));
+ XtError (buf);
+ return 0.0;
+ }
+ return Evaluate (l, box, nexpr, natural);
+ }
+ }
+ return 0.0;
+}
+
+static void
+DisposeExpr (expr)
+ ExprPtr expr;
+{
+ if (!expr)
+ return;
+ switch (expr->type) {
+ case Constant:
+ break;
+ case Binary:
+ DisposeExpr (expr->u.binary.left);
+ DisposeExpr (expr->u.binary.right);
+ break;
+ case Unary:
+ DisposeExpr (expr->u.unary.down);
+ break;
+ case Width:
+ case Height:
+ case Variable:
+ break;
+ }
+ Dispose (expr);
+}
+
+#define CheckGlue(l, box, glue, n) { \
+ if (glue.expr) \
+ glue.value = Evaluate (l, box, glue.expr, n); \
+ if (glue.order == 0 && glue.value == 0) \
+ glue.order = -1; \
+ else if (glue.order == -1 && glue.value != 0) \
+ glue.order = 0; \
+}
+
+#define DoStretch(l, box, dir) \
+ CheckGlue (l, box, box->params.stretch[dir], (double) box->natural[dir]);
+
+#define DoShrink(l, box, dir) \
+ CheckGlue (l, box, box->params.shrink[dir], (double) box->natural[dir])
+
+/* compute the natural sizes of a box */
+static void
+ComputeNaturalSizes (l, box, dir)
+ LayoutWidget l;
+ BoxPtr box;
+ LayoutDirection dir;
+{
+ BoxPtr child;
+ Widget w;
+ SubInfoPtr info;
+ int minStretchOrder, minShrinkOrder;
+ LayoutDirection thisDir;
+
+ DBUG_ENTER("ComputeNaturalSizes");
+ DBUG_PRINT("box->type=%d",box->type);
+ switch (box->type) {
+ case WidgetBox:
+ w = box->u.widget.widget = QuarkToWidget (l, box->u.widget.quark);
+ if (!w)
+ {
+ box->natural[LayoutHorizontal] = 0;
+ box->natural[LayoutVertical] = 0;
+ }
+ else
+ {
+ info = SubInfo (w);
+ box->natural[LayoutHorizontal] = info->naturalSize[LayoutHorizontal];
+ box->natural[LayoutVertical] = info->naturalSize[LayoutVertical];
+ }
+ DoStretch (l, box, dir);
+ DoShrink (l, box, dir);
+ DoStretch (l, box, !dir);
+ DoShrink (l, box, !dir);
+ break;
+ case GlueBox:
+ box->natural[dir] = Evaluate (l, box, box->u.glue.expr, 0.0);
+ box->natural[!dir] = 0;
+ DoStretch (l, box, dir);
+ DoShrink (l, box, dir);
+ break;
+ case BoxBox:
+ thisDir = box->u.box.dir;
+ box->natural[0] = 0;
+ box->natural[1] = 0;
+ minStretchOrder = 100000;
+ minShrinkOrder = 100000;
+ ZeroGlue (box->params.shrink[thisDir]);
+ ZeroGlue (box->params.stretch[thisDir]);
+ box->params.shrink[!thisDir].order = 100000;
+ box->params.stretch[!thisDir].order = 100000;
+ for (child = box->u.box.firstChild; child; child = child->nextSibling)
+ {
+ ComputeNaturalSizes (l, child, thisDir);
+ /*
+ * along box axis:
+ * normal size += child normal size
+ * shrink += child shrink
+ * stretch += child stretch
+ */
+ box->natural[thisDir] += child->natural[thisDir];
+ AddGlue (box->params.shrink[thisDir],
+ box->params.shrink[thisDir],
+ child->params.shrink[thisDir]);
+ AddGlue (box->params.stretch[thisDir],
+ box->params.stretch[thisDir],
+ child->params.stretch[thisDir]);
+ /*
+ * normal to box axis:
+ * normal size = maximum child normal size of minimum shrink order
+ * shrink = difference between normal size and minimum shrink
+ * stretch = minimum child stretch
+ */
+ if (box->natural[!thisDir] >= child->natural[!thisDir])
+ {
+ if (child->params.stretch[!thisDir].order < minShrinkOrder)
+ {
+ box->natural[!thisDir] = child->natural[!thisDir];
+ minStretchOrder = child->params.stretch[!thisDir].order;
+ if (child->params.shrink[!thisDir].order < minShrinkOrder)
+ minShrinkOrder = child->params.shrink[!thisDir].order;
+ }
+ }
+ else
+ {
+ if (child->params.shrink[!thisDir].order <= minStretchOrder)
+ {
+ box->natural[!thisDir] = child->natural[!thisDir];
+ minShrinkOrder = child->params.shrink[!thisDir].order;
+ if (child->params.stretch[!thisDir].order < minStretchOrder)
+ minStretchOrder = child->params.stretch[!thisDir].order;
+ }
+ }
+ MinGlue (box->params.stretch[!thisDir],
+ box->params.stretch[!thisDir],
+ child->params.stretch[!thisDir]);
+ MinGlue (box->params.shrink[!thisDir],
+ box->params.shrink[!thisDir],
+ child->params.shrink[!thisDir]);
+ }
+ if (box->params.shrink[!thisDir].order <= 0)
+ {
+ int minSize;
+ int largestMinSize;
+
+ largestMinSize = 0;
+ for (child = box->u.box.firstChild; child; child = child->nextSibling)
+ {
+ if (child->params.shrink[!thisDir].order <= 0)
+ {
+ minSize = child->natural[!thisDir] -
+ child->params.shrink[!thisDir].value;
+ if (minSize > largestMinSize)
+ largestMinSize = minSize;
+ }
+ }
+ box->params.shrink[!thisDir].value = box->natural[!thisDir] -
+ largestMinSize;
+ if (box->params.shrink[!thisDir].value == 0)
+ box->params.shrink[!thisDir].order = -1;
+ else
+ box->params.shrink[!thisDir].order = 0;
+ }
+ break;
+ case VariableBox:
+ break;
+ }
+ DBUG_VOID_RETURN;
+}
+
+/* given the boxs geometry, set the geometry of the pieces */
+
+#define GluePart(a,b,dist) ((a) ? ((int) (((a) * (dist)) / (b) + \
+ ((dist >= 0) ? 0.5 : -0.5))) : 0)
+
+static Bool
+ComputeSizes (box)
+ BoxPtr box;
+{
+ LayoutDirection dir;
+ BoxPtr child;
+ GlueRec stretch;
+ GlueRec shrink;
+ GlueRec totalGlue[2];
+ double remainingGlue;
+ GluePtr glue;
+ int size;
+ int totalSizes;
+ int totalChange[2];
+ int change;
+ int remainingChange;
+ Bool shrinking;
+ Bool happy;
+ int i;
+ int maxGlue;
+
+ dir = box->u.box.dir;
+ size = box->size[dir];
+
+ stretch = box->params.stretch[dir];
+ shrink = box->params.shrink[dir];
+
+ /* pick the correct adjustment parameters based on the change direction */
+
+ totalChange[0] = size - box->natural[dir];
+
+ shrinking = totalChange[0] < 0;
+
+ totalChange[1] = 0;
+ totalGlue[1].order = 100000;
+ totalGlue[1].value = 0;
+ maxGlue = 1;
+ if (shrinking)
+ {
+ totalGlue[0] = shrink;
+ /* for first-order infinites, shrink it to zero and then
+ * shrink the zero-orders
+ */
+ if (shrink.order == 1) {
+ totalSizes = 0;
+ remainingGlue = 0;
+ for (child = box->u.box.firstChild;
+ child;
+ child = child->nextSibling)
+ {
+ switch (child->params.shrink[dir].order) {
+ case 0:
+ remainingGlue += child->params.shrink[dir].value;
+ break;
+ case 1:
+ totalSizes += child->natural[dir];
+ break;
+ }
+ }
+ if (totalSizes < -totalChange[0])
+ {
+ totalGlue[1] = shrink;
+ totalGlue[0].order = 0;
+ totalGlue[0].value = remainingGlue;
+ totalChange[1] = -totalSizes;
+ totalChange[0] = totalChange[0] - totalChange[1];
+ maxGlue = 2;
+ }
+ }
+ if (totalGlue[0].order <= 0 &&
+ totalChange[0] > totalGlue[0].value)
+ {
+ totalChange[0] = totalGlue[0].value;
+ }
+ }
+ else
+ totalGlue[0] = stretch;
+
+ /* adjust each box */
+ totalSizes = 0;
+ remainingGlue = totalGlue[0].value + totalGlue[1].value;
+ remainingChange = totalChange[0] + totalChange[1];
+ happy = True;
+ for (child = box->u.box.firstChild; child; child = child->nextSibling)
+ {
+ /* never add glue or stretch to a VariableBox! */
+ if (child->type == VariableBox) continue;
+
+ if (shrinking)
+ glue = &child->params.shrink[dir];
+ else
+ glue = &child->params.stretch[dir];
+
+ child->size[dir] = child->natural[dir];
+ for (i = 0; i < maxGlue; i++)
+ {
+ if (glue->order == totalGlue[i].order)
+ {
+ remainingGlue -= glue->value;
+ if (remainingGlue <= 0)
+ change = remainingChange;
+ else
+ change = GluePart (glue->value,
+ totalGlue[i].value,
+ totalChange[i]);
+ child->size[dir] += change;
+ remainingChange -= change;
+ }
+ }
+ child->size[!dir] = box->size[!dir];
+ totalSizes += child->size[dir];
+ if (child->type == BoxBox)
+ if (!ComputeSizes (child))
+ happy = False;
+ }
+ return totalSizes == box->size[dir] && happy;
+}
+
+static void
+SetSizes (box, x, y)
+ BoxPtr box;
+ Position x, y;
+{
+ BoxPtr child;
+ int width, height;
+ int bw;
+ Widget w;
+ SubInfoPtr info;
+
+ switch (box->type) {
+ case WidgetBox:
+ w = box->u.widget.widget;
+ if (w)
+ {
+ info = SubInfo(w);
+ /* info = (SubInfoPtr) w->core.constraints; */
+ width = box->size[LayoutHorizontal];
+ height = box->size[LayoutVertical];
+ bw = info->naturalBw;
+ width -= bw * 2;
+ height -= bw * 2;
+ /* Widgets which grow too small are placed off screen */
+ if (width <= 0 || height <= 0)
+ {
+ width = 1;
+ height = 1;
+ bw = 0;
+ x = -1;
+ y = -1;
+ }
+ XtConfigureWidget (w, x, y,
+ (Dimension)width, (Dimension)height,
+ (Dimension)bw);
+ }
+ break;
+ case BoxBox:
+ for (child = box->u.box.firstChild; child; child = child->nextSibling)
+ {
+ SetSizes (child, x, y);
+ if (box->u.box.dir == LayoutHorizontal)
+ x += child->size[LayoutHorizontal];
+ else
+ y += child->size[LayoutVertical];
+ }
+ break;
+ case GlueBox:
+ case VariableBox:
+ break;
+ }
+}
+
+static void
+LayoutFreeLayout (box)
+ BoxPtr box;
+{
+ BoxPtr child, next;
+
+ switch (box->type) {
+ case BoxBox:
+ for (child = box->u.box.firstChild; child; child = next)
+ {
+ next = child->nextSibling;
+ LayoutFreeLayout (child);
+ }
+ break;
+ case GlueBox:
+ DisposeExpr (box->u.glue.expr);
+ break;
+ case WidgetBox:
+ case VariableBox:
+ default:
+ break;
+ }
+ DisposeExpr (box->params.stretch[LayoutHorizontal].expr);
+ DisposeExpr (box->params.shrink[LayoutHorizontal].expr);
+ DisposeExpr (box->params.stretch[LayoutVertical].expr);
+ DisposeExpr (box->params.shrink[LayoutVertical].expr);
+ Dispose (box);
+}
+
+
+static void
+LayoutGetNaturalSize (l, widthp, heightp)
+ LayoutWidget l;
+ Dimension *widthp, *heightp;
+{
+ BoxPtr box;
+
+ DBUG_ENTER("LayoutGetNaturalSize");
+ box = l->layout.layout;
+ if (box)
+ {
+ ComputeNaturalSizes (l, box, LayoutHorizontal);
+ *widthp = box->natural[LayoutHorizontal];
+ *heightp = box->natural[LayoutVertical];
+ }
+ else
+ {
+ *widthp = 0;
+ *heightp = 0;
+ }
+ DBUG_VOID_RETURN;
+}
+
+static void
+LayoutLayout (l, attemptResize)
+ LayoutWidget l;
+ Bool attemptResize;
+{
+ BoxPtr box;
+ Dimension width, height;
+ Dimension prefered_width, prefered_height;
+
+ DBUG_ENTER("LayoutLayout");
+ box = l->layout.layout;
+ if (!box)
+ return;
+ LayoutGetNaturalSize (l, &prefered_width, &prefered_height);
+ if (l->core.width == 0 || l->core.height == 0)
+ {
+ l->core.width = prefered_width;
+ l->core.height = prefered_height;
+ }
+ box->size[LayoutHorizontal] = l->core.width;
+ box->size[LayoutVertical] = l->core.height;
+ if (!ComputeSizes (box) && attemptResize)
+ {
+ XtMakeResizeRequest ((Widget) l,
+ prefered_width, prefered_height,
+ &width, &height);
+ if (width != box->size[LayoutHorizontal] ||
+ height != box->size[LayoutVertical])
+ {
+ box->size[LayoutHorizontal] = width;
+ box->size[LayoutVertical] = height;
+ ComputeSizes (box);
+ }
+ }
+ if (l->layout.debug)
+ {
+ PrintBox (box, 0);
+ fflush (stdout);
+ }
+ SetSizes (box, 0, 0);
+ DBUG_VOID_RETURN;
+}
+