3 Copyright 1990, 1994, 1998 The Open Group
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
25 * Copyright 1989 Prentice Hall
27 * Permission to use, copy, modify, and distribute this software for any
28 * purpose and without fee is hereby granted, provided that the above
29 * copyright notice appear in all copies and that both the copyright notice
30 * and this permission notice appear in supporting documentation.
32 * Prentice Hall and the authors disclaim all warranties with regard
33 * to this software, including all implied warranties of merchantability and
34 * fitness. In no event shall Prentice Hall or the authors be liable
35 * for any special, indirect or cosequential damages or any damages whatsoever
36 * resulting from loss of use, data or profits, whether in an action of
37 * contract, negligence or other tortious action, arising out of or in
38 * connection with the use or performance of this software.
40 * Authors: Jim Fulton, MIT X Consortium,
41 * based on a version by Douglas Young, Prentice Hall
43 * This widget is based on the Tree widget described on pages 397-419 of
44 * Douglas Young's book "The X Window System, Programming and Applications
45 * with Xt OSF/Motif Edition." The layout code has been rewritten to use
46 * additional blank space to make the structure of the graph easier to see
47 * as well as to support vertical trees.
53 #include <X11/IntrinsicP.h>
54 #include <X11/StringDefs.h>
55 #include <X11/Xaw/XawInit.h>
56 #include <X11/Xaw/Cardinals.h>
57 #include <X11/Xaw/TreeP.h>
60 #define IsHorizontal(tw) ((tw)->tree.gravity == WestGravity || \
61 (tw)->tree.gravity == EastGravity)
66 static void XawTreeChangeManaged(Widget);
67 static void XawTreeClassInitialize(void);
68 static void XawTreeConstraintDestroy(Widget);
69 static void XawTreeConstraintInitialize(Widget, Widget, ArgList, Cardinal*);
70 static Boolean XawTreeConstraintSetValues(Widget, Widget, Widget,
72 static void XawTreeDestroy(Widget);
73 static XtGeometryResult XawTreeGeometryManager(Widget, XtWidgetGeometry*,
75 static void XawTreeInitialize(Widget, Widget, ArgList, Cardinal*);
76 static XtGeometryResult XawTreeQueryGeometry(Widget, XtWidgetGeometry*,
78 static void XawTreeRedisplay(Widget, XEvent*, Region);
79 static Boolean XawTreeSetValues(Widget, Widget, Widget, ArgList, Cardinal*);
84 static void arrange_subtree(TreeWidget, Widget, int, int, int);
85 static void check_gravity(TreeWidget, XtGravity);
86 static void compute_bounding_box_subtree(TreeWidget, Widget, int);
87 static void delete_node(Widget, Widget);
88 static GC get_tree_gc(TreeWidget);
89 static void initialize_dimensions(Dimension**, int*, int);
90 static void insert_node(Widget, Widget);
91 static void layout_tree(TreeWidget, Bool);
92 static void set_positions(TreeWidget, Widget, int);
93 static void set_tree_size(TreeWidget, Bool, unsigned int, unsigned int);
100 * resources of the tree itself
102 static XtResource resources[] = {
103 { XtNautoReconfigure, XtCAutoReconfigure, XtRBoolean, sizeof (Boolean),
104 XtOffsetOf(TreeRec, tree.auto_reconfigure), XtRImmediate,
106 { XtNhSpace, XtCHSpace, XtRDimension, sizeof (Dimension),
107 XtOffsetOf(TreeRec, tree.hpad), XtRImmediate, (XtPointer) 0 },
108 { XtNvSpace, XtCVSpace, XtRDimension, sizeof (Dimension),
109 XtOffsetOf(TreeRec, tree.vpad), XtRImmediate, (XtPointer) 0 },
110 { XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel),
111 XtOffsetOf(TreeRec, tree.foreground), XtRString,
112 XtDefaultForeground},
113 { XtNlineWidth, XtCLineWidth, XtRDimension, sizeof (Dimension),
114 XtOffsetOf(TreeRec, tree.line_width), XtRImmediate, (XtPointer) 0 },
115 { XtNgravity, XtCGravity, XtRGravity, sizeof (XtGravity),
116 XtOffsetOf(TreeRec, tree.gravity), XtRImmediate,
117 (XtPointer) WestGravity },
119 { XawNdisplayList, XawCDisplayList, XawRDisplayList, sizeof(XawDisplayList*),
120 XtOffsetOf(TreeRec, tree.display_list), XtRImmediate,
127 * resources that are attached to all children of the tree
129 static XtResource treeConstraintResources[] = {
130 { XtNtreeParent, XtCTreeParent, XtRWidget, sizeof (Widget),
131 XtOffsetOf(TreeConstraintsRec, tree.parent), XtRImmediate, NULL },
132 { XtNtreeGC, XtCTreeGC, XtRGC, sizeof(GC),
133 XtOffsetOf(TreeConstraintsRec, tree.gc), XtRImmediate, NULL },
137 TreeClassRec treeClassRec = {
139 /* core_class fields */
140 (WidgetClass) &constraintClassRec, /* superclass */
141 "Tree", /* class_name */
142 sizeof(TreeRec), /* widget_size */
143 XawTreeClassInitialize, /* class_init */
144 NULL, /* class_part_init */
145 FALSE, /* class_inited */
146 XawTreeInitialize, /* initialize */
147 NULL, /* initialize_hook */
148 XtInheritRealize, /* realize */
151 resources, /* resources */
152 XtNumber(resources), /* num_resources */
153 NULLQUARK, /* xrm_class */
154 TRUE, /* compress_motion */
155 TRUE, /* compress_exposure */
156 TRUE, /* compress_enterleave*/
157 TRUE, /* visible_interest */
158 XawTreeDestroy, /* destroy */
160 XawTreeRedisplay, /* expose */
161 XawTreeSetValues, /* set_values */
162 NULL, /* set_values_hook */
163 XtInheritSetValuesAlmost, /* set_values_almost */
164 NULL, /* get_values_hook */
165 NULL, /* accept_focus */
166 XtVersion, /* version */
167 NULL, /* callback_private */
169 XawTreeQueryGeometry, /* query_geometry */
170 NULL, /* display_accelerator*/
171 NULL, /* extension */
174 /* composite_class fields */
175 XawTreeGeometryManager, /* geometry_manager */
176 XawTreeChangeManaged, /* change_managed */
177 XtInheritInsertChild, /* insert_child */
178 XtInheritDeleteChild, /* delete_child */
179 NULL, /* extension */
182 /* constraint_class fields */
183 treeConstraintResources, /* subresources */
184 XtNumber(treeConstraintResources), /* subresource_count */
185 sizeof(TreeConstraintsRec), /* constraint_size */
186 XawTreeConstraintInitialize, /* initialize */
187 XawTreeConstraintDestroy, /* destroy */
188 XawTreeConstraintSetValues, /* set_values */
189 NULL, /* extension */
192 /* Tree class fields */
197 WidgetClass treeWidgetClass = (WidgetClass) &treeClassRec;
200 /*****************************************************************************
202 * tree utility routines *
204 *****************************************************************************/
207 initialize_dimensions(Dimension **listp, int *sizep, int n)
213 *listp = (Dimension *) XtCalloc ((unsigned int) n,
214 (unsigned int) sizeof(Dimension));
215 *sizep = ((*listp) ? n : 0);
219 *listp = (Dimension *) XtRealloc((char *) *listp,
220 (unsigned int) (n*sizeof(Dimension)));
225 for (i = *sizep, l = (*listp) + i; i < n; i++, l++) *l = 0;
232 get_tree_gc(TreeWidget w)
234 XtGCMask valuemask = GCBackground | GCForeground;
237 values.background = w->core.background_pixel;
238 values.foreground = w->tree.foreground;
239 if (w->tree.line_width != 0) {
240 valuemask |= GCLineWidth;
241 values.line_width = w->tree.line_width;
244 return XtGetGC ((Widget) w, valuemask, &values);
248 insert_node(Widget parent, Widget node)
251 TreeConstraints nc = TREE_CONSTRAINT(node);
254 nc->tree.parent = parent;
256 if (parent == NULL) return;
259 * If there isn't more room in the children array,
260 * allocate additional space.
262 pc = TREE_CONSTRAINT(parent);
263 nindex = pc->tree.n_children;
265 if (pc->tree.n_children == pc->tree.max_children) {
266 pc->tree.max_children += (pc->tree.max_children / 2) + 2;
267 pc->tree.children = (WidgetList) XtRealloc ((char *)pc->tree.children,
269 ((pc->tree.max_children) *
274 * Add the sub_node in the next available slot and
275 * increment the counter.
277 pc->tree.children[nindex] = node;
278 pc->tree.n_children++;
282 delete_node(Widget parent, Widget node)
288 * Make sure the parent exists.
292 pc = TREE_CONSTRAINT(parent);
295 * Find the sub_node on its parent's list.
297 for (pos = 0; pos < pc->tree.n_children; pos++)
298 if (pc->tree.children[pos] == node) break;
300 if (pos == pc->tree.n_children) return;
303 * Decrement the number of children
305 pc->tree.n_children--;
308 * Fill in the gap left by the sub_node.
309 * Zero the last slot for good luck.
311 for (i = pos; i < pc->tree.n_children; i++)
312 pc->tree.children[i] = pc->tree.children[i+1];
314 pc->tree.children[pc->tree.n_children] = NULL;
318 check_gravity(TreeWidget tw, XtGravity grav)
320 switch (tw->tree.gravity) {
321 case WestGravity: case NorthGravity: case EastGravity: case SouthGravity:
324 tw->tree.gravity = grav;
330 /*****************************************************************************
332 * tree class methods *
334 *****************************************************************************/
337 XawTreeClassInitialize(void)
339 XawInitializeWidgetSet();
340 XtAddConverter(XtRString, XtRGravity, XmuCvtStringToGravity, NULL, 0);
341 XtSetTypeConverter(XtRGravity, XtRString, XmuCvtGravityToString,
342 NULL, 0, XtCacheNone, NULL);
348 XawTreeInitialize(Widget grequest, Widget gnew,
349 ArgList args, Cardinal *num_args)
351 TreeWidget request = (TreeWidget) grequest, cnew = (TreeWidget) gnew;
355 * Make sure the widget's width and height are
358 if (request->core.width <= 0) cnew->core.width = 5;
359 if (request->core.height <= 0) cnew->core.height = 5;
362 * Set the padding according to the orientation
364 if (request->tree.hpad == 0 && request->tree.vpad == 0) {
365 if (IsHorizontal (request)) {
366 cnew->tree.hpad = TREE_HORIZONTAL_DEFAULT_SPACING;
367 cnew->tree.vpad = TREE_VERTICAL_DEFAULT_SPACING;
369 cnew->tree.hpad = TREE_VERTICAL_DEFAULT_SPACING;
370 cnew->tree.vpad = TREE_HORIZONTAL_DEFAULT_SPACING;
375 * Create a graphics context for the connecting lines.
377 cnew->tree.gc = get_tree_gc (cnew);
380 * Create the hidden root widget.
382 cnew->tree.tree_root = (Widget) NULL;
383 XtSetArg(arglist[0], XtNwidth, 1);
384 XtSetArg(arglist[1], XtNheight, 1);
385 cnew->tree.tree_root = XtCreateWidget ("root", widgetClass, gnew,
389 * Allocate the array used to hold the widest values per depth
391 cnew->tree.largest = NULL;
392 cnew->tree.n_largest = 0;
393 initialize_dimensions (&cnew->tree.largest, &cnew->tree.n_largest,
397 * make sure that our gravity is one of the acceptable values
399 check_gravity (cnew, WestGravity);
405 XawTreeConstraintInitialize(Widget request, Widget cnew,
406 ArgList args, Cardinal *num_args)
408 TreeConstraints tc = TREE_CONSTRAINT(cnew);
409 TreeWidget tw = (TreeWidget) cnew->core.parent;
412 * Initialize the widget to have no sub-nodes.
414 tc->tree.n_children = 0;
415 tc->tree.max_children = 0;
416 tc->tree.children = (Widget *) NULL;
417 tc->tree.x = tc->tree.y = 0;
418 tc->tree.bbsubwidth = 0;
419 tc->tree.bbsubheight = 0;
423 * If this widget has a super-node, add it to that
424 * widget' sub-nodes list. Otherwise make it a sub-node of
425 * the tree_root widget.
428 insert_node (tc->tree.parent, cnew);
429 else if (tw->tree.tree_root)
430 insert_node (tw->tree.tree_root, cnew);
436 XawTreeSetValues(Widget gcurrent, Widget grequest, Widget gnew,
437 ArgList args, Cardinal *num_args)
439 TreeWidget current = (TreeWidget) gcurrent, cnew = (TreeWidget) gnew;
440 Boolean redraw = FALSE;
443 * If the foreground color has changed, redo the GC's
444 * and indicate a redraw.
446 if (cnew->tree.foreground != current->tree.foreground ||
447 cnew->core.background_pixel != current->core.background_pixel ||
448 cnew->tree.line_width != current->tree.line_width) {
449 XtReleaseGC (gnew, cnew->tree.gc);
450 cnew->tree.gc = get_tree_gc (cnew);
455 * If the minimum spacing has changed, recalculate the
456 * tree layout. layout_tree() does a redraw, so we don't
457 * need SetValues to do another one.
459 if (cnew->tree.gravity != current->tree.gravity) {
460 check_gravity (cnew, current->tree.gravity);
463 if (IsHorizontal(cnew) != IsHorizontal(current)) {
464 if (cnew->tree.vpad == current->tree.vpad &&
465 cnew->tree.hpad == current->tree.hpad) {
466 cnew->tree.vpad = current->tree.hpad;
467 cnew->tree.hpad = current->tree.vpad;
471 if (cnew->tree.vpad != current->tree.vpad ||
472 cnew->tree.hpad != current->tree.hpad ||
473 cnew->tree.gravity != current->tree.gravity) {
474 layout_tree (cnew, TRUE);
483 XawTreeConstraintSetValues(Widget current, Widget request, Widget cnew,
484 ArgList args, Cardinal *num_args)
486 TreeConstraints newc = TREE_CONSTRAINT(cnew);
487 TreeConstraints curc = TREE_CONSTRAINT(current);
488 TreeWidget tw = (TreeWidget) cnew->core.parent;
491 * If the parent field has changed, remove the widget
492 * from the old widget's children list and add it to the
495 if (curc->tree.parent != newc->tree.parent){
496 if (curc->tree.parent)
497 delete_node (curc->tree.parent, cnew);
498 if (newc->tree.parent)
499 insert_node(newc->tree.parent, cnew);
502 * If the Tree widget has been realized,
503 * compute new layout.
505 if (XtIsRealized((Widget)tw))
506 layout_tree (tw, FALSE);
513 XawTreeConstraintDestroy(Widget w)
515 TreeConstraints tc = TREE_CONSTRAINT(w);
516 TreeWidget tw = (TreeWidget) XtParent(w);
520 * Remove the widget from its parent's sub-nodes list and
521 * make all this widget's sub-nodes sub-nodes of the parent.
524 if (tw->tree.tree_root == w) {
525 if (tc->tree.n_children > 0)
526 tw->tree.tree_root = tc->tree.children[0];
528 tw->tree.tree_root = NULL;
531 delete_node (tc->tree.parent, (Widget) w);
532 for (i = 0; i< tc->tree.n_children; i++)
533 insert_node (tc->tree.parent, tc->tree.children[i]);
535 layout_tree ((TreeWidget) (w->core.parent), FALSE);
539 static XtGeometryResult
540 XawTreeGeometryManager(Widget w, XtWidgetGeometry *request,
541 XtWidgetGeometry *reply)
544 TreeWidget tw = (TreeWidget) w->core.parent;
547 * No position changes allowed!.
549 if ((request->request_mode & CWX && request->x!=w->core.x)
550 ||(request->request_mode & CWY && request->y!=w->core.y))
551 return (XtGeometryNo);
554 * Allow all resize requests.
557 if (request->request_mode & CWWidth)
558 w->core.width = request->width;
559 if (request->request_mode & CWHeight)
560 w->core.height = request->height;
561 if (request->request_mode & CWBorderWidth)
562 w->core.border_width = request->border_width;
564 if (tw->tree.auto_reconfigure) layout_tree (tw, FALSE);
565 return (XtGeometryYes);
569 XawTreeChangeManaged(Widget gw)
571 layout_tree ((TreeWidget) gw, FALSE);
576 XawTreeDestroy(Widget gw)
578 TreeWidget w = (TreeWidget) gw;
580 XtReleaseGC (gw, w->tree.gc);
581 if (w->tree.largest) XtFree ((char *) w->tree.largest);
587 XawTreeRedisplay(Widget gw, XEvent *event, Region region)
589 TreeWidget tw = (TreeWidget) gw;
592 if (tw->tree.display_list)
593 XawRunDisplayList(gw, tw->tree.display_list, event, region);
597 * If the Tree widget is visible, visit each managed child.
599 if (tw->core.visible) {
602 Display *dpy = XtDisplay (tw);
603 Window w = XtWindow (tw);
605 for (i = 0; i < tw->composite.num_children; i++) {
606 Widget child = tw->composite.children[i];
607 TreeConstraints tc = TREE_CONSTRAINT(child);
610 * Don't draw lines from the fake tree_root.
612 if (child != tw->tree.tree_root && tc->tree.n_children) {
613 int srcx = child->core.x + child->core.border_width;
614 int srcy = child->core.y + child->core.border_width;
616 switch (tw->tree.gravity) {
618 srcx += child->core.width + child->core.border_width;
621 srcy += child->core.height / 2;
625 srcy += child->core.height + child->core.border_width;
628 srcx += child->core.width / 2;
632 for (j = 0; j < tc->tree.n_children; j++) {
633 Widget k = tc->tree.children[j];
634 GC gc = (tc->tree.gc ? tc->tree.gc : tw->tree.gc);
636 switch (tw->tree.gravity) {
639 * right center to left center
641 XDrawLine (dpy, w, gc, srcx, srcy,
643 (k->core.y + ((int) k->core.border_width) +
644 ((int) k->core.height) / 2));
649 * bottom center to top center
651 XDrawLine (dpy, w, gc, srcx, srcy,
652 (k->core.x + ((int) k->core.border_width) +
653 ((int) k->core.width) / 2),
659 * left center to right center
661 XDrawLine (dpy, w, gc, srcx, srcy,
663 (((int) k->core.border_width) << 1) +
664 (int) k->core.width),
665 (k->core.y + ((int) k->core.border_width) +
666 ((int) k->core.height) / 2));
671 * top center to bottom center
673 XDrawLine (dpy, w, gc, srcx, srcy,
674 (k->core.x + ((int) k->core.border_width) +
675 ((int) k->core.width) / 2),
677 (((int) k->core.border_width) << 1) +
678 (int) k->core.height));
687 static XtGeometryResult
688 XawTreeQueryGeometry(Widget w, XtWidgetGeometry *intended,
689 XtWidgetGeometry *preferred)
691 TreeWidget tw = (TreeWidget) w;
693 preferred->request_mode = (CWWidth | CWHeight);
694 preferred->width = tw->tree.maxwidth;
695 preferred->height = tw->tree.maxheight;
697 if (((intended->request_mode & (CWWidth | CWHeight)) ==
698 (CWWidth | CWHeight)) &&
699 intended->width == preferred->width &&
700 intended->height == preferred->height)
701 return XtGeometryYes;
702 else if (preferred->width == w->core.width &&
703 preferred->height == w->core.height)
706 return XtGeometryAlmost;
710 /*****************************************************************************
712 * tree layout algorithm *
714 * Each node in the tree is "shrink-wrapped" with a minimal bounding *
715 * rectangle, laid next to its siblings (with a small about of padding in *
716 * between) and then wrapped with their parent. Parents are centered about *
717 * their children (or vice versa if the parent is larger than the children). *
719 *****************************************************************************/
722 compute_bounding_box_subtree(TreeWidget tree, Widget w, int depth)
724 TreeConstraints tc = TREE_CONSTRAINT(w); /* info attached to all kids */
726 Bool horiz = IsHorizontal (tree);
727 Dimension newwidth, newheight;
728 Dimension bw2 = w->core.border_width * 2;
731 * Set the max-size per level.
733 if (depth >= tree->tree.n_largest) {
734 initialize_dimensions (&tree->tree.largest,
735 &tree->tree.n_largest, depth + 1);
737 newwidth = ((horiz ? w->core.width : w->core.height) + bw2);
738 if (tree->tree.largest[depth] < newwidth)
739 tree->tree.largest[depth] = newwidth;
745 tc->tree.bbwidth = w->core.width + bw2;
746 tc->tree.bbheight = w->core.height + bw2;
748 if (tc->tree.n_children == 0) return;
751 * Figure the size of the opposite dimension (vertical if tree is
752 * horizontal, else vice versa). The other dimension will be set
753 * in the second pass once we know the maximum dimensions.
757 for (i = 0; i < tc->tree.n_children; i++) {
758 Widget child = tc->tree.children[i];
759 TreeConstraints cc = TREE_CONSTRAINT(child);
761 compute_bounding_box_subtree (tree, child, depth + 1);
764 if (newwidth < cc->tree.bbwidth) newwidth = cc->tree.bbwidth;
765 newheight += tree->tree.vpad + cc->tree.bbheight;
767 if (newheight < cc->tree.bbheight) newheight = cc->tree.bbheight;
768 newwidth += tree->tree.hpad + cc->tree.bbwidth;
773 tc->tree.bbsubwidth = newwidth;
774 tc->tree.bbsubheight = newheight;
777 * Now fit parent onto side (or top) of bounding box and correct for
778 * extra padding. Be careful of unsigned arithmetic.
781 tc->tree.bbwidth += tree->tree.hpad + newwidth;
782 newheight -= tree->tree.vpad;
783 if (newheight > tc->tree.bbheight) tc->tree.bbheight = newheight;
785 tc->tree.bbheight += tree->tree.vpad + newheight;
786 newwidth -= tree->tree.hpad;
787 if (newwidth > tc->tree.bbwidth) tc->tree.bbwidth = newwidth;
793 set_positions(TreeWidget tw, Widget w, int level)
798 TreeConstraints tc = TREE_CONSTRAINT(w);
802 * mirror if necessary
804 switch (tw->tree.gravity) {
806 tc->tree.x = (((Position) tw->tree.maxwidth) -
807 ((Position) w->core.width) - tc->tree.x);
811 tc->tree.y = (((Position) tw->tree.maxheight) -
812 ((Position) w->core.height) - tc->tree.y);
817 * Move the widget into position.
819 XtMoveWidget (w, tc->tree.x, tc->tree.y);
823 * Set the positions of all children.
825 for (i = 0; i < tc->tree.n_children; i++)
826 set_positions (tw, tc->tree.children[i], level + 1);
832 arrange_subtree(TreeWidget tree, Widget w, int depth, int x, int y)
834 TreeConstraints tc = TREE_CONSTRAINT(w); /* info attached to all kids */
835 TreeConstraints firstcc, lastcc;
838 Bool horiz = IsHorizontal (tree);
841 Dimension bw2 = w->core.border_width * 2;
842 Bool relayout = True;
846 * If no children, then just lay out where requested.
852 int myh = (w->core.height + bw2);
854 if (myh > (int)tc->tree.bbsubheight) {
855 y += (myh - (int)tc->tree.bbsubheight) / 2;
859 int myw = (w->core.width + bw2);
861 if (myw > (int)tc->tree.bbsubwidth) {
862 x += (myw - (int)tc->tree.bbsubwidth) / 2;
867 if ((tmp = ((Dimension) x) + tc->tree.bbwidth) > tree->tree.maxwidth)
868 tree->tree.maxwidth = tmp;
869 if ((tmp = ((Dimension) y) + tc->tree.bbheight) > tree->tree.maxheight)
870 tree->tree.maxheight = tmp;
872 if (tc->tree.n_children == 0) return;
876 * Have children, so walk down tree laying out children, then laying
880 newx = x + tree->tree.largest[depth];
881 if (depth > 0) newx += tree->tree.hpad;
885 newy = y + tree->tree.largest[depth];
886 if (depth > 0) newy += tree->tree.vpad;
889 for (i = 0; i < tc->tree.n_children; i++) {
892 child = tc->tree.children[i]; /* last value is used outside loop */
893 cc = TREE_CONSTRAINT(child);
895 arrange_subtree (tree, child, depth + 1, newx, newy);
897 newy += tree->tree.vpad + cc->tree.bbheight;
899 newx += tree->tree.hpad + cc->tree.bbwidth;
904 * now layout parent between first and last children
908 firstcc = TREE_CONSTRAINT (tc->tree.children[0]);
909 lastcc = TREE_CONSTRAINT (child);
911 /* Adjustments are disallowed if they result in a position above
912 * or to the left of the originally requested position, because
913 * this could collide with the position of the previous sibling.
917 adjusted = firstcc->tree.y +
918 ((lastcc->tree.y + (Position) child->core.height +
919 (Position) child->core.border_width * 2 -
920 firstcc->tree.y - (Position) w->core.height -
921 (Position) w->core.border_width * 2 + 1) / 2);
922 if (adjusted > tc->tree.y) tc->tree.y = adjusted;
924 adjusted = firstcc->tree.x +
925 ((lastcc->tree.x + (Position) child->core.width +
926 (Position) child->core.border_width * 2 -
927 firstcc->tree.x - (Position) w->core.width -
928 (Position) w->core.border_width * 2 + 1) / 2);
929 if (adjusted > tc->tree.x) tc->tree.x = adjusted;
936 set_tree_size(TreeWidget tw, Bool insetvalues,
937 unsigned int width, unsigned int height)
940 tw->core.width = width;
941 tw->core.height = height;
943 Dimension replyWidth = 0, replyHeight = 0;
944 XtGeometryResult result = XtMakeResizeRequest ((Widget) tw,
949 * Accept any compromise.
951 if (result == XtGeometryAlmost)
952 XtMakeResizeRequest ((Widget) tw, replyWidth, replyHeight,
953 (Dimension *) NULL, (Dimension *) NULL);
959 layout_tree(TreeWidget tw, Bool insetvalues)
965 * Do a depth-first search computing the width and height of the bounding
966 * box for the tree at that position (and below). Then, walk again using
967 * this information to layout the children at each level.
970 if (tw->tree.tree_root == NULL)
973 tw->tree.maxwidth = tw->tree.maxheight = 0;
974 for (i = 0, dp = tw->tree.largest; i < tw->tree.n_largest; i++, dp++)
976 initialize_dimensions (&tw->tree.largest, &tw->tree.n_largest,
978 compute_bounding_box_subtree (tw, tw->tree.tree_root, 0);
981 * Second pass to do final layout. Each child's bounding box is stacked
982 * on top of (if horizontal, else next to) on top of its siblings. The
983 * parent is centered between the first and last children.
985 arrange_subtree (tw, tw->tree.tree_root, 0, 0, 0);
988 * Move each widget into place.
990 set_tree_size (tw, insetvalues, tw->tree.maxwidth, tw->tree.maxheight);
991 set_positions (tw, tw->tree.tree_root, 0);
996 if (XtIsRealized ((Widget) tw)) {
997 XClearArea (XtDisplay(tw), XtWindow((Widget)tw), 0, 0, 0, 0, True);
1003 /*****************************************************************************
1007 *****************************************************************************/
1010 XawTreeForceLayout(Widget tree)
1012 layout_tree ((TreeWidget) tree, FALSE);