OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [libgui/] [src/] [tkCanvLayout.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * Copyright (c) 1993 by Sven Delmas
3
 * All rights reserved.
4
 * See the file COPYRIGHT for the copyright notes.
5
 *
6
 */
7
 
8
/* renamed from layout.c to tkCanvLayout.c by Will Taylor 09nov95 */
9
/* converted to Tk4.1 by Will Taylor 05may96 */
10
 
11
#ifdef HAVE_CONFIG_H
12
#include <config.h>
13
#endif
14
#ifdef HAVE_UNISTD_H
15
#include <unistd.h>
16
#endif
17
 
18
#include <stdio.h>
19
#include <stdlib.h>
20
#include <time.h>
21
#include <string.h>
22
#include <tcl.h>
23
#include "tkCanvLayout.h"
24
 
25
#if defined (__MSVC__) && ! defined (HAVE_RAND)
26
#define HAVE_RAND
27
#endif
28
 
29
/*
30
 * Functions to compute random numbers.  These don't have to be
31
 * particular good random number generators.
32
 */
33
#ifdef HAVE_RANDOM
34
#define RANDOM random ()
35
#define SRANDOM srandom
36
#else /* HAVE_RANDOM */
37
#ifdef HAVE_DRAND48
38
#define MY_RAND_MAX 65536
39
#define RANDOM ((long) (drand48 () * MY_RAND_MAX))
40
#define SRANDOM srand48
41
#else /* HAVE_DRAND48 */
42
#ifdef HAVE_RAND
43
#define RANDOM rand ()
44
#define SRANDOM srand
45
#else
46
#warning no random number generator specified, default: random, srandom
47
#define HAVE_RANDOM
48
#define RANDOM random ()
49
#define SRANDOM srandom
50
#endif /* HAVE_RAND */
51
#endif /* HAVE_DRAND48 */
52
#endif /* HAVE_RANDOM */
53
 
54
#define LAYOUT_OK TCL_OK
55
#define LAYOUT_ERROR TCL_ERROR
56
 
57
/*
58
 * This value is added to the line length in pixels, so the distance
59
 * between two nodes can be calculated correctly.
60
 */
61
#define LINE_INCREMENT 10
62
 
63
/*
64
 * Turn on/off debugging.
65
 */
66
#define DEBUGGING 1
67
#define DEBUG_LAYOUT 0
68
#define DEBUG_PLACE 0
69
#define TESTING 0
70
 
71
/*
72
 * the datastructures used for layouting.
73
 */
74
 
75
/*
76
 * these datas/variables are used by the tree layouter.
77
 */
78
 
79
struct TreeData {
80
  double tmpX;                        /* A temporary x position. */
81
  double tmpY;                        /* A temporary y position. */
82
};
83
typedef struct TreeData TreeData;
84
 
85
#define TREE_TMP_X_POS(node)           (node)->treeData.tmpX
86
#define SET_TREE_TMP_X_POS(node,pos)   (node)->treeData.tmpX = (pos)
87
#define TREE_TMP_Y_POS(node)           (node)->treeData.tmpY
88
#define SET_TREE_TMP_Y_POS(node,pos)   (node)->treeData.tmpY = (pos)
89
 
90
#if DEBUGGING
91
#define DEBUG_PRINT_TREE_NODE_POS(node, s) TkCanvLayoutDebugging(node, s, 1)
92
#else
93
#define DEBUG_PRINT_TREE_NODE_POS(node, s)
94
#endif
95
 
96
 
97
/*
98
 * A topologically ordered node. stored in the global array toplist
99
 * (0 to toplistnum).
100
 */
101
struct Topology {
102
  struct Nodes *nodePtr;
103
};
104
typedef struct Topology Topology;
105
 
106
/*
107
Define edge information
108
*/
109
 
110
struct Edge {
111
        pItem edgeid;           /* edge identifier */
112
        ItemGeom info;
113
        struct Nodes* fromNode; /* A pointer to the ``from'' node struct. */
114
        struct Nodes* toNode;   /* A pointer to the ``to'' node struct. */
115
        int ignore;             /* Ignore this edge. */
116
        int visited;    /* This edge was visited. */
117
};
118
typedef struct Edge Edge;
119
 
120
/*
121
 * A graph node. stored in a global array named nodes
122
 * (0 to nodenum).
123
 */
124
struct Nodes {
125
  pItem itemPtr;        /* Pointer to the Node dual. */
126
  ItemGeom info;        /* bounding box of the dual */
127
  int ignore;           /* Ignore this node. */
128
  int visited;          /* This node was already */
129
                        /* visited/layouted. */
130
  double x;             /* The calculated x position. */
131
  double y;             /* The calculated y position. */
132
  int parentNum;        /* The number of parent nodes. */
133
  Edge** parent;        /* The array of parent nodes. */
134
  int succNum;          /* The number of successor nodes. */
135
  Edge** succ;          /* The array of successor nodes. */
136
  struct TreeData treeData; /* temporary tree layout nodes */
137
#if 0
138
  char *data;           /* Special data attached to */
139
                        /* this node. The contents */
140
                        /* depend from the layouting */
141
                        /* algorithms. */
142
#endif
143
};
144
typedef struct Nodes Nodes;
145
typedef struct Nodes Node;
146
 
147
/*
148
 * Defines that hide internal functionality.
149
 */
150
 
151
/*
152
 * Get and set the edge ignore flag. Edges which are ignored will not
153
 * be traversed. The first parameter is the edge, and the second
154
 * parameter (if you call the setting) is the new value of the
155
 * ignore flag.
156
 */
157
#define IGNORE_EDGE(edge)             (edge)->ignore
158
#define SET_IGNORE_EDGE(edge,mode)    (edge)->ignore=mode
159
 
160
/*
161
 * Get and set the edge visited flag. This flag is usually set to true
162
 * when the edge was visited. The first parameter is the edge, and the
163
 * second parameter (if you call the setting) is the new value of the
164
 * visited flag.
165
 */
166
#define VISITED_EDGE(edge)            (edge)->visited
167
#define SET_VISITED_EDGE(edge,mode)   (edge)->visited=mode
168
 
169
/*
170
 * Get and set the node ignore flag. Nodes which are ignored will not
171
 * be traversed, and they are not placed/layouted. The first parameter
172
 * is the node, and the second parameter (if you call the setting) is
173
 * the new value of the ignore flag.
174
 */
175
#define IGNORE_NODE(node)             (node)->ignore
176
#define SET_IGNORE_NODE(node,mode)    (node)->ignore=mode
177
#define RESET_IGNORE_NODE(i)          for (i = 0; i < THIS(nodeNum); i++) nodes[i]->ignore=0;
178
 
179
/*
180
 * Get and set the node visited flag. This flag is usually set to true
181
 * when the node was visited. Currently this flag is mainly used for the
182
 * topological sorting. The first parameter is the node, and the
183
 * second parameter (if you call the setting) is the new value of the
184
 * visited flag.
185
 */
186
#define VISITED_NODE(node)            (node)->visited
187
#define SET_VISITED_NODE(node,mode)   (node)->visited=mode
188
#define RESET_VISITED_NODE(i)         for (i = 0; i < THIS(nodeNum); i++) THIS(nodes)[i]->visited=0;
189
 
190
/*
191
 * Get and set the number of parent nodes. The first parameter is the
192
 * node, and the second parameter (if you call the setting) is the new
193
 * number of parents.
194
 */
195
#define PARENT_NUM(node)              (node)->parentNum
196
#define SET_PARENT_NUM(node,num)      (node)->parentNum=num
197
 
198
/*
199
 * Get and set the number of successor nodes. The first parameter is
200
 * the node, and the second parameter (if you call the setting) is the
201
 * new number of successors.
202
 */
203
#define SUCC_NUM(node)                (node)->succNum
204
#define SET_SUCC_NUM(node,num)        (node)->succNum=num
205
 
206
/*
207
 * Get and set the node item. This item is the corresponding dual
208
 * item for this node. The first parameter is the node, and the second
209
 * parameter (if you call the setting) is the new dual item pointer.
210
 */
211
#define NODE_ITEM(node)               (node)->itemPtr
212
#define SET_NODE_ITEM(node,item)      (node)->itemPtr=item
213
 
214
/* Get and set the node x1,x2,y1, and y2 positions. */
215
#define NODE_X1_POS(node)              (node)->info.x1
216
#define NODE_Y1_POS(node)              (node)->info.y1
217
#define NODE_X2_POS(node)              (node)->info.x2
218
#define NODE_Y2_POS(node)              (node)->info.y2
219
 
220
#define SET_NODE_X1_POS(node,v)              (node)->info.x1 = (v)
221
#define SET_NODE_Y1_POS(node,v)              (node)->info.y1 = (v)
222
#define SET_NODE_X2_POS(node,v)              (node)->info.x2 = (v)
223
#define SET_NODE_Y2_POS(node,v)              (node)->info.y2 = (v)
224
 
225
/* Get, by calculation, the node's width and height */
226
#define CALC_NODE_HEIGHT(n)         (NODE_Y2_POS(n) - NODE_Y1_POS(n))
227
#define CALC_NODE_WIDTH(n)         (NODE_X2_POS(n) - NODE_X1_POS(n))
228
 
229
/* Get/Set the node dual geom */
230
#define NODE_GEOM(node)              (node)->info
231
#define SET_NODE_GEOM(node,inf)      (node)->info = (inf)
232
 
233
/*
234
 * Get and set the node x position. This is the value for the final
235
 * placing of the node. The first parameter is the node, and the
236
 * second parameter (if you call the setting) is the new x position.
237
 */
238
#define NODE_X_POS(node)              (node)->x
239
#define SET_NODE_X_POS(node,pos)      (node)->x=pos
240
 
241
/*
242
 * Get and set the node y position. This is the value for the final
243
 * placing of the node. The first parameter is the node, and the
244
 * second parameter (if you call the setting) is the new y position.
245
 */
246
#define NODE_Y_POS(node)              (node)->y
247
#define SET_NODE_Y_POS(node,pos)      (node)->y=pos
248
 
249
/*
250
 * Get and set the nodes width. The parameter specifies the node
251
 * whose width and height will be returned.
252
 */
253
#define NODE_WIDTH(node)              (node)->info.width
254
#define SET_NODE_WIDTH(node,size)     (node)->info.width=size
255
 
256
/*
257
 * Get and set the nodes height. The parameter specifies the node
258
 * whose width and height will be returned.
259
 */
260
#define NODE_HEIGHT(node)             (node)->info.height
261
#define SET_NODE_HEIGHT(node,size)    (node)->info.height=size
262
 
263
#define EDGE_ITEM(edge)               (edge)->edgeid
264
#define SET_EDGE_ITEM(edge,item)      (edge)->edgeid=item
265
 
266
/*
267
 * Return the parent/successor edge/node for the specified node. The
268
 * second parameter is a integer counter that is used as index for the
269
 * parent/successor array. Usually this index is generated by a
270
 * FOR_ALL_* macro.
271
 */
272
#define PARENT_EDGE(node, i)          (node)->parent[i]
273
#define PARENT_NODE(node, i)          (node)->parent[i]->fromNode
274
#define PARENT_ID(node, i)            (node)->parent[i]->edgeid
275
#define SUCC_EDGE(node, i)            (node)->succ[i]
276
#define SUCC_NODE(node, i)            (node)->succ[i]->toNode
277
#define SUCC_ID(node, i)              (node)->succ[i]->edgeid
278
#define DUMMY_NODE(node)              ((node)->itemPtr == (pItem) NULL)
279
 
280
/* Get and set the edge x1,x2,y1, and y2 positions. */
281
#define EDGE_X1_POS(edge)              (edge)->info.x1
282
#define EDGE_X2_POS(edge)              (edge)->info.x2
283
#define EDGE_Y1_POS(edge)              (edge)->info.y1
284
#define EDGE_Y2_POS(edge)              (edge)->info.y2
285
 
286
/* Get/Set the edge dual geom */
287
#define EDGE_GEOM(edge)              (edge)->info
288
#define SET_EDGE_GEOM(edge,inf)      (edge)->info = inf
289
 
290
/*
291
 * Return the node specified by the integer counter passed to this
292
 * macro. The nodes in the array are topologically ordered (beginning
293
 * with the index 0. The index is usually created by the macro
294
 * FOR_ALL_TOP_NODES.
295
 */
296
#define TOP_NODE(i)                   THIS(topList)[i]->nodePtr
297
 
298
/*
299
 * Walk through all nodes that are currently defined. The only
300
 * parameter is the integer counter that is used to index the array.
301
 */
302
#define FOR_ALL_NODES(i)              for (i = 0; i < THIS(nodeNum); i++)
303
 
304
/*
305
 * Walk through all edges that are currently defined. The only
306
 * parameter is the integer counter that is used to index the array.
307
 */
308
#define FOR_ALL_EDGES(i)              for (i = 0; i < THIS(edgeNum); i++)
309
 
310
/*
311
 * Walk through all parents/successors of the specified node. The
312
 * second parameter is the integer counter that is used to index the
313
 * array.
314
 */
315
#define FOR_ALL_PARENTS(node, i)      for (i = 0; i < (node)->parentNum; i++)
316
#define FOR_ALL_SUCCS(node, i)        for (i = 0; i < (node)->succNum; i++)
317
 
318
/*
319
 * Walk through all nodes in topological order. The only parameter is
320
 * the integer counter that is used to index the array. This call
321
 * requires a call of the topological order function, before it can be
322
 * used.
323
 */
324
#define FOR_ALL_TOP_NODES(i)          for (i = 0; i < THIS(topListNum); i++)
325
 
326
/*
327
 * DEBUGGING MACROS.
328
 */
329
#if DEBUGGING
330
#define DEBUG_PRINT_NODE_POS(GRAPH, NODE, S) LayoutDebugging(GRAPH, NODE, S, 0)
331
#define DEBUG_PRINT_STRING(S1, S2)    fprintf(stderr, "%s %s<\n", S2, S1);
332
#else
333
#define DEBUG_PRINT_NODE_POS(GRAPH, NODE, S)
334
#define DEBUG_PRINT_STRING(S1, S2)
335
#endif
336
 
337
 
338
#define THIS(x) This->x
339
 
340
struct Layout_Graph {
341
        /* Start with user settable configuration items */
342
        long iconSpaceV;                /* The vertical space between icons. */
343
        long iconSpaceH;                /*The horizontal space between icons.*/
344
        int graphOrder;                 /* Ordering... 0 = LR, 1 = TD. */
345
        Node *rootNode;                 /* The root node. */
346
        long xOffset;                   /* The x offset for the placing. */
347
        long yOffset;                   /* The y offset for the placing. */
348
 
349
        /*
350
         * These datas/variables are used by the random layouter.
351
         */
352
        int keepRandomPositions;        /* Don't change the position of */
353
                                        /* already placed icons when */
354
                                        /* layouting with the random */
355
                                        /* placer. */
356
        long maxX, maxY;                /* Maximal X and Y coordinates */
357
                                        /* for the random placer. */
358
        /*
359
         * Misc. variables used for layouting.
360
         */
361
 
362
        int nodeNum;                    /* The number of graph nodes. */
363
        Node** nodes;                   /* The list of graph nodes. */
364
        int edgeNum;                    /* The number of graph edges. */
365
        Edge** edges;                   /* The list of graph edges. */
366
        int topListNum;                 /* The current node number. */
367
        Topology **topList;             /* The sorted nodes. */
368
        int computeiconsize;            /* Use the biggest icon size. */
369
        int elementsPerLine;            /* How many elements per line. */
370
        int hideEdges;                  /* make edges zero length (Matrix)*/
371
        int edgeHeight;                 /* The standard height of an edge. */
372
        int edgeOrder;                  /* Set the edges to the layout order.*/
373
        int edgeWidth;                  /* The standard width of an edge. */
374
        int iconHeight, iconWidth;      /* The standard icon size. */
375
        double posX1, posY1, posX2, posY2;      /* Coordinates */
376
        double maxXPosition;            /* Maximal X and Y coordinates */
377
        double maxYPosition;            /* for the random placer. */
378
        int layoutTypesNum;             /* The number of layout types. */
379
        char **layoutTypes;             /* The types of items that will
380
                                           be layouted. */
381
        int gridlock;                   /* avoid using diagnal lines */
382
        char* errmsg;
383
 
384
#ifdef ignore
385
        char* graphName
386
        char *idlist;                   /* The list of ids to layout. */
387
        char *sortcommand;              /* The Tcl procedure called for */
388
        long rootId;
389
        char convertBuffer[100];        /* Convert numbers to strings.*/
390
#endif
391
};
392
 
393
typedef struct Layout_Graph Layout_Graph;
394
 
395
static  int deleteedge _ANSI_ARGS_((Layout_Graph*,Edge*,int));
396
static  int deletenode _ANSI_ARGS_((Layout_Graph*,Node*,int));
397
static  void compress_succ _ANSI_ARGS_((Layout_Graph*,Node*));
398
static  void compress_parent _ANSI_ARGS_((Layout_Graph*,Node*));
399
 
400
static  void LayoutISISetX _ANSI_ARGS_((Layout_Graph*, Node*));
401
static  void LayoutISISetY _ANSI_ARGS_((Layout_Graph*, Node*/*, int type*/));
402
static  void LayoutTreeSetX _ANSI_ARGS_((Layout_Graph*, Node*));
403
static  void LayoutTreeSetY _ANSI_ARGS_((Layout_Graph*, Node*));
404
static  int LayoutBuildGraph _ANSI_ARGS_((Layout_Graph*));
405
static  Node* LayoutGraphRoot _ANSI_ARGS_((Layout_Graph*));
406
static  void LayoutGraphSortTopological _ANSI_ARGS_((Layout_Graph*, Node*));
407
static  int LayoutGraphPlaceNodes _ANSI_ARGS_((Layout_Graph*));
408
static  int LayoutGraphPlaceEdges _ANSI_ARGS_((Layout_Graph*));
409
static  int LayoutEdgeWidth _ANSI_ARGS_((Layout_Graph*));
410
static  int LayoutEdge _ANSI_ARGS_((Layout_Graph*, Edge*, Node*, Node*));
411
 
412
#if(defined(__cplusplus) || defined(c_plusplus))
413
#define AC1(t1,a1) (t1 a1)
414
#define AC2(t1,a1,t2,a2) (t1 a1, t2 a2)
415
#define AC3(t1,a1,t2,a2,t3,a3) (t1 a1, t2 a2, t3 a3)
416
#define AC4(t1,a1,t2,a2,t3,a3,t4,a4) (t1 a1, t2 a2, t3 a3, t4 a4)
417
#define AC5(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5) (t1 a1, t2 a2, t3 a3, t4 a4, t5 a5)
418
#else
419
#define AC1(t1,a1) (a1) t1 a1;
420
#define AC2(t1,a1,t2,a2) (a1,a2) t1 a1; t2 a2;
421
#define AC3(t1,a1,t2,a2,t3,a3) (a1,a2,a3) t1 a1; t2 a2; t3 a3;
422
#define AC4(t1,a1,t2,a2,t3,a3,t4,a4) (a1,a2,a3,a4) t1 a1; t2 a2; t3 a3; t4 a4;
423
#define AC5(t1,a1,t2,a2,t3,a3,t4,a4,t5,a5) (a1,a2,a3,a4,a5) t1 a1; t2 a2; t3 a3; t4 a4; t5 a5;
424
#endif
425
 
426
static
427
void
428
MY_LayoutISISetY _ANSI_ARGS_((Layout_Graph*, Node*, double));
429
 
430
 
431
 
432
/*
433
 *--------------------------------------------------------------
434
 *
435
 * LayoutDebugging --
436
 *
437
 *      This procedure is invoked to print debugging informations.
438
 *
439
 * Results:
440
 *      None
441
 *
442
 * Side effects:
443
 *      See the user documentation.
444
 *
445
 *--------------------------------------------------------------
446
 */
447
 
448
#if DEBUGGING
449
void
450
LayoutDebugging(
451
     Layout_Graph* This,
452
     Node *currentNode,                /* This is the current node. */
453
     char *string,
454
     int type)
455
{
456
  double tmpX, tmpY;
457
 
458
  if(THIS(graphOrder)) {
459
    /* Place nodes top down. */
460
    tmpX = THIS(xOffset) - NODE_HEIGHT(THIS(rootNode));
461
    tmpY = THIS(yOffset) - NODE_WIDTH(THIS(rootNode));
462
  } else {
463
    /* Place nodes left to right. */
464
    tmpX = THIS(xOffset) - NODE_WIDTH(THIS(rootNode));
465
    tmpY = THIS(yOffset) - NODE_HEIGHT(THIS(rootNode));
466
  }
467
 
468
  if(!DUMMY_NODE(currentNode)) {
469
    fprintf(stderr, "%-6s Node %-3ld: x=%-g y=%-g x=%-g y=%-g\n",
470
            /* string, CANVAS_ITEM_ID(NODE_ITEM(currentNode)), 08nov95 wmt */
471
            string, 0L,
472
            NODE_X_POS(currentNode) + tmpX,
473
            NODE_Y_POS(currentNode) + tmpY,
474
            NODE_X_POS(currentNode),
475
            NODE_Y_POS(currentNode));
476
  } else {
477
    fprintf(stderr, "%-6s Node dummy: x=%-g y=%-g x=%-g y=%-g\n",
478
            string, NODE_X_POS(currentNode) + tmpX,
479
            NODE_Y_POS(currentNode) + tmpY,
480
            NODE_X_POS(currentNode),
481
            NODE_Y_POS(currentNode));
482
  }
483
  switch (type) {
484
  case 1:
485
    fprintf(stderr,
486
            "                 x=%-g y=%-g x=%-g y=%-g\n",
487
            TREE_TMP_X_POS(currentNode) + tmpX,
488
            TREE_TMP_Y_POS(currentNode) + tmpY,
489
            TREE_TMP_X_POS(currentNode),
490
            TREE_TMP_Y_POS(currentNode));
491
    break;
492
  default:
493
    break;
494
  }
495
}
496
#endif
497
 
498
/*
499
 *--------------------------------------------------------------
500
 *
501
 * LayoutISISetX --
502
 *
503
 *      This procedure is invoked to calculate the x ISI position.
504
 *
505
 * Results:
506
 *      None
507
 *
508
 * Side effects:
509
 *      See the user documentation.
510
 *
511
 *--------------------------------------------------------------
512
 */
513
#ifndef max
514
#define max(a,b) ((a) > (b) ? (a) : (b))
515
#define min(a,b) ((a) > (b) ? (b) : (a))
516
#endif
517
static
518
void
519
LayoutISISetX AC2(Layout_Graph*,This, Node*,currentNode) /* This is the current node. */
520
{
521
  int counter, visitedAllChilds = 1;
522
 
523
  if(IGNORE_NODE(currentNode)) {
524
    return;
525
  }
526
  if(VISITED_NODE(currentNode)) {
527
    return;
528
  }
529
 
530
  FOR_ALL_SUCCS(currentNode, counter) {
531
    /* Are there un layouted children ? */
532
    if(IGNORE_EDGE(SUCC_EDGE(currentNode, counter))) {
533
      continue;
534
    }
535
    if(IGNORE_NODE(SUCC_NODE(currentNode, counter))) {
536
      continue;
537
    }
538
    if(!VISITED_NODE(SUCC_NODE(currentNode, counter))) {
539
      visitedAllChilds = 0;
540
    }
541
  }
542
 
543
/*  SET_VISITED_NODE(currentNode, 1);*/
544
  if(!visitedAllChilds) {
545
    FOR_ALL_SUCCS(currentNode, counter) {
546
      /* Layout the children of this node. */
547
      if(IGNORE_EDGE(SUCC_EDGE(currentNode, counter))) {
548
        continue;
549
      }
550
      if(IGNORE_NODE(SUCC_NODE(currentNode, counter))) {
551
        continue;
552
      }
553
      if(!VISITED_NODE(SUCC_NODE(currentNode, counter))) {
554
        LayoutISISetX(This,SUCC_NODE(currentNode, counter));
555
      }
556
    }
557
    if(SUCC_NUM(currentNode) == 1) {
558
      SET_NODE_X_POS(currentNode,
559
                     NODE_X_POS(SUCC_NODE(currentNode, 0)));
560
    }
561
    else
562
    {
563
 
564
      /* Khamis 8:30 23 Oct 1996 */
565
        int i, pingo = 0;
566
        double x1 = 0.0, x2 = 0.0;
567
        FOR_ALL_SUCCS (currentNode, i)
568
        {
569
           if(IGNORE_NODE(SUCC_NODE(currentNode, i)))
570
             continue;
571
           /*
572
           if(! VISITED_NODE(SUCC_NODE(currentNode, i)))
573
                continue;
574
            */
575
           if (PARENT_NODE(SUCC_NODE(currentNode, i), 0) !=
576
                        currentNode)
577
             continue;
578
           if (! pingo)
579
           {
580
             x1 = NODE_X_POS(SUCC_NODE(currentNode, i));
581
             pingo = 1;
582
           }
583
           x1 = min (x1, NODE_X_POS(SUCC_NODE(currentNode, i)));
584
           x2 = max (x2, NODE_X_POS(SUCC_NODE(currentNode, i)));
585
        }
586
        if (! pingo)
587
        {
588
          x1 = x2 = NODE_X_POS (SUCC_NODE(currentNode, 0));
589
        }
590
 
591
#if 1   /* Khamis 8:30 23 Oct 1996 */
592
        SET_NODE_X_POS(currentNode, x1 + (x2 - x1) / 2.0);
593
#else   /* original */
594
        SET_NODE_X_POS(currentNode,
595
                     NODE_X_POS(SUCC_NODE(currentNode, 0)) +
596
                     ((NODE_X_POS(SUCC_NODE(currentNode,
597
                                           SUCC_NUM(currentNode)-1)) -
598
                       NODE_X_POS(SUCC_NODE(currentNode, 0))) / 2));
599
#endif
600
    }
601
  }
602
  else
603
  {
604
    /* Set the x position of the current node. */
605
    if(THIS(graphOrder)) {
606
      /* Place nodes top down. */
607
      SET_NODE_X_POS(currentNode, THIS(maxXPosition));
608
      THIS(maxXPosition) = NODE_X_POS(currentNode) + THIS(iconSpaceH) +
609
        THIS(edgeWidth) + NODE_WIDTH(currentNode);
610
    } else {
611
      /* Place nodes left to right. */
612
      SET_NODE_X_POS(currentNode, THIS(maxXPosition));
613
      THIS(maxXPosition) = NODE_X_POS(currentNode) + THIS(iconSpaceV) +
614
        THIS(edgeHeight) + NODE_HEIGHT(currentNode);
615
    }
616
  }
617
  SET_VISITED_NODE(currentNode, 1);
618
}
619
 
620
/*
621
 *--------------------------------------------------------------
622
 *
623
 * LayoutISISetY --
624
 *
625
 *      This procedure is invoked to calculate the y ISI position.
626
 *
627
 * Results:
628
 *      None
629
 *
630
 * Side effects:
631
 *      See the user documentation.
632
 *
633
 *--------------------------------------------------------------
634
 */
635
 
636
    /* ARGSUSED */
637
static
638
void
639
LayoutISISetY AC2(Layout_Graph*,This, Node*,currentNode) /* This is the current node. */
640
{
641
  int counter;
642
  double tmpMaxY;
643
 
644
  /* Was this node already layouted ? */
645
  if(IGNORE_NODE(currentNode)) {
646
    return;
647
  }
648
  if(VISITED_NODE(currentNode)) {
649
    return;
650
  }
651
 
652
  SET_VISITED_NODE(currentNode, 1);
653
 
654
  if(PARENT_NUM(currentNode) != 0) {
655
    FOR_ALL_PARENTS(currentNode, counter) {
656
      /* Are there un layouted parents ? */
657
      if(IGNORE_EDGE(PARENT_EDGE(currentNode, counter))) {
658
        /*continue;*/
659
        break;
660
      }
661
      if(IGNORE_NODE(PARENT_NODE(currentNode, counter))) {
662
        /*continue;*/
663
        break;
664
      }
665
      if(!VISITED_NODE(PARENT_NODE(currentNode, counter))) {
666
        LayoutISISetY(This,PARENT_NODE(currentNode, counter));
667
      }
668
      break;
669
    }
670
    tmpMaxY = 0;
671
    FOR_ALL_PARENTS(currentNode, counter) {
672
      if(THIS(graphOrder)) {
673
        if(NODE_Y_POS(PARENT_NODE(currentNode, counter)) +
674
            NODE_HEIGHT(PARENT_NODE(currentNode, counter)) > tmpMaxY) {
675
          tmpMaxY = NODE_Y_POS(PARENT_NODE(currentNode, counter)) +
676
            NODE_HEIGHT(PARENT_NODE(currentNode, counter));
677
        }
678
      } else {
679
        if(NODE_Y_POS(PARENT_NODE(currentNode, counter)) +
680
            NODE_WIDTH
681
            (PARENT_NODE(currentNode, counter)) > tmpMaxY) {
682
          tmpMaxY = NODE_Y_POS(PARENT_NODE(currentNode, counter)) +
683
            NODE_WIDTH(PARENT_NODE(currentNode, counter));
684
        }
685
      }
686
      break;
687
    }
688
    if(THIS(graphOrder)) {
689
      /* Place nodes top down. */
690
      SET_NODE_Y_POS(currentNode, tmpMaxY + THIS(edgeHeight) + THIS(iconSpaceV));
691
    } else {
692
      /* Place nodes left to right. */
693
      SET_NODE_Y_POS(currentNode, tmpMaxY + THIS(edgeWidth) + THIS(iconSpaceH));
694
    }
695
  } else {
696
    if(THIS(graphOrder)) {
697
      /* Place nodes top down. */
698
      SET_NODE_Y_POS(currentNode, 0);
699
    } else {
700
      /* Place nodes left to right. */
701
      SET_NODE_Y_POS(currentNode, 0);
702
    }
703
  }
704
 
705
  /*SET_VISITED_NODE(currentNode, 1);*/
706
}
707
 
708
/*********************************************************/
709
static
710
void
711
MY_LayoutISISetY AC3(Layout_Graph*,This, Node*,currentNode, double, y)
712
{
713
  int counter;
714
  double tmpMaxY;
715
 
716
  /* Was this node already layouted ? */
717
  if(IGNORE_NODE(currentNode)) {
718
    return;
719
  }
720
  if(VISITED_NODE(currentNode)) {
721
    return;
722
  }
723
 
724
  SET_VISITED_NODE(currentNode, 1);
725
 
726
  SET_NODE_Y_POS(currentNode, y);
727
 
728
  FOR_ALL_SUCCS (currentNode, counter) {
729
      /* Are there un layouted parents ? */
730
      if(IGNORE_EDGE(PARENT_EDGE(currentNode, counter))) {
731
        /*continue;*/
732
        break;
733
      }
734
      if(IGNORE_NODE(PARENT_NODE(currentNode, counter))) {
735
        /*continue;*/
736
        break;
737
      }
738
 
739
      if (PARENT_NODE(SUCC_NODE(currentNode, counter), 0) !=
740
          currentNode)
741
        continue;
742
 
743
      if(THIS(graphOrder)) {
744
        tmpMaxY = NODE_Y_POS  (currentNode) + NODE_HEIGHT (currentNode);
745
                /*+ THIS(edgeHeight) + THIS(iconSpaceV); */
746
      } else {
747
        tmpMaxY = NODE_Y_POS(currentNode) +
748
                  NODE_WIDTH(currentNode) +
749
                  THIS(edgeWidth) + THIS(iconSpaceH);
750
      }
751
 
752
      MY_LayoutISISetY(This, PARENT_NODE(currentNode, counter),
753
                       tmpMaxY);
754
  }
755
}
756
/*********************************************************/
757
 
758
 
759
 
760
/*
761
 *--------------------------------------------------------------
762
 *
763
 * LayoutTreeSetX --
764
 *
765
 *      This procedure is invoked to calculate the x tree position.
766
 *      The procedure is called for all icons in the topological
767
 *      order.
768
 *
769
 * Results:
770
 *      None
771
 *
772
 * Side effects:
773
 *      See the user documentation.
774
 *
775
 *--------------------------------------------------------------
776
 */
777
 
778
static
779
void
780
LayoutTreeSetX AC2(Layout_Graph*,This, Node*,currentNode) /* This is the current node */
781
{
782
  int counter;
783
 
784
  /* Was this node already layouted ? */
785
  if(TREE_TMP_X_POS(currentNode) != -1 || IGNORE_NODE(currentNode)) {
786
    return;
787
  }
788
  if(DUMMY_NODE(currentNode)) {
789
    return;
790
  }
791
 
792
  SET_VISITED_NODE(currentNode, 1);
793
  if(PARENT_NUM(currentNode) > 0 &&
794
      VISITED_NODE(PARENT_NODE(currentNode, 0))) {
795
    /* There are parents, and the parent was already visited. This */
796
    /* means that this node is the first child we layout at this */
797
    /* level. That means it occurs at the same level as the parent. */
798
    SET_VISITED_NODE(PARENT_NODE(currentNode, 0), 0);
799
    SET_TREE_TMP_X_POS(currentNode,
800
                       TREE_TMP_X_POS(PARENT_NODE(currentNode, 0)));
801
  } else {
802
    /* Append the icon to the current maximal x position. It is not */
803
    /* the first child of the parent. */
804
    SET_TREE_TMP_X_POS(currentNode, THIS(maxXPosition));
805
  }
806
 
807
  /* Set the x position of the current node. If the order is top down, */
808
  /* we use the maximum edge width. */
809
  if(THIS(graphOrder)) {
810
    /* Place nodes top down. */
811
    SET_NODE_X_POS(currentNode, TREE_TMP_X_POS(currentNode));
812
    /* Do we have a new maximal x position ? */
813
    if(NODE_X_POS(currentNode) + THIS(iconSpaceH) + THIS(edgeWidth) +
814
        NODE_WIDTH(currentNode) > THIS(maxXPosition)) {
815
      THIS(maxXPosition) = NODE_X_POS(currentNode) + THIS(iconSpaceH) +
816
        THIS(edgeWidth) + NODE_WIDTH(currentNode);
817
    }
818
  } else {
819
    /* Place nodes left to right. */
820
    SET_NODE_X_POS(currentNode, TREE_TMP_X_POS(currentNode));
821
    /* Do we have a new maximal x position ? */
822
    if((NODE_X_POS(currentNode) + THIS(iconSpaceV) + THIS(edgeHeight) +
823
         NODE_HEIGHT(currentNode)) > THIS(maxXPosition)) {
824
      THIS(maxXPosition) = NODE_X_POS(currentNode) + THIS(iconSpaceV) +
825
        THIS(edgeHeight) + NODE_HEIGHT(currentNode);
826
    }
827
  }
828
 
829
  /* Walk through all successors. */
830
  FOR_ALL_SUCCS(currentNode, counter) {
831
    /* Layout the children of this node. */
832
    if(IGNORE_NODE(SUCC_EDGE(currentNode, counter))) {
833
      continue;
834
    }
835
    LayoutTreeSetX(This,SUCC_NODE(currentNode, counter));
836
  }
837
}
838
 
839
/*
840
 *--------------------------------------------------------------
841
 *
842
 * LayoutTreeSetY --
843
 *
844
 *      This procedure is invoked to calculate the y tree position.
845
 *
846
 * Results:
847
 *      None
848
 *
849
 * Side effects:
850
 *      See the user documentation.
851
 *
852
 *--------------------------------------------------------------
853
 */
854
 
855
static
856
void
857
LayoutTreeSetY AC2(Layout_Graph*,This, Node*,currentNode) /* This is the current node. */
858
{
859
  int counter;
860
  double tmpMaxY;
861
 
862
  if(IGNORE_NODE(currentNode)) {
863
    return;
864
  }
865
  if(DUMMY_NODE(currentNode)) {
866
    return;
867
  }
868
  if(VISITED_NODE(currentNode)) {
869
    return;
870
  }
871
 
872
  SET_VISITED_NODE(currentNode, 1);
873
  tmpMaxY = 0;
874
  /* Walk through all parents. */
875
  FOR_ALL_PARENTS(currentNode, counter) {
876
    /* Find the parent of this node that has the greatest Y. This way */
877
    /* the graph is always growing to the Y direction. */
878
    if(IGNORE_NODE(PARENT_EDGE(currentNode, counter)) ||
879
        IGNORE_NODE(PARENT_NODE(currentNode, counter))) {
880
      continue;
881
    }
882
    if(THIS(graphOrder)) {
883
      /* Place nodes top down. */
884
      if(TREE_TMP_Y_POS(PARENT_NODE(currentNode, counter)) +
885
          NODE_HEIGHT(PARENT_NODE(currentNode, counter)) +
886
          THIS(edgeHeight) + THIS(iconSpaceV) > tmpMaxY) {
887
        tmpMaxY = TREE_TMP_Y_POS(PARENT_NODE(currentNode, counter)) +
888
          NODE_HEIGHT(PARENT_NODE(currentNode, counter)) + THIS(edgeHeight) +
889
            THIS(iconSpaceV);
890
      }
891
    } else {
892
      if(TREE_TMP_Y_POS(PARENT_NODE(currentNode, counter)) +
893
          NODE_WIDTH(PARENT_NODE(currentNode, counter)) +
894
          THIS(edgeWidth) + THIS(iconSpaceH) > tmpMaxY) {
895
        tmpMaxY = TREE_TMP_Y_POS(PARENT_NODE(currentNode, counter)) +
896
          NODE_WIDTH(PARENT_NODE(currentNode, counter)) + THIS(edgeWidth) +
897
            THIS(iconSpaceH);
898
      }
899
    }
900
  }
901
 
902
  /* Set the y position of the current node. */
903
  if(THIS(graphOrder)) {
904
    /* Place nodes top down. */
905
    SET_NODE_Y_POS(currentNode, tmpMaxY);
906
    /* Keep the maximal y position, this way we can later calculate the */
907
    /* correct Y position for children of this widget. */
908
    SET_TREE_TMP_Y_POS(currentNode, NODE_Y_POS(currentNode));
909
  } else {
910
    /* Place nodes left to right. */
911
    SET_NODE_Y_POS(currentNode, tmpMaxY);
912
    /* Keep the maximal y position, this way we can later calculate the */
913
    /* correct Y position for children of this widget. */
914
    SET_TREE_TMP_Y_POS(currentNode, NODE_Y_POS(currentNode));
915
  }
916
}
917
 
918
/*
919
 *--------------------------------------------------------------
920
 *
921
 * createnode --
922
 *
923
 *      This procedure is invoked to create a new node. Optionally the
924
 *      procedure can be used to create dummy nodes. In that case the
925
 *      fromNode and toNode parameters are specified.
926
 *
927
 * Results:
928
 *      None
929
 *
930
 * Side effects:
931
 *      See the user documentation.
932
 *
933
 *--------------------------------------------------------------
934
 */
935
 
936
int
937
LayoutCreateNode AC4(Layout_Graph*,This,pItem,itemPtr, pItem,fromNode, pItem, toNode)
938
{
939
  int counter1 = 0, counter2 = 0, counter3 = 0, counter4 = 0, found = 0;
940
  Node *tmpNode;
941
  Edge *tmpEdge;
942
  ItemGeom bbox;
943
 
944
  /* see if this item was already added */
945
  FOR_ALL_NODES(counter1) {
946
        if(NODE_ITEM(THIS(nodes)[counter1]) == itemPtr) {
947
            THIS(errmsg) = "attempt to insert duplicate graph node";
948
            return LAYOUT_ERROR;
949
        }
950
  }
951
  THIS(nodeNum)++;
952
  if(THIS(nodes) == NULL) {
953
    THIS(nodes) = (Node **) ckalloc(THIS(nodeNum) * sizeof(Node *));
954
  } else {
955
    THIS(nodes) = (Node **) ckrealloc((char *) THIS(nodes),
956
                              THIS(nodeNum) * sizeof(Node *));
957
  }
958
  tmpNode = (Node *) ckalloc(sizeof(Node));
959
  SET_NODE_ITEM(tmpNode, itemPtr);
960
  SET_IGNORE_NODE(tmpNode, 0);
961
  SET_VISITED_NODE(tmpNode, 0);
962
  SET_NODE_X_POS(tmpNode, 0);
963
  SET_NODE_Y_POS(tmpNode, 0);
964
  SET_TREE_TMP_X_POS(tmpNode, -1);
965
  SET_TREE_TMP_Y_POS(tmpNode, -1);
966
  bbox.x1 = bbox.y1 = bbox.x2 = bbox.y2 = bbox.width = bbox.height = 0;
967
  SET_NODE_GEOM(tmpNode,bbox);
968
  SET_PARENT_NUM(tmpNode, 0);
969
  tmpNode->parent = (Edge**) NULL;
970
  SET_SUCC_NUM(tmpNode, 0);
971
  tmpNode->succ = (Edge**) NULL;
972
  THIS(nodes)[THIS(nodeNum)-1] = tmpNode;
973
 
974
#if 0
975
  /* create the specific data slot. */
976
  if(createdatanode != NULL) {
977
    (*createdatanode)(THIS(nodes)[THIS(nodeNum)-1]);
978
  }
979
#endif
980
 
981
  /* insert the dummy node. */
982
  if(fromNode != (Node*) NULL && toNode != (Node*) NULL) {
983
    FOR_ALL_NODES(counter1) {
984
      if(THIS(nodes)[counter1] == fromNode) {
985
        FOR_ALL_SUCCS(THIS(nodes)[counter1], counter2) {
986
          if(SUCC_NODE(THIS(nodes)[counter1], counter2) == toNode) {
987
            found++;
988
            break;
989
          }
990
        }
991
        break;
992
      }
993
    }
994
    FOR_ALL_NODES(counter3) {
995
      if(THIS(nodes)[counter3] == toNode) {
996
        FOR_ALL_PARENTS(THIS(nodes)[counter3], counter4) {
997
          if(PARENT_NODE(THIS(nodes)[counter3], counter4) == fromNode) {
998
            found++;
999
            break;
1000
          }
1001
        }
1002
        break;
1003
      }
1004
    }
1005
    if(found == 2) {
1006
      DEBUG_PRINT_NODE_POS(This, THIS(nodes)[counter1], "dummy insert from");
1007
      DEBUG_PRINT_NODE_POS(This, THIS(nodes)[counter3], "dummy insert to");
1008
      SET_PARENT_NUM(tmpNode, 1);
1009
      SET_SUCC_NUM(tmpNode, 1);
1010
      SET_NODE_X_POS(tmpNode, 10);
1011
      SET_NODE_Y_POS(tmpNode, 10);
1012
      THIS(nodes)[THIS(nodeNum)-1]->parent = (Edge**)
1013
        ckalloc(THIS(nodes)[THIS(nodeNum)-1]->parentNum * sizeof(Edge*));
1014
      tmpEdge = (Edge* ) ckalloc(sizeof(Edge));
1015
      SET_IGNORE_EDGE(tmpEdge, 0);
1016
      SET_VISITED_EDGE(tmpEdge, 0);
1017
      tmpEdge->fromNode = THIS(nodes)[counter1];
1018
      tmpEdge->toNode = THIS(nodes)[counter3];
1019
      THIS(nodes)[THIS(nodeNum)-1]->parent[0] = tmpEdge;
1020
      THIS(nodes)[THIS(nodeNum)-1]->succ = (Edge**)
1021
        ckalloc(THIS(nodes)[THIS(nodeNum)-1]->succNum * sizeof(Edge* ));
1022
      THIS(nodes)[THIS(nodeNum)-1]->succ[0] = tmpEdge;
1023
      THIS(nodes)[counter3]->parent[counter4]->toNode = tmpNode;
1024
      THIS(nodes)[counter1]->succ[counter2]->fromNode = tmpNode;
1025
    }
1026
  }
1027
  return LAYOUT_OK;
1028
}
1029
 
1030
int
1031
LayoutDeleteNode AC2(Layout_Graph*,This, pItem,nodeid)
1032
{
1033
    register int i;
1034
 
1035
    /* find the matching node*/
1036
    FOR_ALL_NODES(i) {
1037
        if(NODE_ITEM(THIS(nodes)[i]) == nodeid) {
1038
            return deletenode(This,THIS(nodes)[i],i);
1039
        }
1040
    }
1041
    THIS(errmsg) = "node delete: no such node";
1042
    return LAYOUT_ERROR;
1043
}
1044
 
1045
static
1046
int
1047
deletenode AC3(Layout_Graph*,This, Node*,thisnode, int,index)
1048
{
1049
    register int i;
1050
    /* remove all attached edges */
1051
    FOR_ALL_EDGES(i) {
1052
        register Edge* e = THIS(edges)[i];
1053
        if(e->toNode == thisnode
1054
           || e->fromNode == thisnode) {
1055
            deleteedge(This,e,i);
1056
        }
1057
    }
1058
 
1059
    /* clean up node */
1060
    if(thisnode->parent) ckfree((char*)thisnode->parent);
1061
    if(thisnode->succ) ckfree((char*)thisnode->succ);
1062
 
1063
    /* free and clear node */
1064
    THIS(nodeNum)--;
1065
    if(THIS(nodeNum) > 0) {
1066
        THIS(nodes)[index] = THIS(nodes)[THIS(nodeNum)];
1067
    }
1068
    ckfree((char*)thisnode);
1069
    return LAYOUT_OK;
1070
}
1071
 
1072
 
1073
int
1074
LayoutCreateEdge AC4(Layout_Graph*,This, pItem,edgeid, pItem,fromid, pItem,toid)
1075
{
1076
    register int i;
1077
    register Node* n;
1078
    Node* fromnode = NULL;
1079
    Node* tonode = NULL;
1080
    Edge* tmpEdge;
1081
 
1082
    /* see if this item was already added */
1083
    FOR_ALL_EDGES(i) {
1084
        if(EDGE_ITEM(THIS(edges)[i]) == edgeid) {
1085
            THIS(errmsg) = "attempt to insert duplicate graph edge";
1086
            return LAYOUT_ERROR;
1087
        }
1088
    }
1089
    /* locate the actual from and to nodes */
1090
    FOR_ALL_NODES(i) {
1091
        n = THIS(nodes)[i];
1092
        if(NODE_ITEM(n) == fromid) {
1093
            fromnode = n;
1094
        } else if(NODE_ITEM(n) == toid) {
1095
            tonode = n;
1096
        }
1097
    }
1098
    if(!fromnode || !tonode) {
1099
        THIS(errmsg) = "edge was missing from or to node";
1100
        return LAYOUT_ERROR;
1101
    }
1102
 
1103
    /* create Edge */
1104
    tmpEdge = (Edge* ) ckalloc(sizeof(Edge));
1105
    if(!tmpEdge) {
1106
        THIS(errmsg) = "malloc failure";
1107
        return LAYOUT_ERROR;
1108
    }
1109
    SET_IGNORE_EDGE(tmpEdge, 0);
1110
    SET_VISITED_EDGE(tmpEdge, 0);
1111
    tmpEdge->edgeid = edgeid;
1112
    tmpEdge->fromNode = fromnode;
1113
    tmpEdge->toNode = tonode;
1114
 
1115
    THIS(edgeNum)++;
1116
    if(THIS(edges) == NULL) {
1117
        THIS(edges) = (Edge* *) ckalloc(THIS(edgeNum) * sizeof(Edge* ));
1118
    } else {
1119
        THIS(edges) = (Edge* *) ckrealloc((char *) THIS(edges),
1120
                              THIS(edgeNum) * sizeof(Edge* ));
1121
    }
1122
    THIS(edges)[THIS(edgeNum)-1] = tmpEdge;
1123
 
1124
    /* insert the succ and parent edge structs */
1125
    tonode->parentNum++;
1126
    if(tonode->parent == NULL) {
1127
        tonode->parent = (Edge**)
1128
                ckalloc(tonode->parentNum * sizeof(Edge*));
1129
    } else {
1130
        tonode->parent = (Edge**)
1131
                ckrealloc((char *) tonode->parent,
1132
                        tonode->parentNum * sizeof(Edge*));
1133
    }
1134
    tonode->parent[tonode->parentNum - 1] = tmpEdge;
1135
 
1136
    fromnode->succNum++;
1137
    if(fromnode->succ == NULL) {
1138
        fromnode->succ = (Edge**)
1139
                ckalloc(fromnode->succNum * sizeof(Edge*));
1140
    } else {
1141
        fromnode->succ = (Edge**)
1142
                ckrealloc((char *) fromnode->succ,
1143
                        fromnode->succNum * sizeof(Edge*));
1144
    }
1145
    fromnode->succ[fromnode->succNum-1] = tmpEdge;
1146
 
1147
    return LAYOUT_OK;
1148
}
1149
 
1150
static
1151
void
1152
compress_succ AC2(Layout_Graph*,This, Node*,n)
1153
{
1154
    register Edge** p;
1155
    register Edge** q;
1156
 
1157
    for(p=n->succ,q=p+(n->succNum);p < q;p++) {
1158
        if(*p != NULL) continue;
1159
        /* found a null entry earlier than where q is pointing */
1160
        /* move q down to look for a non-null entry */
1161
        do { --q; } while(q > p && *q == NULL);
1162
        if(q <= p) break; /* p points to last non-null entry */
1163
        *p = *q;
1164
    }
1165
    n->succNum = p - n->succ;
1166
}
1167
 
1168
static
1169
void
1170
compress_parent AC2(Layout_Graph*,This, Node*,n)
1171
{
1172
    register Edge** p;
1173
    register Edge** q;
1174
 
1175
    for(p=n->parent,q=p+(n->parentNum);p < q;p++) {
1176
        if(*p != NULL) continue;
1177
        /* found a null entry earlier than where q is pointing */
1178
        /* move q down to look for a non-null entry */
1179
        do { --q; } while(q > p && *q == NULL);
1180
        if(q <= p) break; /* p points to last non-null entry */
1181
        *p = *q;
1182
    }
1183
    n->parentNum = p - n->parent;
1184
}
1185
 
1186
static
1187
int
1188
deleteedge AC3(Layout_Graph*,This, Edge*,e, int,index)
1189
{
1190
    register int i;
1191
    register int j;
1192
    register int found;
1193
 
1194
    /* remove all references to this Edge */
1195
    FOR_ALL_NODES(i) {
1196
        register Node* n = THIS(nodes)[i];
1197
        found = 0;
1198
        FOR_ALL_SUCCS(n,j) {
1199
            if(SUCC_EDGE(n,j) == e) {
1200
                SUCC_EDGE(n,j) = NULL;
1201
                found = 1;
1202
            }
1203
        }
1204
        if(found) {compress_succ(This,n);}
1205
        found = 0;
1206
        FOR_ALL_PARENTS(n,j) {
1207
            if(PARENT_EDGE(n,j) == e) {
1208
                PARENT_EDGE(n,j) = NULL;
1209
                found = 1;
1210
            }
1211
        }
1212
        if(found) {compress_parent(This,n);}
1213
    }
1214
    /* free and clear Edge*/
1215
    THIS(edgeNum)--;
1216
    if(THIS(edgeNum) > 0) {
1217
        THIS(edges)[index] = THIS(edges)[THIS(edgeNum)];
1218
    }
1219
    ckfree((char*)e);
1220
    return LAYOUT_OK;
1221
}
1222
 
1223
int
1224
LayoutDeleteEdge AC2(Layout_Graph*,This, pItem,eid)
1225
{
1226
    register int i;
1227
 
1228
    /* find matching edge object */
1229
    FOR_ALL_EDGES(i) {
1230
        register Edge* e = THIS(edges)[i];
1231
        if(e->edgeid == eid) {
1232
            return deleteedge(This,e,i);
1233
        }
1234
    }
1235
    THIS(errmsg) = "edge delete: no such edge";
1236
    return LAYOUT_ERROR;
1237
}
1238
 
1239
 
1240
/*
1241
 *--------------------------------------------------------------
1242
 *
1243
 * LayoutBuildGraph --
1244
 *
1245
 *      This procedure is invoked to create the internal
1246
 *      graph structure used for layouting.
1247
 *
1248
 * Results:
1249
 *      A standard Tcl result.
1250
 *
1251
 * Side effects:
1252
 *      See the user documentation.
1253
 *
1254
 *--------------------------------------------------------------
1255
 */
1256
 
1257
static
1258
int
1259
LayoutBuildGraph AC1(Layout_Graph*,This)
1260
{
1261
  register int counter;
1262
 
1263
  /* Walk through all nodes to compute various things */
1264
  FOR_ALL_NODES(counter) {
1265
    register Node* n = THIS(nodes)[counter];
1266
    /* Find the greatest icon dimensions. */
1267
    if(NODE_WIDTH(n) > THIS(iconWidth)) {
1268
      THIS(iconWidth) = (int)NODE_WIDTH(n);
1269
    }
1270
    if(NODE_HEIGHT(n) > THIS(iconHeight)) {
1271
      THIS(iconHeight) = (int)NODE_HEIGHT(n);
1272
    }
1273
  }
1274
 
1275
  return LAYOUT_OK;
1276
}
1277
 
1278
/*
1279
 *--------------------------------------------------------------
1280
 *
1281
 * LayoutClearGraph --
1282
 *
1283
 *--------------------------------------------------------------
1284
 */
1285
 
1286
void
1287
LayoutClearGraph AC1(Layout_Graph*,This)
1288
{
1289
  register int counter;
1290
  register Node* n;
1291
 
1292
  /* Free allocated memory. */
1293
  FOR_ALL_EDGES(counter) {
1294
    ckfree((char *) THIS(edges)[counter]);
1295
  }
1296
  THIS(edgeNum) = 0;
1297
  FOR_ALL_NODES(counter) {
1298
    n = THIS(nodes)[counter];
1299
    if (n->parent != NULL)
1300
        ckfree((char*)n->parent);
1301
        if (n->succ != NULL)
1302
        ckfree((char*)n->succ);
1303
    if (n != NULL)
1304
        ckfree((char *)n);
1305
  }
1306
  THIS(nodeNum) = 0;
1307
  FOR_ALL_TOP_NODES(counter) {
1308
    ckfree((char *) THIS(topList)[counter]);
1309
  }
1310
  THIS(topListNum) = 0;
1311
  if (THIS(topList) != NULL)
1312
  {
1313
        ckfree ((char *) (THIS(topList)));
1314
        THIS(topList) = NULL;
1315
  }
1316
  if (THIS(nodes) != NULL)
1317
  {
1318
        ckfree ((char *) (THIS(nodes)));
1319
        THIS(nodes) = NULL;
1320
  }
1321
  THIS(rootNode) = NULL;
1322
}
1323
 
1324
 
1325
/*
1326
 *--------------------------------------------------------------
1327
 *
1328
 * LayoutFreeGraph --
1329
 *
1330
 *      This procedure is invoked to free the graph structures
1331
 *      used for layouting.
1332
 *
1333
 * Results:
1334
 *      A standard Tcl result.
1335
 *
1336
 * Side effects:
1337
 *      See the user documentation.
1338
 *
1339
 *--------------------------------------------------------------
1340
 */
1341
 
1342
void
1343
LayoutFreeGraph AC1(Layout_Graph*,This)
1344
{
1345
  LayoutClearGraph(This);
1346
 
1347
  /* now cleanup the Layout Graph structure */
1348
  if (THIS(edges) != NULL)
1349
  {
1350
        ckfree((char *) THIS(edges));
1351
        THIS(edges) = NULL;
1352
  }
1353
  if (THIS(nodes) != NULL)
1354
  {
1355
        ckfree((char *) THIS(nodes));
1356
        THIS(nodes) = NULL;
1357
  }
1358
  if (THIS(topList) != NULL)
1359
  {
1360
        ckfree((char *) THIS(topList));
1361
        THIS(topList) = NULL;
1362
  }
1363
 
1364
  /* free graph layout structure */
1365
  ckfree ((char *) This);
1366
}
1367
 
1368
/*
1369
 *--------------------------------------------------------------
1370
 *
1371
 * LayoutGraphRoot --
1372
 *
1373
 *      This procedure is invoked to find the root of a graph.
1374
 *
1375
 * Results:
1376
 *      The root node.
1377
 *
1378
 * Side effects:
1379
 *      See the user documentation.
1380
 *
1381
 *--------------------------------------------------------------
1382
 */
1383
 
1384
static
1385
Node*
1386
LayoutGraphRoot AC1(Layout_Graph*,This)
1387
{
1388
  int optimalRootNum = -10000, minParentNum = -1, maxSuccNum = -1,
1389
      counter, counter1, counter2, counter3, lidx;
1390
  Node *tmprootNode, *node;
1391
 
1392
  /* Khamis 27-mar-97
1393
   * reorder nodes, so that nodes with not empty subtree displayed
1394
   * first
1395
   */
1396
  lidx = 0;
1397
  FOR_ALL_NODES(counter)
1398
  {
1399
    if (counter == 0 || IGNORE_NODE(THIS(nodes)[counter]))
1400
      continue;
1401
 
1402
    if (SUCC_NUM(THIS(nodes)[counter]) > SUCC_NUM(THIS(nodes)[lidx]))
1403
    {
1404
      node = THIS(nodes)[counter];
1405
      THIS(nodes)[counter] = THIS(nodes)[lidx];
1406
      THIS(nodes)[lidx] = node;
1407
 
1408
      /* search for next node with no subtree */
1409
      while (SUCC_NUM(THIS(nodes)[lidx]) > 0 && lidx < counter)
1410
      {
1411
        lidx ++;
1412
      }
1413
    }
1414
  }
1415
 
1416
  tmprootNode = THIS(rootNode);
1417
 
1418
  /* Find a root node. This node has no parents. In case we do not */
1419
  /* have such a node... find the node with the smallest number of */
1420
  /* parents. */
1421
 
1422
#if 0 /* Zsolt Koppany */
1423
  tmprootNode = THIS(nodes)[0];
1424
  return tmprootNode;
1425
#endif
1426
  if(!tmprootNode) {
1427
    /* We try to find the node with the most children and the least */
1428
    /* parents. This node will become root. */
1429
    FOR_ALL_NODES(counter) {
1430
      if(IGNORE_NODE(THIS(nodes)[counter])) {
1431
        continue;
1432
      }
1433
      if((SUCC_NUM(THIS(nodes)[counter]) > 0 &&
1434
           optimalRootNum <= (SUCC_NUM(THIS(nodes)[counter]) -
1435
                             PARENT_NUM(THIS(nodes)[counter])) &&
1436
           (minParentNum > PARENT_NUM(THIS(nodes)[counter]) ||
1437
            (minParentNum == PARENT_NUM(THIS(nodes)[counter]) &&
1438
            maxSuccNum < SUCC_NUM(THIS(nodes)[counter])))) ||
1439
          optimalRootNum == -10000 ||
1440
 
1441
          /* khamis: 17-mars-97, root with no parents have more priority */
1442
          PARENT_NUM(THIS(nodes)[counter]) < PARENT_NUM(tmprootNode)) {
1443
        tmprootNode = THIS(nodes)[counter];
1444
 
1445
        minParentNum = PARENT_NUM(THIS(nodes)[counter]);
1446
        maxSuccNum = SUCC_NUM(THIS(nodes)[counter]);
1447
        if(SUCC_NUM(THIS(nodes)[counter]) > 0) {
1448
          optimalRootNum =
1449
            (SUCC_NUM(THIS(nodes)[counter]) - PARENT_NUM(THIS(nodes)[counter]));
1450
        }
1451
      }
1452
    }
1453
  }
1454
 
1455
  /* No nodes... so abort the search. */
1456
  if(tmprootNode == NULL) {
1457
    return NULL;
1458
  }
1459
 
1460
  /* There is no node with no parents. So use the node with the */
1461
  /* smallest number of parents, and ignore the edges leading to this */
1462
  /* node. */
1463
  if(PARENT_NUM(tmprootNode) != 0) {
1464
    for (counter1 = 0; counter1 < PARENT_NUM(tmprootNode); counter1++) {
1465
      SET_IGNORE_NODE(PARENT_EDGE(tmprootNode, counter1), 1);
1466
      FOR_ALL_NODES(counter2) {
1467
        /* Ignore dummy nodes. */
1468
        if(DUMMY_NODE(THIS(nodes)[counter2])) {
1469
          continue;
1470
        }
1471
        if(NODE_ITEM(THIS(nodes)[counter2]) ==
1472
            NODE_ITEM(PARENT_NODE(tmprootNode, counter1))) {
1473
          FOR_ALL_SUCCS(THIS(nodes)[counter2], counter3) {
1474
            if(NODE_ITEM(SUCC_NODE(THIS(nodes)[counter2], counter3)) ==
1475
                NODE_ITEM(tmprootNode)) {
1476
              SET_IGNORE_NODE(SUCC_EDGE(THIS(nodes)[counter2], counter3), 1);
1477
            }
1478
          }
1479
        }
1480
      }
1481
    }
1482
  }
1483
  return tmprootNode;
1484
}
1485
 
1486
/*
1487
 *--------------------------------------------------------------
1488
 *
1489
 * LayoutGraphSortTopological --
1490
 *
1491
 *      This procedure is invoked to sort a graph topological.
1492
 *
1493
 * Results:
1494
 *      None
1495
 *
1496
 * Side effects:
1497
 *      See the user documentation.
1498
 *
1499
 *--------------------------------------------------------------
1500
 */
1501
 
1502
static
1503
void
1504
LayoutGraphSortTopological AC2(Layout_Graph*,This, Node*,currentNode) /* This is the current node. */
1505
{
1506
  int counter;
1507
  Topology *tmpTopology;
1508
 
1509
  if(VISITED_NODE(currentNode) || IGNORE_NODE(currentNode)) {
1510
    return;
1511
  }
1512
 
1513
  /* Append the current node to the list of topologically sorted */
1514
  /* nodes. */
1515
  THIS(topListNum)++;
1516
  if(THIS(topList) == NULL) {
1517
    THIS(topList) = (Topology **) ckalloc(THIS(topListNum) * sizeof(Topology *));
1518
  } else {
1519
    THIS(topList) = (Topology **) ckrealloc((char *) THIS(topList),
1520
                                    THIS(topListNum) * sizeof(Topology *));
1521
  }
1522
  tmpTopology = (Topology *) ckalloc(sizeof(Topology));
1523
  tmpTopology->nodePtr = currentNode;
1524
  THIS(topList)[THIS(topListNum)-1] = tmpTopology;
1525
 
1526
  SET_VISITED_NODE(currentNode, 1);
1527
  /* Walk through all successors. */
1528
  FOR_ALL_SUCCS(currentNode, counter) {
1529
    if(IGNORE_EDGE(SUCC_EDGE(currentNode, counter))) {
1530
      continue;
1531
    }
1532
    if(IGNORE_NODE(SUCC_NODE(currentNode, counter))) {
1533
      continue;
1534
    }
1535
    if(VISITED_NODE(SUCC_NODE(currentNode, counter))) {
1536
      SET_IGNORE_EDGE(SUCC_EDGE(currentNode, counter), 1);
1537
      continue;
1538
    }
1539
    LayoutGraphSortTopological(This,SUCC_NODE(currentNode, counter));
1540
  }
1541
}
1542
 
1543
/*
1544
 *--------------------------------------------------------------
1545
 *
1546
 * LayoutGraphPlaceNodes --
1547
 *
1548
 *      This procedure is invoked to actually place the graph nodes.
1549
 *
1550
 * Results:
1551
 *      A standard Tcl result.
1552
 *
1553
 * Side effects:
1554
 *      See the user documentation.
1555
 *
1556
 *--------------------------------------------------------------
1557
 */
1558
 
1559
static
1560
int
1561
LayoutGraphPlaceNodes AC1(Layout_Graph*,This)
1562
{
1563
  int counter;
1564
  double tmpX, tmpY;
1565
 
1566
  SRANDOM(getpid() + time((time_t *) NULL));
1567
 
1568
  FOR_ALL_NODES(counter) {
1569
    register Node* n = THIS(nodes)[counter];
1570
    if(IGNORE_NODE(n)) {
1571
      continue;
1572
    }
1573
    if(NODE_X_POS(n) != -1 &&
1574
        NODE_Y_POS(n) != -1) {
1575
      if(THIS(graphOrder)) {
1576
        /* Place nodes top down. */
1577
        tmpX = NODE_X_POS(n);
1578
        tmpY = NODE_Y_POS(n);
1579
      } else {
1580
        /* Place nodes left to right. */
1581
        tmpX = NODE_Y_POS(n);
1582
        tmpY = NODE_X_POS(n);
1583
      }
1584
    } else {
1585
      /* are we allowed to place the icon ? */
1586
      if(THIS(keepRandomPositions) &&
1587
          NODE_X_POS(n) > 0 &&
1588
          NODE_Y_POS(n) > 0) {
1589
        continue;
1590
      }
1591
      tmpX = (long) (RANDOM % THIS(maxX)) - NODE_WIDTH(n);
1592
      tmpY = (long) (RANDOM % THIS(maxY)) - NODE_HEIGHT(n);
1593
    }
1594
    if(tmpX < 0) {
1595
      tmpX = 0;
1596
    }
1597
    if(tmpY < 0) {
1598
      tmpY = 0;
1599
    }
1600
    if(!DUMMY_NODE(n)) {
1601
        ItemGeom g;
1602
        g = NODE_GEOM(n);
1603
        /* recalc Item Geom based on our layout */
1604
        g.x1 = tmpX+THIS(xOffset);
1605
        g.y1 = tmpY+THIS(yOffset);
1606
        g.x2 = g.x1 + g.width;
1607
        g.y2 = g.y1 + g.height;
1608
        SET_NODE_GEOM(n,g);
1609
    }
1610
  }
1611
  return LAYOUT_OK;
1612
}
1613
 
1614
/*
1615
 *--------------------------------------------------------------
1616
 *
1617
 * LayoutGraphPlaceEdges --
1618
 *
1619
 *      This procedure is invoked to relayout all edges.
1620
 *
1621
 * Results:
1622
 *      A standard Tcl result.
1623
 *
1624
 * Side effects:
1625
 *      See the user documentation.
1626
 *
1627
 *--------------------------------------------------------------
1628
 */
1629
 
1630
static
1631
int
1632
LayoutGraphPlaceEdges AC1(Layout_Graph*,This)
1633
{
1634
  register int i;
1635
 
1636
  /* scan through all edges */
1637
  FOR_ALL_EDGES(i) {
1638
    /* layout edges. */
1639
    LayoutEdge(This,THIS(edges)[i], NULL, NULL);
1640
  }
1641
  return LAYOUT_OK;
1642
}
1643
 
1644
/*
1645
 *--------------------------------------------------------------
1646
 *
1647
 * LayoutEdgeWidth --
1648
 *
1649
 *      This procedure is invoked to find the widest edge. Widest
1650
 *      means the edge with the maximal x expansion.
1651
 *
1652
 * Results:
1653
 *      A standard Tcl result.
1654
 *
1655
 * Side effects:
1656
 *      See the user documentation.
1657
 *
1658
 *--------------------------------------------------------------
1659
 */
1660
 
1661
static
1662
int
1663
LayoutEdgeWidth AC1(Layout_Graph*,This)
1664
{
1665
#if 1 /* Khamis, 19:00 20 Okt 1996 */
1666
  THIS(edgeHeight) = 0;
1667
  THIS(edgeWidth) = 0;
1668
#else
1669
  register int i;
1670
  if(THIS(edgeWidth) == 0) {
1671
    /* Walk through all edges. */
1672
    FOR_ALL_EDGES(i) {
1673
        if(THIS(edges)[i]->info.height + LINE_INCREMENT > THIS(edgeHeight)) {
1674
          THIS(edgeHeight) = THIS(edges)[i]->info.height + LINE_INCREMENT;
1675
        }
1676
        if(THIS(edges)[i]->info.width + LINE_INCREMENT > THIS(edgeWidth)) {
1677
          THIS(edgeWidth) = THIS(edges)[i]->info.width + LINE_INCREMENT;
1678
        }
1679
    }
1680
  }
1681
 
1682
#endif
1683
 
1684
  return LAYOUT_OK;
1685
}
1686
 
1687
/*
1688
 *--------------------------------------------------------------
1689
 *
1690
 * LayoutEdge --
1691
 *
1692
 *      This procedure is invoked to adjust the edge to the new
1693
 *      locations of the connected nodes. This algorithm only works
1694
 *      for simple edges.
1695
 *
1696
 * Results:
1697
 *      A standard Tcl result.
1698
 *
1699
 * Side effects:
1700
 *      See the user documentation.
1701
 *
1702
 *--------------------------------------------------------------
1703
 */
1704
 
1705
static
1706
int
1707
LayoutEdge AC4(Layout_Graph*,This,
1708
    Edge*,e,                    /* Current edge. */
1709
    Node*,fromNode,                     /* Source node. */
1710
    Node*,toNode)                       /* Target node. */
1711
{
1712
  int result = LAYOUT_OK;
1713
#if 0
1714
  Node *currentNode;
1715
#endif
1716
  ItemGeom geom;
1717
 
1718
  if(fromNode == (Node*) NULL && toNode == (Node*) NULL)
1719
  {
1720
    fromNode = e->fromNode;
1721
    toNode = e->toNode;
1722
  }
1723
#if 0
1724
  else
1725
  {
1726
    /* Place one specific edge... */
1727
    /* WARNING !!! this code is old and not adapted to the new Edge*/
1728
    /* placing. The code is not tested. This stuff will be used to */
1729
    /* display multi point edges.... */
1730
    fromPtr = NODE_ITEM(fromNode);
1731
    while (DUMMY_NODE(toNode) && SUCC_NUM(toNode) > 0) {
1732
      toNode = SUCC_NODE(toNode, 0);
1733
    }
1734
    toPtr = NODE_ITEM(toNode);
1735
    if(itemPtr == (pItem ) NULL) {
1736
      /* Match the numeric id value to a concrete item pointer. */
1737
      FOR_ALL_CANVAS_ITEMS(canvasPtr, itemPtr) {
1738
        if(strcmp(CANVAS_ITEM_TYPE(itemPtr), "edge") == 0) {
1739
          /* Get "from" id */
1740
          Tk_ConfigureInfo(canvasPtr->interp, canvasPtr->tkwin,
1741
                           itemPtr->typePtr->configSpecs,
1742
                           (char *) itemPtr, "-from", 0);
1743
          if(Tcl_SplitList(canvasPtr->interp,
1744
                            canvasPtr->interp->result,
1745
                            &argc2, &argv2) != LAYOUT_OK) {
1746
            return LAYOUT_ERROR;
1747
          }
1748
          fromId = atol(argv2[4]);
1749
          ckfree((char *) argv2);
1750
 
1751
          /* Get "to" id */
1752
          Tk_ConfigureInfo(canvasPtr->interp, canvasPtr->tkwin,
1753
                           itemPtr->typePtr->configSpecs,
1754
                           (char *) itemPtr, "-to", 0);
1755
          if(Tcl_SplitList(canvasPtr->interp,
1756
                            canvasPtr->interp->result,
1757
                            &argc2, &argv2) != LAYOUT_OK) {
1758
            return LAYOUT_ERROR;
1759
          }
1760
          toId = atol(argv2[4]);
1761
          ckfree((char *) argv2);
1762
 
1763
          if(fromId == CANVAS_ITEM_ID(fromPtr) &&
1764
              toId == CANVAS_ITEM_ID(toPtr)) {
1765
            curPtr = itemPtr;
1766
            FOR_ALL_SUCCS(fromNode, counter1) {
1767
              Tcl_DStringInit(&positionString);
1768
              if(fromPtr->x1 > fromPtr->x2) {
1769
                THIS(posX1) = fromPtr->x1 + ((fromPtr->x2 - fromPtr->x1) / 2);
1770
              } else {
1771
                THIS(posX1) = fromPtr->x2 + ((fromPtr->x1 - fromPtr->x2) / 2);
1772
              }
1773
              if(fromPtr->y1 > fromPtr->y2) {
1774
                THIS(posY1) = fromPtr->y1 + ((fromPtr->y2 - fromPtr->y1) / 2);
1775
              } else {
1776
                THIS(posY1) = fromPtr->y2 + ((fromPtr->y1 - fromPtr->y2) / 2);
1777
              }
1778
              if(toPtr->x1 > toPtr->x2) {
1779
                THIS(posX2) = toPtr->x1 + ((toPtr->x2 - toPtr->x1) / 2);
1780
              } else {
1781
                THIS(posX2) = toPtr->x2 + ((toPtr->x1 - toPtr->x2) / 2);
1782
              }
1783
              if(toPtr->y1 > toPtr->y2) {
1784
                THIS(posY2) = toPtr->y1 + ((toPtr->y2 - toPtr->y1) / 2);
1785
              } else {
1786
                THIS(posY2) = toPtr->y2 + ((toPtr->y1 - toPtr->y2) / 2);
1787
              }
1788
 
1789
              if(fromPtr->y2 <= toPtr->y1) {
1790
                sprintf(convertBuffer, "%d %d ", THIS(posX1), fromPtr->y2);
1791
              } else {
1792
                if(fromPtr->y1 >= toPtr->y2) {
1793
                  sprintf(convertBuffer, "%d %d ", THIS(posX1), fromPtr->y1);
1794
                } else {
1795
                  if(fromPtr->x2 < toPtr->x1) {
1796
                    sprintf(convertBuffer, "%d %d ", fromPtr->x2, THIS(posY1));
1797
                  } else {
1798
                    sprintf(convertBuffer, "%d %d ", fromPtr->x1, THIS(posY1));
1799
                  }
1800
                }
1801
              }
1802
 
1803
              Tcl_DStringAppend(&positionString, convertBuffer, -1);
1804
              currentNode = SUCC_NODE(fromNode, counter1);
1805
              while (DUMMY_NODE(currentNode) && SUCC_NUM(currentNode) > 0) {
1806
                currentNode = SUCC_NODE(currentNode, 0);
1807
                sprintf(convertBuffer, "%g %g ", /*300.0, 300.0*/
1808
                        NODE_X_POS(currentNode), NODE_Y_POS(currentNode));
1809
                Tcl_DStringAppend(&positionString, convertBuffer, -1);
1810
              }
1811
              if(NODE_ITEM(currentNode) != toPtr) {
1812
                Tcl_DStringFree(&positionString);
1813
                continue;
1814
              }
1815
              if(fromPtr->y2 <= toPtr->y1) {
1816
                sprintf(convertBuffer, "%d %d ", THIS(posX2), toPtr->y1);
1817
              } else {
1818
                if(fromPtr->y1 >= toPtr->y2) {
1819
                  sprintf(convertBuffer, "%d %d ", THIS(posX2), toPtr->y2);
1820
                } else {
1821
                  if(fromPtr->x2 < toPtr->x1) {
1822
                    sprintf(convertBuffer, "%d %d ", toPtr->x1, THIS(posY2));
1823
                  } else {
1824
                    sprintf(convertBuffer, "%d %d ", toPtr->x2, THIS(posY2));
1825
                  }
1826
                }
1827
              }
1828
              Tcl_DStringAppend(&positionString, convertBuffer, -1);
1829
 
1830
              /* Set new coordinates */
1831
              if(Tcl_SplitList(canvasPtr->interp, positionString.string,
1832
                                &argc2, &argv2) != LAYOUT_OK) {
1833
                return LAYOUT_ERROR;
1834
              }
1835
              Tcl_ResetResult(canvasPtr->interp);
1836
              result = (*curPtr->typePtr->coordProc)
1837
                (canvasPtr, curPtr, argc2, argv2);
1838
              ckfree((char *) argv2);
1839
              Tcl_DStringFree(&positionString);
1840
            }
1841
            return result;
1842
          }
1843
        }
1844
      }
1845
    }
1846
  }
1847
#endif /* #if 0 */
1848
 
1849
  /* Is this a regular edge ? */
1850
  if(fromNode != NULL && toNode != NULL) {
1851
    /* calculate the various node anchors. */
1852
    /* calc center of the from node */
1853
    if(fromNode->info.x1 > fromNode->info.x2) {
1854
      THIS(posX1) = fromNode->info.x1 + ((fromNode->info.x2 - fromNode->info.x1) / 2);
1855
    } else {
1856
      THIS(posX1) = fromNode->info.x2 + ((fromNode->info.x1 - fromNode->info.x2) / 2);
1857
    }
1858
    if(fromNode->info.y1 > fromNode->info.y2) {
1859
      THIS(posY1) = fromNode->info.y1 + ((fromNode->info.y2 - fromNode->info.y1) / 2);
1860
    } else {
1861
      THIS(posY1) = fromNode->info.y2 + ((fromNode->info.y1 - fromNode->info.y2) / 2);
1862
    }
1863
    /* calc center of the to node */
1864
    if(toNode->info.x1 > toNode->info.x2) {
1865
      THIS(posX2) = toNode->info.x1 + ((toNode->info.x2 - toNode->info.x1) / 2);
1866
    } else {
1867
      THIS(posX2) = toNode->info.x2 + ((toNode->info.x1 - toNode->info.x2) / 2);
1868
    }
1869
    if(toNode->info.y1 > toNode->info.y2) {
1870
      THIS(posY2) = toNode->info.y1 + ((toNode->info.y2 - toNode->info.y1) / 2);
1871
    } else {
1872
      THIS(posY2) = toNode->info.y2 + ((toNode->info.y1 - toNode->info.y2) / 2);
1873
    }
1874
 
1875
    if(THIS(edgeOrder)) {
1876
      /* Place the edges according to the graph order... only along
1877
       * the generale layout direction. */
1878
      if(THIS(graphOrder)) {
1879
        /* Place nodes top down. */
1880
        if(fromNode->info.y2 <= toNode->info.y1) {
1881
          geom.x1 = THIS(posX1);
1882
          geom.y1 = fromNode->info.y2;
1883
          geom.x2 = THIS(posX2);
1884
          geom.y2 = toNode->info.y1;
1885
        } else {
1886
          geom.x1 = THIS(posX1);
1887
          geom.y1 = fromNode->info.y1;
1888
          geom.x2 = THIS(posX2);
1889
          geom.y2 = toNode->info.y2;
1890
        }
1891
      } else {
1892
        /* Place nodes left to right. */
1893
        if(fromNode->info.x2 < toNode->info.x1) {
1894
          geom.x1 = fromNode->info.x2;
1895
          geom.y1 = THIS(posY1);
1896
          geom.x2 = toNode->info.x1;
1897
          geom.y2 = THIS(posY2);
1898
        } else {
1899
          geom.x1 = fromNode->info.x1;
1900
          geom.y1 = THIS(posY1);
1901
          geom.x2 = toNode->info.x2;
1902
          geom.y2 = THIS(posY2);
1903
        }
1904
      }
1905
    } else {
1906
      /* Place the edges so that they use the shortest distance. */
1907
      if(fromNode->info.y2 <= toNode->info.y1) {
1908
        /* from is above to */
1909
        if(fromNode->info.x2 <= toNode->info.x1) {
1910
          /* from is left from to */
1911
          if(THIS(graphOrder)) {
1912
            /* Place nodes top down. */
1913
            geom.x1 = THIS(posX1);
1914
            geom.y1 = fromNode->info.y2;
1915
            geom.x2 = THIS(posX2);
1916
            geom.y2 = toNode->info.y1;
1917
          } else {
1918
            geom.x1 = fromNode->info.x2;
1919
            geom.y1 = THIS(posY1);
1920
            geom.x2 = toNode->info.x1;
1921
            geom.y2 = THIS(posY2);
1922
          }
1923
        } else {
1924
          if(fromNode->info.x1 >= toNode->info.x2) {
1925
            /* from is right from to */
1926
            if(THIS(graphOrder)) {
1927
              /* Place nodes top down. */
1928
              geom.x1 = THIS(posX1);
1929
              geom.y1 = fromNode->info.y2;
1930
              geom.x2 = THIS(posX2);
1931
              geom.y2 = toNode->info.y1;
1932
            } else {
1933
              geom.x1 = fromNode->info.x1;
1934
              geom.y1 = THIS(posY1);
1935
              geom.x2 = toNode->info.x2;
1936
              geom.y2 = THIS(posY2);
1937
            }
1938
          } else {
1939
            /* from is at same level as to */
1940
            geom.x1 = THIS(posX1);
1941
            geom.y1 = fromNode->info.y2;
1942
            geom.x2 = THIS(posX2);
1943
            geom.y2 = toNode->info.y1;
1944
          }
1945
        }
1946
      } else {
1947
        if(fromNode->info.y1 >= toNode->info.y2) {
1948
          /* from is below to */
1949
          if(fromNode->info.x2 <= toNode->info.x1) {
1950
            /* from is left from to */
1951
            if(THIS(graphOrder)) {
1952
              /* Place nodes top down. */
1953
              geom.x1 = THIS(posX1);
1954
              geom.y1 = fromNode->info.y1;
1955
              geom.x2 = THIS(posX2);
1956
              geom.y2 = toNode->info.y2;
1957
            } else {
1958
              geom.x1 = fromNode->info.x2;
1959
              geom.y1 = THIS(posY1);
1960
              geom.x2 = toNode->info.x1;
1961
              geom.y2 = THIS(posY2);
1962
            }
1963
          } else {
1964
            if(fromNode->info.x1 >= toNode->info.x2) {
1965
              /* from is right from to */
1966
              if(THIS(graphOrder)) {
1967
                /* Place nodes top down. */
1968
                geom.x1 = THIS(posX1);
1969
                geom.y1 = fromNode->info.y1;
1970
                geom.x2 = THIS(posX2);
1971
                geom.y2 = toNode->info.y2;
1972
              } else {
1973
                geom.x1 = fromNode->info.x1;
1974
                geom.y1 = THIS(posY1);
1975
                geom.x2 = toNode->info.x2;
1976
                geom.y2 = THIS(posY2);
1977
              }
1978
            } else {
1979
              /* from is at same level as to */
1980
              geom.x1 = THIS(posX1);
1981
              geom.y1 = fromNode->info.y1;
1982
              geom.x2 = THIS(posX2);
1983
              geom.y2 = toNode->info.y2;
1984
            }
1985
          }
1986
        } else {
1987
          /* from is at same level as to */
1988
          if(fromNode->info.x2 <= toNode->info.x1) {
1989
            /* from is left from to */
1990
            geom.x1 = fromNode->info.x2;
1991
            geom.y1 = THIS(posY1);
1992
            geom.x2 = toNode->info.x1;
1993
            geom.y2 = THIS(posY2);
1994
          } else {
1995
            if(fromNode->info.x1 > toNode->info.x2) {
1996
              /* from is right from to */
1997
              geom.x1 = fromNode->info.x1;
1998
              geom.y1 = THIS(posY1);
1999
              geom.x2 = toNode->info.x2;
2000
              geom.y2 = THIS(posY2);
2001
            } else {
2002
              if(fromNode->info.x1 <= toNode->info.x1) {
2003
                /* from is partially left from to */
2004
                geom.x1 = fromNode->info.x2;
2005
                geom.y1 = THIS(posY1);
2006
                geom.x2 = toNode->info.x1;
2007
                geom.y2 = THIS(posY2);
2008
              } else {
2009
                /* from is partially right from to */
2010
                geom.x1 = fromNode->info.x1;
2011
                geom.y1 = THIS(posY1);
2012
                geom.x2 = toNode->info.x2;
2013
                geom.y2 = THIS(posY2);
2014
              }
2015
            }
2016
          }
2017
        }
2018
      }
2019
    }
2020
  }
2021
 
2022
  /* Set new coordinates on Edge*/
2023
  SET_EDGE_GEOM(e,geom);
2024
 
2025
  return result;
2026
}
2027
 
2028
/*
2029
 *--------------------------------------------------------------
2030
 *
2031
 * LayoutISI --
2032
 *
2033
 *      This procedure is invoked to place icons with ISI.
2034
 *
2035
 * Results:
2036
 *      A standard Tcl result.
2037
 *
2038
 * Side effects:
2039
 *      See the user documentation.
2040
 *
2041
 *--------------------------------------------------------------
2042
 */
2043
 
2044
int
2045
LayoutISI AC1(Layout_Graph*,This)
2046
{
2047
  int counter, result = LAYOUT_OK;
2048
 
2049
  THIS(maxXPosition) = 0;
2050
  THIS(maxYPosition) = 0;
2051
  if(THIS(topList)) {
2052
    /* free layout specific data slots. */
2053
    for (counter = 0; counter < THIS(topListNum); counter++) {
2054
      ckfree((char *) THIS(topList)[counter]);
2055
    }
2056
    ckfree((char*)THIS(topList));
2057
    THIS(topList) = NULL;
2058
  }
2059
  THIS(topListNum) = 0;
2060
  THIS(topList) = (Topology **) NULL;
2061
 
2062
  /* find the widest/highest edge. */
2063
  LayoutEdgeWidth(This);
2064
 
2065
  /* build the internal graph structure. */
2066
  if(LayoutBuildGraph(This) != LAYOUT_OK) {
2067
    return LAYOUT_ERROR;
2068
  }
2069
 
2070
  /* find root of the graph. */
2071
  if((THIS(rootNode) = LayoutGraphRoot(This)) == NULL) {
2072
    THIS(errmsg) = "no root node";
2073
    return LAYOUT_ERROR;
2074
  }
2075
 
2076
  /* sort the graph topological. */
2077
  LayoutGraphSortTopological(This,THIS(rootNode));
2078
  FOR_ALL_NODES(counter) {
2079
    if(PARENT_NUM(THIS(nodes)[counter]) == 0) {
2080
      LayoutGraphSortTopological(This,THIS(nodes)[counter]);
2081
    }
2082
  }
2083
 
2084
  /* Calculate the x position values. */
2085
  RESET_VISITED_NODE(counter);
2086
  FOR_ALL_NODES(counter) {
2087
    if(PARENT_NUM(THIS(nodes)[counter]) == 0) {
2088
      LayoutISISetX(This,THIS(nodes)[counter]);
2089
    }
2090
  }
2091
 
2092
#if 0
2093
  RESET_VISITED_NODE(counter);
2094
  FOR_ALL_NODES(counter) {
2095
    if(PARENT_NUM(THIS(nodes)[counter]) == 0) {
2096
      MY_LayoutISISetY(This,THIS(nodes)[counter], 0);
2097
    }
2098
  }
2099
#else
2100
  RESET_VISITED_NODE(counter);
2101
  FOR_ALL_NODES(counter) {
2102
    if(SUCC_NUM(THIS(nodes)[counter]) == 0) {
2103
      LayoutISISetY(This,THIS(nodes)[counter]);
2104
    }
2105
  }
2106
#endif
2107
 
2108
#if 1
2109
  if (! THIS(graphOrder)) {
2110
     while (1) {
2111
        int found;
2112
        found = 0;
2113
        FOR_ALL_NODES(counter) {
2114
          if(PARENT_NUM (THIS(nodes)[counter]) > 0 &&
2115
           NODE_Y_POS (THIS(nodes)[counter]) <
2116
           NODE_Y_POS (PARENT_NODE(THIS(nodes)[counter], 0)) +
2117
           NODE_WIDTH (PARENT_NODE(THIS(nodes)[counter], 0)) +
2118
                    THIS(edgeWidth) + THIS(iconSpaceH)) {
2119
           SET_NODE_Y_POS(THIS(nodes)[counter],
2120
 
2121
                     NODE_Y_POS (PARENT_NODE(THIS(nodes)[counter], 0)) +
2122
                     NODE_WIDTH (PARENT_NODE(THIS(nodes)[counter], 0)) +
2123
                     THIS(edgeWidth) + THIS(iconSpaceH));
2124
           found = 1;
2125
          }
2126
 
2127
          if (SUCC_NUM (THIS(nodes)[counter]) == 1 &&
2128
             PARENT_NODE (SUCC_NODE (THIS(nodes)[counter], 0), 0) == THIS(nodes)[counter]) {
2129
             SET_NODE_X_POS(SUCC_NODE (THIS(nodes)[counter], 0),
2130
                          NODE_X_POS(THIS(nodes)[counter]));
2131
          }
2132
       }
2133
       if (! found)
2134
         break;
2135
     }
2136
  }
2137
#endif
2138
 
2139
  /* Place the graph items. */
2140
  if(LayoutGraphPlaceNodes(This) != LAYOUT_OK) {
2141
    result = LAYOUT_ERROR;
2142
  } else if(LayoutGraphPlaceEdges(This) != LAYOUT_OK) {
2143
    result = LAYOUT_ERROR;
2144
  }
2145
  return result;
2146
}
2147
 
2148
/*
2149
 *--------------------------------------------------------------
2150
 *
2151
 * LayoutMatrix --
2152
 *
2153
 *      This procedure is invoked to place icons as matrix.
2154
 *
2155
 * Results:
2156
 *      A standard Tcl result.
2157
 *
2158
 * Side effects:
2159
 *      See the user documentation.
2160
 *
2161
 *--------------------------------------------------------------
2162
 */
2163
 
2164
int
2165
LayoutMatrix AC1(Layout_Graph*,This)
2166
{
2167
    int result = LAYOUT_OK, greatestX = 10,
2168
      greatestY = 10, greatestHeight = 0, columnCounter = 0,
2169
      tmpIconWidth = 0, offset = 0, counter;
2170
    ItemGeom geom;
2171
 
2172
    /* Scan through all canvas items. */
2173
    FOR_ALL_NODES(counter) {
2174
        register Node* n = THIS(nodes)[counter];
2175
        /* Find the greatest icon dimensions. */
2176
        if(THIS(computeiconsize)) {
2177
            if(NODE_WIDTH(n) > THIS(iconWidth)) {
2178
                THIS(iconWidth) = (int)NODE_WIDTH(n);
2179
            }
2180
            if(NODE_HEIGHT(n) > THIS(iconHeight)) {
2181
                THIS(iconHeight) = (int)NODE_HEIGHT(n);
2182
            }
2183
        }
2184
    }
2185
 
2186
    /* Walk through the list of NODES */
2187
    FOR_ALL_NODES(counter) {
2188
        register Node* n = THIS(nodes)[counter];
2189
        geom = NODE_GEOM(n);
2190
        if(THIS(iconWidth) == 0) {
2191
            tmpIconWidth = (int)NODE_WIDTH(n);
2192
            offset = (int) ((NODE_WIDTH(n) / 2.0) - (NODE_WIDTH(n) / 2.0));
2193
        } else {
2194
            tmpIconWidth = THIS(iconWidth);
2195
            offset = (int) ((THIS(iconWidth) / 2.0) - (NODE_WIDTH(n) / 2.0));
2196
        }
2197
        /* Is this the highest icon so far ? */
2198
        if(NODE_HEIGHT(n) > greatestHeight) {
2199
            greatestHeight = (int) NODE_HEIGHT(n);
2200
        }
2201
 
2202
        /* Place icon on the current line. */
2203
        if(greatestX + tmpIconWidth < THIS(maxX) &&
2204
           (THIS(elementsPerLine) == 0 ||
2205
            columnCounter < THIS(elementsPerLine))) {
2206
            geom.x1 = offset + greatestX + THIS(xOffset);
2207
            geom.y1 = greatestY + THIS(yOffset);
2208
            geom.x2 = geom.x1 + geom.width;
2209
            geom.y2 = geom.y1 + geom.height;
2210
            greatestX += (tmpIconWidth + THIS(iconSpaceH));
2211
            columnCounter++;
2212
            SET_NODE_GEOM(n,geom);
2213
        } else {
2214
            /* Place icon on the next line. */
2215
            if(THIS(iconHeight) > 0) {
2216
                greatestY += (THIS(iconHeight) + THIS(iconSpaceV));
2217
            } else {
2218
                greatestY += (greatestHeight + THIS(iconSpaceV));
2219
            }
2220
            geom.x1 = 10 + offset + greatestX + THIS(xOffset);
2221
            geom.y1 = greatestY + THIS(yOffset);
2222
            geom.x2 = geom.x1 + geom.width;
2223
            geom.y2 = geom.y1 + geom.height;
2224
            greatestHeight = (int) geom.height;
2225
            greatestX = 10 + (tmpIconWidth + THIS(iconSpaceH));
2226
            columnCounter = 1;
2227
            SET_NODE_GEOM(n,geom);
2228
        }
2229
    }
2230
 
2231
    if(THIS(hideEdges)) {
2232
        /* make all edges zero length, and place at maxX,MaxY
2233
           to get them out of the way
2234
        */
2235
        FOR_ALL_EDGES(counter) {
2236
            geom.x2 = (geom.x1 = THIS(maxX));
2237
            geom.y2 = (geom.y1 = THIS(maxY));
2238
            geom.width = (geom.height = 0);
2239
            SET_EDGE_GEOM(THIS(edges)[counter],geom);
2240
        }
2241
    } else if(LayoutGraphPlaceEdges(This) != LAYOUT_OK) {
2242
        result = LAYOUT_ERROR;
2243
    }
2244
    return result;
2245
}
2246
 
2247
/*
2248
 *--------------------------------------------------------------
2249
 *
2250
 * LayoutRandom --
2251
 *
2252
 *      This procedure is invoked to place icons randomly.
2253
 *
2254
 * Results:
2255
 *      A standard Tcl result.
2256
 *
2257
 * Side effects:
2258
 *      See the user documentation.
2259
 *
2260
 *--------------------------------------------------------------
2261
 */
2262
 
2263
int
2264
LayoutRandom AC1(Layout_Graph*,This)
2265
{
2266
    int result = LAYOUT_OK;
2267
    int counter;
2268
 
2269
    SRANDOM(getpid() + time((time_t *) NULL));
2270
    /* walk through all nodes */
2271
    FOR_ALL_NODES(counter) {
2272
        register Node* itemptr = THIS(nodes)[counter];
2273
        long tmpx, tmpy;
2274
        ItemGeom geom;
2275
 
2276
        /* randomly place icons. */
2277
        /* are we allowed to place the icon ? */
2278
        if(THIS(keepRandomPositions) &&
2279
                NODE_X_POS(itemptr) > 0 &&
2280
                NODE_Y_POS(itemptr) > 0) {
2281
          continue;
2282
        }
2283
        tmpx = (long) (RANDOM % THIS(maxX)) - (long) NODE_WIDTH(itemptr);
2284
        tmpy = (long) (RANDOM % THIS(maxY)) - (long) NODE_HEIGHT(itemptr);
2285
        if(tmpx <= 0) {
2286
          tmpx = 1;
2287
        }
2288
        if(tmpy <= 0) {
2289
          tmpy = 1;
2290
        }
2291
        geom = NODE_GEOM(itemptr);
2292
        geom.x1 = tmpx + THIS(xOffset);
2293
        geom.y1 = tmpy + THIS(yOffset);
2294
        geom.x2 = geom.x1 + NODE_WIDTH(itemptr);
2295
        geom.y2 = geom.y1 + NODE_HEIGHT(itemptr);
2296
        SET_NODE_GEOM(itemptr,geom);
2297
    }
2298
 
2299
    if(LayoutGraphPlaceEdges(This) != LAYOUT_OK) {
2300
        result = LAYOUT_ERROR;
2301
    }
2302
    return result;
2303
}
2304
 
2305
/*
2306
 *--------------------------------------------------------------
2307
 *
2308
 * LayoutTree --
2309
 *
2310
 *      this procedure is invoked to place icons as tree.
2311
 *
2312
 * results:
2313
 *      a standard tcl result.
2314
 *
2315
 * side effects:
2316
 *      see the user documentation.
2317
 *
2318
 * 09nov95 wmt: add handling of -hideedges
2319
 *--------------------------------------------------------------
2320
 */
2321
 
2322
int
2323
LayoutTree AC1(Layout_Graph*,This)
2324
{
2325
  int result = LAYOUT_OK, counter;
2326
  ItemGeom geom;
2327
 
2328
  THIS(maxXPosition) = 0;
2329
  THIS(maxYPosition) = 0;
2330
  if(THIS(topList)) {
2331
    /* free layout specific data slots. */
2332
    for (counter = 0; counter < THIS(topListNum); counter++) {
2333
      ckfree((char *) THIS(topList)[counter]);
2334
    }
2335
    ckfree((char*)THIS(topList));
2336
  }
2337
  THIS(topListNum) = 0;
2338
  THIS(topList) = (Topology **) NULL;
2339
 
2340
  /* find the widest/highest edge. */
2341
  LayoutEdgeWidth(This);
2342
 
2343
  /* build the internal graph structure. */
2344
  if(LayoutBuildGraph(This) != LAYOUT_OK) {
2345
    return LAYOUT_ERROR;
2346
  }
2347
 
2348
  /* find root of the graph. */
2349
  if((THIS(rootNode) = LayoutGraphRoot(This)) == NULL) {
2350
    THIS(errmsg) = "no root node";
2351
    return LAYOUT_ERROR;
2352
  }
2353
 
2354
  /* sort the graph topological. */
2355
  LayoutGraphSortTopological(This,THIS(rootNode));
2356
  FOR_ALL_NODES(counter) {
2357
    if(PARENT_NUM(THIS(nodes)[counter]) == 0) {
2358
      LayoutGraphSortTopological(This,THIS(nodes)[counter]);
2359
    }
2360
  }
2361
 
2362
  /* calculate the position values. */
2363
  RESET_VISITED_NODE(counter);
2364
  LayoutTreeSetX(This,THIS(rootNode));
2365
  FOR_ALL_NODES(counter) {
2366
    if(PARENT_NUM(THIS(nodes)[counter]) == 0) {
2367
      LayoutTreeSetX(This,THIS(nodes)[counter]);
2368
    }
2369
  }
2370
  RESET_VISITED_NODE(counter);
2371
  FOR_ALL_TOP_NODES(counter) {
2372
    LayoutTreeSetY(This,TOP_NODE(counter));
2373
  }
2374
 
2375
  /* place the graph items. */
2376
  if(LayoutGraphPlaceNodes(This) != LAYOUT_OK) {
2377
    result = LAYOUT_ERROR;
2378
  }
2379
  if(THIS(hideEdges)) {
2380
    /* make all edges zero length, and place at maxX,MaxY
2381
       to get them out of the way
2382
       */
2383
    FOR_ALL_EDGES(counter) {
2384
      geom.x2 = (geom.x1 = THIS(maxX));
2385
      geom.y2 = (geom.y1 = THIS(maxY));
2386
      geom.width = (geom.height = 0);
2387
      SET_EDGE_GEOM(THIS(edges)[counter],geom);
2388
    }
2389
  } else if(LayoutGraphPlaceEdges(This) != LAYOUT_OK) {
2390
    result = LAYOUT_ERROR;
2391
  }
2392
  return result;
2393
}
2394
 
2395
Layout_Graph*
2396
LayoutCreateGraph()
2397
{
2398
    register Layout_Graph* This;
2399
 
2400
    This = (Layout_Graph*)ckalloc(sizeof(Layout_Graph));
2401
    if(!This) return This;
2402
#if 1 /* multiX */
2403
    memset((char *)This,0,sizeof(Layout_Graph));
2404
#endif
2405
    /* Initialize global data. */
2406
    THIS(graphOrder) = 0;
2407
    THIS(iconSpaceH) = 5;
2408
    THIS(iconSpaceV) = 5;
2409
    THIS(xOffset) = 4;
2410
    THIS(yOffset) = 4;
2411
    THIS(maxX) = 0;
2412
    THIS(maxY) = 0;
2413
    THIS(rootNode) = NULL;
2414
 
2415
    THIS(keepRandomPositions) = 0;
2416
    THIS(nodeNum) = 0;
2417
    THIS(nodes) = NULL;
2418
    THIS(edgeNum) = 0;
2419
    THIS(edges) = NULL;
2420
    THIS(topListNum) = 0;
2421
    THIS(topList) = NULL;
2422
    THIS(computeiconsize) = 0;
2423
    THIS(elementsPerLine) = 0;
2424
    THIS(hideEdges) = 0;
2425
    THIS(edgeHeight) = 2;
2426
    THIS(edgeOrder) = 0;
2427
    THIS(edgeWidth) = 0;
2428
    THIS(iconWidth) = 0;
2429
    THIS(iconHeight) = 0;
2430
    THIS(posX1) = 0;
2431
    THIS(posY1) = 0;
2432
    THIS(posX2) = 0;
2433
    THIS(posY2) = 0;
2434
        THIS(gridlock) = 0;
2435
#if 0
2436
    THIS(idlist) = NULL;
2437
#endif
2438
    THIS(maxXPosition) = 0.0;
2439
    THIS(maxYPosition) = 0.0;
2440
#if 1
2441
    THIS(layoutTypesNum) = 0;
2442
#else
2443
    THIS(layoutTypesNum) = 1;
2444
    THIS(layoutTypes) = (char **) ckalloc(2);
2445
    THIS(layoutTypes) = (char **) ckalloc(10);
2446
    *THIS(layoutTypes) = '\0';
2447
    *(1+THIS(layoutTypes))) = '\0';
2448
    *THIS(layoutTypes) = (char *) ckalloc(10);
2449
    strcpy(*THIS(layoutTypes), "icon");
2450
#endif
2451
    THIS(errmsg) = (char*)NULL;
2452
    return This;
2453
}
2454
 
