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