Layout.c

Go to the documentation of this file.
00001 /*
00002  * $XConsortium: Layout.c,v 1.1 91/09/13 18:51:44 keith Exp $
00003  *
00004  * Copyright 1991 Massachusetts Institute of Technology
00005  *
00006  * Permission to use, copy, modify, distribute, and sell this software and its
00007  * documentation for any purpose is hereby granted without fee, provided that
00008  * the above copyright notice appear in all copies and that both that
00009  * copyright notice and this permission notice appear in supporting
00010  * documentation, and that the name of M.I.T. not be used in advertising or
00011  * publicity pertaining to distribution of the software without specific,
00012  * written prior permission.  M.I.T. makes no representations about the
00013  * suitability of this software for any purpose.  It is provided "as is"
00014  * without express or implied warranty.
00015  *
00016  * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
00017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
00018  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00019  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
00020  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
00021  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00022  *
00023  * Author:  Keith Packard, MIT X Consortium
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  * Full instance record declaration
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 /* core class fields */
00114     /* superclass         */   (WidgetClass) SuperClass,
00115     /* class name         */   "Layout",
00116     /* size               */   sizeof(LayoutRec),
00117     /* class_initialize   */   ClassInitialize,
00118     /* class_part init    */   NULL,
00119     /* class_inited       */   FALSE,
00120     /* initialize         */   Initialize,
00121     /* initialize_hook    */   NULL,
00122     /* realize            */   XtInheritRealize,
00123     /* actions            */   NULL,
00124     /* num_actions        */   0,
00125     /* resources          */   resources,
00126     /* resource_count     */   XtNumber(resources),
00127     /* xrm_class          */   NULLQUARK,
00128     /* compress_motion    */   FALSE,
00129     /* compress_exposure  */   0,
00130     /* compress_enterleave*/   FALSE,
00131     /* visible_interest   */   FALSE,
00132     /* destroy            */   NULL,
00133     /* resize             */   Resize,
00134 #ifdef MOTIF
00135     /* expose             */   Redisplay,
00136 #else
00137     /* expose             */   NULL,
00138 #endif
00139     /* set_values         */   SetValues,
00140     /* set_values_hook    */   NULL,
00141     /* set_values_almost  */   XtInheritSetValuesAlmost,
00142     /* get_values_hook    */   NULL,
00143     /* accept_focus       */   NULL,
00144     /* version            */   XtVersion,
00145     /* callback_private   */   NULL,
00146 #ifdef MOTIF
00147     /* tm_table           */   XtInheritTranslations,
00148 #else
00149     /* tm_table           */   NULL,
00150 #endif
00151     /* query_geometry     */   QueryGeometry,
00152     /* display_accelerator*/   XtInheritDisplayAccelerator,
00153     /* extension          */   NULL
00154    }, {
00155 /* composite class fields */
00156     /* geometry_manager   */   GeometryManager,
00157     /* change_managed     */   ChangeManaged,
00158     /* insert_child       */   InsertChild,
00159     /* delete_child       */   XtInheritDeleteChild,
00160     /* extension          */   NULL
00161    }, {
00162 /* constraint class fields */
00163     /* subresources       */   NULL,
00164     /* subresource_count  */   0,
00165     /* constraint_size    */   sizeof(LayoutConstraintsRec),
00166     /* initialize         */   NULL,
00167     /* destroy            */   NULL,
00168     /* set_values         */   NULL,
00169     /* extension          */   NULL
00170    },
00171 #ifdef MOTIF
00172    {
00173     /* manager class */
00174     XtInheritTranslations,                /* translations           */
00175     NULL,                                 /* syn resources          */
00176     0,                                    /* num syn_resources      */
00177     NULL,                                 /* get_cont_resources     */
00178     0,                                    /* num_get_cont_resources */
00179     XmInheritParentProcess,               /* parent_process       */
00180     NULL,                                 /* extension              */
00181    },
00182 #endif
00183    { /* layout_class fields */     
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  * Semi-public routines. 
00198  *
00199  ************************************************************/
00200 
00201 /*      Function Name: ClassInitialize
00202  *      Description: The Layout widgets class initialization proc.
00203  *      Arguments: none.
00204  *      Returns: none.
00205  */
00206 
00207 /*ARGSUSED*/
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 /*ARGSUSED*/
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     * If the Layout widget is visible, redraw gadgets.
00253     */
00254  
00255     if ( XtIsRealized ( gw ) && gw->core.visible ) 
00256     {
00257         _XmRedisplayGadgets ( gw, event, region );
00258     }
00259     /* ChangeManaged(gw);*/
00260 }
00261 #endif
00262 
00263 /*ARGSUSED*/
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 /* ARGSUSED */
00302 static void Initialize(request, new, args, num_args)
00303 Widget request, new;
00304 ArgList args;
00305 Cardinal *num_args;
00306 {
00307 /*    LayoutWidget w = (LayoutWidget)new; */
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 /* ARGSUSED */
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 } /* SetValues */
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  * Layout section.  Exports LayoutGetNaturalSize and
00426  * LayoutLayout to above section
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         /* in the original code there was no nexpr, 
00590            expr was overwritten by LookupVariable and 
00591            the expression "expr->u.variable" to obtain the
00592            variable name for the errormessage cause a segmentation
00593            violation */
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 /* compute the natural sizes of a box */
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              * along box axis:
00704              *  normal size += child normal size
00705              *  shrink += child shrink
00706              *  stretch += child stretch
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              * normal to box axis:
00717              *  normal size = maximum child normal size of minimum shrink order
00718              *  shrink = difference between normal size and minimum shrink
00719              *  stretch = minimum child stretch
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 /* given the boxs geometry, set the geometry of the pieces */
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     /* pick the correct adjustment parameters based on the change direction */
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         /* for first-order infinites, shrink it to zero and then
00824          * shrink the zero-orders
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     /* adjust each box */
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         /* never add glue or stretch to a VariableBox! */
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             /* info = (SubInfoPtr) w->core.constraints; */
00919             width = box->size[LayoutHorizontal];
00920             height = box->size[LayoutVertical];
00921             bw = info->naturalBw;
00922             width -= bw * 2;
00923             height -= bw * 2;
00924             /* Widgets which grow too small are placed off screen */
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 

Generated on Sun Mar 4 15:03:55 2007 for Scilab [trunk] by  doxygen 1.5.1