2455
LayoutConfig
2456
GetLayoutConfig(This)
2457
        struct Layout_Graph* This;
2458
{
2459
    LayoutConfig c;
2460
    c.rootnode = THIS(rootNode)?NODE_ITEM(THIS(rootNode)):NULL;
2461
    c.graphorder = THIS(graphOrder);
2462
    c.nodespaceH = (long)THIS(iconSpaceH);
2463
    c.nodespaceV = (long)THIS(iconSpaceV);
2464
    c.xoffset = THIS(xOffset);
2465
    c.yoffset = THIS(yOffset);
2466
    c.computenodesize = THIS(computeiconsize);
2467
    c.elementsperline = THIS(elementsPerLine);
2468
    c.hideedges = THIS(hideEdges);
2469
    c.keeprandompositions = THIS(keepRandomPositions);
2470
    c.maxx = THIS(maxX);
2471
    c.maxy = THIS(maxY);
2472
    c.gridlock = THIS(gridlock);
2473
    return c;
2474
}
2475
 
2476
void
2477
SetLayoutConfig(This,c)
2478
        struct Layout_Graph* This;
2479
        LayoutConfig c;
2480
{
2481
    register int i;
2482
    THIS(graphOrder) = c.graphorder;
2483
    THIS(iconSpaceH) = c.nodespaceH;
2484
    THIS(iconSpaceV) = c.nodespaceV;
2485
    THIS(xOffset) = c.xoffset;
2486
    THIS(yOffset) = c.yoffset;
2487
    THIS(computeiconsize) = c.computenodesize;
2488
    THIS(elementsPerLine) = c.elementsperline;
2489
    THIS(hideEdges) = c.hideedges;
2490
    THIS(keepRandomPositions) = c.keeprandompositions;
2491
    THIS(maxX) = c.maxx;
2492
    THIS(maxY) = c.maxy;
2493
    THIS(gridlock) = c.gridlock;
2494
 
2495
    /* rootNode needs special work */
2496
    if(c.rootnode) {
2497
        FOR_ALL_NODES(i) {
2498
            if(NODE_ITEM(THIS(nodes)[i]) == c.rootnode) {
2499
                THIS(rootNode) = THIS(nodes)[i];
2500
            }
2501
        }
2502
    }
2503
}
2504
 
