# # dotty_draw: drawing functions and data structures # dotty.protogt.drawgraph = function (gt, views) { local gid, eid, nid, graph; graph = gt.graph; gt.drawsgraph (gt, views, graph); for (gid in graph.graphs) gt.drawsgraph (gt, views, graph.graphs[gid]); for (eid in graph.edges) gt.drawedge (gt, views, graph.edges[eid]); for (nid in graph.nodes) gt.drawnode (gt, views, graph.nodes[nid]); }; dotty.protogt.redrawgraph = function (gt, views) { local vid; for (vid in views) clear (views[vid].canvas); gt.drawgraph (gt, views); }; dotty.protogt.setviewsize = function (views, r) { local vid, vt, w2v, scale, attr; for (vid in views) { vt = views[vid]; vt.wrect = copy (r); if (r[1].x == 0 | r[1].y == 0) { attr = getwidgetattr (vt.scroll, [0 = 'size';]); vt.wrect[1] = copy (attr.size); } if (vt.type == 'birdseye') { attr = getwidgetattr (vt.scroll, [0 = 'size';]); scale.x = (vt.wrect[1].x - vt.wrect[0].x) / attr.size.x; scale.y = (vt.wrect[1].y - vt.wrect[0].y) / attr.size.y; if (scale.x > 1 & scale.x > scale.y) vt.w2v = scale.x; else if (scale.y > 1) vt.w2v = scale.y; else vt.w2v = 1; } w2v = vt.w2v; vt.vsize = [ 'x' = (vt.wrect[1].x - vt.wrect[0].x) / w2v; 'y' = (vt.wrect[1].y - vt.wrect[0].y) / w2v; ]; setwidgetattr (vt.canvas, [ 'window' = vt.wrect; 'viewport' = vt.vsize; ]); } }; dotty.protogt.setviewscale = function (views, factor) { local vid, vt, w2v; for (vid in views) { vt = views[vid]; if ((w2v = vt.w2v * factor) < 0.01) { dotty.message (0, 'cannot zoom any closer'); return; } vt.w2v = w2v; vt.vsize = [ 'x' = (vt.wrect[1].x - vt.wrect[0].x) / w2v; 'y' = (vt.wrect[1].y - vt.wrect[0].y) / w2v; ]; setwidgetattr (vt.canvas, ['viewport' = vt.vsize;]); } }; dotty.protogt.setviewcenter = function (views, center) { local vid, vt, pos; for (vid in views) { vt = views[vid]; pos = [ 'x' = center.x * vt.vsize.x / (vt.wrect[1].x - vt.wrect[0].x); 'y' = (vt.wrect[1].y - center.y) * vt.vsize.y / (vt.wrect[1].y - vt.wrect[0].y); ]; setwidgetattr (vt.scroll, ['childcenter' = pos;]); } }; dotty.protogt.drawsgraph = function (gt, views, sgraph) { local vid, canvas, pos; sgraph.draw = 1; if (~sgraph.rect[0] | sgraph.graphattr.style == 'invis') return; for (vid in views) { canvas = views[vid].canvas; if (~sgraph.type) # 'type' only exists on top level box (canvas, null, sgraph.rect, ['color' = sgraph.color;]); if (sgraph.graphattr.label) { if (sgraph.lp.x >= 0) { pos = sgraph.lp; text (canvas, null, pos, sgraph.graphattr.label, sgraph.fontname, sgraph.fontsize, 'cc', ['color' = sgraph.fontcolor;]); } else { pos = ['x' = sgraph.rect[0].x; 'y' = sgraph.rect[1].y;]; text (canvas, null, pos, sgraph.graphattr.label, sgraph.fontname, sgraph.fontsize, 'ld', ['color' = sgraph.fontcolor;]); } } } }; dotty.protogt.undrawsgraph = function (gt, views, sgraph) { local vid, canvas, pos; if (~sgraph.drawn) return; sgraph.drawn = 0; if (~sgraph.rect[0] | sgraph.graphattr.style == 'invis') return; for (vid in views) { canvas = views[vid].canvas; if (~sgraph.type) # 'type' only exists on top level box (canvas, null, sgraph.rect, ['color' = 0;]); if (sgraph.graphattr.label) { if (sgraph.lp.x >= 0) { pos = sgraph.lp; text (canvas, null, pos, sgraph.graphattr.label, sgraph.fontname, sgraph.fontsize, 'cc', ['color' = 0;]); } else { pos = ['x' = sgraph.rect[0].x; 'y' = sgraph.rect[1].y;]; text (canvas, null, pos, sgraph.graphattr.label, sgraph.fontname, sgraph.fontsize, 'ld', ['color' = 0;]); } } clearpick (canvas, sgraph); } }; dotty.protogt.drawnode = function (gt, views, node) { local vid, func, pos, size, rect; node.drawn = 1; if (~node.pos) return; if (node.attr.style == 'invis') { pos = node.pos; size = node.size; rect[0] = ['x' = pos.x - size.x / 2; 'y' = pos.y - size.y / 2;]; rect[1] = ['x' = rect[0].x + size.x; 'y' = rect[0].y + size.y;]; for (vid in views) setpick (views[vid].canvas, node, rect); return; } if (~(func = gt.shapefunc[node.attr.shape])) func = gt.shapefunc['box']; for (vid in views) func (gt, views[vid].canvas, node); }; dotty.protogt.undrawnode = function (gt, views, node) { local vid, func, pos, size, rect, color, fontcolor, outlinecolor; if (~node.drawn) return; node.drawn = 0; if (~node.pos) return; if (node.attr.style == 'invis') { pos = node.pos; size = node.size; rect[0] = ['x' = pos.x - size.x / 2; 'y' = pos.y - size.y / 2;]; rect[1] = ['x' = rect[0].x + size.x; 'y' = rect[0].y + size.y;]; for (vid in views) clearpick (views[vid].canvas, node); return; } color = node.color; node.color = 0; fontcolor = node.fontcolor; node.fontcolor = 0; outlinecolor = dotty.outlinecolor; dotty.outlinecolor = 0; if (~(func = gt.shapefunc[node.attr.shape])) func = gt.shapefunc['box']; for (vid in views) { func (gt, views[vid].canvas, node); clearpick (views[vid].canvas, node); } node.color = color; node.fontcolor = fontcolor; dotty.outlinecolor = outlinecolor; }; dotty.protogt.shapefunc.record = function (gt, canvas, node) { local rect, pos, size; pos = node.pos; size = node.size; rect[0] = ['x' = pos.x - size.x / 2; 'y' = pos.y - size.y / 2;]; rect[1] = ['x' = rect[0].x + size.x; 'y' = rect[0].y + size.y;]; if (node.attr.style == 'filled') { box (canvas, node, rect, ['color' = node.color; 'fill' = 'on';]); box (canvas, node, rect, ['color' = dotty.outlinecolor;]); } gt.shapefunc.rfields (gt, canvas, node, node.fields); setpick (canvas, node, rect); }; dotty.protogt.shapefunc.rfields = function (gt, canvas, node, fields) { local fid, field, pos, label; for (fid in fields) { field = fields[fid]; if (field.fields) gt.shapefunc.rfields (gt, canvas, node, field.fields); else { if (node.attr.style == 'filled') box (canvas, null, field.rect, ['color' = dotty.outlinecolor;]); else box (canvas, null, field.rect, ['color' = node.color;]); pos.x = (field.rect[1].x + field.rect[0].x) / 2; pos.y = (field.rect[1].y + field.rect[0].y) / 2; if (~(label = field.text) | label == '\N') label = node.name; text (canvas, null, pos, label, node.fontname, node.fontsize, 'cc', ['color' = node.fontcolor;]); } } }; dotty.protogt.shapefunc.plaintext = function (gt, canvas, node) { local pos, size, label, rect; pos = node.pos; size = node.size; if (~(label = node.attr.label) | label == '\N') label = node.name; rect[0] = ['x' = pos.x - size.x / 2; 'y' = pos.y - size.y / 2;]; rect[1] = ['x' = rect[0].x + size.x; 'y' = rect[0].y + size.y;]; setpick (canvas, node, rect); text (canvas, null, pos, label, node.fontname, node.fontsize, 'cc', ['color' = node.fontcolor;]); }; dotty.protogt.shapefunc.box = function (gt, canvas, node) { local pos, size, label, rect; pos = node.pos; size = node.size; if (~(label = node.attr.label) | label == '\N') label = node.name; rect[0] = ['x' = pos.x - size.x / 2; 'y' = pos.y - size.y / 2;]; rect[1] = ['x' = rect[0].x + size.x; 'y' = rect[0].y + size.y;]; if (node.attr.style == 'filled') { box (canvas, node, rect, ['color' = node.color; 'fill' = 'on';]); box (canvas, node, rect, ['color' = dotty.outlinecolor;]); } else box (canvas, node, rect, ['color' = node.color;]); text (canvas, null, pos, label, node.fontname, node.fontsize, 'cc', ['color' = node.fontcolor;]); }; dotty.protogt.shapefunc.Msquare = function (gt, canvas, node) { local pos, size, label, rect, color; pos = node.pos; size = node.size; if (~(label = node.attr.label) | label == '\N') label = node.name; rect[0] = ['x' = pos.x - size.x / 2; 'y' = pos.y - size.y / 2;]; rect[1] = ['x' = rect[0].x + size.x; 'y' = rect[0].y + size.y;]; if (node.attr.style == 'filled') { box (canvas, node, rect, ['color' = node.color; 'fill' = 'on';]); color = dotty.outlinecolor; box (canvas, node, rect, ['color' = color;]); line (canvas, null, ['x' = rect[0].x; 'y' = rect[0].y + 10;], ['x' = rect[0].x + 10; 'y' = rect[0].y;], ['color' = color;]); line (canvas, null, ['x' = rect[0].x; 'y' = rect[1].y - 10;], ['x' = rect[0].x + 10; 'y' = rect[1].y;], ['color' = color;]); line (canvas, null, ['x' = rect[1].x; 'y' = rect[0].y + 10;], ['x' = rect[1].x - 10; 'y' = rect[0].y;], ['color' = color;]); line (canvas, null, ['x' = rect[1].x; 'y' = rect[1].y - 10;], ['x' = rect[1].x - 10; 'y' = rect[1].y;], ['color' = color;]); } else { color = node.color; box (canvas, node, rect, ['color' = color;]); line (canvas, null, ['x' = rect[0].x; 'y' = rect[0].y + 10;], ['x' = rect[0].x + 10; 'y' = rect[0].y;], ['color' = color;]); line (canvas, null, ['x' = rect[0].x; 'y' = rect[1].y - 10;], ['x' = rect[0].x + 10; 'y' = rect[1].y;], ['color' = color;]); line (canvas, null, ['x' = rect[1].x; 'y' = rect[0].y + 10;], ['x' = rect[1].x - 10; 'y' = rect[0].y;], ['color' = color;]); line (canvas, null, ['x' = rect[1].x; 'y' = rect[1].y - 10;], ['x' = rect[1].x - 10; 'y' = rect[1].y;], ['color' = color;]); } text (canvas, null, pos, label, node.fontname, node.fontsize, 'cc', ['color' = node.fontcolor;]); }; dotty.protogt.shapefunc.ellipse = function (gt, canvas, node) { local pos, size, label; pos = node.pos; size.x = node.size.x / 2; size.y = node.size.y / 2; if (~(label = node.attr.label) | label == '\N') label = node.name; if (node.attr.style == 'filled') { if (node.attr.shape == 'doublecircle') { arc (canvas, node, pos, size, ['color' = dotty.outlinecolor;]); size.x = size.x - 4; size.y = size.y - 4; } arc (canvas, node, pos, size, ['color' = node.color; 'fill' = 'on';]); arc (canvas, node, pos, size, ['color' = dotty.outlinecolor;]); } else { if (node.attr.shape == 'doublecircle') { arc (canvas, node, pos, size, ['color' = node.color;]); size.x = size.x - 4; size.y = size.y - 4; } arc (canvas, node, pos, size, ['color' = node.color;]); } text (canvas, null, pos, label, node.fontname, node.fontsize, 'cc', ['color' = node.fontcolor;]); }; dotty.protogt.shapefunc.circle = dotty.protogt.shapefunc.ellipse; dotty.protogt.shapefunc.doublecircle = dotty.protogt.shapefunc.ellipse; dotty.protogt.shapefunc.diamond = function (gt, canvas, node) { local pos, size, label, p, rect; pos = node.pos; size = node.size; if (~(label = node.attr.label) | label == '\N') label = node.name; p[0] = ['x' = pos.x; 'y' = pos.y + size.y / 2;]; p[1] = ['x' = pos.x + size.x / 2; 'y' = pos.y;]; p[2] = ['x' = pos.x; 'y' = pos.y - size.y / 2;]; p[3] = ['x' = pos.x - size.x / 2; 'y' = pos.y;]; p[4] = p[0]; rect[0] = ['x' = pos.x - size.x / 2; 'y' = pos.y - size.y / 2;]; rect[1] = ['x' = rect[0].x + size.x; 'y' = rect[0].y + size.y;]; if (node.attr.style == 'filled') { polygon (canvas, node, p, ['color' = node.color; 'fill' = 'on';]); polygon (canvas, node, p, ['color' = dotty.outlinecolor;]); } else polygon (canvas, node, p, ['color' = node.color;]); setpick (canvas, node, rect); text (canvas, null, pos, label, node.fontname, node.fontsize, 'cc', ['color' = node.fontcolor;]); }; dotty.protogt.shapefunc.parallelogram = function (gt, canvas, node) { local pos, size, label, rect, color, dx, p; pos = node.pos; size = node.size; if (~(label = node.attr.label) | label == '\N') label = node.name; rect[0] = ['x' = pos.x - size.x / 2; 'y' = pos.y - size.y / 2;]; rect[1] = ['x' = rect[0].x + size.x; 'y' = rect[0].y + size.y;]; dx = (rect[1].x - rect[0].x) / 5; p[0] = ['x' = rect[0].x; 'y' = rect[0].y;]; p[1] = ['x' = rect[1].x - dx; 'y' = rect[0].y;]; p[2] = ['x' = rect[1].x; 'y' = rect[1].y;]; p[3] = ['x' = rect[0].x + dx; 'y' = rect[1].y;]; p[4] = ['x' = rect[0].x; 'y' = rect[0].y;]; if (node.attr.style == 'filled') { polygon (canvas, node, p, ['color' = node.color; 'fill' = 'on';]); polygon (canvas, node, p, ['color' = dotty.outlinecolor;]); } else polygon (canvas, node, p, ['color' = node.color;]); setpick (canvas, node, rect); text (canvas, null, pos, label, node.fontname, node.fontsize, 'cc', ['color' = node.fontcolor;]); }; dotty.protogt.shapefunc.trapezium = function (gt, canvas, node) { local pos, size, label, rect, color, dx, p; pos = node.pos; size = node.size; if (~(label = node.attr.label) | label == '\N') label = node.name; rect[0] = ['x' = pos.x - size.x / 2; 'y' = pos.y - size.y / 2;]; rect[1] = ['x' = rect[0].x + size.x; 'y' = rect[0].y + size.y;]; dx = (rect[1].x - rect[0].x) / 5; p[0] = ['x' = rect[0].x; 'y' = rect[0].y;]; p[1] = ['x' = rect[1].x; 'y' = rect[0].y;]; p[2] = ['x' = rect[1].x - dx; 'y' = rect[1].y;]; p[3] = ['x' = rect[0].x + dx; 'y' = rect[1].y;]; p[4] = ['x' = rect[0].x; 'y' = rect[0].y;]; if (node.attr.style == 'filled') { polygon (canvas, node, p, ['color' = node.color; 'fill' = 'on';]); polygon (canvas, node, p, ['color' = dotty.outlinecolor;]); } else polygon (canvas, node, p, ['color' = node.color;]); setpick (canvas, node, rect); text (canvas, null, pos, label, node.fontname, node.fontsize, 'cc', ['color' = node.fontcolor;]); }; dotty.protogt.shapefunc.triangle = function (gt, canvas, node) { local pos, size, label, rect, color, dx, dy, p; pos = node.pos; size = node.size; if (~(label = node.attr.label) | label == '\N') label = node.name; rect[0] = ['x' = pos.x - size.x / 2; 'y' = pos.y - size.y / 2;]; rect[1] = ['x' = rect[0].x + size.x; 'y' = rect[0].y + size.y;]; if (node.attr.orientation ~= -90) { dx = size.x / 2; dy = size.y / 4; p[0] = ['x' = pos.x - dx; 'y' = pos.y - dy;]; p[1] = ['x' = pos.x + dx; 'y' = pos.y - dy;]; p[2] = ['x' = pos.x; 'y' = rect[1].y;]; p[3] = ['x' = pos.x - dx; 'y' = pos.y - dy;]; } else { dx = size.x / 4; dy = size.y / 2; p[0] = ['x' = pos.x - dx; 'y' = pos.y - dy;]; p[1] = ['x' = pos.x - dx; 'y' = pos.y + dy;]; p[2] = ['x' = pos.x + dx * 2; 'y' = pos.y;]; p[3] = ['x' = pos.x - dx; 'y' = pos.y - dy;]; } if (node.attr.style == 'filled') { polygon (canvas, node, p, ['color' = node.color; 'fill' = 'on';]); polygon (canvas, node, p, ['color' = dotty.outlinecolor;]); } else polygon (canvas, node, p, ['color' = node.color;]); setpick (canvas, node, rect); text (canvas, null, pos, label, node.fontname, node.fontsize, 'cc', ['color' = node.fontcolor;]); }; dotty.protogt.movenode = function (gt, node, pos) { local ppos, eid, edge, p, fp, lp; ppos = copy (node.pos); gt.undrawnode (gt, gt.views, node); node.pos.x = pos.x; node.pos.y = pos.y; if (node.attr.shape == 'record') gt.moverecordfields (gt, node.fields, pos.x - ppos.x, pos.y - ppos.y); for (eid in node.edges) { edge = node.edges[eid]; if (~edge.dir & edge.head ~= edge.tail) { p = edge.tail.pos; fp = edge.points[0]; lp = edge.points[tablesize (edge.points) - 1]; if (((p.x - fp.x) * (p.x - fp.x) + (p.y - fp.y) * (p.y - fp.y)) < ((p.x - lp.x) * (p.x - lp.x) + (p.y - lp.y) * (p.y - lp.y))) edge.dir = 1; else edge.dir = -1; } gt.moveedge (gt, edge, node, ppos, pos); } gt.drawnode (gt, gt.views, node); }; dotty.protogt.moverecordfields = function (gt, fields, dx, dy) { local fid, field; for (fid in fields) { field = fields[fid]; if (field.fields) gt.moverecordfields (gt, field.fields, dx, dy); else { field.rect[0].x = field.rect[0].x + dx; field.rect[0].y = field.rect[0].y + dy; field.rect[1].x = field.rect[1].x + dx; field.rect[1].y = field.rect[1].y + dy; } } }; dotty.protogt.drawedge = function (gt, views, edge) { local vid, canvas; edge.drawn = 1; if (~edge.points) return; if (edge.attr.style == 'invis') { if (gt.edgehandles == 0) return; for (vid in views) { arc (views[vid].canvas, edge, [ 'x' = (edge.points[1].x + edge.points[2].x) / 2; 'y' = (edge.points[1].y + edge.points[2].y) / 2; ], ['x' = 5; 'y' = 5;], ['color' = 1;]); } return; } for (vid in views) { canvas = views[vid].canvas; if (edge.attr.style == 'bold') setgfxattr (canvas, ['width' = 3;]); splinegon (canvas, null, edge.points, ['color' = edge.color; 'style' = edge.attr.style;]); if (edge.sp) arrow (canvas, null, edge.points[0], edge.sp, ['color' = edge.color;]); if (edge.ep) arrow (canvas, null, edge.points[tablesize (edge.points) - 1], edge.ep, ['color' = edge.color;]); if (edge.attr.style == 'bold') setgfxattr (canvas, ['width' = 0;]); if (edge.lp) text (canvas, null, edge.lp, edge.attr.label, edge.fontname, edge.fontsize, 'cc', ['color' = edge.fontcolor;]); if (gt.edgehandles == 0) continue; arc (canvas, edge, [ 'x' = (edge.points[1].x + edge.points[2].x) / 2; 'y' = (edge.points[1].y + edge.points[2].y) / 2; ], ['x' = 5; 'y' = 5;], ['color' = 1;]); } }; dotty.protogt.undrawedge = function (gt, views, edge) { local vid, canvas; if (~edge.drawn) return; edge.drawn = 0; if (~edge.points) return; if (edge.attr.style == 'invis') { if (gt.edgehandles == 0) return; for (vid in views) { arc (views[vid].canvas, edge, [ 'x' = (edge.points[1].x + edge.points[2].x) / 2; 'y' = (edge.points[1].y + edge.points[2].y) / 2; ], ['x' = 5; 'y' = 5;], ['color' = 0;]); clearpick (views[vid].canvas, edge); } return; } for (vid in views) { canvas = views[vid].canvas; if (edge.attr.style == 'bold') setgfxattr (canvas, ['width' = 3;]); splinegon (canvas, null, edge.points, ['color' = 0;]); if (edge.sp) arrow (canvas, null, edge.points[0], edge.sp, ['color' = 0;]); if (edge.ep) arrow (canvas, null, edge.points[tablesize (edge.points) - 1], edge.ep, ['color' = 0;]); if (edge.attr.style == 'bold') setgfxattr (canvas, ['width' = 0;]); if (edge.lp) text (canvas, null, edge.lp, edge.attr.label, edge.fontname, edge.fontsize, 'cc', ['color' = 0;]); if (gt.edgehandles == 0) continue; arc (canvas, edge, [ 'x' = (edge.points[1].x + edge.points[2].x) / 2; 'y' = (edge.points[1].y + edge.points[2].y) / 2; ], ['x' = 5; 'y' = 5;], ['color' = 0;]); clearpick (canvas, edge); } }; dotty.protogt.moveedge = function (gt, edge, node, pb, pc) { local dx, dy, tp, hp, pid, p, pa, da, lab, lac, s, ce, se, n, x, y, dir; gt.undrawedge (gt, gt.views, edge); dx = pc.x - pb.x; dy = pc.y - pb.y; tp = edge.sp; hp = edge.ep; if (edge.tail == node) { if (edge.head == node) { for (pid in edge.points) { p = edge.points[pid]; p.x = p.x + dx; p.y = p.y + dy; } if (tp) { tp.x = tp.x + dx; tp.y = tp.y + dy; } if (hp) { hp.x = hp.x + dx; hp.y = hp.y + dy; } if (edge.lp) { edge.lp.x = edge.lp.x + dx; edge.lp.y = edge.lp.y + dy; } gt.drawedge (gt, gt.views, edge); return; } pa = edge.head.pos; dir = 1; } else { pa = edge.tail.pos; dir = -1; } dir = edge.dir * dir; da = atan (pc.y - pa.y, pc.x - pa.x) - atan (pb.y - pa.y, pb.x - pa.x); lab = sqrt ((pb.y - pa.y) * (pb.y - pa.y) + (pb.x - pa.x) * (pb.x - pa.x)); lac = sqrt ((pc.y - pa.y) * (pc.y - pa.y) + (pc.x - pa.x) * (pc.x - pa.x)); s = lac / lab; ce = cos (da); se = sin (da); n = tablesize (edge.points); for (pid = 1; pid < n - 1; pid = pid + 1) { p = edge.points[pid]; x = p.x - pa.x; y = p.y - pa.y; p.x = pa.x + (ce * x - se * y) * s; p.y = pa.y + (se * x + ce * y) * s; } if (dir == 1) { p = edge.points[0]; p.x = p.x + dx; p.y = p.y + dy; if (tp) { tp.x = tp.x + dx; tp.y = tp.y + dy; } } else { p = edge.points[n - 1]; p.x = p.x + dx; p.y = p.y + dy; if (hp) { hp.x = hp.x + dx; hp.y = hp.y + dy; } } if (edge.lp) { x = edge.lp.x - pa.x; y = edge.lp.y - pa.y; edge.lp.x = pa.x + (ce * x - se * y) * s; edge.lp.y = pa.y + (se * x + ce * y) * s; } gt.drawedge (gt, gt.views, edge); }; dotty.protogt.getcolor = function (views, name) { local vid, vt, color, t; for (vid in views) { vt = views[vid]; if (~(color >= 0)) { if (~(vt.colors[name] >= 0)) color = (vt.colors[name] = vt.colorn); else { color = vt.colors[name]; break; } } else if (~(vt.colors[name] >= 0)) vt.colors[name] = color; else if (vt.colors[name] ~= color) dotty.message (0, concat ('inconsistent color ids for ', name)); if (setwidgetattr (vt.canvas, ['color' = [color = name;];]) ~= 1) { t = split (name, ' '); if (tablesize (t) ~= 3 | setwidgetattr (vt.canvas, ['color' = [color = [ 'h' = ston (t[0]); 's' = ston (t[1]); 'v' = ston (t[2]); ];];]) ~= 1) { dotty.message (0, concat ('unknown color ', name, ' using #1')); return 1; } } vt.colorn = color + 1; } return color; }; dotty.protogt.unpacksgraphattr = function (gt, sgraph) { local attr; attr = sgraph.graphattr; if (dotty.fontmap[attr.fontname]) sgraph[dotty.keys.fname] = dotty.fontmap[attr.fontname]; else sgraph[dotty.keys.fname] = attr.fontname; sgraph[dotty.keys.fsize] = ston (attr.fontsize); sgraph[dotty.keys.fcolor] = gt.getcolor (gt.views, attr.fontcolor); if (attr.style == 'filled' & attr.color == 'black') sgraph[dotty.keys.color] = gt.getcolor (gt.views, 'grey'); else sgraph[dotty.keys.color] = gt.getcolor (gt.views, attr.color); }; dotty.protogt.unpacknodeattr = function (gt, node) { local attr; attr = node.attr; if (dotty.fontmap[attr.fontname]) node[dotty.keys.fname] = dotty.fontmap[attr.fontname]; else node[dotty.keys.fname] = attr.fontname; node[dotty.keys.fsize] = ston (attr.fontsize); node[dotty.keys.fcolor] = gt.getcolor (gt.views, attr.fontcolor); if (attr.style == 'filled' & attr.color == 'black') node[dotty.keys.color] = gt.getcolor (gt.views, 'grey'); else node[dotty.keys.color] = gt.getcolor (gt.views, attr.color); }; dotty.protogt.unpackedgeattr = function (gt, edge) { local attr, n; attr = edge.attr; if (dotty.fontmap[attr.fontname]) edge[dotty.keys.fname] = dotty.fontmap[attr.fontname]; else edge[dotty.keys.fname] = attr.fontname; edge[dotty.keys.fsize] = ston (attr.fontsize); edge[dotty.keys.fcolor] = gt.getcolor (gt.views, attr.fontcolor); if (attr.style == 'filled' & attr.color == 'black') edge[dotty.keys.color] = gt.getcolor (gt.views, 'grey'); else edge[dotty.keys.color] = gt.getcolor (gt.views, attr.color); if (attr.label & attr.label ~= '' & ~edge.lp & edge.points) { if ((n = tablesize (edge.points)) > 4) edge.lp = [ 'x' = edge.points[toint (n / 2)].x + 5; 'y' = edge.points[toint (n / 2)].y + 5; ]; else edge.lp = [ 'x' = (edge.points[1].x + edge.points[2].x) / 2 + 5; 'y' = (edge.points[1].y + edge.points[2].y) / 2 + 5; ]; } }; dotty.protogt.unpackattr = function (gt) { local gid, sgraph, nid, node, eid, edge, graph, attr; graph = gt.graph; attr = graph.graphattr; if (dotty.fontmap[attr.fontname]) graph[dotty.keys.fname] = dotty.fontmap[attr.fontname]; else graph[dotty.keys.fname] = attr.fontname; graph[dotty.keys.fsize] = ston (attr.fontsize); graph[dotty.keys.fcolor] = gt.getcolor (gt.views, attr.fontcolor); if (attr.style == 'filled' & attr.color == 'black') graph[dotty.keys.color] = gt.getcolor (gt.views, 'grey'); else graph[dotty.keys.color] = gt.getcolor (gt.views, attr.color); for (gid in graph.graphdict) { sgraph = graph.graphs[graph.graphdict[gid]]; attr = sgraph.graphattr; if (dotty.fontmap[attr.fontname]) sgraph[dotty.keys.fname] = dotty.fontmap[attr.fontname]; else sgraph[dotty.keys.fname] = attr.fontname; sgraph[dotty.keys.fsize] = ston (attr.fontsize); sgraph[dotty.keys.fcolor] = gt.getcolor (gt.views, attr.fontcolor); if (attr.style == 'filled' & attr.color == 'black') sgraph[dotty.keys.color] = gt.getcolor (gt.views, 'grey'); else sgraph[dotty.keys.color] = gt.getcolor (gt.views, attr.color); } for (nid in graph.nodedict) { node = graph.nodes[graph.nodedict[nid]]; attr = node.attr; if (dotty.fontmap[attr.fontname]) node[dotty.keys.fname] = dotty.fontmap[attr.fontname]; else node[dotty.keys.fname] = attr.fontname; node[dotty.keys.fsize] = ston (attr.fontsize); node[dotty.keys.fcolor] = gt.getcolor (gt.views, attr.fontcolor); if (attr.style == 'filled' & attr.color == 'black') node[dotty.keys.color] = gt.getcolor (gt.views, 'grey'); else node[dotty.keys.color] = gt.getcolor (gt.views, attr.color); } for (eid in graph.edges) { edge = graph.edges[eid]; attr = edge.attr; if (dotty.fontmap[attr.fontname]) edge[dotty.keys.fname] = dotty.fontmap[attr.fontname]; else edge[dotty.keys.fname] = attr.fontname; edge[dotty.keys.fsize] = ston (attr.fontsize); edge[dotty.keys.fcolor] = gt.getcolor (gt.views, attr.fontcolor); edge[dotty.keys.color] = gt.getcolor (gt.views, attr.color); } };