00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <X11/IntrinsicP.h>
00027 #include <X11/StringDefs.h>
00028
00029 #include <X11/Xmu/Misc.h>
00030 #include <X11/Xmu/Converters.h>
00031
00032 #ifdef MOTIF
00033 # include <Xm/XmP.h>
00034 #endif
00035
00036 #if defined(LAYOUT)
00037 # include "LayoutP.h"
00038 #else
00039 # include <X11/Xaw3d/LayoutP.h>
00040 #endif
00041
00042 #include <ctype.h>
00043 #include <stdio.h>
00044
00045 #undef DEBUG
00046 #ifdef DEBUG
00047 static char *DBUG_currentproc, *DBUG_lastproc;
00048 static int DBUG_level = 0;
00049 # define DBUG_ENTER(s) \
00050 {DBUG_lastproc=DBUG_currentproc;DBUG_currentproc=s;\
00051 fprintf(stderr,"begin: (%d) %s\n",++DBUG_level,s);}
00052 # define DBUG_VOID_RETURN \
00053 {fprintf(stderr,"end: (%d) %s\n",DBUG_level--,DBUG_currentproc); \
00054 DBUG_currentproc=DBUG_lastproc;return;}
00055 # define DBUG_RETURN(f,v) \
00056 {fprintf(stderr,"return (%d) %s (",DBUG_level--,DBUG_currentproc); \
00057 fprintf(stderr,(f),(v)); \
00058 fprintf(stderr,")\n"); DBUG_currentproc=DBUG_lastproc;return (v);}
00059 # define DBUG_PRINT(f,s) \
00060 {fprintf(stderr," (%d) %s:",DBUG_level, DBUG_currentproc); \
00061 fprintf(stderr,f,s);fprintf(stderr,"\n");}
00062 #else
00063 # define DBUG_ENTER(s)
00064 # define DBUG_VOID_RETURN return
00065 # define DBUG_PRINT(f,s)
00066 # define DBUG_RETURN(f,v) return(v)
00067 #endif
00068
00069
00070
00071
00072
00073
00074
00075 #define offset(field) XtOffsetOf(LayoutRec, layout.field)
00076
00077 static XtResource resources[] = {
00078 {XtNlayout, XtCLayout, XtRLayout, sizeof (BoxPtr),
00079 offset(layout), XtRLayout, NULL },
00080 {XtNdebug, XtCBoolean, XtRBoolean, sizeof(Boolean),
00081 offset(debug), XtRImmediate, (XtPointer) FALSE},
00082 };
00083
00084 #undef offset
00085
00086 static void ClassInitialize(), Initialize();
00087 static void Resize();
00088 static Boolean SetValues();
00089 static XtGeometryResult GeometryManager();
00090 static void ChangeManaged();
00091 static void InsertChild();
00092 static XtGeometryResult QueryGeometry ();
00093 static void GetDesiredSize ();
00094 #ifdef MOTIF
00095 static void Redisplay ();
00096 #endif
00097
00098 static void LayoutLayout ();
00099 static void LayoutGetNaturalSize ();
00100 static void LayoutFreeLayout ();
00101
00102 extern void LayYYsetsource(), LayYYsetdest();
00103 extern int LayYYparse();
00104
00105 #ifdef MOTIF
00106 #define SuperClass ((ConstraintWidgetClass)&xmManagerClassRec)
00107 #else
00108 #define SuperClass ((ConstraintWidgetClass)&constraintClassRec)
00109 #endif
00110
00111 LayoutClassRec layoutClassRec = {
00112 {
00113
00114 (WidgetClass) SuperClass,
00115 "Layout",
00116 sizeof(LayoutRec),
00117 ClassInitialize,
00118 NULL,
00119 FALSE,
00120 Initialize,
00121 NULL,
00122 XtInheritRealize,
00123 NULL,
00124 0,
00125 resources,
00126 XtNumber(resources),
00127 NULLQUARK,
00128 FALSE,
00129 0,
00130 FALSE,
00131 FALSE,
00132 NULL,
00133 Resize,
00134 #ifdef MOTIF
00135 Redisplay,
00136 #else
00137 NULL,
00138 #endif
00139 SetValues,
00140 NULL,
00141 XtInheritSetValuesAlmost,
00142 NULL,
00143 NULL,
00144 XtVersion,
00145 NULL,
00146 #ifdef MOTIF
00147 XtInheritTranslations,
00148 #else
00149 NULL,
00150 #endif
00151 QueryGeometry,
00152 XtInheritDisplayAccelerator,
00153 NULL
00154 }, {
00155
00156 GeometryManager,
00157 ChangeManaged,
00158 InsertChild,
00159 XtInheritDeleteChild,
00160 NULL
00161 }, {
00162
00163 NULL,
00164 0,
00165 sizeof(LayoutConstraintsRec),
00166 NULL,
00167 NULL,
00168 NULL,
00169 NULL
00170 },
00171 #ifdef MOTIF
00172 {
00173
00174 XtInheritTranslations,
00175 NULL,
00176 0,
00177 NULL,
00178 0,
00179 XmInheritParentProcess,
00180 NULL,
00181 },
00182 #endif
00183 {
00184 0
00185 }
00186 };
00187
00188 WidgetClass layoutWidgetClass = (WidgetClass) &layoutClassRec;
00189
00190 #define ForAllChildren(pw, childP) \
00191 for ( (childP) = (pw)->composite.children ; \
00192 (childP) < (pw)->composite.children + (pw)->composite.num_children ; \
00193 (childP)++ ) if (!XtIsManaged(*childP)) ; else
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208 static Boolean
00209 CvtStringToLayout (dpy, args, num_args, from, to, converter_data)
00210 Display *dpy;
00211 XrmValue *args;
00212 Cardinal *num_args;
00213 XrmValue *from, *to;
00214 XtPointer *converter_data;
00215 {
00216 static BoxPtr tmp;
00217
00218 LayYYsetsource ((char *) from->addr);
00219 if (!to->addr) to->addr = (XtPointer)&tmp;
00220 LayYYsetdest ((BoxPtr *) to->addr);
00221 to->size = sizeof (BoxPtr *);
00222 return LayYYparse() ? FALSE : TRUE;
00223 }
00224
00225
00226 static void
00227 DisposeLayout (app, to, data, args, num_args)
00228 XtAppContext app;
00229 XrmValue *to;
00230 XtPointer data;
00231 XrmValuePtr args;
00232 Cardinal *num_args;
00233 {
00234 LayoutFreeLayout (* (LayoutPtr *) to->addr);
00235 }
00236
00237 static void
00238 ClassInitialize()
00239 {
00240 XtSetTypeConverter ( XtRString, XtRLayout, CvtStringToLayout,
00241 (XtConvertArgList)NULL, (Cardinal)0, XtCacheNone,
00242 DisposeLayout );
00243 }
00244
00245 #ifdef MOTIF
00246 static void Redisplay ( gw, event, region )
00247 Widget gw;
00248 XEvent *event;
00249 Region region;
00250 {
00251
00252
00253
00254
00255 if ( XtIsRealized ( gw ) && gw->core.visible )
00256 {
00257 _XmRedisplayGadgets ( gw, event, region );
00258 }
00259
00260 }
00261 #endif
00262
00263
00264 static XtGeometryResult GeometryManager(child, request, reply)
00265 Widget child;
00266 XtWidgetGeometry *request, *reply;
00267 {
00268 LayoutWidget w = (LayoutWidget) XtParent(child);
00269 SubInfoPtr p = SubInfo(child);
00270 int bw;
00271 Bool changed, bwChanged;
00272
00273 bw = p->naturalBw;
00274 changed = FALSE;
00275 bwChanged = FALSE;
00276 if (request->request_mode & CWBorderWidth &&
00277 request->border_width != child->core.border_width)
00278 {
00279 p->naturalBw = bw;
00280 bw = request->border_width;
00281 changed = TRUE;
00282 bwChanged = TRUE;
00283 }
00284 if (bwChanged || ((request->request_mode & CWWidth) &&
00285 request->width != child->core.width))
00286 {
00287 p->naturalSize[LayoutHorizontal] = request->width + bw * 2;
00288 changed = TRUE;
00289 }
00290 if (bwChanged || ((request->request_mode & CWHeight) &&
00291 request->height != child->core.height))
00292 {
00293 p->naturalSize[LayoutVertical] = request->height + bw * 2;
00294 changed = TRUE;
00295 }
00296 if (changed)
00297 LayoutLayout (w, TRUE);
00298 return XtGeometryDone;
00299 }
00300
00301
00302 static void Initialize(request, new, args, num_args)
00303 Widget request, new;
00304 ArgList args;
00305 Cardinal *num_args;
00306 {
00307
00308 }
00309
00310 static void ChangeManaged(gw)
00311 Widget gw;
00312 {
00313 LayoutWidget w = (LayoutWidget) gw;
00314 Widget *children;
00315
00316 DBUG_ENTER("changeManaged");
00317
00318 ForAllChildren (w, children)
00319 GetDesiredSize (*children);
00320 LayoutLayout ((LayoutWidget) w, TRUE);
00321 #ifdef MOTIF
00322 _XmNavigChangeManaged ( gw );
00323 #endif
00324 DBUG_VOID_RETURN;
00325 }
00326
00327 static void
00328 GetDesiredSize (child)
00329 Widget child;
00330 {
00331 XtWidgetGeometry desired;
00332 SubInfoPtr p;
00333
00334 XtQueryGeometry (child, (XtWidgetGeometry *) NULL, &desired);
00335 p = SubInfo (child);
00336 p->naturalBw = desired.border_width;
00337 p->naturalSize[LayoutHorizontal] = desired.width + desired.border_width * 2;
00338 p->naturalSize[LayoutVertical] = desired.height + desired.border_width * 2;
00339 }
00340
00341 static void InsertChild (child)
00342 Widget child;
00343 {
00344 (*SuperClass->composite_class.insert_child) (child);
00345 GetDesiredSize (child);
00346 }
00347
00348 static void
00349 Resize(gw)
00350 Widget gw;
00351 {
00352 LayoutLayout ((LayoutWidget) gw, FALSE);
00353 }
00354
00355
00356 static Boolean
00357 SetValues(gold, greq, gnew, args, num_args)
00358 Widget gold, greq, gnew;
00359 ArgList args;
00360 Cardinal *num_args;
00361 {
00362 LayoutWidget old = (LayoutWidget) gold,
00363 new = (LayoutWidget) gnew;
00364
00365 if (old->layout.layout != new->layout.layout)
00366 LayoutLayout (new, TRUE);
00367 return FALSE;
00368 }
00369
00370 static XtGeometryResult
00371 QueryGeometry (gw, request, prefered_return)
00372 Widget gw;
00373 XtWidgetGeometry *request, *prefered_return;
00374 {
00375 LayoutWidget w = (LayoutWidget) gw;
00376 XtGeometryResult result;
00377 XtWidgetGeometry prefered_size;
00378
00379 if (request && !(request->request_mode & (CWWidth|CWHeight)))
00380 return XtGeometryYes;
00381 LayoutGetNaturalSize (w, &prefered_size.width, &prefered_size.height);
00382 prefered_return->request_mode = 0;
00383 result = XtGeometryYes;
00384 if (!request) {
00385 prefered_return->width = prefered_size.width;
00386 prefered_return->height= prefered_size.height;
00387 if (prefered_size.width != w->core.width) {
00388 prefered_return->request_mode |= CWWidth;
00389 result = XtGeometryAlmost;
00390 }
00391 if (prefered_size.height != w->core.height) {
00392 prefered_return->request_mode |= CWHeight;
00393 result = XtGeometryAlmost;
00394 }
00395 } else {
00396 if (request->request_mode & CWWidth) {
00397 if (prefered_size.width > request->width)
00398 {
00399 if (prefered_size.width == w->core.width)
00400 result = XtGeometryNo;
00401 else if (result != XtGeometryNo) {
00402 result = XtGeometryAlmost;
00403 prefered_return->request_mode |= CWWidth;
00404 prefered_return->width = prefered_size.width;
00405 }
00406 }
00407 }
00408 if (request->request_mode & CWHeight) {
00409 if (prefered_size.height > request->height)
00410 {
00411 if (prefered_size.height == w->core.height)
00412 result = XtGeometryNo;
00413 else if (result != XtGeometryNo) {
00414 result = XtGeometryAlmost;
00415 prefered_return->request_mode |= CWHeight;
00416 prefered_return->height = prefered_size.height;
00417 }
00418 }
00419 }
00420 }
00421 return result;
00422 }
00423
00424
00425
00426
00427
00428
00429 static void
00430 PrintGlue (g)
00431 GlueRec g;
00432 {
00433 if (g.order == 0 || g.value != 1.0)
00434 (void) printf ("%g", g.value);
00435 if (g.order > 0)
00436 {
00437 (void) printf ("%s", " inf");
00438 if (g.order > 1)
00439 (void) printf (" %d", g.order);
00440 }
00441 }
00442
00443 static void
00444 PrintDirection (dir)
00445 LayoutDirection dir;
00446 {
00447 switch (dir) {
00448 case LayoutHorizontal:
00449 (void) printf ("%s", "horizontal");
00450 break;
00451 case LayoutVertical:
00452 (void) printf ("%s", "vertical");
00453 break;
00454 default:
00455 (void) printf ("Unknown layout direction %d\n", dir);
00456 break;
00457
00458 }
00459 }
00460
00461 static void
00462 TabTo(level)
00463 int level;
00464 {
00465 while (level--)
00466 (void) printf ("%s", " ");
00467 }
00468
00469 static void
00470 PrintBox (box, level)
00471 BoxPtr box;
00472 int level;
00473 {
00474 BoxPtr child;
00475
00476 TabTo (level);
00477 (void) printf ("%s", "< ");
00478 (void) printf ("%s", " + ");
00479 PrintGlue (box->params.stretch[LayoutHorizontal]);
00480 (void) printf ("%s", " - ");
00481 PrintGlue (box->params.shrink[LayoutHorizontal]);
00482 (void) printf ("%s", " * ");
00483 (void) printf ("%s", " + ");
00484 PrintGlue (box->params.stretch[LayoutVertical]);
00485 (void) printf ("%s", " - ");
00486 PrintGlue (box->params.shrink[LayoutVertical]);
00487 (void) printf ("%s", " >");
00488 (void) printf (" size: %d x %d", box->size[0], box->size[1]);
00489 (void) printf (" natural: %d x %d ", box->natural[0], box->natural[1]);
00490 switch (box->type) {
00491 case BoxBox:
00492 PrintDirection (box->u.box.dir);
00493 (void) printf ("%s\n", "");
00494 for (child = box->u.box.firstChild; child; child = child->nextSibling)
00495 PrintBox (child, level+1);
00496 break;
00497 case WidgetBox:
00498 (void) printf (" %s\n", XrmQuarkToString (box->u.widget.quark));
00499 break;
00500 case GlueBox:
00501 (void) printf ("%s\n", " glue");
00502 break;
00503 case VariableBox:
00504 (void) printf (" variable %s\n", XrmQuarkToString (box->u.variable.quark));
00505 break;
00506 }
00507 }
00508
00509 static ExprPtr
00510 LookupVariable (child, quark)
00511 BoxPtr child;
00512 XrmQuark quark;
00513 {
00514 BoxPtr parent, box;
00515
00516 DBUG_ENTER("LookupVariable");
00517 DBUG_PRINT("name = <%s>",XrmQuarkToString(quark));
00518 DBUG_PRINT("child = %p",child);
00519 while ((parent = child->parent))
00520 {
00521 for (box = parent->u.box.firstChild;
00522 box != child;
00523 box = box->nextSibling)
00524 {
00525 if (box->type == VariableBox && box->u.variable.quark == quark)
00526 DBUG_RETURN("%p", box->u.variable.expr);
00527 }
00528 child = parent;
00529 }
00530 DBUG_RETURN("failure -> %d",0);
00531 }
00532
00533 static double
00534 Evaluate (l, box, expr, natural)
00535 LayoutWidget l;
00536 BoxPtr box;
00537 ExprPtr expr;
00538 double natural;
00539 {
00540 double left, right, down;
00541 Widget widget;
00542 SubInfoPtr info;
00543
00544 DBUG_PRINT("Evaluate %d", expr->type);
00545 switch (expr->type) {
00546 case Constant:
00547 return expr->u.constant;
00548 case Binary:
00549 left = Evaluate (l, box, expr->u.binary.left, natural);
00550 right = Evaluate (l, box, expr->u.binary.right, natural);
00551 switch (expr->u.binary.op) {
00552 case Plus:
00553 return left + right;
00554 case Minus:
00555 return left - right;
00556 case Times:
00557 return left * right;
00558 case Divide:
00559 return left / right;
00560 case Percent:
00561 return right * left / 100.0;
00562 }
00563 case Unary:
00564 down = Evaluate (l, box, expr->u.unary.down, natural);
00565 switch (expr->u.unary.op) {
00566 case Percent:
00567 return natural * down / 100.0;
00568 case Minus:
00569 return -down;
00570 case Plus:
00571 case Times:
00572 case Divide:
00573 break;
00574 }
00575 case Width:
00576 widget = QuarkToWidget (l, expr->u.width);
00577 if (!widget)
00578 return 0;
00579 info = SubInfo (widget);
00580 return info->naturalSize[LayoutHorizontal];
00581 case Height:
00582 widget = QuarkToWidget (l, expr->u.height);
00583 if (!widget)
00584 return 0;
00585 info = SubInfo (widget);
00586 return info->naturalSize[LayoutVertical];
00587 case Variable:
00588 {
00589
00590
00591
00592
00593
00594 ExprPtr nexpr;
00595 nexpr = LookupVariable (box, expr->u.variable);
00596 if (!nexpr)
00597 {
00598 char buf[256];
00599 (void) sprintf (buf, "Layout: undefined variable %s\n",
00600 XrmQuarkToString (expr->u.variable));
00601 XtError (buf);
00602 return 0.0;
00603 }
00604 return Evaluate (l, box, nexpr, natural);
00605 }
00606 }
00607 return 0.0;
00608 }
00609
00610 static void
00611 DisposeExpr (expr)
00612 ExprPtr expr;
00613 {
00614 if (!expr)
00615 return;
00616 switch (expr->type) {
00617 case Constant:
00618 break;
00619 case Binary:
00620 DisposeExpr (expr->u.binary.left);
00621 DisposeExpr (expr->u.binary.right);
00622 break;
00623 case Unary:
00624 DisposeExpr (expr->u.unary.down);
00625 break;
00626 case Width:
00627 case Height:
00628 case Variable:
00629 break;
00630 }
00631 Dispose (expr);
00632 }
00633
00634 #define CheckGlue(l, box, glue, n) { \
00635 if (glue.expr) \
00636 glue.value = Evaluate (l, box, glue.expr, n); \
00637 if (glue.order == 0 && glue.value == 0) \
00638 glue.order = -1; \
00639 else if (glue.order == -1 && glue.value != 0) \
00640 glue.order = 0; \
00641 }
00642
00643 #define DoStretch(l, box, dir) \
00644 CheckGlue (l, box, box->params.stretch[dir], (double) box->natural[dir]);
00645
00646 #define DoShrink(l, box, dir) \
00647 CheckGlue (l, box, box->params.shrink[dir], (double) box->natural[dir])
00648
00649
00650 static void
00651 ComputeNaturalSizes (l, box, dir)
00652 LayoutWidget l;
00653 BoxPtr box;
00654 LayoutDirection dir;
00655 {
00656 BoxPtr child;
00657 Widget w;
00658 SubInfoPtr info;
00659 int minStretchOrder, minShrinkOrder;
00660 LayoutDirection thisDir;
00661
00662 DBUG_ENTER("ComputeNaturalSizes");
00663 DBUG_PRINT("box->type=%d",box->type);
00664 switch (box->type) {
00665 case WidgetBox:
00666 w = box->u.widget.widget = QuarkToWidget (l, box->u.widget.quark);
00667 if (!w)
00668 {
00669 box->natural[LayoutHorizontal] = 0;
00670 box->natural[LayoutVertical] = 0;
00671 }
00672 else
00673 {
00674 info = SubInfo (w);
00675 box->natural[LayoutHorizontal] = info->naturalSize[LayoutHorizontal];
00676 box->natural[LayoutVertical] = info->naturalSize[LayoutVertical];
00677 }
00678 DoStretch (l, box, dir);
00679 DoShrink (l, box, dir);
00680 DoStretch (l, box, !dir);
00681 DoShrink (l, box, !dir);
00682 break;
00683 case GlueBox:
00684 box->natural[dir] = Evaluate (l, box, box->u.glue.expr, 0.0);
00685 box->natural[!dir] = 0;
00686 DoStretch (l, box, dir);
00687 DoShrink (l, box, dir);
00688 break;
00689 case BoxBox:
00690 thisDir = box->u.box.dir;
00691 box->natural[0] = 0;
00692 box->natural[1] = 0;
00693 minStretchOrder = 100000;
00694 minShrinkOrder = 100000;
00695 ZeroGlue (box->params.shrink[thisDir]);
00696 ZeroGlue (box->params.stretch[thisDir]);
00697 box->params.shrink[!thisDir].order = 100000;
00698 box->params.stretch[!thisDir].order = 100000;
00699 for (child = box->u.box.firstChild; child; child = child->nextSibling)
00700 {
00701 ComputeNaturalSizes (l, child, thisDir);
00702
00703
00704
00705
00706
00707
00708 box->natural[thisDir] += child->natural[thisDir];
00709 AddGlue (box->params.shrink[thisDir],
00710 box->params.shrink[thisDir],
00711 child->params.shrink[thisDir]);
00712 AddGlue (box->params.stretch[thisDir],
00713 box->params.stretch[thisDir],
00714 child->params.stretch[thisDir]);
00715
00716
00717
00718
00719
00720
00721 if (box->natural[!thisDir] >= child->natural[!thisDir])
00722 {
00723 if (child->params.stretch[!thisDir].order < minShrinkOrder)
00724 {
00725 box->natural[!thisDir] = child->natural[!thisDir];
00726 minStretchOrder = child->params.stretch[!thisDir].order;
00727 if (child->params.shrink[!thisDir].order < minShrinkOrder)
00728 minShrinkOrder = child->params.shrink[!thisDir].order;
00729 }
00730 }
00731 else
00732 {
00733 if (child->params.shrink[!thisDir].order <= minStretchOrder)
00734 {
00735 box->natural[!thisDir] = child->natural[!thisDir];
00736 minShrinkOrder = child->params.shrink[!thisDir].order;
00737 if (child->params.stretch[!thisDir].order < minStretchOrder)
00738 minStretchOrder = child->params.stretch[!thisDir].order;
00739 }
00740 }
00741 MinGlue (box->params.stretch[!thisDir],
00742 box->params.stretch[!thisDir],
00743 child->params.stretch[!thisDir]);
00744 MinGlue (box->params.shrink[!thisDir],
00745 box->params.shrink[!thisDir],
00746 child->params.shrink[!thisDir]);
00747 }
00748 if (box->params.shrink[!thisDir].order <= 0)
00749 {
00750 int minSize;
00751 int largestMinSize;
00752
00753 largestMinSize = 0;
00754 for (child = box->u.box.firstChild; child; child = child->nextSibling)
00755 {
00756 if (child->params.shrink[!thisDir].order <= 0)
00757 {
00758 minSize = child->natural[!thisDir] -
00759 child->params.shrink[!thisDir].value;
00760 if (minSize > largestMinSize)
00761 largestMinSize = minSize;
00762 }
00763 }
00764 box->params.shrink[!thisDir].value = box->natural[!thisDir] -
00765 largestMinSize;
00766 if (box->params.shrink[!thisDir].value == 0)
00767 box->params.shrink[!thisDir].order = -1;
00768 else
00769 box->params.shrink[!thisDir].order = 0;
00770 }
00771 break;
00772 case VariableBox:
00773 break;
00774 }
00775 DBUG_VOID_RETURN;
00776 }
00777
00778
00779
00780 #define GluePart(a,b,dist) ((a) ? ((int) (((a) * (dist)) / (b) + \
00781 ((dist >= 0) ? 0.5 : -0.5))) : 0)
00782
00783 static Bool
00784 ComputeSizes (box)
00785 BoxPtr box;
00786 {
00787 LayoutDirection dir;
00788 BoxPtr child;
00789 GlueRec stretch;
00790 GlueRec shrink;
00791 GlueRec totalGlue[2];
00792 double remainingGlue;
00793 GluePtr glue;
00794 int size;
00795 int totalSizes;
00796 int totalChange[2];
00797 int change;
00798 int remainingChange;
00799 Bool shrinking;
00800 Bool happy;
00801 int i;
00802 int maxGlue;
00803
00804 dir = box->u.box.dir;
00805 size = box->size[dir];
00806
00807 stretch = box->params.stretch[dir];
00808 shrink = box->params.shrink[dir];
00809
00810
00811
00812 totalChange[0] = size - box->natural[dir];
00813
00814 shrinking = totalChange[0] < 0;
00815
00816 totalChange[1] = 0;
00817 totalGlue[1].order = 100000;
00818 totalGlue[1].value = 0;
00819 maxGlue = 1;
00820 if (shrinking)
00821 {
00822 totalGlue[0] = shrink;
00823
00824
00825
00826 if (shrink.order == 1) {
00827 totalSizes = 0;
00828 remainingGlue = 0;
00829 for (child = box->u.box.firstChild;
00830 child;
00831 child = child->nextSibling)
00832 {
00833 switch (child->params.shrink[dir].order) {
00834 case 0:
00835 remainingGlue += child->params.shrink[dir].value;
00836 break;
00837 case 1:
00838 totalSizes += child->natural[dir];
00839 break;
00840 }
00841 }
00842 if (totalSizes < -totalChange[0])
00843 {
00844 totalGlue[1] = shrink;
00845 totalGlue[0].order = 0;
00846 totalGlue[0].value = remainingGlue;
00847 totalChange[1] = -totalSizes;
00848 totalChange[0] = totalChange[0] - totalChange[1];
00849 maxGlue = 2;
00850 }
00851 }
00852 if (totalGlue[0].order <= 0 &&
00853 totalChange[0] > totalGlue[0].value)
00854 {
00855 totalChange[0] = totalGlue[0].value;
00856 }
00857 }
00858 else
00859 totalGlue[0] = stretch;
00860
00861
00862 totalSizes = 0;
00863 remainingGlue = totalGlue[0].value + totalGlue[1].value;
00864 remainingChange = totalChange[0] + totalChange[1];
00865 happy = True;
00866 for (child = box->u.box.firstChild; child; child = child->nextSibling)
00867 {
00868
00869 if (child->type == VariableBox) continue;
00870
00871 if (shrinking)
00872 glue = &child->params.shrink[dir];
00873 else
00874 glue = &child->params.stretch[dir];
00875
00876 child->size[dir] = child->natural[dir];
00877 for (i = 0; i < maxGlue; i++)
00878 {
00879 if (glue->order == totalGlue[i].order)
00880 {
00881 remainingGlue -= glue->value;
00882 if (remainingGlue <= 0)
00883 change = remainingChange;
00884 else
00885 change = GluePart (glue->value,
00886 totalGlue[i].value,
00887 totalChange[i]);
00888 child->size[dir] += change;
00889 remainingChange -= change;
00890 }
00891 }
00892 child->size[!dir] = box->size[!dir];
00893 totalSizes += child->size[dir];
00894 if (child->type == BoxBox)
00895 if (!ComputeSizes (child))
00896 happy = False;
00897 }
00898 return totalSizes == box->size[dir] && happy;
00899 }
00900
00901 static void
00902 SetSizes (box, x, y)
00903 BoxPtr box;
00904 Position x, y;
00905 {
00906 BoxPtr child;
00907 int width, height;
00908 int bw;
00909 Widget w;
00910 SubInfoPtr info;
00911
00912 switch (box->type) {
00913 case WidgetBox:
00914 w = box->u.widget.widget;
00915 if (w)
00916 {
00917 info = SubInfo(w);
00918
00919 width = box->size[LayoutHorizontal];
00920 height = box->size[LayoutVertical];
00921 bw = info->naturalBw;
00922 width -= bw * 2;
00923 height -= bw * 2;
00924
00925 if (width <= 0 || height <= 0)
00926 {
00927 width = 1;
00928 height = 1;
00929 bw = 0;
00930 x = -1;
00931 y = -1;
00932 }
00933 XtConfigureWidget (w, x, y,
00934 (Dimension)width, (Dimension)height,
00935 (Dimension)bw);
00936 }
00937 break;
00938 case BoxBox:
00939 for (child = box->u.box.firstChild; child; child = child->nextSibling)
00940 {
00941 SetSizes (child, x, y);
00942 if (box->u.box.dir == LayoutHorizontal)
00943 x += child->size[LayoutHorizontal];
00944 else
00945 y += child->size[LayoutVertical];
00946 }
00947 break;
00948 case GlueBox:
00949 case VariableBox:
00950 break;
00951 }
00952 }
00953
00954 static void
00955 LayoutFreeLayout (box)
00956 BoxPtr box;
00957 {
00958 BoxPtr child, next;
00959
00960 switch (box->type) {
00961 case BoxBox:
00962 for (child = box->u.box.firstChild; child; child = next)
00963 {
00964 next = child->nextSibling;
00965 LayoutFreeLayout (child);
00966 }
00967 break;
00968 case GlueBox:
00969 DisposeExpr (box->u.glue.expr);
00970 break;
00971 case WidgetBox:
00972 case VariableBox:
00973 default:
00974 break;
00975 }
00976 DisposeExpr (box->params.stretch[LayoutHorizontal].expr);
00977 DisposeExpr (box->params.shrink[LayoutHorizontal].expr);
00978 DisposeExpr (box->params.stretch[LayoutVertical].expr);
00979 DisposeExpr (box->params.shrink[LayoutVertical].expr);
00980 Dispose (box);
00981 }
00982
00983
00984 static void
00985 LayoutGetNaturalSize (l, widthp, heightp)
00986 LayoutWidget l;
00987 Dimension *widthp, *heightp;
00988 {
00989 BoxPtr box;
00990
00991 DBUG_ENTER("LayoutGetNaturalSize");
00992 box = l->layout.layout;
00993 if (box)
00994 {
00995 ComputeNaturalSizes (l, box, LayoutHorizontal);
00996 *widthp = box->natural[LayoutHorizontal];
00997 *heightp = box->natural[LayoutVertical];
00998 }
00999 else
01000 {
01001 *widthp = 0;
01002 *heightp = 0;
01003 }
01004 DBUG_VOID_RETURN;
01005 }
01006
01007 static void
01008 LayoutLayout (l, attemptResize)
01009 LayoutWidget l;
01010 Bool attemptResize;
01011 {
01012 BoxPtr box;
01013 Dimension width, height;
01014 Dimension prefered_width, prefered_height;
01015
01016 DBUG_ENTER("LayoutLayout");
01017 box = l->layout.layout;
01018 if (!box)
01019 return;
01020 LayoutGetNaturalSize (l, &prefered_width, &prefered_height);
01021 if (l->core.width == 0 || l->core.height == 0)
01022 {
01023 l->core.width = prefered_width;
01024 l->core.height = prefered_height;
01025 }
01026 box->size[LayoutHorizontal] = l->core.width;
01027 box->size[LayoutVertical] = l->core.height;
01028 if (!ComputeSizes (box) && attemptResize)
01029 {
01030 XtMakeResizeRequest ((Widget) l,
01031 prefered_width, prefered_height,
01032 &width, &height);
01033 if (width != box->size[LayoutHorizontal] ||
01034 height != box->size[LayoutVertical])
01035 {
01036 box->size[LayoutHorizontal] = width;
01037 box->size[LayoutVertical] = height;
01038 ComputeSizes (box);
01039 }
01040 }
01041 if (l->layout.debug)
01042 {
01043 PrintBox (box, 0);
01044 fflush (stdout);
01045 }
01046 SetSizes (box, 0, 0);
01047 DBUG_VOID_RETURN;
01048 }
01049