#
# 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);
}
};