Linux ip-172-26-7-228 5.4.0-1103-aws #111~18.04.1-Ubuntu SMP Tue May 23 20:04:10 UTC 2023 x86_64
Your IP : 3.147.77.51
#
# DOTTY
#
dotty = [
'keys' = [
'nid' = 'nid';
'eid' = 'eid';
'gid' = 'gid';
'name' = 'name';
'attr' = 'attr';
'gattr' = 'graphattr';
'eattr' = 'edgeattr';
'nattr' = 'nodeattr';
'edges' = 'edges';
'tail' = 'tail';
'tport' = 'tport';
'head' = 'head';
'hport' = 'hport';
'pos' = 'pos';
'size' = 'size';
'rect' = 'rect';
'fname' = 'fontname';
'fsize' = 'fontsize';
'fcolor' = 'fontcolor';
'dcolor' = 'drawcolor';
'bcolor' = 'fillcolor';
];
'maps' = [
'X11' = [
'fontmap' = [
'Times-Roman' = '-*-times-medium-r-*--%d-*-*-*-*-*-*-1';
'Times-Italic' = '-*-times-medium-i-*--%d-*-*-*-*-*-*-1';
'Times-Bold' = '-*-times-bold-r-*--%d-*-*-*-*-*-*-1';
'Courier' = '-*-courier-bold-r-*--%d-*-*-*-*-*-*-1';
'Courier-Bold' = '-*-courier-bold-r-*--%d-*-*-*-*-*-*-1';
'Helvetica' = (
'-*-helvetica-medium-r-normal--%d-*-*-*-p-*-iso8859-1'
);
'Helvetica-Bold' = (
'-*-helvetica-bold-r-normal--%d-*-*-*-p-*-iso8859-1'
);
];
'psfontmap' = [
'Times-Roman' = 'Times-Roman';
'Times-Italic' = 'Times-Italic';
'Times-Bold' = 'Times-Bold';
'Courier' = 'Courier';
'Courier-Bold' = 'Courier-Bold';
'Helvetica' = 'Helvetica';
'Helvetica-Bold' = 'Helvetica-Bold';
];
];
'mswin' = [
'fontmap' = [
'Times-Roman' = 'Times New Roman';
'Times-Italic' = 'Times New Roman Italic';
'Times-Bold' = 'Times New Roman Bold';
'Courier' = 'Courier New';
'Courier-Bold' = 'Courier New Bold';
'Helvetica' = 'Arial';
'Helvetica-Bold' = 'Arial Bold';
];
'psfontmap' = [
'Times-Roman' = 'Times New Roman';
'Times-Italic' = 'Times New Roman Italic';
'Times-Bold' = 'Times New Roman Bold';
'Courier' = 'Courier New';
'Courier-Bold' = 'Courier New Bold';
'Helvetica' = 'Arial';
'Helvetica-Bold' = 'Arial Bold';
];
];
];
'protogt' = [
'graph' = [
'graphattr' = [
'fontsize' = '14';
'fontname' = 'Times-Roman';
'fontcolor' = 'black';
];
'nodeattr' = [
'shape' = 'ellipse';
'fontsize' = '14';
'fontname' = 'Times-Roman';
'fontcolor' = 'black';
'style' = 'solid';
];
'edgeattr' = [
'fontsize' = '14';
'fontname' = 'Times-Roman';
'fontcolor' = 'black';
'style' = 'solid';
];
'graphdict' = [];
'nodedict' = [];
'graphs' = [];
'nodes' = [];
'edges' = [];
'maxgid' = 0;
'maxnid' = 0;
'maxeid' = 0;
'type' = 'digraph';
];
'layoutmode' = 'sync';
'lserver' = 'dot';
'edgehandles' = 1;
'noundo' = 0;
];
'lservers' = [];
'mlevel' = 0;
'graphs' = [];
'views' = [];
'protovt' = [
'normal' = [
'name' = 'DOTTY';
'orig' = ['x' = 1; 'y' = 1;];
'size' = ['x' = 420; 'y' = 520;];
'wrect' = [
0 = ['x' = 0; 'y' = 0;];
1 = ['x' = 400; 'y' = 500;];
];
'vsize' = ['x' = 400; 'y' = 500;];
'w2v' = 1;
];
'birdseye' = [
'type' = 'birdseye';
'name' = 'DOTTY birdseye view';
'orig' = ['x' = 1; 'y' = 1;];
'size' = ['x' = 220; 'y' = 260;];
'wrect' = [
0 = ['x' = 0; 'y' = 0;];
1 = ['x' = 200; 'y' = 250;];
];
'vsize' = ['x' = 200; 'y' = 250;];
'w2v' = 1;
];
];
'pagesizes' = [
'8.5x11' = ['x' = 8; 'y' = 10.5;];
'11x17' = ['x' = 10.5; 'y' = 16.5;];
'36x50' = ['x' = 35.5; 'y' = 49.5;];
];
];
load ('dotty_draw.lefty');
load ('dotty_edit.lefty');
load ('dotty_layout.lefty');
load ('dotty_ui.lefty');
#
# initialization functions
#
dotty.init = function () {
dotty.fontmap = dotty.maps[getenv ('LEFTYWINSYS')].fontmap;
dotty.clipgt = dotty.protogt.creategraph (['noundo' = 1;]);
dotty.inited = 1;
};
dotty.simple = function (file) {
if (dotty.inited ~= 1)
dotty.init ();
dotty.createviewandgraph (file, 'file', null, null);
txtview ('off');
};
#
# main operations
#
dotty.protogt.creategraph = function (protogt) {
local gt, id, gtid;
if (~protogt)
protogt = dotty.protogt;
for (gtid = 0; dotty.graphs[gtid]; gtid = gtid + 1)
;
gt = (dotty.graphs[gtid] = []);
if (protogt.mode ~= 'replace') {
for (id in dotty.protogt)
gt[id] = copy (dotty.protogt[id]);
}
for (id in protogt)
gt[id] = copy (protogt[id]);
gt.gtid = gtid;
gt.views = [];
gt.undoarray = ['level' = 0; 'entries' = [];];
gt.busy = 0;
return gt;
};
dotty.protogt.copygraph = function (ogt) {
local gt, gtid, id;
for (gtid = 0; dotty.graphs[gtid]; gtid = gtid + 1)
;
gt = (dotty.graphs[gtid] = []);
for (id in ogt)
gt[id] = copy (ogt[id]);
gt.gtid = gtid;
gt.views = [];
gt.undoarray = ['level' = 0; 'entries' = [];];
gt.busy = 0;
return gt;
};
dotty.protogt.destroygraph = function (gt) {
local vid, vlist;
if (gt.layoutpending > 0)
gt.cancellayout (gt);
for (vid in gt.views)
vlist[vid] = gt.views[vid];
for (vid in gt.views)
gt.destroyview (gt, vlist[vid]);
remove (gt.gtid, dotty.graphs);
};
dotty.protogt.loadgraph = function (gt, name, type, protograph, layoutflag) {
local fd, vid, vt, graph, nid, eid, gid;
if (gt.layoutpending > 0)
gt.cancellayout (gt);
if (~name)
if (~(name = ask ('file name:', 'file', '')))
return;
dotty.pushbusy (gt, gt.views);
dotty.message (1, 'loading');
if (~protograph)
protograph = dotty.protogt.graph;
if (
~((fd = dotty.openio (name, type, 'r')) >= 0) |
~(graph = readgraph (fd, protograph))
) {
dotty.message (0, 'cannot load graph');
dotty.popbusy (gt, gt.views);
return;
}
for (vid in gt.views) {
vt = gt.views[vid];
vt.colors = [];
vt.colorn = 2;
}
gt.graph = graph;
gt.name = name;
gt.type = type;
gt.undoarray = ['level' = 0; 'entries' = [];];
if (~(type == 'file' & name == '-'))
closeio (fd);
graph.maxgid = tablesize (graph.graphs);
graph.maxnid = tablesize (graph.nodes);
graph.maxeid = tablesize (graph.edges);
for (nid in graph.nodes)
graph.nodes[nid][dotty.keys.nid] = nid;
for (eid in graph.edges)
graph.edges[eid][dotty.keys.eid] = eid;
for (gid in graph.graphs)
graph.graphs[gid][dotty.keys.gid] = gid;
gt.unpackattr (gt);
if (layoutflag) {
dotty.message (1, 'generating layout');
gt.layoutgraph (gt);
}
dotty.popbusy (gt, gt.views);
return gt.graph;
};
dotty.protogt.savegraph = function (gt, name, type) {
local fd;
if (~name)
if (~(name = ask ('file name:', 'file', '')))
return;
if (
~((fd = dotty.openio (name, type, 'w')) >= 0) |
~writegraph (fd, gt.graph, 0)
) {
dotty.message (0, 'cannot save graph');
return;
}
if (~(type == 'file' & name == '-'))
closeio (fd);
};
dotty.protogt.setgraph = function (gt, graph) {
local vid, vt, nid, eid, gid;
if (gt.layoutpending > 0)
gt.cancellayout (gt);
for (vid in gt.views) {
vt = gt.views[vid];
vt.colors = [];
vt.colorn = 2;
}
gt.graph = copy (graph);
gt.undoarray = ['level' = 0; 'entries' = [];];
gt.unpackattr (gt);
gt.graph.maxgid = tablesize (graph.graphs);
gt.graph.maxnid = tablesize (graph.nodes);
gt.graph.maxeid = tablesize (graph.edges);
for (nid in gt.graph.nodes)
gt.graph.nodes[nid][dotty.keys.nid] = nid;
for (eid in gt.graph.edges)
gt.graph.edges[eid][dotty.keys.eid] = eid;
for (gid in gt.graph.graphs)
gt.graph.graphs[gid][dotty.keys.gid] = gid;
gt.unpackattr (gt);
dotty.message (1, 'generating layout');
gt.layoutgraph (gt);
return gt.graph;
};
dotty.protogt.erasegraph = function (gt, protogt, protovt) {
local vid, vt;
if (gt.layoutpending > 0)
gt.cancellayout (gt);
for (vid in gt.views) {
vt = gt.views[vid];
vt.colors = [];
vt.colorn = 2;
clear (vt.canvas);
}
if (~protogt)
protogt = dotty.protogt;
gt.graph = copy (protogt.graph);
gt.undoarray = ['level' = 0; 'entries' = [];];
};
dotty.protogt.layoutgraph = function (gt) {
if (gt.graph.graphattr.xdotversion) {
gt.unpacklayout (gt, gt.graph);
gt.setviewsize (gt.views, gt.graph.rect);
gt.redrawgraph (gt, gt.views);
return;
}
if (gt.layoutmode == 'async') {
if (~gt.haveinput) {
gt.startlayout (gt);
return;
}
if (~gt.finishlayout (gt))
return;
gt.setviewsize (gt.views, gt.graph.rect);
gt.redrawgraph (gt, gt.views);
} else {
if (~gt.startlayout (gt))
return;
else
while (~gt.finishlayout (gt))
;
gt.setviewsize (gt.views, gt.graph.rect);
gt.redrawgraph (gt, gt.views);
}
};
dotty.protogt.createview = function (gt, protovt) {
local vt, ovt, id, t;
vt = [];
vt.colors = [];
vt.colorn = 2;
if (~protovt)
protovt = dotty.protovt.normal;
if (protovt.mode ~= 'replace') {
for (id in dotty.protovt[protovt.type])
vt[id] = copy (dotty.protovt[protovt.type][id]);
}
for (id in protovt)
vt[id] = copy (protovt[id]);
if (~(vt.parent >= 0)) {
vt.view = createwidget (-1, [
'type' = 'view';
'name' = vt.name;
'origin' = vt.orig;
'size' = vt.size;
]);
vt.scroll = createwidget (vt.view, ['type' = 'scroll';]);
} else {
vt.view = -1;
vt.scroll = createwidget (vt.parent, [
'type' = 'scroll';
'size' = vt.size;
]);
}
vt.canvas = createwidget (vt.scroll, [
'type' = 'canvas';
'color' = [0 = protovt.bgcolor; 1 = protovt.fgcolor;];
]);
setwidgetattr (vt.canvas, [
'window' = vt.wrect;
'viewport' = vt.vsize;
]);
clear (vt.canvas);
dotty.views[vt.canvas] = vt;
vt.vtid = vt.canvas;
vt.gtid = gt.gtid;
gt.views[vt.vtid] = vt;
dotty.views[vt.scroll] = vt;
if (vt.view ~= -1)
dotty.views[vt.view] = vt;
if (protovt.colors & tablesize (protovt.colors) > 0) {
for (id in protovt.colors)
if (id == '_bgcolor_')
setwidgetattr (vt.canvas, [
'color' = [0 = protovt.colors[id];];
]);
else if (setwidgetattr (vt.canvas, ['color' = [
protovt.colors[id] = id;
];]) ~= 1) {
t = split (id, ' ');
if (tablesize (t) ~= 3 | setwidgetattr (vt.canvas, [
'color' = [protovt.colors[id] = [
'h' = ston (t[0]); 's' = ston (t[1]); 'v' = ston (t[2]);
];];
]) ~= 1) {
dotty.message (
0, concat ('unknown color ', id, ' using #1')
);
}
}
vt.colors = copy (protovt.colors);
vt.colorn = protovt.colorn;
} else if (tablesize (gt.views) > 1) {
for (id in gt.views)
if (gt.views[id] ~= vt)
break;
ovt = gt.views[id];
for (id in ovt.colors)
if (id == '_bgcolor_')
setwidgetattr (vt.canvas, ['color' = [0 = ovt.colors[id];];]);
else if (setwidgetattr (vt.canvas, ['color' = [
ovt.colors[id] = id;
];]) ~= 1) {
t = split (id, ' ');
if (tablesize (t) ~= 3 | setwidgetattr (vt.canvas, [
'color' = [ovt.colors[id] = [
'h' = ston (t[0]); 's' = ston (t[1]); 'v' = ston (t[2]);
];];
]) ~= 1) {
dotty.message (
0, concat ('unknown color ', id, ' using #1')
);
}
}
vt.colors = copy (ovt.colors);
vt.colorn = ovt.colorn;
}
if (gt.graph.rect)
gt.setviewsize ([vt.vtid = vt;], gt.graph.rect);
gt.drawgraph (gt, [vt.vtid = vt;]);
for (id in vt.uifuncs)
if (id == 'closeview')
widgets[vt.view][id] = vt.uifuncs[id];
else
widgets[vt.canvas][id] = vt.uifuncs[id];
return vt;
};
dotty.protogt.destroyview = function (gt, vt) {
destroywidget (vt.canvas);
destroywidget (vt.scroll);
if (vt.view ~= -1) {
destroywidget (vt.view);
remove (vt.view, dotty.views);
}
remove (vt.scroll, dotty.views);
remove (vt.canvas, dotty.views);
if (vt.gtid >= 0)
remove (vt.vtid, gt.views);
if (tablesize (dotty.views) == 0)
exit ();
};
dotty.protogt.zoom = function (gt, vt, factor, pos) {
gt.setviewscale ([vt.vtid = vt;], factor);
if (pos)
gt.setviewcenter ([vt.vtid = vt;], pos);
gt.redrawgraph (gt, [vt.vtid = vt;]);
};
dotty.protogt.findnode = function (gt, vt) {
local key, node, node1, nid;
if (~(key = ask ('give node name or label')))
return;
if (gt.graph.nodedict[key] >= 0)
node = gt.graph.nodes[gt.graph.nodedict[key]];
else if (gt.graph.nodedict[ston (key)] >= 0)
node = gt.graph.nodes[gt.graph.nodedict[ston (key)]];
else {
for (nid in gt.graph.nodes) {
node1 = gt.graph.nodes[nid];
if (node1.attr.label == key | node1.attr.label == ston (key)) {
node = node1;
break;
}
}
}
if (~node) {
dotty.message (0, concat ('cannot find node: ', key));
return;
}
gt.setviewcenter ([vt.vtid = vt;], node.pos);
};
dotty.protogt.setattr = function (gt, obj) {
local kv, t, attr, value, n, i, s;
if (~(kv = ask ('give attr/value, eg. color=blue')))
return;
t = split (kv, '=');
attr = t[0];
value = t[1];
if ((n = tablesize (t)) > 2)
for (i = 2; i < n; i = i + 1)
value = concat (value, '=', t[i]);
# Check for HTML string and convert using lefty convention
s = split (value, '');
n = tablesize (s);
if ((s[0] == '<') & (s[n-1] == '>')) {
s[0] = '>';
s[n-1] = '<';
value = s[0];
for (i = 1; i < n; i = i + 1)
value = concat (value, s[i]);
}
if (
obj.attr == gt.graph.graphattr |
obj.attr == gt.graph.edgeattr |
obj.attr == gt.graph.nodeattr
) {
obj.attr[attr] = value;
return;
}
if (obj.nid >= 0) {
gt.undrawnode (gt, gt.views, obj);
obj.attr[attr] = value;
gt.unpacknodeattr (gt, obj);
gt.drawnode (gt, gt.views, obj);
} else if (obj.eid >= 0) {
gt.undrawedge (gt, gt.views, obj);
obj.attr[attr] = value;
gt.unpackedgeattr (gt, obj);
gt.drawedge (gt, gt.views, obj);
}
};
dotty.protogt.getattr = function (gt, node) {
local kv;
if (~(kv.key = ask ('give attr name')))
return null;
if ((kv.val = node.attr[kv.key]))
return kv;
return null;
};
#
# utilities
#
dotty.createviewandgraph = function (name, type, protogt, protovt) {
local vt, gt;
if (~protogt)
protogt = dotty.protogt;
if (protogt.creategraph)
gt = protogt.creategraph (protogt);
else
gt = dotty.protogt.creategraph (protogt);
vt = gt.createview (gt, protovt);
if (~protogt.graph)
protogt.graph = copy (dotty.protogt.graph);
if (name)
gt.loadgraph (gt, name, type, protogt.graph, 1);
return ['gt' = gt; 'vt' = vt;];
};
dotty.openio = function (name, type, mode) {
local fd;
if (~name)
return null;
if (type == 'file') {
if (name == '-') {
if (mode == 'r' | mode == 'r+')
fd = 0;
else
fd = 1;
} else if (~((fd = openio ('file', name, mode)) >= 0)) {
dotty.message (0, concat ('cannot open file: ', name));
return null;
}
} else if (type == 'pipe') {
if (~((fd = openio (
'pipe', 'ksh', mode, concat ("%e ", name)
)) >= 0)) {
dotty.message (0, concat ('cannot run command: ', name));
return null;
}
} else
return null;
return fd;
};
dotty.pushbusy = function (gt, views) {
local vid;
if (gt.busy == 0)
for (vid in gt.views)
setwidgetattr (vid, ['cursor' = 'watch';]);
gt.busy = gt.busy + 1;
};
dotty.popbusy = function (gt, views) {
local vid;
gt.busy = gt.busy - 1;
if (gt.busy == 0)
for (vid in gt.views)
setwidgetattr (vid, ['cursor' = 'default';]);
};
dotty.message = function (level, text) {
if (level <= dotty.mlevel)
echo ('dotty.lefty: ', text);
};
#
# printing or saving to file
#
dotty.protogt.printorsave = function (gt, vt, otype, name, mode, ptype) {
local pr, wrect, vsize, xy, psize, canvas, pscanvas, cid, cname, t;
local graph, edgehandles, fontmap, eid, edge, nid, node, gid, sgraph;
local did, draw, i;
if (~otype)
if (~(otype = ask ('print to', 'choice', 'file|printer')))
return;
if (otype == 'printer') {
if (~getenv ('TMPDIR'))
name = concat (getenv ('HOME'), '/.dottyout.ps');
else
name = concat (getenv ('TMPDIR'), '/.dottyout.ps', random (10000));
if (getenv ('LEFTYWINSYS') ~= 'mswin' & ~pr)
if (~(pr = ask ('printer command', 'string', 'lpr')))
return;
}
if (~name)
if (~(name = ask ('postscript file', 'file', 'out.ps')))
return;
if (~ptype)
if (~(ptype = ask ('page size', 'choice', '8.5x11|11x17|36x50')))
return;
if (~mode)
if (~(mode = ask ('mode', 'choice', 'portrait|landscape|best fit')))
return;
wrect = copy (vt.wrect);
wrect[0].x = wrect[0].x - 1;
wrect[1].x = wrect[1].x + 1;
wrect[0].y = wrect[0].y - 1;
wrect[1].y = wrect[1].y + 1;
vsize = copy (vt.vsize);
if (vsize.x == 0)
vsize.x = 1;
if (vsize.y == 0)
vsize.y = 1;
xy = vsize.x / vsize.y;
if (mode == 'best fit') {
if (xy < 1)
mode = 'portrait';
else
mode = 'landscape';
}
psize = dotty.pagesizes[ptype];
if (mode == 'portrait') {
if (xy < psize.x / psize.y) {
vsize.y = psize.y * 300;
vsize.x = vsize.y * xy;
} else {
vsize.x = psize.x * 300;
vsize.y = vsize.x / xy;
}
} else {
if (xy < psize.y / psize.x) {
vsize.y = psize.x * 300;
vsize.x = vsize.y * xy;
} else {
vsize.x = psize.y * 300;
vsize.y = vsize.x / xy;
}
}
if (~((pscanvas = createwidget (-1, [
'type' = 'ps';
'origin' = ['x' = 0; 'y' = 0;];
'size' = vsize;
'mode' = mode;
'name' = name;
])) >= 0)) {
dotty.message (0, 'cannot open printer device');
return;
}
for (cname in vt.colors) {
cid = vt.colors[cname];
if (cname == '_bgcolor_')
setwidgetattr (pscanvas, ['color' = [0 = cid;];]);
else if (setwidgetattr (pscanvas, ['color' = [cid = cname;];]) ~= 1) {
t = split (cname, ' ');
if (tablesize (t) ~= 3 | setwidgetattr (pscanvas, [
'color' = [cid = [
'h' = ston (t[0]); 's' = ston (t[1]); 'v' = ston (t[2]);
];];
]) ~= 1) {
dotty.message (
0, concat ('unknown color ', cname, ' using #1')
);
}
}
}
setwidgetattr (pscanvas, ['window' = wrect;]);
graph = copy (gt.graph);
canvas = vt.canvas;
vt.canvas = pscanvas;
edgehandles = gt.edgehandles;
gt.edgehandles = 0;
fontmap = dotty.maps[getenv ('LEFTYWINSYS')].psfontmap;
for (eid in graph.edges) {
edge = graph.edges[eid];
edge.fontname = fontmap[edge.attr.fontname];
for (did in edge.draws) {
if (did == 'ep')
continue;
draw = edge.draws[did];
for (i = 0; draw[i]; i = i + 1)
if (draw[i].type == 'F')
draw[i].fn = fontmap[draw[i].ofn];
}
gt.drawedge (gt, [0 = vt;], edge);
}
for (nid in graph.nodes) {
node = graph.nodes[nid];
node.fontname = fontmap[node.attr.fontname];
for (did in node.draws) {
if (did == 'ep')
continue;
draw = node.draws[did];
for (i = 0; draw[i]; i = i + 1)
if (draw[i].type == 'F')
draw[i].fn = fontmap[draw[i].ofn];
}
gt.drawnode (gt, [0 = vt;], node);
}
for (gid in graph.graphs) {
sgraph = graph.graphs[gid];
sgraph.fontname = fontmap[sgraph.graphattr.fontname];
for (did in sgraph.draws) {
if (did == 'ep')
continue;
draw = sgraph.draws[did];
for (i = 0; draw[i]; i = i + 1)
if (draw[i].type == 'F')
draw[i].fn = fontmap[draw[i].ofn];
}
gt.drawsgraph (gt, [0 = vt;], sgraph);
}
graph.fontname = fontmap[graph.graphattr.fontname];
gt.drawsgraph (gt, [0 = vt;], graph);
gt.edgehandles = edgehandles;
vt.canvas = canvas;
destroywidget (pscanvas);
if (otype == 'printer' & getenv ('LEFTYWINSYS') ~= 'mswin')
system (concat (pr, ' ', name, '; rm ',name));
};
|