2505
int
2506
LayoutGetIthNode(This,index,idp)
2507
        struct Layout_Graph* This;
2508
        long index;
2509
        pItem* idp;
2510
{
2511
    if(index < 0 || index >= THIS(nodeNum)) return LAYOUT_ERROR;
2512
    *idp = NODE_ITEM(THIS(nodes)[index]);
2513
    return LAYOUT_OK;
2514
}
2515
 
2516
int
2517
LayoutGetNodeBBox(This,id,geomp)
2518
        struct Layout_Graph* This;
2519
        pItem id;
2520
        ItemGeom* geomp;
2521
{
2522
    register Node* ip = NULL;
2523
    register int i;
2524
 
2525
    /* find matching node */
2526
    FOR_ALL_NODES(i) {
2527
                if(NODE_ITEM(THIS(nodes)[i]) == id) {
2528
                        ip = THIS(nodes)[i];
2529
                        break; /* Khamis 11-oct-96 */
2530
                }
2531
    }
2532
    if(!ip) return LAYOUT_ERROR;
2533
    *geomp = NODE_GEOM(ip);
2534
    return LAYOUT_OK;
2535
}
2536
 
2537
int
2538
LayoutSetNodeBBox(This,id,geom)
2539
        struct Layout_Graph* This;
2540
        pItem id;
