Tree.c

Go to the documentation of this file.
00001 /*
00002  * $XConsortium: Tree.c,v 1.45 94/04/17 20:13:20 kaleb Exp $
00003  *
00004 
00005 Copyright (c) 1990, 1994  X Consortium
00006 
00007 Permission is hereby granted, free of charge, to any person obtaining a copy
00008 of this software and associated documentation files (the "Software"), to deal
00009 in the Software without restriction, including without limitation the rights
00010 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00011 copies of the Software, and to permit persons to whom the Software is
00012 furnished to do so, subject to the following conditions:
00013 
00014 The above copyright notice and this permission notice shall be included in
00015 all copies or substantial portions of the Software.
00016 
00017 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00018 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00019 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00020 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00021 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00022 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00023 
00024 Except as contained in this notice, the name of the X Consortium shall not be
00025 used in advertising or otherwise to promote the sale, use or other dealings
00026 in this Software without prior written authorization from the X Consortium.
00027 
00028  * Copyright 1989 Prentice Hall
00029  *
00030  * Permission to use, copy, modify, and distribute this software for any
00031  * purpose and without fee is hereby granted, provided that the above
00032  * copyright notice appear in all copies and that both the copyright notice
00033  * and this permission notice appear in supporting documentation.
00034  * 
00035  * Prentice Hall and the authors disclaim all warranties with regard
00036  * to this software, including all implied warranties of merchantability and
00037  * fitness.  In no event shall Prentice Hall or the authors be liable
00038  * for any special, indirect or cosequential damages or any damages whatsoever
00039  * resulting from loss of use, data or profits, whether in an action of
00040  * contract, negligence or other tortious action, arising out of or in
00041  * connection with the use or performance of this software.
00042  * 
00043  * Authors:  Jim Fulton, MIT X Consortium,
00044  *           based on a version by Douglas Young, Prentice Hall
00045  * 
00046  * This widget is based on the Tree widget described on pages 397-419 of
00047  * Douglas Young's book "The X Window System, Programming and Applications 
00048  * with Xt OSF/Motif Edition."  The layout code has been rewritten to use
00049  * additional blank space to make the structure of the graph easier to see
00050  * as well as to support vertical trees.
00051  */
00052 
00053 #include <X11/IntrinsicP.h>
00054 #include <X11/StringDefs.h>
00055 #include <X11/Xaw3d/XawInit.h>
00056 #include <X11/Xaw3d/Cardinals.h>
00057 #include <X11/Xaw3d/TreeP.h>
00058 
00059 #define IsHorizontal(tw) ((tw)->tree.gravity == WestGravity || \
00060                           (tw)->tree.gravity == EastGravity)
00061 
00062 
00063                                         /* widget class method */
00064 static void             ClassInitialize();
00065 static void             Initialize();
00066 static void             ConstraintInitialize();
00067 static void             ConstraintDestroy();
00068 static Boolean          ConstraintSetValues();
00069 static void             Destroy();
00070 static Boolean          SetValues();
00071 static XtGeometryResult GeometryManager();
00072 static void             ChangeManaged();
00073 static void             Redisplay();
00074 static XtGeometryResult QueryGeometry();
00075 
00076                                         /* utility routines */
00077 static void             insert_node();
00078 static void             delete_node();
00079 static void             layout_tree();
00080 
00081 
00082 /*
00083  * resources of the tree itself
00084  */
00085 static XtResource resources[] = {
00086     { XtNautoReconfigure, XtCAutoReconfigure, XtRBoolean, sizeof (Boolean),
00087         XtOffsetOf(TreeRec, tree.auto_reconfigure), XtRImmediate,
00088         (XtPointer) FALSE },
00089     { XtNhSpace, XtCHSpace, XtRDimension, sizeof (Dimension),
00090         XtOffsetOf(TreeRec, tree.hpad), XtRImmediate, (XtPointer) 0 },
00091     { XtNvSpace, XtCVSpace, XtRDimension, sizeof (Dimension),
00092         XtOffsetOf(TreeRec, tree.vpad), XtRImmediate, (XtPointer) 0 },
00093     { XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel),
00094         XtOffsetOf(TreeRec, tree.foreground), XtRString,
00095         XtDefaultForeground},
00096     { XtNlineWidth, XtCLineWidth, XtRDimension, sizeof (Dimension),
00097         XtOffsetOf(TreeRec, tree.line_width), XtRImmediate, (XtPointer) 0 },
00098     { XtNgravity, XtCGravity, XtRGravity, sizeof (XtGravity),
00099         XtOffsetOf(TreeRec, tree.gravity), XtRImmediate,
00100         (XtPointer) WestGravity },
00101 };
00102 
00103 
00104 /*
00105  * resources that are attached to all children of the tree
00106  */
00107 static XtResource treeConstraintResources[] = {
00108     { XtNtreeParent, XtCTreeParent, XtRWidget, sizeof (Widget),
00109         XtOffsetOf(TreeConstraintsRec, tree.parent), XtRImmediate, NULL },
00110     { XtNtreeGC, XtCTreeGC, XtRGC, sizeof(GC),
00111         XtOffsetOf(TreeConstraintsRec, tree.gc), XtRImmediate, NULL },
00112 };
00113 
00114 
00115 TreeClassRec treeClassRec = {
00116   {
00117                                         /* core_class fields  */
00118     (WidgetClass) &constraintClassRec,  /* superclass         */
00119     "Tree",                             /* class_name         */
00120     sizeof(TreeRec),                    /* widget_size        */
00121     ClassInitialize,                    /* class_init         */
00122     NULL,                               /* class_part_init    */
00123     FALSE,                              /* class_inited       */        
00124     Initialize,                         /* initialize         */
00125     NULL,                               /* initialize_hook    */        
00126     XtInheritRealize,                   /* realize            */
00127     NULL,                               /* actions            */
00128     0,                                  /* num_actions        */        
00129     resources,                          /* resources          */
00130     XtNumber(resources),                /* num_resources      */
00131     NULLQUARK,                          /* xrm_class          */
00132     TRUE,                               /* compress_motion    */        
00133     TRUE,                               /* compress_exposure  */        
00134     TRUE,                               /* compress_enterleave*/        
00135     TRUE,                               /* visible_interest   */
00136     Destroy,                            /* destroy            */
00137     NULL,                               /* resize             */
00138     Redisplay,                          /* expose             */
00139     SetValues,                          /* set_values         */
00140     NULL,                               /* set_values_hook    */        
00141     XtInheritSetValuesAlmost,           /* set_values_almost  */
00142     NULL,                               /* get_values_hook    */        
00143     NULL,                               /* accept_focus       */
00144     XtVersion,                          /* version            */        
00145     NULL,                               /* callback_private   */
00146     NULL,                               /* tm_table           */
00147     QueryGeometry,                      /* query_geometry     */        
00148     NULL,                               /* display_accelerator*/
00149     NULL,                               /* extension          */
00150   },
00151   {
00152                                         /* composite_class fields */
00153     GeometryManager,                    /* geometry_manager    */
00154     ChangeManaged,                      /* change_managed      */
00155     XtInheritInsertChild,               /* insert_child        */       
00156     XtInheritDeleteChild,               /* delete_child        */       
00157     NULL,                               /* extension           */
00158   },
00159   { 
00160                                         /* constraint_class fields */
00161    treeConstraintResources,             /* subresources        */
00162    XtNumber(treeConstraintResources),   /* subresource_count   */
00163    sizeof(TreeConstraintsRec),          /* constraint_size     */
00164    ConstraintInitialize,                /* initialize          */
00165    ConstraintDestroy,                   /* destroy             */
00166    ConstraintSetValues,                 /* set_values          */
00167    NULL,                                /* extension           */
00168    },
00169   {
00170                                         /* Tree class fields */
00171     0,                                  /* ignore              */       
00172   }
00173 };
00174 
00175 WidgetClass treeWidgetClass = (WidgetClass) &treeClassRec;
00176 
00177 
00178 /*****************************************************************************
00179  *                                                                           *
00180  *                           tree utility routines                           *
00181  *                                                                           *
00182  *****************************************************************************/
00183 
00184 static void initialize_dimensions (listp, sizep, n)
00185     Dimension **listp;
00186     int *sizep;
00187     int n;
00188 {
00189     int i;
00190     Dimension *l;
00191 
00192     if (!*listp) {
00193         *listp = (Dimension *) XtCalloc ((unsigned int) n,
00194                                          (unsigned int) sizeof(Dimension));
00195         *sizep = ((*listp) ? n : 0);
00196         return;
00197     }
00198     if (n > *sizep) {
00199         *listp = (Dimension *) XtRealloc((char *) *listp,
00200                                          (unsigned int) (n*sizeof(Dimension)));
00201         if (!*listp) {
00202             *sizep = 0;
00203             return;
00204         }
00205         for (i = *sizep, l = (*listp) + i; i < n; i++, l++) *l = 0;
00206         *sizep = n;
00207     }
00208     return;
00209 }
00210 
00211 static GC get_tree_gc (w)
00212     TreeWidget w;
00213 {
00214     XtGCMask valuemask = GCBackground | GCForeground;
00215     XGCValues values;
00216 
00217     values.background = w->core.background_pixel;
00218     values.foreground = w->tree.foreground;
00219     if (w->tree.line_width != 0) {
00220         valuemask |= GCLineWidth;
00221         values.line_width = w->tree.line_width;
00222     }
00223 
00224     return XtGetGC ((Widget) w, valuemask, &values);
00225 }
00226 
00227 static void insert_node (parent, node)
00228      Widget parent, node;
00229 {
00230     TreeConstraints pc;
00231     TreeConstraints nc = TREE_CONSTRAINT(node);
00232     int nindex;
00233   
00234     nc->tree.parent = parent;
00235 
00236     if (parent == NULL) return;
00237 
00238     /*
00239      * If there isn't more room in the children array, 
00240      * allocate additional space.
00241      */  
00242     pc = TREE_CONSTRAINT(parent);
00243     nindex = pc->tree.n_children;
00244   
00245     if (pc->tree.n_children == pc->tree.max_children) {
00246         pc->tree.max_children += (pc->tree.max_children / 2) + 2;
00247         pc->tree.children = (WidgetList) XtRealloc ((char *)pc->tree.children, 
00248                                                     (unsigned int)
00249                                                     ((pc->tree.max_children) *
00250                                                     sizeof(Widget)));
00251     } 
00252 
00253     /*
00254      * Add the sub_node in the next available slot and 
00255      * increment the counter.
00256      */
00257     pc->tree.children[nindex] = node;
00258     pc->tree.n_children++;
00259 }
00260 
00261 static void delete_node (parent, node)
00262     Widget parent, node;
00263 {
00264     TreeConstraints pc;
00265     int pos, i;
00266 
00267     /*
00268      * Make sure the parent exists.
00269      */
00270     if (!parent) return;  
00271   
00272     pc = TREE_CONSTRAINT(parent);
00273 
00274     /*
00275      * Find the sub_node on its parent's list.
00276      */
00277     for (pos = 0; pos < pc->tree.n_children; pos++)
00278       if (pc->tree.children[pos] == node) break;
00279 
00280     if (pos == pc->tree.n_children) return;
00281 
00282     /*
00283      * Decrement the number of children
00284      */  
00285     pc->tree.n_children--;
00286 
00287     /*
00288      * Fill in the gap left by the sub_node.
00289      * Zero the last slot for good luck.
00290      */
00291     for (i = pos; i < pc->tree.n_children; i++) 
00292       pc->tree.children[i] = pc->tree.children[i+1];
00293 
00294     pc->tree.children[pc->tree.n_children]=0;
00295 }
00296 
00297 static void check_gravity (tw, grav)
00298     TreeWidget tw;
00299     XtGravity grav;
00300 {
00301     switch (tw->tree.gravity) {
00302       case WestGravity: case NorthGravity: case EastGravity: case SouthGravity:
00303         break;
00304       default:
00305         tw->tree.gravity = grav;
00306         break;
00307     }
00308 }
00309 
00310 
00311 /*****************************************************************************
00312  *                                                                           *
00313  *                            tree class methods                             *
00314  *                                                                           *
00315  *****************************************************************************/
00316 
00317 static void ClassInitialize ()
00318 {
00319     XawInitializeWidgetSet();
00320     XtAddConverter (XtRString, XtRGravity, XmuCvtStringToGravity,
00321                     (XtConvertArgList) NULL, (Cardinal) 0);
00322 }
00323 
00324 
00325 /*ARGSUSED*/
00326 static void Initialize (grequest, gnew, args, num_args)
00327     Widget grequest, gnew;
00328     ArgList args;
00329     Cardinal *num_args;
00330 {
00331     TreeWidget request = (TreeWidget) grequest, new = (TreeWidget) gnew;
00332     Arg arglist[2];
00333 
00334     /*
00335      * Make sure the widget's width and height are 
00336      * greater than zero.
00337      */
00338     if (request->core.width <= 0) new->core.width = 5;
00339     if (request->core.height <= 0) new->core.height = 5;
00340 
00341     /*
00342      * Set the padding according to the orientation
00343      */
00344     if (request->tree.hpad == 0 && request->tree.vpad == 0) {
00345         if (IsHorizontal (request)) {
00346             new->tree.hpad = TREE_HORIZONTAL_DEFAULT_SPACING;
00347             new->tree.vpad = TREE_VERTICAL_DEFAULT_SPACING;
00348         } else {
00349             new->tree.hpad = TREE_VERTICAL_DEFAULT_SPACING;
00350             new->tree.vpad = TREE_HORIZONTAL_DEFAULT_SPACING;
00351         }
00352     }
00353 
00354     /*
00355      * Create a graphics context for the connecting lines.
00356      */
00357     new->tree.gc = get_tree_gc (new);
00358 
00359     /*
00360      * Create the hidden root widget.
00361      */
00362     new->tree.tree_root = (Widget) NULL;
00363     XtSetArg(arglist[0], XtNwidth, 1);
00364     XtSetArg(arglist[1], XtNheight, 1);
00365     new->tree.tree_root = XtCreateWidget ("root", widgetClass, gnew,
00366                                           arglist,TWO);
00367 
00368     /*
00369      * Allocate the array used to hold the widest values per depth
00370      */
00371     new->tree.largest = NULL;
00372     new->tree.n_largest = 0;
00373     initialize_dimensions (&new->tree.largest, &new->tree.n_largest, 
00374                            TREE_INITIAL_DEPTH);
00375 
00376     /*
00377      * make sure that our gravity is one of the acceptable values
00378      */
00379     check_gravity (new, WestGravity);
00380 } 
00381 
00382 
00383 /* ARGSUSED */
00384 static void ConstraintInitialize (request, new, args, num_args)
00385      Widget request, new;
00386      ArgList args;
00387      Cardinal *num_args;
00388 {
00389     TreeConstraints tc = TREE_CONSTRAINT(new);
00390     TreeWidget tw = (TreeWidget) new->core.parent;
00391 
00392     /*
00393      * Initialize the widget to have no sub-nodes.
00394      */
00395     tc->tree.n_children = 0;
00396     tc->tree.max_children = 0;
00397     tc->tree.children = (Widget *) NULL;
00398     tc->tree.x = tc->tree.y = 0; 
00399     tc->tree.bbsubwidth = 0;
00400     tc->tree.bbsubheight = 0;
00401 
00402 
00403     /*
00404      * If this widget has a super-node, add it to that 
00405      * widget' sub-nodes list. Otherwise make it a sub-node of 
00406      * the tree_root widget.
00407      */
00408     if (tc->tree.parent)
00409       insert_node (tc->tree.parent, new);
00410     else if (tw->tree.tree_root)
00411       insert_node (tw->tree.tree_root, new);
00412 } 
00413 
00414 
00415 /* ARGSUSED */
00416 static Boolean SetValues (gcurrent, grequest, gnew, args, num_args)
00417     Widget gcurrent, grequest, gnew;
00418     ArgList args;
00419     Cardinal *num_args;
00420 {
00421     TreeWidget current = (TreeWidget) gcurrent, new = (TreeWidget) gnew;
00422     Boolean redraw = FALSE;
00423 
00424     /*
00425      * If the foreground color has changed, redo the GC's
00426      * and indicate a redraw.
00427      */
00428     if (new->tree.foreground != current->tree.foreground ||
00429         new->core.background_pixel != current->core.background_pixel ||
00430         new->tree.line_width != current->tree.line_width) {
00431         XtReleaseGC (gnew, new->tree.gc);
00432         new->tree.gc = get_tree_gc (new);
00433         redraw = TRUE;     
00434     }
00435 
00436     /*
00437      * If the minimum spacing has changed, recalculate the
00438      * tree layout. layout_tree() does a redraw, so we don't
00439      * need SetValues to do another one.
00440      */
00441     if (new->tree.gravity != current->tree.gravity) {
00442         check_gravity (new, current->tree.gravity);
00443     }
00444 
00445     if (IsHorizontal(new) != IsHorizontal(current)) {
00446         if (new->tree.vpad == current->tree.vpad &&
00447             new->tree.hpad == current->tree.hpad) {
00448             new->tree.vpad = current->tree.hpad;
00449             new->tree.hpad = current->tree.vpad;
00450         }
00451     }
00452 
00453     if (new->tree.vpad != current->tree.vpad ||
00454         new->tree.hpad != current->tree.hpad ||
00455         new->tree.gravity != current->tree.gravity) {
00456         layout_tree (new, TRUE);
00457         redraw = FALSE;
00458     }
00459     return redraw;
00460 }
00461 
00462 
00463 /* ARGSUSED */
00464 static Boolean ConstraintSetValues (current, request, new, args, num_args)
00465     Widget current, request, new;
00466     ArgList args;
00467     Cardinal *num_args;
00468 {
00469     TreeConstraints newc = TREE_CONSTRAINT(new);
00470     TreeConstraints curc = TREE_CONSTRAINT(current);
00471     TreeWidget tw = (TreeWidget) new->core.parent;
00472 
00473     /*
00474      * If the parent field has changed, remove the widget
00475      * from the old widget's children list and add it to the
00476      * new one.
00477      */
00478     if (curc->tree.parent != newc->tree.parent){
00479         if (curc->tree.parent)
00480           delete_node (curc->tree.parent, new);
00481         if (newc->tree.parent)
00482           insert_node(newc->tree.parent, new);
00483 
00484         /*
00485          * If the Tree widget has been realized, 
00486          * compute new layout.
00487          */
00488         if (XtIsRealized((Widget)tw))
00489           layout_tree (tw, FALSE);
00490     }
00491     return False;
00492 }
00493 
00494 
00495 static void ConstraintDestroy (w) 
00496     Widget w;
00497 { 
00498     TreeConstraints tc = TREE_CONSTRAINT(w);
00499     TreeWidget tw = (TreeWidget) XtParent(w);
00500     int i;
00501 
00502     /* 
00503      * Remove the widget from its parent's sub-nodes list and
00504      * make all this widget's sub-nodes sub-nodes of the parent.
00505      */
00506   
00507     if (tw->tree.tree_root == w) {
00508         if (tc->tree.n_children > 0)
00509           tw->tree.tree_root = tc->tree.children[0];
00510         else
00511           tw->tree.tree_root = NULL;
00512     }
00513 
00514     delete_node (tc->tree.parent, (Widget) w);
00515     for (i = 0; i< tc->tree.n_children; i++)
00516       insert_node (tc->tree.parent, tc->tree.children[i]);
00517 
00518     layout_tree ((TreeWidget) (w->core.parent), FALSE);
00519 }
00520 
00521 /* ARGSUSED */
00522 static XtGeometryResult GeometryManager (w, request, reply)
00523     Widget w;
00524     XtWidgetGeometry *request;
00525     XtWidgetGeometry *reply;
00526 {
00527 
00528     TreeWidget tw = (TreeWidget) w->core.parent;
00529 
00530     /*
00531      * No position changes allowed!.
00532      */
00533     if ((request->request_mode & CWX && request->x!=w->core.x)
00534         ||(request->request_mode & CWY && request->y!=w->core.y))
00535       return (XtGeometryNo);
00536 
00537     /*
00538      * Allow all resize requests.
00539      */
00540 
00541     if (request->request_mode & CWWidth)
00542       w->core.width = request->width;
00543     if (request->request_mode & CWHeight)
00544       w->core.height = request->height;
00545     if (request->request_mode & CWBorderWidth)
00546       w->core.border_width = request->border_width;
00547 
00548     if (tw->tree.auto_reconfigure) layout_tree (tw, FALSE);
00549     return (XtGeometryYes);
00550 }
00551 
00552 static void ChangeManaged (gw)
00553     Widget gw;
00554 {
00555     layout_tree ((TreeWidget) gw, FALSE);
00556 }
00557 
00558 
00559 static void Destroy (gw)
00560     Widget gw;
00561 {
00562     TreeWidget w = (TreeWidget) gw;
00563 
00564     XtReleaseGC (gw, w->tree.gc);
00565     if (w->tree.largest) XtFree ((char *) w->tree.largest);
00566 }
00567 
00568 
00569 /* ARGSUSED */
00570 static void Redisplay (gw, event, region)
00571      Widget gw;
00572      XEvent *event;
00573      Region region;
00574 {
00575     TreeWidget tw = (TreeWidget) gw;
00576 
00577     /*
00578      * If the Tree widget is visible, visit each managed child.
00579      */
00580     if (tw->core.visible) {
00581         int i, j;
00582         Display *dpy = XtDisplay (tw);
00583         Window w = XtWindow (tw);
00584 
00585         for (i = 0; i < tw->composite.num_children; i++) {
00586             Widget child = tw->composite.children[i];
00587             TreeConstraints tc = TREE_CONSTRAINT(child);
00588 
00589             /*
00590              * Don't draw lines from the fake tree_root.
00591              */
00592             if (child != tw->tree.tree_root && tc->tree.n_children) {
00593                 int srcx = child->core.x + child->core.border_width;
00594                 int srcy = child->core.y + child->core.border_width;
00595 
00596                 switch (tw->tree.gravity) {
00597                   case WestGravity:
00598                     srcx += child->core.width + child->core.border_width;
00599                     /* fall through */
00600                   case EastGravity:
00601                     srcy += child->core.height / 2;
00602                     break;
00603 
00604                   case NorthGravity:
00605                     srcy += child->core.height + child->core.border_width;
00606                     /* fall through */
00607                   case SouthGravity:
00608                     srcx += child->core.width / 2;
00609                     break;
00610                 }
00611 
00612                 for (j = 0; j < tc->tree.n_children; j++) {
00613                     Widget k = tc->tree.children[j];
00614                     GC gc = (tc->tree.gc ? tc->tree.gc : tw->tree.gc);
00615 
00616                     switch (tw->tree.gravity) {
00617                       case WestGravity:
00618                         /*
00619                          * right center to left center
00620                          */
00621                         XDrawLine (dpy, w, gc, srcx, srcy,
00622                                    (int) k->core.x,
00623                                    (k->core.y + ((int) k->core.border_width) +
00624                                     ((int) k->core.height) / 2));
00625                         break;
00626 
00627                       case NorthGravity:
00628                         /*
00629                          * bottom center to top center
00630                          */
00631                         XDrawLine (dpy, w, gc, srcx, srcy,
00632                                    (k->core.x + ((int) k->core.border_width) +
00633                                     ((int) k->core.width) / 2),
00634                                    (int) k->core.y);
00635                         break;
00636 
00637                       case EastGravity:
00638                         /*
00639                          * left center to right center
00640                          */
00641                         XDrawLine (dpy, w, gc, srcx, srcy,
00642                                    (k->core.x +
00643                                     (((int) k->core.border_width) << 1) +
00644                                     (int) k->core.width),
00645                                    (k->core.y + ((int) k->core.border_width) +
00646                                     ((int) k->core.height) / 2));
00647                         break;
00648 
00649                       case SouthGravity:
00650                         /*
00651                          * top center to bottom center
00652                          */
00653                         XDrawLine (dpy, w, gc, srcx, srcy,
00654                                    (k->core.x + ((int) k->core.border_width) +
00655                                     ((int) k->core.width) / 2),
00656                                    (k->core.y +
00657                                     (((int) k->core.border_width) << 1) +
00658                                     (int) k->core.height));
00659                         break;
00660                     }
00661                 }
00662             }
00663         }
00664     }
00665 }
00666 
00667 static XtGeometryResult QueryGeometry (w, intended, preferred)
00668     Widget w;
00669     XtWidgetGeometry *intended, *preferred;
00670 {
00671     TreeWidget tw = (TreeWidget) w;
00672 
00673     preferred->request_mode = (CWWidth | CWHeight);
00674     preferred->width = tw->tree.maxwidth;
00675     preferred->height = tw->tree.maxheight;
00676 
00677     if (((intended->request_mode & (CWWidth | CWHeight)) ==
00678          (CWWidth | CWHeight)) &&
00679         intended->width == preferred->width &&
00680         intended->height == preferred->height)
00681       return XtGeometryYes;
00682     else if (preferred->width == w->core.width &&
00683              preferred->height == w->core.height)
00684       return XtGeometryNo;
00685     else
00686       return XtGeometryAlmost;
00687 }
00688 
00689 
00690 /*****************************************************************************
00691  *                                                                           *
00692  *                           tree layout algorithm                           *
00693  *                                                                           *
00694  * Each node in the tree is "shrink-wrapped" with a minimal bounding         *
00695  * rectangle, laid next to its siblings (with a small about of padding in    *
00696  * between) and then wrapped with their parent.  Parents are centered about  *
00697  * their children (or vice versa if the parent is larger than the children). *
00698  *                                                                           *
00699  *****************************************************************************/
00700 
00701 static void compute_bounding_box_subtree (tree, w, depth)
00702     TreeWidget tree;
00703     Widget w;
00704     int depth;
00705 {
00706     TreeConstraints tc = TREE_CONSTRAINT(w);  /* info attached to all kids */
00707     int i;
00708     Bool horiz = IsHorizontal (tree);
00709     Dimension newwidth, newheight;
00710     Dimension bw2 = w->core.border_width * 2;
00711 
00712     /*
00713      * Set the max-size per level.
00714      */
00715     if (depth >= tree->tree.n_largest) {
00716         initialize_dimensions (&tree->tree.largest,
00717                                &tree->tree.n_largest, depth + 1);
00718     }
00719     newwidth = ((horiz ? w->core.width : w->core.height) + bw2);
00720     if (tree->tree.largest[depth] < newwidth)
00721       tree->tree.largest[depth] = newwidth;
00722 
00723 
00724     /*
00725      * initialize
00726      */
00727     tc->tree.bbwidth = w->core.width + bw2;
00728     tc->tree.bbheight = w->core.height + bw2;
00729 
00730     if (tc->tree.n_children == 0) return;
00731 
00732     /*
00733      * Figure the size of the opposite dimension (vertical if tree is 
00734      * horizontal, else vice versa).  The other dimension will be set 
00735      * in the second pass once we know the maximum dimensions.
00736      */
00737     newwidth = 0;
00738     newheight = 0;
00739     for (i = 0; i < tc->tree.n_children; i++) {
00740         Widget child = tc->tree.children[i];
00741         TreeConstraints cc = TREE_CONSTRAINT(child);
00742             
00743         compute_bounding_box_subtree (tree, child, depth + 1);
00744 
00745         if (horiz) {
00746             if (newwidth < cc->tree.bbwidth) newwidth = cc->tree.bbwidth;
00747             newheight += tree->tree.vpad + cc->tree.bbheight;
00748         } else {
00749             if (newheight < cc->tree.bbheight) newheight = cc->tree.bbheight;
00750             newwidth += tree->tree.hpad + cc->tree.bbwidth;
00751         }
00752     }
00753 
00754 
00755     tc->tree.bbsubwidth = newwidth;
00756     tc->tree.bbsubheight = newheight;
00757 
00758     /*
00759      * Now fit parent onto side (or top) of bounding box and correct for
00760      * extra padding.  Be careful of unsigned arithmetic.
00761      */
00762     if (horiz) {
00763         tc->tree.bbwidth += tree->tree.hpad + newwidth;
00764         newheight -= tree->tree.vpad;
00765         if (newheight > tc->tree.bbheight) tc->tree.bbheight = newheight;
00766     } else {
00767         tc->tree.bbheight += tree->tree.vpad + newheight;
00768         newwidth -= tree->tree.hpad;
00769         if (newwidth > tc->tree.bbwidth) tc->tree.bbwidth = newwidth;
00770     }
00771 }
00772 
00773 
00774 static void set_positions (tw, w, level)
00775      TreeWidget tw;
00776      Widget w;
00777      int level;
00778 {
00779     int i;
00780   
00781     if (w) {
00782         TreeConstraints tc = TREE_CONSTRAINT(w);
00783 
00784         if (level > 0) {
00785             /*
00786              * mirror if necessary
00787              */
00788             switch (tw->tree.gravity) {
00789               case EastGravity:
00790                 tc->tree.x = (((Position) tw->tree.maxwidth) -
00791                               ((Position) w->core.width) - tc->tree.x);
00792                 break;
00793 
00794               case SouthGravity:
00795                 tc->tree.y = (((Position) tw->tree.maxheight) -
00796                               ((Position) w->core.height) - tc->tree.y);
00797                 break;
00798             }
00799 
00800             /*
00801              * Move the widget into position.
00802              */
00803             XtMoveWidget (w, tc->tree.x, tc->tree.y);
00804         }
00805 
00806         /*
00807          * Set the positions of all children.
00808          */
00809         for (i = 0; i < tc->tree.n_children; i++)
00810           set_positions (tw, tc->tree.children[i], level + 1);
00811     }
00812 }
00813 
00814 
00815 static void arrange_subtree (tree, w, depth, x, y)
00816     TreeWidget tree;
00817     Widget w;
00818     int depth;
00819     Position x, y;
00820 {
00821     TreeConstraints tc = TREE_CONSTRAINT(w);  /* info attached to all kids */
00822     TreeConstraints firstcc, lastcc;
00823     int i;
00824     int newx, newy;
00825     Bool horiz = IsHorizontal (tree);
00826     Widget child = NULL;
00827     Dimension tmp;
00828     Dimension bw2 = w->core.border_width * 2;
00829     Bool relayout = True;
00830 
00831 
00832     /*
00833      * If no children, then just lay out where requested.
00834      */
00835     tc->tree.x = x;
00836     tc->tree.y = y;
00837 
00838     if (horiz) {
00839         int myh = (w->core.height + bw2);
00840 
00841         if (myh > (int)tc->tree.bbsubheight) {
00842             y += (myh - (int)tc->tree.bbsubheight) / 2;
00843             relayout = False;
00844         }
00845     } else {
00846         int myw = (w->core.width + bw2);
00847 
00848         if (myw > (int)tc->tree.bbsubwidth) {
00849             x += (myw - (int)tc->tree.bbsubwidth) / 2;
00850             relayout = False;
00851         }
00852     }
00853 
00854     if ((tmp = ((Dimension) x) + tc->tree.bbwidth) > tree->tree.maxwidth)
00855       tree->tree.maxwidth = tmp;
00856     if ((tmp = ((Dimension) y) + tc->tree.bbheight) > tree->tree.maxheight)
00857       tree->tree.maxheight = tmp;
00858 
00859     if (tc->tree.n_children == 0) return;
00860 
00861 
00862     /*
00863      * Have children, so walk down tree laying out children, then laying
00864      * out parents.
00865      */
00866     if (horiz) {
00867         newx = x + tree->tree.largest[depth];
00868         if (depth > 0) newx += tree->tree.hpad;
00869         newy = y;
00870     } else {
00871         newx = x;
00872         newy = y + tree->tree.largest[depth];
00873         if (depth > 0) newy += tree->tree.vpad;
00874     }
00875 
00876     for (i = 0; i < tc->tree.n_children; i++) {
00877         TreeConstraints cc;
00878 
00879         child = tc->tree.children[i];   /* last value is used outside loop */
00880         cc = TREE_CONSTRAINT(child);
00881 
00882         arrange_subtree (tree, child, depth + 1, newx, newy);
00883         if (horiz) {
00884             newy += tree->tree.vpad + cc->tree.bbheight;
00885         } else {
00886             newx += tree->tree.hpad + cc->tree.bbwidth;
00887         }
00888     }
00889 
00890     /*
00891      * now layout parent between first and last children
00892      */
00893     if (relayout) {
00894         Position adjusted;
00895         firstcc = TREE_CONSTRAINT (tc->tree.children[0]);
00896         lastcc = TREE_CONSTRAINT (child);
00897 
00898         /* Adjustments are disallowed if they result in a position above
00899          * or to the left of the originally requested position, because
00900          * this could collide with the position of the previous sibling.
00901          */
00902         if (horiz) {
00903             tc->tree.x = x;
00904             adjusted = firstcc->tree.y +
00905               ((lastcc->tree.y + (Position) child->core.height + 
00906                 (Position) child->core.border_width * 2 -
00907                 firstcc->tree.y - (Position) w->core.height - 
00908                 (Position) w->core.border_width * 2 + 1) / 2);
00909             if (adjusted > tc->tree.y) tc->tree.y = adjusted;
00910         } else {
00911             adjusted = firstcc->tree.x +
00912               ((lastcc->tree.x + (Position) child->core.width +
00913                 (Position) child->core.border_width * 2 -
00914                 firstcc->tree.x - (Position) w->core.width -
00915                 (Position) w->core.border_width * 2 + 1) / 2);
00916             if (adjusted > tc->tree.x) tc->tree.x = adjusted;
00917             tc->tree.y = y;
00918         }
00919     }
00920 }
00921 
00922 static void set_tree_size (tw, insetvalues, width, height)
00923     TreeWidget tw;
00924     Boolean insetvalues;
00925     Dimension width, height;
00926 {
00927     if (insetvalues) {
00928         tw->core.width = width;
00929         tw->core.height = height;
00930     } else {
00931         Dimension replyWidth = 0, replyHeight = 0;
00932         XtGeometryResult result = XtMakeResizeRequest ((Widget) tw,
00933                                                        width, height,
00934                                                        &replyWidth,
00935                                                        &replyHeight);
00936         /*
00937          * Accept any compromise.
00938          */
00939         if (result == XtGeometryAlmost)
00940           XtMakeResizeRequest ((Widget) tw, replyWidth, replyHeight,
00941                                (Dimension *) NULL, (Dimension *) NULL);
00942     }
00943     return;
00944 }
00945 
00946 static void layout_tree (tw, insetvalues)
00947     TreeWidget tw;
00948     Boolean insetvalues;
00949 {
00950     int i;
00951     Dimension *dp;
00952 
00953     /*
00954      * Do a depth-first search computing the width and height of the bounding
00955      * box for the tree at that position (and below).  Then, walk again using
00956      * this information to layout the children at each level.
00957      */
00958 
00959     if (tw->tree.tree_root == NULL)
00960         return;
00961 
00962     tw->tree.maxwidth = tw->tree.maxheight = 0;
00963     for (i = 0, dp = tw->tree.largest; i < tw->tree.n_largest; i++, dp++)
00964       *dp = 0;
00965     initialize_dimensions (&tw->tree.largest, &tw->tree.n_largest, 
00966                            tw->tree.n_largest);
00967     compute_bounding_box_subtree (tw, tw->tree.tree_root, 0);
00968 
00969    /*
00970     * Second pass to do final layout.  Each child's bounding box is stacked
00971     * on top of (if horizontal, else next to) on top of its siblings.  The
00972     * parent is centered between the first and last children.
00973     */
00974     arrange_subtree (tw, tw->tree.tree_root, 0, 0, 0);
00975 
00976     /*
00977      * Move each widget into place.
00978      */
00979     set_tree_size (tw, insetvalues, tw->tree.maxwidth, tw->tree.maxheight);
00980     set_positions (tw, tw->tree.tree_root, 0);
00981 
00982     /*
00983      * And redisplay.
00984      */
00985     if (XtIsRealized ((Widget) tw)) {
00986         XClearArea (XtDisplay(tw), XtWindow((Widget)tw), 0, 0, 0, 0, True);
00987     }
00988 }
00989 
00990 
00991 
00992 /*****************************************************************************
00993  *                                                                           *
00994  *                              Public Routines                              *
00995  *                                                                           *
00996  *****************************************************************************/
00997 
00998 void
00999 #if NeedFunctionPrototypes
01000 XawTreeForceLayout (Widget tree)
01001 #else
01002 XawTreeForceLayout (tree)
01003     Widget tree;
01004 #endif
01005 {
01006     layout_tree ((TreeWidget) tree, FALSE);
01007 }
01008 

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