comparison pkg-src/tree-x/draw.c @ 167:85ec50267440 r20-3b10

Import from CVS: tag r20-3b10
author cvs
date Mon, 13 Aug 2007 09:45:46 +0200
parents 0132846995bd
children 15872534500d
comparison
equal deleted inserted replaced
166:7a77eb660975 167:85ec50267440
2 * File : draw.c 2 * File : draw.c
3 * Purpose : drawing-specific routines for dynamic tree program 3 * Purpose : drawing-specific routines for dynamic tree program
4 * ---------------------------------------------------------------------------- 4 * ----------------------------------------------------------------------------
5 */ 5 */
6 6
7 #include <stdlib.h>
7 #include <X11/Intrinsic.h> 8 #include <X11/Intrinsic.h>
8 #include <X11/StringDefs.h> 9 #include <X11/StringDefs.h>
9 10
11 #include "dissolve.h"
10 #include "defs.h" 12 #include "defs.h"
11 #include "tree.h" 13 #include "tree.h"
12 #include "dbl.h" 14 #include "dbl.h"
13 #include "intf.h" 15 #include "intf.h"
14 16
21 23
22 /* ------------------------------------------------------------------------- */ 24 /* ------------------------------------------------------------------------- */
23 /* Local Variables */ 25 /* Local Variables */
24 /* ------------------------------------------------------------------------- */ 26 /* ------------------------------------------------------------------------- */
25 27
26 static char AnimationMode = FALSE; 28 static char AnimationMode = FALSE;
27 static char strbuf[BUFSIZ]; 29 static char strbuf[BUFSIZ];
28 static int AnimationStep = ANIMATION_STEP; 30 static int AnimationStep = ANIMATION_STEP;
29
30 /* ------------------------------------------------------------------------- */
31 /* Forward Function Declarations */
32 /* ------------------------------------------------------------------------- */
33
34 void DrawNode();
35 void DrawTreeContour();
36 31
37 32
38 /* ------------------------------------------------------------------------- */ 33 /* ------------------------------------------------------------------------- */
39 /* Functions */ 34 /* Functions */
40 /* ------------------------------------------------------------------------- */ 35 /* ------------------------------------------------------------------------- */
41 36
42 37
43 /* ---------------------------------------------------------------------------- 38 /* ----------------------------------------------------------------------------
44 * 39 *
45 * BeginFrame() provides an abstraction for double buffering. It should 40 * BeginFrame() provides an abstraction for double buffering. It should
46 * be called prior to creating a new frame of animation. 41 * be called prior to creating a new frame of animation.
47 * 42 *
48 * ---------------------------------------------------------------------------- 43 * ----------------------------------------------------------------------------
49 */ 44 */
50 45
51 void 46 void
52 BeginFrame() 47 BeginFrame(void)
53 { 48 {
54 DBLbegin_frame(TreeDrawingAreaDB); 49 DBLbegin_frame(TreeDrawingAreaDB);
55 } 50 }
56 51
57 52
58 /* ---------------------------------------------------------------------------- 53 /* ----------------------------------------------------------------------------
59 * 54 *
60 * EndFrame() provides an abstraction for double buffering. It should 55 * EndFrame() provides an abstraction for double buffering. It should
61 * be called after creating a new frame of animation. 56 * be called after creating a new frame of animation.
62 * 57 *
63 * ---------------------------------------------------------------------------- 58 * ----------------------------------------------------------------------------
64 */ 59 */
65 60
66 void 61 void
67 EndFrame() 62 EndFrame(void)
68 { 63 {
69 DBLend_frame(TreeDrawingAreaDB, 0); 64 DBLend_frame(TreeDrawingAreaDB, 0);
70 } 65 }
71 66
72 67
73 /* ---------------------------------------------------------------------------- 68 /* ----------------------------------------------------------------------------
74 * 69 *
75 * GetDrawingSize() gets the size of the drawing area, and returns the 70 * GetDrawingSize() gets the size of the drawing area, and returns the
76 * dimensions in the arguments. 71 * dimensions in the arguments.
77 * 72 *
78 * ---------------------------------------------------------------------------- 73 * ----------------------------------------------------------------------------
79 */ 74 */
80 75
81 void 76 static void
82 GetDrawingSize(width, height) 77 GetDrawingSize(int *width, int *height)
83 int *width, *height;
84 { 78 {
85 Dimension w, h; 79 Dimension w, h;
86 80 Arg al [2];
87 XtVaGetValues(TreeDrawingArea, 81
88 XtNwidth, &w, 82 XtSetArg (al [0], XtNwidth, &w);
89 XtNheight, &h, 83 XtSetArg (al [1], XtNheight, &h);
90 NULL); 84 XtGetValues(TreeDrawingArea, al, 2);
91 85
92 *width = (int) w; 86 *width = (int) w;
93 *height = (int) h; 87 *height = (int) h;
94 } 88 }
95 89
96 90
97 /* ---------------------------------------------------------------------------- 91 /* ----------------------------------------------------------------------------
98 * 92 *
99 * SetDrawingSize() sets the size of the drawing area to the given 93 * SetDrawingSize() sets the size of the drawing area to the given
100 * dimensions. 94 * dimensions.
101 * 95 *
102 * ---------------------------------------------------------------------------- 96 * ----------------------------------------------------------------------------
103 */ 97 */
104 98
105 void 99 static void
106 SetDrawingSize(width, height) 100 SetDrawingSize(int width, int height)
107 int width, height; 101 {
108 { 102 Arg al [2];
109 XtVaSetValues(TreeDrawingArea, 103 XtSetArg (al [0], XtNwidth, (Dimension) width);
110 XtNwidth, (Dimension) width, 104 XtSetArg (al [1], XtNheight, (Dimension) height);
111 XtNheight, (Dimension) height, 105 XtSetValues (TreeDrawingArea, al, 2);
112 NULL); 106 }
113 } 107
114 108
115 109 /* ----------------------------------------------------------------------------
116 /* ---------------------------------------------------------------------------- 110 *
117 *
118 * SetDrawingTree() is used to specify what tree is to be drawn in the 111 * SetDrawingTree() is used to specify what tree is to be drawn in the
119 * drawing area. 112 * drawing area.
120 * 113 *
121 * ---------------------------------------------------------------------------- 114 * ----------------------------------------------------------------------------
122 */ 115 */
123 116
124 void 117 void
125 SetDrawingTree(tree) 118 SetDrawingTree(Tree *tree)
126 Tree *tree; 119 {
127 { 120 TheTree = tree;
128 TheTree = tree; 121 }
129 } 122
130 123
131 124 /* ----------------------------------------------------------------------------
132 /* ---------------------------------------------------------------------------- 125 *
133 *
134 * SetNodeLabel() sets the label text of the specified node and computes 126 * SetNodeLabel() sets the label text of the specified node and computes
135 * the bounding rectangle so that the layout can be determined. This 127 * the bounding rectangle so that the layout can be determined. This
136 * function is called when new nodes are created. If TreeAlignNodes is 128 * function is called when new nodes are created. If TreeAlignNodes is
137 * True, the string is truncated so that the node's width is no longer 129 * True, the string is truncated so that the node's width is no longer
138 * than TreeParentDistance. 130 * than TreeParentDistance.
139 * 131 *
140 * ---------------------------------------------------------------------------- 132 * ----------------------------------------------------------------------------
141 */ 133 */
142 134
143 void 135 void
144 SetNodeLabel(node, label) 136 SetNodeLabel(Tree *node, char *label)
145 Tree *node;
146 char *label;
147 { 137 {
148 int len; 138 int len;
149 int dummy; 139 int dummy;
150 XCharStruct rtrn; 140 XCharStruct rtrn;
151 141
152 len = strlen(label); 142 len = strlen(label);
153 while (len > 1) { 143 while (len > 1) {
154 XTextExtents(TreeLabelFont, label, len, &dummy, &dummy, &dummy, &rtrn); 144 XTextExtents(TreeLabelFont, label, len, &dummy, &dummy, &dummy, &rtrn);
155 node->width = rtrn.lbearing + rtrn.rbearing + (LABEL_MAT_WIDTH * 2) + 1; 145 node->width = rtrn.lbearing + rtrn.rbearing + (LABEL_MAT_WIDTH * 2) + 1;
156 node->height = rtrn.ascent + rtrn.descent + (LABEL_MAT_HEIGHT * 2) + 1; 146 node->height = rtrn.ascent + rtrn.descent + (LABEL_MAT_HEIGHT * 2) + 1;
161 len--; 151 len--;
162 } 152 }
163 else 153 else
164 break; 154 break;
165 } 155 }
166 156
167 node->label.text = label; 157 node->label.text = label;
168 node->label.len = len; 158 node->label.len = len;
169 node->label.xoffset = LABEL_MAT_WIDTH + 1, 159 node->label.xoffset = LABEL_MAT_WIDTH + 1,
170 node->label.yoffset = rtrn.ascent + LABEL_MAT_HEIGHT + 1; 160 node->label.yoffset = rtrn.ascent + LABEL_MAT_HEIGHT + 1;
171 } 161 }
172 162
173 163
174 /* ---------------------------------------------------------------------------- 164 /* ----------------------------------------------------------------------------
175 * 165 *
176 * SetDrawColor() sets the drawing color of the TreeDrawingArea. 166 * SetDrawColor() sets the drawing color of the TreeDrawingArea.
177 * 167 *
178 * ---------------------------------------------------------------------------- 168 * ----------------------------------------------------------------------------
179 */ 169 */
180 170
181 void 171 void
182 SetDrawColor(color) 172 SetDrawColor(int color)
183 int color;
184 { 173 {
185 XSetForeground(TreeDrawingAreaDB->display, TreeDrawingAreaDB->gc, 174 XSetForeground(TreeDrawingAreaDB->display, TreeDrawingAreaDB->gc,
186 TreeDrawingAreaDB->colors[color]); 175 TreeDrawingAreaDB->colors[color]);
187 } 176 }
188 177
189 /* ---------------------------------------------------------------------------- 178 /* ----------------------------------------------------------------------------
190 * 179 *
191 * SetLineWidth() sets the line width of lines drawn in the TreeDrawingArea. 180 * SetLineWidth() sets the line width of lines drawn in the TreeDrawingArea.
192 * 181 *
193 * ---------------------------------------------------------------------------- 182 * ----------------------------------------------------------------------------
194 */ 183 */
195 184
196 void 185 static void
197 SetLineWidth(width) 186 SetLineWidth(unsigned int width)
198 unsigned int width;
199 { 187 {
200 XSetLineAttributes(TreeDrawingAreaDB->display, TreeDrawingAreaDB->gc, 188 XSetLineAttributes(TreeDrawingAreaDB->display, TreeDrawingAreaDB->gc,
201 width, LineSolid, CapButt, JoinRound); 189 width, LineSolid, CapButt, JoinRound);
202 } 190 }
203 191
204 192
205 /* ---------------------------------------------------------------------------- 193 /* ----------------------------------------------------------------------------
206 * 194 *
207 * SetContours() sets the visibility of three possible contour modes: 195 * SetContours() sets the visibility of three possible contour modes:
208 * the outside contour, all subtree contours, or selected contours. 196 * the outside contour, all subtree contours, or selected contours.
209 * 197 *
210 * ---------------------------------------------------------------------------- 198 * ----------------------------------------------------------------------------
211 */ 199 */
212 200
213 void 201 static void
214 SetContours(option) 202 SetContours(ContourOption option)
215 ContourOption option;
216 { 203 {
217 if (option == NoContours) { 204 if (option == NoContours) {
218 switch (TreeShowContourOption) { 205 switch (TreeShowContourOption) {
219 case OutsideContour: 206 case OutsideContour:
220 DrawTreeContour(TheTree, New, BACKGROUND_COLOR, FALSE, FALSE, FALSE); 207 DrawTreeContour(TheTree, New, BACKGROUND_COLOR, FALSE, FALSE, FALSE);
260 TreeShowContourOption = option; 247 TreeShowContourOption = option;
261 } 248 }
262 249
263 250
264 /* ---------------------------------------------------------------------------- 251 /* ----------------------------------------------------------------------------
265 * 252 *
266 * HiliteNode() is called by Unzip() to change the color of a node. 253 * HiliteNode() is called by Unzip() to change the color of a node.
267 * 254 *
268 * ---------------------------------------------------------------------------- 255 * ----------------------------------------------------------------------------
269 */ 256 */
270 257
271 void 258 void
272 HiliteNode(tree, pos_mode) 259 HiliteNode(Tree *tree, PosMode pos_mode)
273 Tree *tree;
274 { 260 {
275 SetDrawColor(HIGHLIGHT_COLOR); 261 SetDrawColor(HIGHLIGHT_COLOR);
276 DrawNode(tree, pos_mode); 262 DrawNode(tree, pos_mode);
277 SetDrawColor(TREE_COLOR); 263 SetDrawColor(TREE_COLOR);
278 } 264 }
279 265
280 266
281 /* ---------------------------------------------------------------------------- 267 /* ----------------------------------------------------------------------------
282 * 268 *
283 * DrawNode() takes a node and draws the node in the specified widget 269 * DrawNode() takes a node and draws the node in the specified widget
284 * at its (x,y) coordinate. (x, y) indicates the upper-left corner where 270 * at its (x,y) coordinate. (x, y) indicates the upper-left corner where
285 * the node is drawn. Also, a line is drawn from the center of the left 271 * the node is drawn. Also, a line is drawn from the center of the left
286 * edge to the center of the parent's right edge. 'draw_mode' specifies 272 * edge to the center of the parent's right edge. 'draw_mode' specifies
287 * the drawing mode (whether or not the node is erased, rather than drawn). 273 * the drawing mode (whether or not the node is erased, rather than drawn).
288 * 'pos_mode' determines whether or not to use the old position of the node. 274 * 'pos_mode' determines whether or not to use the old position of the node.
289 * This flag is used in animating the movement of a node from its old 275 * This flag is used in animating the movement of a node from its old
290 * position to its new position. 276 * position to its new position.
291 * 277 *
292 * ---------------------------------------------------------------------------- 278 * ----------------------------------------------------------------------------
293 */ 279 */
294 280
295 void 281 void
296 DrawNode(node, pos_mode) 282 DrawNode(Tree *node, PosMode pos_mode)
297 Tree *node;
298 PosMode pos_mode;
299 { 283 {
300 Widget w; 284 Widget w;
301 GC gc; 285 GC gc;
302 286
303 w = TreeDrawingArea; 287 w = TreeDrawingArea;
304 gc = TreeDrawingAreaDB->gc; 288 gc = TreeDrawingAreaDB->gc;
305 289
306 if (pos_mode == Old) { 290 if (pos_mode == Old) {
307 XDrawString(XtDisplay(w), XtWindow(w), gc, 291 XDrawString(XtDisplay(w), XtWindow(w), gc,
308 node->old_pos.x + node->label.xoffset, 292 node->old_pos.x + node->label.xoffset,
309 node->old_pos.y + node->label.yoffset, 293 node->old_pos.y + node->label.yoffset,
310 node->label.text, node->label.len); 294 node->label.text, node->label.len);
311 XDrawRectangle(XtDisplay(w), XtWindow(w), gc, 295 XDrawRectangle(XtDisplay(w), XtWindow(w), gc,
312 node->old_pos.x, node->old_pos.y, 296 node->old_pos.x, node->old_pos.y,
313 node->width, node->height); 297 node->width, node->height);
314 if (node->parent) 298 if (node->parent)
315 XDrawLine(XtDisplay(w), XtWindow(w), gc, 299 XDrawLine(XtDisplay(w), XtWindow(w), gc,
316 node->old_pos.x - 1, 300 node->old_pos.x - 1,
317 node->old_pos.y + (node->height / 2), 301 node->old_pos.y + (node->height / 2),
318 node->parent->old_pos.x + node->parent->width + 1, 302 node->parent->old_pos.x + node->parent->width + 1,
319 node->parent->old_pos.y + (node->parent->height / 2)); 303 node->parent->old_pos.y + (node->parent->height / 2));
329 } else { 313 } else {
330 XDrawString(XtDisplay(w), XtWindow(w), gc, 314 XDrawString(XtDisplay(w), XtWindow(w), gc,
331 node->pos.x + node->label.xoffset, 315 node->pos.x + node->label.xoffset,
332 node->pos.y + node->label.yoffset, 316 node->pos.y + node->label.yoffset,
333 node->label.text, node->label.len); 317 node->label.text, node->label.len);
334 318
335 XDrawRectangle(XtDisplay(w), XtWindow(w), gc, 319 XDrawRectangle(XtDisplay(w), XtWindow(w), gc,
336 node->pos.x, node->pos.y, 320 node->pos.x, node->pos.y,
337 node->width, node->height); 321 node->width, node->height);
338 if (node->parent) 322 if (node->parent)
339 XDrawLine(XtDisplay(w), XtWindow(w), gc, 323 XDrawLine(XtDisplay(w), XtWindow(w), gc,
340 node->pos.x - 1, 324 node->pos.x - 1,
341 node->pos.y + (node->height / 2), 325 node->pos.y + (node->height / 2),
342 node->parent->pos.x + node->parent->width + 1, 326 node->parent->pos.x + node->parent->width + 1,
343 node->parent->pos.y + (node->parent->height / 2)); 327 node->parent->pos.y + (node->parent->height / 2));
353 } 337 }
354 } 338 }
355 339
356 340
357 /* ---------------------------------------------------------------------------- 341 /* ----------------------------------------------------------------------------
358 * 342 *
359 * DrawTreeContour() draws the contour of the specified subtree. Bridges 343 * DrawTreeContour() draws the contour of the specified subtree. Bridges
360 * are not traversed, so the actual subtree contour is drawn, as opposed 344 * are not traversed, so the actual subtree contour is drawn, as opposed
361 * to the merged contour. 'color' specifies the drawing color. If 'detach' 345 * to the merged contour. 'color' specifies the drawing color. If 'detach'
362 * is True, the lines attaching the subtree contour to the node are not 346 * is True, the lines attaching the subtree contour to the node are not
363 * drawn. If 'select' is true, then only subtrees that are flagged as 347 * drawn. If 'select' is true, then only subtrees that are flagged as
364 * selected are shown. If 'recursive' is True, the entire tree is traversed. 348 * selected are shown. If 'recursive' is True, the entire tree is traversed.
365 * 349 *
366 * ---------------------------------------------------------------------------- 350 * ----------------------------------------------------------------------------
367 */ 351 */
368 352
369 void 353 void
370 DrawTreeContour(tree, pos_mode, color, detach, select, recursive) 354 DrawTreeContour(Tree *tree, PosMode pos_mode,
371 Tree *tree; 355 int color, int detach_p, int select_p, int recursive)
372 PosMode pos_mode;
373 int color;
374 int detach;
375 int select;
376 int recursive;
377 { 356 {
378 Widget w = TreeDrawingArea; 357 Widget w = TreeDrawingArea;
379 Polyline *contour, *tail; 358 Polyline *contour, *tail;
380 Tree *child; 359 Tree *child;
381 int x, y, i; 360 int x, y, i;
382 361
383 if (tree == NULL) 362 if (tree == NULL)
384 return; 363 return;
385 364
386 if ((select && tree->show_contour) || !select) { 365 if ((select_p && tree->show_contour) || !select_p) {
387 366
388 SetDrawColor(color); 367 SetDrawColor(color);
389 SetLineWidth(TreeContourWidth); 368 SetLineWidth(TreeContourWidth);
390 369
391 /* draw upper contour */ 370 /* draw upper contour */
392 contour = tree->contour.upper.head; 371 contour = tree->contour.upper.head;
393 tail = tree->contour.upper.tail; 372 tail = tree->contour.upper.tail;
394 if (pos_mode == Old) { 373 if (pos_mode == Old) {
395 x = tree->old_pos.x - tree->border; 374 x = tree->old_pos.x - tree->border;
398 else { 377 else {
399 x = tree->pos.x - tree->border; 378 x = tree->pos.x - tree->border;
400 y = tree->pos.y - tree->border; 379 y = tree->pos.y - tree->border;
401 } 380 }
402 381
403 if (detach) { /* skip over attaching lines */ 382 if (detach_p) { /* skip over attaching lines */
404 for (i = 0 ; i < 2 ; i++) { 383 for (i = 0 ; i < 2 ; i++) {
405 x += contour->dx; 384 x += contour->dx;
406 y += contour->dy; 385 y += contour->dy;
407 contour = contour->link; 386 contour = contour->link;
408 } 387 }
409 } 388 }
410 389
411 while (contour) { 390 while (contour) {
412 XDrawLine(XtDisplay(w), XtWindow(w), TreeDrawingAreaDB->gc, 391 XDrawLine(XtDisplay(w), XtWindow(w), TreeDrawingAreaDB->gc,
413 x, y, x + contour->dx, y + contour->dy); 392 x, y, x + contour->dx, y + contour->dy);
414 x += contour->dx; 393 x += contour->dx;
415 y += contour->dy; 394 y += contour->dy;
428 } else { 407 } else {
429 x = tree->pos.x - tree->border; 408 x = tree->pos.x - tree->border;
430 y = tree->pos.y + tree->border + tree->height; 409 y = tree->pos.y + tree->border + tree->height;
431 } 410 }
432 411
433 if (detach) { /* skip over attaching lines */ 412 if (detach_p) { /* skip over attaching lines */
434 for (i = 0 ; i < 2 ; i++) { 413 for (i = 0 ; i < 2 ; i++) {
435 x += contour->dx; 414 x += contour->dx;
436 y += contour->dy; 415 y += contour->dy;
437 contour = contour->link; 416 contour = contour->link;
438 } 417 }
447 contour = NULL; 426 contour = NULL;
448 else 427 else
449 contour = contour->link; 428 contour = contour->link;
450 } 429 }
451 } 430 }
452 431
453 if (recursive) { 432 if (recursive) {
454 FOREACH_CHILD(child, tree) 433 FOREACH_CHILD(child, tree)
455 if (!child->elision) 434 if (!child->elision)
456 DrawTreeContour(child, pos_mode, color, 435 DrawTreeContour(child, pos_mode, color,
457 detach, select, recursive); 436 detach_p, select_p, recursive);
458 } 437 }
459 438
460 SetDrawColor(TREE_COLOR); 439 SetDrawColor(TREE_COLOR);
461 SetLineWidth(0); 440 SetLineWidth(0);
462 } 441 }
463 442
464 443
465 /* ---------------------------------------------------------------------------- 444 /* ----------------------------------------------------------------------------
466 * 445 *
467 * DrawTree() traverses the given tree, drawing the node and connecting 446 * DrawTree() traverses the given tree, drawing the node and connecting
468 * segments. The tree contours are also drawn at each step, if enabled. 447 * segments. The tree contours are also drawn at each step, if enabled.
469 * 'draw_mode' specifies the drawing mode in which the tree is drawn. 448 * 'draw_mode' specifies the drawing mode in which the tree is drawn.
470 * 'pos_mode' determines whether or not to use the old position of the node. 449 * 'pos_mode' determines whether or not to use the old position of the node.
471 * This flag is used in animating the movement of a node from its old 450 * This flag is used in animating the movement of a node from its old
472 * position to its new position. DrawNode() is called to draw an individual 451 * position to its new position. DrawNode() is called to draw an individual
473 * node. 452 * node.
474 * 453 *
475 * ---------------------------------------------------------------------------- 454 * ----------------------------------------------------------------------------
476 */ 455 */
477 456
478 void 457 void
479 DrawTree(tree, pos_mode) 458 DrawTree(Tree *tree, PosMode pos_mode)
480 Tree *tree;
481 PosMode pos_mode;
482 { 459 {
483 if (tree == NULL) 460 if (tree == NULL)
484 return; 461 return;
485 462
486 DrawNode(tree, pos_mode); 463 DrawNode(tree, pos_mode);
495 DrawTreeContour(tree, pos_mode, ACTION_COLOR, FALSE, FALSE, FALSE); 472 DrawTreeContour(tree, pos_mode, ACTION_COLOR, FALSE, FALSE, FALSE);
496 } 473 }
497 if (tree->on_path) 474 if (tree->on_path)
498 HiliteNode(tree, pos_mode); 475 HiliteNode(tree, pos_mode);
499 476
500 if (tree->child && !tree->elision) 477 if (tree->child && !tree->elision)
501 DrawTree(tree->child, pos_mode); 478 DrawTree(tree->child, pos_mode);
502 if (tree->sibling) 479 if (tree->sibling)
503 DrawTree(tree->sibling, pos_mode); 480 DrawTree(tree->sibling, pos_mode);
504 } 481 }
505 482
506 483
507 /* ---------------------------------------------------------------------------- 484 /* ----------------------------------------------------------------------------
508 * 485 *
509 * ShiftTree() adjusts the positions of each node so that it moves from 486 * ShiftTree() adjusts the positions of each node so that it moves from
510 * the "old" position towards the "new position". This is used by 487 * the "old" position towards the "new position". This is used by
511 * AnimateTree(). 'done' is set to FALSE if the tree is not in its 488 * AnimateTree(). 'done' is set to FALSE if the tree is not in its
512 * final position; it is used to determine when to stop animating the tree. 489 * final position; it is used to determine when to stop animating the tree.
513 * 490 *
514 * ---------------------------------------------------------------------------- 491 * ----------------------------------------------------------------------------
515 */ 492 */
516 493
517 void 494 static void
518 ShiftTree(tree, done) 495 ShiftTree(Tree *tree, int *done)
519 Tree *tree;
520 int *done;
521 { 496 {
522 Tree *child; 497 Tree *child;
523 498
524 if (tree->old_pos.x != tree->pos.x || 499 if (tree->old_pos.x != tree->pos.x ||
525 tree->old_pos.y != tree->pos.y) 500 tree->old_pos.y != tree->pos.y)
526 { 501 {
527 tree->old_pos.x = tree->pos.x; 502 tree->old_pos.x = tree->pos.x;
528 tree->old_pos.y = tree->pos.y; 503 tree->old_pos.y = tree->pos.y;
529 } 504 }
530 505
531 FOREACH_CHILD(child, tree) 506 FOREACH_CHILD(child, tree)
532 ShiftTree(child, done); 507 ShiftTree(child, done);
533 } 508 }
534 509
535 510
536 /* ---------------------------------------------------------------------------- 511 /* ----------------------------------------------------------------------------
537 * 512 *
538 * AnimateTree() draws the given tree in a series of steps to give the 513 * AnimateTree() draws the given tree in a series of steps to give the
539 * effect of animation from the "old" layout to the "new" layout of the 514 * effect of animation from the "old" layout to the "new" layout of the
540 * tree. 515 * tree.
541 * 516 *
542 * The algorithm used here is not efficient; the entire tree is drawn 517 * The algorithm used here is not efficient; the entire tree is drawn
543 * on each iteration of the animation sequence; it would be more efficient 518 * on each iteration of the animation sequence; it would be more efficient
544 * to only redraw what is necessary. However, the method used here takes 519 * to only redraw what is necessary. However, the method used here takes
545 * advantage of existing code without modification. 520 * advantage of existing code without modification.
546 * 521 *
547 * ---------------------------------------------------------------------------- 522 * ----------------------------------------------------------------------------
548 */ 523 */
549 524
550 void 525 static void
551 AnimateTree(tree) 526 AnimateTree(Tree *tree)
552 Tree *tree;
553 { 527 {
554 int done = FALSE; 528 int done = FALSE;
555 529
556 AnimationMode = FALSE; 530 AnimationMode = FALSE;
557 /* highlight which nodes have to move */ 531 /* highlight which nodes have to move */
558 BeginFrame(); 532 BeginFrame();
559 DrawTree(tree, Old); 533 DrawTree(tree, Old);
560 EndFrame(); 534 EndFrame();
561 Pause(); 535 Pause();
562 if (PauseAfterStep) 536 if (PauseAfterStep)
563 AnimationStep = ANIMATION_STEP_STEP; 537 AnimationStep = ANIMATION_STEP_STEP;
564 while (!done) { 538 while (!done) {
565 done = TRUE; 539 done = TRUE;
566 ShiftTree(tree, &done); 540 ShiftTree(tree, &done);
575 AnimationMode = FALSE; 549 AnimationMode = FALSE;
576 } 550 }
577 551
578 552
579 /* ---------------------------------------------------------------------------- 553 /* ----------------------------------------------------------------------------
580 * 554 *
581 * AnimateZip() generates a sequence of frames that animates the Zip() step. 555 * AnimateZip() generates a sequence of frames that animates the Zip() step.
582 * It is similar in logical structure to Zip(). 556 * It is similar in logical structure to Zip().
583 * 557 *
584 * ---------------------------------------------------------------------------- 558 * ----------------------------------------------------------------------------
585 */ 559 */
586 560
587 void 561 static void
588 AnimateZip(tree) 562 AnimateZip(Tree *tree)
589 Tree *tree;
590 { 563 {
591 Tree *child; 564 Tree *child;
592 565
593 /* show results of Join() step */ 566 /* show results of Join() step */
594 if (tree->child) { 567 if (tree->child) {
595 BeginFrame(); 568 BeginFrame();
596 FOREACH_CHILD(child, tree) 569 FOREACH_CHILD(child, tree)
597 child->split = FALSE; 570 child->split = FALSE;
598 DrawTree(TheTree, New); 571 DrawTree(TheTree, New);
599 DrawTreeContour(tree, New, CONTOUR_COLOR, TRUE, FALSE, FALSE); 572 DrawTreeContour(tree, New, CONTOUR_COLOR, TRUE, FALSE, FALSE);
600 EndFrame(); 573 EndFrame();
601 574
602 StatusMsg("Zip: merge and join contours", FALSE); 575 StatusMsg("Zip: merge and join contours", FALSE);
603 Pause(); 576 Pause();
604 577
605 /* show results of AttachParent() step */ 578 /* show results of AttachParent() step */
606 BeginFrame(); 579 BeginFrame();
607 DrawTree(TheTree, New); 580 DrawTree(TheTree, New);
608 DrawTreeContour(tree, New, CONTOUR_COLOR, FALSE, FALSE, FALSE); 581 DrawTreeContour(tree, New, CONTOUR_COLOR, FALSE, FALSE, FALSE);
609 EndFrame(); 582 EndFrame();
610 583
611 StatusMsg("Zip: attach parents", FALSE); 584 StatusMsg("Zip: attach parents", FALSE);
612 Pause(); 585 Pause();
613 } 586 }
614 587
615 tree->on_path = FALSE; 588 tree->on_path = FALSE;
616 589
617 if (tree->parent) 590 if (tree->parent)
618 AnimateZip(tree->parent); 591 AnimateZip(tree->parent);
619 else { 592 else {
620 tree->on_path = FALSE; 593 tree->on_path = FALSE;
621 BeginFrame(); 594 BeginFrame();
622 DrawTree(TheTree, New); 595 DrawTree(TheTree, New);
623 DrawTreeContour(TheTree, New, CONTOUR_COLOR, FALSE, FALSE, FALSE); 596 DrawTreeContour(TheTree, New, CONTOUR_COLOR, FALSE, FALSE, FALSE);
624 EndFrame(); 597 EndFrame();
625 StatusMsg("Zip: reassemble entire contour", FALSE); 598 StatusMsg("Zip: reassemble entire contour", FALSE);
626 Pause(); 599 Pause();
627 } 600 }
628 } 601 }
629 602
630 603
631 /* ---------------------------------------------------------------------------- 604 /* ----------------------------------------------------------------------------
632 * 605 *
633 * CountNodes() returns the number of nodes in the specified tree. 606 * CountNodes() returns the number of nodes in the specified tree.
634 * Nodes below a node that has been collapsed are ignored. 607 * Nodes below a node that has been collapsed are ignored.
635 * 608 *
636 * ---------------------------------------------------------------------------- 609 * ----------------------------------------------------------------------------
637 */ 610 */
638 611
639 int 612 static int
640 CountNodes(tree) 613 CountNodes(Tree *tree)
641 Tree *tree;
642 { 614 {
643 int num_nodes = 1; /* count root of subtree */ 615 int num_nodes = 1; /* count root of subtree */
644 Tree *child; 616 Tree *child;
645 617
646 if (!tree->elision) { 618 if (!tree->elision) {
647 FOREACH_CHILD(child, tree) 619 FOREACH_CHILD(child, tree)
648 num_nodes += CountNodes(child); 620 num_nodes += CountNodes(child);
649 } 621 }
650 return (num_nodes); 622 return (num_nodes);
651 } 623 }
652 624
653 625
654 /* ---------------------------------------------------------------------------- 626 /* ----------------------------------------------------------------------------
655 * 627 *
656 * CollectNodeRectangles() is a recursive function used by 628 * CollectNodeRectangles() is a recursive function used by
657 * GetSubTreeRectangles() to collect the rectangles of descendant nodes 629 * GetSubTreeRectangles() to collect the rectangles of descendant nodes
658 * into the pre-allocated storage passed to this function. 630 * into the pre-allocated storage passed to this function.
659 * 631 *
660 * ---------------------------------------------------------------------------- 632 * ----------------------------------------------------------------------------
661 */ 633 */
662 634
663 void 635 static void
664 CollectNodeRectangles(node, rectangles, fill) 636 CollectNodeRectangles(Tree *node, XRectangle **rectangles, int fill)
665 Tree *node;
666 XRectangle **rectangles;
667 int fill;
668 { 637 {
669 Tree *child; 638 Tree *child;
670 639
671 (*rectangles)->x = node->pos.x; 640 (*rectangles)->x = node->pos.x;
672 (*rectangles)->y = node->pos.y; 641 (*rectangles)->y = node->pos.y;
673 if (fill) { 642 if (fill) {
674 (*rectangles)->width = node->width + 1; 643 (*rectangles)->width = node->width + 1;
675 (*rectangles)->height = node->height + 1; 644 (*rectangles)->height = node->height + 1;
676 } else { 645 } else {
677 (*rectangles)->width = node->width; 646 (*rectangles)->width = node->width;
678 (*rectangles)->height = node->height; 647 (*rectangles)->height = node->height;
679 } 648 }
680 (*rectangles)++; 649 (*rectangles)++;
681 650
682 if (!node->elision) 651 if (!node->elision)
683 FOREACH_CHILD(child, node) 652 FOREACH_CHILD(child, node)
684 CollectNodeRectangles(child, rectangles, fill); 653 CollectNodeRectangles(child, rectangles, fill);
685 } 654 }
686 655
687 656
688 /* ---------------------------------------------------------------------------- 657 /* ----------------------------------------------------------------------------
689 * 658 *
690 * GetSubTreeRectangles() builds an array of XRectangles that contain 659 * GetSubTreeRectangles() builds an array of XRectangles that contain
691 * all the node rectangles in the tree, except the root node itself. 660 * all the node rectangles in the tree, except the root node itself.
692 * The array is returned in 'rectangles' and the number of rectangles 661 * The array is returned in 'rectangles' and the number of rectangles
693 * is returned in 'nrectangles.' Storage for the rectangles is allocated 662 * is returned in 'nrectangles.' Storage for the rectangles is allocated
694 * in this function. This function is used by PickAction to determine 663 * in this function. This function is used by PickAction to determine
695 * what rectangles need to be dissolved away. 'fill', if True, specifies 664 * what rectangles need to be dissolved away. 'fill', if True, specifies
696 * that the rectangles should be 1 pixel larger in each dimension to 665 * that the rectangles should be 1 pixel larger in each dimension to
697 * compensate for FillRectangle behavior. 666 * compensate for FillRectangle behavior.
698 * 667 *
699 * ---------------------------------------------------------------------------- 668 * ----------------------------------------------------------------------------
700 */ 669 */
701 670
702 void 671 static void
703 GetSubTreeRectangles(tree, rectangles, nrectangles, fill) 672 GetSubTreeRectangles(Tree *tree, XRectangle **rectangles,
704 Tree *tree; 673 int *nrectangles, int fill)
705 XRectangle **rectangles;
706 int *nrectangles, fill;
707 { 674 {
708 Tree *child; 675 Tree *child;
709 XRectangle *crect; /* current rectangle */ 676 XRectangle *crect; /* current rectangle */
710 677
711 *nrectangles = CountNodes(tree) - 1; /* don't count root node */ 678 *nrectangles = CountNodes(tree) - 1; /* don't count root node */
712 *rectangles = (XRectangle *) malloc(sizeof(XRectangle) * *nrectangles); 679 *rectangles = (XRectangle *) malloc(sizeof(XRectangle) * *nrectangles);
713 ASSERT(*rectangles, "could not allocate memory for rectangles"); 680 ASSERT(*rectangles, "could not allocate memory for rectangles");
714 681
715 crect = *rectangles; 682 crect = *rectangles;
716 if (!tree->elision) 683 if (!tree->elision)
717 FOREACH_CHILD(child, tree) 684 FOREACH_CHILD(child, tree)
718 CollectNodeRectangles(child, &crect, fill); 685 CollectNodeRectangles(child, &crect, fill);
719 } 686 }
720 687
721 688
722 /* ---------------------------------------------------------------------------- 689 /* ----------------------------------------------------------------------------
723 * 690 *
724 * CollectNodeSegments() is a recursive function used by GetSubTreeSegments() 691 * CollectNodeSegments() is a recursive function used by GetSubTreeSegments()
725 * to collect the line segments connecting nodes into the pre-allocated 692 * to collect the line segments connecting nodes into the pre-allocated
726 * storage passed to this function. 693 * storage passed to this function.
727 * 694 *
728 * ---------------------------------------------------------------------------- 695 * ----------------------------------------------------------------------------
729 */ 696 */
730 697
731 void 698 static void
732 CollectNodeSegments(node, segments) 699 CollectNodeSegments(Tree *node, XSegment **segments)
733 Tree *node;
734 XSegment **segments;
735 { 700 {
736 Tree *child; 701 Tree *child;
737 702
738 (*segments)->x1 = node->pos.x - 1; 703 (*segments)->x1 = node->pos.x - 1;
739 (*segments)->y1 = node->pos.y + (node->height / 2), 704 (*segments)->y1 = node->pos.y + (node->height / 2),
740 (*segments)->x2 = node->parent->pos.x + node->parent->width + 1; 705 (*segments)->x2 = node->parent->pos.x + node->parent->width + 1;
741 (*segments)->y2 = node->parent->pos.y + (node->parent->height / 2); 706 (*segments)->y2 = node->parent->pos.y + (node->parent->height / 2);
742 (*segments)++; 707 (*segments)++;
743 708
744 if (!node->elision) 709 if (!node->elision)
745 FOREACH_CHILD(child, node) 710 FOREACH_CHILD(child, node)
746 CollectNodeSegments(child, segments); 711 CollectNodeSegments(child, segments);
747 } 712 }
748 713
749 714
750 /* ---------------------------------------------------------------------------- 715 /* ----------------------------------------------------------------------------
751 * 716 *
752 * GetSubTreeSegments() builds an array of XSegments that contain 717 * GetSubTreeSegments() builds an array of XSegments that contain
753 * all the line segments connecting the nodes in the tree. The array is 718 * all the line segments connecting the nodes in the tree. The array is
754 * returned in 'segments' and the number of segments is returned in 719 * returned in 'segments' and the number of segments is returned in
755 * 'nsegments.' Storage for the segments is allocated in this function. 720 * 'nsegments.' Storage for the segments is allocated in this function.
756 * This function is used by PickAction to determine what line segments 721 * This function is used by PickAction to determine what line segments
757 * rectangles need to be dissolved away. 722 * rectangles need to be dissolved away.
758 * 723 *
759 * ---------------------------------------------------------------------------- 724 * ----------------------------------------------------------------------------
760 */ 725 */
761 726
762 void 727 static void
763 GetSubTreeSegments(tree, segments, nsegments) 728 GetSubTreeSegments(Tree *tree, XSegment **segments, int *nsegments)
764 Tree *tree;
765 XSegment **segments;
766 int *nsegments;
767 { 729 {
768 Tree *child; 730 Tree *child;
769 XSegment *cseg; /* current segment */ 731 XSegment *cseg; /* current segment */
770 732
771 *nsegments = CountNodes(tree) - 1; 733 *nsegments = CountNodes(tree) - 1;
772 *segments = (XSegment *) malloc(sizeof(XSegment) * *nsegments); 734 *segments = (XSegment *) malloc(sizeof(XSegment) * *nsegments);
773 ASSERT(*segments, "could not allocate memory for segments"); 735 ASSERT(*segments, "could not allocate memory for segments");
774 736
775 cseg = *segments; 737 cseg = *segments;
776 if (!tree->elision) 738 if (!tree->elision)
777 FOREACH_CHILD(child, tree) 739 FOREACH_CHILD(child, tree)
778 CollectNodeSegments(child, &cseg); 740 CollectNodeSegments(child, &cseg);
779 } 741 }
780 742
781 743
782 /* ---------------------------------------------------------------------------- 744 /* ----------------------------------------------------------------------------
783 * 745 *
784 * ComputeSubTreeExtent() computes the extent of a subtree. This is 746 * ComputeSubTreeExtent() computes the extent of a subtree. This is
785 * easily computed based on the tree's contour, as in ComputeTreeSize(). 747 * easily computed based on the tree's contour, as in ComputeTreeSize().
786 * This extent is stored in the node, and used by SearchTree for 748 * This extent is stored in the node, and used by SearchTree for
787 * pick-correlation. 749 * pick-correlation.
788 * 750 *
789 * This function assumes that the given tree has at least one child; do not 751 * This function assumes that the given tree has at least one child; do not
790 * pass a leaf node to this function. 752 * pass a leaf node to this function.
791 * 753 *
792 * ---------------------------------------------------------------------------- 754 * ----------------------------------------------------------------------------
793 */ 755 */
794 756
795 void 757 void
796 ComputeSubTreeExtent(tree) 758 ComputeSubTreeExtent(Tree *tree)
797 Tree *tree;
798 { 759 {
799 int width, height; 760 int width, height;
800 int x_offset, y_offset; 761 int x_offset, y_offset;
801 762
802 ComputeTreeSize(tree, &width, &height, &x_offset, &y_offset); 763 ComputeTreeSize(tree, &width, &height, &x_offset, &y_offset);
806 tree->subextent.height = height - 1; 767 tree->subextent.height = height - 1;
807 } 768 }
808 769
809 770
810 /* ---------------------------------------------------------------------------- 771 /* ----------------------------------------------------------------------------
811 * 772 *
812 * SearchTree() determines if a node's rectangular region encloses the 773 * SearchTree() determines if a node's rectangular region encloses the
813 * specified point in (x,y). Rather than using a brute-force search 774 * specified point in (x,y). Rather than using a brute-force search
814 * through all node rectangles of a given tree, the subtree extents 775 * through all node rectangles of a given tree, the subtree extents
815 * are used in a recursive fashion to drive the search as long as the 776 * are used in a recursive fashion to drive the search as long as the
816 * given point is enclosed in an extent. In the worst case, the search 777 * given point is enclosed in an extent. In the worst case, the search
817 * time would be on the order of a brute-force search, but with complex 778 * time would be on the order of a brute-force search, but with complex
818 * trees, this method reduces the number of visits. 779 * trees, this method reduces the number of visits.
819 * 780 *
820 * The extent of a subtree is computed by ComputeSubTreeExtent() and is 781 * The extent of a subtree is computed by ComputeSubTreeExtent() and is
821 * stored in each node of the tree. 782 * stored in each node of the tree.
822 * 783 *
823 * ---------------------------------------------------------------------------- 784 * ----------------------------------------------------------------------------
824 */ 785 */
825 786
826 int 787 int
827 SearchTree(tree, x, y, node) 788 SearchTree(Tree *tree, int x, int y, Tree **node)
828 Tree *tree, **node;
829 int x, y;
830 { 789 {
831 Tree *child; 790 Tree *child;
832 791
833 if (tree == NULL) 792 if (tree == NULL)
834 return (FALSE); 793 return (FALSE);
835 794
836 if (PT_IN_RECT(x, y, tree->pos.x, tree->pos.y, 795 if (PT_IN_RECT(x, y, tree->pos.x, tree->pos.y,
837 tree->pos.x + tree->width, 796 tree->pos.x + tree->width,
838 tree->pos.y + tree->height)) { 797 tree->pos.y + tree->height)) {
839 *node = tree; 798 *node = tree;
840 return (TRUE); 799 return (TRUE);
841 } 800 }
842 if (tree->child && (PT_IN_EXTENT(x, y, tree->subextent))) 801 if (tree->child && (PT_IN_EXTENT(x, y, tree->subextent)))
843 FOREACH_CHILD(child, tree) { 802 FOREACH_CHILD(child, tree) {
844 if (SearchTree(child, x, y, node)) 803 if (SearchTree(child, x, y, node))
845 return (TRUE); 804 return (TRUE);
846 } 805 }
847 return (FALSE); 806 return (FALSE);
848 } 807 }
849 808
850 809
851 /* ---------------------------------------------------------------------------- 810 /* ----------------------------------------------------------------------------
852 * 811 *
853 * ExposeHandler() handles expose events in the TreeDrawingArea. This 812 * ExposeHandler() handles expose events in the TreeDrawingArea. This
854 * function is not intelligent; it just redraws the entire contents. 813 * function is not intelligent; it just redraws the entire contents.
855 * 814 *
856 * ---------------------------------------------------------------------------- 815 * ----------------------------------------------------------------------------
857 */ 816 */
858 817
859 void 818 void
860 ExposeHandler(w, client_data, event) 819 ExposeHandler(Widget w, XtPointer closure,
861 Widget w; 820 XEvent *event, Boolean *continue_to_dispatch)
862 caddr_t client_data; 821 {
863 XExposeEvent *event; 822 if (event->xexpose.count == 0) {
864 {
865
866 if (event->count == 0) {
867 BeginFrame(); 823 BeginFrame();
868 SetContours(TreeShowContourOption); 824 SetContours(TreeShowContourOption);
869 DrawTree(TheTree, New); 825 DrawTree(TheTree, New);
870 EndFrame(); 826 EndFrame();
871 } 827 }
872 } 828 }
873 829
874 830
875 /* ---------------------------------------------------------------------------- 831 /* ----------------------------------------------------------------------------
876 * 832 *
877 * ExpandCollapseNode is called to expand or collapse a node in the tree. 833 * ExpandCollapseNode is called to expand or collapse a node in the tree.
878 * 834 *
879 * ---------------------------------------------------------------------------- 835 * ----------------------------------------------------------------------------
880 */ 836 */
881 837
882 void 838 void
883 ExpandCollapseNode(node) 839 ExpandCollapseNode(Tree *node)
884 Tree *node;
885 { 840 {
886 int width, height; 841 int width, height;
887 int old_width, old_height; 842 int old_width, old_height;
888 int x_offset, y_offset; 843 int x_offset, y_offset;
889 XRectangle *rectangles; 844 XRectangle *rectangles;
890 XSegment *segments; 845 XSegment *segments;
891 int nrectangles, nsegments; 846 int nrectangles, nsegments;
892 int expand = FALSE; 847 int expand = FALSE;
893 Widget w = TreeDrawingArea; 848 Widget w = TreeDrawingArea;
894 849
895 StatusMsg("", TRUE); 850 StatusMsg("", TRUE);
896 851
897 /* hilite node so that we know where we are */ 852 /* hilite node so that we know where we are */
898 /* DrawTree will hilite it as a side effect */ 853 /* DrawTree will hilite it as a side effect */
899 if (TreeShowSteps) 854 if (TreeShowSteps)
900 node->on_path = TRUE; 855 node->on_path = TRUE;
901 856
902 /* erase the contour before changing in the tree */ 857 /* erase the contour before changing in the tree */
903 if ((TreeShowContourOption != NoContours) || TreeShowSteps) { 858 if ((TreeShowContourOption != NoContours) || TreeShowSteps) {
904 BeginFrame(); 859 BeginFrame();
905 DrawTree(TheTree, New); 860 DrawTree(TheTree, New);
906 EndFrame(); 861 EndFrame();
907 } 862 }
908 863
909 sprintf(strbuf, "Node `%s' selected for %s", node->label.text, 864 sprintf(strbuf, "Node `%s' selected for %s", node->label.text,
910 node->elision ? "expansion" : "collapse"); 865 node->elision ? "expansion" : "collapse");
911 StatusMsg(strbuf, FALSE); 866 StatusMsg(strbuf, FALSE);
912 Pause(); 867 Pause();
913 868
914 if (node->parent) 869 if (node->parent)
915 Unzip(node->parent); 870 Unzip(node->parent);
916 else { 871 else {
917 StatusMsg("Show entire contour", FALSE); 872 StatusMsg("Show entire contour", FALSE);
918 if (TreeShowSteps) { 873 if (TreeShowSteps) {
919 BeginFrame(); 874 BeginFrame();
920 DrawTreeContour(TheTree, New, CONTOUR_COLOR, FALSE, FALSE, FALSE); 875 DrawTreeContour(TheTree, New, CONTOUR_COLOR, FALSE, FALSE, FALSE);
921 DrawTree(TheTree, New); 876 DrawTree(TheTree, New);
922 EndFrame(); 877 EndFrame();
923 Pause(); 878 Pause();
924 } 879 }
925 } 880 }
926 881
927 /* are we collapsing a subtree? */ 882 /* are we collapsing a subtree? */
928 if (!node->elision) { 883 if (!node->elision) {
932 DissolveTree(XtDisplay(w), XtWindow(w), 887 DissolveTree(XtDisplay(w), XtWindow(w),
933 rectangles, nrectangles, 888 rectangles, nrectangles,
934 segments, nsegments, TRUE); 889 segments, nsegments, TRUE);
935 free(rectangles); 890 free(rectangles);
936 free(segments); 891 free(segments);
937 Pause(); 892 Pause();
938 893
939 StatusMsg("Replace subtree contour with leaf contour", FALSE); 894 StatusMsg("Replace subtree contour with leaf contour", FALSE);
940 node->elision = TRUE; 895 node->elision = TRUE;
941 if (TreeShowSteps) 896 if (TreeShowSteps)
942 node->split = TRUE; /* turned off in AnimateZip */ 897 node->split = TRUE; /* turned off in AnimateZip */
943 node->old_contour = node->contour; 898 node->old_contour = node->contour;
945 LayoutLeaf(node); 900 LayoutLeaf(node);
946 BeginFrame(); 901 BeginFrame();
947 SetContours(TreeShowContourOption); 902 SetContours(TreeShowContourOption);
948 DrawTree(TheTree, New); 903 DrawTree(TheTree, New);
949 EndFrame(); 904 EndFrame();
950 Pause(); 905 Pause();
951 } else { 906 } else {
952 StatusMsg("Replace leaf contour with old subtree contour", FALSE); 907 StatusMsg("Replace leaf contour with old subtree contour", FALSE);
953 if (TreeShowSteps) 908 if (TreeShowSteps)
954 node->split = TRUE; /* turned off in AnimateZip */ 909 node->split = TRUE; /* turned off in AnimateZip */
955 RuboutLeaf(node); 910 RuboutLeaf(node);
956 node->contour = node->old_contour; 911 node->contour = node->old_contour;
957 expand = TRUE; 912 expand = TRUE;
958 } 913 }
959 914
960 if (node->parent) 915 if (node->parent)
961 Zip(node->parent); 916 Zip(node->parent);
962 917
963 ComputeTreeSize(TheTree, &width, &height, &x_offset, &y_offset); 918 ComputeTreeSize(TheTree, &width, &height, &x_offset, &y_offset);
964 PetrifyTree(TheTree, x_offset + MAT_SIZE, y_offset + MAT_SIZE); 919 PetrifyTree(TheTree, x_offset + MAT_SIZE, y_offset + MAT_SIZE);
965 GetDrawingSize(&old_width, &old_height); 920 GetDrawingSize(&old_width, &old_height);
966 921
967 if (expand) { 922 if (expand) {
968 SetDrawingSize(width + (2 * MAT_SIZE), height + (2 * MAT_SIZE)); 923 SetDrawingSize(width + (2 * MAT_SIZE), height + (2 * MAT_SIZE));
969 BeginFrame(); 924 BeginFrame();
970 DrawTree(TheTree, Old); 925 DrawTree(TheTree, Old);
971 EndFrame(); 926 EndFrame();
972 Pause(); 927 Pause();
973 StatusMsg("Move tree to new configuration", FALSE); 928 StatusMsg("Move tree to new configuration", FALSE);
974 AnimateTree(TheTree); 929 AnimateTree(TheTree);
975 } else { 930 } else {
976 /* we are shrinking or staying the same */ 931 /* we are shrinking or staying the same */
977 StatusMsg("Move tree to new configuration", FALSE); 932 StatusMsg("Move tree to new configuration", FALSE);
980 } 935 }
981 936
982 if (expand) { 937 if (expand) {
983 StatusMsg("Expand subtree", FALSE); 938 StatusMsg("Expand subtree", FALSE);
984 node->elision = FALSE; 939 node->elision = FALSE;
985 940
986 /* erase elision marker */ 941 /* erase elision marker */
987 XSetFunction(TreeDrawingAreaDB->display, TreeDrawingAreaDB->gc, 942 XSetFunction(TreeDrawingAreaDB->display, TreeDrawingAreaDB->gc,
988 GXclear); 943 GXclear);
989 XFillRectangle(XtDisplay(w), XtWindow(w), TreeDrawingAreaDB->gc, 944 XFillRectangle(XtDisplay(w), XtWindow(w), TreeDrawingAreaDB->gc,
990 node->pos.x + node->width - ELISION_WIDTH + 1, 945 node->pos.x + node->width - ELISION_WIDTH + 1,
991 node->pos.y, ELISION_WIDTH, node->height + 1); 946 node->pos.y, ELISION_WIDTH, node->height + 1);
992 XSetFunction(TreeDrawingAreaDB->display, TreeDrawingAreaDB->gc, 947 XSetFunction(TreeDrawingAreaDB->display, TreeDrawingAreaDB->gc,
993 GXcopy); 948 GXcopy);
994 node->width -= ELISION_WIDTH; 949 node->width -= ELISION_WIDTH;
995 950
996 GetSubTreeRectangles(node, &rectangles, &nrectangles, FALSE); 951 GetSubTreeRectangles(node, &rectangles, &nrectangles, FALSE);
997 GetSubTreeSegments(node, &segments, &nsegments); 952 GetSubTreeSegments(node, &segments, &nsegments);
998 /* dissolve the tree back in */ 953 /* dissolve the tree back in */
999 DissolveTree(XtDisplay(w), XtWindow(w), 954 DissolveTree(XtDisplay(w), XtWindow(w),
1000 rectangles, nrectangles, 955 rectangles, nrectangles,
1001 segments, nsegments, FALSE); 956 segments, nsegments, FALSE);
1002 free(rectangles); 957 free(rectangles);
1003 free(segments); 958 free(segments);
1004 959
1005 /* draw text of nodes */ 960 /* draw text of nodes */
1006 BeginFrame(); 961 BeginFrame();
1007 SetContours(TreeShowContourOption); 962 SetContours(TreeShowContourOption);
1008 DrawTree(TheTree, New); 963 DrawTree(TheTree, New);
1009 EndFrame(); 964 EndFrame();
1010 Pause(); 965 Pause();
1011 } 966 }
1012 967
1013 if (TreeShowSteps) { 968 if (TreeShowSteps) {
1014 node->on_path = FALSE; 969 node->on_path = FALSE;
1015 if (node->parent) 970 if (node->parent)
1016 AnimateZip(node->parent); 971 AnimateZip(node->parent);
1017 else 972 else
1018 node->split = FALSE; 973 node->split = FALSE;
1019 } 974 }
1020 975
1021 /* BUG: the display isn't properly updated here! */ 976 /* BUG: the display isn't properly updated here! */
1022 /* There should probably be some code here that 977 /* There should probably be some code here that
1023 clears the tree below the node currently being 978 clears the tree below the node currently being
1024 collapsed or expanded. Hack added 20.03.95 (torgeir@ii.uib.no). 979 collapsed or expanded. Hack added 20.03.95 (torgeir@ii.uib.no).
1025 I'll try to fix this later. */ 980 I'll try to fix this later. */
1026 981
1027 XClearArea(TreeDisplay, XtWindow(TreeDrawingArea), 0, 0, 0, 0, FALSE); 982 XClearArea(TreeDisplay, XtWindow(TreeDrawingArea), 0, 0, 0, 0, FALSE);
1028 983
1029 BeginFrame(); 984 BeginFrame();
1030 SetContours(TreeShowContourOption); 985 SetContours(TreeShowContourOption);
1031 DrawTree(TheTree, New); 986 DrawTree(TheTree, New);
1032 EndFrame(); 987 EndFrame();
1033 988
1034 StatusMsg("Ready", TRUE); 989 StatusMsg("Ready", TRUE);
1035 } 990 }
1036 991
1037 /* ---------------------------------------------------------------------------- 992 /* ----------------------------------------------------------------------------
1038 * 993 *
1039 * InsertNode() handles the task of inserting a new node in the tree, 994 * InsertNode() handles the task of inserting a new node in the tree,
1040 * at the given position with respect to 'base_node'. When 'node_pos' is 995 * at the given position with respect to 'base_node'. When 'node_pos' is
1041 * either Before or After, it is assumed that 'base_node' has a parent. 996 * either Before or After, it is assumed that 'base_node' has a parent.
1042 * 997 *
1043 * ---------------------------------------------------------------------------- 998 * ----------------------------------------------------------------------------
1044 */ 999 */
1045 1000
1046 void 1001 void
1047 InsertNode(base_node, node_pos, new_node_text) 1002 InsertNode(Tree *base_node, NodePosition node_pos, char *new_node_text)
1048 Tree *base_node;
1049 NodePosition node_pos;
1050 char *new_node_text;
1051 { 1003 {
1052 Tree *new_node; 1004 Tree *new_node;
1053 Tree *parent; 1005 Tree *parent;
1054 Tree *sibling = NULL; 1006 Tree *sibling = NULL;
1055 Tree *child; 1007 Tree *child;
1077 FOREACH_CHILD(child, parent) 1029 FOREACH_CHILD(child, parent)
1078 if (child->sibling == base_node) { 1030 if (child->sibling == base_node) {
1079 sibling = child; 1031 sibling = child;
1080 break; 1032 break;
1081 } 1033 }
1034 } else {
1035 parent = NULL;
1036 abort();
1082 } 1037 }
1083 1038
1084 if (TreeShowSteps) 1039 if (TreeShowSteps)
1085 parent->on_path = TRUE; 1040 parent->on_path = TRUE;
1086 1041
1087 if ((TreeShowContourOption != NoContours) || 1042 if ((TreeShowContourOption != NoContours) ||
1088 TreeShowSteps) { 1043 TreeShowSteps) {
1089 BeginFrame(); 1044 BeginFrame();
1090 DrawTree(TheTree, New); 1045 DrawTree(TheTree, New);
1091 EndFrame(); 1046 EndFrame();
1092 } 1047 }
1093 1048
1094 sprintf(strbuf, "Inserting `%s' as child of node `%s'", 1049 sprintf(strbuf, "Inserting `%s' as child of node `%s'",
1095 new_node_text, parent->label.text); 1050 new_node_text, parent->label.text);
1096 StatusMsg(strbuf, FALSE); 1051 StatusMsg(strbuf, FALSE);
1097 Pause(); 1052 Pause();
1098 1053
1099 /* erase the contour before changing in the tree */ 1054 /* erase the contour before changing in the tree */
1100 1055
1101 Insert(parent, new_node, sibling); 1056 Insert(parent, new_node, sibling);
1102 1057
1103 ComputeTreeSize(TheTree, &width, &height, &x_offset, &y_offset); 1058 ComputeTreeSize(TheTree, &width, &height, &x_offset, &y_offset);
1104 PetrifyTree(TheTree, x_offset + MAT_SIZE, y_offset + MAT_SIZE); 1059 PetrifyTree(TheTree, x_offset + MAT_SIZE, y_offset + MAT_SIZE);
1105 1060
1106 if (sibling) 1061 if (sibling)
1107 new_node->old_pos = sibling->old_pos; 1062 new_node->old_pos = sibling->old_pos;
1108 else if (new_node->sibling) 1063 else if (new_node->sibling)
1109 new_node->old_pos = new_node->sibling->old_pos; 1064 new_node->old_pos = new_node->sibling->old_pos;
1110 else { 1065 else {
1111 new_node->old_pos.x = new_node->pos.x; 1066 new_node->old_pos.x = new_node->pos.x;
1112 new_node->old_pos.y = parent->old_pos.y; 1067 new_node->old_pos.y = parent->old_pos.y;
1113 } 1068 }
1114 1069
1115 if (TreeShowSteps) 1070 if (TreeShowSteps)
1116 new_node->split = TRUE; 1071 new_node->split = TRUE;
1117 1072
1118 SetDrawingSize(width + (2 * MAT_SIZE), height + (2 * MAT_SIZE)); 1073 SetDrawingSize(width + (2 * MAT_SIZE), height + (2 * MAT_SIZE));
1119 BeginFrame(); 1074 BeginFrame();
1120 DrawTree(TheTree, Old); 1075 DrawTree(TheTree, Old);
1121 EndFrame(); 1076 EndFrame();
1122 StatusMsg("Insert: add new node and contour", FALSE); 1077 StatusMsg("Insert: add new node and contour", FALSE);
1123 Pause(); 1078 Pause();
1124 1079
1125 StatusMsg("Move tree to new configuration", FALSE); 1080 StatusMsg("Move tree to new configuration", FALSE);
1126 AnimateTree(TheTree); 1081 AnimateTree(TheTree);
1127 1082
1128 if (TreeShowSteps) { 1083 if (TreeShowSteps) {
1129 if (parent) 1084 if (parent)
1134 SetContours(TreeShowContourOption); 1089 SetContours(TreeShowContourOption);
1135 DrawTree(TheTree, New); 1090 DrawTree(TheTree, New);
1136 EndFrame(); 1091 EndFrame();
1137 1092
1138 StatusMsg("Ready", TRUE); 1093 StatusMsg("Ready", TRUE);
1139 } 1094 }
1140 1095
1141 /* ---------------------------------------------------------------------------- 1096 /* ----------------------------------------------------------------------------
1142 * 1097 *
1143 * DeleteNode() handles the task of deleting a given node in the tree. 1098 * DeleteNode() handles the task of deleting a given node in the tree.
1144 * 1099 *
1145 * ---------------------------------------------------------------------------- 1100 * ----------------------------------------------------------------------------
1146 */ 1101 */
1147 1102
1148 void 1103 void
1149 DeleteNode(node) 1104 DeleteNode(Tree *node)
1150 Tree *node;
1151 { 1105 {
1152 Tree *parent; 1106 Tree *parent;
1153 1107
1154 XRectangle *rectangles; 1108 XRectangle *rectangles;
1155 XSegment *segments; 1109 XSegment *segments;
1156 int nrectangles, nsegments; 1110 int nrectangles, nsegments;
1157 Widget w = TreeDrawingArea; 1111 Widget w = TreeDrawingArea;
1158 int width, height; 1112 int width, height;
1159 int x_offset, y_offset; 1113 int x_offset, y_offset;
1160 1114
1161 StatusMsg("", TRUE); 1115 StatusMsg("", TRUE);
1162 1116
1163 if (TreeShowSteps) 1117 if (TreeShowSteps)
1164 node->on_path = TRUE; 1118 node->on_path = TRUE;
1165 1119
1166 /* erase the contour before changing in the tree */ 1120 /* erase the contour before changing in the tree */
1167 if ((TreeShowContourOption != NoContours) || 1121 if ((TreeShowContourOption != NoContours) ||
1168 TreeShowSteps) { 1122 TreeShowSteps) {
1169 BeginFrame(); 1123 BeginFrame();
1170 DrawTree(TheTree, New); 1124 DrawTree(TheTree, New);
1171 EndFrame(); 1125 EndFrame();
1172 } 1126 }
1173 1127
1174 sprintf(strbuf, "Node `%s' selected for deletion", node->label.text); 1128 sprintf(strbuf, "Node `%s' selected for deletion", node->label.text);
1175 StatusMsg(strbuf, FALSE); 1129 StatusMsg(strbuf, FALSE);
1176 Pause(); 1130 Pause();
1177 1131
1178 parent = node->parent; 1132 parent = node->parent;
1179 1133
1180 if (parent) 1134 if (parent)
1181 Unzip(parent); 1135 Unzip(parent);
1182 else 1136 else
1183 TheTree = NULL; /* delete root of tree */ 1137 TheTree = NULL; /* delete root of tree */
1184 1138
1193 free(segments); 1147 free(segments);
1194 1148
1195 Delete(node); 1149 Delete(node);
1196 1150
1197 BeginFrame(); 1151 BeginFrame();
1198 if (TheTree) 1152 if (TheTree)
1199 DrawTree(TheTree, New); 1153 DrawTree(TheTree, New);
1200 EndFrame(); 1154 EndFrame();
1201 Pause(); 1155 Pause();
1202 1156
1203 if (parent) 1157 if (parent)
1204 Zip(parent); 1158 Zip(parent);
1205 1159
1206 if (TheTree) { 1160 if (TheTree) {
1207 ComputeTreeSize(TheTree, &width, &height, &x_offset, &y_offset); 1161 ComputeTreeSize(TheTree, &width, &height, &x_offset, &y_offset);
1208 PetrifyTree(TheTree, x_offset + MAT_SIZE, y_offset + MAT_SIZE); 1162 PetrifyTree(TheTree, x_offset + MAT_SIZE, y_offset + MAT_SIZE);
1209 StatusMsg("Move tree to new configuration", FALSE); 1163 StatusMsg("Move tree to new configuration", FALSE);
1210 AnimateTree(TheTree); 1164 AnimateTree(TheTree);
1211 SetDrawingSize(width + (2 * MAT_SIZE), height + (2 * MAT_SIZE)); 1165 SetDrawingSize(width + (2 * MAT_SIZE), height + (2 * MAT_SIZE));
1212 Pause(); 1166 Pause();
1213 1167
1214 if (TreeShowSteps) { 1168 if (TreeShowSteps) {
1215 if (parent) 1169 if (parent)
1216 AnimateZip(parent); 1170 AnimateZip(parent);
1217 } 1171 }
1226 StatusMsg("Ready", TRUE); 1180 StatusMsg("Ready", TRUE);
1227 } 1181 }
1228 1182
1229 1183
1230 /* ---------------------------------------------------------------------------- 1184 /* ----------------------------------------------------------------------------
1231 * 1185 *
1232 * ResetLabels() is called when the TreeAlignNodes mode is changed. 1186 * ResetLabels() is called when the TreeAlignNodes mode is changed.
1233 * When TreeParentDistance changes, the node width changes, so this 1187 * When TreeParentDistance changes, the node width changes, so this
1234 * function forces each node's width to be recomputed. 1188 * function forces each node's width to be recomputed.
1235 * 1189 *
1236 * ---------------------------------------------------------------------------- 1190 * ----------------------------------------------------------------------------
1237 */ 1191 */
1238 1192
1239 ResetLabels(tree) 1193 void
1240 Tree *tree; 1194 ResetLabels(Tree *tree)
1241 { 1195 {
1242 Tree *child; 1196 Tree *child;
1243 1197
1244 SetNodeLabel(tree, tree->label.text); 1198 SetNodeLabel(tree, tree->label.text);
1245 FOREACH_CHILD(child, tree) 1199 FOREACH_CHILD(child, tree)
1246 ResetLabels(child); 1200 ResetLabels(child);
1247 } 1201 }
1248 1202
1249 1203
1250 /* ---------------------------------------------------------------------------- 1204 /* ----------------------------------------------------------------------------
1251 * 1205 *
1252 * SetupTree() handles the task of setting up the specified tree in 1206 * SetupTree() handles the task of setting up the specified tree in
1253 * the drawing area. 1207 * the drawing area.
1254 * 1208 *
1255 * ---------------------------------------------------------------------------- 1209 * ----------------------------------------------------------------------------
1256 */ 1210 */
1257 1211
1258 void 1212 void
1259 SetupTree(tree) 1213 SetupTree(Tree *tree)
1260 Tree *tree;
1261 { 1214 {
1262 int width, height; 1215 int width, height;
1263 int x_offset, y_offset; 1216 int x_offset, y_offset;
1264 1217
1265 LayoutTree(tree); 1218 LayoutTree(tree);
1266 ComputeTreeSize(tree, &width, &height, &x_offset, &y_offset); 1219 ComputeTreeSize(tree, &width, &height, &x_offset, &y_offset);
1267 PetrifyTree(tree, x_offset + MAT_SIZE, y_offset + MAT_SIZE); 1220 PetrifyTree(tree, x_offset + MAT_SIZE, y_offset + MAT_SIZE);
1268 SetDrawingTree(tree); 1221 SetDrawingTree(tree);
1269 SetDrawingSize(width + (2 * MAT_SIZE), height + (2 * MAT_SIZE)); 1222 SetDrawingSize(width + (2 * MAT_SIZE), height + (2 * MAT_SIZE));
1270 BeginFrame(); 1223 BeginFrame();
1271 SetContours(TreeShowContourOption); 1224 SetContours(TreeShowContourOption);
1272 DrawTree(tree, New); 1225 DrawTree(tree, New);
1273 EndFrame(); 1226 EndFrame();
1274 } 1227 }
1275
1276
1277
1278
1279
1280