2541
        ItemGeom geom;
2542
{
2543
    register Node* ip = NULL;
2544
    register int i;
2545
 
2546
    /* find matching node */
2547
    FOR_ALL_NODES(i) {
2548
        if(NODE_ITEM(THIS(nodes)[i]) == id) {
2549
            ip = THIS(nodes)[i];
2550
            break; /* Khamis 11-oct-96 */
2551
        }
2552
    }
2553
    if(!ip) return LAYOUT_ERROR;
2554
    if(!DUMMY_NODE(ip)) {
2555
        SET_NODE_GEOM(ip,geom);
2556
        SET_NODE_HEIGHT(ip, CALC_NODE_HEIGHT(ip));
2557
        SET_NODE_WIDTH(ip, CALC_NODE_WIDTH(ip));
2558
    } else {
2559
        SET_NODE_HEIGHT(ip, 1);
2560
        SET_NODE_WIDTH(ip, 1);
2561
    }
2562
    return LAYOUT_OK;
2563
}
2564
 
2565
int
2566
LayoutGetIthEdge(This,index,idp)
2567
        struct Layout_Graph* This;
2568
        long index;
2569
        pItem* idp;
2570
{
2571
    if(index < 0 || index >= THIS(edgeNum)) return LAYOUT_ERROR;
2572
    *idp = EDGE_ITEM(THIS(edges)[index]);
2573
    return LAYOUT_OK;
2574
}
2575
 
