annotate toolboxes/graph_visualisation/lib/lefty/dotty_edit.lefty @ 0:cc4b1211e677 tip

initial commit to HG from Changeset: 646 (e263d8a21543) added further path and more save "camirversion.m"
author Daniel Wolff
date Fri, 19 Aug 2016 13:07:06 +0200
parents
children
rev   line source
Daniel@0 1 #
Daniel@0 2 # dotty_edit: editing functions and data structures
Daniel@0 3 #
Daniel@0 4 dotty.protogt.getnodesbyattr = function (gt, key, val) {
Daniel@0 5 local nid, node, nlist;
Daniel@0 6
Daniel@0 7 nlist = [];
Daniel@0 8 for (nid in gt.graph.nodes) {
Daniel@0 9 node = gt.graph.nodes[nid];
Daniel@0 10 if (node.attr[key] == val)
Daniel@0 11 nlist[nid] = node;
Daniel@0 12 }
Daniel@0 13 return nlist;
Daniel@0 14 };
Daniel@0 15 dotty.protogt.reachablenodes = function (gt, node) {
Daniel@0 16 local nlist, stack, eid, edge, i;
Daniel@0 17
Daniel@0 18 stack[0] = node;
Daniel@0 19 i = 1;
Daniel@0 20 while (i > 0) {
Daniel@0 21 node = stack[i - 1];
Daniel@0 22 i = i - 1;
Daniel@0 23 nlist[node.nid] = node;
Daniel@0 24 for (eid in node.edges) {
Daniel@0 25 edge = node.edges[eid];
Daniel@0 26 if (~nlist[edge.head.nid]) {
Daniel@0 27 nlist[edge.head.nid] = edge.head;
Daniel@0 28 stack[i] = edge.head;
Daniel@0 29 i = i + 1;
Daniel@0 30 }
Daniel@0 31 }
Daniel@0 32 }
Daniel@0 33 return nlist;
Daniel@0 34 };
Daniel@0 35 dotty.protogt.mergegraph = function (gt, graph, show) {
Daniel@0 36 local nameid, onode, pos, size, eid, eid2, tnode, hnode, oedge;
Daniel@0 37
Daniel@0 38 if (~gt.noundo)
Daniel@0 39 gt.startadd2undo (gt);
Daniel@0 40 for (nameid in graph.nodedict) {
Daniel@0 41 pos = null;
Daniel@0 42 size = null;
Daniel@0 43 onode = graph.nodes[graph.nodedict[nameid]];
Daniel@0 44 if (onode.pos)
Daniel@0 45 pos = node.pos;
Daniel@0 46 if (onode.size)
Daniel@0 47 size = node.size;
Daniel@0 48 if (~(gt.graph.nodedict[nameid] >= 0)) {
Daniel@0 49 pos = null;
Daniel@0 50 size = null;
Daniel@0 51 if (onode.pos)
Daniel@0 52 pos = node.pos;
Daniel@0 53 if (onode.size)
Daniel@0 54 size = node.size;
Daniel@0 55 gt.insertnode (gt, pos, size, nameid, onode.attr, show);
Daniel@0 56 }
Daniel@0 57 }
Daniel@0 58 for (eid in graph.edges) {
Daniel@0 59 oedge = graph.edges[eid];
Daniel@0 60 tnode = gt.graph.nodes[gt.graph.nodedict[oedge.tail.name]];
Daniel@0 61 hnode = gt.graph.nodes[gt.graph.nodedict[oedge.head.name]];
Daniel@0 62 for (eid2 in tnode.edges)
Daniel@0 63 if (
Daniel@0 64 tnode.edges[eid2].tail == tnode &
Daniel@0 65 tnode.edges[eid2].head == hnode
Daniel@0 66 ) {
Daniel@0 67 oedge = null;
Daniel@0 68 break;
Daniel@0 69 }
Daniel@0 70 if (oedge)
Daniel@0 71 gt.insertedge (gt, tnode, null, hnode, null, oedge.attr, show);
Daniel@0 72 }
Daniel@0 73 if (~gt.noundo)
Daniel@0 74 gt.endadd2undo (gt);
Daniel@0 75 };
Daniel@0 76 dotty.protogt.insertsgraph = function (gt, name, attr, show) {
Daniel@0 77 local gid, sgraph, aid;
Daniel@0 78
Daniel@0 79 if (~gt)
Daniel@0 80 return null;
Daniel@0 81 gid = gt.graph.maxgid;
Daniel@0 82 if (~name) {
Daniel@0 83 while (gt.graph.graphdict[(name = concat ('g', gid))] >= 0)
Daniel@0 84 gid = gid + 1;
Daniel@0 85 } else if (gt.graph.graphdict[name]) {
Daniel@0 86 dotty.message (0, concat ('graph: ', name, ' exists'));
Daniel@0 87 return null;
Daniel@0 88 }
Daniel@0 89 gt.graph.graphdict[name] = gid;
Daniel@0 90 gt.graph.maxgid = gid + 1;
Daniel@0 91 gt.graph.graphs[gid] = [
Daniel@0 92 dotty.keys.gid = gid;
Daniel@0 93 dotty.keys.name = name;
Daniel@0 94 dotty.keys.gattr = copy (gt.graph.graphattr);
Daniel@0 95 dotty.keys.nattr = copy (gt.graph.nodeattr);
Daniel@0 96 dotty.keys.eattr = copy (gt.graph.edgeattr);
Daniel@0 97 ];
Daniel@0 98 sgraph = gt.graph.graphs[gid];
Daniel@0 99 if (~attr)
Daniel@0 100 attr = [];
Daniel@0 101 if (~attr.label)
Daniel@0 102 attr.label = '\N';
Daniel@0 103 for (aid in attr)
Daniel@0 104 sgraph.graphattr[aid] = attr[aid];
Daniel@0 105 gt.unpacksgraphattr (gt, sgraph);
Daniel@0 106 if (show)
Daniel@0 107 gt.drawsgraph (gt, gt.views, sgraph);
Daniel@0 108 return sgraph;
Daniel@0 109 };
Daniel@0 110 dotty.protogt.removesgraph = function (gt, sgraph) {
Daniel@0 111 gt.undrawsgraph (gt, gt.views, sgraph);
Daniel@0 112 remove (sgraph.name, gt.graph.graphdict);
Daniel@0 113 remove (sgraph.gid, gt.graph.graphs);
Daniel@0 114 };
Daniel@0 115 dotty.protogt.insertnode = function (gt, pos, size, name, attr, show) {
Daniel@0 116 local nid, node, aid;
Daniel@0 117
Daniel@0 118 nid = gt.graph.maxnid;
Daniel@0 119 if (~name) {
Daniel@0 120 while (gt.graph.nodedict[(name = concat ('n', nid))] >= 0)
Daniel@0 121 nid = nid + 1;
Daniel@0 122 } else if (gt.graph.nodedict[name] >= 0) {
Daniel@0 123 dotty.message (0, concat ('node: ', name, ' exists'));
Daniel@0 124 return null;
Daniel@0 125 }
Daniel@0 126 gt.graph.nodedict[name] = nid;
Daniel@0 127 gt.graph.maxnid = nid + 1;
Daniel@0 128 gt.graph.nodes[nid] = [
Daniel@0 129 dotty.keys.nid = nid;
Daniel@0 130 dotty.keys.name = name;
Daniel@0 131 dotty.keys.attr = copy (gt.graph.nodeattr);
Daniel@0 132 dotty.keys.edges = [];
Daniel@0 133 ];
Daniel@0 134 node = gt.graph.nodes[nid];
Daniel@0 135 if (~attr)
Daniel@0 136 attr = [];
Daniel@0 137 if (~attr.label)
Daniel@0 138 attr.label = '\N';
Daniel@0 139 for (aid in attr)
Daniel@0 140 node.attr[aid] = attr[aid];
Daniel@0 141 gt.unpacknodeattr (gt, node);
Daniel@0 142 if (~pos)
Daniel@0 143 pos = ['x' = 10; 'y' = 10;];
Daniel@0 144 node[dotty.keys.pos] = copy (pos);
Daniel@0 145 if (~size)
Daniel@0 146 size = ['x' = strlen (attr.label) * 30; 'y' = 30;];
Daniel@0 147 if (size.x == 0)
Daniel@0 148 size.x = 30;
Daniel@0 149 node[dotty.keys.size] = copy (size);
Daniel@0 150 node[dotty.keys.rect] = [
Daniel@0 151 0 = ['x' = pos.x - size.x / 2; 'y' = pos.y - size.y / 2;];
Daniel@0 152 1 = ['x' = pos.x + size.x / 2; 'y' = pos.y + size.y / 2;];
Daniel@0 153 ];
Daniel@0 154 node.draws = gt.simplenodedraw (node, pos, size);
Daniel@0 155 if (show)
Daniel@0 156 gt.drawnode (gt, gt.views, node);
Daniel@0 157 if (~gt.noundo) {
Daniel@0 158 gt.startadd2undo (gt);
Daniel@0 159 gt.currundo.inserted.nodes[nid] = node;
Daniel@0 160 gt.endadd2undo (gt);
Daniel@0 161 }
Daniel@0 162 return node;
Daniel@0 163 };
Daniel@0 164 dotty.protogt.removenode = function (gt, node) {
Daniel@0 165 local eid, list, edge, gid;
Daniel@0 166
Daniel@0 167 if (~gt.noundo)
Daniel@0 168 gt.startadd2undo (gt);
Daniel@0 169 for (eid in node.edges)
Daniel@0 170 list[eid] = node.edges[eid];
Daniel@0 171 for (eid in list)
Daniel@0 172 gt.removeedge (gt, list[eid]);
Daniel@0 173 gt.undrawnode (gt, gt.views, node);
Daniel@0 174 for (gid in gt.graph.graphs)
Daniel@0 175 remove (node.nid, gt.graph.graphs[gid].nodes);
Daniel@0 176 remove (node.name, gt.graph.nodedict);
Daniel@0 177 remove (node.nid, gt.graph.nodes);
Daniel@0 178 if (~gt.noundo) {
Daniel@0 179 gt.currundo.deleted.nodes[node.nid] = node;
Daniel@0 180 gt.endadd2undo (gt);
Daniel@0 181 }
Daniel@0 182 };
Daniel@0 183 dotty.protogt.insertedge = function (
Daniel@0 184 gt, nodea, porta, nodeb, portb, attr, show
Daniel@0 185 ) {
Daniel@0 186 local eid, edge, aid, tport, hport;
Daniel@0 187
Daniel@0 188 if (~nodea | ~nodeb)
Daniel@0 189 return null;
Daniel@0 190 if (porta)
Daniel@0 191 tport = porta;
Daniel@0 192 if (portb)
Daniel@0 193 hport = portb;
Daniel@0 194 eid = gt.graph.maxeid;
Daniel@0 195 while (gt.graph.edges[eid])
Daniel@0 196 eid = eid + 1;
Daniel@0 197 gt.graph.maxeid = eid + 1;
Daniel@0 198 gt.graph.edges[eid] = [
Daniel@0 199 dotty.keys.eid = eid;
Daniel@0 200 dotty.keys.tail = nodea;
Daniel@0 201 dotty.keys.tport = porta;
Daniel@0 202 dotty.keys.head = nodeb;
Daniel@0 203 dotty.keys.hport = portb;
Daniel@0 204 dotty.keys.attr = copy (gt.graph.edgeattr);
Daniel@0 205 ];
Daniel@0 206 edge = gt.graph.edges[eid];
Daniel@0 207 if (~attr)
Daniel@0 208 attr = [];
Daniel@0 209 for (aid in attr)
Daniel@0 210 edge.attr[aid] = attr[aid];
Daniel@0 211 nodea.edges[eid] = edge;
Daniel@0 212 nodeb.edges[eid] = edge;
Daniel@0 213 gt.unpackedgeattr (gt, edge);
Daniel@0 214 edge.draws = gt.simpleedgedraw (edge, nodea.pos, nodeb.pos);
Daniel@0 215 if (show)
Daniel@0 216 gt.drawedge (gt, gt.views, edge);
Daniel@0 217 if (~gt.noundo) {
Daniel@0 218 gt.startadd2undo (gt);
Daniel@0 219 gt.currundo.inserted.edges[eid] = edge;
Daniel@0 220 gt.endadd2undo (gt);
Daniel@0 221 }
Daniel@0 222 return edge;
Daniel@0 223 };
Daniel@0 224 dotty.protogt.removeedge = function (gt, edge) {
Daniel@0 225 local head, tail;
Daniel@0 226
Daniel@0 227 if (~gt.noundo)
Daniel@0 228 gt.startadd2undo (gt);
Daniel@0 229 if (edge.head.attr.support == 1)
Daniel@0 230 head = edge.head;
Daniel@0 231 if (edge.tail.attr.support == 1)
Daniel@0 232 if (head ~= edge.tail)
Daniel@0 233 tail = edge.tail;
Daniel@0 234 gt.undrawedge (gt, gt.views, edge);
Daniel@0 235 remove (edge.eid, edge.head.edges);
Daniel@0 236 remove (edge.eid, edge.tail.edges);
Daniel@0 237 remove (edge.eid, gt.graph.edges);
Daniel@0 238 if (head & tablesize (head.edges) == 0)
Daniel@0 239 gt.removenode (gt, head);
Daniel@0 240 if (tail & tablesize (tail.edges) == 0)
Daniel@0 241 gt.removenode (gt, tail);
Daniel@0 242 if (~gt.noundo) {
Daniel@0 243 gt.currundo.deleted.edges[edge.eid] = edge;
Daniel@0 244 gt.endadd2undo (gt);
Daniel@0 245 }
Daniel@0 246 };
Daniel@0 247 dotty.protogt.swapedgeids = function (gt, edge1, edge2) {
Daniel@0 248 local eid1, eid2;
Daniel@0 249
Daniel@0 250 if (edge1.eid == edge2.eid)
Daniel@0 251 return;
Daniel@0 252 if (~gt.noundo)
Daniel@0 253 gt.startadd2undo (gt);
Daniel@0 254 eid1 = edge1.eid;
Daniel@0 255 eid2 = edge2.eid;
Daniel@0 256 gt.graph.edges[eid1] = edge2;
Daniel@0 257 gt.graph.edges[eid2] = edge1;
Daniel@0 258 remove (eid1, edge1.tail.edges);
Daniel@0 259 remove (eid1, edge1.head.edges);
Daniel@0 260 remove (eid2, edge2.tail.edges);
Daniel@0 261 remove (eid2, edge2.head.edges);
Daniel@0 262 edge1.tail.edges[eid2] = edge1;
Daniel@0 263 edge1.head.edges[eid2] = edge1;
Daniel@0 264 edge2.tail.edges[eid1] = edge2;
Daniel@0 265 edge2.head.edges[eid1] = edge2;
Daniel@0 266 edge1.eid = eid2;
Daniel@0 267 edge2.eid = eid1;
Daniel@0 268 if (~gt.noundo) {
Daniel@0 269 gt.currundo.swapped.edges[eid1] = edge1;
Daniel@0 270 gt.currundo.swapped.edges[eid2] = edge2;
Daniel@0 271 gt.endadd2undo (gt);
Daniel@0 272 }
Daniel@0 273 };
Daniel@0 274 dotty.protogt.removesubtree = function (gt, obj) {
Daniel@0 275 local nlist, node, head, nid, edge, eid;
Daniel@0 276
Daniel@0 277 if (~gt.noundo)
Daniel@0 278 gt.startadd2undo (gt);
Daniel@0 279 if (obj.nid >= 0)
Daniel@0 280 node = obj;
Daniel@0 281 else if (obj.eid >= 0) {
Daniel@0 282 node = obj.head;
Daniel@0 283 gt.removeedge (gt, obj);
Daniel@0 284 if (~gt.graph.nodes[node.nid]) {
Daniel@0 285 if (~gt.noundo)
Daniel@0 286 gt.endadd2undo (gt);
Daniel@0 287 return;
Daniel@0 288 }
Daniel@0 289 for (eid in node.edges) {
Daniel@0 290 edge = node.edges[eid];
Daniel@0 291 if (edge.head == node & edge.tail ~= node) {
Daniel@0 292 if (~gt.noundo)
Daniel@0 293 gt.endadd2undo (gt);
Daniel@0 294 return;
Daniel@0 295 }
Daniel@0 296 }
Daniel@0 297 } else {
Daniel@0 298 dotty.message (0, 'bad object type in gt.removesubtree');
Daniel@0 299 return;
Daniel@0 300 }
Daniel@0 301 nlist = [node.nid = node;];
Daniel@0 302 while (node) {
Daniel@0 303 for (eid in node.edges) {
Daniel@0 304 head = node.edges[eid].head;
Daniel@0 305 if (head ~= node)
Daniel@0 306 nlist[head.nid] = head;
Daniel@0 307 }
Daniel@0 308 gt.removenode (gt, node);
Daniel@0 309 remove (node.nid, nlist);
Daniel@0 310 node = null;
Daniel@0 311 for (nid in nlist) {
Daniel@0 312 node = nlist[nid];
Daniel@0 313 for (eid in node.edges) {
Daniel@0 314 edge = node.edges[eid];
Daniel@0 315 if (edge.head == node & edge.tail ~= node) {
Daniel@0 316 node = null;
Daniel@0 317 break;
Daniel@0 318 }
Daniel@0 319 }
Daniel@0 320 if (node)
Daniel@0 321 break;
Daniel@0 322 }
Daniel@0 323 }
Daniel@0 324 if (~gt.noundo)
Daniel@0 325 gt.endadd2undo (gt);
Daniel@0 326 };
Daniel@0 327 dotty.protogt.removenodesbyattr = function (gt, key, val) {
Daniel@0 328 local nlist, nid;
Daniel@0 329
Daniel@0 330 if (~gt.noundo)
Daniel@0 331 gt.startadd2undo (gt);
Daniel@0 332 nlist = gt.getnodesbyattr (gt, key, val);
Daniel@0 333 for (nid in nlist)
Daniel@0 334 gt.removenode (gt, nlist[nid]);
Daniel@0 335 if (~gt.noundo)
Daniel@0 336 gt.endadd2undo (gt);
Daniel@0 337 };
Daniel@0 338 dotty.protogt.removesubtreesbyattr = function (gt, key, val) {
Daniel@0 339 local nlist, nid;
Daniel@0 340
Daniel@0 341 if (~gt.noundo)
Daniel@0 342 gt.startadd2undo (gt);
Daniel@0 343 nlist = gt.getnodesbyattr (gt, key, val);
Daniel@0 344 for (nid in nlist)
Daniel@0 345 if (gt.graph.nodes[nid])
Daniel@0 346 gt.removesubtree (gt, nlist[nid]);
Daniel@0 347 if (~gt.noundo)
Daniel@0 348 gt.endadd2undo (gt);
Daniel@0 349 };
Daniel@0 350 dotty.protogt.groupnodes = function (
Daniel@0 351 gt, nlist, gnode, pos, size, attr, keepmulti, show
Daniel@0 352 ) {
Daniel@0 353 local nid, node, elist, eid, edge, nodea, nodeb, inlist, outlist;
Daniel@0 354
Daniel@0 355 if (~nlist | tablesize (nlist) == 0)
Daniel@0 356 return;
Daniel@0 357 if (gnode.attr.support) {
Daniel@0 358 dotty.message (0, 'cannot group nodes in a support node');
Daniel@0 359 return;
Daniel@0 360 }
Daniel@0 361 if (~gt.noundo)
Daniel@0 362 gt.startadd2undo (gt);
Daniel@0 363 if (~gnode)
Daniel@0 364 gnode = gt.insertnode (gt, pos, size, null, attr, show);
Daniel@0 365 inlist = [];
Daniel@0 366 outlist = [];
Daniel@0 367 for (nid in nlist) {
Daniel@0 368 if ((node = nlist[nid]) == gnode)
Daniel@0 369 continue;
Daniel@0 370 elist = [];
Daniel@0 371 for (eid in node.edges)
Daniel@0 372 elist[eid] = node.edges[eid];
Daniel@0 373 for (eid in elist) {
Daniel@0 374 edge = elist[eid];
Daniel@0 375 if (edge.head == node) {
Daniel@0 376 nodea = edge.tail;
Daniel@0 377 nodeb = gnode;
Daniel@0 378 if (~keepmulti) {
Daniel@0 379 if (inlist[nodea.nid])
Daniel@0 380 continue;
Daniel@0 381 inlist[nodea.nid] = nodea;
Daniel@0 382 if (nodea == gnode)
Daniel@0 383 outlist[nodea.nid] = nodea;
Daniel@0 384 }
Daniel@0 385 } else {
Daniel@0 386 nodea = gnode;
Daniel@0 387 nodeb = edge.head;
Daniel@0 388 if (~keepmulti) {
Daniel@0 389 if (outlist[nodeb.nid])
Daniel@0 390 continue;
Daniel@0 391 outlist[nodeb.nid] = nodeb;
Daniel@0 392 if (nodeb == gnode)
Daniel@0 393 inlist[nodeb.nid] = nodeb;
Daniel@0 394 }
Daniel@0 395 }
Daniel@0 396 gt.insertedge (gt, nodea, null, nodeb, null, edge.attr, show);
Daniel@0 397 }
Daniel@0 398 gt.removenode (gt, node);
Daniel@0 399 }
Daniel@0 400 if (~gt.noundo)
Daniel@0 401 gt.endadd2undo (gt);
Daniel@0 402 return gnode;
Daniel@0 403 };
Daniel@0 404 dotty.protogt.groupnodesbyattr = function (
Daniel@0 405 gt, key, val, attr, keepmulti, show
Daniel@0 406 ) {
Daniel@0 407 local nlist, nid, pos, size;
Daniel@0 408
Daniel@0 409 pos = null;
Daniel@0 410 size = null;
Daniel@0 411 nlist = gt.getnodesbyattr (gt, key, val);
Daniel@0 412 if (show)
Daniel@0 413 for (nid in nlist) {
Daniel@0 414 pos = nlist[nid].pos;
Daniel@0 415 size = nlist[nid].size;
Daniel@0 416 break;
Daniel@0 417 }
Daniel@0 418 return gt.groupnodes (gt, nlist, null, pos, size, attr, keepmulti, show);
Daniel@0 419 };
Daniel@0 420 dotty.protogt.cut = function (gt, obj, set, mode, op) {
Daniel@0 421 local clipgt, list, node, nid, edge, eid, clipnode;
Daniel@0 422
Daniel@0 423 clipgt = dotty.clipgt;
Daniel@0 424 clipgt.graph = copy (dotty.protogt.graph);
Daniel@0 425 if (obj.eid >= 0) { # it's an edge
Daniel@0 426 list.edges[obj.eid] = obj;
Daniel@0 427 node = obj.head;
Daniel@0 428 } else if (obj.nid >= 0) {
Daniel@0 429 list.nodes[obj.nid] = obj;
Daniel@0 430 node = obj;
Daniel@0 431 for (eid in node.edges)
Daniel@0 432 list.edges[eid] = node.edges[eid];
Daniel@0 433 } else {
Daniel@0 434 dotty.message (0, 'unknown object type in gt.cut');
Daniel@0 435 return;
Daniel@0 436 }
Daniel@0 437 if (set == 'reachable') {
Daniel@0 438 list.nodes = gt.reachablenodes (gt, node);
Daniel@0 439 for (nid in list.nodes) {
Daniel@0 440 node = list.nodes[nid];
Daniel@0 441 for (eid in node.edges) {
Daniel@0 442 edge = node.edges[eid];
Daniel@0 443 list.edges[edge.eid] = edge;
Daniel@0 444 }
Daniel@0 445 }
Daniel@0 446 }
Daniel@0 447 if (mode == 'support') {
Daniel@0 448 for (eid in list.edges) {
Daniel@0 449 edge = list.edges[eid];
Daniel@0 450 if (~list.nodes[edge.tail.nid]) {
Daniel@0 451 list.support[edge.tail.nid] = edge.tail;
Daniel@0 452 list.nodes[edge.tail.nid] = edge.tail;
Daniel@0 453 }
Daniel@0 454 if (~list.nodes[edge.head.nid]) {
Daniel@0 455 list.support[edge.head.nid] = edge.head;
Daniel@0 456 list.nodes[edge.head.nid] = edge.head;
Daniel@0 457 }
Daniel@0 458 }
Daniel@0 459 }
Daniel@0 460 for (nid = 0; nid < gt.graph.maxnid; nid = nid + 1) {
Daniel@0 461 if (~list.nodes[nid])
Daniel@0 462 continue;
Daniel@0 463 node = list.nodes[nid];
Daniel@0 464 clipnode = gt.insertnode (clipgt, null, null, node.name, node.attr, 0);
Daniel@0 465 if (list.support[nid])
Daniel@0 466 clipnode.support = 1;
Daniel@0 467 list.clipnodes[nid] = clipnode;
Daniel@0 468 }
Daniel@0 469 for (eid = 0; eid < gt.graph.maxeid; eid = eid + 1) {
Daniel@0 470 if (~list.edges[eid])
Daniel@0 471 continue;
Daniel@0 472 edge = list.edges[eid];
Daniel@0 473 if (~list.nodes[edge.tail.nid] | ~list.nodes[edge.head.nid])
Daniel@0 474 continue;
Daniel@0 475 gt.insertedge (
Daniel@0 476 clipgt, list.clipnodes[edge.tail.nid], null,
Daniel@0 477 list.clipnodes[edge.head.nid], null, edge.attr, 0
Daniel@0 478 );
Daniel@0 479 }
Daniel@0 480 if (op ~= 'cut')
Daniel@0 481 return;
Daniel@0 482 if (~gt.noundo)
Daniel@0 483 gt.startadd2undo (gt);
Daniel@0 484 for (eid in list.edges)
Daniel@0 485 gt.removeedge (gt, list.edges[eid]);
Daniel@0 486 for (nid in list.nodes)
Daniel@0 487 if (~list.support[nid] & gt.graph.nodes[nid])
Daniel@0 488 gt.removenode (gt, list.nodes[nid]);
Daniel@0 489 if (~gt.noundo)
Daniel@0 490 gt.endadd2undo (gt);
Daniel@0 491 };
Daniel@0 492 dotty.protogt.paste = function (gt, pos, show) {
Daniel@0 493 local clipgt, offset, center, nid, node, eid, edge, nodes;
Daniel@0 494
Daniel@0 495 if (~gt.noundo)
Daniel@0 496 gt.startadd2undo (gt);
Daniel@0 497 clipgt = dotty.clipgt;
Daniel@0 498 if (clipgt.graph.rect)
Daniel@0 499 center = [
Daniel@0 500 'x' = (clipgt.graph.rect[1].x + clipgt.graph.rect[0].x) / 2;
Daniel@0 501 'y' = (clipgt.graph.rect[1].y + clipgt.graph.rect[0].y) / 2;
Daniel@0 502 ];
Daniel@0 503 else
Daniel@0 504 center = pos;
Daniel@0 505 offset = [
Daniel@0 506 'x' = center.x - pos.x;
Daniel@0 507 'y' = center.y - pos.y;
Daniel@0 508 ];
Daniel@0 509 for (nid = 0; clipgt.graph.nodes[nid]; nid = nid + 1) {
Daniel@0 510 node = clipgt.graph.nodes[nid];
Daniel@0 511 if (node.attr.label == '\N' | ~node.attr.label)
Daniel@0 512 node.attr.label = node.name;
Daniel@0 513 if (node.support == 1)
Daniel@0 514 nodes[nid] = gt.insertnode (gt, [
Daniel@0 515 'x' = node.pos.x - offset.x;
Daniel@0 516 'y' = node.pos.y - offset.y;
Daniel@0 517 ], null, null, [
Daniel@0 518 'support' = 1; 'shape' = 'circle';
Daniel@0 519 'label' = ''; 'width' = 0.2;
Daniel@0 520 ], show);
Daniel@0 521 else
Daniel@0 522 nodes[nid] = gt.insertnode (gt, [
Daniel@0 523 'x' = node.pos.x - offset.x;
Daniel@0 524 'y' = node.pos.y - offset.y;
Daniel@0 525 ], node.size, null, node.attr, show);
Daniel@0 526 }
Daniel@0 527 for (eid = 0; clipgt.graph.edges[eid]; eid = eid + 1) {
Daniel@0 528 edge = clipgt.graph.edges[eid];
Daniel@0 529 gt.insertedge (
Daniel@0 530 gt, nodes[edge.tail.nid], null,
Daniel@0 531 nodes[edge.head.nid], null, edge.attr, show
Daniel@0 532 );
Daniel@0 533 }
Daniel@0 534 if (~gt.noundo)
Daniel@0 535 gt.endadd2undo (gt);
Daniel@0 536 };
Daniel@0 537 dotty.protogt.startadd2undo = function (gt) {
Daniel@0 538 if (~gt.undoarray.level)
Daniel@0 539 gt.currundo = (
Daniel@0 540 gt.undoarray.entries[tablesize (gt.undoarray.entries)] = []
Daniel@0 541 );
Daniel@0 542 gt.undoarray.level = gt.undoarray.level + 1;
Daniel@0 543 };
Daniel@0 544 dotty.protogt.endadd2undo = function (gt) {
Daniel@0 545 gt.undoarray.level = gt.undoarray.level - 1;
Daniel@0 546 };
Daniel@0 547 dotty.protogt.undo = function (gt, show) {
Daniel@0 548 local entry, n, eid, edge, nid, node, edges;
Daniel@0 549
Daniel@0 550 if ((n = tablesize (gt.undoarray.entries)) < 1)
Daniel@0 551 return;
Daniel@0 552 entry = gt.undoarray.entries[n - 1];
Daniel@0 553 remove (n - 1, gt.undoarray.entries);
Daniel@0 554 remove ('currundo', gt);
Daniel@0 555 gt.noundo = 1;
Daniel@0 556 # hardwire nodes and edges back with the same id's as the originals
Daniel@0 557 for (nid in entry.deleted.nodes) {
Daniel@0 558 node = entry.deleted.nodes[nid];
Daniel@0 559 gt.graph.nodedict[node.name] = node.nid;
Daniel@0 560 gt.graph.nodes[node.nid] = node;
Daniel@0 561 node.edges = [];
Daniel@0 562 if (show)
Daniel@0 563 gt.drawnode (gt, gt.views, node);
Daniel@0 564 }
Daniel@0 565 for (eid in entry.deleted.edges) {
Daniel@0 566 edge = entry.deleted.edges[eid];
Daniel@0 567 gt.graph.edges[edge.eid] = edge;
Daniel@0 568 edge.head.edges[edge.eid] = edge;
Daniel@0 569 edge.tail.edges[edge.eid] = edge;
Daniel@0 570 if (show)
Daniel@0 571 gt.drawedge (gt, gt.views, edge);
Daniel@0 572 }
Daniel@0 573 if (entry.swapped.edges) {
Daniel@0 574 if (tablesize (entry.swapped.edges) == 2) {
Daniel@0 575 n = 0;
Daniel@0 576 for (eid in entry.swapped.edges) {
Daniel@0 577 edges[n] = entry.swapped.edges[eid];
Daniel@0 578 n = n + 1;
Daniel@0 579 }
Daniel@0 580 gt.swapedgeids (gt, edges[0], edges[1]);
Daniel@0 581 } else
Daniel@0 582 dotty.message (0, 'cannot handle undoing swap of > 2 edges');
Daniel@0 583 }
Daniel@0 584 for (eid in entry.inserted.edges) {
Daniel@0 585 edge = entry.inserted.edges[eid];
Daniel@0 586 gt.removeedge (gt, edge);
Daniel@0 587 }
Daniel@0 588 for (nid in entry.inserted.nodes) {
Daniel@0 589 node = entry.inserted.nodes[nid];
Daniel@0 590 gt.removenode (gt, node);
Daniel@0 591 }
Daniel@0 592 gt.noundo = 0;
Daniel@0 593 };