2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
24 * $Id: Tree.c,v 1.2 1993/05/18 16:05:53 brennan Exp $
26 * Copyright (c) 1991 HaL Computer Systems, Inc. All rights reserved.
27 * UNPUBLISHED -- rights reserved under the Copyright Laws of the United
28 * States. Use of a copyright notice is precautionary only and does not
29 * imply publication or disclosure.
31 * This software contains confidential information and trade secrets of HaL
32 * Computer Systems, Inc. Use, disclosure, or reproduction is prohibited
33 * without the prior express written permission of HaL Computer Systems, Inc.
35 * RESTRICTED RIGHTS LEGEND
36 * Use, duplication, or disclosure by the Government is subject to
37 * restrictions as set forth in subparagraph (c)(l)(ii) of the Rights in
38 * Technical Data and Computer Software clause at DFARS 252.227-7013.
39 * HaL Computer Systems, Inc.
40 * 1315 Dell Avenue, Campbell, CA 95008
45 * $XConsortium: Tree.c,v 1.42 91/02/20 20:06:07 converse Exp $
47 * Copyright 1990 Massachusetts Institute of Technology
48 * Copyright 1989 Prentice Hall
50 * Permission to use, copy, modify, and distribute this software for any
51 * purpose and without fee is hereby granted, provided that the above
52 * copyright notice appear in all copies and that both the copyright notice
53 * and this permission notice appear in supporting documentation.
55 * M.I.T., Prentice Hall and the authors disclaim all warranties with regard
56 * to this software, including all implied warranties of merchantability and
57 * fitness. In no event shall M.I.T., Prentice Hall or the authors be liable
58 * for any special, indirect or cosequential damages or any damages whatsoever
59 * resulting from loss of use, data or profits, whether in an action of
60 * contract, negligence or other tortious action, arising out of or in
61 * connection with the use or performance of this software.
63 * Authors: Jim Fulton, MIT X Consortium,
64 * based on a version by Douglas Young, Prentice Hall
66 * This widget is based on the Tree widget described on pages 397-419 of
67 * Douglas Young's book "The X Window System, Programming and Applications
68 * with Xt OSF/Motif Edition." The layout code has been rewritten to use
69 * additional blank space to make the structure of the graph easier to see
70 * as well as to support vertical trees.
73 #include <X11/Intrinsic.h>
74 #include <X11/IntrinsicP.h>
75 #include <X11/StringDefs.h>
76 #include <X11/CoreP.h>
77 #include <X11/CompositeP.h>
78 #include <X11/ConstrainP.h>
79 #include <X11/Xaw/XawInit.h>
80 #include <X11/Xaw/Cardinals.h>
81 #include <X11/Xaw/TreeP.h>
83 #define IsHorizontal(tw) ((tw)->tree.gravity == WestGravity || \
84 (tw)->tree.gravity == EastGravity)
87 /* widget class method */
88 static void ClassInitialize();
89 static void Initialize();
90 static void ConstraintInitialize();
91 static void ConstraintDestroy();
92 static Boolean ConstraintSetValues();
93 static void Destroy();
94 static Boolean SetValues();
95 static XtGeometryResult GeometryManager();
96 static void ChangeManaged();
97 static void Redisplay();
98 static XtGeometryResult QueryGeometry();
100 /* utility routines */
101 static void insert_node();
102 static void delete_node();
103 static void layout_tree();
107 * resources of the tree itself
109 static XtResource resources[] = {
110 /* Added border width of 0 to get rid of ugly 1 pixel line when map
111 is updated or resized. 13:36 15-May-93 DJB */
112 { XtNborderWidth, XtCBorderWidth, XtRDimension, sizeof (Dimension),
113 XtOffsetOf(TreeRec, core.border_width), XtRImmediate,
115 { XtNautoReconfigure, XtCAutoReconfigure, XtRBoolean, sizeof (Boolean),
116 XtOffsetOf(TreeRec, tree.auto_reconfigure), XtRImmediate,
118 { XtNhSpace, XtCHSpace, XtRDimension, sizeof (Dimension),
119 XtOffsetOf(TreeRec, tree.hpad), XtRImmediate, (XtPointer) 0 },
120 { XtNvSpace, XtCVSpace, XtRDimension, sizeof (Dimension),
121 XtOffsetOf(TreeRec, tree.vpad), XtRImmediate, (XtPointer) 0 },
122 { XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel),
123 XtOffsetOf(TreeRec, tree.foreground), XtRString,
124 XtDefaultForeground},
125 { XtNlineWidth, XtCLineWidth, XtRDimension, sizeof (Dimension),
126 XtOffsetOf(TreeRec, tree.line_width), XtRImmediate, (XtPointer) 0 },
127 { XtNgravity, XtCGravity, XtRGravity, sizeof (XtGravity),
128 XtOffsetOf(TreeRec, tree.gravity), XtRImmediate,
129 (XtPointer) WestGravity },
134 * resources that are attached to all children of the tree
136 static XtResource treeConstraintResources[] = {
137 { XtNtreeParent, XtCTreeParent, XtRWidget, sizeof (Widget),
138 XtOffsetOf(TreeConstraintsRec, tree.parent), XtRImmediate, NULL },
139 { XtNtreeGC, XtCTreeGC, XtRGC, sizeof(GC),
140 XtOffsetOf(TreeConstraintsRec, tree.gc), XtRImmediate, NULL },
144 TreeClassRec treeClassRec = {
146 /* core_class fields */
147 (WidgetClass) &constraintClassRec, /* superclass */
148 "Tree", /* class_name */
149 sizeof(TreeRec), /* widget_size */
150 ClassInitialize, /* class_init */
151 NULL, /* class_part_init */
152 FALSE, /* class_inited */
153 Initialize, /* initialize */
154 NULL, /* initialize_hook */
155 XtInheritRealize, /* realize */
158 resources, /* resources */
159 XtNumber(resources), /* num_resources */
160 NULLQUARK, /* xrm_class */
161 TRUE, /* compress_motion */
162 TRUE, /* compress_exposure */
163 TRUE, /* compress_enterleave*/
164 TRUE, /* visible_interest */
165 Destroy, /* destroy */
167 Redisplay, /* expose */
168 SetValues, /* set_values */
169 NULL, /* set_values_hook */
170 XtInheritSetValuesAlmost, /* set_values_almost */
171 NULL, /* get_values_hook */
172 NULL, /* accept_focus */
173 XtVersion, /* version */
174 NULL, /* callback_private */
176 QueryGeometry, /* query_geometry */
177 NULL, /* display_accelerator*/
178 NULL, /* extension */
181 /* composite_class fields */
182 GeometryManager, /* geometry_manager */
183 ChangeManaged, /* change_managed */
184 XtInheritInsertChild, /* insert_child */
185 XtInheritDeleteChild, /* delete_child */
186 NULL, /* extension */
189 /* constraint_class fields */
190 treeConstraintResources, /* subresources */
191 XtNumber(treeConstraintResources), /* subresource_count */
192 sizeof(TreeConstraintsRec), /* constraint_size */
193 ConstraintInitialize, /* initialize */
194 ConstraintDestroy, /* destroy */
195 ConstraintSetValues, /* set_values */
196 NULL, /* extension */
199 /* Tree class fields */
204 WidgetClass treeWidgetClass = (WidgetClass) &treeClassRec;
207 /*****************************************************************************
209 * tree utility routines *
211 *****************************************************************************/
213 static void initialize_dimensions (listp, sizep, n)
219 register Dimension *l;
222 *listp = (Dimension *) XtCalloc ((unsigned int) n,
223 (unsigned int) sizeof(Dimension));
224 *sizep = ((*listp) ? n : 0);
228 *listp = (Dimension *) XtRealloc((char *) *listp,
229 (unsigned int) (n*sizeof(Dimension)));
234 for (i = *sizep, l = (*listp) + i; i < n; i++, l++) *l = 0;
240 static GC get_tree_gc (w)
243 XtGCMask valuemask = GCBackground | GCForeground;
246 values.background = w->core.background_pixel;
247 values.foreground = w->tree.foreground;
248 if (w->tree.line_width != 0) {
249 valuemask |= GCLineWidth;
250 values.line_width = w->tree.line_width;
253 return XtGetGC ((Widget) w, valuemask, &values);
256 static void insert_node (parent, node)
260 TreeConstraints nc = TREE_CONSTRAINT(node);
263 nc->tree.parent = parent;
265 if (parent == NULL) return;
268 * If there isn't more room in the children array,
269 * allocate additional space.
271 pc = TREE_CONSTRAINT(parent);
272 nindex = pc->tree.n_children;
274 if (pc->tree.n_children == pc->tree.max_children) {
275 pc->tree.max_children += (pc->tree.max_children / 2) + 2;
276 pc->tree.children = (WidgetList) XtRealloc ((char *)pc->tree.children,
278 ((pc->tree.max_children) *
283 * Add the sub_node in the next available slot and
284 * increment the counter.
286 pc->tree.children[nindex] = node;
287 pc->tree.n_children++;
290 static void delete_node (parent, node)
297 * Make sure the parent exists.
301 pc = TREE_CONSTRAINT(parent);
304 * Find the sub_node on its parent's list.
306 for (pos = 0; pos < pc->tree.n_children; pos++)
307 if (pc->tree.children[pos] == node) break;
309 if (pos == pc->tree.n_children) return;
312 * Decrement the number of children
314 pc->tree.n_children--;
317 * Fill in the gap left by the sub_node.
318 * Zero the last slot for good luck.
320 for (i = pos; i < pc->tree.n_children; i++)
321 pc->tree.children[i] = pc->tree.children[i+1];
323 pc->tree.children[pc->tree.n_children]=0;
326 static void check_gravity (tw, grav)
330 switch (tw->tree.gravity) {
331 case WestGravity: case NorthGravity: case EastGravity: case SouthGravity:
334 tw->tree.gravity = grav;
340 /*****************************************************************************
342 * tree class methods *
344 *****************************************************************************/
346 static void ClassInitialize ()
348 XawInitializeWidgetSet();
349 XtAddConverter (XtRString, XtRGravity, XmuCvtStringToGravity,
350 (XtConvertArgList) NULL, (Cardinal) 0);
354 static void Initialize (grequest, gnew)
355 Widget grequest, gnew;
357 TreeWidget request = (TreeWidget) grequest, new = (TreeWidget) gnew;
361 * Make sure the widget's width and height are
364 if (request->core.width <= 0) new->core.width = 5;
365 if (request->core.height <= 0) new->core.height = 5;
368 * Set the padding according to the orientation
370 if (request->tree.hpad == 0 && request->tree.vpad == 0) {
371 if (IsHorizontal (request)) {
372 new->tree.hpad = TREE_HORIZONTAL_DEFAULT_SPACING;
373 new->tree.vpad = TREE_VERTICAL_DEFAULT_SPACING;
375 new->tree.hpad = TREE_VERTICAL_DEFAULT_SPACING;
376 new->tree.vpad = TREE_HORIZONTAL_DEFAULT_SPACING;
381 * Create a graphics context for the connecting lines.
383 new->tree.gc = get_tree_gc (new);
386 * Create the hidden root widget.
388 new->tree.tree_root = (Widget) NULL;
389 XtSetArg(args[0], XtNwidth, 1);
390 XtSetArg(args[1], XtNheight, 1);
391 new->tree.tree_root = XtCreateWidget ("root", widgetClass, gnew, args,TWO);
394 * Allocate the array used to hold the widest values per depth
396 new->tree.largest = NULL;
397 new->tree.n_largest = 0;
398 initialize_dimensions (&new->tree.largest, &new->tree.n_largest,
402 * make sure that our gravity is one of the acceptable values
404 check_gravity (new, WestGravity);
409 static void ConstraintInitialize (request, new)
412 TreeConstraints tc = TREE_CONSTRAINT(new);
413 TreeWidget tw = (TreeWidget) new->core.parent;
416 * Initialize the widget to have no sub-nodes.
418 tc->tree.n_children = 0;
419 tc->tree.max_children = 0;
420 tc->tree.children = (Widget *) NULL;
421 tc->tree.x = tc->tree.y = 0;
422 tc->tree.bbsubwidth = 0;
423 tc->tree.bbsubheight = 0;
427 * If this widget has a super-node, add it to that
428 * widget' sub-nodes list. Otherwise make it a sub-node of
429 * the tree_root widget.
432 insert_node (tc->tree.parent, new);
433 else if (tw->tree.tree_root)
434 insert_node (tw->tree.tree_root, new);
439 static Boolean SetValues (gcurrent, grequest, gnew)
440 Widget gcurrent, grequest, gnew;
442 TreeWidget current = (TreeWidget) gcurrent, new = (TreeWidget) gnew;
443 Boolean redraw = FALSE;
446 * If the foreground color has changed, redo the GC's
447 * and indicate a redraw.
449 if (new->tree.foreground != current->tree.foreground ||
450 new->core.background_pixel != current->core.background_pixel ||
451 new->tree.line_width != current->tree.line_width) {
452 XtReleaseGC (gnew, new->tree.gc);
453 new->tree.gc = get_tree_gc (new);
458 * If the minimum spacing has changed, recalculate the
459 * tree layout. layout_tree() does a redraw, so we don't
460 * need SetValues to do another one.
462 if (new->tree.gravity != current->tree.gravity) {
463 check_gravity (new, current->tree.gravity);
466 if (IsHorizontal(new) != IsHorizontal(current)) {
467 if (new->tree.vpad == current->tree.vpad &&
468 new->tree.hpad == current->tree.hpad) {
469 new->tree.vpad = current->tree.hpad;
470 new->tree.hpad = current->tree.vpad;
474 if (new->tree.vpad != current->tree.vpad ||
475 new->tree.hpad != current->tree.hpad ||
476 new->tree.gravity != current->tree.gravity) {
477 layout_tree (new, TRUE);
485 static Boolean ConstraintSetValues (current, request, new, args, num_args)
486 Widget current, request, new;
490 TreeConstraints newc = TREE_CONSTRAINT(new);
491 TreeConstraints curc = TREE_CONSTRAINT(current);
492 TreeWidget tw = (TreeWidget) new->core.parent;
495 * If the parent field has changed, remove the widget
496 * from the old widget's children list and add it to the
499 if (curc->tree.parent != newc->tree.parent){
500 if (curc->tree.parent)
501 delete_node (curc->tree.parent, new);
502 if (newc->tree.parent)
503 insert_node(newc->tree.parent, new);
506 * If the Tree widget has been realized,
507 * compute new layout.
509 if (XtIsRealized((Widget)tw))
510 layout_tree (tw, FALSE);
516 static void ConstraintDestroy (w)
519 TreeConstraints tc = TREE_CONSTRAINT(w);
520 TreeWidget tw = (TreeWidget) XtParent(w);
524 * Remove the widget from its parent's sub-nodes list and
525 * make all this widget's sub-nodes sub-nodes of the parent.
528 if (tw->tree.tree_root == w) {
529 if (tc->tree.n_children > 0)
530 tw->tree.tree_root = tc->tree.children[0];
532 tw->tree.tree_root = NULL;
535 delete_node (tc->tree.parent, (Widget) w);
536 for (i = 0; i< tc->tree.n_children; i++)
537 insert_node (tc->tree.parent, tc->tree.children[i]);
539 layout_tree ((TreeWidget) (w->core.parent), FALSE);
543 static XtGeometryResult GeometryManager (w, request, reply)
545 XtWidgetGeometry *request;
546 XtWidgetGeometry *reply;
549 TreeWidget tw = (TreeWidget) w->core.parent;
552 * No position changes allowed!.
554 if ((request->request_mode & CWX && request->x!=w->core.x)
555 ||(request->request_mode & CWY && request->y!=w->core.y))
556 return (XtGeometryNo);
559 * Allow all resize requests.
562 if (request->request_mode & CWWidth)
563 w->core.width = request->width;
564 if (request->request_mode & CWHeight)
565 w->core.height = request->height;
566 if (request->request_mode & CWBorderWidth)
567 w->core.border_width = request->border_width;
569 if (tw->tree.auto_reconfigure) layout_tree (tw, FALSE);
570 return (XtGeometryYes);
573 static void ChangeManaged (gw)
576 layout_tree ((TreeWidget) gw, FALSE);
580 static void Destroy (gw)
583 TreeWidget w = (TreeWidget) gw;
585 XtReleaseGC (gw, w->tree.gc);
586 if (w->tree.largest) XtFree ((char *) w->tree.largest);
591 static void Redisplay (tw, event, region)
597 * If the Tree widget is visible, visit each managed child.
599 if (tw->core.visible) {
601 Display *dpy = XtDisplay (tw);
602 Window w = XtWindow (tw);
604 for (i = 0; i < tw->composite.num_children; i++) {
605 register Widget child = tw->composite.children[i];
606 TreeConstraints tc = TREE_CONSTRAINT(child);
609 * Don't draw lines from the fake tree_root.
611 if (child != tw->tree.tree_root && tc->tree.n_children) {
612 int srcx = child->core.x + child->core.border_width;
613 int srcy = child->core.y + child->core.border_width;
615 switch (tw->tree.gravity) {
617 srcx += child->core.width + child->core.border_width;
620 srcy += child->core.height / 2;
624 srcy += child->core.height + child->core.border_width;
627 srcx += child->core.width / 2;
631 for (j = 0; j < tc->tree.n_children; j++) {
632 register Widget k = tc->tree.children[j];
633 GC gc = (tc->tree.gc ? tc->tree.gc : tw->tree.gc);
635 switch (tw->tree.gravity) {
638 * right center to left center
640 XDrawLine (dpy, w, gc, srcx, srcy,
642 (k->core.y + ((int) k->core.border_width) +
643 ((int) k->core.height) / 2));
648 * bottom center to top center
650 XDrawLine (dpy, w, gc, srcx, srcy,
651 (k->core.x + ((int) k->core.border_width) +
652 ((int) k->core.width) / 2),
658 * left center to right center
660 XDrawLine (dpy, w, gc, srcx, srcy,
662 (((int) k->core.border_width) << 1) +
663 (int) k->core.width),
664 (k->core.y + ((int) k->core.border_width) +
665 ((int) k->core.height) / 2));
670 * top center to bottom center
672 XDrawLine (dpy, w, gc, srcx, srcy,
673 (k->core.x + ((int) k->core.border_width) +
674 ((int) k->core.width) / 2),
676 (((int) k->core.border_width) << 1) +
677 (int) k->core.height));
686 static XtGeometryResult QueryGeometry (w, intended, preferred)
688 XtWidgetGeometry *intended, *preferred;
690 register TreeWidget tw = (TreeWidget) w;
692 preferred->request_mode = (CWWidth | CWHeight);
693 preferred->width = tw->tree.maxwidth;
694 preferred->height = tw->tree.maxheight;
696 if (((intended->request_mode & (CWWidth | CWHeight)) ==
697 (CWWidth | CWHeight)) &&
698 intended->width == preferred->width &&
699 intended->height == preferred->height)
700 return XtGeometryYes;
701 else if (preferred->width == w->core.width &&
702 preferred->height == w->core.height)
705 return XtGeometryAlmost;
709 /*****************************************************************************
711 * tree layout algorithm *
713 * Each node in the tree is "shrink-wrapped" with a minimal bounding *
714 * rectangle, laid next to its siblings (with a small about of padding in *
715 * between) and then wrapped with their parent. Parents are centered about *
716 * their children (or vice versa if the parent is larger than the children). *
718 *****************************************************************************/
720 static void compute_bounding_box_subtree (tree, w, depth)
725 TreeConstraints tc = TREE_CONSTRAINT(w); /* info attached to all kids */
727 Bool horiz = IsHorizontal (tree);
728 Dimension newwidth, newheight;
729 Dimension bw2 = w->core.border_width * 2;
732 * Set the max-size per level.
734 if (depth >= tree->tree.n_largest) {
735 initialize_dimensions (&tree->tree.largest,
736 &tree->tree.n_largest, depth + 1);
738 newwidth = ((horiz ? w->core.width : w->core.height) + bw2);
739 if (tree->tree.largest[depth] < newwidth)
740 tree->tree.largest[depth] = newwidth;
746 tc->tree.bbwidth = w->core.width + bw2;
747 tc->tree.bbheight = w->core.height + bw2;
749 if (tc->tree.n_children == 0) return;
752 * Figure the size of the opposite dimension (vertical if tree is
753 * horizontal, else vice versa). The other dimension will be set
754 * in the second pass once we know the maximum dimensions.
758 for (i = 0; i < tc->tree.n_children; i++) {
759 Widget child = tc->tree.children[i];
760 TreeConstraints cc = TREE_CONSTRAINT(child);
762 compute_bounding_box_subtree (tree, child, depth + 1);
765 if (newwidth < cc->tree.bbwidth) newwidth = cc->tree.bbwidth;
766 newheight += tree->tree.vpad + cc->tree.bbheight;
768 if (newheight < cc->tree.bbheight) newheight = cc->tree.bbheight;
769 newwidth += tree->tree.hpad + cc->tree.bbwidth;
774 tc->tree.bbsubwidth = newwidth;
775 tc->tree.bbsubheight = newheight;
778 * Now fit parent onto side (or top) of bounding box and correct for
779 * extra padding. Be careful of unsigned arithmetic.
782 tc->tree.bbwidth += tree->tree.hpad + newwidth;
783 newheight -= tree->tree.vpad;
784 if (newheight > tc->tree.bbheight) tc->tree.bbheight = newheight;
786 tc->tree.bbheight += tree->tree.vpad + newheight;
787 newwidth -= tree->tree.hpad;
788 if (newwidth > tc->tree.bbwidth) tc->tree.bbwidth = newwidth;
793 static void set_positions (tw, w, level)
801 TreeConstraints tc = TREE_CONSTRAINT(w);
805 * mirror if necessary
807 switch (tw->tree.gravity) {
809 tc->tree.x = (((Position) tw->tree.maxwidth) -
810 ((Position) w->core.width) - tc->tree.x);
814 tc->tree.y = (((Position) tw->tree.maxheight) -
815 ((Position) w->core.height) - tc->tree.y);
820 * Move the widget into position.
822 XtMoveWidget (w, tc->tree.x, tc->tree.y);
826 * Set the positions of all children.
828 for (i = 0; i < tc->tree.n_children; i++)
829 set_positions (tw, tc->tree.children[i], level + 1);
834 static void arrange_subtree (tree, w, depth, x, y)
840 TreeConstraints tc = TREE_CONSTRAINT(w); /* info attached to all kids */
841 TreeConstraints firstcc, lastcc;
844 Bool horiz = IsHorizontal (tree);
847 Dimension bw2 = w->core.border_width * 2;
848 Bool relayout = True;
852 * If no children, then just lay out where requested.
858 int myh = (w->core.height + bw2);
860 if (myh > (int)tc->tree.bbsubheight) {
861 y += (myh - (int)tc->tree.bbsubheight) / 2;
865 int myw = (w->core.width + bw2);
867 if (myw > (int)tc->tree.bbsubwidth) {
868 x += (myw - (int)tc->tree.bbsubwidth) / 2;
873 if ((tmp = ((Dimension) x) + tc->tree.bbwidth) > tree->tree.maxwidth)
874 tree->tree.maxwidth = tmp;
875 if ((tmp = ((Dimension) y) + tc->tree.bbheight) > tree->tree.maxheight)
876 tree->tree.maxheight = tmp;
878 if (tc->tree.n_children == 0) return;
882 * Have children, so walk down tree laying out children, then laying
886 newx = x + tree->tree.largest[depth];
887 if (depth > 0) newx += tree->tree.hpad;
891 newy = y + tree->tree.largest[depth];
892 if (depth > 0) newy += tree->tree.vpad;
895 for (i = 0; i < tc->tree.n_children; i++) {
898 child = tc->tree.children[i]; /* last value is used outside loop */
899 cc = TREE_CONSTRAINT(child);
901 arrange_subtree (tree, child, depth + 1, newx, newy);
903 newy += tree->tree.vpad + cc->tree.bbheight;
905 newx += tree->tree.hpad + cc->tree.bbwidth;
910 * now layout parent between first and last children
914 firstcc = TREE_CONSTRAINT (tc->tree.children[0]);
915 lastcc = TREE_CONSTRAINT (child);
917 /* Adjustments are disallowed if they result in a position above
918 * or to the left of the originally requested position, because
919 * this could collide with the position of the previous sibling.
923 adjusted = firstcc->tree.y +
924 ((lastcc->tree.y + (Position) child->core.height +
925 (Position) child->core.border_width * 2 -
926 firstcc->tree.y - (Position) w->core.height -
927 (Position) w->core.border_width * 2 + 1) / 2);
928 if (adjusted > tc->tree.y) tc->tree.y = adjusted;
930 adjusted = firstcc->tree.x +
931 ((lastcc->tree.x + (Position) child->core.width +
932 (Position) child->core.border_width * 2 -
933 firstcc->tree.x - (Position) w->core.width -
934 (Position) w->core.border_width * 2 + 1) / 2);
935 if (adjusted > tc->tree.x) tc->tree.x = adjusted;
941 static void set_tree_size (tw, insetvalues, width, height)
944 Dimension width, height;
947 tw->core.width = width;
948 tw->core.height = height;
950 Dimension replyWidth = 0, replyHeight = 0;
951 XtGeometryResult result = XtMakeResizeRequest ((Widget) tw,
956 * Accept any compromise.
958 if (result == XtGeometryAlmost)
959 XtMakeResizeRequest ((Widget) tw, replyWidth, replyHeight,
960 (Dimension *) NULL, (Dimension *) NULL);
965 static void layout_tree (tw, insetvalues)
973 * Do a depth-first search computing the width and height of the bounding
974 * box for the tree at that position (and below). Then, walk again using
975 * this information to layout the children at each level.
978 if (tw->tree.tree_root == NULL)
981 tw->tree.maxwidth = tw->tree.maxheight = 0;
982 for (i = 0, dp = tw->tree.largest; i < tw->tree.n_largest; i++, dp++)
984 initialize_dimensions (&tw->tree.largest, &tw->tree.n_largest,
986 compute_bounding_box_subtree (tw, tw->tree.tree_root, 0);
989 * Second pass to do final layout. Each child's bounding box is stacked
990 * on top of (if horizontal, else next to) on top of its siblings. The
991 * parent is centered between the first and last children.
993 arrange_subtree (tw, tw->tree.tree_root, 0, 0, 0);
996 * Move each widget into place.
998 set_tree_size (tw, insetvalues, tw->tree.maxwidth, tw->tree.maxheight);
999 set_positions (tw, tw->tree.tree_root, 0);
1004 if (XtIsRealized ((Widget) tw)) {
1005 XClearArea (XtDisplay(tw), XtWindow((Widget)tw), 0, 0, 0, 0, True);
1011 /*****************************************************************************
1015 *****************************************************************************/
1018 #if NeedFunctionPrototypes
1019 XawTreeForceLayout (Widget tree)
1021 XawTreeForceLayout (tree)
1025 layout_tree ((TreeWidget) tree, FALSE);