764 lines
29 KiB
Plaintext
764 lines
29 KiB
Plaintext
#
|
|
# 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);
|
|
}
|
|
};
|