home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / lib / Xaw / Tree.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-02-20  |  27.3 KB  |  981 lines

  1. /*
  2.  * $XConsortium: Tree.c,v 1.42 91/02/20 20:06:07 converse Exp $
  3.  *
  4.  * Copyright 1990 Massachusetts Institute of Technology
  5.  * Copyright 1989 Prentice Hall
  6.  *
  7.  * Permission to use, copy, modify, and distribute this software for any
  8.  * purpose and without fee is hereby granted, provided that the above
  9.  * copyright notice appear in all copies and that both the copyright notice
  10.  * and this permission notice appear in supporting documentation.
  11.  * 
  12.  * M.I.T., Prentice Hall and the authors disclaim all warranties with regard
  13.  * to this software, including all implied warranties of merchantability and
  14.  * fitness.  In no event shall M.I.T., Prentice Hall or the authors be liable
  15.  * for any special, indirect or cosequential damages or any damages whatsoever
  16.  * resulting from loss of use, data or profits, whether in an action of
  17.  * contract, negligence or other tortious action, arising out of or in
  18.  * connection with the use or performance of this software.
  19.  * 
  20.  * Authors:  Jim Fulton, MIT X Consortium,
  21.  *           based on a version by Douglas Young, Prentice Hall
  22.  * 
  23.  * This widget is based on the Tree widget described on pages 397-419 of
  24.  * Douglas Young's book "The X Window System, Programming and Applications 
  25.  * with Xt OSF/Motif Edition."  The layout code has been rewritten to use
  26.  * additional blank space to make the structure of the graph easier to see
  27.  * as well as to support vertical trees.
  28.  */
  29.  
  30. #include <X11/Intrinsic.h>
  31. #include <X11/IntrinsicP.h>
  32. #include <X11/StringDefs.h>
  33. #include <X11/CoreP.h>
  34. #include <X11/CompositeP.h>
  35. #include <X11/ConstrainP.h>
  36. #include <X11/Xaw/XawInit.h>
  37. #include <X11/Xaw/Cardinals.h>
  38. #include <X11/Xaw/TreeP.h>
  39.  
  40. #define IsHorizontal(tw) ((tw)->tree.gravity == WestGravity || \
  41.               (tw)->tree.gravity == EastGravity)
  42.  
  43.  
  44.                     /* widget class method */
  45. static void             ClassInitialize();
  46. static void             Initialize();
  47. static void             ConstraintInitialize();
  48. static void             ConstraintDestroy();
  49. static Boolean          ConstraintSetValues();
  50. static void             Destroy();
  51. static Boolean          SetValues();
  52. static XtGeometryResult GeometryManager();
  53. static void             ChangeManaged();
  54. static void             Redisplay();
  55. static XtGeometryResult    QueryGeometry();
  56.  
  57.                     /* utility routines */
  58. static void             insert_node();
  59. static void             delete_node();
  60. static void             layout_tree();
  61.  
  62.  
  63. /*
  64.  * resources of the tree itself
  65.  */
  66. static XtResource resources[] = {
  67.     { XtNautoReconfigure, XtCAutoReconfigure, XtRBoolean, sizeof (Boolean),
  68.     XtOffsetOf(TreeRec, tree.auto_reconfigure), XtRImmediate,
  69.     (XtPointer) FALSE },
  70.     { XtNhSpace, XtCHSpace, XtRDimension, sizeof (Dimension),
  71.     XtOffsetOf(TreeRec, tree.hpad), XtRImmediate, (XtPointer) 0 },
  72.     { XtNvSpace, XtCVSpace, XtRDimension, sizeof (Dimension),
  73.     XtOffsetOf(TreeRec, tree.vpad), XtRImmediate, (XtPointer) 0 },
  74.     { XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel),
  75.     XtOffsetOf(TreeRec, tree.foreground), XtRString,
  76.     XtDefaultForeground},
  77.     { XtNlineWidth, XtCLineWidth, XtRDimension, sizeof (Dimension),
  78.     XtOffsetOf(TreeRec, tree.line_width), XtRImmediate, (XtPointer) 0 },
  79.     { XtNgravity, XtCGravity, XtRGravity, sizeof (XtGravity),
  80.     XtOffsetOf(TreeRec, tree.gravity), XtRImmediate,
  81.     (XtPointer) WestGravity },
  82. };
  83.  
  84.  
  85. /*
  86.  * resources that are attached to all children of the tree
  87.  */
  88. static XtResource treeConstraintResources[] = {
  89.     { XtNtreeParent, XtCTreeParent, XtRWidget, sizeof (Widget),
  90.     XtOffsetOf(TreeConstraintsRec, tree.parent), XtRImmediate, NULL },
  91.     { XtNtreeGC, XtCTreeGC, XtRGC, sizeof(GC),
  92.     XtOffsetOf(TreeConstraintsRec, tree.gc), XtRImmediate, NULL },
  93. };
  94.  
  95.  
  96. TreeClassRec treeClassRec = {
  97.   {
  98.                     /* core_class fields  */
  99.     (WidgetClass) &constraintClassRec,    /* superclass         */
  100.     "Tree",                /* class_name         */
  101.     sizeof(TreeRec),            /* widget_size        */
  102.     ClassInitialize,            /* class_init         */
  103.     NULL,                /* class_part_init    */
  104.     FALSE,                /* class_inited       */    
  105.     Initialize,                /* initialize         */
  106.     NULL,                /* initialize_hook    */    
  107.     XtInheritRealize,            /* realize            */
  108.     NULL,                /* actions            */
  109.     0,                    /* num_actions        */    
  110.     resources,                /* resources          */
  111.     XtNumber(resources),        /* num_resources      */
  112.     NULLQUARK,                /* xrm_class          */
  113.     TRUE,                /* compress_motion    */    
  114.     TRUE,                /* compress_exposure  */    
  115.     TRUE,                /* compress_enterleave*/    
  116.     TRUE,                /* visible_interest   */
  117.     Destroy,                /* destroy            */
  118.     NULL,                /* resize             */
  119.     Redisplay,                /* expose             */
  120.     SetValues,                /* set_values         */
  121.     NULL,                /* set_values_hook    */    
  122.     XtInheritSetValuesAlmost,        /* set_values_almost  */
  123.     NULL,                /* get_values_hook    */    
  124.     NULL,                /* accept_focus       */
  125.     XtVersion,                /* version            */    
  126.     NULL,                /* callback_private   */
  127.     NULL,                /* tm_table           */
  128.     QueryGeometry,            /* query_geometry     */    
  129.     NULL,                /* display_accelerator*/
  130.     NULL,                /* extension          */
  131.   },
  132.   {
  133.                     /* composite_class fields */
  134.     GeometryManager,            /* geometry_manager    */
  135.     ChangeManaged,            /* change_managed      */
  136.     XtInheritInsertChild,        /* insert_child        */    
  137.     XtInheritDeleteChild,        /* delete_child        */    
  138.     NULL,                /* extension           */
  139.   },
  140.   { 
  141.                     /* constraint_class fields */
  142.    treeConstraintResources,        /* subresources        */
  143.    XtNumber(treeConstraintResources),    /* subresource_count   */
  144.    sizeof(TreeConstraintsRec),        /* constraint_size     */
  145.    ConstraintInitialize,        /* initialize          */
  146.    ConstraintDestroy,            /* destroy             */
  147.    ConstraintSetValues,            /* set_values          */
  148.    NULL,                /* extension           */
  149.    },
  150.   {
  151.                     /* Tree class fields */
  152.     0,                    /* ignore              */    
  153.   }
  154. };
  155.  
  156. WidgetClass treeWidgetClass = (WidgetClass) &treeClassRec;
  157.  
  158.  
  159. /*****************************************************************************
  160.  *                                                                           *
  161.  *                 tree utility routines                           *
  162.  *                                                                           *
  163.  *****************************************************************************/
  164.  
  165. static void initialize_dimensions (listp, sizep, n)
  166.     Dimension **listp;
  167.     int *sizep;
  168.     int n;
  169. {
  170.     register int i;
  171.     register Dimension *l;
  172.  
  173.     if (!*listp) {
  174.     *listp = (Dimension *) XtCalloc ((unsigned int) n,
  175.                      (unsigned int) sizeof(Dimension));
  176.     *sizep = ((*listp) ? n : 0);
  177.     return;
  178.     }
  179.     if (n > *sizep) {
  180.     *listp = (Dimension *) XtRealloc((char *) *listp,
  181.                      (unsigned int) (n*sizeof(Dimension)));
  182.     if (!*listp) {
  183.         *sizep = 0;
  184.         return;
  185.     }
  186.     for (i = *sizep, l = (*listp) + i; i < n; i++, l++) *l = 0;
  187.     *sizep = n;
  188.     }
  189.     return;
  190. }
  191.  
  192. static GC get_tree_gc (w)
  193.     TreeWidget w;
  194. {
  195.     XtGCMask valuemask = GCBackground | GCForeground;
  196.     XGCValues values;
  197.  
  198.     values.background = w->core.background_pixel;
  199.     values.foreground = w->tree.foreground;
  200.     if (w->tree.line_width != 0) {
  201.     valuemask |= GCLineWidth;
  202.     values.line_width = w->tree.line_width;
  203.     }
  204.  
  205.     return XtGetGC ((Widget) w, valuemask, &values);
  206. }
  207.  
  208. static void insert_node (parent, node)
  209.      Widget parent, node;
  210. {
  211.     TreeConstraints pc;
  212.     TreeConstraints nc = TREE_CONSTRAINT(node);
  213.     int nindex;
  214.   
  215.     nc->tree.parent = parent;
  216.  
  217.     if (parent == NULL) return;
  218.  
  219.     /*
  220.      * If there isn't more room in the children array, 
  221.      * allocate additional space.
  222.      */  
  223.     pc = TREE_CONSTRAINT(parent);
  224.     nindex = pc->tree.n_children;
  225.   
  226.     if (pc->tree.n_children == pc->tree.max_children) {
  227.     pc->tree.max_children += (pc->tree.max_children / 2) + 2;
  228.     pc->tree.children = (WidgetList) XtRealloc ((char *)pc->tree.children, 
  229.                             (unsigned int)
  230.                             ((pc->tree.max_children) *
  231.                             sizeof(Widget)));
  232.     } 
  233.  
  234.     /*
  235.      * Add the sub_node in the next available slot and 
  236.      * increment the counter.
  237.      */
  238.     pc->tree.children[nindex] = node;
  239.     pc->tree.n_children++;
  240. }
  241.  
  242. static void delete_node (parent, node)
  243.     Widget parent, node;
  244. {
  245.     TreeConstraints pc;
  246.     int pos, i;
  247.  
  248.     /*
  249.      * Make sure the parent exists.
  250.      */
  251.     if (!parent) return;  
  252.   
  253.     pc = TREE_CONSTRAINT(parent);
  254.  
  255.     /*
  256.      * Find the sub_node on its parent's list.
  257.      */
  258.     for (pos = 0; pos < pc->tree.n_children; pos++)
  259.       if (pc->tree.children[pos] == node) break;
  260.  
  261.     if (pos == pc->tree.n_children) return;
  262.  
  263.     /*
  264.      * Decrement the number of children
  265.      */  
  266.     pc->tree.n_children--;
  267.  
  268.     /*
  269.      * Fill in the gap left by the sub_node.
  270.      * Zero the last slot for good luck.
  271.      */
  272.     for (i = pos; i < pc->tree.n_children; i++) 
  273.       pc->tree.children[i] = pc->tree.children[i+1];
  274.  
  275.     pc->tree.children[pc->tree.n_children]=0;
  276. }
  277.  
  278. static void check_gravity (tw, grav)
  279.     TreeWidget tw;
  280.     XtGravity grav;
  281. {
  282.     switch (tw->tree.gravity) {
  283.       case WestGravity: case NorthGravity: case EastGravity: case SouthGravity:
  284.     break;
  285.       default:
  286.     tw->tree.gravity = grav;
  287.     break;
  288.     }
  289. }
  290.  
  291.  
  292. /*****************************************************************************
  293.  *                                                                           *
  294.  *                   tree class methods                             *
  295.  *                                                                           *
  296.  *****************************************************************************/
  297.  
  298. static void ClassInitialize ()
  299. {
  300.     XawInitializeWidgetSet();
  301.     XtAddConverter (XtRString, XtRGravity, XmuCvtStringToGravity,
  302.             (XtConvertArgList) NULL, (Cardinal) 0);
  303. }
  304.  
  305.  
  306. static void Initialize (grequest, gnew)
  307.     Widget grequest, gnew;
  308. {
  309.     TreeWidget request = (TreeWidget) grequest, new = (TreeWidget) gnew;
  310.     Arg args[2];
  311.  
  312.     /*
  313.      * Make sure the widget's width and height are 
  314.      * greater than zero.
  315.      */
  316.     if (request->core.width <= 0) new->core.width = 5;
  317.     if (request->core.height <= 0) new->core.height = 5;
  318.  
  319.     /*
  320.      * Set the padding according to the orientation
  321.      */
  322.     if (request->tree.hpad == 0 && request->tree.vpad == 0) {
  323.     if (IsHorizontal (request)) {
  324.         new->tree.hpad = TREE_HORIZONTAL_DEFAULT_SPACING;
  325.         new->tree.vpad = TREE_VERTICAL_DEFAULT_SPACING;
  326.     } else {
  327.         new->tree.hpad = TREE_VERTICAL_DEFAULT_SPACING;
  328.         new->tree.vpad = TREE_HORIZONTAL_DEFAULT_SPACING;
  329.     }
  330.     }
  331.  
  332.     /*
  333.      * Create a graphics context for the connecting lines.
  334.      */
  335.     new->tree.gc = get_tree_gc (new);
  336.  
  337.     /*
  338.      * Create the hidden root widget.
  339.      */
  340.     new->tree.tree_root = (Widget) NULL;
  341.     XtSetArg(args[0], XtNwidth, 1);
  342.     XtSetArg(args[1], XtNheight, 1);
  343.     new->tree.tree_root = XtCreateWidget ("root", widgetClass, gnew, args,TWO);
  344.  
  345.     /*
  346.      * Allocate the array used to hold the widest values per depth
  347.      */
  348.     new->tree.largest = NULL;
  349.     new->tree.n_largest = 0;
  350.     initialize_dimensions (&new->tree.largest, &new->tree.n_largest, 
  351.                TREE_INITIAL_DEPTH);
  352.  
  353.     /*
  354.      * make sure that our gravity is one of the acceptable values
  355.      */
  356.     check_gravity (new, WestGravity);
  357.  
  358.  
  359. /* ARGSUSED */
  360. static void ConstraintInitialize (request, new)
  361.      Widget request, new;
  362. {
  363.     TreeConstraints tc = TREE_CONSTRAINT(new);
  364.     TreeWidget tw = (TreeWidget) new->core.parent;
  365.  
  366.     /*
  367.      * Initialize the widget to have no sub-nodes.
  368.      */
  369.     tc->tree.n_children = 0;
  370.     tc->tree.max_children = 0;
  371.     tc->tree.children = (Widget *) NULL;
  372.     tc->tree.x = tc->tree.y = 0; 
  373.     tc->tree.bbsubwidth = 0;
  374.     tc->tree.bbsubheight = 0;
  375.  
  376.  
  377.     /*
  378.      * If this widget has a super-node, add it to that 
  379.      * widget' sub-nodes list. Otherwise make it a sub-node of 
  380.      * the tree_root widget.
  381.      */
  382.     if (tc->tree.parent)
  383.       insert_node (tc->tree.parent, new);
  384.     else if (tw->tree.tree_root)
  385.       insert_node (tw->tree.tree_root, new);
  386.  
  387.  
  388. /* ARGSUSED */
  389. static Boolean SetValues (gcurrent, grequest, gnew)
  390.     Widget gcurrent, grequest, gnew;
  391. {
  392.     TreeWidget current = (TreeWidget) gcurrent, new = (TreeWidget) gnew;
  393.     Boolean redraw = FALSE;
  394.  
  395.     /*
  396.      * If the foreground color has changed, redo the GC's
  397.      * and indicate a redraw.
  398.      */
  399.     if (new->tree.foreground != current->tree.foreground ||
  400.     new->core.background_pixel != current->core.background_pixel ||
  401.     new->tree.line_width != current->tree.line_width) {
  402.     XtReleaseGC (gnew, new->tree.gc);
  403.     new->tree.gc = get_tree_gc (new);
  404.     redraw = TRUE;     
  405.     }
  406.  
  407.     /*
  408.      * If the minimum spacing has changed, recalculate the
  409.      * tree layout. layout_tree() does a redraw, so we don't
  410.      * need SetValues to do another one.
  411.      */
  412.     if (new->tree.gravity != current->tree.gravity) {
  413.     check_gravity (new, current->tree.gravity);
  414.     }
  415.  
  416.     if (IsHorizontal(new) != IsHorizontal(current)) {
  417.     if (new->tree.vpad == current->tree.vpad &&
  418.         new->tree.hpad == current->tree.hpad) {
  419.         new->tree.vpad = current->tree.hpad;
  420.         new->tree.hpad = current->tree.vpad;
  421.     }
  422.     }
  423.  
  424.     if (new->tree.vpad != current->tree.vpad ||
  425.     new->tree.hpad != current->tree.hpad ||
  426.     new->tree.gravity != current->tree.gravity) {
  427.     layout_tree (new, TRUE);
  428.     redraw = FALSE;
  429.     }
  430.     return redraw;
  431. }
  432.  
  433.  
  434. /* ARGSUSED */
  435. static Boolean ConstraintSetValues (current, request, new, args, num_args)
  436.     Widget current, request, new;
  437.     ArgList args;
  438.     Cardinal *num_args;
  439. {
  440.     TreeConstraints newc = TREE_CONSTRAINT(new);
  441.     TreeConstraints curc = TREE_CONSTRAINT(current);
  442.     TreeWidget tw = (TreeWidget) new->core.parent;
  443.  
  444.     /*
  445.      * If the parent field has changed, remove the widget
  446.      * from the old widget's children list and add it to the
  447.      * new one.
  448.      */
  449.     if (curc->tree.parent != newc->tree.parent){
  450.     if (curc->tree.parent)
  451.       delete_node (curc->tree.parent, new);
  452.     if (newc->tree.parent)
  453.       insert_node(newc->tree.parent, new);
  454.  
  455.     /*
  456.      * If the Tree widget has been realized, 
  457.      * compute new layout.
  458.      */
  459.     if (XtIsRealized((Widget)tw))
  460.       layout_tree (tw, FALSE);
  461.     }
  462.     return False;
  463. }
  464.  
  465.  
  466. static void ConstraintDestroy (w) 
  467.     Widget w;
  468.     TreeConstraints tc = TREE_CONSTRAINT(w);
  469.     TreeWidget tw = (TreeWidget) XtParent(w);
  470.     int i;
  471.  
  472.     /* 
  473.      * Remove the widget from its parent's sub-nodes list and
  474.      * make all this widget's sub-nodes sub-nodes of the parent.
  475.      */
  476.   
  477.     if (tw->tree.tree_root == w) {
  478.     if (tc->tree.n_children > 0)
  479.       tw->tree.tree_root = tc->tree.children[0];
  480.     else
  481.       tw->tree.tree_root = NULL;
  482.     }
  483.  
  484.     delete_node (tc->tree.parent, (Widget) w);
  485.     for (i = 0; i< tc->tree.n_children; i++)
  486.       insert_node (tc->tree.parent, tc->tree.children[i]);
  487.  
  488.     layout_tree ((TreeWidget) (w->core.parent), FALSE);
  489. }
  490.  
  491. /* ARGSUSED */
  492. static XtGeometryResult GeometryManager (w, request, reply)
  493.     Widget w;
  494.     XtWidgetGeometry *request;
  495.     XtWidgetGeometry *reply;
  496. {
  497.  
  498.     TreeWidget tw = (TreeWidget) w->core.parent;
  499.  
  500.     /*
  501.      * No position changes allowed!.
  502.      */
  503.     if ((request->request_mode & CWX && request->x!=w->core.x)
  504.     ||(request->request_mode & CWY && request->y!=w->core.y))
  505.       return (XtGeometryNo);
  506.  
  507.     /*
  508.      * Allow all resize requests.
  509.      */
  510.  
  511.     if (request->request_mode & CWWidth)
  512.       w->core.width = request->width;
  513.     if (request->request_mode & CWHeight)
  514.       w->core.height = request->height;
  515.     if (request->request_mode & CWBorderWidth)
  516.       w->core.border_width = request->border_width;
  517.  
  518.     if (tw->tree.auto_reconfigure) layout_tree (tw, FALSE);
  519.     return (XtGeometryYes);
  520. }
  521.  
  522. static void ChangeManaged (gw)
  523.     Widget gw;
  524. {
  525.     layout_tree ((TreeWidget) gw, FALSE);
  526. }
  527.  
  528.  
  529. static void Destroy (gw)
  530.     Widget gw;
  531. {
  532.     TreeWidget w = (TreeWidget) gw;
  533.  
  534.     XtReleaseGC (gw, w->tree.gc);
  535.     if (w->tree.largest) XtFree ((char *) w->tree.largest);
  536. }
  537.  
  538.  
  539. /* ARGSUSED */
  540. static void Redisplay (tw, event, region)
  541.      TreeWidget tw;
  542.      XEvent *event;
  543.      Region region;
  544. {
  545.     /*
  546.      * If the Tree widget is visible, visit each managed child.
  547.      */
  548.     if (tw->core.visible) {
  549.     int i, j;
  550.     Display *dpy = XtDisplay (tw);
  551.     Window w = XtWindow (tw);
  552.  
  553.     for (i = 0; i < tw->composite.num_children; i++) {
  554.         register Widget child = tw->composite.children[i];
  555.         TreeConstraints tc = TREE_CONSTRAINT(child);
  556.  
  557.         /*
  558.          * Don't draw lines from the fake tree_root.
  559.          */
  560.         if (child != tw->tree.tree_root && tc->tree.n_children) {
  561.         int srcx = child->core.x + child->core.border_width;
  562.         int srcy = child->core.y + child->core.border_width;
  563.  
  564.         switch (tw->tree.gravity) {
  565.           case WestGravity:
  566.             srcx += child->core.width + child->core.border_width;
  567.             /* fall through */
  568.           case EastGravity:
  569.             srcy += child->core.height / 2;
  570.             break;
  571.  
  572.           case NorthGravity:
  573.             srcy += child->core.height + child->core.border_width;
  574.             /* fall through */
  575.           case SouthGravity:
  576.             srcx += child->core.width / 2;
  577.             break;
  578.         }
  579.  
  580.         for (j = 0; j < tc->tree.n_children; j++) {
  581.             register Widget k = tc->tree.children[j];
  582.             GC gc = (tc->tree.gc ? tc->tree.gc : tw->tree.gc);
  583.  
  584.             switch (tw->tree.gravity) {
  585.               case WestGravity:
  586.             /*
  587.              * right center to left center
  588.              */
  589.             XDrawLine (dpy, w, gc, srcx, srcy,
  590.                    (int) k->core.x,
  591.                    (k->core.y + ((int) k->core.border_width) +
  592.                     ((int) k->core.height) / 2));
  593.             break;
  594.  
  595.               case NorthGravity:
  596.             /*
  597.              * bottom center to top center
  598.              */
  599.             XDrawLine (dpy, w, gc, srcx, srcy,
  600.                    (k->core.x + ((int) k->core.border_width) +
  601.                     ((int) k->core.width) / 2),
  602.                    (int) k->core.y);
  603.             break;
  604.  
  605.               case EastGravity:
  606.             /*
  607.              * left center to right center
  608.              */
  609.             XDrawLine (dpy, w, gc, srcx, srcy,
  610.                    (k->core.x +
  611.                     (((int) k->core.border_width) << 1) +
  612.                     (int) k->core.width),
  613.                    (k->core.y + ((int) k->core.border_width) +
  614.                     ((int) k->core.height) / 2));
  615.             break;
  616.  
  617.               case SouthGravity:
  618.             /*
  619.              * top center to bottom center
  620.              */
  621.             XDrawLine (dpy, w, gc, srcx, srcy,
  622.                    (k->core.x + ((int) k->core.border_width) +
  623.                     ((int) k->core.width) / 2),
  624.                    (k->core.y +
  625.                     (((int) k->core.border_width) << 1) +
  626.                     (int) k->core.height));
  627.             break;
  628.             }
  629.         }
  630.         }
  631.     }
  632.     }
  633. }
  634.  
  635. static XtGeometryResult QueryGeometry (w, intended, preferred)
  636.     Widget w;
  637.     XtWidgetGeometry *intended, *preferred;
  638. {
  639.     register TreeWidget tw = (TreeWidget) w;
  640.  
  641.     preferred->request_mode = (CWWidth | CWHeight);
  642.     preferred->width = tw->tree.maxwidth;
  643.     preferred->height = tw->tree.maxheight;
  644.  
  645.     if (((intended->request_mode & (CWWidth | CWHeight)) ==
  646.      (CWWidth | CWHeight)) &&
  647.     intended->width == preferred->width &&
  648.     intended->height == preferred->height)
  649.       return XtGeometryYes;
  650.     else if (preferred->width == w->core.width &&
  651.              preferred->height == w->core.height)
  652.       return XtGeometryNo;
  653.     else
  654.       return XtGeometryAlmost;
  655. }
  656.  
  657.  
  658. /*****************************************************************************
  659.  *                                                                           *
  660.  *                 tree layout algorithm                           *
  661.  *                                                                           *
  662.  * Each node in the tree is "shrink-wrapped" with a minimal bounding         *
  663.  * rectangle, laid next to its siblings (with a small about of padding in    *
  664.  * between) and then wrapped with their parent.  Parents are centered about  *
  665.  * their children (or vice versa if the parent is larger than the children). *
  666.  *                                                                           *
  667.  *****************************************************************************/
  668.  
  669. static void compute_bounding_box_subtree (tree, w, depth)
  670.     TreeWidget tree;
  671.     Widget w;
  672.     int depth;
  673. {
  674.     TreeConstraints tc = TREE_CONSTRAINT(w);  /* info attached to all kids */
  675.     register int i;
  676.     Bool horiz = IsHorizontal (tree);
  677.     Dimension newwidth, newheight;
  678.     Dimension bw2 = w->core.border_width * 2;
  679.  
  680.     /*
  681.      * Set the max-size per level.
  682.      */
  683.     if (depth >= tree->tree.n_largest) {
  684.     initialize_dimensions (&tree->tree.largest,
  685.                    &tree->tree.n_largest, depth + 1);
  686.     }
  687.     newwidth = ((horiz ? w->core.width : w->core.height) + bw2);
  688.     if (tree->tree.largest[depth] < newwidth)
  689.       tree->tree.largest[depth] = newwidth;
  690.  
  691.  
  692.     /*
  693.      * initialize
  694.      */
  695.     tc->tree.bbwidth = w->core.width + bw2;
  696.     tc->tree.bbheight = w->core.height + bw2;
  697.  
  698.     if (tc->tree.n_children == 0) return;
  699.  
  700.     /*
  701.      * Figure the size of the opposite dimension (vertical if tree is 
  702.      * horizontal, else vice versa).  The other dimension will be set 
  703.      * in the second pass once we know the maximum dimensions.
  704.      */
  705.     newwidth = 0;
  706.     newheight = 0;
  707.     for (i = 0; i < tc->tree.n_children; i++) {
  708.     Widget child = tc->tree.children[i];
  709.     TreeConstraints cc = TREE_CONSTRAINT(child);
  710.         
  711.     compute_bounding_box_subtree (tree, child, depth + 1);
  712.  
  713.     if (horiz) {
  714.         if (newwidth < cc->tree.bbwidth) newwidth = cc->tree.bbwidth;
  715.         newheight += tree->tree.vpad + cc->tree.bbheight;
  716.     } else {
  717.         if (newheight < cc->tree.bbheight) newheight = cc->tree.bbheight;
  718.         newwidth += tree->tree.hpad + cc->tree.bbwidth;
  719.     }
  720.     }
  721.  
  722.  
  723.     tc->tree.bbsubwidth = newwidth;
  724.     tc->tree.bbsubheight = newheight;
  725.  
  726.     /*
  727.      * Now fit parent onto side (or top) of bounding box and correct for
  728.      * extra padding.  Be careful of unsigned arithmetic.
  729.      */
  730.     if (horiz) {
  731.     tc->tree.bbwidth += tree->tree.hpad + newwidth;
  732.     newheight -= tree->tree.vpad;
  733.     if (newheight > tc->tree.bbheight) tc->tree.bbheight = newheight;
  734.     } else {
  735.     tc->tree.bbheight += tree->tree.vpad + newheight;
  736.     newwidth -= tree->tree.hpad;
  737.     if (newwidth > tc->tree.bbwidth) tc->tree.bbwidth = newwidth;
  738.     }
  739. }
  740.  
  741.  
  742. static void set_positions (tw, w, level)
  743.      TreeWidget tw;
  744.      Widget w;
  745.      int level;
  746. {
  747.     int i;
  748.   
  749.     if (w) {
  750.     TreeConstraints tc = TREE_CONSTRAINT(w);
  751.  
  752.     if (level > 0) {
  753.         /*
  754.          * mirror if necessary
  755.          */
  756.         switch (tw->tree.gravity) {
  757.           case EastGravity:
  758.         tc->tree.x = (((Position) tw->tree.maxwidth) -
  759.                   ((Position) w->core.width) - tc->tree.x);
  760.         break;
  761.  
  762.           case SouthGravity:
  763.         tc->tree.y = (((Position) tw->tree.maxheight) -
  764.                   ((Position) w->core.height) - tc->tree.y);
  765.         break;
  766.         }
  767.  
  768.         /*
  769.          * Move the widget into position.
  770.          */
  771.         XtMoveWidget (w, tc->tree.x, tc->tree.y);
  772.     }
  773.  
  774.     /*
  775.      * Set the positions of all children.
  776.      */
  777.     for (i = 0; i < tc->tree.n_children; i++)
  778.       set_positions (tw, tc->tree.children[i], level + 1);
  779.     }
  780. }
  781.  
  782.  
  783. static void arrange_subtree (tree, w, depth, x, y)
  784.     TreeWidget tree;
  785.     Widget w;
  786.     int depth;
  787.     Position x, y;
  788. {
  789.     TreeConstraints tc = TREE_CONSTRAINT(w);  /* info attached to all kids */
  790.     TreeConstraints firstcc, lastcc;
  791.     register int i;
  792.     int newx, newy;
  793.     Bool horiz = IsHorizontal (tree);
  794.     Widget child = NULL;
  795.     Dimension tmp;
  796.     Dimension bw2 = w->core.border_width * 2;
  797.     Bool relayout = True;
  798.  
  799.  
  800.     /*
  801.      * If no children, then just lay out where requested.
  802.      */
  803.     tc->tree.x = x;
  804.     tc->tree.y = y;
  805.  
  806.     if (horiz) {
  807.     int myh = (w->core.height + bw2);
  808.  
  809.     if (myh > (int)tc->tree.bbsubheight) {
  810.         y += (myh - (int)tc->tree.bbsubheight) / 2;
  811.         relayout = False;
  812.     }
  813.     } else {
  814.     int myw = (w->core.width + bw2);
  815.  
  816.     if (myw > (int)tc->tree.bbsubwidth) {
  817.         x += (myw - (int)tc->tree.bbsubwidth) / 2;
  818.         relayout = False;
  819.     }
  820.     }
  821.  
  822.     if ((tmp = ((Dimension) x) + tc->tree.bbwidth) > tree->tree.maxwidth)
  823.       tree->tree.maxwidth = tmp;
  824.     if ((tmp = ((Dimension) y) + tc->tree.bbheight) > tree->tree.maxheight)
  825.       tree->tree.maxheight = tmp;
  826.  
  827.     if (tc->tree.n_children == 0) return;
  828.  
  829.  
  830.     /*
  831.      * Have children, so walk down tree laying out children, then laying
  832.      * out parents.
  833.      */
  834.     if (horiz) {
  835.     newx = x + tree->tree.largest[depth];
  836.     if (depth > 0) newx += tree->tree.hpad;
  837.     newy = y;
  838.     } else {
  839.     newx = x;
  840.     newy = y + tree->tree.largest[depth];
  841.     if (depth > 0) newy += tree->tree.vpad;
  842.     }
  843.  
  844.     for (i = 0; i < tc->tree.n_children; i++) {
  845.     TreeConstraints cc;
  846.  
  847.     child = tc->tree.children[i];    /* last value is used outside loop */
  848.     cc = TREE_CONSTRAINT(child);
  849.  
  850.     arrange_subtree (tree, child, depth + 1, newx, newy);
  851.     if (horiz) {
  852.         newy += tree->tree.vpad + cc->tree.bbheight;
  853.     } else {
  854.         newx += tree->tree.hpad + cc->tree.bbwidth;
  855.     }
  856.     }
  857.  
  858.     /*
  859.      * now layout parent between first and last children
  860.      */
  861.     if (relayout) {
  862.     Position adjusted;
  863.     firstcc = TREE_CONSTRAINT (tc->tree.children[0]);
  864.     lastcc = TREE_CONSTRAINT (child);
  865.  
  866.     /* Adjustments are disallowed if they result in a position above
  867.          * or to the left of the originally requested position, because
  868.      * this could collide with the position of the previous sibling.
  869.      */
  870.     if (horiz) {
  871.         tc->tree.x = x;
  872.         adjusted = firstcc->tree.y +
  873.           ((lastcc->tree.y + (Position) child->core.height + 
  874.         (Position) child->core.border_width * 2 -
  875.         firstcc->tree.y - (Position) w->core.height - 
  876.         (Position) w->core.border_width * 2 + 1) / 2);
  877.         if (adjusted > tc->tree.y) tc->tree.y = adjusted;
  878.     } else {
  879.         adjusted = firstcc->tree.x +
  880.           ((lastcc->tree.x + (Position) child->core.width +
  881.         (Position) child->core.border_width * 2 -
  882.         firstcc->tree.x - (Position) w->core.width -
  883.         (Position) w->core.border_width * 2 + 1) / 2);
  884.         if (adjusted > tc->tree.x) tc->tree.x = adjusted;
  885.         tc->tree.y = y;
  886.     }
  887.     }
  888. }
  889.  
  890. static void set_tree_size (tw, insetvalues, width, height)
  891.     TreeWidget tw;
  892.     Boolean insetvalues;
  893.     Dimension width, height;
  894. {
  895.     if (insetvalues) {
  896.     tw->core.width = width;
  897.     tw->core.height = height;
  898.     } else {
  899.     Dimension replyWidth = 0, replyHeight = 0;
  900.     XtGeometryResult result = XtMakeResizeRequest ((Widget) tw,
  901.                                width, height,
  902.                                &replyWidth,
  903.                                &replyHeight);
  904.     /*
  905.      * Accept any compromise.
  906.      */
  907.     if (result == XtGeometryAlmost)
  908.       XtMakeResizeRequest ((Widget) tw, replyWidth, replyHeight,
  909.                    (Dimension *) NULL, (Dimension *) NULL);
  910.     }
  911.     return;
  912. }
  913.  
  914. static void layout_tree (tw, insetvalues)
  915.     TreeWidget tw;
  916.     Boolean insetvalues;
  917. {
  918.     int i;
  919.     Dimension *dp;
  920.  
  921.     /*
  922.      * Do a depth-first search computing the width and height of the bounding
  923.      * box for the tree at that position (and below).  Then, walk again using
  924.      * this information to layout the children at each level.
  925.      */
  926.  
  927.     if (tw->tree.tree_root == NULL)
  928.     return;
  929.  
  930.     tw->tree.maxwidth = tw->tree.maxheight = 0;
  931.     for (i = 0, dp = tw->tree.largest; i < tw->tree.n_largest; i++, dp++)
  932.       *dp = 0;
  933.     initialize_dimensions (&tw->tree.largest, &tw->tree.n_largest, 
  934.                tw->tree.n_largest);
  935.     compute_bounding_box_subtree (tw, tw->tree.tree_root, 0);
  936.  
  937.    /*
  938.     * Second pass to do final layout.  Each child's bounding box is stacked
  939.     * on top of (if horizontal, else next to) on top of its siblings.  The
  940.     * parent is centered between the first and last children.
  941.     */
  942.     arrange_subtree (tw, tw->tree.tree_root, 0, 0, 0);
  943.  
  944.     /*
  945.      * Move each widget into place.
  946.      */
  947.     set_tree_size (tw, insetvalues, tw->tree.maxwidth, tw->tree.maxheight);
  948.     set_positions (tw, tw->tree.tree_root, 0);
  949.  
  950.     /*
  951.      * And redisplay.
  952.      */
  953.     if (XtIsRealized ((Widget) tw)) {
  954.     XClearArea (XtDisplay(tw), XtWindow((Widget)tw), 0, 0, 0, 0, True);
  955.     }
  956. }
  957.  
  958.  
  959.  
  960. /*****************************************************************************
  961.  *                                                                           *
  962.  *                 Public Routines                              *
  963.  *                                                                           *
  964.  *****************************************************************************/
  965.  
  966. void
  967. #if NeedFunctionPrototypes
  968. XawTreeForceLayout (Widget tree)
  969. #else
  970. XawTreeForceLayout (tree)
  971.     Widget tree;
  972. #endif
  973. {
  974.     layout_tree ((TreeWidget) tree, FALSE);
  975. }
  976.  
  977.  
  978.