2576
int
2577
LayoutGetEdgeEndPoints(This,id,geomp)
2578
        struct Layout_Graph* This;
2579
        pItem id;
2580
        ItemGeom* geomp;
2581
{
2582
    register Edge* ip = NULL;
2583
    register int i;
2584
 
2585
    /* find matching edge */
2586
    FOR_ALL_EDGES(i) {
2587
                if(EDGE_ITEM(THIS(edges)[i]) == id) {
2588
                    ip = THIS(edges)[i];
2589
                    break; /* Khamis 11-oct-96 */
2590
                }
2591
    }
2592
    if(!ip) return LAYOUT_ERROR;
2593
    *geomp = EDGE_GEOM(ip);
2594
    return LAYOUT_OK;
2595
}
2596
 
2597
int
2598
LayoutSetEdgeDim(This,id,geom)
2599
        struct Layout_Graph* This;
2600
        pItem id;
2601
        ItemGeom geom;
2602
{
2603
    register Edge* ip = NULL;
2604
    register int i;
2605
 
2606
    /* find matching edge */
2607
    FOR_ALL_EDGES(i) {
2608
        if(EDGE_ITEM(THIS(edges)[i]) == id) {
2609
            ip = THIS(edges)[i];
2610
            break; /* Khamis 11-oct-96 */
2611
        }
2612
    }
2613
    if(!ip) return LAYOUT_ERROR;
2614
    SET_EDGE_GEOM(ip,geom);
2615
    return LAYOUT_OK;
2616
}
2617
 
