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, 1125ec34c4cSmrg (XtPointer) 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 if (!*listp) { 2107a84e134Smrg *listp = (Dimension *) XtCalloc ((unsigned int) n, 2117a84e134Smrg (unsigned int) sizeof(Dimension)); 2127a84e134Smrg *sizep = ((*listp) ? n : 0); 2137a84e134Smrg return; 2147a84e134Smrg } 2157a84e134Smrg if (n > *sizep) { 2167a84e134Smrg *listp = (Dimension *) XtRealloc((char *) *listp, 2175ec34c4cSmrg (Cardinal) ((size_t)n*sizeof(Dimension))); 2187a84e134Smrg if (!*listp) { 2197a84e134Smrg *sizep = 0; 2207a84e134Smrg return; 221efbcb2bfSmrg } else { 222efbcb2bfSmrg int i; 223efbcb2bfSmrg Dimension *l; 224efbcb2bfSmrg 225efbcb2bfSmrg for (i = *sizep, l = (*listp) + i; i < n; i++, l++) 226efbcb2bfSmrg *l = 0; 227efbcb2bfSmrg *sizep = n; 2287a84e134Smrg } 2297a84e134Smrg } 2307a84e134Smrg return; 2317a84e134Smrg} 2327a84e134Smrg 2337a84e134Smrgstatic GC 2347a84e134Smrgget_tree_gc(TreeWidget w) 2357a84e134Smrg{ 2367a84e134Smrg XtGCMask valuemask = GCBackground | GCForeground; 2377a84e134Smrg XGCValues values; 2387a84e134Smrg 2397a84e134Smrg values.background = w->core.background_pixel; 2407a84e134Smrg values.foreground = w->tree.foreground; 2417a84e134Smrg if (w->tree.line_width != 0) { 2427a84e134Smrg valuemask |= GCLineWidth; 2437a84e134Smrg values.line_width = w->tree.line_width; 2447a84e134Smrg } 2457a84e134Smrg 2467a84e134Smrg return XtGetGC ((Widget) w, valuemask, &values); 2477a84e134Smrg} 2487a84e134Smrg 2497a84e134Smrgstatic void 2507a84e134Smrginsert_node(Widget parent, Widget node) 2517a84e134Smrg{ 2527a84e134Smrg TreeConstraints pc; 2537a84e134Smrg TreeConstraints nc = TREE_CONSTRAINT(node); 2547a84e134Smrg int nindex; 255421c997bSmrg 2567a84e134Smrg nc->tree.parent = parent; 2577a84e134Smrg 2587a84e134Smrg if (parent == NULL) return; 2597a84e134Smrg 2607a84e134Smrg /* 261421c997bSmrg * If there isn't more room in the children array, 2627a84e134Smrg * allocate additional space. 263421c997bSmrg */ 2647a84e134Smrg pc = TREE_CONSTRAINT(parent); 2657a84e134Smrg nindex = pc->tree.n_children; 266421c997bSmrg 2677a84e134Smrg if (pc->tree.n_children == pc->tree.max_children) { 2687a84e134Smrg pc->tree.max_children += (pc->tree.max_children / 2) + 2; 269421c997bSmrg pc->tree.children = (WidgetList) XtRealloc ((char *)pc->tree.children, 2705ec34c4cSmrg (Cardinal) 2715ec34c4cSmrg ((size_t)pc->tree.max_children * 2727a84e134Smrg sizeof(Widget))); 273421c997bSmrg } 2747a84e134Smrg 2757a84e134Smrg /* 276421c997bSmrg * Add the sub_node in the next available slot and 2777a84e134Smrg * increment the counter. 2787a84e134Smrg */ 2797a84e134Smrg pc->tree.children[nindex] = node; 2807a84e134Smrg pc->tree.n_children++; 2817a84e134Smrg} 2827a84e134Smrg 2837a84e134Smrgstatic void 2847a84e134Smrgdelete_node(Widget parent, Widget node) 2857a84e134Smrg{ 2867a84e134Smrg TreeConstraints pc; 287efbcb2bfSmrg int pos; 288efbcb2bfSmrg int i; 2897a84e134Smrg 2907a84e134Smrg /* 2917a84e134Smrg * Make sure the parent exists. 2927a84e134Smrg */ 293421c997bSmrg if (!parent) return; 294421c997bSmrg 2957a84e134Smrg pc = TREE_CONSTRAINT(parent); 2967a84e134Smrg 2977a84e134Smrg /* 2987a84e134Smrg * Find the sub_node on its parent's list. 2997a84e134Smrg */ 3007a84e134Smrg for (pos = 0; pos < pc->tree.n_children; pos++) 3017a84e134Smrg if (pc->tree.children[pos] == node) break; 3027a84e134Smrg 3037a84e134Smrg if (pos == pc->tree.n_children) return; 3047a84e134Smrg 3057a84e134Smrg /* 3067a84e134Smrg * Decrement the number of children 307421c997bSmrg */ 3087a84e134Smrg pc->tree.n_children--; 3097a84e134Smrg 3107a84e134Smrg /* 3117a84e134Smrg * Fill in the gap left by the sub_node. 3127a84e134Smrg * Zero the last slot for good luck. 3137a84e134Smrg */ 314421c997bSmrg for (i = pos; i < pc->tree.n_children; i++) 3157a84e134Smrg pc->tree.children[i] = pc->tree.children[i+1]; 3167a84e134Smrg 317775e7de9Smrg pc->tree.children[pc->tree.n_children] = NULL; 3187a84e134Smrg} 3197a84e134Smrg 3207a84e134Smrgstatic void 3217a84e134Smrgcheck_gravity(TreeWidget tw, XtGravity grav) 3227a84e134Smrg{ 3237a84e134Smrg switch (tw->tree.gravity) { 3247a84e134Smrg case WestGravity: case NorthGravity: case EastGravity: case SouthGravity: 3257a84e134Smrg break; 3267a84e134Smrg default: 3277a84e134Smrg tw->tree.gravity = grav; 3287a84e134Smrg break; 3297a84e134Smrg } 3307a84e134Smrg} 3317a84e134Smrg 3327a84e134Smrg 3337a84e134Smrg/***************************************************************************** 3347a84e134Smrg * * 335421c997bSmrg * tree class methods * 3367a84e134Smrg * * 3377a84e134Smrg *****************************************************************************/ 3387a84e134Smrg 3397a84e134Smrgstatic void 3407a84e134SmrgXawTreeClassInitialize(void) 3417a84e134Smrg{ 3427a84e134Smrg XawInitializeWidgetSet(); 3437a84e134Smrg XtAddConverter(XtRString, XtRGravity, XmuCvtStringToGravity, NULL, 0); 3447a84e134Smrg XtSetTypeConverter(XtRGravity, XtRString, XmuCvtGravityToString, 3457a84e134Smrg NULL, 0, XtCacheNone, NULL); 3467a84e134Smrg} 3477a84e134Smrg 3487a84e134Smrg 3497a84e134Smrg/*ARGSUSED*/ 3507a84e134Smrgstatic void 3517a84e134SmrgXawTreeInitialize(Widget grequest, Widget gnew, 3525ec34c4cSmrg ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED) 3537a84e134Smrg{ 3547a84e134Smrg TreeWidget request = (TreeWidget) grequest, cnew = (TreeWidget) gnew; 3557a84e134Smrg Arg arglist[2]; 3567a84e134Smrg 3577a84e134Smrg /* 358421c997bSmrg * Make sure the widget's width and height are 3597a84e134Smrg * greater than zero. 3607a84e134Smrg */ 3617a84e134Smrg if (request->core.width <= 0) cnew->core.width = 5; 3627a84e134Smrg if (request->core.height <= 0) cnew->core.height = 5; 3637a84e134Smrg 3647a84e134Smrg /* 3657a84e134Smrg * Set the padding according to the orientation 3667a84e134Smrg */ 3677a84e134Smrg if (request->tree.hpad == 0 && request->tree.vpad == 0) { 3687a84e134Smrg if (IsHorizontal (request)) { 3697a84e134Smrg cnew->tree.hpad = TREE_HORIZONTAL_DEFAULT_SPACING; 3707a84e134Smrg cnew->tree.vpad = TREE_VERTICAL_DEFAULT_SPACING; 3717a84e134Smrg } else { 3727a84e134Smrg cnew->tree.hpad = TREE_VERTICAL_DEFAULT_SPACING; 3737a84e134Smrg cnew->tree.vpad = TREE_HORIZONTAL_DEFAULT_SPACING; 3747a84e134Smrg } 3757a84e134Smrg } 3767a84e134Smrg 3777a84e134Smrg /* 3787a84e134Smrg * Create a graphics context for the connecting lines. 3797a84e134Smrg */ 3807a84e134Smrg cnew->tree.gc = get_tree_gc (cnew); 3817a84e134Smrg 3827a84e134Smrg /* 3837a84e134Smrg * Create the hidden root widget. 3847a84e134Smrg */ 3857a84e134Smrg cnew->tree.tree_root = (Widget) NULL; 3867a84e134Smrg XtSetArg(arglist[0], XtNwidth, 1); 3877a84e134Smrg XtSetArg(arglist[1], XtNheight, 1); 3887a84e134Smrg cnew->tree.tree_root = XtCreateWidget ("root", widgetClass, gnew, 3897a84e134Smrg arglist,TWO); 3907a84e134Smrg 3917a84e134Smrg /* 3927a84e134Smrg * Allocate the array used to hold the widest values per depth 3937a84e134Smrg */ 3947a84e134Smrg cnew->tree.largest = NULL; 3957a84e134Smrg cnew->tree.n_largest = 0; 396421c997bSmrg initialize_dimensions (&cnew->tree.largest, &cnew->tree.n_largest, 3977a84e134Smrg TREE_INITIAL_DEPTH); 3987a84e134Smrg 3997a84e134Smrg /* 4007a84e134Smrg * make sure that our gravity is one of the acceptable values 4017a84e134Smrg */ 4027a84e134Smrg check_gravity (cnew, WestGravity); 403421c997bSmrg} 4047a84e134Smrg 4057a84e134Smrg 4067a84e134Smrg/* ARGSUSED */ 4077a84e134Smrgstatic void 4085ec34c4cSmrgXawTreeConstraintInitialize(Widget request _X_UNUSED, Widget cnew, 4095ec34c4cSmrg ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED) 4107a84e134Smrg{ 4117a84e134Smrg TreeConstraints tc = TREE_CONSTRAINT(cnew); 4127a84e134Smrg TreeWidget tw = (TreeWidget) cnew->core.parent; 4137a84e134Smrg 4147a84e134Smrg /* 4157a84e134Smrg * Initialize the widget to have no sub-nodes. 4167a84e134Smrg */ 4177a84e134Smrg tc->tree.n_children = 0; 4187a84e134Smrg tc->tree.max_children = 0; 4197a84e134Smrg tc->tree.children = (Widget *) NULL; 420421c997bSmrg tc->tree.x = tc->tree.y = 0; 4217a84e134Smrg tc->tree.bbsubwidth = 0; 4227a84e134Smrg tc->tree.bbsubheight = 0; 4237a84e134Smrg 4247a84e134Smrg 4257a84e134Smrg /* 426421c997bSmrg * If this widget has a super-node, add it to that 427421c997bSmrg * widget' sub-nodes list. Otherwise make it a sub-node of 4287a84e134Smrg * the tree_root widget. 4297a84e134Smrg */ 4307a84e134Smrg if (tc->tree.parent) 4317a84e134Smrg insert_node (tc->tree.parent, cnew); 4327a84e134Smrg else if (tw->tree.tree_root) 4337a84e134Smrg insert_node (tw->tree.tree_root, cnew); 434421c997bSmrg} 4357a84e134Smrg 4367a84e134Smrg 4377a84e134Smrg/* ARGSUSED */ 4387a84e134Smrgstatic Boolean 4395ec34c4cSmrgXawTreeSetValues(Widget gcurrent, Widget grequest _X_UNUSED, Widget gnew, 4405ec34c4cSmrg ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED) 4417a84e134Smrg{ 4427a84e134Smrg TreeWidget current = (TreeWidget) gcurrent, cnew = (TreeWidget) gnew; 4437a84e134Smrg Boolean redraw = FALSE; 4447a84e134Smrg 4457a84e134Smrg /* 4467a84e134Smrg * If the foreground color has changed, redo the GC's 4477a84e134Smrg * and indicate a redraw. 4487a84e134Smrg */ 4497a84e134Smrg if (cnew->tree.foreground != current->tree.foreground || 4507a84e134Smrg cnew->core.background_pixel != current->core.background_pixel || 4517a84e134Smrg cnew->tree.line_width != current->tree.line_width) { 4527a84e134Smrg XtReleaseGC (gnew, cnew->tree.gc); 4537a84e134Smrg cnew->tree.gc = get_tree_gc (cnew); 454421c997bSmrg redraw = TRUE; 4557a84e134Smrg } 4567a84e134Smrg 4577a84e134Smrg /* 4587a84e134Smrg * If the minimum spacing has changed, recalculate the 4597a84e134Smrg * tree layout. layout_tree() does a redraw, so we don't 4607a84e134Smrg * need SetValues to do another one. 4617a84e134Smrg */ 4627a84e134Smrg if (cnew->tree.gravity != current->tree.gravity) { 4637a84e134Smrg check_gravity (cnew, current->tree.gravity); 4647a84e134Smrg } 4657a84e134Smrg 4667a84e134Smrg if (IsHorizontal(cnew) != IsHorizontal(current)) { 4677a84e134Smrg if (cnew->tree.vpad == current->tree.vpad && 4687a84e134Smrg cnew->tree.hpad == current->tree.hpad) { 4697a84e134Smrg cnew->tree.vpad = current->tree.hpad; 4707a84e134Smrg cnew->tree.hpad = current->tree.vpad; 4717a84e134Smrg } 4727a84e134Smrg } 4737a84e134Smrg 4747a84e134Smrg if (cnew->tree.vpad != current->tree.vpad || 4757a84e134Smrg cnew->tree.hpad != current->tree.hpad || 4767a84e134Smrg cnew->tree.gravity != current->tree.gravity) { 4777a84e134Smrg layout_tree (cnew, TRUE); 4787a84e134Smrg redraw = FALSE; 4797a84e134Smrg } 4807a84e134Smrg return redraw; 4817a84e134Smrg} 4827a84e134Smrg 4837a84e134Smrg 4847a84e134Smrg/* ARGSUSED */ 4857a84e134Smrgstatic Boolean 4865ec34c4cSmrgXawTreeConstraintSetValues(Widget current, Widget request _X_UNUSED, Widget cnew, 4875ec34c4cSmrg ArgList args _X_UNUSED, Cardinal *num_args _X_UNUSED) 4887a84e134Smrg{ 4897a84e134Smrg TreeConstraints newc = TREE_CONSTRAINT(cnew); 4907a84e134Smrg TreeConstraints curc = TREE_CONSTRAINT(current); 4917a84e134Smrg TreeWidget tw = (TreeWidget) cnew->core.parent; 4927a84e134Smrg 4937a84e134Smrg /* 4947a84e134Smrg * If the parent field has changed, remove the widget 4957a84e134Smrg * from the old widget's children list and add it to the 4967a84e134Smrg * new one. 4977a84e134Smrg */ 4987a84e134Smrg if (curc->tree.parent != newc->tree.parent){ 4997a84e134Smrg if (curc->tree.parent) 5007a84e134Smrg delete_node (curc->tree.parent, cnew); 5017a84e134Smrg if (newc->tree.parent) 5027a84e134Smrg insert_node(newc->tree.parent, cnew); 5037a84e134Smrg 5047a84e134Smrg /* 505421c997bSmrg * If the Tree widget has been realized, 5067a84e134Smrg * compute new layout. 5077a84e134Smrg */ 5087a84e134Smrg if (XtIsRealized((Widget)tw)) 5097a84e134Smrg layout_tree (tw, FALSE); 5107a84e134Smrg } 5117a84e134Smrg return False; 5127a84e134Smrg} 5137a84e134Smrg 5147a84e134Smrg 5157a84e134Smrgstatic void 5167a84e134SmrgXawTreeConstraintDestroy(Widget w) 517421c997bSmrg{ 5187a84e134Smrg TreeConstraints tc = TREE_CONSTRAINT(w); 5197a84e134Smrg TreeWidget tw = (TreeWidget) XtParent(w); 5207a84e134Smrg int i; 5217a84e134Smrg 522421c997bSmrg /* 5237a84e134Smrg * Remove the widget from its parent's sub-nodes list and 5247a84e134Smrg * make all this widget's sub-nodes sub-nodes of the parent. 5257a84e134Smrg */ 526421c997bSmrg 5277a84e134Smrg if (tw->tree.tree_root == w) { 5287a84e134Smrg if (tc->tree.n_children > 0) 5297a84e134Smrg tw->tree.tree_root = tc->tree.children[0]; 5307a84e134Smrg else 5317a84e134Smrg tw->tree.tree_root = NULL; 5327a84e134Smrg } 5337a84e134Smrg 5347a84e134Smrg delete_node (tc->tree.parent, (Widget) w); 5357a84e134Smrg for (i = 0; i< tc->tree.n_children; i++) 5367a84e134Smrg insert_node (tc->tree.parent, tc->tree.children[i]); 5377a84e134Smrg 5387a84e134Smrg layout_tree ((TreeWidget) (w->core.parent), FALSE); 5397a84e134Smrg} 5407a84e134Smrg 5417a84e134Smrg/* ARGSUSED */ 5427a84e134Smrgstatic XtGeometryResult 5437a84e134SmrgXawTreeGeometryManager(Widget w, XtWidgetGeometry *request, 5445ec34c4cSmrg XtWidgetGeometry *reply _X_UNUSED) 5457a84e134Smrg{ 5467a84e134Smrg 5477a84e134Smrg TreeWidget tw = (TreeWidget) w->core.parent; 5487a84e134Smrg 5497a84e134Smrg /* 5507a84e134Smrg * No position changes allowed!. 5517a84e134Smrg */ 5527a84e134Smrg if ((request->request_mode & CWX && request->x!=w->core.x) 5537a84e134Smrg ||(request->request_mode & CWY && request->y!=w->core.y)) 5547a84e134Smrg return (XtGeometryNo); 5557a84e134Smrg 5567a84e134Smrg /* 5577a84e134Smrg * Allow all resize requests. 5587a84e134Smrg */ 5597a84e134Smrg 5607a84e134Smrg if (request->request_mode & CWWidth) 5617a84e134Smrg w->core.width = request->width; 5627a84e134Smrg if (request->request_mode & CWHeight) 5637a84e134Smrg w->core.height = request->height; 5647a84e134Smrg if (request->request_mode & CWBorderWidth) 5657a84e134Smrg w->core.border_width = request->border_width; 5667a84e134Smrg 5677a84e134Smrg if (tw->tree.auto_reconfigure) layout_tree (tw, FALSE); 5687a84e134Smrg return (XtGeometryYes); 5697a84e134Smrg} 5707a84e134Smrg 5717a84e134Smrgstatic void 5727a84e134SmrgXawTreeChangeManaged(Widget gw) 5737a84e134Smrg{ 5747a84e134Smrg layout_tree ((TreeWidget) gw, FALSE); 5757a84e134Smrg} 5767a84e134Smrg 5777a84e134Smrg 5787a84e134Smrgstatic void 5797a84e134SmrgXawTreeDestroy(Widget gw) 5807a84e134Smrg{ 5817a84e134Smrg TreeWidget w = (TreeWidget) gw; 5827a84e134Smrg 5837a84e134Smrg XtReleaseGC (gw, w->tree.gc); 5847a84e134Smrg if (w->tree.largest) XtFree ((char *) w->tree.largest); 5857a84e134Smrg} 5867a84e134Smrg 5877a84e134Smrg 5887a84e134Smrg/* ARGSUSED */ 5897a84e134Smrgstatic void 5905ec34c4cSmrgXawTreeRedisplay(Widget gw, XEvent *event _X_UNUSED, Region region _X_UNUSED) 5917a84e134Smrg{ 5927a84e134Smrg TreeWidget tw = (TreeWidget) gw; 593efbcb2bfSmrg Cardinal i; 594efbcb2bfSmrg int j; 5957a84e134Smrg 5967a84e134Smrg#ifndef OLDXAW 5977a84e134Smrg if (tw->tree.display_list) 5987a84e134Smrg XawRunDisplayList(gw, tw->tree.display_list, event, region); 5997a84e134Smrg#endif 6007a84e134Smrg 6017a84e134Smrg /* 6027a84e134Smrg * If the Tree widget is visible, visit each managed child. 6037a84e134Smrg */ 6047a84e134Smrg if (tw->core.visible) { 6057a84e134Smrg Display *dpy = XtDisplay (tw); 6067a84e134Smrg Window w = XtWindow (tw); 6077a84e134Smrg 6087a84e134Smrg for (i = 0; i < tw->composite.num_children; i++) { 6097a84e134Smrg Widget child = tw->composite.children[i]; 6107a84e134Smrg TreeConstraints tc = TREE_CONSTRAINT(child); 6117a84e134Smrg 6127a84e134Smrg /* 6137a84e134Smrg * Don't draw lines from the fake tree_root. 6147a84e134Smrg */ 6157a84e134Smrg if (child != tw->tree.tree_root && tc->tree.n_children) { 6167a84e134Smrg int srcx = child->core.x + child->core.border_width; 6177a84e134Smrg int srcy = child->core.y + child->core.border_width; 6187a84e134Smrg 6197a84e134Smrg switch (tw->tree.gravity) { 6207a84e134Smrg case WestGravity: 6217a84e134Smrg srcx += child->core.width + child->core.border_width; 6227a84e134Smrg /* fall through */ 6237a84e134Smrg case EastGravity: 6247a84e134Smrg srcy += child->core.height / 2; 6257a84e134Smrg break; 6267a84e134Smrg 6277a84e134Smrg case NorthGravity: 6287a84e134Smrg srcy += child->core.height + child->core.border_width; 6297a84e134Smrg /* fall through */ 6307a84e134Smrg case SouthGravity: 6317a84e134Smrg srcx += child->core.width / 2; 6327a84e134Smrg break; 6337a84e134Smrg } 6347a84e134Smrg 6357a84e134Smrg for (j = 0; j < tc->tree.n_children; j++) { 6367a84e134Smrg Widget k = tc->tree.children[j]; 6377a84e134Smrg GC gc = (tc->tree.gc ? tc->tree.gc : tw->tree.gc); 6387a84e134Smrg 6397a84e134Smrg switch (tw->tree.gravity) { 6407a84e134Smrg case WestGravity: 6417a84e134Smrg /* 6427a84e134Smrg * right center to left center 6437a84e134Smrg */ 6447a84e134Smrg XDrawLine (dpy, w, gc, srcx, srcy, 6457a84e134Smrg (int) k->core.x, 6467a84e134Smrg (k->core.y + ((int) k->core.border_width) + 6477a84e134Smrg ((int) k->core.height) / 2)); 6487a84e134Smrg break; 6497a84e134Smrg 6507a84e134Smrg case NorthGravity: 6517a84e134Smrg /* 6527a84e134Smrg * bottom center to top center 6537a84e134Smrg */ 6547a84e134Smrg XDrawLine (dpy, w, gc, srcx, srcy, 6557a84e134Smrg (k->core.x + ((int) k->core.border_width) + 6567a84e134Smrg ((int) k->core.width) / 2), 6577a84e134Smrg (int) k->core.y); 6587a84e134Smrg break; 6597a84e134Smrg 6607a84e134Smrg case EastGravity: 6617a84e134Smrg /* 6627a84e134Smrg * left center to right center 6637a84e134Smrg */ 6647a84e134Smrg XDrawLine (dpy, w, gc, srcx, srcy, 6657a84e134Smrg (k->core.x + 6667a84e134Smrg (((int) k->core.border_width) << 1) + 6677a84e134Smrg (int) k->core.width), 6687a84e134Smrg (k->core.y + ((int) k->core.border_width) + 6697a84e134Smrg ((int) k->core.height) / 2)); 6707a84e134Smrg break; 6717a84e134Smrg 6727a84e134Smrg case SouthGravity: 6737a84e134Smrg /* 6747a84e134Smrg * top center to bottom center 6757a84e134Smrg */ 6767a84e134Smrg XDrawLine (dpy, w, gc, srcx, srcy, 6777a84e134Smrg (k->core.x + ((int) k->core.border_width) + 6787a84e134Smrg ((int) k->core.width) / 2), 6797a84e134Smrg (k->core.y + 6807a84e134Smrg (((int) k->core.border_width) << 1) + 6817a84e134Smrg (int) k->core.height)); 6827a84e134Smrg break; 6837a84e134Smrg } 6847a84e134Smrg } 6857a84e134Smrg } 6867a84e134Smrg } 6877a84e134Smrg } 6887a84e134Smrg} 6897a84e134Smrg 6907a84e134Smrgstatic XtGeometryResult 6917a84e134SmrgXawTreeQueryGeometry(Widget w, XtWidgetGeometry *intended, 6927a84e134Smrg XtWidgetGeometry *preferred) 6937a84e134Smrg{ 6947a84e134Smrg TreeWidget tw = (TreeWidget) w; 6957a84e134Smrg 6967a84e134Smrg preferred->request_mode = (CWWidth | CWHeight); 6977a84e134Smrg preferred->width = tw->tree.maxwidth; 6987a84e134Smrg preferred->height = tw->tree.maxheight; 6997a84e134Smrg 7007a84e134Smrg if (((intended->request_mode & (CWWidth | CWHeight)) == 7017a84e134Smrg (CWWidth | CWHeight)) && 7027a84e134Smrg intended->width == preferred->width && 7037a84e134Smrg intended->height == preferred->height) 7047a84e134Smrg return XtGeometryYes; 7057a84e134Smrg else if (preferred->width == w->core.width && 7067a84e134Smrg preferred->height == w->core.height) 7077a84e134Smrg return XtGeometryNo; 7087a84e134Smrg else 7097a84e134Smrg return XtGeometryAlmost; 7107a84e134Smrg} 7117a84e134Smrg 7127a84e134Smrg 7137a84e134Smrg/***************************************************************************** 7147a84e134Smrg * * 7157a84e134Smrg * tree layout algorithm * 7167a84e134Smrg * * 7177a84e134Smrg * Each node in the tree is "shrink-wrapped" with a minimal bounding * 7187a84e134Smrg * rectangle, laid next to its siblings (with a small about of padding in * 7197a84e134Smrg * between) and then wrapped with their parent. Parents are centered about * 7207a84e134Smrg * their children (or vice versa if the parent is larger than the children). * 7217a84e134Smrg * * 7227a84e134Smrg *****************************************************************************/ 7237a84e134Smrg 7247a84e134Smrgstatic void 7257a84e134Smrgcompute_bounding_box_subtree(TreeWidget tree, Widget w, int depth) 7267a84e134Smrg{ 7277a84e134Smrg TreeConstraints tc = TREE_CONSTRAINT(w); /* info attached to all kids */ 7287a84e134Smrg Bool horiz = IsHorizontal (tree); 7297a84e134Smrg Dimension newwidth, newheight; 7305ec34c4cSmrg Dimension bw2 = (Dimension)(w->core.border_width * 2); 731efbcb2bfSmrg int i; 7327a84e134Smrg 7337a84e134Smrg /* 7347a84e134Smrg * Set the max-size per level. 7357a84e134Smrg */ 7367a84e134Smrg if (depth >= tree->tree.n_largest) { 7377a84e134Smrg initialize_dimensions (&tree->tree.largest, 7387a84e134Smrg &tree->tree.n_largest, depth + 1); 7397a84e134Smrg } 7405ec34c4cSmrg newwidth = (Dimension)((horiz ? w->core.width : w->core.height) + bw2); 7417a84e134Smrg if (tree->tree.largest[depth] < newwidth) 7427a84e134Smrg tree->tree.largest[depth] = newwidth; 7437a84e134Smrg 7447a84e134Smrg 7457a84e134Smrg /* 7467a84e134Smrg * initialize 7477a84e134Smrg */ 7485ec34c4cSmrg tc->tree.bbwidth = (Dimension)(w->core.width + bw2); 7495ec34c4cSmrg tc->tree.bbheight = (Dimension)(w->core.height + bw2); 7507a84e134Smrg 7517a84e134Smrg if (tc->tree.n_children == 0) return; 7527a84e134Smrg 7537a84e134Smrg /* 754421c997bSmrg * Figure the size of the opposite dimension (vertical if tree is 755421c997bSmrg * horizontal, else vice versa). The other dimension will be set 7567a84e134Smrg * in the second pass once we know the maximum dimensions. 7577a84e134Smrg */ 7587a84e134Smrg newwidth = 0; 7597a84e134Smrg newheight = 0; 7607a84e134Smrg for (i = 0; i < tc->tree.n_children; i++) { 7617a84e134Smrg Widget child = tc->tree.children[i]; 7627a84e134Smrg TreeConstraints cc = TREE_CONSTRAINT(child); 763421c997bSmrg 7647a84e134Smrg compute_bounding_box_subtree (tree, child, depth + 1); 7657a84e134Smrg 7667a84e134Smrg if (horiz) { 7677a84e134Smrg if (newwidth < cc->tree.bbwidth) newwidth = cc->tree.bbwidth; 7685ec34c4cSmrg newheight = (Dimension)(newheight + (tree->tree.vpad + cc->tree.bbheight)); 7697a84e134Smrg } else { 7707a84e134Smrg if (newheight < cc->tree.bbheight) newheight = cc->tree.bbheight; 7715ec34c4cSmrg newwidth = (Dimension)(newwidth + (tree->tree.hpad + cc->tree.bbwidth)); 7727a84e134Smrg } 7737a84e134Smrg } 7747a84e134Smrg 7757a84e134Smrg 7767a84e134Smrg tc->tree.bbsubwidth = newwidth; 7777a84e134Smrg tc->tree.bbsubheight = newheight; 7787a84e134Smrg 7797a84e134Smrg /* 7807a84e134Smrg * Now fit parent onto side (or top) of bounding box and correct for 7817a84e134Smrg * extra padding. Be careful of unsigned arithmetic. 7827a84e134Smrg */ 7837a84e134Smrg if (horiz) { 7845ec34c4cSmrg tc->tree.bbwidth = (Dimension)(tc->tree.bbwidth + (tree->tree.hpad + newwidth)); 7855ec34c4cSmrg newheight = (Dimension)(newheight - tree->tree.vpad); 7867a84e134Smrg if (newheight > tc->tree.bbheight) tc->tree.bbheight = newheight; 7877a84e134Smrg } else { 7885ec34c4cSmrg tc->tree.bbheight = (Dimension)(tc->tree.bbheight + (tree->tree.vpad + newheight)); 7895ec34c4cSmrg newwidth = (Dimension)(newwidth - tree->tree.hpad); 7907a84e134Smrg if (newwidth > tc->tree.bbwidth) tc->tree.bbwidth = newwidth; 7917a84e134Smrg } 7927a84e134Smrg} 7937a84e134Smrg 7947a84e134Smrg 7957a84e134Smrgstatic void 7967a84e134Smrgset_positions(TreeWidget tw, Widget w, int level) 7977a84e134Smrg{ 7987a84e134Smrg if (w) { 7997a84e134Smrg TreeConstraints tc = TREE_CONSTRAINT(w); 800efbcb2bfSmrg int i; 8017a84e134Smrg 8027a84e134Smrg if (level > 0) { 8037a84e134Smrg /* 8047a84e134Smrg * mirror if necessary 8057a84e134Smrg */ 8067a84e134Smrg switch (tw->tree.gravity) { 8077a84e134Smrg case EastGravity: 8085ec34c4cSmrg tc->tree.x = (Position) (tw->tree.maxwidth - 8095ec34c4cSmrg w->core.width - tc->tree.x); 8107a84e134Smrg break; 8117a84e134Smrg 8127a84e134Smrg case SouthGravity: 8135ec34c4cSmrg tc->tree.y = (Position) (tw->tree.maxheight - 8145ec34c4cSmrg w->core.height - tc->tree.y); 8157a84e134Smrg break; 8167a84e134Smrg } 8177a84e134Smrg 8187a84e134Smrg /* 8197a84e134Smrg * Move the widget into position. 8207a84e134Smrg */ 8217a84e134Smrg XtMoveWidget (w, tc->tree.x, tc->tree.y); 8227a84e134Smrg } 8237a84e134Smrg 8247a84e134Smrg /* 8257a84e134Smrg * Set the positions of all children. 8267a84e134Smrg */ 8277a84e134Smrg for (i = 0; i < tc->tree.n_children; i++) 8287a84e134Smrg set_positions (tw, tc->tree.children[i], level + 1); 8297a84e134Smrg } 8307a84e134Smrg} 8317a84e134Smrg 8327a84e134Smrg 8337a84e134Smrgstatic void 8347a84e134Smrgarrange_subtree(TreeWidget tree, Widget w, int depth, int x, int y) 8357a84e134Smrg{ 8367a84e134Smrg TreeConstraints tc = TREE_CONSTRAINT(w); /* info attached to all kids */ 8377a84e134Smrg int newx, newy; 8387a84e134Smrg Bool horiz = IsHorizontal (tree); 8397a84e134Smrg Widget child = NULL; 8407a84e134Smrg Dimension tmp; 8415ec34c4cSmrg Dimension bw2 = (Dimension)(w->core.border_width * 2); 8427a84e134Smrg Bool relayout = True; 843efbcb2bfSmrg int i; 8447a84e134Smrg 8457a84e134Smrg /* 8467a84e134Smrg * If no children, then just lay out where requested. 8477a84e134Smrg */ 8485ec34c4cSmrg tc->tree.x = (Position)x; 8495ec34c4cSmrg tc->tree.y = (Position)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 8675ec34c4cSmrg if ((tmp = (Dimension)(x + tc->tree.bbwidth)) > tree->tree.maxwidth) 8687a84e134Smrg tree->tree.maxwidth = tmp; 8695ec34c4cSmrg 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 */ 906efbcb2bfSmrg if (relayout && (child != NULL)) { 9077a84e134Smrg Position adjusted; 908efbcb2bfSmrg TreeConstraints firstcc = TREE_CONSTRAINT (tc->tree.children[0]); 909efbcb2bfSmrg TreeConstraints 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) { 9165ec34c4cSmrg tc->tree.x = (Position)x; 9175ec34c4cSmrg adjusted = (Position)(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 - 9215ec34c4cSmrg (Position) w->core.border_width * 2 + 1) / 2)); 9227a84e134Smrg if (adjusted > tc->tree.y) tc->tree.y = adjusted; 9237a84e134Smrg } else { 9245ec34c4cSmrg adjusted = (Position)(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 - 9285ec34c4cSmrg (Position) w->core.border_width * 2 + 1) / 2)); 9297a84e134Smrg if (adjusted > tc->tree.x) tc->tree.x = adjusted; 9305ec34c4cSmrg tc->tree.y = (Position)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) { 9405ec34c4cSmrg tw->core.width = (Dimension)width; 9415ec34c4cSmrg tw->core.height = (Dimension)height; 9427a84e134Smrg } else { 9437a84e134Smrg Dimension replyWidth = 0, replyHeight = 0; 9447a84e134Smrg XtGeometryResult result = XtMakeResizeRequest ((Widget) tw, 9455ec34c4cSmrg (Dimension)width, 9465ec34c4cSmrg (Dimension)height, 9477a84e134Smrg &replyWidth, 9487a84e134Smrg &replyHeight); 9497a84e134Smrg /* 9507a84e134Smrg * Accept any compromise. 9517a84e134Smrg */ 9527a84e134Smrg if (result == XtGeometryAlmost) 9537a84e134Smrg XtMakeResizeRequest ((Widget) tw, replyWidth, replyHeight, 9547a84e134Smrg (Dimension *) NULL, (Dimension *) NULL); 9557a84e134Smrg } 9567a84e134Smrg return; 9577a84e134Smrg} 9587a84e134Smrg 9597a84e134Smrgstatic void 9607a84e134Smrglayout_tree(TreeWidget tw, Bool insetvalues) 9617a84e134Smrg{ 9627a84e134Smrg int i; 9637a84e134Smrg Dimension *dp; 9647a84e134Smrg 9657a84e134Smrg /* 9667a84e134Smrg * Do a depth-first search computing the width and height of the bounding 9677a84e134Smrg * box for the tree at that position (and below). Then, walk again using 9687a84e134Smrg * this information to layout the children at each level. 9697a84e134Smrg */ 9707a84e134Smrg 9717a84e134Smrg if (tw->tree.tree_root == NULL) 9727a84e134Smrg return; 9737a84e134Smrg 9747a84e134Smrg tw->tree.maxwidth = tw->tree.maxheight = 0; 9757a84e134Smrg for (i = 0, dp = tw->tree.largest; i < tw->tree.n_largest; i++, dp++) 9767a84e134Smrg *dp = 0; 977421c997bSmrg initialize_dimensions (&tw->tree.largest, &tw->tree.n_largest, 9787a84e134Smrg tw->tree.n_largest); 9797a84e134Smrg compute_bounding_box_subtree (tw, tw->tree.tree_root, 0); 9807a84e134Smrg 9817a84e134Smrg /* 9827a84e134Smrg * Second pass to do final layout. Each child's bounding box is stacked 9837a84e134Smrg * on top of (if horizontal, else next to) on top of its siblings. The 9847a84e134Smrg * parent is centered between the first and last children. 9857a84e134Smrg */ 9867a84e134Smrg arrange_subtree (tw, tw->tree.tree_root, 0, 0, 0); 9877a84e134Smrg 9887a84e134Smrg /* 9897a84e134Smrg * Move each widget into place. 9907a84e134Smrg */ 9917a84e134Smrg set_tree_size (tw, insetvalues, tw->tree.maxwidth, tw->tree.maxheight); 9927a84e134Smrg set_positions (tw, tw->tree.tree_root, 0); 9937a84e134Smrg 9947a84e134Smrg /* 9957a84e134Smrg * And redisplay. 9967a84e134Smrg */ 9977a84e134Smrg if (XtIsRealized ((Widget) tw)) { 9987a84e134Smrg XClearArea (XtDisplay(tw), XtWindow((Widget)tw), 0, 0, 0, 0, True); 9997a84e134Smrg } 10007a84e134Smrg} 10017a84e134Smrg 10027a84e134Smrg 10037a84e134Smrg 10047a84e134Smrg/***************************************************************************** 10057a84e134Smrg * * 1006421c997bSmrg * Public Routines * 10077a84e134Smrg * * 10087a84e134Smrg *****************************************************************************/ 10097a84e134Smrg 10107a84e134Smrgvoid 10117a84e134SmrgXawTreeForceLayout(Widget tree) 10127a84e134Smrg{ 10137a84e134Smrg layout_tree ((TreeWidget) tree, FALSE); 10147a84e134Smrg} 10157a84e134Smrg 1016