diff options
author | marha <marha@users.sourceforge.net> | 2011-09-12 11:27:51 +0200 |
---|---|---|
committer | marha <marha@users.sourceforge.net> | 2011-09-12 11:27:51 +0200 |
commit | dafebc5bb70303f0b5baf0b087cf4d9a64b5c7f0 (patch) | |
tree | bdf833cc6a4fc9035411779e10dd9e8478201885 /libXaw/src/Tree.c | |
parent | 0b40f5f4b54453a77f4b09c431f8efc6875da61f (diff) | |
download | vcxsrv-dafebc5bb70303f0b5baf0b087cf4d9a64b5c7f0.tar.gz vcxsrv-dafebc5bb70303f0b5baf0b087cf4d9a64b5c7f0.tar.bz2 vcxsrv-dafebc5bb70303f0b5baf0b087cf4d9a64b5c7f0.zip |
Synchronised line endinge with release branch
Diffstat (limited to 'libXaw/src/Tree.c')
-rw-r--r-- | libXaw/src/Tree.c | 2028 |
1 files changed, 1014 insertions, 1014 deletions
diff --git a/libXaw/src/Tree.c b/libXaw/src/Tree.c index c5e9a00f6..9dd9b7f53 100644 --- a/libXaw/src/Tree.c +++ b/libXaw/src/Tree.c @@ -1,1014 +1,1014 @@ -/*
-
-Copyright 1990, 1994, 1998 The Open Group
-
-Permission to use, copy, modify, distribute, and sell this software and its
-documentation for any purpose is hereby granted without fee, provided that
-the above copyright notice appear in all copies and that both that
-copyright notice and this permission notice appear in supporting
-documentation.
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
-AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-Except as contained in this notice, the name of The Open Group shall not be
-used in advertising or otherwise to promote the sale, use or other dealings
-in this Software without prior written authorization from The Open Group.
-
- * Copyright 1989 Prentice Hall
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose and without fee is hereby granted, provided that the above
- * copyright notice appear in all copies and that both the copyright notice
- * and this permission notice appear in supporting documentation.
- *
- * Prentice Hall and the authors disclaim all warranties with regard
- * to this software, including all implied warranties of merchantability and
- * fitness. In no event shall Prentice Hall or the authors be liable
- * for any special, indirect or cosequential damages or any damages whatsoever
- * resulting from loss of use, data or profits, whether in an action of
- * contract, negligence or other tortious action, arising out of or in
- * connection with the use or performance of this software.
- *
- * Authors: Jim Fulton, MIT X Consortium,
- * based on a version by Douglas Young, Prentice Hall
- *
- * This widget is based on the Tree widget described on pages 397-419 of
- * Douglas Young's book "The X Window System, Programming and Applications
- * with Xt OSF/Motif Edition." The layout code has been rewritten to use
- * additional blank space to make the structure of the graph easier to see
- * as well as to support vertical trees.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <X11/IntrinsicP.h>
-#include <X11/StringDefs.h>
-#include <X11/Xaw/XawInit.h>
-#include <X11/Xaw/Cardinals.h>
-#include <X11/Xaw/TreeP.h>
-#include "Private.h"
-
-#define IsHorizontal(tw) ((tw)->tree.gravity == WestGravity || \
- (tw)->tree.gravity == EastGravity)
-
-/*
- * Class Methods
- */
-static void XawTreeChangeManaged(Widget);
-static void XawTreeClassInitialize(void);
-static void XawTreeConstraintDestroy(Widget);
-static void XawTreeConstraintInitialize(Widget, Widget, ArgList, Cardinal*);
-static Boolean XawTreeConstraintSetValues(Widget, Widget, Widget,
- ArgList, Cardinal*);
-static void XawTreeDestroy(Widget);
-static XtGeometryResult XawTreeGeometryManager(Widget, XtWidgetGeometry*,
- XtWidgetGeometry*);
-static void XawTreeInitialize(Widget, Widget, ArgList, Cardinal*);
-static XtGeometryResult XawTreeQueryGeometry(Widget, XtWidgetGeometry*,
- XtWidgetGeometry*);
-static void XawTreeRedisplay(Widget, XEvent*, Region);
-static Boolean XawTreeSetValues(Widget, Widget, Widget, ArgList, Cardinal*);
-
-/*
- * Prototypes
- */
-static void arrange_subtree(TreeWidget, Widget, int, int, int);
-static void check_gravity(TreeWidget, XtGravity);
-static void compute_bounding_box_subtree(TreeWidget, Widget, int);
-static void delete_node(Widget, Widget);
-static GC get_tree_gc(TreeWidget);
-static void initialize_dimensions(Dimension**, int*, int);
-static void insert_node(Widget, Widget);
-static void layout_tree(TreeWidget, Bool);
-static void set_positions(TreeWidget, Widget, int);
-static void set_tree_size(TreeWidget, Bool, unsigned int, unsigned int);
-
-/*
- * Initialization
- */
-
-/*
- * resources of the tree itself
- */
-static XtResource resources[] = {
- { XtNautoReconfigure, XtCAutoReconfigure, XtRBoolean, sizeof (Boolean),
- XtOffsetOf(TreeRec, tree.auto_reconfigure), XtRImmediate,
- (XtPointer) FALSE },
- { XtNhSpace, XtCHSpace, XtRDimension, sizeof (Dimension),
- XtOffsetOf(TreeRec, tree.hpad), XtRImmediate, (XtPointer) 0 },
- { XtNvSpace, XtCVSpace, XtRDimension, sizeof (Dimension),
- XtOffsetOf(TreeRec, tree.vpad), XtRImmediate, (XtPointer) 0 },
- { XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel),
- XtOffsetOf(TreeRec, tree.foreground), XtRString,
- XtDefaultForeground},
- { XtNlineWidth, XtCLineWidth, XtRDimension, sizeof (Dimension),
- XtOffsetOf(TreeRec, tree.line_width), XtRImmediate, (XtPointer) 0 },
- { XtNgravity, XtCGravity, XtRGravity, sizeof (XtGravity),
- XtOffsetOf(TreeRec, tree.gravity), XtRImmediate,
- (XtPointer) WestGravity },
-#ifndef OLDXAW
- { XawNdisplayList, XawCDisplayList, XawRDisplayList, sizeof(XawDisplayList*),
- XtOffsetOf(TreeRec, tree.display_list), XtRImmediate,
- NULL },
-#endif
-};
-
-
-/*
- * resources that are attached to all children of the tree
- */
-static XtResource treeConstraintResources[] = {
- { XtNtreeParent, XtCTreeParent, XtRWidget, sizeof (Widget),
- XtOffsetOf(TreeConstraintsRec, tree.parent), XtRImmediate, NULL },
- { XtNtreeGC, XtCTreeGC, XtRGC, sizeof(GC),
- XtOffsetOf(TreeConstraintsRec, tree.gc), XtRImmediate, NULL },
-};
-
-
-TreeClassRec treeClassRec = {
- {
- /* core_class fields */
- (WidgetClass) &constraintClassRec, /* superclass */
- "Tree", /* class_name */
- sizeof(TreeRec), /* widget_size */
- XawTreeClassInitialize, /* class_init */
- NULL, /* class_part_init */
- FALSE, /* class_inited */
- XawTreeInitialize, /* initialize */
- NULL, /* initialize_hook */
- XtInheritRealize, /* realize */
- NULL, /* actions */
- 0, /* num_actions */
- resources, /* resources */
- XtNumber(resources), /* num_resources */
- NULLQUARK, /* xrm_class */
- TRUE, /* compress_motion */
- TRUE, /* compress_exposure */
- TRUE, /* compress_enterleave*/
- TRUE, /* visible_interest */
- XawTreeDestroy, /* destroy */
- NULL, /* resize */
- XawTreeRedisplay, /* expose */
- XawTreeSetValues, /* set_values */
- NULL, /* set_values_hook */
- XtInheritSetValuesAlmost, /* set_values_almost */
- NULL, /* get_values_hook */
- NULL, /* accept_focus */
- XtVersion, /* version */
- NULL, /* callback_private */
- NULL, /* tm_table */
- XawTreeQueryGeometry, /* query_geometry */
- NULL, /* display_accelerator*/
- NULL, /* extension */
- },
- {
- /* composite_class fields */
- XawTreeGeometryManager, /* geometry_manager */
- XawTreeChangeManaged, /* change_managed */
- XtInheritInsertChild, /* insert_child */
- XtInheritDeleteChild, /* delete_child */
- NULL, /* extension */
- },
- {
- /* constraint_class fields */
- treeConstraintResources, /* subresources */
- XtNumber(treeConstraintResources), /* subresource_count */
- sizeof(TreeConstraintsRec), /* constraint_size */
- XawTreeConstraintInitialize, /* initialize */
- XawTreeConstraintDestroy, /* destroy */
- XawTreeConstraintSetValues, /* set_values */
- NULL, /* extension */
- },
- {
- /* Tree class fields */
- NULL, /* ignore */
- }
-};
-
-WidgetClass treeWidgetClass = (WidgetClass) &treeClassRec;
-
-
-/*****************************************************************************
- * *
- * tree utility routines *
- * *
- *****************************************************************************/
-
-static void
-initialize_dimensions(Dimension **listp, int *sizep, int n)
-{
- int i;
- Dimension *l;
-
- if (!*listp) {
- *listp = (Dimension *) XtCalloc ((unsigned int) n,
- (unsigned int) sizeof(Dimension));
- *sizep = ((*listp) ? n : 0);
- return;
- }
- if (n > *sizep) {
- *listp = (Dimension *) XtRealloc((char *) *listp,
- (unsigned int) (n*sizeof(Dimension)));
- if (!*listp) {
- *sizep = 0;
- return;
- }
- for (i = *sizep, l = (*listp) + i; i < n; i++, l++) *l = 0;
- *sizep = n;
- }
- return;
-}
-
-static GC
-get_tree_gc(TreeWidget w)
-{
- XtGCMask valuemask = GCBackground | GCForeground;
- XGCValues values;
-
- values.background = w->core.background_pixel;
- values.foreground = w->tree.foreground;
- if (w->tree.line_width != 0) {
- valuemask |= GCLineWidth;
- values.line_width = w->tree.line_width;
- }
-
- return XtGetGC ((Widget) w, valuemask, &values);
-}
-
-static void
-insert_node(Widget parent, Widget node)
-{
- TreeConstraints pc;
- TreeConstraints nc = TREE_CONSTRAINT(node);
- int nindex;
-
- nc->tree.parent = parent;
-
- if (parent == NULL) return;
-
- /*
- * If there isn't more room in the children array,
- * allocate additional space.
- */
- pc = TREE_CONSTRAINT(parent);
- nindex = pc->tree.n_children;
-
- if (pc->tree.n_children == pc->tree.max_children) {
- pc->tree.max_children += (pc->tree.max_children / 2) + 2;
- pc->tree.children = (WidgetList) XtRealloc ((char *)pc->tree.children,
- (unsigned int)
- ((pc->tree.max_children) *
- sizeof(Widget)));
- }
-
- /*
- * Add the sub_node in the next available slot and
- * increment the counter.
- */
- pc->tree.children[nindex] = node;
- pc->tree.n_children++;
-}
-
-static void
-delete_node(Widget parent, Widget node)
-{
- TreeConstraints pc;
- int pos, i;
-
- /*
- * Make sure the parent exists.
- */
- if (!parent) return;
-
- pc = TREE_CONSTRAINT(parent);
-
- /*
- * Find the sub_node on its parent's list.
- */
- for (pos = 0; pos < pc->tree.n_children; pos++)
- if (pc->tree.children[pos] == node) break;
-
- if (pos == pc->tree.n_children) return;
-
- /*
- * Decrement the number of children
- */
- pc->tree.n_children--;
-
- /*
- * Fill in the gap left by the sub_node.
- * Zero the last slot for good luck.
- */
- for (i = pos; i < pc->tree.n_children; i++)
- pc->tree.children[i] = pc->tree.children[i+1];
-
- pc->tree.children[pc->tree.n_children] = NULL;
-}
-
-static void
-check_gravity(TreeWidget tw, XtGravity grav)
-{
- switch (tw->tree.gravity) {
- case WestGravity: case NorthGravity: case EastGravity: case SouthGravity:
- break;
- default:
- tw->tree.gravity = grav;
- break;
- }
-}
-
-
-/*****************************************************************************
- * *
- * tree class methods *
- * *
- *****************************************************************************/
-
-static void
-XawTreeClassInitialize(void)
-{
- XawInitializeWidgetSet();
- XtAddConverter(XtRString, XtRGravity, XmuCvtStringToGravity, NULL, 0);
- XtSetTypeConverter(XtRGravity, XtRString, XmuCvtGravityToString,
- NULL, 0, XtCacheNone, NULL);
-}
-
-
-/*ARGSUSED*/
-static void
-XawTreeInitialize(Widget grequest, Widget gnew,
- ArgList args, Cardinal *num_args)
-{
- TreeWidget request = (TreeWidget) grequest, cnew = (TreeWidget) gnew;
- Arg arglist[2];
-
- /*
- * Make sure the widget's width and height are
- * greater than zero.
- */
- if (request->core.width <= 0) cnew->core.width = 5;
- if (request->core.height <= 0) cnew->core.height = 5;
-
- /*
- * Set the padding according to the orientation
- */
- if (request->tree.hpad == 0 && request->tree.vpad == 0) {
- if (IsHorizontal (request)) {
- cnew->tree.hpad = TREE_HORIZONTAL_DEFAULT_SPACING;
- cnew->tree.vpad = TREE_VERTICAL_DEFAULT_SPACING;
- } else {
- cnew->tree.hpad = TREE_VERTICAL_DEFAULT_SPACING;
- cnew->tree.vpad = TREE_HORIZONTAL_DEFAULT_SPACING;
- }
- }
-
- /*
- * Create a graphics context for the connecting lines.
- */
- cnew->tree.gc = get_tree_gc (cnew);
-
- /*
- * Create the hidden root widget.
- */
- cnew->tree.tree_root = (Widget) NULL;
- XtSetArg(arglist[0], XtNwidth, 1);
- XtSetArg(arglist[1], XtNheight, 1);
- cnew->tree.tree_root = XtCreateWidget ("root", widgetClass, gnew,
- arglist,TWO);
-
- /*
- * Allocate the array used to hold the widest values per depth
- */
- cnew->tree.largest = NULL;
- cnew->tree.n_largest = 0;
- initialize_dimensions (&cnew->tree.largest, &cnew->tree.n_largest,
- TREE_INITIAL_DEPTH);
-
- /*
- * make sure that our gravity is one of the acceptable values
- */
- check_gravity (cnew, WestGravity);
-}
-
-
-/* ARGSUSED */
-static void
-XawTreeConstraintInitialize(Widget request, Widget cnew,
- ArgList args, Cardinal *num_args)
-{
- TreeConstraints tc = TREE_CONSTRAINT(cnew);
- TreeWidget tw = (TreeWidget) cnew->core.parent;
-
- /*
- * Initialize the widget to have no sub-nodes.
- */
- tc->tree.n_children = 0;
- tc->tree.max_children = 0;
- tc->tree.children = (Widget *) NULL;
- tc->tree.x = tc->tree.y = 0;
- tc->tree.bbsubwidth = 0;
- tc->tree.bbsubheight = 0;
-
-
- /*
- * If this widget has a super-node, add it to that
- * widget' sub-nodes list. Otherwise make it a sub-node of
- * the tree_root widget.
- */
- if (tc->tree.parent)
- insert_node (tc->tree.parent, cnew);
- else if (tw->tree.tree_root)
- insert_node (tw->tree.tree_root, cnew);
-}
-
-
-/* ARGSUSED */
-static Boolean
-XawTreeSetValues(Widget gcurrent, Widget grequest, Widget gnew,
- ArgList args, Cardinal *num_args)
-{
- TreeWidget current = (TreeWidget) gcurrent, cnew = (TreeWidget) gnew;
- Boolean redraw = FALSE;
-
- /*
- * If the foreground color has changed, redo the GC's
- * and indicate a redraw.
- */
- if (cnew->tree.foreground != current->tree.foreground ||
- cnew->core.background_pixel != current->core.background_pixel ||
- cnew->tree.line_width != current->tree.line_width) {
- XtReleaseGC (gnew, cnew->tree.gc);
- cnew->tree.gc = get_tree_gc (cnew);
- redraw = TRUE;
- }
-
- /*
- * If the minimum spacing has changed, recalculate the
- * tree layout. layout_tree() does a redraw, so we don't
- * need SetValues to do another one.
- */
- if (cnew->tree.gravity != current->tree.gravity) {
- check_gravity (cnew, current->tree.gravity);
- }
-
- if (IsHorizontal(cnew) != IsHorizontal(current)) {
- if (cnew->tree.vpad == current->tree.vpad &&
- cnew->tree.hpad == current->tree.hpad) {
- cnew->tree.vpad = current->tree.hpad;
- cnew->tree.hpad = current->tree.vpad;
- }
- }
-
- if (cnew->tree.vpad != current->tree.vpad ||
- cnew->tree.hpad != current->tree.hpad ||
- cnew->tree.gravity != current->tree.gravity) {
- layout_tree (cnew, TRUE);
- redraw = FALSE;
- }
- return redraw;
-}
-
-
-/* ARGSUSED */
-static Boolean
-XawTreeConstraintSetValues(Widget current, Widget request, Widget cnew,
- ArgList args, Cardinal *num_args)
-{
- TreeConstraints newc = TREE_CONSTRAINT(cnew);
- TreeConstraints curc = TREE_CONSTRAINT(current);
- TreeWidget tw = (TreeWidget) cnew->core.parent;
-
- /*
- * If the parent field has changed, remove the widget
- * from the old widget's children list and add it to the
- * new one.
- */
- if (curc->tree.parent != newc->tree.parent){
- if (curc->tree.parent)
- delete_node (curc->tree.parent, cnew);
- if (newc->tree.parent)
- insert_node(newc->tree.parent, cnew);
-
- /*
- * If the Tree widget has been realized,
- * compute new layout.
- */
- if (XtIsRealized((Widget)tw))
- layout_tree (tw, FALSE);
- }
- return False;
-}
-
-
-static void
-XawTreeConstraintDestroy(Widget w)
-{
- TreeConstraints tc = TREE_CONSTRAINT(w);
- TreeWidget tw = (TreeWidget) XtParent(w);
- int i;
-
- /*
- * Remove the widget from its parent's sub-nodes list and
- * make all this widget's sub-nodes sub-nodes of the parent.
- */
-
- if (tw->tree.tree_root == w) {
- if (tc->tree.n_children > 0)
- tw->tree.tree_root = tc->tree.children[0];
- else
- tw->tree.tree_root = NULL;
- }
-
- delete_node (tc->tree.parent, (Widget) w);
- for (i = 0; i< tc->tree.n_children; i++)
- insert_node (tc->tree.parent, tc->tree.children[i]);
-
- layout_tree ((TreeWidget) (w->core.parent), FALSE);
-}
-
-/* ARGSUSED */
-static XtGeometryResult
-XawTreeGeometryManager(Widget w, XtWidgetGeometry *request,
- XtWidgetGeometry *reply)
-{
-
- TreeWidget tw = (TreeWidget) w->core.parent;
-
- /*
- * No position changes allowed!.
- */
- if ((request->request_mode & CWX && request->x!=w->core.x)
- ||(request->request_mode & CWY && request->y!=w->core.y))
- return (XtGeometryNo);
-
- /*
- * Allow all resize requests.
- */
-
- if (request->request_mode & CWWidth)
- w->core.width = request->width;
- if (request->request_mode & CWHeight)
- w->core.height = request->height;
- if (request->request_mode & CWBorderWidth)
- w->core.border_width = request->border_width;
-
- if (tw->tree.auto_reconfigure) layout_tree (tw, FALSE);
- return (XtGeometryYes);
-}
-
-static void
-XawTreeChangeManaged(Widget gw)
-{
- layout_tree ((TreeWidget) gw, FALSE);
-}
-
-
-static void
-XawTreeDestroy(Widget gw)
-{
- TreeWidget w = (TreeWidget) gw;
-
- XtReleaseGC (gw, w->tree.gc);
- if (w->tree.largest) XtFree ((char *) w->tree.largest);
-}
-
-
-/* ARGSUSED */
-static void
-XawTreeRedisplay(Widget gw, XEvent *event, Region region)
-{
- TreeWidget tw = (TreeWidget) gw;
-
-#ifndef OLDXAW
- if (tw->tree.display_list)
- XawRunDisplayList(gw, tw->tree.display_list, event, region);
-#endif
-
- /*
- * If the Tree widget is visible, visit each managed child.
- */
- if (tw->core.visible) {
- Cardinal i;
- int j;
- Display *dpy = XtDisplay (tw);
- Window w = XtWindow (tw);
-
- for (i = 0; i < tw->composite.num_children; i++) {
- Widget child = tw->composite.children[i];
- TreeConstraints tc = TREE_CONSTRAINT(child);
-
- /*
- * Don't draw lines from the fake tree_root.
- */
- if (child != tw->tree.tree_root && tc->tree.n_children) {
- int srcx = child->core.x + child->core.border_width;
- int srcy = child->core.y + child->core.border_width;
-
- switch (tw->tree.gravity) {
- case WestGravity:
- srcx += child->core.width + child->core.border_width;
- /* fall through */
- case EastGravity:
- srcy += child->core.height / 2;
- break;
-
- case NorthGravity:
- srcy += child->core.height + child->core.border_width;
- /* fall through */
- case SouthGravity:
- srcx += child->core.width / 2;
- break;
- }
-
- for (j = 0; j < tc->tree.n_children; j++) {
- Widget k = tc->tree.children[j];
- GC gc = (tc->tree.gc ? tc->tree.gc : tw->tree.gc);
-
- switch (tw->tree.gravity) {
- case WestGravity:
- /*
- * right center to left center
- */
- XDrawLine (dpy, w, gc, srcx, srcy,
- (int) k->core.x,
- (k->core.y + ((int) k->core.border_width) +
- ((int) k->core.height) / 2));
- break;
-
- case NorthGravity:
- /*
- * bottom center to top center
- */
- XDrawLine (dpy, w, gc, srcx, srcy,
- (k->core.x + ((int) k->core.border_width) +
- ((int) k->core.width) / 2),
- (int) k->core.y);
- break;
-
- case EastGravity:
- /*
- * left center to right center
- */
- XDrawLine (dpy, w, gc, srcx, srcy,
- (k->core.x +
- (((int) k->core.border_width) << 1) +
- (int) k->core.width),
- (k->core.y + ((int) k->core.border_width) +
- ((int) k->core.height) / 2));
- break;
-
- case SouthGravity:
- /*
- * top center to bottom center
- */
- XDrawLine (dpy, w, gc, srcx, srcy,
- (k->core.x + ((int) k->core.border_width) +
- ((int) k->core.width) / 2),
- (k->core.y +
- (((int) k->core.border_width) << 1) +
- (int) k->core.height));
- break;
- }
- }
- }
- }
- }
-}
-
-static XtGeometryResult
-XawTreeQueryGeometry(Widget w, XtWidgetGeometry *intended,
- XtWidgetGeometry *preferred)
-{
- TreeWidget tw = (TreeWidget) w;
-
- preferred->request_mode = (CWWidth | CWHeight);
- preferred->width = tw->tree.maxwidth;
- preferred->height = tw->tree.maxheight;
-
- if (((intended->request_mode & (CWWidth | CWHeight)) ==
- (CWWidth | CWHeight)) &&
- intended->width == preferred->width &&
- intended->height == preferred->height)
- return XtGeometryYes;
- else if (preferred->width == w->core.width &&
- preferred->height == w->core.height)
- return XtGeometryNo;
- else
- return XtGeometryAlmost;
-}
-
-
-/*****************************************************************************
- * *
- * tree layout algorithm *
- * *
- * Each node in the tree is "shrink-wrapped" with a minimal bounding *
- * rectangle, laid next to its siblings (with a small about of padding in *
- * between) and then wrapped with their parent. Parents are centered about *
- * their children (or vice versa if the parent is larger than the children). *
- * *
- *****************************************************************************/
-
-static void
-compute_bounding_box_subtree(TreeWidget tree, Widget w, int depth)
-{
- TreeConstraints tc = TREE_CONSTRAINT(w); /* info attached to all kids */
- int i;
- Bool horiz = IsHorizontal (tree);
- Dimension newwidth, newheight;
- Dimension bw2 = w->core.border_width * 2;
-
- /*
- * Set the max-size per level.
- */
- if (depth >= tree->tree.n_largest) {
- initialize_dimensions (&tree->tree.largest,
- &tree->tree.n_largest, depth + 1);
- }
- newwidth = ((horiz ? w->core.width : w->core.height) + bw2);
- if (tree->tree.largest[depth] < newwidth)
- tree->tree.largest[depth] = newwidth;
-
-
- /*
- * initialize
- */
- tc->tree.bbwidth = w->core.width + bw2;
- tc->tree.bbheight = w->core.height + bw2;
-
- if (tc->tree.n_children == 0) return;
-
- /*
- * Figure the size of the opposite dimension (vertical if tree is
- * horizontal, else vice versa). The other dimension will be set
- * in the second pass once we know the maximum dimensions.
- */
- newwidth = 0;
- newheight = 0;
- for (i = 0; i < tc->tree.n_children; i++) {
- Widget child = tc->tree.children[i];
- TreeConstraints cc = TREE_CONSTRAINT(child);
-
- compute_bounding_box_subtree (tree, child, depth + 1);
-
- if (horiz) {
- if (newwidth < cc->tree.bbwidth) newwidth = cc->tree.bbwidth;
- newheight += tree->tree.vpad + cc->tree.bbheight;
- } else {
- if (newheight < cc->tree.bbheight) newheight = cc->tree.bbheight;
- newwidth += tree->tree.hpad + cc->tree.bbwidth;
- }
- }
-
-
- tc->tree.bbsubwidth = newwidth;
- tc->tree.bbsubheight = newheight;
-
- /*
- * Now fit parent onto side (or top) of bounding box and correct for
- * extra padding. Be careful of unsigned arithmetic.
- */
- if (horiz) {
- tc->tree.bbwidth += tree->tree.hpad + newwidth;
- newheight -= tree->tree.vpad;
- if (newheight > tc->tree.bbheight) tc->tree.bbheight = newheight;
- } else {
- tc->tree.bbheight += tree->tree.vpad + newheight;
- newwidth -= tree->tree.hpad;
- if (newwidth > tc->tree.bbwidth) tc->tree.bbwidth = newwidth;
- }
-}
-
-
-static void
-set_positions(TreeWidget tw, Widget w, int level)
-{
- int i;
-
- if (w) {
- TreeConstraints tc = TREE_CONSTRAINT(w);
-
- if (level > 0) {
- /*
- * mirror if necessary
- */
- switch (tw->tree.gravity) {
- case EastGravity:
- tc->tree.x = (((Position) tw->tree.maxwidth) -
- ((Position) w->core.width) - tc->tree.x);
- break;
-
- case SouthGravity:
- tc->tree.y = (((Position) tw->tree.maxheight) -
- ((Position) w->core.height) - tc->tree.y);
- break;
- }
-
- /*
- * Move the widget into position.
- */
- XtMoveWidget (w, tc->tree.x, tc->tree.y);
- }
-
- /*
- * Set the positions of all children.
- */
- for (i = 0; i < tc->tree.n_children; i++)
- set_positions (tw, tc->tree.children[i], level + 1);
- }
-}
-
-
-static void
-arrange_subtree(TreeWidget tree, Widget w, int depth, int x, int y)
-{
- TreeConstraints tc = TREE_CONSTRAINT(w); /* info attached to all kids */
- TreeConstraints firstcc, lastcc;
- int i;
- int newx, newy;
- Bool horiz = IsHorizontal (tree);
- Widget child = NULL;
- Dimension tmp;
- Dimension bw2 = w->core.border_width * 2;
- Bool relayout = True;
-
-
- /*
- * If no children, then just lay out where requested.
- */
- tc->tree.x = x;
- tc->tree.y = y;
-
- if (horiz) {
- int myh = (w->core.height + bw2);
-
- if (myh > (int)tc->tree.bbsubheight) {
- y += (myh - (int)tc->tree.bbsubheight) / 2;
- relayout = False;
- }
- } else {
- int myw = (w->core.width + bw2);
-
- if (myw > (int)tc->tree.bbsubwidth) {
- x += (myw - (int)tc->tree.bbsubwidth) / 2;
- relayout = False;
- }
- }
-
- if ((tmp = ((Dimension) x) + tc->tree.bbwidth) > tree->tree.maxwidth)
- tree->tree.maxwidth = tmp;
- if ((tmp = ((Dimension) y) + tc->tree.bbheight) > tree->tree.maxheight)
- tree->tree.maxheight = tmp;
-
- if (tc->tree.n_children == 0) return;
-
-
- /*
- * Have children, so walk down tree laying out children, then laying
- * out parents.
- */
- if (horiz) {
- newx = x + tree->tree.largest[depth];
- if (depth > 0) newx += tree->tree.hpad;
- newy = y;
- } else {
- newx = x;
- newy = y + tree->tree.largest[depth];
- if (depth > 0) newy += tree->tree.vpad;
- }
-
- for (i = 0; i < tc->tree.n_children; i++) {
- TreeConstraints cc;
-
- child = tc->tree.children[i]; /* last value is used outside loop */
- cc = TREE_CONSTRAINT(child);
-
- arrange_subtree (tree, child, depth + 1, newx, newy);
- if (horiz) {
- newy += tree->tree.vpad + cc->tree.bbheight;
- } else {
- newx += tree->tree.hpad + cc->tree.bbwidth;
- }
- }
-
- /*
- * now layout parent between first and last children
- */
- if (relayout) {
- Position adjusted;
- firstcc = TREE_CONSTRAINT (tc->tree.children[0]);
- lastcc = TREE_CONSTRAINT (child);
-
- /* Adjustments are disallowed if they result in a position above
- * or to the left of the originally requested position, because
- * this could collide with the position of the previous sibling.
- */
- if (horiz) {
- tc->tree.x = x;
- adjusted = firstcc->tree.y +
- ((lastcc->tree.y + (Position) child->core.height +
- (Position) child->core.border_width * 2 -
- firstcc->tree.y - (Position) w->core.height -
- (Position) w->core.border_width * 2 + 1) / 2);
- if (adjusted > tc->tree.y) tc->tree.y = adjusted;
- } else {
- adjusted = firstcc->tree.x +
- ((lastcc->tree.x + (Position) child->core.width +
- (Position) child->core.border_width * 2 -
- firstcc->tree.x - (Position) w->core.width -
- (Position) w->core.border_width * 2 + 1) / 2);
- if (adjusted > tc->tree.x) tc->tree.x = adjusted;
- tc->tree.y = y;
- }
- }
-}
-
-static void
-set_tree_size(TreeWidget tw, Bool insetvalues,
- unsigned int width, unsigned int height)
-{
- if (insetvalues) {
- tw->core.width = width;
- tw->core.height = height;
- } else {
- Dimension replyWidth = 0, replyHeight = 0;
- XtGeometryResult result = XtMakeResizeRequest ((Widget) tw,
- width, height,
- &replyWidth,
- &replyHeight);
- /*
- * Accept any compromise.
- */
- if (result == XtGeometryAlmost)
- XtMakeResizeRequest ((Widget) tw, replyWidth, replyHeight,
- (Dimension *) NULL, (Dimension *) NULL);
- }
- return;
-}
-
-static void
-layout_tree(TreeWidget tw, Bool insetvalues)
-{
- int i;
- Dimension *dp;
-
- /*
- * Do a depth-first search computing the width and height of the bounding
- * box for the tree at that position (and below). Then, walk again using
- * this information to layout the children at each level.
- */
-
- if (tw->tree.tree_root == NULL)
- return;
-
- tw->tree.maxwidth = tw->tree.maxheight = 0;
- for (i = 0, dp = tw->tree.largest; i < tw->tree.n_largest; i++, dp++)
- *dp = 0;
- initialize_dimensions (&tw->tree.largest, &tw->tree.n_largest,
- tw->tree.n_largest);
- compute_bounding_box_subtree (tw, tw->tree.tree_root, 0);
-
- /*
- * Second pass to do final layout. Each child's bounding box is stacked
- * on top of (if horizontal, else next to) on top of its siblings. The
- * parent is centered between the first and last children.
- */
- arrange_subtree (tw, tw->tree.tree_root, 0, 0, 0);
-
- /*
- * Move each widget into place.
- */
- set_tree_size (tw, insetvalues, tw->tree.maxwidth, tw->tree.maxheight);
- set_positions (tw, tw->tree.tree_root, 0);
-
- /*
- * And redisplay.
- */
- if (XtIsRealized ((Widget) tw)) {
- XClearArea (XtDisplay(tw), XtWindow((Widget)tw), 0, 0, 0, 0, True);
- }
-}
-
-
-
-/*****************************************************************************
- * *
- * Public Routines *
- * *
- *****************************************************************************/
-
-void
-XawTreeForceLayout(Widget tree)
-{
- layout_tree ((TreeWidget) tree, FALSE);
-}
-
+/* + +Copyright 1990, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from The Open Group. + + * Copyright 1989 Prentice Hall + * + * Permission to use, copy, modify, and distribute this software for any + * purpose and without fee is hereby granted, provided that the above + * copyright notice appear in all copies and that both the copyright notice + * and this permission notice appear in supporting documentation. + * + * Prentice Hall and the authors disclaim all warranties with regard + * to this software, including all implied warranties of merchantability and + * fitness. In no event shall Prentice Hall or the authors be liable + * for any special, indirect or cosequential damages or any damages whatsoever + * resulting from loss of use, data or profits, whether in an action of + * contract, negligence or other tortious action, arising out of or in + * connection with the use or performance of this software. + * + * Authors: Jim Fulton, MIT X Consortium, + * based on a version by Douglas Young, Prentice Hall + * + * This widget is based on the Tree widget described on pages 397-419 of + * Douglas Young's book "The X Window System, Programming and Applications + * with Xt OSF/Motif Edition." The layout code has been rewritten to use + * additional blank space to make the structure of the graph easier to see + * as well as to support vertical trees. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <X11/IntrinsicP.h> +#include <X11/StringDefs.h> +#include <X11/Xaw/XawInit.h> +#include <X11/Xaw/Cardinals.h> +#include <X11/Xaw/TreeP.h> +#include "Private.h" + +#define IsHorizontal(tw) ((tw)->tree.gravity == WestGravity || \ + (tw)->tree.gravity == EastGravity) + +/* + * Class Methods + */ +static void XawTreeChangeManaged(Widget); +static void XawTreeClassInitialize(void); +static void XawTreeConstraintDestroy(Widget); +static void XawTreeConstraintInitialize(Widget, Widget, ArgList, Cardinal*); +static Boolean XawTreeConstraintSetValues(Widget, Widget, Widget, + ArgList, Cardinal*); +static void XawTreeDestroy(Widget); +static XtGeometryResult XawTreeGeometryManager(Widget, XtWidgetGeometry*, + XtWidgetGeometry*); +static void XawTreeInitialize(Widget, Widget, ArgList, Cardinal*); +static XtGeometryResult XawTreeQueryGeometry(Widget, XtWidgetGeometry*, + XtWidgetGeometry*); +static void XawTreeRedisplay(Widget, XEvent*, Region); +static Boolean XawTreeSetValues(Widget, Widget, Widget, ArgList, Cardinal*); + +/* + * Prototypes + */ +static void arrange_subtree(TreeWidget, Widget, int, int, int); +static void check_gravity(TreeWidget, XtGravity); +static void compute_bounding_box_subtree(TreeWidget, Widget, int); +static void delete_node(Widget, Widget); +static GC get_tree_gc(TreeWidget); +static void initialize_dimensions(Dimension**, int*, int); +static void insert_node(Widget, Widget); +static void layout_tree(TreeWidget, Bool); +static void set_positions(TreeWidget, Widget, int); +static void set_tree_size(TreeWidget, Bool, unsigned int, unsigned int); + +/* + * Initialization + */ + +/* + * resources of the tree itself + */ +static XtResource resources[] = { + { XtNautoReconfigure, XtCAutoReconfigure, XtRBoolean, sizeof (Boolean), + XtOffsetOf(TreeRec, tree.auto_reconfigure), XtRImmediate, + (XtPointer) FALSE }, + { XtNhSpace, XtCHSpace, XtRDimension, sizeof (Dimension), + XtOffsetOf(TreeRec, tree.hpad), XtRImmediate, (XtPointer) 0 }, + { XtNvSpace, XtCVSpace, XtRDimension, sizeof (Dimension), + XtOffsetOf(TreeRec, tree.vpad), XtRImmediate, (XtPointer) 0 }, + { XtNforeground, XtCForeground, XtRPixel, sizeof (Pixel), + XtOffsetOf(TreeRec, tree.foreground), XtRString, + XtDefaultForeground}, + { XtNlineWidth, XtCLineWidth, XtRDimension, sizeof (Dimension), + XtOffsetOf(TreeRec, tree.line_width), XtRImmediate, (XtPointer) 0 }, + { XtNgravity, XtCGravity, XtRGravity, sizeof (XtGravity), + XtOffsetOf(TreeRec, tree.gravity), XtRImmediate, + (XtPointer) WestGravity }, +#ifndef OLDXAW + { XawNdisplayList, XawCDisplayList, XawRDisplayList, sizeof(XawDisplayList*), + XtOffsetOf(TreeRec, tree.display_list), XtRImmediate, + NULL }, +#endif +}; + + +/* + * resources that are attached to all children of the tree + */ +static XtResource treeConstraintResources[] = { + { XtNtreeParent, XtCTreeParent, XtRWidget, sizeof (Widget), + XtOffsetOf(TreeConstraintsRec, tree.parent), XtRImmediate, NULL }, + { XtNtreeGC, XtCTreeGC, XtRGC, sizeof(GC), + XtOffsetOf(TreeConstraintsRec, tree.gc), XtRImmediate, NULL }, +}; + + +TreeClassRec treeClassRec = { + { + /* core_class fields */ + (WidgetClass) &constraintClassRec, /* superclass */ + "Tree", /* class_name */ + sizeof(TreeRec), /* widget_size */ + XawTreeClassInitialize, /* class_init */ + NULL, /* class_part_init */ + FALSE, /* class_inited */ + XawTreeInitialize, /* initialize */ + NULL, /* initialize_hook */ + XtInheritRealize, /* realize */ + NULL, /* actions */ + 0, /* num_actions */ + resources, /* resources */ + XtNumber(resources), /* num_resources */ + NULLQUARK, /* xrm_class */ + TRUE, /* compress_motion */ + TRUE, /* compress_exposure */ + TRUE, /* compress_enterleave*/ + TRUE, /* visible_interest */ + XawTreeDestroy, /* destroy */ + NULL, /* resize */ + XawTreeRedisplay, /* expose */ + XawTreeSetValues, /* set_values */ + NULL, /* set_values_hook */ + XtInheritSetValuesAlmost, /* set_values_almost */ + NULL, /* get_values_hook */ + NULL, /* accept_focus */ + XtVersion, /* version */ + NULL, /* callback_private */ + NULL, /* tm_table */ + XawTreeQueryGeometry, /* query_geometry */ + NULL, /* display_accelerator*/ + NULL, /* extension */ + }, + { + /* composite_class fields */ + XawTreeGeometryManager, /* geometry_manager */ + XawTreeChangeManaged, /* change_managed */ + XtInheritInsertChild, /* insert_child */ + XtInheritDeleteChild, /* delete_child */ + NULL, /* extension */ + }, + { + /* constraint_class fields */ + treeConstraintResources, /* subresources */ + XtNumber(treeConstraintResources), /* subresource_count */ + sizeof(TreeConstraintsRec), /* constraint_size */ + XawTreeConstraintInitialize, /* initialize */ + XawTreeConstraintDestroy, /* destroy */ + XawTreeConstraintSetValues, /* set_values */ + NULL, /* extension */ + }, + { + /* Tree class fields */ + NULL, /* ignore */ + } +}; + +WidgetClass treeWidgetClass = (WidgetClass) &treeClassRec; + + +/***************************************************************************** + * * + * tree utility routines * + * * + *****************************************************************************/ + +static void +initialize_dimensions(Dimension **listp, int *sizep, int n) +{ + int i; + Dimension *l; + + if (!*listp) { + *listp = (Dimension *) XtCalloc ((unsigned int) n, + (unsigned int) sizeof(Dimension)); + *sizep = ((*listp) ? n : 0); + return; + } + if (n > *sizep) { + *listp = (Dimension *) XtRealloc((char *) *listp, + (unsigned int) (n*sizeof(Dimension))); + if (!*listp) { + *sizep = 0; + return; + } + for (i = *sizep, l = (*listp) + i; i < n; i++, l++) *l = 0; + *sizep = n; + } + return; +} + +static GC +get_tree_gc(TreeWidget w) +{ + XtGCMask valuemask = GCBackground | GCForeground; + XGCValues values; + + values.background = w->core.background_pixel; + values.foreground = w->tree.foreground; + if (w->tree.line_width != 0) { + valuemask |= GCLineWidth; + values.line_width = w->tree.line_width; + } + + return XtGetGC ((Widget) w, valuemask, &values); +} + +static void +insert_node(Widget parent, Widget node) +{ + TreeConstraints pc; + TreeConstraints nc = TREE_CONSTRAINT(node); + int nindex; + + nc->tree.parent = parent; + + if (parent == NULL) return; + + /* + * If there isn't more room in the children array, + * allocate additional space. + */ + pc = TREE_CONSTRAINT(parent); + nindex = pc->tree.n_children; + + if (pc->tree.n_children == pc->tree.max_children) { + pc->tree.max_children += (pc->tree.max_children / 2) + 2; + pc->tree.children = (WidgetList) XtRealloc ((char *)pc->tree.children, + (unsigned int) + ((pc->tree.max_children) * + sizeof(Widget))); + } + + /* + * Add the sub_node in the next available slot and + * increment the counter. + */ + pc->tree.children[nindex] = node; + pc->tree.n_children++; +} + +static void +delete_node(Widget parent, Widget node) +{ + TreeConstraints pc; + int pos, i; + + /* + * Make sure the parent exists. + */ + if (!parent) return; + + pc = TREE_CONSTRAINT(parent); + + /* + * Find the sub_node on its parent's list. + */ + for (pos = 0; pos < pc->tree.n_children; pos++) + if (pc->tree.children[pos] == node) break; + + if (pos == pc->tree.n_children) return; + + /* + * Decrement the number of children + */ + pc->tree.n_children--; + + /* + * Fill in the gap left by the sub_node. + * Zero the last slot for good luck. + */ + for (i = pos; i < pc->tree.n_children; i++) + pc->tree.children[i] = pc->tree.children[i+1]; + + pc->tree.children[pc->tree.n_children] = NULL; +} + +static void +check_gravity(TreeWidget tw, XtGravity grav) +{ + switch (tw->tree.gravity) { + case WestGravity: case NorthGravity: case EastGravity: case SouthGravity: + break; + default: + tw->tree.gravity = grav; + break; + } +} + + +/***************************************************************************** + * * + * tree class methods * + * * + *****************************************************************************/ + +static void +XawTreeClassInitialize(void) +{ + XawInitializeWidgetSet(); + XtAddConverter(XtRString, XtRGravity, XmuCvtStringToGravity, NULL, 0); + XtSetTypeConverter(XtRGravity, XtRString, XmuCvtGravityToString, + NULL, 0, XtCacheNone, NULL); +} + + +/*ARGSUSED*/ +static void +XawTreeInitialize(Widget grequest, Widget gnew, + ArgList args, Cardinal *num_args) +{ + TreeWidget request = (TreeWidget) grequest, cnew = (TreeWidget) gnew; + Arg arglist[2]; + + /* + * Make sure the widget's width and height are + * greater than zero. + */ + if (request->core.width <= 0) cnew->core.width = 5; + if (request->core.height <= 0) cnew->core.height = 5; + + /* + * Set the padding according to the orientation + */ + if (request->tree.hpad == 0 && request->tree.vpad == 0) { + if (IsHorizontal (request)) { + cnew->tree.hpad = TREE_HORIZONTAL_DEFAULT_SPACING; + cnew->tree.vpad = TREE_VERTICAL_DEFAULT_SPACING; + } else { + cnew->tree.hpad = TREE_VERTICAL_DEFAULT_SPACING; + cnew->tree.vpad = TREE_HORIZONTAL_DEFAULT_SPACING; + } + } + + /* + * Create a graphics context for the connecting lines. + */ + cnew->tree.gc = get_tree_gc (cnew); + + /* + * Create the hidden root widget. + */ + cnew->tree.tree_root = (Widget) NULL; + XtSetArg(arglist[0], XtNwidth, 1); + XtSetArg(arglist[1], XtNheight, 1); + cnew->tree.tree_root = XtCreateWidget ("root", widgetClass, gnew, + arglist,TWO); + + /* + * Allocate the array used to hold the widest values per depth + */ + cnew->tree.largest = NULL; + cnew->tree.n_largest = 0; + initialize_dimensions (&cnew->tree.largest, &cnew->tree.n_largest, + TREE_INITIAL_DEPTH); + + /* + * make sure that our gravity is one of the acceptable values + */ + check_gravity (cnew, WestGravity); +} + + +/* ARGSUSED */ +static void +XawTreeConstraintInitialize(Widget request, Widget cnew, + ArgList args, Cardinal *num_args) +{ + TreeConstraints tc = TREE_CONSTRAINT(cnew); + TreeWidget tw = (TreeWidget) cnew->core.parent; + + /* + * Initialize the widget to have no sub-nodes. + */ + tc->tree.n_children = 0; + tc->tree.max_children = 0; + tc->tree.children = (Widget *) NULL; + tc->tree.x = tc->tree.y = 0; + tc->tree.bbsubwidth = 0; + tc->tree.bbsubheight = 0; + + + /* + * If this widget has a super-node, add it to that + * widget' sub-nodes list. Otherwise make it a sub-node of + * the tree_root widget. + */ + if (tc->tree.parent) + insert_node (tc->tree.parent, cnew); + else if (tw->tree.tree_root) + insert_node (tw->tree.tree_root, cnew); +} + + +/* ARGSUSED */ +static Boolean +XawTreeSetValues(Widget gcurrent, Widget grequest, Widget gnew, + ArgList args, Cardinal *num_args) +{ + TreeWidget current = (TreeWidget) gcurrent, cnew = (TreeWidget) gnew; + Boolean redraw = FALSE; + + /* + * If the foreground color has changed, redo the GC's + * and indicate a redraw. + */ + if (cnew->tree.foreground != current->tree.foreground || + cnew->core.background_pixel != current->core.background_pixel || + cnew->tree.line_width != current->tree.line_width) { + XtReleaseGC (gnew, cnew->tree.gc); + cnew->tree.gc = get_tree_gc (cnew); + redraw = TRUE; + } + + /* + * If the minimum spacing has changed, recalculate the + * tree layout. layout_tree() does a redraw, so we don't + * need SetValues to do another one. + */ + if (cnew->tree.gravity != current->tree.gravity) { + check_gravity (cnew, current->tree.gravity); + } + + if (IsHorizontal(cnew) != IsHorizontal(current)) { + if (cnew->tree.vpad == current->tree.vpad && + cnew->tree.hpad == current->tree.hpad) { + cnew->tree.vpad = current->tree.hpad; + cnew->tree.hpad = current->tree.vpad; + } + } + + if (cnew->tree.vpad != current->tree.vpad || + cnew->tree.hpad != current->tree.hpad || + cnew->tree.gravity != current->tree.gravity) { + layout_tree (cnew, TRUE); + redraw = FALSE; + } + return redraw; +} + + +/* ARGSUSED */ +static Boolean +XawTreeConstraintSetValues(Widget current, Widget request, Widget cnew, + ArgList args, Cardinal *num_args) +{ + TreeConstraints newc = TREE_CONSTRAINT(cnew); + TreeConstraints curc = TREE_CONSTRAINT(current); + TreeWidget tw = (TreeWidget) cnew->core.parent; + + /* + * If the parent field has changed, remove the widget + * from the old widget's children list and add it to the + * new one. + */ + if (curc->tree.parent != newc->tree.parent){ + if (curc->tree.parent) + delete_node (curc->tree.parent, cnew); + if (newc->tree.parent) + insert_node(newc->tree.parent, cnew); + + /* + * If the Tree widget has been realized, + * compute new layout. + */ + if (XtIsRealized((Widget)tw)) + layout_tree (tw, FALSE); + } + return False; +} + + +static void +XawTreeConstraintDestroy(Widget w) +{ + TreeConstraints tc = TREE_CONSTRAINT(w); + TreeWidget tw = (TreeWidget) XtParent(w); + int i; + + /* + * Remove the widget from its parent's sub-nodes list and + * make all this widget's sub-nodes sub-nodes of the parent. + */ + + if (tw->tree.tree_root == w) { + if (tc->tree.n_children > 0) + tw->tree.tree_root = tc->tree.children[0]; + else + tw->tree.tree_root = NULL; + } + + delete_node (tc->tree.parent, (Widget) w); + for (i = 0; i< tc->tree.n_children; i++) + insert_node (tc->tree.parent, tc->tree.children[i]); + + layout_tree ((TreeWidget) (w->core.parent), FALSE); +} + +/* ARGSUSED */ +static XtGeometryResult +XawTreeGeometryManager(Widget w, XtWidgetGeometry *request, + XtWidgetGeometry *reply) +{ + + TreeWidget tw = (TreeWidget) w->core.parent; + + /* + * No position changes allowed!. + */ + if ((request->request_mode & CWX && request->x!=w->core.x) + ||(request->request_mode & CWY && request->y!=w->core.y)) + return (XtGeometryNo); + + /* + * Allow all resize requests. + */ + + if (request->request_mode & CWWidth) + w->core.width = request->width; + if (request->request_mode & CWHeight) + w->core.height = request->height; + if (request->request_mode & CWBorderWidth) + w->core.border_width = request->border_width; + + if (tw->tree.auto_reconfigure) layout_tree (tw, FALSE); + return (XtGeometryYes); +} + +static void +XawTreeChangeManaged(Widget gw) +{ + layout_tree ((TreeWidget) gw, FALSE); +} + + +static void +XawTreeDestroy(Widget gw) +{ + TreeWidget w = (TreeWidget) gw; + + XtReleaseGC (gw, w->tree.gc); + if (w->tree.largest) XtFree ((char *) w->tree.largest); +} + + +/* ARGSUSED */ +static void +XawTreeRedisplay(Widget gw, XEvent *event, Region region) +{ + TreeWidget tw = (TreeWidget) gw; + +#ifndef OLDXAW + if (tw->tree.display_list) + XawRunDisplayList(gw, tw->tree.display_list, event, region); +#endif + + /* + * If the Tree widget is visible, visit each managed child. + */ + if (tw->core.visible) { + Cardinal i; + int j; + Display *dpy = XtDisplay (tw); + Window w = XtWindow (tw); + + for (i = 0; i < tw->composite.num_children; i++) { + Widget child = tw->composite.children[i]; + TreeConstraints tc = TREE_CONSTRAINT(child); + + /* + * Don't draw lines from the fake tree_root. + */ + if (child != tw->tree.tree_root && tc->tree.n_children) { + int srcx = child->core.x + child->core.border_width; + int srcy = child->core.y + child->core.border_width; + + switch (tw->tree.gravity) { + case WestGravity: + srcx += child->core.width + child->core.border_width; + /* fall through */ + case EastGravity: + srcy += child->core.height / 2; + break; + + case NorthGravity: + srcy += child->core.height + child->core.border_width; + /* fall through */ + case SouthGravity: + srcx += child->core.width / 2; + break; + } + + for (j = 0; j < tc->tree.n_children; j++) { + Widget k = tc->tree.children[j]; + GC gc = (tc->tree.gc ? tc->tree.gc : tw->tree.gc); + + switch (tw->tree.gravity) { + case WestGravity: + /* + * right center to left center + */ + XDrawLine (dpy, w, gc, srcx, srcy, + (int) k->core.x, + (k->core.y + ((int) k->core.border_width) + + ((int) k->core.height) / 2)); + break; + + case NorthGravity: + /* + * bottom center to top center + */ + XDrawLine (dpy, w, gc, srcx, srcy, + (k->core.x + ((int) k->core.border_width) + + ((int) k->core.width) / 2), + (int) k->core.y); + break; + + case EastGravity: + /* + * left center to right center + */ + XDrawLine (dpy, w, gc, srcx, srcy, + (k->core.x + + (((int) k->core.border_width) << 1) + + (int) k->core.width), + (k->core.y + ((int) k->core.border_width) + + ((int) k->core.height) / 2)); + break; + + case SouthGravity: + /* + * top center to bottom center + */ + XDrawLine (dpy, w, gc, srcx, srcy, + (k->core.x + ((int) k->core.border_width) + + ((int) k->core.width) / 2), + (k->core.y + + (((int) k->core.border_width) << 1) + + (int) k->core.height)); + break; + } + } + } + } + } +} + +static XtGeometryResult +XawTreeQueryGeometry(Widget w, XtWidgetGeometry *intended, + XtWidgetGeometry *preferred) +{ + TreeWidget tw = (TreeWidget) w; + + preferred->request_mode = (CWWidth | CWHeight); + preferred->width = tw->tree.maxwidth; + preferred->height = tw->tree.maxheight; + + if (((intended->request_mode & (CWWidth | CWHeight)) == + (CWWidth | CWHeight)) && + intended->width == preferred->width && + intended->height == preferred->height) + return XtGeometryYes; + else if (preferred->width == w->core.width && + preferred->height == w->core.height) + return XtGeometryNo; + else + return XtGeometryAlmost; +} + + +/***************************************************************************** + * * + * tree layout algorithm * + * * + * Each node in the tree is "shrink-wrapped" with a minimal bounding * + * rectangle, laid next to its siblings (with a small about of padding in * + * between) and then wrapped with their parent. Parents are centered about * + * their children (or vice versa if the parent is larger than the children). * + * * + *****************************************************************************/ + +static void +compute_bounding_box_subtree(TreeWidget tree, Widget w, int depth) +{ + TreeConstraints tc = TREE_CONSTRAINT(w); /* info attached to all kids */ + int i; + Bool horiz = IsHorizontal (tree); + Dimension newwidth, newheight; + Dimension bw2 = w->core.border_width * 2; + + /* + * Set the max-size per level. + */ + if (depth >= tree->tree.n_largest) { + initialize_dimensions (&tree->tree.largest, + &tree->tree.n_largest, depth + 1); + } + newwidth = ((horiz ? w->core.width : w->core.height) + bw2); + if (tree->tree.largest[depth] < newwidth) + tree->tree.largest[depth] = newwidth; + + + /* + * initialize + */ + tc->tree.bbwidth = w->core.width + bw2; + tc->tree.bbheight = w->core.height + bw2; + + if (tc->tree.n_children == 0) return; + + /* + * Figure the size of the opposite dimension (vertical if tree is + * horizontal, else vice versa). The other dimension will be set + * in the second pass once we know the maximum dimensions. + */ + newwidth = 0; + newheight = 0; + for (i = 0; i < tc->tree.n_children; i++) { + Widget child = tc->tree.children[i]; + TreeConstraints cc = TREE_CONSTRAINT(child); + + compute_bounding_box_subtree (tree, child, depth + 1); + + if (horiz) { + if (newwidth < cc->tree.bbwidth) newwidth = cc->tree.bbwidth; + newheight += tree->tree.vpad + cc->tree.bbheight; + } else { + if (newheight < cc->tree.bbheight) newheight = cc->tree.bbheight; + newwidth += tree->tree.hpad + cc->tree.bbwidth; + } + } + + + tc->tree.bbsubwidth = newwidth; + tc->tree.bbsubheight = newheight; + + /* + * Now fit parent onto side (or top) of bounding box and correct for + * extra padding. Be careful of unsigned arithmetic. + */ + if (horiz) { + tc->tree.bbwidth += tree->tree.hpad + newwidth; + newheight -= tree->tree.vpad; + if (newheight > tc->tree.bbheight) tc->tree.bbheight = newheight; + } else { + tc->tree.bbheight += tree->tree.vpad + newheight; + newwidth -= tree->tree.hpad; + if (newwidth > tc->tree.bbwidth) tc->tree.bbwidth = newwidth; + } +} + + +static void +set_positions(TreeWidget tw, Widget w, int level) +{ + int i; + + if (w) { + TreeConstraints tc = TREE_CONSTRAINT(w); + + if (level > 0) { + /* + * mirror if necessary + */ + switch (tw->tree.gravity) { + case EastGravity: + tc->tree.x = (((Position) tw->tree.maxwidth) - + ((Position) w->core.width) - tc->tree.x); + break; + + case SouthGravity: + tc->tree.y = (((Position) tw->tree.maxheight) - + ((Position) w->core.height) - tc->tree.y); + break; + } + + /* + * Move the widget into position. + */ + XtMoveWidget (w, tc->tree.x, tc->tree.y); + } + + /* + * Set the positions of all children. + */ + for (i = 0; i < tc->tree.n_children; i++) + set_positions (tw, tc->tree.children[i], level + 1); + } +} + + +static void +arrange_subtree(TreeWidget tree, Widget w, int depth, int x, int y) +{ + TreeConstraints tc = TREE_CONSTRAINT(w); /* info attached to all kids */ + TreeConstraints firstcc, lastcc; + int i; + int newx, newy; + Bool horiz = IsHorizontal (tree); + Widget child = NULL; + Dimension tmp; + Dimension bw2 = w->core.border_width * 2; + Bool relayout = True; + + + /* + * If no children, then just lay out where requested. + */ + tc->tree.x = x; + tc->tree.y = y; + + if (horiz) { + int myh = (w->core.height + bw2); + + if (myh > (int)tc->tree.bbsubheight) { + y += (myh - (int)tc->tree.bbsubheight) / 2; + relayout = False; + } + } else { + int myw = (w->core.width + bw2); + + if (myw > (int)tc->tree.bbsubwidth) { + x += (myw - (int)tc->tree.bbsubwidth) / 2; + relayout = False; + } + } + + if ((tmp = ((Dimension) x) + tc->tree.bbwidth) > tree->tree.maxwidth) + tree->tree.maxwidth = tmp; + if ((tmp = ((Dimension) y) + tc->tree.bbheight) > tree->tree.maxheight) + tree->tree.maxheight = tmp; + + if (tc->tree.n_children == 0) return; + + + /* + * Have children, so walk down tree laying out children, then laying + * out parents. + */ + if (horiz) { + newx = x + tree->tree.largest[depth]; + if (depth > 0) newx += tree->tree.hpad; + newy = y; + } else { + newx = x; + newy = y + tree->tree.largest[depth]; + if (depth > 0) newy += tree->tree.vpad; + } + + for (i = 0; i < tc->tree.n_children; i++) { + TreeConstraints cc; + + child = tc->tree.children[i]; /* last value is used outside loop */ + cc = TREE_CONSTRAINT(child); + + arrange_subtree (tree, child, depth + 1, newx, newy); + if (horiz) { + newy += tree->tree.vpad + cc->tree.bbheight; + } else { + newx += tree->tree.hpad + cc->tree.bbwidth; + } + } + + /* + * now layout parent between first and last children + */ + if (relayout) { + Position adjusted; + firstcc = TREE_CONSTRAINT (tc->tree.children[0]); + lastcc = TREE_CONSTRAINT (child); + + /* Adjustments are disallowed if they result in a position above + * or to the left of the originally requested position, because + * this could collide with the position of the previous sibling. + */ + if (horiz) { + tc->tree.x = x; + adjusted = firstcc->tree.y + + ((lastcc->tree.y + (Position) child->core.height + + (Position) child->core.border_width * 2 - + firstcc->tree.y - (Position) w->core.height - + (Position) w->core.border_width * 2 + 1) / 2); + if (adjusted > tc->tree.y) tc->tree.y = adjusted; + } else { + adjusted = firstcc->tree.x + + ((lastcc->tree.x + (Position) child->core.width + + (Position) child->core.border_width * 2 - + firstcc->tree.x - (Position) w->core.width - + (Position) w->core.border_width * 2 + 1) / 2); + if (adjusted > tc->tree.x) tc->tree.x = adjusted; + tc->tree.y = y; + } + } +} + +static void +set_tree_size(TreeWidget tw, Bool insetvalues, + unsigned int width, unsigned int height) +{ + if (insetvalues) { + tw->core.width = width; + tw->core.height = height; + } else { + Dimension replyWidth = 0, replyHeight = 0; + XtGeometryResult result = XtMakeResizeRequest ((Widget) tw, + width, height, + &replyWidth, + &replyHeight); + /* + * Accept any compromise. + */ + if (result == XtGeometryAlmost) + XtMakeResizeRequest ((Widget) tw, replyWidth, replyHeight, + (Dimension *) NULL, (Dimension *) NULL); + } + return; +} + +static void +layout_tree(TreeWidget tw, Bool insetvalues) +{ + int i; + Dimension *dp; + + /* + * Do a depth-first search computing the width and height of the bounding + * box for the tree at that position (and below). Then, walk again using + * this information to layout the children at each level. + */ + + if (tw->tree.tree_root == NULL) + return; + + tw->tree.maxwidth = tw->tree.maxheight = 0; + for (i = 0, dp = tw->tree.largest; i < tw->tree.n_largest; i++, dp++) + *dp = 0; + initialize_dimensions (&tw->tree.largest, &tw->tree.n_largest, + tw->tree.n_largest); + compute_bounding_box_subtree (tw, tw->tree.tree_root, 0); + + /* + * Second pass to do final layout. Each child's bounding box is stacked + * on top of (if horizontal, else next to) on top of its siblings. The + * parent is centered between the first and last children. + */ + arrange_subtree (tw, tw->tree.tree_root, 0, 0, 0); + + /* + * Move each widget into place. + */ + set_tree_size (tw, insetvalues, tw->tree.maxwidth, tw->tree.maxheight); + set_positions (tw, tw->tree.tree_root, 0); + + /* + * And redisplay. + */ + if (XtIsRealized ((Widget) tw)) { + XClearArea (XtDisplay(tw), XtWindow((Widget)tw), 0, 0, 0, 0, True); + } +} + + + +/***************************************************************************** + * * + * Public Routines * + * * + *****************************************************************************/ + +void +XawTreeForceLayout(Widget tree) +{ + layout_tree ((TreeWidget) tree, FALSE); +} + |