home *** CD-ROM | disk | FTP | other *** search
- /**
- GRAB Graph Layout and Browser System
-
- Copyright (c) 1986, 1988 Regents of the University of California
- Copyright (c) 1989, Tera Computer Company
- **/
-
- /**
- Routines to insert an arc. This can be tricky, since certain arcs
- are illegal. Also, if there's already an arc between two nodes, a new
- one must follow the same path as the old ones
- **/
-
- #include "malloc.h"
- #include "attribute.h"
- #include "digraph.h"
- #include "screen.h"
- #include "globals.h"
- #include "scrdep.h"
- #include "interf.h"
- #include "tedge.h"
- #include "clip.h"
-
- NODE *CreateDummy(), *get_next_node(), *next_dummy();
- NODE *get_prev_node();
- BOOL DoInsArcEnd();
- char *UniqueName();
- BOOL on_screen();
- OUTEDGE *get_edge();
- INEDGE *get_in_edge();
-
- static NODE *start, *end, *firstnode;
- static NODE **addedN = NULL; /* keep track of what dummy nodes were added */
- static int num_added;
-
- BOOL DoSetUpInsArc()
- /* return FALSE if you can't add an arc from here */
- {
- start = (NODE *) ICurNode();
-
- if (Coalescer(start))
- /**
- Disallow edges from coalescer nodes
- **/
- {
- IChangeStatusLine("Cannot add edge from coalescer node", FALSE);
- return FALSE;
- }
- else
- {
- firstnode = start;
- num_added = 0;
-
- if (addedN != NULL)
- {
- dispose(addedN);
- addedN = NULL;
- }
-
- IChangeStatusLine("Inserting arc ...", TRUE);
- return TRUE;
- }
- }
-
- BOOL DoInsArcEnd()
- {
- int ax, ay, curx, cury;
-
- if (start == NULL)
- /* this better not happen */
- {
- return TRUE;
- }
-
- IGetCurPos(&curx, &cury);
- ax = SCRX_TO_ABSX(&screen, curx);
- ay = SCRY_TO_ABSY(&screen, cury);
-
- /**
- check if on node. if yes, put new edge in edgelist. if not,
- set down dummy node and make it the new start node.
- **/
- if ((end = (NODE *) ICurNode()) == NULL)
- /* dropping on a vacant spot */
- {
- end = CreateDummy(digraph, ax, ay);
- ScrAddDummy (end, 1, &screen, TRUE);
- (void) CreateEdge(digraph, start, end);
- ScrAddEdge(digraph, start, end, &screen, TRUE);
-
- /* keep a record of what was added */
- num_added++;
-
- if (addedN == NULL)
- {
- addedN = (NODE **) malloc(sizeof(NODE *));
- }
- else
- {
- addedN = (NODE **) realloc((char *) addedN,
- num_added * sizeof(NODE *));
- }
-
- addedN[num_added - 1] = end;
- start = end;
- return FALSE;
- }
- else if (Is_dummy(end)) /* Trying to drop on a dummy */
- {
- IChangeStatusLine(
- "Can't end arc on a dummy node. Insertion aborted", FALSE);
- DeleteAdded(firstnode, addedN, num_added);
- return TRUE;
- }
- else if (Coalescer(end)) /* trying to drop on a coalescer */
- {
- IChangeStatusLine(
- "Can't end arc on a coalescer node. Insertion aborted", FALSE);
- DeleteAdded(firstnode, addedN, num_added);
- return TRUE;
- }
- else if (firstnode == end)
- {
- /* can't start and finish in the same place */
- IChangeStatusLine(
- "Can't draw an edge to the same node. Insertion aborted",
- FALSE);
- DeleteAdded(firstnode, addedN, num_added);
- return TRUE;
- }
- else
- {
- /* dropping on a node */
-
- /**
- if there are edges already between the beginning and ending node,
- make this one follow their path
- **/
- if (num_edges(firstnode, end) != 0)
- {
- DeleteAdded(firstnode, addedN, num_added);
- new_follow_edge(firstnode, end, FALSE);
- }
- else if (num_edges(end, firstnode) != 0)
- {
- DeleteAdded(firstnode, addedN, num_added);
- new_follow_edge(end, firstnode, TRUE);
- }
- else /* this is new, so can leave it as is */
- {
- (void) CreateEdge(digraph, start, end);
-
- if (start != firstnode)
- /* dummies were added between */
- {
- char **attr;
- int i;
-
- ScrAddEdge(digraph, start, end, &screen, TRUE);
-
- /**
- create in_edge & out_edge between the 2 non-dummies.
- We don't want to fool around with the prev&succ set.
- Give it null edge attributes.
- **/
-
- attr = (char **) malloc (NEdgeAttr(digraph) * sizeof(char *));
-
- for (i = 0; i < NEdgeAttr(digraph); i++)
- {
- strsave(attr[i], NULL_STRING);
- }
-
- add_out_edge(firstnode, attr, DEFAULT_BRUSH, DEFAULT_COLOR,
- Vno(end), 1);
- add_in_edge(end, Vno(firstnode), 1);
- }
- else
- {
- draw_edge(digraph, get_edge(digraph, start, end, 1),
- start, end, 1, &screen, TRUE);
- }
- }
-
- start = NULL;
- num_added = 0;
- EndInsertArc();
- return TRUE;
- }
- }
-
- EndInsertArc()
- {
- IChangeStatusLine("End arc insertion", FALSE);
- graphChanged = TRUE;
- ckpt_done = FALSE;
- }
-
- DeleteAdded(start, nodes, num_nodes)
- NODE *start, **nodes;
- int num_nodes;
- /**
- for whatever reason, we want to delete the chain of edges and dummy
- nodes we've just added
- **/
- {
- int i;
- int ord = 1;
-
- if (num_nodes != 0)
- {
- IDelEdge((char *) start, (char *) nodes[0], ord);
- remove_link(start, nodes[0]);
-
- for (i = 1; i < num_nodes; i++)
- {
- IDelEdge((char *) nodes[i-1], (char *) nodes[i], ord);
- remove_link(nodes[i-1], nodes[i]);
- IDelNode((char *) nodes[i-1], ord);
- dispose_node(digraph, nodes[i-1]);
- }
-
- IDelNode((char *) nodes[num_nodes-1], ord);
- dispose_node(digraph, nodes[num_nodes-1]);
- }
- }
-
- new_follow_edge(fromnode, tonode, reversed)
- NODE *fromnode, *tonode;
- BOOL reversed;
- /**
- we know there's an edge from fromnode to tonode. 'Follow' it (go
- to the same dummy nodes, if any, etc.) Since an edge exists already,
- there's no need to add any links, just add the in and out edges and
- draw them on the screen
- **/
- {
- char **attr;
- int ord, i;
- OUTEDGE *outedge;
- INEDGE *inedge;
- VNO to_vno;
- NODE *nextnode, *prevnode;
-
- attr = (char **) malloc (NEdgeAttr(digraph) * sizeof(char *));
- ord = max_edges(fromnode, tonode) + 1;
-
- for (i = 0; i < NEdgeAttr(digraph); i++)
- {
- strsave(attr[i], NULL_STRING);
- }
-
- add_out_edge(fromnode, attr, DEFAULT_BRUSH, DEFAULT_COLOR,
- Vno(tonode), ord);
- add_in_edge(tonode, Vno(fromnode), ord);
-
- if (reversed)
- {
- outedge = get_edge(digraph, fromnode, tonode, ord);
- inedge = get_in_edge(digraph, fromnode, tonode, ord);
- Edge_reversed(outedge) = TRUE;
- Edge_reversed(inedge) = TRUE;
- }
-
- nextnode = NULL;
-
- each_element(Succ_set(fromnode), to_vno)
- loop
- /* look for a dummy node between fromnode and tonode */
-
- if (Is_dummy(Node(digraph, to_vno)) &&
- get_next_node(digraph, Node(digraph, to_vno)) == tonode)
- {
- nextnode = Node(digraph, to_vno);
- draw_edge(digraph, get_edge(digraph, fromnode, nextnode, ord),
- fromnode, nextnode, ord, &screen, TRUE);
-
- do
- {
- ScrAddDummy(nextnode, ord, &screen, TRUE);
- prevnode = nextnode;
- nextnode = next_dummy(digraph, nextnode);
- draw_edge(digraph, get_edge(digraph, prevnode, nextnode, ord),
- prevnode, nextnode, ord, &screen, TRUE);
- } while (Is_dummy(nextnode));
-
- break;
- }
- endloop;
-
- if (nextnode == NULL)
- {
- draw_edge(digraph, get_edge(digraph, fromnode, tonode, ord),
- fromnode, tonode, ord, &screen, TRUE);
- }
- }
-
- NODE *CreateDummy(digraph, x_pos, y_pos)
- DIGRAPH *digraph;
- int x_pos, y_pos;
- /* Create a dummy node at (x_pos, y_pos) */
- {
- NODE *node, *CreateNode();
- char name[MAXSTR];
-
- strcpy(name, UniqueName());
-
- node = CreateNode(digraph, name, NULL_STRING, x_pos, y_pos);
- Status(node) = DUMMY;
- Shape(node) = POINT;
- Half_width(node) = DUMMY_HALF_WIDTH;
- Half_height(node) = 0;
- return (node);
- }
-
- ScrAddEdge(digraph, fromnode, tonode, screen, draw)
- DIGRAPH *digraph;
- NODE *fromnode, *tonode;
- SCREEN *screen;
- BOOL draw;
- /**
- add an edge to the screen from fromnode to tonode. No edges
- exist between these two nodes. Looks a lot like draw_edge, but
- we can't use drawedge becase tonode could be a dummy node
- without a successor (which would make draw_edge core dump)
- **/
- {
- double from_x; /* x-coordinate of start of edge */
- double from_y; /* y-coordinates of start of edge */
- double to_x; /* x-coordinate of end of edge */
- double to_y; /* y-coordinates of end of edge */
- NODE *prevnode;
- TEDGE *edge;
- BOOL parrow, reversed;
- BRUSH brush;
- COLOR color;
-
- parrow = FALSE;
- reversed = FALSE;
-
- edge = (TEDGE *) malloc(sizeof(TEDGE));
- strsave(edge->label, NULL_STRING); /* no label yet */
- edge->tonode = (char *) tonode;
- edge->fromnode = (char *) fromnode;
- edge->ord = 1;
-
- /* clip in both directions */
- Clip(fromnode, tonode, edge->ord, &from_x, &from_y, &to_x, &to_y, screen);
-
- if (!Is_dummy(tonode))
- {
- if (outedge_reversed(digraph, fromnode, tonode, edge->ord))
- {
- parrow = TRUE;
- reversed = TRUE;
- }
- else
- {
- if (Is_dummy(fromnode))
- {
- prevnode = get_prev_node(digraph, fromnode);
- }
- else
- {
- prevnode = fromnode;
- }
-
- if (!outedge_reversed(digraph, prevnode, tonode, edge->ord))
- {
- parrow = TRUE;
- }
- }
- }
-
- brush = DEFAULT_BRUSH;
- color = DEFAULT_COLOR;
-
- if (reversed)
- {
- IAddEdge(
- (int) ABSX_TO_SCRX(screen, to_x),
- (int) ABSY_TO_SCRY(screen, to_y),
- (int) ABSX_TO_SCRX(screen, from_x),
- (int) ABSY_TO_SCRY(screen, from_y),
- parrow, (char *) edge, edge->label, brush, color, draw, edge->ord);
- }
- else
- {
- IAddEdge(
- (int) ABSX_TO_SCRX(screen, from_x),
- (int) ABSY_TO_SCRY(screen, from_y),
- (int) ABSX_TO_SCRX(screen, to_x),
- (int) ABSY_TO_SCRY(screen, to_y),
- parrow, (char *) edge, edge->label, brush, color, draw, edge->ord);
- }
- }
-
- ScrAddDummy(node, ord, screen, draw)
- NODE *node; /* node to draw */
- int ord; /* ordinality of dummy node */
- SCREEN *screen; /* window information */
- BOOL draw; /* draw it now, or wait? */
- /**
- much like draw_node, except we assume a lot of values. This should be a
- newly added dummy node
- **/
- {
- char *text;
- char upbc[20]; /* up or down bc */
- char downbc[20]; /* up or down bc */
-
- if (on_screen(node))
- {
- int shift;
-
- strsave(text, NULL_STRING);
- strcpy(upbc, NULL_STRING);
- strcpy(downbc, NULL_STRING);
-
- shift = ORD_TO_SHIFT(ord);
-
- if (markDummyNodes)
- {
- IAddNode ((int) ABSX_TO_SCRX(screen, X_position(node) + shift),
- (int) ABSY_TO_SCRY(screen, Y_position(node)),
- 1, 1,
- RECTANGLE, text, Is_dummy(node),
- (char *) node, upbc, downbc,
- Brush(node), Color(node), draw, ord);
- }
- else
- {
- IAddNode ((int) ABSX_TO_SCRX(screen, X_position(node) + shift),
- (int) ABSY_TO_SCRY(screen, Y_position(node)),
- 0, 0,
- POINT, text, Is_dummy(node),
- (char *) node, upbc, downbc,
- Brush(node), Color(node), draw, ord);
- }
- }
- } /* ScrAddDummy */
-