diff options
Diffstat (limited to 'src/Layout.c')
-rw-r--r-- | src/Layout.c | 1049 |
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; +} + |