2618
char*
2619
LayoutGetError(This)
2620
        struct Layout_Graph* This;
2621
{
2622
    register char* msg = THIS(errmsg);
2623
    THIS(errmsg) = (char*)0;
2624
    return msg;
2625
}
2626
 
2627
 
2628
/* KHAMIS */
2629
 
2630
void * MY_EdgeFromNode (This, i)
2631
        struct Layout_Graph* This;
2632
        int i;
2633
{
2634
        return THIS(edges)[i]->fromNode;
2635
}
2636
 
2637
void * MY_EdgeToNode (This, i)
2638
        struct Layout_Graph* This;
2639
        int i;
2640
{
2641
        return THIS(edges)[i]->toNode;
2642
}
2643
 
2644
int MY_EdgeParentNum (This, i)
2645
        struct Layout_Graph* This;
2646
        int i;
2647
{
2648
        return THIS(edges)[i]->toNode->parentNum;
2649
}
2650
 
2651
void * MY_EdgeParent (This, i, num)
2652
        struct Layout_Graph* This;
2653
        int i;
2654
        int num;
2655
{
2656
        return THIS(edges)[i]->toNode->parent[num]->fromNode;
2657
}
2658
 
2659
int MY_EdgeSuccNum (This, i)
2660
        struct Layout_Graph* This;
2661
        int i;
2662
{
2663
        return THIS(edges)[i]->fromNode->succNum;
2664
}
2665
 
2666
void * MY_EdgeSucc (This, i, num)
2667
        struct Layout_Graph* This;
2668
        int i;
2669
{
2670
        return THIS(edges)[i]->fromNode->succ[num]->toNode;
2671
}
2672
 
2673
int MY_graphOrder (This)
2674
        struct Layout_Graph* This;
2675
{
2676
        return THIS(graphOrder);
2677
}
2678
 
2679
/* KHAMIS END */
2680
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.