Tree.c revision 7a84e134
17a84e134Smrg/*
27a84e134Smrg * $Xorg: Tree.c,v 1.4 2001/02/09 02:03:47 xorgcvs Exp $
37a84e134Smrg *
47a84e134Smrg
57a84e134SmrgCopyright 1990, 1994, 1998  The Open Group
67a84e134Smrg
77a84e134SmrgPermission to use, copy, modify, distribute, and sell this software and its
87a84e134Smrgdocumentation for any purpose is hereby granted without fee, provided that
97a84e134Smrgthe above copyright notice appear in all copies and that both that
107a84e134Smrgcopyright notice and this permission notice appear in supporting
117a84e134Smrgdocumentation.
127a84e134Smrg
137a84e134SmrgThe above copyright notice and this permission notice shall be included in
147a84e134Smrgall copies or substantial portions of the Software.
157a84e134Smrg
167a84e134SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
177a84e134SmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
187a84e134SmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
197a84e134SmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
207a84e134SmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
217a84e134SmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
227a84e134Smrg
237a84e134SmrgExcept as contained in this notice, the name of The Open Group shall not be
247a84e134Smrgused in advertising or otherwise to promote the sale, use or other dealings
257a84e134Smrgin this Software without prior written authorization from The Open Group.
267a84e134Smrg
277a84e134Smrg * Copyright 1989 Prentice Hall
287a84e134Smrg *
297a84e134Smrg * Permission to use, copy, modify, and distribute this software for any
307a84e134Smrg * purpose and without fee is hereby granted, provided that the above
317a84e134Smrg * copyright notice appear in all copies and that both the copyright notice
327a84e134Smrg * and this permission notice appear in supporting documentation.
337a84e134Smrg *
347a84e134Smrg * Prentice Hall and the authors disclaim all warranties with regard
357a84e134Smrg * to this software, including all implied warranties of merchantability and
367a84e134Smrg * fitness.  In no event shall Prentice Hall or the authors be liable
377a84e134Smrg * for any special, indirect or cosequential damages or any damages whatsoever
387a84e134Smrg * resulting from loss of use, data or profits, whether in an action of
397a84e134Smrg * contract, negligence or other tortious action, arising out of or in
407a84e134Smrg * connection with the use or performance of this software.
417a84e134Smrg *
427a84e134Smrg * Authors:  Jim Fulton, MIT X Consortium,
437a84e134Smrg *           based on a version by Douglas Young, Prentice Hall
447a84e134Smrg *
457a84e134Smrg * This widget is based on the Tree widget described on pages 397-419 of
467a84e134Smrg * Douglas Young's book "The X Window System, Programming and Applications
477a84e134Smrg * with Xt OSF/Motif Edition."  The layout code has been rewritten to use
487a84e134Smrg * additional blank space to make the structure of the graph easier to see
497a84e134Smrg * as well as to support vertical trees.
507a84e134Smrg */
517a84e134Smrg/* $XFree86: xc/lib/Xaw/Tree.c,v 1.9 2001/01/17 19:42:35 dawes Exp $ */
527a84e134Smrg
537a84e134Smrg#ifdef HAVE_CONFIG_H
547a84e134Smrg#include <config.h>
557a84e134Smrg#endif
567a84e134Smrg#include <X11/IntrinsicP.h>
577a84e134Smrg#include <X11/StringDefs.h>
587a84e134Smrg#include <X11/Xaw/XawInit.h>
597a84e134Smrg#include <X11/Xaw/Cardinals.h>
607a84e134Smrg#include <X11/Xaw/TreeP.h>
617a84e134Smrg#include "Private.h"
627a84e134Smrg
637a84e134Smrg#define IsHorizontal(tw) ((tw)->tree.gravity == WestGravity || \
647a84e134Smrg			  (tw)->tree.gravity == EastGravity)
657a84e134Smrg
667a84e134Smrg/*
677a84e134Smrg * Class Methods
687a84e134Smrg */
697a84e134Smrgstatic void XawTreeChangeManaged(Widget);
707a84e134Smrgstatic void XawTreeClassInitialize(void);
717a84e134Smrgstatic void XawTreeConstraintDestroy(Widget);
727a84e134Smrgstatic void XawTreeConstraintInitialize(Widget, Widget, ArgList, Cardinal*);
737a84e134Smrgstatic Boolean XawTreeConstraintSetValues(Widget, Widget, Widget,
747a84e134Smrg					  ArgList, Cardinal*);
757a84e134Smrgstatic void XawTreeDestroy(Widget);
767a84e134Smrgstatic XtGeometryResult XawTreeGeometryManager(Widget, XtWidgetGeometry*,
777a84e134Smrg					       XtWidgetGeometry*);
787a84e134Smrgstatic void XawTreeInitialize(Widget, Widget, ArgList, Cardinal*);
797a84e134Smrgstatic XtGeometryResult XawTreeQueryGeometry(Widget, XtWidgetGeometry*,
807a84e134Smrg					     XtWidgetGeometry*);
817a84e134Smrgstatic void XawTreeRedisplay(Widget, XEvent*, Region);
827a84e134Smrgstatic Boolean XawTreeSetValues(Widget, Widget, Widget, ArgList, Cardinal*);
837a84e134Smrg
847a84e134Smrg/*
857a84e134Smrg * Prototypes
867a84e134Smrg */
877a84e134Smrgstatic void arrange_subtree(TreeWidget, Widget, int, int, int);
887a84e134Smrgstatic void check_gravity(TreeWidget, XtGravity);
897a84e134Smrgstatic void compute_bounding_box_subtree(TreeWidget, Widget, int);
907a84e134Smrgstatic void delete_node(Widget, Widget);
917a84e134Smrgstatic GC get_tree_gc(TreeWidget);
927a84e134Smrgstatic void initialize_dimensions(Dimension**, int*, int);
937a84e134Smrgstatic void insert_node(Widget, Widget);
947a84e134Smrgstatic void layout_tree(TreeWidget, Bool);
957a84e134Smrgstatic void set_positions(TreeWidget, Widget, int);
967a84e134Smrgstatic void set_tree_size(TreeWidget, Bool, unsigned int, unsigned int);
977a84e134Smrg
987a84e134Smrg/*
997a84e134Smrg * Initialization
1007a84e134Smrg */
1017a84e134Smrg
1027a84e134Smrg/*
1037a84e134Smrg * resources of the tree itself
1047a84e134Smrg */
1057a84e134Smrgstatic XtResource resources[] = {
1067a84e134Smrg    { XtNautoReconfigure, XtCAutoReconfigure, XtRBoolean, sizeof (Boolean),
1077a84e134Smrg	XtOffsetOf(TreeRec, tree.auto_reconfigure), XtRImmediate,
1087a84e134Smrg	(XtPointer) FALSE },
1097a84e134Smrg    { XtNhSpace, XtCHSpace, XtRDimension, sizeof (Dimension),
1107a84e134Smrg	XtOffsetOf(TreeRec, tree.hpad), XtRImmediate, (XtPointer) 0 },
1117a84e134Smrg    { XtNvSpace, XtCVSpace, XtRDimension, sizeof (Dimension),
1127a84e134Smrg	XtOffsetOf(TreeRec, tree.vpad), XtRImmediate, (XtPointer) 0 },
1137a84e134Smrg    { XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel),
1147a84e134Smrg	XtOffsetOf(TreeRec, tree.foreground), XtRString,
1157a84e134Smrg	XtDefaultForeground},
1167a84e134Smrg    { XtNlineWidth, XtCLineWidth, XtRDimension, sizeof (Dimension),
1177a84e134Smrg	XtOffsetOf(TreeRec, tree.line_width), XtRImmediate, (XtPointer) 0 },
1187a84e134Smrg    { XtNgravity, XtCGravity, XtRGravity, sizeof (XtGravity),
1197a84e134Smrg	XtOffsetOf(TreeRec, tree.gravity), XtRImmediate,
1207a84e134Smrg	(XtPointer) WestGravity },
1217a84e134Smrg#ifndef OLDXAW
1227a84e134Smrg    { XawNdisplayList, XawCDisplayList, XawRDisplayList, sizeof(XawDisplayList*),
1237a84e134Smrg	XtOffsetOf(TreeRec, tree.display_list), XtRImmediate,
1247a84e134Smrg	NULL },
1257a84e134Smrg#endif
1267a84e134Smrg};
1277a84e134Smrg
1287a84e134Smrg
1297a84e134Smrg/*
1307a84e134Smrg * resources that are attached to all children of the tree
1317a84e134Smrg */
1327a84e134Smrgstatic XtResource treeConstraintResources[] = {
1337a84e134Smrg    { XtNtreeParent, XtCTreeParent, XtRWidget, sizeof (Widget),
1347a84e134Smrg	XtOffsetOf(TreeConstraintsRec, tree.parent), XtRImmediate, NULL },
1357a84e134Smrg    { XtNtreeGC, XtCTreeGC, XtRGC, sizeof(GC),
1367a84e134Smrg	XtOffsetOf(TreeConstraintsRec, tree.gc), XtRImmediate, NULL },
1377a84e134Smrg};
1387a84e134Smrg
1397a84e134Smrg
1407a84e134SmrgTreeClassRec treeClassRec = {
1417a84e134Smrg  {
1427a84e134Smrg					/* core_class fields  */
1437a84e134Smrg    (WidgetClass) &constraintClassRec,	/* superclass         */
1447a84e134Smrg    "Tree",				/* class_name         */
1457a84e134Smrg    sizeof(TreeRec),			/* widget_size        */
1467a84e134Smrg    XawTreeClassInitialize,		/* class_init         */
1477a84e134Smrg    NULL,				/* class_part_init    */
1487a84e134Smrg    FALSE,				/* class_inited       */
1497a84e134Smrg    XawTreeInitialize,			/* initialize         */
1507a84e134Smrg    NULL,				/* initialize_hook    */
1517a84e134Smrg    XtInheritRealize,			/* realize            */
1527a84e134Smrg    NULL,				/* actions            */
1537a84e134Smrg    0,					/* num_actions        */
1547a84e134Smrg    resources,				/* resources          */
1557a84e134Smrg    XtNumber(resources),		/* num_resources      */
1567a84e134Smrg    NULLQUARK,				/* xrm_class          */
1577a84e134Smrg    TRUE,				/* compress_motion    */
1587a84e134Smrg    TRUE,				/* compress_exposure  */
1597a84e134Smrg    TRUE,				/* compress_enterleave*/
1607a84e134Smrg    TRUE,				/* visible_interest   */
1617a84e134Smrg    XawTreeDestroy,			/* destroy            */
1627a84e134Smrg    NULL,				/* resize             */
1637a84e134Smrg    XawTreeRedisplay,			/* expose             */
1647a84e134Smrg    XawTreeSetValues,			/* set_values         */
1657a84e134Smrg    NULL,				/* set_values_hook    */
1667a84e134Smrg    XtInheritSetValuesAlmost,		/* set_values_almost  */
1677a84e134Smrg    NULL,				/* get_values_hook    */
1687a84e134Smrg    NULL,				/* accept_focus       */
1697a84e134Smrg    XtVersion,				/* version            */
1707a84e134Smrg    NULL,				/* callback_private   */
1717a84e134Smrg    NULL,				/* tm_table           */
1727a84e134Smrg    XawTreeQueryGeometry,		/* query_geometry     */
1737a84e134Smrg    NULL,				/* display_accelerator*/
1747a84e134Smrg    NULL,				/* extension          */
1757a84e134Smrg  },
1767a84e134Smrg  {
1777a84e134Smrg					/* composite_class fields */
1787a84e134Smrg    XawTreeGeometryManager,		/* geometry_manager    */
1797a84e134Smrg    XawTreeChangeManaged,		/* change_managed      */
1807a84e134Smrg    XtInheritInsertChild,		/* insert_child        */
1817a84e134Smrg    XtInheritDeleteChild,		/* delete_child        */
1827a84e134Smrg    NULL,				/* extension           */
1837a84e134Smrg  },
1847a84e134Smrg  {
1857a84e134Smrg					/* constraint_class fields */
1867a84e134Smrg   treeConstraintResources,		/* subresources        */
1877a84e134Smrg   XtNumber(treeConstraintResources),	/* subresource_count   */
1887a84e134Smrg   sizeof(TreeConstraintsRec),		/* constraint_size     */
1897a84e134Smrg   XawTreeConstraintInitialize,		/* initialize          */
1907a84e134Smrg   XawTreeConstraintDestroy,		/* destroy             */
1917a84e134Smrg   XawTreeConstraintSetValues,		/* set_values          */
1927a84e134Smrg   NULL,				/* extension           */
1937a84e134Smrg   },
1947a84e134Smrg  {
1957a84e134Smrg					/* Tree class fields */
1967a84e134Smrg    0,					/* ignore              */
1977a84e134Smrg  }
1987a84e134Smrg};
1997a84e134Smrg
2007a84e134SmrgWidgetClass treeWidgetClass = (WidgetClass) &treeClassRec;
2017a84e134Smrg
2027a84e134Smrg
2037a84e134Smrg/*****************************************************************************
2047a84e134Smrg *                                                                           *
2057a84e134Smrg *			     tree utility routines                           *
2067a84e134Smrg *                                                                           *
2077a84e134Smrg *****************************************************************************/
2087a84e134Smrg
2097a84e134Smrgstatic void
2107a84e134Smrginitialize_dimensions(Dimension **listp, int *sizep, int n)
2117a84e134Smrg{
2127a84e134Smrg    int i;
2137a84e134Smrg    Dimension *l;
2147a84e134Smrg
2157a84e134Smrg    if (!*listp) {
2167a84e134Smrg	*listp = (Dimension *) XtCalloc ((unsigned int) n,
2177a84e134Smrg					 (unsigned int) sizeof(Dimension));
2187a84e134Smrg	*sizep = ((*listp) ? n : 0);
2197a84e134Smrg	return;
2207a84e134Smrg    }
2217a84e134Smrg    if (n > *sizep) {
2227a84e134Smrg	*listp = (Dimension *) XtRealloc((char *) *listp,
2237a84e134Smrg					 (unsigned int) (n*sizeof(Dimension)));
2247a84e134Smrg	if (!*listp) {
2257a84e134Smrg	    *sizep = 0;
2267a84e134Smrg	    return;
2277a84e134Smrg	}
2287a84e134Smrg	for (i = *sizep, l = (*listp) + i; i < n; i++, l++) *l = 0;
2297a84e134Smrg	*sizep = n;
2307a84e134Smrg    }
2317a84e134Smrg    return;
2327a84e134Smrg}
2337a84e134Smrg
2347a84e134Smrgstatic GC
2357a84e134Smrgget_tree_gc(TreeWidget w)
2367a84e134Smrg{
2377a84e134Smrg    XtGCMask valuemask = GCBackground | GCForeground;
2387a84e134Smrg    XGCValues values;
2397a84e134Smrg
2407a84e134Smrg    values.background = w->core.background_pixel;
2417a84e134Smrg    values.foreground = w->tree.foreground;
2427a84e134Smrg    if (w->tree.line_width != 0) {
2437a84e134Smrg	valuemask |= GCLineWidth;
2447a84e134Smrg	values.line_width = w->tree.line_width;
2457a84e134Smrg    }
2467a84e134Smrg
2477a84e134Smrg    return XtGetGC ((Widget) w, valuemask, &values);
2487a84e134Smrg}
2497a84e134Smrg
2507a84e134Smrgstatic void
2517a84e134Smrginsert_node(Widget parent, Widget node)
2527a84e134Smrg{
2537a84e134Smrg    TreeConstraints pc;
2547a84e134Smrg    TreeConstraints nc = TREE_CONSTRAINT(node);
2557a84e134Smrg    int nindex;
2567a84e134Smrg
2577a84e134Smrg    nc->tree.parent = parent;
2587a84e134Smrg
2597a84e134Smrg    if (parent == NULL) return;
2607a84e134Smrg
2617a84e134Smrg    /*
2627a84e134Smrg     * If there isn't more room in the children array,
2637a84e134Smrg     * allocate additional space.
2647a84e134Smrg     */
2657a84e134Smrg    pc = TREE_CONSTRAINT(parent);
2667a84e134Smrg    nindex = pc->tree.n_children;
2677a84e134Smrg
2687a84e134Smrg    if (pc->tree.n_children == pc->tree.max_children) {
2697a84e134Smrg	pc->tree.max_children += (pc->tree.max_children / 2) + 2;
2707a84e134Smrg	pc->tree.children = (WidgetList) XtRealloc ((char *)pc->tree.children,
2717a84e134Smrg						    (unsigned int)
2727a84e134Smrg						    ((pc->tree.max_children) *
2737a84e134Smrg						    sizeof(Widget)));
2747a84e134Smrg    }
2757a84e134Smrg
2767a84e134Smrg    /*
2777a84e134Smrg     * Add the sub_node in the next available slot and
2787a84e134Smrg     * increment the counter.
2797a84e134Smrg     */
2807a84e134Smrg    pc->tree.children[nindex] = node;
2817a84e134Smrg    pc->tree.n_children++;
2827a84e134Smrg}
2837a84e134Smrg
2847a84e134Smrgstatic void
2857a84e134Smrgdelete_node(Widget parent, Widget node)
2867a84e134Smrg{
2877a84e134Smrg    TreeConstraints pc;
2887a84e134Smrg    int pos, i;
2897a84e134Smrg
2907a84e134Smrg    /*
2917a84e134Smrg     * Make sure the parent exists.
2927a84e134Smrg     */
2937a84e134Smrg    if (!parent) return;
2947a84e134Smrg
2957a84e134Smrg    pc = TREE_CONSTRAINT(parent);
2967a84e134Smrg
2977a84e134Smrg    /*
2987a84e134Smrg     * Find the sub_node on its parent's list.
2997a84e134Smrg     */
3007a84e134Smrg    for (pos = 0; pos < pc->tree.n_children; pos++)
3017a84e134Smrg      if (pc->tree.children[pos] == node) break;
3027a84e134Smrg
3037a84e134Smrg    if (pos == pc->tree.n_children) return;
3047a84e134Smrg
3057a84e134Smrg    /*
3067a84e134Smrg     * Decrement the number of children
3077a84e134Smrg     */
3087a84e134Smrg    pc->tree.n_children--;
3097a84e134Smrg
3107a84e134Smrg    /*
3117a84e134Smrg     * Fill in the gap left by the sub_node.
3127a84e134Smrg     * Zero the last slot for good luck.
3137a84e134Smrg     */
3147a84e134Smrg    for (i = pos; i < pc->tree.n_children; i++)
3157a84e134Smrg      pc->tree.children[i] = pc->tree.children[i+1];
3167a84e134Smrg
3177a84e134Smrg    pc->tree.children[pc->tree.n_children]=0;
3187a84e134Smrg}
3197a84e134Smrg
3207a84e134Smrgstatic void
3217a84e134Smrgcheck_gravity(TreeWidget tw, XtGravity grav)
3227a84e134Smrg{
3237a84e134Smrg    switch (tw->tree.gravity) {
3247a84e134Smrg      case WestGravity: case NorthGravity: case EastGravity: case SouthGravity:
3257a84e134Smrg	break;
3267a84e134Smrg      default:
3277a84e134Smrg	tw->tree.gravity = grav;
3287a84e134Smrg	break;
3297a84e134Smrg    }
3307a84e134Smrg}
3317a84e134Smrg
3327a84e134Smrg
3337a84e134Smrg/*****************************************************************************
3347a84e134Smrg *                                                                           *
3357a84e134Smrg * 			      tree class methods                             *
3367a84e134Smrg *                                                                           *
3377a84e134Smrg *****************************************************************************/
3387a84e134Smrg
3397a84e134Smrgstatic void
3407a84e134SmrgXawTreeClassInitialize(void)
3417a84e134Smrg{
3427a84e134Smrg    XawInitializeWidgetSet();
3437a84e134Smrg  XtAddConverter(XtRString, XtRGravity, XmuCvtStringToGravity, NULL, 0);
3447a84e134Smrg  XtSetTypeConverter(XtRGravity, XtRString, XmuCvtGravityToString,
3457a84e134Smrg		     NULL, 0, XtCacheNone, NULL);
3467a84e134Smrg}
3477a84e134Smrg
3487a84e134Smrg
3497a84e134Smrg/*ARGSUSED*/
3507a84e134Smrgstatic void
3517a84e134SmrgXawTreeInitialize(Widget grequest, Widget gnew,
3527a84e134Smrg		  ArgList args, Cardinal *num_args)
3537a84e134Smrg{
3547a84e134Smrg    TreeWidget request = (TreeWidget) grequest, cnew = (TreeWidget) gnew;
3557a84e134Smrg    Arg arglist[2];
3567a84e134Smrg
3577a84e134Smrg    /*
3587a84e134Smrg     * Make sure the widget's width and height are
3597a84e134Smrg     * greater than zero.
3607a84e134Smrg     */
3617a84e134Smrg    if (request->core.width <= 0) cnew->core.width = 5;
3627a84e134Smrg    if (request->core.height <= 0) cnew->core.height = 5;
3637a84e134Smrg
3647a84e134Smrg    /*
3657a84e134Smrg     * Set the padding according to the orientation
3667a84e134Smrg     */
3677a84e134Smrg    if (request->tree.hpad == 0 && request->tree.vpad == 0) {
3687a84e134Smrg	if (IsHorizontal (request)) {
3697a84e134Smrg	    cnew->tree.hpad = TREE_HORIZONTAL_DEFAULT_SPACING;
3707a84e134Smrg	    cnew->tree.vpad = TREE_VERTICAL_DEFAULT_SPACING;
3717a84e134Smrg	} else {
3727a84e134Smrg	    cnew->tree.hpad = TREE_VERTICAL_DEFAULT_SPACING;
3737a84e134Smrg	    cnew->tree.vpad = TREE_HORIZONTAL_DEFAULT_SPACING;
3747a84e134Smrg	}
3757a84e134Smrg    }
3767a84e134Smrg
3777a84e134Smrg    /*
3787a84e134Smrg     * Create a graphics context for the connecting lines.
3797a84e134Smrg     */
3807a84e134Smrg    cnew->tree.gc = get_tree_gc (cnew);
3817a84e134Smrg
3827a84e134Smrg    /*
3837a84e134Smrg     * Create the hidden root widget.
3847a84e134Smrg     */
3857a84e134Smrg    cnew->tree.tree_root = (Widget) NULL;
3867a84e134Smrg    XtSetArg(arglist[0], XtNwidth, 1);
3877a84e134Smrg    XtSetArg(arglist[1], XtNheight, 1);
3887a84e134Smrg    cnew->tree.tree_root = XtCreateWidget ("root", widgetClass, gnew,
3897a84e134Smrg					  arglist,TWO);
3907a84e134Smrg
3917a84e134Smrg    /*
3927a84e134Smrg     * Allocate the array used to hold the widest values per depth
3937a84e134Smrg     */
3947a84e134Smrg    cnew->tree.largest = NULL;
3957a84e134Smrg    cnew->tree.n_largest = 0;
3967a84e134Smrg    initialize_dimensions (&cnew->tree.largest, &cnew->tree.n_largest,
3977a84e134Smrg			   TREE_INITIAL_DEPTH);
3987a84e134Smrg
3997a84e134Smrg    /*
4007a84e134Smrg     * make sure that our gravity is one of the acceptable values
4017a84e134Smrg     */
4027a84e134Smrg    check_gravity (cnew, WestGravity);
4037a84e134Smrg}
4047a84e134Smrg
4057a84e134Smrg
4067a84e134Smrg/* ARGSUSED */
4077a84e134Smrgstatic void
4087a84e134SmrgXawTreeConstraintInitialize(Widget request, Widget cnew,
4097a84e134Smrg			    ArgList args, Cardinal *num_args)
4107a84e134Smrg{
4117a84e134Smrg    TreeConstraints tc = TREE_CONSTRAINT(cnew);
4127a84e134Smrg    TreeWidget tw = (TreeWidget) cnew->core.parent;
4137a84e134Smrg
4147a84e134Smrg    /*
4157a84e134Smrg     * Initialize the widget to have no sub-nodes.
4167a84e134Smrg     */
4177a84e134Smrg    tc->tree.n_children = 0;
4187a84e134Smrg    tc->tree.max_children = 0;
4197a84e134Smrg    tc->tree.children = (Widget *) NULL;
4207a84e134Smrg    tc->tree.x = tc->tree.y = 0;
4217a84e134Smrg    tc->tree.bbsubwidth = 0;
4227a84e134Smrg    tc->tree.bbsubheight = 0;
4237a84e134Smrg
4247a84e134Smrg
4257a84e134Smrg    /*
4267a84e134Smrg     * If this widget has a super-node, add it to that
4277a84e134Smrg     * widget' sub-nodes list. Otherwise make it a sub-node of
4287a84e134Smrg     * the tree_root widget.
4297a84e134Smrg     */
4307a84e134Smrg    if (tc->tree.parent)
4317a84e134Smrg      insert_node (tc->tree.parent, cnew);
4327a84e134Smrg    else if (tw->tree.tree_root)
4337a84e134Smrg      insert_node (tw->tree.tree_root, cnew);
4347a84e134Smrg}
4357a84e134Smrg
4367a84e134Smrg
4377a84e134Smrg/* ARGSUSED */
4387a84e134Smrgstatic Boolean
4397a84e134SmrgXawTreeSetValues(Widget gcurrent, Widget grequest, Widget gnew,
4407a84e134Smrg		 ArgList args, Cardinal *num_args)
4417a84e134Smrg{
4427a84e134Smrg    TreeWidget current = (TreeWidget) gcurrent, cnew = (TreeWidget) gnew;
4437a84e134Smrg    Boolean redraw = FALSE;
4447a84e134Smrg
4457a84e134Smrg    /*
4467a84e134Smrg     * If the foreground color has changed, redo the GC's
4477a84e134Smrg     * and indicate a redraw.
4487a84e134Smrg     */
4497a84e134Smrg    if (cnew->tree.foreground != current->tree.foreground ||
4507a84e134Smrg	cnew->core.background_pixel != current->core.background_pixel ||
4517a84e134Smrg	cnew->tree.line_width != current->tree.line_width) {
4527a84e134Smrg	XtReleaseGC (gnew, cnew->tree.gc);
4537a84e134Smrg	cnew->tree.gc = get_tree_gc (cnew);
4547a84e134Smrg	redraw = TRUE;
4557a84e134Smrg    }
4567a84e134Smrg
4577a84e134Smrg    /*
4587a84e134Smrg     * If the minimum spacing has changed, recalculate the
4597a84e134Smrg     * tree layout. layout_tree() does a redraw, so we don't
4607a84e134Smrg     * need SetValues to do another one.
4617a84e134Smrg     */
4627a84e134Smrg    if (cnew->tree.gravity != current->tree.gravity) {
4637a84e134Smrg	check_gravity (cnew, current->tree.gravity);
4647a84e134Smrg    }
4657a84e134Smrg
4667a84e134Smrg    if (IsHorizontal(cnew) != IsHorizontal(current)) {
4677a84e134Smrg	if (cnew->tree.vpad == current->tree.vpad &&
4687a84e134Smrg	    cnew->tree.hpad == current->tree.hpad) {
4697a84e134Smrg	    cnew->tree.vpad = current->tree.hpad;
4707a84e134Smrg	    cnew->tree.hpad = current->tree.vpad;
4717a84e134Smrg	}
4727a84e134Smrg    }
4737a84e134Smrg
4747a84e134Smrg    if (cnew->tree.vpad != current->tree.vpad ||
4757a84e134Smrg	cnew->tree.hpad != current->tree.hpad ||
4767a84e134Smrg	cnew->tree.gravity != current->tree.gravity) {
4777a84e134Smrg	layout_tree (cnew, TRUE);
4787a84e134Smrg	redraw = FALSE;
4797a84e134Smrg    }
4807a84e134Smrg    return redraw;
4817a84e134Smrg}
4827a84e134Smrg
4837a84e134Smrg
4847a84e134Smrg/* ARGSUSED */
4857a84e134Smrgstatic Boolean
4867a84e134SmrgXawTreeConstraintSetValues(Widget current, Widget request, Widget cnew,
4877a84e134Smrg			   ArgList args, Cardinal *num_args)
4887a84e134Smrg{
4897a84e134Smrg    TreeConstraints newc = TREE_CONSTRAINT(cnew);
4907a84e134Smrg    TreeConstraints curc = TREE_CONSTRAINT(current);
4917a84e134Smrg    TreeWidget tw = (TreeWidget) cnew->core.parent;
4927a84e134Smrg
4937a84e134Smrg    /*
4947a84e134Smrg     * If the parent field has changed, remove the widget
4957a84e134Smrg     * from the old widget's children list and add it to the
4967a84e134Smrg     * new one.
4977a84e134Smrg     */
4987a84e134Smrg    if (curc->tree.parent != newc->tree.parent){
4997a84e134Smrg	if (curc->tree.parent)
5007a84e134Smrg	  delete_node (curc->tree.parent, cnew);
5017a84e134Smrg	if (newc->tree.parent)
5027a84e134Smrg	  insert_node(newc->tree.parent, cnew);
5037a84e134Smrg
5047a84e134Smrg	/*
5057a84e134Smrg	 * If the Tree widget has been realized,
5067a84e134Smrg	 * compute new layout.
5077a84e134Smrg	 */
5087a84e134Smrg	if (XtIsRealized((Widget)tw))
5097a84e134Smrg	  layout_tree (tw, FALSE);
5107a84e134Smrg    }
5117a84e134Smrg    return False;
5127a84e134Smrg}
5137a84e134Smrg
5147a84e134Smrg
5157a84e134Smrgstatic void
5167a84e134SmrgXawTreeConstraintDestroy(Widget w)
5177a84e134Smrg{
5187a84e134Smrg    TreeConstraints tc = TREE_CONSTRAINT(w);
5197a84e134Smrg    TreeWidget tw = (TreeWidget) XtParent(w);
5207a84e134Smrg    int i;
5217a84e134Smrg
5227a84e134Smrg    /*
5237a84e134Smrg     * Remove the widget from its parent's sub-nodes list and
5247a84e134Smrg     * make all this widget's sub-nodes sub-nodes of the parent.
5257a84e134Smrg     */
5267a84e134Smrg
5277a84e134Smrg    if (tw->tree.tree_root == w) {
5287a84e134Smrg	if (tc->tree.n_children > 0)
5297a84e134Smrg	  tw->tree.tree_root = tc->tree.children[0];
5307a84e134Smrg	else
5317a84e134Smrg	  tw->tree.tree_root = NULL;
5327a84e134Smrg    }
5337a84e134Smrg
5347a84e134Smrg    delete_node (tc->tree.parent, (Widget) w);
5357a84e134Smrg    for (i = 0; i< tc->tree.n_children; i++)
5367a84e134Smrg      insert_node (tc->tree.parent, tc->tree.children[i]);
5377a84e134Smrg
5387a84e134Smrg    layout_tree ((TreeWidget) (w->core.parent), FALSE);
5397a84e134Smrg}
5407a84e134Smrg
5417a84e134Smrg/* ARGSUSED */
5427a84e134Smrgstatic XtGeometryResult
5437a84e134SmrgXawTreeGeometryManager(Widget w, XtWidgetGeometry *request,
5447a84e134Smrg		       XtWidgetGeometry *reply)
5457a84e134Smrg{
5467a84e134Smrg
5477a84e134Smrg    TreeWidget tw = (TreeWidget) w->core.parent;
5487a84e134Smrg
5497a84e134Smrg    /*
5507a84e134Smrg     * No position changes allowed!.
5517a84e134Smrg     */
5527a84e134Smrg    if ((request->request_mode & CWX && request->x!=w->core.x)
5537a84e134Smrg	||(request->request_mode & CWY && request->y!=w->core.y))
5547a84e134Smrg      return (XtGeometryNo);
5557a84e134Smrg
5567a84e134Smrg    /*
5577a84e134Smrg     * Allow all resize requests.
5587a84e134Smrg     */
5597a84e134Smrg
5607a84e134Smrg    if (request->request_mode & CWWidth)
5617a84e134Smrg      w->core.width = request->width;
5627a84e134Smrg    if (request->request_mode & CWHeight)
5637a84e134Smrg      w->core.height = request->height;
5647a84e134Smrg    if (request->request_mode & CWBorderWidth)
5657a84e134Smrg      w->core.border_width = request->border_width;
5667a84e134Smrg
5677a84e134Smrg    if (tw->tree.auto_reconfigure) layout_tree (tw, FALSE);
5687a84e134Smrg    return (XtGeometryYes);
5697a84e134Smrg}
5707a84e134Smrg
5717a84e134Smrgstatic void
5727a84e134SmrgXawTreeChangeManaged(Widget gw)
5737a84e134Smrg{
5747a84e134Smrg    layout_tree ((TreeWidget) gw, FALSE);
5757a84e134Smrg}
5767a84e134Smrg
5777a84e134Smrg
5787a84e134Smrgstatic void
5797a84e134SmrgXawTreeDestroy(Widget gw)
5807a84e134Smrg{
5817a84e134Smrg    TreeWidget w = (TreeWidget) gw;
5827a84e134Smrg
5837a84e134Smrg    XtReleaseGC (gw, w->tree.gc);
5847a84e134Smrg    if (w->tree.largest) XtFree ((char *) w->tree.largest);
5857a84e134Smrg}
5867a84e134Smrg
5877a84e134Smrg
5887a84e134Smrg/* ARGSUSED */
5897a84e134Smrgstatic void
5907a84e134SmrgXawTreeRedisplay(Widget gw, XEvent *event, Region region)
5917a84e134Smrg{
5927a84e134Smrg    TreeWidget tw = (TreeWidget) gw;
5937a84e134Smrg
5947a84e134Smrg#ifndef OLDXAW
5957a84e134Smrg    if (tw->tree.display_list)
5967a84e134Smrg	XawRunDisplayList(gw, tw->tree.display_list, event, region);
5977a84e134Smrg#endif
5987a84e134Smrg
5997a84e134Smrg    /*
6007a84e134Smrg     * If the Tree widget is visible, visit each managed child.
6017a84e134Smrg     */
6027a84e134Smrg    if (tw->core.visible) {
6037a84e134Smrg	Cardinal i;
6047a84e134Smrg	int j;
6057a84e134Smrg	Display *dpy = XtDisplay (tw);
6067a84e134Smrg	Window w = XtWindow (tw);
6077a84e134Smrg
6087a84e134Smrg	for (i = 0; i < tw->composite.num_children; i++) {
6097a84e134Smrg	    Widget child = tw->composite.children[i];
6107a84e134Smrg	    TreeConstraints tc = TREE_CONSTRAINT(child);
6117a84e134Smrg
6127a84e134Smrg	    /*
6137a84e134Smrg	     * Don't draw lines from the fake tree_root.
6147a84e134Smrg	     */
6157a84e134Smrg	    if (child != tw->tree.tree_root && tc->tree.n_children) {
6167a84e134Smrg		int srcx = child->core.x + child->core.border_width;
6177a84e134Smrg		int srcy = child->core.y + child->core.border_width;
6187a84e134Smrg
6197a84e134Smrg		switch (tw->tree.gravity) {
6207a84e134Smrg		  case WestGravity:
6217a84e134Smrg		    srcx += child->core.width + child->core.border_width;
6227a84e134Smrg		    /* fall through */
6237a84e134Smrg		  case EastGravity:
6247a84e134Smrg		    srcy += child->core.height / 2;
6257a84e134Smrg		    break;
6267a84e134Smrg
6277a84e134Smrg		  case NorthGravity:
6287a84e134Smrg		    srcy += child->core.height + child->core.border_width;
6297a84e134Smrg		    /* fall through */
6307a84e134Smrg		  case SouthGravity:
6317a84e134Smrg		    srcx += child->core.width / 2;
6327a84e134Smrg		    break;
6337a84e134Smrg		}
6347a84e134Smrg
6357a84e134Smrg		for (j = 0; j < tc->tree.n_children; j++) {
6367a84e134Smrg		    Widget k = tc->tree.children[j];
6377a84e134Smrg		    GC gc = (tc->tree.gc ? tc->tree.gc : tw->tree.gc);
6387a84e134Smrg
6397a84e134Smrg		    switch (tw->tree.gravity) {
6407a84e134Smrg		      case WestGravity:
6417a84e134Smrg			/*
6427a84e134Smrg			 * right center to left center
6437a84e134Smrg			 */
6447a84e134Smrg			XDrawLine (dpy, w, gc, srcx, srcy,
6457a84e134Smrg				   (int) k->core.x,
6467a84e134Smrg				   (k->core.y + ((int) k->core.border_width) +
6477a84e134Smrg				    ((int) k->core.height) / 2));
6487a84e134Smrg			break;
6497a84e134Smrg
6507a84e134Smrg		      case NorthGravity:
6517a84e134Smrg			/*
6527a84e134Smrg			 * bottom center to top center
6537a84e134Smrg			 */
6547a84e134Smrg			XDrawLine (dpy, w, gc, srcx, srcy,
6557a84e134Smrg				   (k->core.x + ((int) k->core.border_width) +
6567a84e134Smrg				    ((int) k->core.width) / 2),
6577a84e134Smrg				   (int) k->core.y);
6587a84e134Smrg			break;
6597a84e134Smrg
6607a84e134Smrg		      case EastGravity:
6617a84e134Smrg			/*
6627a84e134Smrg			 * left center to right center
6637a84e134Smrg			 */
6647a84e134Smrg			XDrawLine (dpy, w, gc, srcx, srcy,
6657a84e134Smrg				   (k->core.x +
6667a84e134Smrg				    (((int) k->core.border_width) << 1) +
6677a84e134Smrg				    (int) k->core.width),
6687a84e134Smrg				   (k->core.y + ((int) k->core.border_width) +
6697a84e134Smrg				    ((int) k->core.height) / 2));
6707a84e134Smrg			break;
6717a84e134Smrg
6727a84e134Smrg		      case SouthGravity:
6737a84e134Smrg			/*
6747a84e134Smrg			 * top center to bottom center
6757a84e134Smrg			 */
6767a84e134Smrg			XDrawLine (dpy, w, gc, srcx, srcy,
6777a84e134Smrg				   (k->core.x + ((int) k->core.border_width) +
6787a84e134Smrg				    ((int) k->core.width) / 2),
6797a84e134Smrg				   (k->core.y +
6807a84e134Smrg				    (((int) k->core.border_width) << 1) +
6817a84e134Smrg				    (int) k->core.height));
6827a84e134Smrg			break;
6837a84e134Smrg		    }
6847a84e134Smrg		}
6857a84e134Smrg	    }
6867a84e134Smrg	}
6877a84e134Smrg    }
6887a84e134Smrg}
6897a84e134Smrg
6907a84e134Smrgstatic XtGeometryResult
6917a84e134SmrgXawTreeQueryGeometry(Widget w, XtWidgetGeometry *intended,
6927a84e134Smrg		     XtWidgetGeometry *preferred)
6937a84e134Smrg{
6947a84e134Smrg    TreeWidget tw = (TreeWidget) w;
6957a84e134Smrg
6967a84e134Smrg    preferred->request_mode = (CWWidth | CWHeight);
6977a84e134Smrg    preferred->width = tw->tree.maxwidth;
6987a84e134Smrg    preferred->height = tw->tree.maxheight;
6997a84e134Smrg
7007a84e134Smrg    if (((intended->request_mode & (CWWidth | CWHeight)) ==
7017a84e134Smrg	 (CWWidth | CWHeight)) &&
7027a84e134Smrg	intended->width == preferred->width &&
7037a84e134Smrg	intended->height == preferred->height)
7047a84e134Smrg      return XtGeometryYes;
7057a84e134Smrg    else if (preferred->width == w->core.width &&
7067a84e134Smrg             preferred->height == w->core.height)
7077a84e134Smrg      return XtGeometryNo;
7087a84e134Smrg    else
7097a84e134Smrg      return XtGeometryAlmost;
7107a84e134Smrg}
7117a84e134Smrg
7127a84e134Smrg
7137a84e134Smrg/*****************************************************************************
7147a84e134Smrg *                                                                           *
7157a84e134Smrg *			     tree layout algorithm                           *
7167a84e134Smrg *                                                                           *
7177a84e134Smrg * Each node in the tree is "shrink-wrapped" with a minimal bounding         *
7187a84e134Smrg * rectangle, laid next to its siblings (with a small about of padding in    *
7197a84e134Smrg * between) and then wrapped with their parent.  Parents are centered about  *
7207a84e134Smrg * their children (or vice versa if the parent is larger than the children). *
7217a84e134Smrg *                                                                           *
7227a84e134Smrg *****************************************************************************/
7237a84e134Smrg
7247a84e134Smrgstatic void
7257a84e134Smrgcompute_bounding_box_subtree(TreeWidget tree, Widget w, int depth)
7267a84e134Smrg{
7277a84e134Smrg    TreeConstraints tc = TREE_CONSTRAINT(w);  /* info attached to all kids */
7287a84e134Smrg    int i;
7297a84e134Smrg    Bool horiz = IsHorizontal (tree);
7307a84e134Smrg    Dimension newwidth, newheight;
7317a84e134Smrg    Dimension bw2 = w->core.border_width * 2;
7327a84e134Smrg
7337a84e134Smrg    /*
7347a84e134Smrg     * Set the max-size per level.
7357a84e134Smrg     */
7367a84e134Smrg    if (depth >= tree->tree.n_largest) {
7377a84e134Smrg	initialize_dimensions (&tree->tree.largest,
7387a84e134Smrg			       &tree->tree.n_largest, depth + 1);
7397a84e134Smrg    }
7407a84e134Smrg    newwidth = ((horiz ? w->core.width : w->core.height) + bw2);
7417a84e134Smrg    if (tree->tree.largest[depth] < newwidth)
7427a84e134Smrg      tree->tree.largest[depth] = newwidth;
7437a84e134Smrg
7447a84e134Smrg
7457a84e134Smrg    /*
7467a84e134Smrg     * initialize
7477a84e134Smrg     */
7487a84e134Smrg    tc->tree.bbwidth = w->core.width + bw2;
7497a84e134Smrg    tc->tree.bbheight = w->core.height + bw2;
7507a84e134Smrg
7517a84e134Smrg    if (tc->tree.n_children == 0) return;
7527a84e134Smrg
7537a84e134Smrg    /*
7547a84e134Smrg     * Figure the size of the opposite dimension (vertical if tree is
7557a84e134Smrg     * horizontal, else vice versa).  The other dimension will be set
7567a84e134Smrg     * in the second pass once we know the maximum dimensions.
7577a84e134Smrg     */
7587a84e134Smrg    newwidth = 0;
7597a84e134Smrg    newheight = 0;
7607a84e134Smrg    for (i = 0; i < tc->tree.n_children; i++) {
7617a84e134Smrg	Widget child = tc->tree.children[i];
7627a84e134Smrg	TreeConstraints cc = TREE_CONSTRAINT(child);
7637a84e134Smrg
7647a84e134Smrg	compute_bounding_box_subtree (tree, child, depth + 1);
7657a84e134Smrg
7667a84e134Smrg	if (horiz) {
7677a84e134Smrg	    if (newwidth < cc->tree.bbwidth) newwidth = cc->tree.bbwidth;
7687a84e134Smrg	    newheight += tree->tree.vpad + cc->tree.bbheight;
7697a84e134Smrg	} else {
7707a84e134Smrg	    if (newheight < cc->tree.bbheight) newheight = cc->tree.bbheight;
7717a84e134Smrg	    newwidth += tree->tree.hpad + cc->tree.bbwidth;
7727a84e134Smrg	}
7737a84e134Smrg    }
7747a84e134Smrg
7757a84e134Smrg
7767a84e134Smrg    tc->tree.bbsubwidth = newwidth;
7777a84e134Smrg    tc->tree.bbsubheight = newheight;
7787a84e134Smrg
7797a84e134Smrg    /*
7807a84e134Smrg     * Now fit parent onto side (or top) of bounding box and correct for
7817a84e134Smrg     * extra padding.  Be careful of unsigned arithmetic.
7827a84e134Smrg     */
7837a84e134Smrg    if (horiz) {
7847a84e134Smrg	tc->tree.bbwidth += tree->tree.hpad + newwidth;
7857a84e134Smrg	newheight -= tree->tree.vpad;
7867a84e134Smrg	if (newheight > tc->tree.bbheight) tc->tree.bbheight = newheight;
7877a84e134Smrg    } else {
7887a84e134Smrg	tc->tree.bbheight += tree->tree.vpad + newheight;
7897a84e134Smrg	newwidth -= tree->tree.hpad;
7907a84e134Smrg	if (newwidth > tc->tree.bbwidth) tc->tree.bbwidth = newwidth;
7917a84e134Smrg    }
7927a84e134Smrg}
7937a84e134Smrg
7947a84e134Smrg
7957a84e134Smrgstatic void
7967a84e134Smrgset_positions(TreeWidget tw, Widget w, int level)
7977a84e134Smrg{
7987a84e134Smrg    int i;
7997a84e134Smrg
8007a84e134Smrg    if (w) {
8017a84e134Smrg	TreeConstraints tc = TREE_CONSTRAINT(w);
8027a84e134Smrg
8037a84e134Smrg	if (level > 0) {
8047a84e134Smrg	    /*
8057a84e134Smrg	     * mirror if necessary
8067a84e134Smrg	     */
8077a84e134Smrg	    switch (tw->tree.gravity) {
8087a84e134Smrg	      case EastGravity:
8097a84e134Smrg		tc->tree.x = (((Position) tw->tree.maxwidth) -
8107a84e134Smrg			      ((Position) w->core.width) - tc->tree.x);
8117a84e134Smrg		break;
8127a84e134Smrg
8137a84e134Smrg	      case SouthGravity:
8147a84e134Smrg		tc->tree.y = (((Position) tw->tree.maxheight) -
8157a84e134Smrg			      ((Position) w->core.height) - tc->tree.y);
8167a84e134Smrg		break;
8177a84e134Smrg	    }
8187a84e134Smrg
8197a84e134Smrg	    /*
8207a84e134Smrg	     * Move the widget into position.
8217a84e134Smrg	     */
8227a84e134Smrg	    XtMoveWidget (w, tc->tree.x, tc->tree.y);
8237a84e134Smrg	}
8247a84e134Smrg
8257a84e134Smrg	/*
8267a84e134Smrg	 * Set the positions of all children.
8277a84e134Smrg	 */
8287a84e134Smrg	for (i = 0; i < tc->tree.n_children; i++)
8297a84e134Smrg	  set_positions (tw, tc->tree.children[i], level + 1);
8307a84e134Smrg    }
8317a84e134Smrg}
8327a84e134Smrg
8337a84e134Smrg
8347a84e134Smrgstatic void
8357a84e134Smrgarrange_subtree(TreeWidget tree, Widget w, int depth, int x, int y)
8367a84e134Smrg{
8377a84e134Smrg    TreeConstraints tc = TREE_CONSTRAINT(w);  /* info attached to all kids */
8387a84e134Smrg    TreeConstraints firstcc, lastcc;
8397a84e134Smrg    int i;
8407a84e134Smrg    int newx, newy;
8417a84e134Smrg    Bool horiz = IsHorizontal (tree);
8427a84e134Smrg    Widget child = NULL;
8437a84e134Smrg    Dimension tmp;
8447a84e134Smrg    Dimension bw2 = w->core.border_width * 2;
8457a84e134Smrg    Bool relayout = True;
8467a84e134Smrg
8477a84e134Smrg
8487a84e134Smrg    /*
8497a84e134Smrg     * If no children, then just lay out where requested.
8507a84e134Smrg     */
8517a84e134Smrg    tc->tree.x = x;
8527a84e134Smrg    tc->tree.y = y;
8537a84e134Smrg
8547a84e134Smrg    if (horiz) {
8557a84e134Smrg	int myh = (w->core.height + bw2);
8567a84e134Smrg
8577a84e134Smrg	if (myh > (int)tc->tree.bbsubheight) {
8587a84e134Smrg	    y += (myh - (int)tc->tree.bbsubheight) / 2;
8597a84e134Smrg	    relayout = False;
8607a84e134Smrg	}
8617a84e134Smrg    } else {
8627a84e134Smrg	int myw = (w->core.width + bw2);
8637a84e134Smrg
8647a84e134Smrg	if (myw > (int)tc->tree.bbsubwidth) {
8657a84e134Smrg	    x += (myw - (int)tc->tree.bbsubwidth) / 2;
8667a84e134Smrg	    relayout = False;
8677a84e134Smrg	}
8687a84e134Smrg    }
8697a84e134Smrg
8707a84e134Smrg    if ((tmp = ((Dimension) x) + tc->tree.bbwidth) > tree->tree.maxwidth)
8717a84e134Smrg      tree->tree.maxwidth = tmp;
8727a84e134Smrg    if ((tmp = ((Dimension) y) + tc->tree.bbheight) > tree->tree.maxheight)
8737a84e134Smrg      tree->tree.maxheight = tmp;
8747a84e134Smrg
8757a84e134Smrg    if (tc->tree.n_children == 0) return;
8767a84e134Smrg
8777a84e134Smrg
8787a84e134Smrg    /*
8797a84e134Smrg     * Have children, so walk down tree laying out children, then laying
8807a84e134Smrg     * out parents.
8817a84e134Smrg     */
8827a84e134Smrg    if (horiz) {
8837a84e134Smrg	newx = x + tree->tree.largest[depth];
8847a84e134Smrg	if (depth > 0) newx += tree->tree.hpad;
8857a84e134Smrg	newy = y;
8867a84e134Smrg    } else {
8877a84e134Smrg	newx = x;
8887a84e134Smrg	newy = y + tree->tree.largest[depth];
8897a84e134Smrg	if (depth > 0) newy += tree->tree.vpad;
8907a84e134Smrg    }
8917a84e134Smrg
8927a84e134Smrg    for (i = 0; i < tc->tree.n_children; i++) {
8937a84e134Smrg	TreeConstraints cc;
8947a84e134Smrg
8957a84e134Smrg	child = tc->tree.children[i];	/* last value is used outside loop */
8967a84e134Smrg	cc = TREE_CONSTRAINT(child);
8977a84e134Smrg
8987a84e134Smrg	arrange_subtree (tree, child, depth + 1, newx, newy);
8997a84e134Smrg	if (horiz) {
9007a84e134Smrg	    newy += tree->tree.vpad + cc->tree.bbheight;
9017a84e134Smrg	} else {
9027a84e134Smrg	    newx += tree->tree.hpad + cc->tree.bbwidth;
9037a84e134Smrg	}
9047a84e134Smrg    }
9057a84e134Smrg
9067a84e134Smrg    /*
9077a84e134Smrg     * now layout parent between first and last children
9087a84e134Smrg     */
9097a84e134Smrg    if (relayout) {
9107a84e134Smrg	Position adjusted;
9117a84e134Smrg	firstcc = TREE_CONSTRAINT (tc->tree.children[0]);
9127a84e134Smrg	lastcc = TREE_CONSTRAINT (child);
9137a84e134Smrg
9147a84e134Smrg	/* Adjustments are disallowed if they result in a position above
9157a84e134Smrg         * or to the left of the originally requested position, because
9167a84e134Smrg	 * this could collide with the position of the previous sibling.
9177a84e134Smrg	 */
9187a84e134Smrg	if (horiz) {
9197a84e134Smrg	    tc->tree.x = x;
9207a84e134Smrg	    adjusted = firstcc->tree.y +
9217a84e134Smrg	      ((lastcc->tree.y + (Position) child->core.height +
9227a84e134Smrg		(Position) child->core.border_width * 2 -
9237a84e134Smrg		firstcc->tree.y - (Position) w->core.height -
9247a84e134Smrg		(Position) w->core.border_width * 2 + 1) / 2);
9257a84e134Smrg	    if (adjusted > tc->tree.y) tc->tree.y = adjusted;
9267a84e134Smrg	} else {
9277a84e134Smrg	    adjusted = firstcc->tree.x +
9287a84e134Smrg	      ((lastcc->tree.x + (Position) child->core.width +
9297a84e134Smrg		(Position) child->core.border_width * 2 -
9307a84e134Smrg		firstcc->tree.x - (Position) w->core.width -
9317a84e134Smrg		(Position) w->core.border_width * 2 + 1) / 2);
9327a84e134Smrg	    if (adjusted > tc->tree.x) tc->tree.x = adjusted;
9337a84e134Smrg	    tc->tree.y = y;
9347a84e134Smrg	}
9357a84e134Smrg    }
9367a84e134Smrg}
9377a84e134Smrg
9387a84e134Smrgstatic void
9397a84e134Smrgset_tree_size(TreeWidget tw, Bool insetvalues,
9407a84e134Smrg	      unsigned int width, unsigned int height)
9417a84e134Smrg{
9427a84e134Smrg    if (insetvalues) {
9437a84e134Smrg	tw->core.width = width;
9447a84e134Smrg	tw->core.height = height;
9457a84e134Smrg    } else {
9467a84e134Smrg	Dimension replyWidth = 0, replyHeight = 0;
9477a84e134Smrg	XtGeometryResult result = XtMakeResizeRequest ((Widget) tw,
9487a84e134Smrg						       width, height,
9497a84e134Smrg						       &replyWidth,
9507a84e134Smrg						       &replyHeight);
9517a84e134Smrg	/*
9527a84e134Smrg	 * Accept any compromise.
9537a84e134Smrg	 */
9547a84e134Smrg	if (result == XtGeometryAlmost)
9557a84e134Smrg	  XtMakeResizeRequest ((Widget) tw, replyWidth, replyHeight,
9567a84e134Smrg			       (Dimension *) NULL, (Dimension *) NULL);
9577a84e134Smrg    }
9587a84e134Smrg    return;
9597a84e134Smrg}
9607a84e134Smrg
9617a84e134Smrgstatic void
9627a84e134Smrglayout_tree(TreeWidget tw, Bool insetvalues)
9637a84e134Smrg{
9647a84e134Smrg    int i;
9657a84e134Smrg    Dimension *dp;
9667a84e134Smrg
9677a84e134Smrg    /*
9687a84e134Smrg     * Do a depth-first search computing the width and height of the bounding
9697a84e134Smrg     * box for the tree at that position (and below).  Then, walk again using
9707a84e134Smrg     * this information to layout the children at each level.
9717a84e134Smrg     */
9727a84e134Smrg
9737a84e134Smrg    if (tw->tree.tree_root == NULL)
9747a84e134Smrg	return;
9757a84e134Smrg
9767a84e134Smrg    tw->tree.maxwidth = tw->tree.maxheight = 0;
9777a84e134Smrg    for (i = 0, dp = tw->tree.largest; i < tw->tree.n_largest; i++, dp++)
9787a84e134Smrg      *dp = 0;
9797a84e134Smrg    initialize_dimensions (&tw->tree.largest, &tw->tree.n_largest,
9807a84e134Smrg			   tw->tree.n_largest);
9817a84e134Smrg    compute_bounding_box_subtree (tw, tw->tree.tree_root, 0);
9827a84e134Smrg
9837a84e134Smrg   /*
9847a84e134Smrg    * Second pass to do final layout.  Each child's bounding box is stacked
9857a84e134Smrg    * on top of (if horizontal, else next to) on top of its siblings.  The
9867a84e134Smrg    * parent is centered between the first and last children.
9877a84e134Smrg    */
9887a84e134Smrg    arrange_subtree (tw, tw->tree.tree_root, 0, 0, 0);
9897a84e134Smrg
9907a84e134Smrg    /*
9917a84e134Smrg     * Move each widget into place.
9927a84e134Smrg     */
9937a84e134Smrg    set_tree_size (tw, insetvalues, tw->tree.maxwidth, tw->tree.maxheight);
9947a84e134Smrg    set_positions (tw, tw->tree.tree_root, 0);
9957a84e134Smrg
9967a84e134Smrg    /*
9977a84e134Smrg     * And redisplay.
9987a84e134Smrg     */
9997a84e134Smrg    if (XtIsRealized ((Widget) tw)) {
10007a84e134Smrg	XClearArea (XtDisplay(tw), XtWindow((Widget)tw), 0, 0, 0, 0, True);
10017a84e134Smrg    }
10027a84e134Smrg}
10037a84e134Smrg
10047a84e134Smrg
10057a84e134Smrg
10067a84e134Smrg/*****************************************************************************
10077a84e134Smrg *                                                                           *
10087a84e134Smrg * 				Public Routines                              *
10097a84e134Smrg *                                                                           *
10107a84e134Smrg *****************************************************************************/
10117a84e134Smrg
10127a84e134Smrgvoid
10137a84e134SmrgXawTreeForceLayout(Widget tree)
10147a84e134Smrg{
10157a84e134Smrg    layout_tree ((TreeWidget) tree, FALSE);
10167a84e134Smrg}
10177a84e134Smrg
1018