| Current Path : /home/emeraadmin/public_html/4d695/ |
| Current File : /home/emeraadmin/public_html/4d695/graphviz.tar |
gvpr/addedges 0000644 00000000443 15170512710 0007205 0 ustar 00 /* Add edges from input graph to argument graph
* Does not add nodes.
*/
BEGIN{
graph_t g = readG(ARGV[0]);
node_t h, t;
edge_t e;
}
E {
if ((h = isNode(g,head.name)) && (t = isNode(g,tail.name))) {
if (!isEdge(t,h,"")) {
e = copy(g,$);
}
}
}
END {
write(g);
}
gvpr/addranks 0000644 00000001476 15170512710 0007243 0 ustar 00 /* Assuming nodes have been positioned by dot, this adds a rank
* attribute by placing all nodes with the same y value on a specific
* integer rank.
* If the graph has rankdir=LR, x and y are flipped.
*/
BEG_G {
double x,y;
int lv[double];
int r, rk[double];
int flip;
if (isAttr($,"G","rankdir") && $.rankdir=="LR") flip = 1;
}
N {
sscanf($.pos,"%f,%f",&x,&y);
if (flip) lv[x] = 1;
else lv[y] = 1;
}
BEG_G {
r = 0;
if (flip)
forr (lv[x]) {
rk[x] = r++;
/* printf (2, "rk[%f] = %d\n", y, rk[y]); */
}
else
forr (lv[y]) {
rk[y] = r++;
/* printf (2, "rk[%f] = %d\n", y, rk[y]); */
}
}
N {
sscanf($.pos,"%f,%f",&x,&y);
/* printf(2, "node %s y %f rk %d\n", $.name, y, rk[y]); */
if (flip) $.rank = sprintf("%d", rk[x]);
else $.rank = sprintf("%d", rk[y]);
}
gvpr/addrings 0000644 00000002447 15170512710 0007246 0 ustar 00 /* Takes a graph laid out by twopi and adds rings.
* Assumes ARGV[] = "root" "=" <rootname>, as output by twopi -v.
* Usage:
* twopi -v foo.dot > out 2> log
* gvpr -f addrings.g -a"`grep root log`" out | neato -n2 ...
*/
BEG_G {
graph_t og;
edge_t e;
node_t ctr = node($, ARGV[0]);
double rs = 1.0; /* min. slack between the squares of two consecutive radii */
int cx, cy;
int x, y;
node_t n;
int i, n_r;
int d;
int rads[int];
char* ctr_s = ctr.pos;
sscanf (ctr_s, "%d,%d", &cx, &cy);
if (hasAttr($, "ranksep")) {
sscanf ($.ranksep, "%f", &rs);
if (rs == 0.0) rs = 1.0;
}
rs *= 72;
rs = 1.5*rs*rs;
}
N [$ != ctr] {
sscanf ($.pos, "%d,%d", &x, &y);
d = (x-cx)*(x-cx) + (y-cy)*(y-cy);
for (rads[i]) {
if ((rads[i]-rs <= d) && (d <= rads[i]+rs)) return;
}
n_r++;
rads[n_r] = d;
}
END_G {
og = copy (NULL, $);
og.outputorder = "nodesfirst";
setDflt (og, "N", "label", "\\N");
for (rads[i]) {
n = node(og, "ring_"+((string)i));
n.shape = "circle";
n.pos = ctr_s;
n.style = "";
n.label = "";
d = rads[i];
n.width = sprintf("%f", sqrt(d)/36.0);
}
for (n=fstnode($);n;n = nxtnode(n))
clone (og, n);
for (n=fstnode($);n;n = nxtnode(n))
for (e=fstedge(n);e;e = nxtedge(e,n))
clone (og, e);
write(og);
}
gvpr/anon 0000644 00000000646 15170512710 0006405 0 ustar 00 /* anonymize the graph */
BEG_G {
node_t map[node_t];
graph_t dup;
int id = 0;
char* gtype;
node_t n;
edge_t e;
char* l;
if ($.directed) gtype = "D";
else gtype = "U";
if ($.strict) gtype = gtype + "S";
dup = graph ($.name, gtype);
$tvtype = TV_ne;
}
N {
n = node(dup, (char*)id);
n.label=$.name;
map[$] = n;
id++;
}
E {
edge (map[$.tail],map[$.head],"");
}
END_G {
write (dup);
}
gvpr/attr 0000644 00000000227 15170512710 0006417 0 ustar 00 /* List known node attributes */
BEG_G {
char* attr;
for (attr = fstAttr($,"N"); attr != ""; attr = nxtAttr($,"N",attr)) {
print (attr);
}
}
gvpr/bb 0000644 00000001745 15170512710 0006036 0 ustar 00 /* computes the bounding box of a graph based on its nodes
taking into account clusters and node sizes.
*/
BEGIN {
double x, y, w2, h2;
double llx, lly, urx, ury;
double llx0, lly0, urx0, ury0;
graph_t clustBB (graph_t G) {
graph_t sg;
for (sg = fstsubg(G); sg; sg = nxtsubg(sg)) {
sg = clustBB(sg);
}
if (G.name == "cluster*") {
sscanf (G.bb, "%lf,%lf,%lf,%lf", &llx0, &lly0, &urx0, &ury0);
if (llx0 < llx) llx = llx0;
if (lly0 < lly) lly = lly0;
if (urx0 > urx) urx = urx0;
if (ury0 > ury) ury = ury0;
}
return G;
}
}
BEG_G {
llx = 1000000; lly = 1000000; urx = -1000000; ury = -1000000;
}
N {
sscanf ($.pos, "%lf,%lf", &x, &y);
w2 = (36.0*(double)$.width);
h2 = (36.0*(double)$.height);
if ((x - w2) < llx) llx = x - w2;
if ((x + w2) > urx) urx = x + w2;
if ((y - h2) < lly) lly = y - h2;
if ((y + h2) > ury) ury = y + h2;
}
END_G {
clustBB ($);
$.bb = sprintf ("%lf,%lf,%lf,%lf", llx, lly, urx, ury);
}
gvpr/bbox 0000644 00000001024 15170512710 0006373 0 ustar 00 /* computes the bounding box of a graph based on node positions */
BEGIN {
double xmin, ymin, xmax, ymax;
xmin = ymin = 1.7976931348623157e+308;
xmax = ymax = -ymin;
double x, y;
}
N {
if (sscanf ($.pos, "%f,%f", &x, &y) == 2) {
if (x < xmin) xmin = x;
if (y < ymin) ymin = y;
if (x > xmax) xmax = x;
if (y > ymax) ymax = y;
}
}
END {
printf ("(%f,%f) (%f,%f)\n", xmin, ymin, xmax, ymax);
if (ARGC) printf ("area = %f aspect = %f\n", ((xmax-xmin)*(ymax-ymin))/1000000., (xmax-xmin)/(ymax-ymin));
}
gvpr/binduce 0000644 00000002216 15170512710 0007056 0 ustar 00 /* Given a bipartite graph, induce a non-bipartite graph.
* argv[0]="name=value" This is used to identify the nodes used
* to induce edges. If aget(n,name) == value,
* if deg(n) == 1, delete
* if deg(n) == 2, delete and connect to neighbor with edge
* if deg(n) > 2, delete and add edge between all pairs of neighbors
* Add weights to edge.
*/
BEGIN{
int i, cnt;
int wt[edge_t];
string values[int];
node_t nbrs[int];
edge_t e;
tokens(ARGV[0],values,"=");
string aname = values[0];
string value = values[1];
printf(2, "%s=%s\n", aname, value);
}
N[aget($,aname)==value] {
if ($.degree > 1) {
cnt = 0;
for (e = fstedge($); e; e = nxtedge(e, $))
nbrs[cnt++] = opp(e,$);
for (i = 0; i < cnt-1; i++) {
if ((e = isEdge(nbrs[i],nbrs[i+1],"")) != NULL) {
wt[e] += 1;
}
else if ($G.directed && (e = isEdge(nbrs[i+1],nbrs[i],""))) {
wt[e] += 1;
}
else if (nbrs[i] != nbrs[i+1]) { // avoid loops
e = edge(nbrs[i],nbrs[i+1],"");
wt[e] = 1;
}
}
unset(nbrs);
}
delete($G,$);
}
END_G{
for (wt[e]) {
e.multiplicity = sprintf ("%d", wt[e]);
}
}
gvpr/bipart 0000644 00000000707 15170512710 0006731 0 ustar 00 /* Determine if a graph is bipartite or not.
*/
BEG_G{
int vc, c, color[node_t];
node_t v;
edge_t e;
$tvtype = TV_dfs;
$tvroot = fstnode($);
}
N{
if ($tvedge == NULL)
color[$] = 1;
if (color[$] == 1)
c = 2;
else
c = 1;
for (e = fstedge($); e; e = nxtedge(e,$)) {
v = opp(e,$);
vc = color[v];
if (vc == 0)
color[v] = c;
else if (vc != c) {
printf(2, "Not bipartite\n");
exit(1);
}
}
}
gvpr/chkclusters 0000644 00000001024 15170512710 0007773 0 ustar 00 /* Report if graph has non-hierarchical clusters */
BEGIN {
graph_t c[node_t];
node_t n;
void proc (graph_t h, graph_t p, graph_t g)
{
if (h.name == "cluster*") {
for (n = fstnode(h); n; n = nxtnode_sg(h,n)) {
g = c[n];
if (g) {
if (g != p) {
printf(2,"node %s in %s and %s\n", n.name, h.name, g.name);
exit(1);
}
}
c[n] = h;
}
p = h;
}
for (g = fstsubg(h); g; g = nxtsubg(g)) {
proc(g,p,NULL);
}
}
}
BEG_G {
proc($,$,NULL);
}
gvpr/chkedges 0000644 00000001624 15170512710 0007224 0 ustar 00 /* Looks for multiedges and loops, and output
* those found along with counts. If the -d flag
* is given, edge direction is taken into account.
*/
BEGIN{
char* ename;
char* n;
int doDir, cnt[];
int loopcnt[];
int nloops, nmulti;
if ((ARGC > 0) && (ARGV[0] == "-d"))
doDir = 1;
else
doDir = 0;
}
BEG_G{unset(cnt); unset(loopcnt); nloops = nmulti = 0;}
E{
if (doDir || (tail.name <= head.name)) ename=tail.name+"_"+head.name;
else ename = head.name+"_"+tail.name;
if (tail == head) {
loopcnt[ename] += 1;
if (loopcnt[ename] == 1) nloops += 1;
}
else {
cnt[ename] += 1;
if (cnt[ename] == 2) nmulti += 1;
}
}
END_G{
printf ("graph %s: %d loops %d multiedges\n", $.name, nloops, nmulti);
for (cnt[n]) {
if (cnt[n] > 1)
printf ("%s : %d\n", n, cnt[n]);
}
for (loopcnt[n]) {
if (loopcnt[n] > 0)
printf ("%s : %d\n", n, loopcnt[n]);
}
}
gvpr/cliptree 0000644 00000000262 15170512710 0007253 0 ustar 00 /* Construct subgraph reachable from node ARGV[0] by forward edges */
BEG_G {
node_t r = node($,ARGV[0]);
$tvroot = r;
$tvtype = TV_fwd;
}
N{$tvroot=NULL; subnode($T,$);}
gvpr/col 0000644 00000001131 15170512710 0006215 0 ustar 00 # test
/* color nodes using output of dijkstra */
BEG_G {
double h, hn, hf, d, sat, md = maxdist;
if (hue_near =="") hue_near = 0.8;
if (hue_far =="") hue_far = 1.2;
hn = hue_near;
hf = hue_far;
}
# test
N {
d = dist;
sat = (md - d + 1.0) /( md + 1.0);
h = hn + ((hf - hn) * d)/md;
while (h < 0.0) h = h + 1.0;
while (h > 1.0) h = h - 1.0;
color = sprintf("%lf %lf %lf",hue,sat,1.0);
/* make sure the shape is filled */
if (!match(style,"filled")>=0) {
if (style != "") style=sprintf("%s,filled",style);
else style="filled";
}
}
gvpr/collapse 0000644 00000000725 15170512710 0007252 0 ustar 00 /* Collapse all edges with same group attribute into a single edge */
BEG_G {
int seen[string];
$O = $; // Use the input graph as output.
}
E {
if (collapse == "") return; // If no collapse, ignore.
if (seen[collapse]) delete ($G, $); // If already seen an edge with this collapse value,
// delete the edge.
else seen[collapse] = 1; // Else mark collapse value as seen and keep edge.
}
gvpr/color 0000644 00000002640 15170512710 0006564 0 ustar 00 /* color edges based on normalized length alpha.
* If we have lim[i-1] <= alpha <= lim[i], the color
* is linearly interpolated between color[i-1] and color[i].
* Edges already having a color attribute are left unchanged.
*/
BEGIN {
double lens [edge_t];
double maxlen, len, minlen=1.7976931348623157e+308;
double alpha, x0, y0, x1, y1;
double h0, s0, v0;
int i;
int ncolors; /* number of colors: ncolors >= 2 */
/* start of color i.
* lim[0]=0 < lim[1] < ... < lim[ncolors-1]=1
*/
double lim[int];
/* HSV values for color i */
double h[int];
double s[int];
double v[int];
/* simple default */
ncolors = 2;
lim[0] = 0;
lim[1] = 1;
h[0] = 0;
h[1] = 0.67;
s[0] = 1;
s[1] = 1;
v[0] = 1;
v[1] = 1;
}
E{
sscanf ($.tail.pos, "%f,%f", &x0, &y0);
sscanf ($.head.pos, "%f,%f", &x1, &y1);
len = sqrt ((x0-x1)*(x0-x1) + (y0-y1)*(y0-y1));
lens[$] = len;
if (len > maxlen) maxlen = len;
if (len < minlen) minlen = len;
}
BEG_G {
if (!isAttr($,"E","color"))
setDflt($,"E","color","");
}
E{
if ($.color != "") return;
alpha = (lens[$]-minlen)/(maxlen-minlen);
for (i = 1; i < ncolors; i++) {
if (alpha < lim[i]) break;
}
alpha = (alpha - lim[i-1])/(lim[i] - lim[i-1]);
h0 = (1-alpha)*h[i-1] + alpha*h[i];
s0 = (1-alpha)*s[i-1] + alpha*s[i];
v0 = (1-alpha)*v[i-1] + alpha*v[i];
$.color = sprintf ("%.02f %.02f %.02f", h0, s0, v0);
}
gvpr/cycle 0000644 00000001060 15170512710 0006540 0 ustar 00 /* Detect directed cycle and print one if found */
BEG_G{
node_t tp, hp;
node_t stk[node_t];
$tvtype = TV_prepostfwd;
$tvroot = fstnode($);
}
N {
if (stk[$]) {
stk[$] = NULL;
}
else if ($tvedge == NULL) { /* current root */
stk[$] = $;
}
else {
stk[$] = $tvedge.tail;
}
}
E {
if (stk[$.head]) {
tp = $.tail;
hp = $.head;
while (tp != $.head) {
printf ("%s -> %s\n", tp.name, hp.name);
hp = tp;
tp = stk[tp];
}
printf ("%s -> %s\n", tp.name, hp.name);
exit(0);
}
}
gvpr/dechain 0000644 00000000410 15170512710 0007032 0 ustar 00 /* Remove peninsulas - chains hanging off the main graph */
BEGIN {
edge_t e;
node_t v, n;
}
N [degree == 1] {
n = $;
while (n.degree == 1) {
e = fstedge (n);
if (e.head == n) v = e.tail;
else v = e.head;
delete($G,n);
n = v;
}
}
gvpr/deghist 0000644 00000000537 15170512710 0007100 0 ustar 00 /* print histogram of node degrees */
BEGIN {
int degrees[];
int maxd = 0;
int i, d;
char* maxn;
}
N{
degrees[degree]++;
if (degree > maxd) {
maxn = $.name;
maxd = degree;
}
}
END {
printf ("max node %s (%d)\n", maxn, maxd);
for (i = 1; i <= maxd; i++) {
d = degrees[i];
if (d > 0) printf ("[%d] %d\n", i, d);
}
}
gvpr/deledges 0000644 00000000164 15170512710 0007221 0 ustar 00 /* delete all edges */
BEGIN {
int map[edge_t];
edge_t e;
}
E {map[$]=1}
END_G {
for (map[e]) delete ($,e);
}
gvpr/delmulti 0000644 00000000615 15170512710 0007265 0 ustar 00 /* create a copy of the input graph with no multiedges */
BEG_G {
graph_t g = graph ("merge", "S");
}
E {
int wt;
node_t h = node(g,$.head.name);
node_t t = node(g,$.tail.name);
edge_t e = isEdge(t,h,"");
wt = $.weight;
if (wt <= 0) wt = 1;
if (e) {
e.weight = e.weight + wt;
}
else if (h != t) {
e = edge(t,h,"");
e.weight = wt;
}
}
END_G {
fwriteG(g,1);
}
gvpr/delnodes 0000644 00000000371 15170512710 0007242 0 ustar 00 /* Delete nodes whose names are given in ARGV */
BEG_G {
int names[char*];
int nodes[node_t];
node_t n;
int i;
for (i = 0; i < ARGC; i++)
names[ARGV[i]] = 1;
}
N[names[name]]{nodes[$] = 1}
END_G {
for (nodes[n])
delete ($,n);
}
gvpr/depath 0000644 00000001043 15170512710 0006707 0 ustar 00 /* Replace paths a -> b -> ... -> c with a -> c */
BEGIN {
edge_t e;
node_t n, prv, nxt;
}
N [(indegree == 1) && (outdegree == 1)] {
e = fstin ($);
prv = e.tail;
e = fstout ($);
nxt = e.head;
delete ($G,$);
while ((prv.indegree == 1) && (prv.outdegree == 0)) {
e = fstin (prv);
n = e.tail;
delete ($G,prv);
prv = n;
}
while ((nxt.indegree == 0) && (nxt.outdegree == 1)) {
e = fstout (nxt);
n = e.head;
delete ($G,nxt);
nxt = n;
}
if (!isEdge (prv,nxt,""))
edge (prv,nxt,"");
}
gvpr/dijkstra 0000644 00000001207 15170512710 0007257 0 ustar 00 /* Given graph processed by dijkstra, and node,
* color shortest path
* Assumes path has been computed by dijkstra
*/
BEG_G {
node_t n = isNode($,ARGV[0]);
node_t nxt;
edge_t e;
double d, totd = 0;
if (n == NULL) {
printf(2, "no node named \"%s\"\n", ARGV[0]);
exit(1);
}
while (n.prev != "") {
nxt = isNode($,n.prev);
/* printf(2, "nxt \"%s\"\n", nxt.name); */
e = isEdge (n, nxt, "");
if (e == NULL) {
printf(2, "no edge between %s and %s\n", n.name, nxt.name);
}
e.color = "blue";
/* printf(2, "len %s\n", e.len); */
/* sscanf (e.len, "%f", &d); */
/* totd += d; */
n = nxt;
}
}
gvpr/flatten 0000644 00000000130 15170512710 0007073 0 ustar 00 /* Wipe out any cluster structure */
BEG_G { $O = copy (NULL,$); }
E { clone ($O, $); }
gvpr/get-layers-list 0000644 00000000425 15170512710 0010472 0 ustar 00 BEG_G {
char* larr[int];
int i;
if (!isAttr($,"G","layers")) return;
if (isAttr($,"G","layersep"))
tokens($.layers,larr,$.layersep);
else
tokens($.layers,larr," :\t");
for (larr[i]) {
if (i>0) printf(" %s",larr[i]);
else printf("%s",larr[i]);
}
}
gvpr/group 0000644 00000001427 15170512710 0006604 0 ustar 00 /* Collapse all nodes with group = X into a single node */
BEG_G {
node_t metaN;
graph_t g = graph ("metagraph", "S");
$tvtype = TV_ne;
$O = g;
}
/* create only one node with given name/value */
N[group == "X"] {
if (!metaN) {
metaN = node (g, $.name);
}
}
/* duplicate all others */
N[group != "X"] { node (g, $.name); }
/* Create an edge only if at least one of the nodes
* is not a collapsed node */
E {
node_t t;
node_t h;
if ($.tail.group == "X") {
if ($.head.group == "X") return;
t = metaN;
h = node (g, $.head.name);
}
else if ($.head.group == "X") {
t = node (g, $.tail.name);
h = metaN;
}
else {
t = node (g, $.tail.name);
h = node (g, $.head.name);
}
edge (t, h, "");
}
/* set g to be output graph */
gvpr/histogram 0000644 00000000477 15170512710 0007451 0 ustar 00 /* print histogram of integer attribute */
BEGIN {
int count[];
int maxd = 0;
int i, d, v;
char* attrname = ARGV[0];
}
N{
v = (int)(aget($,attrname));
count[v]++;
if (v > maxd) {
maxd = v;
}
}
END {
for (i = 1; i <= maxd; i++) {
d = count[i];
if (d > 0) printf ("[%d] %d\n", i, d);
}
}
gvpr/indent 0000644 00000000572 15170512710 0006731 0 ustar 00 /* Print the depth-first traversal of nodes
* as an indented list
*/
BEGIN {
int i, indent;
int seen[string];
void prInd () {
for (i = 0; i < indent; i++) printf (" ");
}
}
BEG_G {
$tvtype = TV_prepostfwd;
$tvroot = node($,ARGV[0]);
}
N {
if (seen[$.name]) indent--;
else {
prInd();
print ($.name);
seen[$.name] = 1;
indent++;
}
}
gvpr/knbhd 0000644 00000002312 15170512710 0006530 0 ustar 00 /* knbhd - Return the k-neighborhood of a node, i.e., allnodes
* whose path length from the given node is <= k.
* ARGV[] = k node_name
*/
BEG_G {
node_t ctr;
int maxlen;
graph_t comp = subg($, "kcomp");
int sid = 0, eid = 0;
int curlen;
node_t curnode;
int nlen[node_t];
node_t stk[int];
node_t other;
edge_t e;
if (ARGC != 2) {
printf (2, "Two arguments required\n");
exit(1);
}
if (!sscanf(ARGV[0],"%d",&maxlen)) {
printf (2, "Improper length parameter \"%s\"\n", ARGV[0]);
exit(1);
}
maxlen++; /* length of 0 means unset */
ctr = isNode ($, ARGV[1]);
if (!ctr) {
printf (2, "node %s not found\n", ARGV[1]);
exit(1);
}
subnode (comp,ctr);
nlen[ctr] = 1;
curnode = ctr;
while (curnode) {
curlen = nlen[curnode];
if (curlen == maxlen) break;
for (e = fstedge(curnode); e; e = nxtedge(e,curnode)) {
other = e.head;
if (other == curnode) other = e.tail;
if (nlen[other]) continue; /* already seen */
subnode(comp,other);
nlen[other] = curlen+1;
stk[eid++] = other;
}
if (sid < eid) curnode = stk[sid++];
else curnode = NULL;
}
induce(comp);
write(comp);
}
gvpr/maxdeg 0000644 00000000463 15170512710 0006714 0 ustar 00 /* find nodes of max and min degree */
BEG_G {node_t mxn, mnn; int maxd = -1; int mind = 1000000;}
N {
if (degree > maxd)
{maxd = degree; mxn = $;}
if (degree < mind)
{mind = degree; mnn = $;}
}
END_G {printf ("max degree = %d, node %s, min degree = %d, node %s\n",
maxd, mxn.name, mind, mnn.name)}
gvpr/path 0000644 00000000701 15170512710 0006376 0 ustar 00 /* Report the distance from src = ARGV[0] to dst = ARGV[1]
*/
BEG_G {
int dist[node_t];
node_t n, curn;
node_t src = node($G, ARGV[0]);
node_t dst = node($G, ARGV[1]);
$tvroot = src;
$tvtype = TV_bfs;
}
N {
curn = $;
if ($ == dst) {
printf ("dist from %s to %s is %d\n", src.name, dst.name, dist[dst]);
exit(0);
}
}
E {
if ($.head == curn) n = $.tail;
else n = $.head;
if (dist[n] == 0) dist[n] = dist[curn]+1;
}
gvpr/rotate 0000644 00000002252 15170512710 0006743 0 ustar 00 /* Given node name and angle, rotate a layout using the given
* node as origin.
*/
BEGIN {
double x,y;
double x0,y0;
double x1,y1;
double angle, cosa, sina;
int cnt, sz;
void rotate (double a, double b) {
a -= x0;
b -= y0;
x1 = a*cosa - b*sina;
y1 = a*sina + b*cosa;
}
char* rotateE (char* p) {
char* newpos = "";
cnt = sscanf (p, "e,%lf,%lf%n", &x, &y, &sz);
if (cnt == 2) {
rotate (x,y);
newpos = newpos + sprintf ("e%lf,%lf ", x1, y1);
p = substr(p, sz);
}
cnt = sscanf (p, "s,%lf,%lf%n", &x, &y, &sz);
if (cnt == 2) {
rotate (x,y);
newpos = newpos + sprintf ("s%lf,%lf ", x1, y1);
p = substr(p, sz);
}
while (sscanf (p, "%lf,%lf%n", &x, &y, &sz) == 2) {
rotate (x,y);
newpos = newpos + sprintf ("%lf,%lf ", x1, y1);
p = substr(p, sz);
}
return newpos;
}
}
BEG_G {
node_t ctr = node ($, ARGV[0]);
sscanf (ARGV[1], "%f", &angle);
cosa = cos(angle);
sina = sin(angle);
sscanf (ctr.pos, "%f,%f", &x0, &y0);
$.bb ="";
}
N {
sscanf ($.pos, "%f,%f", &x, &y);
rotate (x,y);
$.pos = sprintf ("%f,%f", x1, y1);
}
E {
$.pos = rotateE($.pos);
}
gvpr/scale 0000644 00000002173 15170512710 0006536 0 ustar 00 /* finds node n with root attribute
* finds distance minr of closest node
* the layout is then scaled out from n so that
* a node is put on the smallest circle of radius x*minr
* containing n
*/
BEG_G {
node_t ctr;
int cx, cy;
int x, y;
double delx, dely;
int newx, newy;
node_t n;
edge_t e;
int i, sc, d, mind = -1;
double fact, newr, ang, minr;
ctr = node($,aget($,"root"));
sscanf (ctr.pos, "%d,%d", &cx, &cy);
for (e = fstedge(ctr); e; e = nxtedge(e, ctr)) {
if (e.head == ctr) n = e.tail;
else n = e.head;
sscanf (n.pos, "%d,%d", &x, &y);
d = (x-cx)*(x-cx) + (y-cy)*(y-cy);
if ((mind == -1) || (d < mind)) mind = d;
}
minr = (int)sqrt((double)mind);
}
N [$ != ctr] {
sscanf ($.pos, "%d,%d", &x, &y);
dely = y - cy;
delx = x - cx;
d = delx*delx + dely*dely;
sc = (int)sqrt((double)(d/mind));
if (sc > 1) {
fact = 2.0;
for (i=1; i<sc-1;i++) fact *= 2.0;
newr = minr*(2.0 - (1.0/fact));
ang = atan2 (dely, delx);
newx = newr*cos(ang) + cx;
newy = newr*sin(ang) + cy;
$.pos = sprintf ("%d,%d", newx, newy);
}
}
gvpr/scalexy 0000644 00000002143 15170512710 0007114 0 ustar 00 /* finds root node of graph.
* scales the x and y position of all other nodes using, first,
* ARGV[0], or $G.scale.
*
* The expected syntax is "x,y" where at least one of x or y must
* be given. If only one is given, the other is taken as 1.
*/
BEGIN {
double scalex, scaley;
int r, done;
int setScale (char* s)
{
if ((sscanf (s, ",%f",&scaley))) {
scalex = 1;
return 1;
}
else {
r = sscanf (s, "%f,%f",&scalex,&scaley);
if (r) {
if (r == 1) scaley = 1;
return 1;
}
}
return 0;
}
}
BEG_G {
node_t ctr = node($,aget($,"root"));
double cx, cy, x, y, delx;
/* get scale argument */
done = 0;
if (ARGC == 1)
done = setScale (ARGV[0]);
if (!done && isAttr($,"G","scale"))
done = setScale ($.scale);
if (!done)
scalex = scaley = 1.0;
if ((scalex == 1.0) && (scaley == 1.0))
exit (0);
$.bb = "";
sscanf (ctr.pos, "%f,%f", &cx, &cy);
}
N [$ != ctr] {
sscanf ($.pos, "%f,%f", &x, &y);
delx = scalex*(x - cx) + cx;
dely = scaley*(y - cy) + cy;
$.pos = sprintf ("%f,%f", delx, dely);
}
gvpr/span 0000644 00000000213 15170512710 0006401 0 ustar 00 /* derive simple spanning tree */
BEG_G { $tvtype = TV_dfs; $tvroot = node($,ARGV[0]);}
E [!isSubnode($T,$.head) || !isSubnode($T,$.tail)]
gvpr/topon 0000644 00000000655 15170512710 0006611 0 ustar 00 /* Generate copy of topology of input graph
* Replace names with numbers
*/
BEGIN {
int id = 0;
char* names[char*];
char* mapn (char* inname)
{
char* s = names[inname];
if (s == "") {
s = id++;
names[inname] = s;
}
return s;
}
}
BEG_G {
graph_t g = graph ($.name, "U");
}
N { node (g, mapn($.name)); }
E { edge (node (g, mapn($.tail.name)), node (g, mapn($.head.name)), ""); }
END_G {
write (g);
}
gvpr/treetoclust 0000644 00000001734 15170512710 0010026 0 ustar 00 /* Convert a rooted tree to a hierarchy of clusters for patchwork.
* ARGV[0] is desired root
*/
BEG_G {
node_t rt;
node_t n;
graph_t cg;
graph_t sg;
int depth;
int mark[node_t];
graph_t stk[int];
if (! $.directed) {
printf(2,"Input graph is not directed\n");
exit (1);
}
rt = isNode($,ARGV[0]);
if (rt == NULL) {
printf(2,"Root node \"%s\" not found\n", ARGV[0]);
exit (1);
}
$tvroot = rt;
$tvtype = TV_prepostfwd;
cg = graph(rt.name,"U");
}
N {
if (mark[$]) {
depth--;
}
else {
mark[$] = 1;
if (depth > 0) {
if (fstout($)) {
sg = subg(stk[depth-1], "cluster_" + $.name);
if (($.style == "filled") && ($.fillcolor != ""))
sg.bgcolor = $.fillcolor;
}
else {
sg = NULL;
n = node(stk[depth-1], $.name);
n.style = "filled";
n.fillcolor = $.fillcolor;
}
}
else sg = cg;
stk[depth] = sg;
depth++;
}
}
END_G {
write(cg);
}
lefty/box.lefty 0000644 00000007035 15170512710 0007530 0 ustar 00 load ('def.lefty');
definit ();
#
# initialize window data
#
canvas = defcanvas;
wrect = [0 = ['x' = 0; 'y' = 0;]; 1 = ['x' = 400; 'y' = 500;];];
setwidgetattr (canvas, ['window' = wrect;]);
#
# data structures
#
objarray = [];
objnum = 0;
#
# misc functions
#
min = function (a, b) {
if (a <= b)
return a;
return b;
};
max = function (a, b) {
if (b <= a)
return a;
return b;
};
rectof = function (p1, p2) {
return [
0 = ['x' = min (p1.x, p2.x); 'y' = min (p1.y, p2.y);];
1 = ['x' = max (p1.x, p2.x); 'y' = max (p1.y, p2.y);];
];
};
pointadd = function (p1, p2) {
return ['x' = p2.x + p1.x; 'y' = p2.y + p1.y;];
};
pointsub = function (p1, p2) {
return ['x' = p2.x - p1.x; 'y' = p2.y - p1.y;];
};
#
# rendering functions
#
drawbox = function (obj, color) {
box (canvas, obj, obj.rect, ['color' = color;]);
};
redrawboxes = function () {
local i;
clear (canvas);
for (i = 0; i < objnum; i = i + 1)
drawbox (objarray[i], 1);
};
redraw = function (canvas) {
redrawboxes ();
};
#
# editing functions
#
new = function (rect) {
objarray[objnum] = [
'rect' = rect;
'id' = objnum;
];
objnum = objnum + 1;
return objarray[objnum - 1];
};
reshape = function (obj, rect) {
obj.rect = rect;
return obj;
};
move = function (obj, p) {
obj.rect[0] = pointadd (obj.rect[0], p);
obj.rect[1] = pointadd (obj.rect[1], p);
return obj;
};
delete = function (obj) {
if (obj.id ~= objnum - 1) {
objarray[obj.id] = objarray[objnum - 1];
objarray[obj.id].id = obj.id;
}
remove (objnum - 1, objarray);
objnum = objnum - 1;
};
#
# user interface functions
#
# left mouse button creates new box
# middle button moves a box
# right button deletes a box
#
leftdown = function (data) {
if (data.obj ~= null)
return;
leftbox = new (rectof (data.pos, data.pos));
drawbox (leftbox, 1);
setgfxattr (canvas, ['mode' = 'xor';]);
};
leftmove = function (data) {
if (~leftbox)
return;
drawbox (leftbox, 1);
clearpick (canvas, leftbox);
reshape (leftbox, rectof (data.ppos, data.pos));
drawbox (leftbox, 1);
};
leftup = function (data) {
if (~leftbox)
return;
drawbox (leftbox, 1);
clearpick (canvas, leftbox);
reshape (leftbox, rectof (data.ppos, data.pos));
setgfxattr (canvas, ['mode' = 'src';]);
drawbox (leftbox, 1);
remove ('leftbox');
};
middledown = function (data) {
if (data.obj == null)
return;
middlebox = data.obj;
middlepos = data.pos;
setgfxattr (canvas, ['mode' = 'xor';]);
};
middlemove = function (data) {
if (~middlebox)
return;
drawbox (middlebox, 1);
clearpick (canvas, middlebox);
move (middlebox, pointsub (middlepos, data.pos));
middlepos = data.pos;
drawbox (middlebox, 1);
};
middleup = function (data) {
if (~middlebox)
return;
drawbox (middlebox, 1);
clearpick (canvas, middlebox);
move (middlebox, pointsub (middlepos, data.pos));
setgfxattr (canvas, ['mode' = 'src';]);
drawbox (middlebox, 1);
remove ('middlepos');
remove ('middlebox');
};
rightup = function (data) {
if (data.pobj == null)
return;
drawbox (data.obj, 0);
clearpick (canvas, data.obj);
delete (data.obj);
};
dops = function () {
local s;
s = ['x' = 8 * 300; 'y' = 10.5 * 300;];
canvas = createwidget (-1, ['type' = 'ps'; 'size' = s;]);
setwidgetattr (canvas, ['window' = wrect;]);
redraw (canvas);
destroywidget (canvas);
canvas=defcanvas;
};
lefty/def.lefty 0000644 00000000713 15170512710 0007472 0 ustar 00 definit = function () {
defview = createwidget (-1, [
'type' = 'view';
'name' = 'graphics view';
'origin' = ['x' = 1; 'y' = 1;];
'size' = ['x' = 400; 'y' = 500;];
]);
defscroll = createwidget (defview, ['type' = 'scroll';]);
defcanvas = createwidget (defscroll, [
'type' = 'canvas';
'origin' = ['x' = 1; 'y' = 1;];
'size' = ['x' = 400; 'y' = 500;];
'borderwidth' = 1;
]);
};
lefty/dotty.lefty 0000644 00000054774 15170512710 0010117 0 ustar 00 #
# 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));
};
lefty/dotty_draw.lefty 0000644 00000046752 15170512710 0011131 0 ustar 00 #
# 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' = toint ((vt.wrect[1].x - vt.wrect[0].x) / w2v);
'y' = toint ((vt.wrect[1].y - vt.wrect[0].y) / w2v);
];
setwidgetattr (vt.canvas, [
'window' = vt.wrect;
'viewport' = vt.vsize;
]);
attr = getwidgetattr (vt.canvas, [0 = 'viewport';]);
vt.vsize = copy (attr.viewport);
}
};
dotty.protogt.setviewscale = function (views, factor) {
local vid, vt, w2v, attr;
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;]);
attr = getwidgetattr (vt.canvas, [0 = 'viewport';]);
vt.vsize = copy (attr.viewport);
}
};
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;]);
}
};
#
# draw graph components
#
dotty.protogt.drawsgraph = function (gt, views, sgraph) {
sgraph.draw = 1;
if (~sgraph.draws)
return;
gt.execalldraw (gt, views, null, sgraph.draws, [
'fontname' = sgraph.fontname;
'fontsize' = sgraph.fontsize;
'fontcolor' = sgraph.fontcolor;
'drawcolor' = sgraph.drawcolor;
'fillcolor' = sgraph.fillcolor;
]);
};
dotty.protogt.undrawsgraph = function (gt, views, sgraph) {
sgraph.drawn = 0;
if (~sgraph.draws)
return;
gt.execalldraw (gt, views, null, sgraph.draws, [
'fontname' = sgraph.fontname;
'fontsize' = sgraph.fontsize;
'fontcolor' = sgraph.fontcolor;
'drawcolor' = 0;
'fillcolor' = 0;
]);
};
dotty.protogt.drawnode = function (gt, views, node) {
local vid;
node.drawn = 1;
if (~node.draws)
return;
gt.execalldraw (gt, views, node, node.draws, [
'fontname' = node.fontname;
'fontsize' = node.fontsize;
'fontcolor' = node.fontcolor;
'drawcolor' = node.drawcolor;
'fillcolor' = node.fillcolor;
]);
for (vid in views)
setpick (views[vid].canvas, node, node.rect);
};
dotty.protogt.undrawnode = function (gt, views, node) {
local vid;
if (~node.drawn)
return;
node.drawn = 0;
if (~node.pos)
return;
gt.execalldraw (gt, views, node, node.draws, [
'nooverride' = 1;
'fontname' = node.fontname;
'fontsize' = node.fontsize;
'fontcolor' = 0;
'drawcolor' = 0;
'fillcolor' = 0;
]);
for (vid in views)
clearpick (views[vid].canvas, node);
};
dotty.protogt.movenode = function (gt, node, pos) {
local dp, eid, edge;
dp.x = pos.x - node.pos.x;
dp.y = pos.y - node.pos.y;
gt.undrawnode (gt, gt.views, node);
node.pos.x = pos.x;
node.pos.y = pos.y;
gt.movenodedraw (node.draws, dp);
for (eid in node.edges) {
edge = node.edges[eid];
gt.undrawedge (gt, gt.views, edge);
gt.moveedgedraw (edge.draws, edge.tail.pos, edge.head.pos);
gt.drawedge (gt, gt.views, edge);
}
gt.drawnode (gt, gt.views, node);
};
dotty.protogt.drawedge = function (gt, views, edge) {
local vid, canvas;
edge.drawn = 1;
if (~edge.draws)
return;
gt.execalldraw (gt, views, edge, edge.draws, [
'fontname' = edge.fontname;
'fontsize' = edge.fontsize;
'fontcolor' = edge.fontcolor;
'drawcolor' = edge.drawcolor;
'fillcolor' = edge.fillcolor;
]);
for (vid in views) {
canvas = views[vid].canvas;
if (gt.edgehandles == 0 | ~edge.draws.ep)
continue;
arc (canvas, edge, edge.draws.ep, ['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.draws)
return;
gt.execalldraw (gt, views, edge, edge.draws, [
'nooverride' = 1;
'fontname' = edge.fontname;
'fontsize' = edge.fontsize;
'fontcolor' = 0;
'drawcolor' = 0;
'fillcolor' = 0;
]);
for (vid in views) {
canvas = views[vid].canvas;
if (gt.edgehandles == 0 | ~edge.draws.ep)
continue;
arc (canvas, edge, edge.draws.ep, ['x' = 5; 'y' = 5;], ['color' = 0;]);
clearpick (canvas, edge);
}
};
#
# draw directives
#
dotty.protogt.execalldraw = function (gt, views, obj, draws, gc) {
local vid, vt, did, draw, i, func;
for (vid in views) {
vt = views[vid];
for (did in draws) {
if (did == 'ep')
continue;
draw = draws[did];
for (i = 0; draw[i]; i = i + 1)
if ((func = gt.drawfunc[draw[i].type]))
func (gt, vt.canvas, obj, draw[i], gc);
}
}
};
dotty.protogt.drawfunc.E = function (gt, canvas, obj, data, gc) {
arc (canvas, obj, data.c, data.s, [
'color' = gc.fillcolor; 'style' = gc.style; 'width' = gc.width;
'fill' = 'on';
]);
arc (canvas, obj, data.c, data.s, [
'color' = gc.drawcolor; 'style' = gc.style; 'width' = gc.width;
]);
};
dotty.protogt.drawfunc.e = function (gt, canvas, obj, data, gc) {
arc (canvas, obj, data.c, data.s, [
'color' = gc.drawcolor; 'style' = gc.style; 'width' = gc.width;
]);
};
dotty.protogt.drawfunc.P = function (gt, canvas, obj, data, gc) {
polygon (canvas, obj, data.ps, [
'color' = gc.fillcolor; 'style' = gc.style; 'width' = gc.width;
'fill' = 'on';
]);
polygon (canvas, obj, data.ps, [
'color' = gc.drawcolor; 'style' = gc.style; 'width' = gc.width;
]);
};
dotty.protogt.drawfunc.p = function (gt, canvas, obj, data, gc) {
polygon (canvas, obj, data.ps, [
'color' = gc.drawcolor; 'style' = gc.style; 'width' = gc.width;
]);
};
dotty.protogt.drawfunc.L = function (gt, canvas, obj, data, gc) {
polygon (canvas, obj, data.ps, [
'color' = gc.drawcolor; 'style' = gc.style; 'width' = gc.width;
]);
};
dotty.protogt.drawfunc.b = function (gt, canvas, obj, data, gc) {
splinegon (canvas, obj, data.ps, [
'color' = gc.fillcolor; 'style' = gc.style; 'width' = gc.width;
'fill' = 'on';
]);
};
dotty.protogt.drawfunc.B = function (gt, canvas, obj, data, gc) {
splinegon (canvas, obj, data.ps, [
'color' = gc.drawcolor; 'style' = gc.style; 'width' = gc.width;
]);
};
dotty.protogt.drawfunc.T = function (gt, canvas, obj, data, gc) {
text (canvas, obj, data.p, data.s, gc.fontname, gc.fontsize, data.j, [
'color' = gc.fontcolor; 'style' = gc.style; 'width' = gc.width;
]);
};
dotty.protogt.drawfunc.C = function (gt, canvas, obj, data, gc) {
if (gc.nooverride ~= 1)
gc.fillcolor = data.fillcolor;
};
dotty.protogt.drawfunc.c = function (gt, canvas, obj, data, gc) {
if (gc.nooverride ~= 1) {
gc.drawcolor = data.drawcolor;
gc.fontcolor = data.drawcolor;
}
};
dotty.protogt.drawfunc.F = function (gt, canvas, obj, data, gc) {
gc.fontname = data.fn;
gc.fontsize = data.fs;
};
dotty.protogt.drawfunc.S = function (gt, canvas, obj, data, gc) {
gc.style = data.style;
gc.width = data.width;
};
dotty.protogt.movenodedraw = function (draws, dp) {
local did, draw, i, j;
for (did in draws) {
if (did == 'ep')
continue;
draw = draws[did];
for (i = 0; draw[i]; i = i + 1) {
if (draw[i].type == 'E' | draw[i].type == 'e') {
draw[i].c.x = draw[i].c.x + dp.x;
draw[i].c.y = draw[i].c.y + dp.y;
} else if (draw[i].type == 'P' | draw[i].type == 'p') {
for (j = 1; draw[i].ps[j]; j = j + 1) {
draw[i].ps[j].x = draw[i].ps[j].x + dp.x;
draw[i].ps[j].y = draw[i].ps[j].y + dp.y;
}
} else if (draw[i].type == 'L' | draw[i].type == 'B') {
for (j = 0; draw[i].ps[j]; j = j + 1) {
draw[i].ps[j].x = draw[i].ps[j].x + dp.x;
draw[i].ps[j].y = draw[i].ps[j].y + dp.y;
}
} else if (draw[i].type == 'T') {
draw[i].p.x = draw[i].p.x + dp.x;
draw[i].p.y = draw[i].p.y + dp.y;
}
}
}
};
dotty.protogt.moveedgedraw = function (draws, tp, hp) {
local draws2, did;
for (did in draws)
draws2[did] = draws[did];
for (did in draws2)
remove (did, draws);
draws[0] = [
0 = [
'type' = 'L';
'n' = 2;
'ps' = [
0 = copy (tp);
1 = copy (hp);
];
];
'ep' = ['x' = (tp.x + hp.x) / 2; 'y' = (tp.y + hp.y) / 2;];
];
};
dotty.protogt.simplenodedraw = function (node, c, s) {
local draws;
if (node.attr.shape == 'ellipse')
draws[0] = [
0 = [
'type' = 'e';
'c' = copy (c);
's' = ['x' = s.x / 2; 'y' = s.y / 2;];
];
];
else
draws[0] = [
0 = [
'type' = 'p';
'n' = 5;
'ps' = [
0 = ['x' = c.x - s.x / 2; 'y' = c.y - s.y / 2;];
1 = ['x' = c.x + s.x / 2; 'y' = c.y - s.y / 2;];
2 = ['x' = c.x + s.x / 2; 'y' = c.y + s.y / 2;];
3 = ['x' = c.x - s.x / 2; 'y' = c.y + s.y / 2;];
4 = ['x' = c.x - s.x / 2; 'y' = c.y - s.y / 2;];
];
];
];
return draws;
};
dotty.protogt.simpleedgedraw = function (edge, tp, hp) {
local draws;
draws[0] = [
0 = [
'type' = 'L';
'n' = 2;
'ps' = [
0 = copy (tp);
1 = copy (hp);
];
];
'ep' = ['x' = (tp.x + hp.x) / 2; 'y' = (tp.y + hp.y) / 2;];
];
return draws;
};
#
# utilities
#
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.setbgcolor = function (views, name) {
local vid, vt, t;
for (vid in views) {
vt = views[vid];
if (setwidgetattr (vt.canvas, ['color' = [0 = name;];]) ~= 1) {
t = split (name, ' ');
if (tablesize (t) ~= 3 |
setwidgetattr (vt.canvas, ['color' = [0 = [
'h' = ston (t[0]); 's' = ston (t[1]); 'v' = ston (t[2]);
];];]) ~= 1) {
dotty.message (0, concat ('unknown bgcolor ', name));
return;
}
}
vt.colors['_bgcolor_'] = name;
}
};
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.color)
sgraph[dotty.keys.dcolor] = gt.getcolor (gt.views, attr.color);
else
sgraph[dotty.keys.dcolor] = gt.getcolor (gt.views, 'black');
if (attr.style == 'filled') {
if (attr.fillcolor)
sgraph[dotty.keys.bcolor] = gt.getcolor (gt.views, attr.fillcolor);
else if (attr.color)
sgraph[dotty.keys.bcolor] = gt.getcolor (gt.views, attr.color);
else
sgraph[dotty.keys.bcolor] = gt.getcolor (gt.views, 'lightgrey');
}
};
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.color)
node[dotty.keys.dcolor] = gt.getcolor (gt.views, attr.color);
else
node[dotty.keys.dcolor] = gt.getcolor (gt.views, 'black');
if (attr.style == 'filled') {
if (attr.fillcolor)
node[dotty.keys.bcolor] = gt.getcolor (gt.views, attr.fillcolor);
else if (attr.color)
node[dotty.keys.bcolor] = gt.getcolor (gt.views, attr.color);
else
node[dotty.keys.bcolor] = gt.getcolor (gt.views, 'lightgrey');
}
};
dotty.protogt.unpackedgeattr = function (gt, edge) {
local attr;
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.color)
edge[dotty.keys.dcolor] = gt.getcolor (gt.views, attr.color);
else
edge[dotty.keys.dcolor] = gt.getcolor (gt.views, 'black');
if (attr.style == 'filled') {
if (attr.fillcolor)
edge[dotty.keys.bcolor] = gt.getcolor (gt.views, attr.fillcolor);
else if (attr.color)
edge[dotty.keys.bcolor] = gt.getcolor (gt.views, attr.color);
else
edge[dotty.keys.bcolor] = gt.getcolor (gt.views, 'lightgrey');
}
};
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.color)
graph[dotty.keys.dcolor] = gt.getcolor (gt.views, attr.color);
else
graph[dotty.keys.dcolor] = gt.getcolor (gt.views, 'black');
if (attr.style == 'filled') {
if (attr.fillcolor)
graph[dotty.keys.bcolor] = gt.getcolor (gt.views, attr.fillcolor);
else if (attr.color)
graph[dotty.keys.bcolor] = gt.getcolor (gt.views, attr.color);
else
graph[dotty.keys.bcolor] = gt.getcolor (gt.views, 'lightgrey');
}
if (attr.bgcolor & attr.bgcolor ~= '')
gt.setbgcolor (gt.views, attr.bgcolor);
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.color)
sgraph[dotty.keys.dcolor] = gt.getcolor (gt.views, attr.color);
else
sgraph[dotty.keys.dcolor] = gt.getcolor (gt.views, 'black');
if (attr.style == 'filled') {
if (attr.fillcolor)
sgraph[dotty.keys.bcolor] = gt.getcolor (
gt.views, attr.fillcolor
);
else if (attr.color)
sgraph[dotty.keys.bcolor] = gt.getcolor (gt.views, attr.color);
else
sgraph[dotty.keys.bcolor] = gt.getcolor (gt.views, 'lightgrey');
}
}
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.color)
node[dotty.keys.dcolor] = gt.getcolor (gt.views, attr.color);
else
node[dotty.keys.dcolor] = gt.getcolor (gt.views, 'black');
if (attr.style == 'filled') {
if (attr.fillcolor)
node[dotty.keys.bcolor] = gt.getcolor (
gt.views, attr.fillcolor
);
else if (attr.color)
node[dotty.keys.bcolor] = gt.getcolor (gt.views, attr.color);
else
node[dotty.keys.bcolor] = gt.getcolor (gt.views, 'lightgrey');
}
}
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);
if (attr.color)
edge[dotty.keys.dcolor] = gt.getcolor (gt.views, attr.color);
else
edge[dotty.keys.dcolor] = gt.getcolor (gt.views, 'black');
}
};
lefty/dotty_edit.lefty 0000644 00000043176 15170512710 0011116 0 ustar 00 #
# dotty_edit: editing functions and data structures
#
dotty.protogt.getnodesbyattr = function (gt, key, val) {
local nid, node, nlist;
nlist = [];
for (nid in gt.graph.nodes) {
node = gt.graph.nodes[nid];
if (node.attr[key] == val)
nlist[nid] = node;
}
return nlist;
};
dotty.protogt.reachablenodes = function (gt, node) {
local nlist, stack, eid, edge, i;
stack[0] = node;
i = 1;
while (i > 0) {
node = stack[i - 1];
i = i - 1;
nlist[node.nid] = node;
for (eid in node.edges) {
edge = node.edges[eid];
if (~nlist[edge.head.nid]) {
nlist[edge.head.nid] = edge.head;
stack[i] = edge.head;
i = i + 1;
}
}
}
return nlist;
};
dotty.protogt.mergegraph = function (gt, graph, show) {
local nameid, onode, pos, size, eid, eid2, tnode, hnode, oedge;
if (~gt.noundo)
gt.startadd2undo (gt);
for (nameid in graph.nodedict) {
pos = null;
size = null;
onode = graph.nodes[graph.nodedict[nameid]];
if (onode.pos)
pos = node.pos;
if (onode.size)
size = node.size;
if (~(gt.graph.nodedict[nameid] >= 0)) {
pos = null;
size = null;
if (onode.pos)
pos = node.pos;
if (onode.size)
size = node.size;
gt.insertnode (gt, pos, size, nameid, onode.attr, show);
}
}
for (eid in graph.edges) {
oedge = graph.edges[eid];
tnode = gt.graph.nodes[gt.graph.nodedict[oedge.tail.name]];
hnode = gt.graph.nodes[gt.graph.nodedict[oedge.head.name]];
for (eid2 in tnode.edges)
if (
tnode.edges[eid2].tail == tnode &
tnode.edges[eid2].head == hnode
) {
oedge = null;
break;
}
if (oedge)
gt.insertedge (gt, tnode, null, hnode, null, oedge.attr, show);
}
if (~gt.noundo)
gt.endadd2undo (gt);
};
dotty.protogt.insertsgraph = function (gt, name, attr, show) {
local gid, sgraph, aid;
if (~gt)
return null;
gid = gt.graph.maxgid;
if (~name) {
while (gt.graph.graphdict[(name = concat ('g', gid))] >= 0)
gid = gid + 1;
} else if (gt.graph.graphdict[name]) {
dotty.message (0, concat ('graph: ', name, ' exists'));
return null;
}
gt.graph.graphdict[name] = gid;
gt.graph.maxgid = gid + 1;
gt.graph.graphs[gid] = [
dotty.keys.gid = gid;
dotty.keys.name = name;
dotty.keys.gattr = copy (gt.graph.graphattr);
dotty.keys.nattr = copy (gt.graph.nodeattr);
dotty.keys.eattr = copy (gt.graph.edgeattr);
];
sgraph = gt.graph.graphs[gid];
if (~attr)
attr = [];
if (~attr.label)
attr.label = '\N';
for (aid in attr)
sgraph.graphattr[aid] = attr[aid];
gt.unpacksgraphattr (gt, sgraph);
if (show)
gt.drawsgraph (gt, gt.views, sgraph);
return sgraph;
};
dotty.protogt.removesgraph = function (gt, sgraph) {
gt.undrawsgraph (gt, gt.views, sgraph);
remove (sgraph.name, gt.graph.graphdict);
remove (sgraph.gid, gt.graph.graphs);
};
dotty.protogt.insertnode = function (gt, pos, size, name, attr, show) {
local nid, node, aid;
nid = gt.graph.maxnid;
if (~name) {
while (gt.graph.nodedict[(name = concat ('n', nid))] >= 0)
nid = nid + 1;
} else if (gt.graph.nodedict[name] >= 0) {
dotty.message (0, concat ('node: ', name, ' exists'));
return null;
}
gt.graph.nodedict[name] = nid;
gt.graph.maxnid = nid + 1;
gt.graph.nodes[nid] = [
dotty.keys.nid = nid;
dotty.keys.name = name;
dotty.keys.attr = copy (gt.graph.nodeattr);
dotty.keys.edges = [];
];
node = gt.graph.nodes[nid];
if (~attr)
attr = [];
if (~attr.label)
attr.label = '\N';
for (aid in attr)
node.attr[aid] = attr[aid];
gt.unpacknodeattr (gt, node);
if (~pos)
pos = ['x' = 10; 'y' = 10;];
node[dotty.keys.pos] = copy (pos);
if (~size)
size = ['x' = strlen (attr.label) * 30; 'y' = 30;];
if (size.x == 0)
size.x = 30;
node[dotty.keys.size] = copy (size);
node[dotty.keys.rect] = [
0 = ['x' = pos.x - size.x / 2; 'y' = pos.y - size.y / 2;];
1 = ['x' = pos.x + size.x / 2; 'y' = pos.y + size.y / 2;];
];
node.draws = gt.simplenodedraw (node, pos, size);
if (show)
gt.drawnode (gt, gt.views, node);
if (~gt.noundo) {
gt.startadd2undo (gt);
gt.currundo.inserted.nodes[nid] = node;
gt.endadd2undo (gt);
}
return node;
};
dotty.protogt.removenode = function (gt, node) {
local eid, list, edge, gid;
if (~gt.noundo)
gt.startadd2undo (gt);
for (eid in node.edges)
list[eid] = node.edges[eid];
for (eid in list)
gt.removeedge (gt, list[eid]);
gt.undrawnode (gt, gt.views, node);
for (gid in gt.graph.graphs)
remove (node.nid, gt.graph.graphs[gid].nodes);
remove (node.name, gt.graph.nodedict);
remove (node.nid, gt.graph.nodes);
if (~gt.noundo) {
gt.currundo.deleted.nodes[node.nid] = node;
gt.endadd2undo (gt);
}
};
dotty.protogt.insertedge = function (
gt, nodea, porta, nodeb, portb, attr, show
) {
local eid, edge, aid, tport, hport;
if (~nodea | ~nodeb)
return null;
if (porta)
tport = porta;
if (portb)
hport = portb;
eid = gt.graph.maxeid;
while (gt.graph.edges[eid])
eid = eid + 1;
gt.graph.maxeid = eid + 1;
gt.graph.edges[eid] = [
dotty.keys.eid = eid;
dotty.keys.tail = nodea;
dotty.keys.tport = porta;
dotty.keys.head = nodeb;
dotty.keys.hport = portb;
dotty.keys.attr = copy (gt.graph.edgeattr);
];
edge = gt.graph.edges[eid];
if (~attr)
attr = [];
for (aid in attr)
edge.attr[aid] = attr[aid];
nodea.edges[eid] = edge;
nodeb.edges[eid] = edge;
gt.unpackedgeattr (gt, edge);
edge.draws = gt.simpleedgedraw (edge, nodea.pos, nodeb.pos);
if (show)
gt.drawedge (gt, gt.views, edge);
if (~gt.noundo) {
gt.startadd2undo (gt);
gt.currundo.inserted.edges[eid] = edge;
gt.endadd2undo (gt);
}
return edge;
};
dotty.protogt.removeedge = function (gt, edge) {
local head, tail;
if (~gt.noundo)
gt.startadd2undo (gt);
if (edge.head.attr.support == 1)
head = edge.head;
if (edge.tail.attr.support == 1)
if (head ~= edge.tail)
tail = edge.tail;
gt.undrawedge (gt, gt.views, edge);
remove (edge.eid, edge.head.edges);
remove (edge.eid, edge.tail.edges);
remove (edge.eid, gt.graph.edges);
if (head & tablesize (head.edges) == 0)
gt.removenode (gt, head);
if (tail & tablesize (tail.edges) == 0)
gt.removenode (gt, tail);
if (~gt.noundo) {
gt.currundo.deleted.edges[edge.eid] = edge;
gt.endadd2undo (gt);
}
};
dotty.protogt.swapedgeids = function (gt, edge1, edge2) {
local eid1, eid2;
if (edge1.eid == edge2.eid)
return;
if (~gt.noundo)
gt.startadd2undo (gt);
eid1 = edge1.eid;
eid2 = edge2.eid;
gt.graph.edges[eid1] = edge2;
gt.graph.edges[eid2] = edge1;
remove (eid1, edge1.tail.edges);
remove (eid1, edge1.head.edges);
remove (eid2, edge2.tail.edges);
remove (eid2, edge2.head.edges);
edge1.tail.edges[eid2] = edge1;
edge1.head.edges[eid2] = edge1;
edge2.tail.edges[eid1] = edge2;
edge2.head.edges[eid1] = edge2;
edge1.eid = eid2;
edge2.eid = eid1;
if (~gt.noundo) {
gt.currundo.swapped.edges[eid1] = edge1;
gt.currundo.swapped.edges[eid2] = edge2;
gt.endadd2undo (gt);
}
};
dotty.protogt.removesubtree = function (gt, obj) {
local nlist, node, head, nid, edge, eid;
if (~gt.noundo)
gt.startadd2undo (gt);
if (obj.nid >= 0)
node = obj;
else if (obj.eid >= 0) {
node = obj.head;
gt.removeedge (gt, obj);
if (~gt.graph.nodes[node.nid]) {
if (~gt.noundo)
gt.endadd2undo (gt);
return;
}
for (eid in node.edges) {
edge = node.edges[eid];
if (edge.head == node & edge.tail ~= node) {
if (~gt.noundo)
gt.endadd2undo (gt);
return;
}
}
} else {
dotty.message (0, 'bad object type in gt.removesubtree');
return;
}
nlist = [node.nid = node;];
while (node) {
for (eid in node.edges) {
head = node.edges[eid].head;
if (head ~= node)
nlist[head.nid] = head;
}
gt.removenode (gt, node);
remove (node.nid, nlist);
node = null;
for (nid in nlist) {
node = nlist[nid];
for (eid in node.edges) {
edge = node.edges[eid];
if (edge.head == node & edge.tail ~= node) {
node = null;
break;
}
}
if (node)
break;
}
}
if (~gt.noundo)
gt.endadd2undo (gt);
};
dotty.protogt.removenodesbyattr = function (gt, key, val) {
local nlist, nid;
if (~gt.noundo)
gt.startadd2undo (gt);
nlist = gt.getnodesbyattr (gt, key, val);
for (nid in nlist)
gt.removenode (gt, nlist[nid]);
if (~gt.noundo)
gt.endadd2undo (gt);
};
dotty.protogt.removesubtreesbyattr = function (gt, key, val) {
local nlist, nid;
if (~gt.noundo)
gt.startadd2undo (gt);
nlist = gt.getnodesbyattr (gt, key, val);
for (nid in nlist)
if (gt.graph.nodes[nid])
gt.removesubtree (gt, nlist[nid]);
if (~gt.noundo)
gt.endadd2undo (gt);
};
dotty.protogt.groupnodes = function (
gt, nlist, gnode, pos, size, attr, keepmulti, show
) {
local nid, node, elist, eid, edge, nodea, nodeb, inlist, outlist;
if (~nlist | tablesize (nlist) == 0)
return;
if (gnode.attr.support) {
dotty.message (0, 'cannot group nodes in a support node');
return;
}
if (~gt.noundo)
gt.startadd2undo (gt);
if (~gnode)
gnode = gt.insertnode (gt, pos, size, null, attr, show);
inlist = [];
outlist = [];
for (nid in nlist) {
if ((node = nlist[nid]) == gnode)
continue;
elist = [];
for (eid in node.edges)
elist[eid] = node.edges[eid];
for (eid in elist) {
edge = elist[eid];
if (edge.head == node) {
nodea = edge.tail;
nodeb = gnode;
if (~keepmulti) {
if (inlist[nodea.nid])
continue;
inlist[nodea.nid] = nodea;
if (nodea == gnode)
outlist[nodea.nid] = nodea;
}
} else {
nodea = gnode;
nodeb = edge.head;
if (~keepmulti) {
if (outlist[nodeb.nid])
continue;
outlist[nodeb.nid] = nodeb;
if (nodeb == gnode)
inlist[nodeb.nid] = nodeb;
}
}
gt.insertedge (gt, nodea, null, nodeb, null, edge.attr, show);
}
gt.removenode (gt, node);
}
if (~gt.noundo)
gt.endadd2undo (gt);
return gnode;
};
dotty.protogt.groupnodesbyattr = function (
gt, key, val, attr, keepmulti, show
) {
local nlist, nid, pos, size;
pos = null;
size = null;
nlist = gt.getnodesbyattr (gt, key, val);
if (show)
for (nid in nlist) {
pos = nlist[nid].pos;
size = nlist[nid].size;
break;
}
return gt.groupnodes (gt, nlist, null, pos, size, attr, keepmulti, show);
};
dotty.protogt.cut = function (gt, obj, set, mode, op) {
local clipgt, list, node, nid, edge, eid, clipnode;
clipgt = dotty.clipgt;
clipgt.graph = copy (dotty.protogt.graph);
if (obj.eid >= 0) { # it's an edge
list.edges[obj.eid] = obj;
node = obj.head;
} else if (obj.nid >= 0) {
list.nodes[obj.nid] = obj;
node = obj;
for (eid in node.edges)
list.edges[eid] = node.edges[eid];
} else {
dotty.message (0, 'unknown object type in gt.cut');
return;
}
if (set == 'reachable') {
list.nodes = gt.reachablenodes (gt, node);
for (nid in list.nodes) {
node = list.nodes[nid];
for (eid in node.edges) {
edge = node.edges[eid];
list.edges[edge.eid] = edge;
}
}
}
if (mode == 'support') {
for (eid in list.edges) {
edge = list.edges[eid];
if (~list.nodes[edge.tail.nid]) {
list.support[edge.tail.nid] = edge.tail;
list.nodes[edge.tail.nid] = edge.tail;
}
if (~list.nodes[edge.head.nid]) {
list.support[edge.head.nid] = edge.head;
list.nodes[edge.head.nid] = edge.head;
}
}
}
for (nid = 0; nid < gt.graph.maxnid; nid = nid + 1) {
if (~list.nodes[nid])
continue;
node = list.nodes[nid];
clipnode = gt.insertnode (clipgt, null, null, node.name, node.attr, 0);
if (list.support[nid])
clipnode.support = 1;
list.clipnodes[nid] = clipnode;
}
for (eid = 0; eid < gt.graph.maxeid; eid = eid + 1) {
if (~list.edges[eid])
continue;
edge = list.edges[eid];
if (~list.nodes[edge.tail.nid] | ~list.nodes[edge.head.nid])
continue;
gt.insertedge (
clipgt, list.clipnodes[edge.tail.nid], null,
list.clipnodes[edge.head.nid], null, edge.attr, 0
);
}
if (op ~= 'cut')
return;
if (~gt.noundo)
gt.startadd2undo (gt);
for (eid in list.edges)
gt.removeedge (gt, list.edges[eid]);
for (nid in list.nodes)
if (~list.support[nid] & gt.graph.nodes[nid])
gt.removenode (gt, list.nodes[nid]);
if (~gt.noundo)
gt.endadd2undo (gt);
};
dotty.protogt.paste = function (gt, pos, show) {
local clipgt, offset, center, nid, node, eid, edge, nodes;
if (~gt.noundo)
gt.startadd2undo (gt);
clipgt = dotty.clipgt;
if (clipgt.graph.rect)
center = [
'x' = (clipgt.graph.rect[1].x + clipgt.graph.rect[0].x) / 2;
'y' = (clipgt.graph.rect[1].y + clipgt.graph.rect[0].y) / 2;
];
else
center = pos;
offset = [
'x' = center.x - pos.x;
'y' = center.y - pos.y;
];
for (nid = 0; clipgt.graph.nodes[nid]; nid = nid + 1) {
node = clipgt.graph.nodes[nid];
if (node.attr.label == '\N' | ~node.attr.label)
node.attr.label = node.name;
if (node.support == 1)
nodes[nid] = gt.insertnode (gt, [
'x' = node.pos.x - offset.x;
'y' = node.pos.y - offset.y;
], null, null, [
'support' = 1; 'shape' = 'circle';
'label' = ''; 'width' = 0.2;
], show);
else
nodes[nid] = gt.insertnode (gt, [
'x' = node.pos.x - offset.x;
'y' = node.pos.y - offset.y;
], node.size, null, node.attr, show);
}
for (eid = 0; clipgt.graph.edges[eid]; eid = eid + 1) {
edge = clipgt.graph.edges[eid];
gt.insertedge (
gt, nodes[edge.tail.nid], null,
nodes[edge.head.nid], null, edge.attr, show
);
}
if (~gt.noundo)
gt.endadd2undo (gt);
};
dotty.protogt.startadd2undo = function (gt) {
if (~gt.undoarray.level)
gt.currundo = (
gt.undoarray.entries[tablesize (gt.undoarray.entries)] = []
);
gt.undoarray.level = gt.undoarray.level + 1;
};
dotty.protogt.endadd2undo = function (gt) {
gt.undoarray.level = gt.undoarray.level - 1;
};
dotty.protogt.undo = function (gt, show) {
local entry, n, eid, edge, nid, node, edges;
if ((n = tablesize (gt.undoarray.entries)) < 1)
return;
entry = gt.undoarray.entries[n - 1];
remove (n - 1, gt.undoarray.entries);
remove ('currundo', gt);
gt.noundo = 1;
# hardwire nodes and edges back with the same id's as the originals
for (nid in entry.deleted.nodes) {
node = entry.deleted.nodes[nid];
gt.graph.nodedict[node.name] = node.nid;
gt.graph.nodes[node.nid] = node;
node.edges = [];
if (show)
gt.drawnode (gt, gt.views, node);
}
for (eid in entry.deleted.edges) {
edge = entry.deleted.edges[eid];
gt.graph.edges[edge.eid] = edge;
edge.head.edges[edge.eid] = edge;
edge.tail.edges[edge.eid] = edge;
if (show)
gt.drawedge (gt, gt.views, edge);
}
if (entry.swapped.edges) {
if (tablesize (entry.swapped.edges) == 2) {
n = 0;
for (eid in entry.swapped.edges) {
edges[n] = entry.swapped.edges[eid];
n = n + 1;
}
gt.swapedgeids (gt, edges[0], edges[1]);
} else
dotty.message (0, 'cannot handle undoing swap of > 2 edges');
}
for (eid in entry.inserted.edges) {
edge = entry.inserted.edges[eid];
gt.removeedge (gt, edge);
}
for (nid in entry.inserted.nodes) {
node = entry.inserted.nodes[nid];
gt.removenode (gt, node);
}
gt.noundo = 0;
};
lefty/dotty_layout.lefty 0000644 00000034352 15170512710 0011502 0 ustar 00 #
# dotty_layout: layout functions and data structures
#
dotty.grablserver = function (lserver) {
local fd;
if (~dotty.lservers[lserver] | tablesize (dotty.lservers[lserver]) == 0) {
if (~((fd = openio ('pipe', lserver, 'r+', '%e -Txdot1.2')) >= 0)) {
dotty.message (0, concat ('cannot start ', lserver));
return null;
}
dotty.lservers[lserver][fd] = [
'fd' = fd;
'count' = 0;
];
}
for (fd in dotty.lservers[lserver]) {
dotty.lservers[lserver][fd].count = dotty.lservers[
lserver
][fd].count + 1;
dotty.lservers.inuse[fd] = dotty.lservers[lserver][fd];
remove (fd, dotty.lservers[lserver]);
return fd;
}
};
dotty.releaselserver = function (lserver, fd, state) {
if (state == 'bad' | dotty.lservers.inuse[fd].count > 40) {
closeio (fd, 'kill');
remove (fd, dotty.lservers.inuse);
return;
}
dotty.lservers[lserver][fd] = dotty.lservers.inuse[fd];
remove (fd, dotty.lservers.inuse);
};
dotty.protogt.startlayout = function (gt) {
local lpt, fd;
if (gt.layoutpending >= 1) {
lpt = dotty.layoutpending[gt.gtid];
if (gt.layoutmode == 'async')
monitor ('off', lpt.fd);
dotty.releaselserver (gt.lserver, lpt.fd, 'bad');
remove (gt.gtid, dotty.layoutpending);
gt.layoutpending = 0;
gt.haveinput = 0;
dotty.popbusy (gt, gt.views);
}
if (~((fd = dotty.grablserver (gt.lserver)) >= 0))
return null;
dotty.pushbusy (gt, gt.views);
writegraph (fd, gt.graph, 1);
gt.layoutpending = 1;
dotty.layoutpending[gt.gtid] = [
'fd' = fd;
'gtid' = gt.gtid;
];
if (gt.layoutmode == 'async')
monitor ('on', fd);
return 1;
};
dotty.protogt.finishlayout = function (gt) {
local graph, lpt, fd;
if (~(gt.layoutpending >= 1)) {
dotty.message (0, concat ('no layout pending for graph ', gt.gtid));
return null;
}
lpt = dotty.layoutpending[gt.gtid];
if (~(graph = readgraph (lpt.fd))) {
if (gt.layoutmode == 'async')
monitor ('off', lpt.fd);
dotty.releaselserver (gt.lserver, lpt.fd, 'bad');
if (gt.layoutpending == 2) {
dotty.message (0, concat ('giving up on ', gt.lserver));
if ((fd = openio ('file', 'dottybug.gv', 'w+')) >= 0) {
writegraph (fd, gt.graph, 0);
closeio (fd);
dotty.message (
0, concat ('graph that causes ', gt.lserver)
);
dotty.message (
0, 'to fail has been saved in file dottybug.gv'
);
dotty.message (
0, 'please fill out a bug report at'
);
dotty.message (
0, 'http://www.graphviz.org/bugs/bugform.html'
);
}
dotty.popbusy (gt, gt.views);
gt.layoutpending = 0;
gt.haveinput = 0;
return 1;
}
dotty.message (
1, concat ('lost connection to ', gt.lserver, ', restarting...')
);
lpt.fd = dotty.grablserver (gt.lserver);
writegraph (lpt.fd, gt.graph, 1);
if (gt.layoutmode == 'async')
monitor ('on', lpt.fd);
gt.layoutpending = 2;
gt.haveinput = 0;
return null;
}
if (gt.layoutmode == 'async')
monitor ('off', lpt.fd);
dotty.releaselserver (gt.lserver, lpt.fd, null);
remove (gt.gtid, dotty.layoutpending);
gt.layoutpending = 0;
gt.haveinput = 0;
gt.unpacklayout (gt, graph);
dotty.popbusy (gt, gt.views);
return 1;
};
dotty.protogt.cancellayout = function (gt) {
local lpt, vid;
if (gt.layoutpending >= 1) {
lpt = dotty.layoutpending[gt.gtid];
if (gt.layoutmode == 'async')
monitor ('off', lpt.fd);
dotty.releaselserver (gt.lserver, lpt.fd, 'bad');
remove (gt.gtid, dotty.layoutpending);
gt.layoutpending = 0;
gt.haveinput = 0;
dotty.popbusy (gt, gt.views);
}
};
dotty.protogt.unpacklayout = function (gt, graph2) {
local graph, gid, sgraph1, sgraph2, nid, node1, node2, eid, edge1, edge2;
local t1, pos, size;
graph = gt.graph;
for (gid in graph2.graphdict) {
if (~(sgraph1 = graph.graphs[graph.graphdict[gid]]))
continue;
sgraph2 = graph2.graphs[graph2.graphdict[gid]];
sgraph1.draws = gt.unpackalldraw (gt, sgraph2.graphattr);
}
for (nid in graph2.nodedict) {
if (~(node1 = graph.nodes[graph.nodedict[nid]]))
continue;
node2 = graph2.nodes[graph2.nodedict[nid]];
node1.draws = gt.unpackalldraw (gt, node2.attr);
t1 = split (node2.attr.pos, ',');
pos = ['x' = ston (t1[0]); 'y' = ston (t1[1]);];
size = [
'x' = ston (node2.attr.width) * 72;
'y' = ston (node2.attr.height) * 72;
];
node1.pos = pos;
node1.size = size;
node1.rect = [
0 = ['x' = pos.x - size.x / 2; 'y' = pos.y - size.y / 2;];
1 = ['x' = pos.x + size.x / 2; 'y' = pos.y + size.y / 2;];
];
}
for (eid in graph2.edges) {
edge2 = graph2.edges[eid];
if (edge2.attr.id) {
if (~(edge1 = graph.edges[ston (edge2.attr.id)]))
continue;
} else if (graph == graph2)
edge1 = edge2;
edge1.draws = gt.unpackalldraw (gt, edge2.attr);
}
graph.draws = gt.unpackalldraw (gt, graph2.graphattr);
t1 = split (graph2.graphattr.bb, ',');
graph.rect[0].x = ston (t1[0]);
graph.rect[0].y = ston (t1[1]);
graph.rect[1].x = ston (t1[2]);
graph.rect[1].y = ston (t1[3]);
if (gt.graph ~= graph2)
return;
# strip position and size info from the attributes
for (gid in graph2.graphdict) {
sgraph2 = graph2.graphs[graph2.graphdict[gid]];
gt.removealldraw (gt, sgraph2.graphattr);
if (sgraph2.graphattr.bb)
remove ('bb', sgraph2.graphattr);
}
for (nid in graph2.nodedict) {
node2 = graph2.nodes[graph2.nodedict[nid]];
gt.removealldraw (gt, node2.attr);
if (node2.attr.rects)
remove ('rects', node2.attr);
remove ('pos', node2.attr);
remove ('width', node2.attr);
remove ('height', node2.attr);
}
for (eid in graph2.edges) {
edge2 = graph2.edges[eid];
gt.removealldraw (gt, edge2.attr);
if (edge2.attr.pos)
remove ('pos', edge2.attr);
if (edge2.attr.lp)
remove ('lp', edge2.attr);
}
gt.removealldraw (gt, graph2.graphattr);
remove ('bb', graph2.graphattr);
if (graph2.graphattr.lp)
remove ('lp', graph2.graphattr);
};
#
# draw directive parsing
#
dotty.protogt.unpackalldraw = function (gt, attr) {
local o, did;
o = [];
if (attr._draw_)
o._draw_ = gt.unpackdraw (gt, attr._draw_);
if (attr._background)
o._background = gt.unpackdraw (gt, attr._background);
if (attr._ldraw_)
o._ldraw_ = gt.unpackdraw (gt, attr._ldraw_);
if (attr._hdraw_)
o._hdraw_ = gt.unpackdraw (gt, attr._hdraw_);
if (attr._tdraw_)
o._tdraw_ = gt.unpackdraw (gt, attr._tdraw_);
if (attr._hldraw_)
o._hldraw_ = gt.unpackdraw (gt, attr._hldraw_);
if (attr._tldraw_)
o._tldraw_ = gt.unpackdraw (gt, attr._tldraw_);
for (did in o)
if (o[did].ep) {
o.ep = o[did].ep;
break;
}
return o;
};
dotty.protogt.removealldraw = function (gt, attr) {
if (attr._draw_)
remove ('_draw_', attr);
if (attr._ldraw_)
remove ('_ldraw_', attr);
if (attr._hdraw_)
remove ('_hdraw_', attr);
if (attr._tdraw_)
remove ('_tdraw_', attr);
if (attr._hldraw_)
remove ('_hldraw_', attr);
if (attr._tldraw_)
remove ('_tldraw_', attr);
};
dotty.protogt.unpackdraw = function (gt, attr) {
local oo, o, tt, t, n, i, j, s, l, ep;
oo = [];
t = split (attr, ' ', 0);
n = tablesize (t);
if (t[n - 1] == '') {
remove (n - 1, t);
n = n - 1;
}
i = 0;
while (i < n) {
o = [];
if (t[i] == 'E') {
o.type = t[i];
o.c.x = ston (t[i + 1]);
o.c.y = ston (t[i + 2]);
o.s.x = ston (t[i + 3]);
o.s.y = ston (t[i + 4]);
i = i + 5;
} else if (t[i] == 'e') {
o.type = t[i];
o.c.x = ston (t[i + 1]);
o.c.y = ston (t[i + 2]);
o.s.x = ston (t[i + 3]);
o.s.y = ston (t[i + 4]);
i = i + 5;
} else if (t[i] == 'P') {
o.type = t[i];
o.n = ston (t[i + 1]);
for (j = 0; j < o.n; j = j + 1) {
o.ps[j].x = ston (t[i + 2 + j * 2]);
o.ps[j].y = ston (t[i + 2 + j * 2 + 1]);
}
i = i + 2 + o.n * 2;
o.ps[o.n] = o.ps[0];
o.n = o.n + 1;
} else if (t[i] == 'p') {
o.type = t[i];
o.n = ston (t[i + 1]);
for (j = 0; j < o.n; j = j + 1) {
o.ps[j].x = ston (t[i + 2 + j * 2]);
o.ps[j].y = ston (t[i + 2 + j * 2 + 1]);
}
i = i + 2 + o.n * 2;
o.ps[o.n] = o.ps[0];
o.n = o.n + 1;
} else if (t[i] == 'L') {
o.type = t[i];
o.n = ston (t[i + 1]);
for (j = 0; j < o.n; j = j + 1) {
o.ps[j].x = ston (t[i + 2 + j * 2]);
o.ps[j].y = ston (t[i + 2 + j * 2 + 1]);
}
i = i + 2 + o.n * 2;
if (~ep)
ep = copy (o.ps[1]);
} else if (t[i] == 'B') {
o.type = t[i];
o.n = ston (t[i + 1]);
for (j = 0; j < o.n; j = j + 1) {
o.ps[j].x = ston (t[i + 2 + j * 2]);
o.ps[j].y = ston (t[i + 2 + j * 2 + 1]);
}
i = i + 2 + o.n * 2;
if (~ep)
ep = copy (o.ps[1]);
} else if (t[i] == 'b') {
o.type = t[i];
o.n = ston (t[i + 1]);
for (j = 0; j < o.n; j = j + 1) {
o.ps[j].x = ston (t[i + 2 + j * 2]);
o.ps[j].y = ston (t[i + 2 + j * 2 + 1]);
}
i = i + 2 + o.n * 2;
if (~ep)
ep = copy (o.ps[1]);
} else if (t[i] == 'T') {
o.type = t[i];
o.p.x = ston (t[i + 1]);
o.p.y = ston (t[i + 2]);
o.j = ston (t[i + 3]);
if (o.j == -1)
o.j = 'lb';
else if (o.j == 1)
o.j = 'rb';
else if (o.j == 0)
o.j = 'cb';
o.w = ston (t[i + 4]);
o.n = ston (t[i + 5]);
i = i + 6;
s = t[i];
i = i + 1;
l = strlen (s) - 1;
while (l < o.n) {
s = concat (s, ' ', t[i]);
l = l + 1 + strlen (t[i]);
i = i + 1;
}
tt = split (s, '');
l = tablesize (tt);
s = '';
for (j = 1; j < l; j = j + 1)
s = concat (s, tt[j]);
o.s = s;
} else if (t[i] == 'C') {
o.type = t[i];
o.n = ston (t[i + 1]);
i = i + 2;
s = t[i];
i = i + 1;
l = strlen (s) - 1;
while (l < o.n) {
s = concat (s, ' ', t[i]);
l = l + 1 + strlen (t[i]);
i = i + 1;
}
tt = split (s, '');
l = tablesize (tt);
s = '';
for (j = 1; j < l; j = j + 1)
s = concat (s, tt[j]);
o.fillcolor = gt.getcolor (gt.views, s);
} else if (t[i] == 'c') {
o.type = t[i];
o.n = ston (t[i + 1]);
i = i + 2;
s = t[i];
i = i + 1;
l = strlen (s) - 1;
while (l < o.n) {
s = concat (s, ' ', t[i]);
l = l + 1 + strlen (t[i]);
i = i + 1;
}
tt = split (s, '');
l = tablesize (tt);
s = '';
for (j = 1; j < l; j = j + 1)
s = concat (s, tt[j]);
o.drawcolor = gt.getcolor (gt.views, s);
} else if (t[i] == 'F') {
o.type = t[i];
o.fs = ston (t[i + 1]);
o.n = ston (t[i + 2]);
i = i + 3;
s = t[i];
i = i + 1;
l = strlen (s) - 1;
while (l < o.n) {
s = concat (s, ' ', t[i]);
l = l + 1 + strlen (t[i]);
i = i + 1;
}
tt = split (s, '');
l = tablesize (tt);
s = '';
for (j = 1; j < l; j = j + 1)
s = concat (s, tt[j]);
o.ofn = s;
o.fn = dotty.fontmap[s];
} else if (t[i] == 'S') {
o.type = t[i];
o.n = ston (t[i + 1]);
i = i + 2;
s = t[i];
i = i + 1;
l = strlen (s) - 1;
while (l < o.n) {
s = concat (s, ' ', t[i]);
l = l + 1 + strlen (t[i]);
i = i + 1;
}
tt = split (s, '');
l = tablesize (tt);
s = '';
for (j = 1; j < l; j = j + 1)
s = concat (s, tt[j]);
if (
s == 'solid' | s == 'dashed' | s == 'dotted' |
s == 'longdashed' | s == 'shortdashed'
)
o.style = s;
else if (s == 'bold')
o.width = 3;
else {
tt = split (s, '(');
if (tt[0] == 'setlinewidth') {
tt = split (tt[1], ')');
o.width = ston (tt[0]);
} else
continue;
}
} else if (t[i] == 'I') {
i = i + 7;
} else if (t[i] == 't') {
i = i + 2;
} else {
dotty.message (0, concat ('draw language parser error: ', t[i]));
return null;
}
oo[tablesize (oo)] = o;
}
oo.ep = ep;
return oo;
};
lefty/dotty_ui.lefty 0000644 00000033602 15170512710 0010577 0 ustar 00 #
# dotty_ui: user interface functions and data structures
#
dotty.protogt.doaction = function (data, s) {
local vt, gt;
vt = dotty.views[data.widget];
gt = dotty.graphs[vt.gtid];
data.menuitem = s;
if (data.obj.nid >= 0) {
if (gt.actions.node[s]) {
gt.actions.node[s] (gt, vt, data.obj, data);
return;
}
} else if (data.obj.eid >= 0) {
if (gt.actions.edge[s]) {
gt.actions.edge[s] (gt, vt, data.obj, data);
return;
}
}
if (gt.actions.general[s])
gt.actions.general[s] (gt, vt, data);
};
dotty.protogt.actions.general = [
"undo" = function (gt, vt, data) {
gt.undo (gt, 1);
};
"paste" = function (gt, vt, data) {
gt.paste (gt, data.pos, 1);
};
"do layout" = function (gt, vt, data) {
gt.layoutgraph (gt);
};
"cancel layout" = function (gt, vt, data) {
gt.cancellayout (gt);
};
"redraw" = function (gt, vt, data) {
gt.redrawgraph (gt, [vt.vtid = vt;]);
};
"new graph" = function (gt, vt, data) {
gt.erasegraph (gt, null, null);
};
"load graph" = function (gt, vt, data) {
gt.loadgraph (gt, null, 'file', dotty.protogt.graph, 1);
};
"reload graph" = function (gt, vt, data) {
gt.loadgraph (gt, gt.name, gt.type, gt.graph, 1);
};
"save graph" = function (gt, vt, data) {
gt.savegraph (gt, gt.name, gt.type);
};
"save graph as" = function (gt, vt, data) {
gt.savegraph (gt, null, 'file');
};
"open view" = function (gt, vt, data) {
gt = dotty.protogt.creategraph (null);
gt.createview (gt, null);
};
"copy view" = function (gt, vt, data) {
gt = gt.copygraph (gt);
gt.createview (gt, vt);
};
"birdseye view" = function (gt, vt, data) {
gt.createview (gt, dotty.protovt.birdseye);
};
"clone view" = function (gt, vt, data) {
gt.createview (gt, vt);
};
"close view" = function (gt, vt, data) {
gt.destroyview (gt, vt);
if (tablesize (gt.views) == 0)
gt.destroygraph (gt);
};
"set graph attr" = function (gt, vt, data) {
gt.setattr (gt, ['attr' = gt.graph.graphattr;]);
};
"set node attr" = function (gt, vt, data) {
gt.setattr (gt, ['attr' = gt.graph.nodeattr;]);
};
"set edge attr" = function (gt, vt, data) {
gt.setattr (gt, ['attr' = gt.graph.edgeattr;]);
};
"zoom in" = function (gt, vt, data) {
gt.zoom (gt, vt, 0.5, data.pos);
};
"zoom out" = function (gt, vt, data) {
gt.zoom (gt, vt, 2, data.pos);
};
"zoom in slowly" = function (gt, vt, data) {
gt.zoom (gt, vt, 0.9, data.pos);
};
"zoom out slowly" = function (gt, vt, data) {
gt.zoom (gt, vt, 1.1, data.pos);
};
"scroll horizontally" = function (gt, vt, data) {
vt.scrollmode = 'h';
};
"scroll vertically" = function (gt, vt, data) {
vt.scrollmode = 'v';
};
"find node" = function (gt, vt, data) {
gt.findnode (gt, vt);
};
"print graph" = function (gt, vt, data) {
gt.printorsave (gt, vt, null, null, null, null);
};
"text view" = function (gt, vt, data) {
if (dotty.txtview == 'on')
dotty.txtview = 'off';
else
dotty.txtview = 'on';
txtview (dotty.txtview);
};
"quit" = function (gt, vt, data) {
exit ();
};
];
dotty.protogt.actions.node = [
"cut" = function (gt, vt, obj, data) {
gt.cut (gt, obj, 'one', 'support', 'cut');
dotty.clipgt.layoutgraph (dotty.clipgt);
};
"Cut" = function (gt, vt, obj, data) {
gt.cut (gt, obj, 'reachable', 'support', 'cut');
dotty.clipgt.layoutgraph (dotty.clipgt);
};
"copy" = function (gt, vt, obj, data) {
gt.cut (gt, obj, 'one', 'support', 'copy');
dotty.clipgt.layoutgraph (dotty.clipgt);
};
"Copy" = function (gt, vt, obj, data) {
gt.cut (gt, obj, 'reachable', 'support', 'copy');
dotty.clipgt.layoutgraph (dotty.clipgt);
};
"group" = function (gt, vt, obj, data) {
local kv;
if ((kv = gt.getattr (gt, obj)))
gt.groupnodesbyattr (gt, kv.key, kv.val, [
'label' = kv.val; kv.key = kv.val;
], 1, 1);
};
"Group" = function (gt, vt, obj, data) {
local kv;
if ((kv = gt.getattr (gt, obj)))
gt.groupnodesbyattr (gt, kv.key, kv.val, [
'label' = kv.val; kv.key = kv.val;
], 0, 1);
};
"delete" = function (gt, vt, obj, data) {
if (obj.eid >= 0)
gt.removeedge (gt, obj);
else
gt.removenode (gt, obj);
};
"Delete" = function (gt, vt, obj, data) {
gt.removesubtree (gt, obj);
};
"remove" = function (gt, vt, obj, data) {
if (obj.nid >= 0)
if ((kv = gt.getattr (gt, obj)))
gt.removenodesbyattr (gt, kv.key, kv.val);
};
"Remove" = function (gt, vt, obj, data) {
if (obj.nid >= 0)
if ((kv = gt.getattr (gt, obj)))
gt.removesubtreesbyattr (gt, kv.key, kv.val);
};
"set attr" = function (gt, vt, obj, data) {
gt.setattr (gt, obj);
};
"print attr" = function (gt, vt, obj, data) {
if (obj.nid >= 0)
echo ('node: ', obj.name);
dump (obj.attr);
};
];
dotty.protogt.actions.edge = dotty.protogt.actions.node;
dotty.protovt.normal.menus = [
'general' = [
0 = "undo";
1 = "paste";
2 = "do layout";
3 = "cancel layout";
4 = "redraw";
5 = "new graph";
6 = "load graph";
7 = "reload graph";
8 = "save graph";
9 = "save graph as";
10 = "open view";
11 = "copy view";
12 = "clone view";
13 = "birdseye view";
14 = "close view";
15 = "set graph attr";
16 = "set node attr";
17 = "set edge attr";
18 = "zoom in";
19 = "zoom out";
20 = "find node";
21 = "print graph";
22 = "text view";
23 = "quit";
];
'node' = [
0 = "cut";
1 = "Cut";
2 = "copy";
3 = "Copy";
4 = "group";
5 = "Group";
6 = "delete";
7 = "Delete";
8 = "remove";
9 = "Remove";
10 = "set attr";
11 = "print attr";
];
'edge' = [
0 = "cut";
1 = "Cut";
2 = "copy";
3 = "Copy";
4 = "delete";
5 = "Delete";
6 = "set attr";
7 = "print attr";
];
];
dotty.protovt.normal.keys = [
'general' = [
'u' = "undo";
'p' = "paste";
'l' = "do layout";
'k' = "cancel layout";
' ' = "redraw";
'L' = "reload graph";
's' = "save graph";
'Z' = "zoom in slowly";
'z' = "zoom out slowly";
'h' = "scroll horizontally";
'v' = "scroll vertically";
];
'node' = [
'c' = "copy";
'C' = "Copy";
'g' = "group";
'G' = "Group";
'd' = "delete";
'D' = "Delete";
'r' = "remove";
'R' = "Remove";
'a' = "set attr";
];
'edge' = [
'c' = "copy";
'C' = "Copy";
'd' = "delete";
'D' = "Delete";
'a' = "set attr";
];
];
dotty.protovt.birdseye.menus = dotty.protovt.normal.menus;
dotty.protovt.birdseye.keys = dotty.protovt.normal.keys;
dotty.protovt.normal.uifuncs = [
'leftdown' = function (data) {
local gt;
gt = dotty.graphs[dotty.views[data.widget].gtid];
if (data.obj.nid >= 0) {
dotty.node2move = data.obj;
dotty.movewidget = data.widget;
dotty.rp2 = data.pos;
}
};
'leftmove' = function (data) {
local gt;
gt = dotty.graphs[dotty.views[data.widget].gtid];
if (dotty.node2move & (
dotty.rp2.x ~= data.pos.x | dotty.rp2.y ~= data.pos.y
)) {
gt.movenode (gt, dotty.node2move, data.pos);
dotty.rp2 = data.pos;
}
};
'leftup' = function (data) {
local gt;
gt = dotty.graphs[dotty.views[data.widget].gtid];
if (dotty.node2move) {
if (dotty.movewidget == data.widget)
gt.movenode (gt, dotty.node2move, data.pos);
dotty.node2move = 0;
} else if (~data.obj)
gt.insertnode (gt, data.pos, null, null, null, 1);
};
'middledown' = function (data) {
if (~(data.obj.nid >= 0))
return;
dotty.rubberband = 1;
dotty.movewidget = data.widget;
setgfxattr (data.widget, ['mode' = 'xor';]);
dotty.rp1 = data.pos;
dotty.rp2 = data.pos;
line (data.widget, null, dotty.rp1, dotty.rp2, ['color' = 1;]);
};
'middlemove' = function (data) {
if (dotty.rubberband ~= 1 | (
dotty.rp2.x == data.pos.x & dotty.rp2.y == data.pos.y
))
return;
line (data.widget, null, dotty.rp1, dotty.rp2, ['color' = 1;]);
dotty.rp2 = data.pos;
line (data.widget, null, dotty.rp1, dotty.rp2, ['color' = 1;]);
};
'middleup' = function (data) {
local gt;
gt = dotty.graphs[dotty.views[data.widget].gtid];
if (dotty.rubberband ~= 1)
return;
dotty.rubberband = 0;
line (dotty.movewidget, null, dotty.rp1, dotty.rp2, ['color' = 1;]);
setgfxattr (dotty.movewidget, ['mode' = 'src';]);
if (dotty.movewidget ~= data.widget | ~(
data.pobj.nid >= 0) | ~(data.obj.nid >= 0
))
return;
if (data.pobj.attr.support)
gt.groupnodes (gt, [
data.obj.nid = data.obj;
data.pobj.nid = data.pobj;
], data.obj, null, null, null, 1, 1);
else if (data.obj.attr.support)
gt.groupnodes (gt, [
data.obj.nid = data.obj;
data.pobj.nid = data.pobj;
], data.pobj, null, null, null, 1, 1);
else
gt.insertedge (gt, data.pobj, null, data.obj, null, null, 1);
};
'rightup' = function (data) {
local vt, gt, menu, i;
vt = dotty.views[data.widget];
gt = dotty.graphs[vt.gtid];
if (~data.obj)
menu = vt.menus.general;
else if (data.obj.nid >= 0)
menu = vt.menus.node;
else if (data.obj.eid >= 0)
menu = vt.menus.edge;
if ((i = displaymenu (data.widget, menu)) >= 0)
gt.doaction (data, menu[i]);
};
'button3up' = function (data) {
local vt, attr;
vt = dotty.views[data.widget];
attr = getwidgetattr (vt.scroll, [0 = 'childcenter';]);
if (vt.scrollmode == 'h')
attr.childcenter.x = attr.childcenter.x - 40;
else
attr.childcenter.y = attr.childcenter.y - 40;
setwidgetattr (vt.scroll, ['childcenter' = attr.childcenter;]);
};
'button4up' = function (data) {
local vt, attr;
vt = dotty.views[data.widget];
attr = getwidgetattr (vt.scroll, [0 = 'childcenter';]);
if (vt.scrollmode == 'h')
attr.childcenter.x = attr.childcenter.x + 40;
else
attr.childcenter.y = attr.childcenter.y + 40;
setwidgetattr (vt.scroll, ['childcenter' = attr.childcenter;]);
};
'keyup' = function (data) {
local vt, gt, action;
vt = dotty.views[data.widget];
gt = dotty.graphs[vt.gtid];
if (data.obj.nid >= 0) {
if (vt.keys.node[data.key])
action = vt.keys.node[data.key];
} else if (data.obj.eid >= 0) {
if (vt.keys.edge[data.key])
action = vt.keys.edge[data.key];
}
if (~action)
if (vt.keys.general[data.key])
action = vt.keys.general[data.key];
if (action)
gt.doaction (data, action);
};
'redraw' = function (data) {
local vt, gt;
vt = dotty.views[data.widget];
gt = dotty.graphs[vt.gtid];
gt.drawgraph (gt, [vt.vtid = vt;]);
};
'closeview' = function (data) {
local vt, gt;
vt = dotty.views[data.widget];
gt = dotty.graphs[vt.gtid];
gt.destroyview (gt, vt);
if (tablesize (gt.views) == 0)
gt.destroygraph (gt);
};
];
dotty.protovt.birdseye.uifuncs = [
'leftdown' = function (data) {
local gt, vid;
gt = dotty.graphs[dotty.views[data.widget].gtid];
for (vid in gt.views) {
vt = gt.views[vid];
if (vt.type ~= 'birdseye')
gt.setviewcenter ([vid = vt;], data.pos);
}
};
'leftmove' = function (data) {
local gt, vid;
gt = dotty.graphs[dotty.views[data.widget].gtid];
for (vid in gt.views) {
vt = gt.views[vid];
if (vt.type ~= 'birdseye')
gt.setviewcenter ([vid = vt;], data.pos);
}
};
'leftup' = function (data) {
local gt, vid;
gt = dotty.graphs[dotty.views[data.widget].gtid];
for (vid in gt.views) {
vt = gt.views[vid];
if (vt.type ~= 'birdseye')
gt.setviewcenter ([vid = vt;], data.pos);
}
};
'middledown' = dotty.protovt.normal.uifuncs.middledown;
'middlemove' = dotty.protovt.normal.uifuncs.middlemove;
'middleup' = dotty.protovt.normal.uifuncs.middleup;
'rightup' = dotty.protovt.normal.uifuncs.rightup;
'keyup' = dotty.protovt.normal.uifuncs.keyup;
'redraw' = dotty.protovt.normal.uifuncs.redraw;
'closeview' = dotty.protovt.normal.uifuncs.closeview;
];
dotty.monitorfile = function (data) {
local gtid, gt, lpt;
for (gtid in dotty.layoutpending) {
lpt = dotty.layoutpending[gtid];
if (lpt.fd == data.fd) {
gt = dotty.graphs[lpt.gtid];
gt.haveinput = 1;
gt.layoutgraph (gt);
return 1;
}
}
return 0;
};
lefty/fractal.lefty 0000644 00000005234 15170512710 0010353 0 ustar 00 load ('def.lefty');
definit ();
#
# initialize window data
#
canvas = defcanvas;
wrect = [0 = ['x' = 0; 'y' = 0;]; 1 = ['x' = 400; 'y' = 500;];];
setwidgetattr (canvas, ['window' = wrect;]);
sq = function (x) {
return x * x;
};
# data structures
#
length = 300;
center = ['x' = 200; 'y' = 250;];
radius = 2 * length / sqrt (12);
fractalangle = 0;
maxlevel = 2;
# drawing functions
#
# draw a Koch curve (a ``snowflake'' fractal)
#
# start with a triangle and keep replacing edges
# with the construct: _/\_
# until the recursion level reaches 'maxlevel'
#
fractal = function (level, length, angle) {
local nlength, newpenpos;
if (level >= maxlevel) {
newpenpos.x = penpos.x + length * cos (angle);
newpenpos.y = penpos.y + length * sin (angle);
line (canvas, null, penpos, newpenpos, ['color' = 1;]);
penpos = newpenpos;
return;
}
nlength = length / 3;
fractal (level + 1, nlength, angle);
fractal (level + 1, nlength, angle + 60);
fractal (level + 1, nlength, angle - 60);
fractal (level + 1, nlength, angle);
};
drawfractal = function () {
clear (canvas);
setpick (canvas, center, wrect);
penpos = [
'x' = center.x + cos (fractalangle + 210) * radius;
'y' = center.y + sin (fractalangle + 210) * radius;
];
fractal (0, length, fractalangle + 60);
fractal (0, length, fractalangle - 60);
fractal (0, length, fractalangle - 180);
remove ('penpos');
};
# editing functions
#
# transform the fractal.
#
# map point 'prevpoint' to point 'currpoint'
# with respect to the center of the fractal.
#
transformfractal = function (prevpoint, currpoint) {
local prevtan, currtan, prevradius, currradius;
prevtan = atan (prevpoint.y - center.y, prevpoint.x - center.x);
currtan = atan (currpoint.y - center.y, currpoint.x - center.x);
fractalangle = fractalangle + (currtan - prevtan);
prevradius = sqrt (
sq (prevpoint.y - center.y) + sq (prevpoint.x - center.x)
);
currradius = sqrt (
sq (currpoint.y - center.y) + sq (currpoint.x - center.x)
);
radius = radius / prevradius * currradius;
length = radius / 2 * sqrt (12);
};
# user interface functions
#
# bind changes to the fractal to user actions
#
leftup = function (data) {
transformfractal (data.ppos, data.pos);
drawfractal ();
};
dops = function () {
local s;
s = ['x' = 8 * 300; 'y' = 10.5 * 300;];
canvas = createwidget (-1, ['type' = 'ps'; 'size' = s;]);
setwidgetattr (canvas, ['window' = wrect;]);
drawfractal ();
destroywidget (canvas);
canvas=defcanvas;
};
transformfractal (['x' = 0; 'y' = 0;], ['x' = 0; 'y' = 0;]);
drawfractal ();
lefty/fractal2.lefty 0000644 00000013167 15170512710 0010441 0 ustar 00 #
# data structures
#
length = 300;
center = ['x' = 200; 'y' = 250;];
radius = 2 * length / sqrt (12);
fractalangle = 0;
maxlevel = 2;
sizes = [
'button' = [ 'x' = 100; 'y' = 40; ];
'canvas' = [ 'x' = 400; 'y' = 500; ];
'view' = [ 'x' = 400; 'y' = 600; ];
];
sq = function (x) {
return x * x;
};
#
# create view and other widgets
#
init = function () {
view = createwidget (-1, [
'type' = 'view'; 'name' = 'fractal'; 'size' = sizes.view;
]);
array1 = createwidget (view, [
'type' = 'array'; 'borderwidth' = 1; 'mode' = 'vertical';
]);
widgets[array1].resize = resize;
array2 = createwidget (array1, [
'type' = 'array'; 'borderwidth' = 1; 'mode' = 'horizontal';
]);
widgets[array2].resize = resize;
array3 = createwidget (array2, [
'type' = 'array'; 'borderwidth' = 1; 'mode' = 'vertical';
]);
widgets[array3].resize = resize;
morebutton = createwidget (array3, [
'type' = 'button'; 'text' = 'more';
]);
widgets[morebutton].pressed = pressed;
lessbutton = createwidget (array3, [
'type' = 'button'; 'text' = 'less';
]);
widgets[lessbutton].pressed = pressed;
setwidgetattr (morebutton, ['size' = sizes.button;]);
setwidgetattr (lessbutton, ['size' = sizes.button;]);
atext = createwidget (array2, [
'type' = 'text'; 'mode' = 'oneline';
]);
widgets[atext].oneline = oneline;
setwidgetattr (atext, [
'size' = ['x' = sizes.button.x; 'y' = sizes.button.y * 2;];
]);
scroll = createwidget (array1, ['type' = 'scroll';]);
canvas = createwidget (scroll, ['type' = 'canvas';]);
wrect = [0 = ['x' = 0; 'y' = 0;]; 1 = sizes.canvas;];
setwidgetattr (canvas, ['window' = wrect; 'viewport' = wrect[1];]);
};
#
# drawing functions
#
# draw a Koch curve (a ``snowflake'' fractal)
#
# start with a triangle and keep replacing edges
# with the construct: _/\_
# until the recursion level reaches 'maxlevel'
#
fractal = function (level, length, angle) {
local nlength, newpenpos;
if (level >= maxlevel) {
newpenpos.x = penpos.x + length * cos (angle);
newpenpos.y = penpos.y + length * sin (angle);
line (canvas, null, penpos, newpenpos, ['color' = 1;]);
penpos = newpenpos;
return;
}
nlength = length / 3;
fractal (level + 1, nlength, angle);
fractal (level + 1, nlength, angle + 60);
fractal (level + 1, nlength, angle - 60);
fractal (level + 1, nlength, angle);
};
redrawfractal = function () {
clear (canvas);
setpick (canvas, center, wrect);
penpos = [
'x' = center.x + cos (fractalangle + 210) * radius;
'y' = center.y + sin (fractalangle + 210) * radius;
];
fractal (0, length, fractalangle + 60);
fractal (0, length, fractalangle - 60);
fractal (0, length, fractalangle - 180);
remove ('penpos');
};
#
# editing functions
#
# transform the fractal.
#
# map point 'prevpoint' to point 'currpoint'
# with respect to the center of the fractal.
#
transformfractal = function (prevpoint, currpoint) {
local prevtan, currtan, prevradius, currradius;
prevtan = atan (prevpoint.y - center.y, prevpoint.x - center.x);
currtan = atan (currpoint.y - center.y, currpoint.x - center.x);
fractalangle = fractalangle + (currtan - prevtan);
prevradius = sqrt (
sq (prevpoint.y - center.y) + sq (prevpoint.x - center.x)
);
currradius = sqrt (
sq (currpoint.y - center.y) + sq (currpoint.x - center.x)
);
radius = radius / prevradius * currradius;
length = radius / 2 * sqrt (12);
};
#
# main actions
#
redraw = function (data) {
redrawfractal ();
};
changemaxlevel = function (dn) {
maxlevel = maxlevel + dn;
if (maxlevel < 0)
maxlevel = 0;
redrawfractal ();
};
resize = function (data) {
local ret;
if (data.widget == array1) {
ret = [
array2 = [
'x' = data.size.x;
'y' = sizes.button.y * 2;
];
scroll = [
'x' = data.size.x;
'y' = data.size.y - sizes.button.y * 2;
];
];
} else if (data.widget == array2) {
ret = [
array3 = [
'x' = sizes.button.x;
'y' = 2 * sizes.button.y;
];
atext = [
'x' = data.size.x - sizes.button.x;
'y' = 2 * sizes.button.y;
];
];
} else if (data.widget == array3) {
ret = [
morebutton = sizes.button;
lessbutton = sizes.button;
];
}
return ret;
};
#
# user interface functions
#
# bind changes to the fractal to user actions
#
leftup = function (data) {
transformfractal (data.ppos, data.pos);
redrawfractal ();
};
menu = [
0 = 'more';
1 = 'less';
];
domenu = function (i) {
local s;
s = menu[i];
if (s == 'more')
changemaxlevel (1);
else if (s == 'less')
changemaxlevel (-1);
};
rightdown = function (data) {
domenu (displaymenu (canvas, menu));
};
pressed = function (data) {
if (data.widget == morebutton)
changemaxlevel (1);
else if (data.widget == lessbutton)
changemaxlevel (-1);
};
oneline = function (data) {
local dn;
dn = ston (data.text);
if (dn > 0 | dn < 0)
changemaxlevel (dn - maxlevel);
};
#
# postscript generation
#
dops = function () {
local r;
r = [0 = ['x' = 0; 'y' = 0;]; 1 = ['x' = 8 * 300; 'y' = 10.5 * 300;];];
canvas = opencanvas ('pscanvas', '', r);
setwidgetattr (canvas, ['window' = wrect;]);
redraw ();
closecanvas (canvas);
canvas=defcanvas;
};
init ();
#txtview ('off');
lefty/lefty.psp 0000644 00000004567 15170512710 0007551 0 ustar 00 /BOX {
/boxy1 exch def /boxx1 exch def /boxy0 exch def /boxx0 exch def
boxx0 boxy0 moveto boxx1 boxy0 lineto
boxx1 boxy1 lineto boxx0 boxy1 lineto
closepath
} def
/SCP { stroke initclip newpath BOX clip newpath } def
/CL { stroke setrgbcolor } def
/DO { stroke } def
/NP { newpath } def
/FI { fill } def
/LI { moveto lineto } def
/CT { curveto } def
/AR {
/ang2 exch def /ang1 exch def
/radius exch def /y2x exch def /cy exch def /cx exch def
gsave
cx cy translate 1 y2x scale 0 0 radius ang1 ang2 arc stroke
grestore
} def
/ARF {
/ang2 exch def /ang1 exch def
/radius exch def /y2x exch def /cy exch def /cx exch def
gsave
cx cy translate 1 y2x scale 0 0 radius ang1 ang2 arc fill
grestore
} def
/TXT {
/texth exch def
/textf exch def
/textn exch def
/texts exch def
/textyj exch def /texty exch def
/textxj exch def /textx exch def
textf findfont texth scalefont dup setfont
/FontBBox get 1 get 1000 div texth mul /textbl exch def
/textth texth textn mul def /texttw 0 def
0 1 textn 1 sub {
texts exch get 0 get stringwidth pop
dup texttw gt { /texttw exch def } { pop } ifelse
} for
textyj (b) eq { /ty texty textth add textbl add def } if
textyj (d) eq { /ty texty textth add def } if
textyj (c) eq { /ty texty textth 2 div add def } if
textyj (u) eq { /ty texty def } if
/ty ty textbl sub def
textxj (l) eq { /tx textx def } if
textxj (c) eq { /tx textx texttw 2 div sub def } if
textxj (r) eq { /tx textx texttw sub def } if
0 1 textn 1 sub {
/ty ty texth sub def
texts exch get dup 0 get /ts exch def 1 get /tj exch def
tj (l) eq { tx ty moveto ts show } if
tj (n) eq {
tx texttw ts stringwidth pop sub 2 div add ty moveto ts show
} if
tj (r) eq {
tx texttw ts stringwidth pop sub add ty moveto ts show
} if
} for
} def
/colorimage where {
pop
} {
/bwproc {
rgbproc dup length 3 idiv string 0 3 0 5 -1 roll {
add 2 1 roll 1 sub dup 0 eq {
pop 3 idiv 3 -1 roll dup 4 -1 roll
dup 3 1 roll 5 -1 roll put 1 add 3 0
} {
2 1 roll
} ifelse
} forall
pop pop pop
} def
/colorimage {
pop pop /rgbproc exch def {bwproc} image
} bind def
} ifelse
lefty/slides.lefty 0000644 00000006176 15170512710 0010230 0 ustar 00 load ('def.lefty');
definit ();
#
# initialize window data
#
canvas = defcanvas;
wrect = [0 = ['x' = 0; 'y' = 0;]; 1 = ['x' = 800; 'y' = 1000;];];
lmargin = 100;
width = 800;
height = 1000;
setwidgetattr (canvas, ['window' = wrect;]);
fonts = [
'timr' = [
14 = 'timr14';
18 = 'timr18';
24 = 'timr24';
];
'courr' = [
14 = 'courr14';
18 = 'courr18';
24 = 'courr24';
];
];
x2ps = [
'timr24' = 'Times-Roman';
'timr18' = 'Times-Roman';
'timr14' = 'Times-Roman';
'courr24' = 'Courier';
'courr18' = 'Courier';
'courr14' = 'Courier';
];
calc = function () {
local i, j, cpos, tsiz, dist, slidep;
tsiz = ['x' = 0; 'y' = 0;];
for (i = 0; slides[i]; i = i + 1) {
slidep = slides[i];
if (slidep.skip) {
tsiz.y = tsiz.y + slidep.skip;
} else {
for (j = 0; slidep.text[j]; j = j + 1) {
if (j > 0)
tsiz.y = tsiz.y + 5;
if (~slidep.font)
slidep.font = slides.font;
if (~slidep.size)
slidep.size = slides.size;
if (~slidep.just)
slidep.just = slides.just;
slidep.tsiz[j] = textsize (canvas, slidep.text[j],
fonts[slidep.font][slidep.size], 0);
tsiz.y = tsiz.y + slidep.tsiz[j].y;
}
}
}
dist = (height - tsiz.y) / (i + 1);
cpos = ['x' = lmargin; 'y' = height - dist;];
for (i = 0; slides[i]; i = i + 1) {
slidep = slides[i];
if (slidep.skip) {
cpos.y = cpos.y - slidep.skip - dist;
} else {
for (j = 0; slidep.text[j]; j = j + 1) {
if (j > 0)
cpos.y = cpos.y - 5;
if (slidep.just == 0)
slidep.tpos[j].x = cpos.x;
else
slidep.tpos[j].x = width / 2;
cpos.y = cpos.y - slidep.tsiz[j].y;
slidep.tpos[j].y = cpos.y;
}
cpos.y = cpos.y - dist;
}
}
};
redraw = function () {
local i, j, slidep;
for (i = 0; slides[i]; i = i + 1) {
slidep = slides[i];
if (~slidep.skip)
for (j = 0; slidep.text[j]; j = j + 1)
text (canvas, slidep, slidep.tpos[j], slidep.text[j],
fonts[slidep.font][slidep.size], 0, slidep.just);
}
};
dops = function () {
local i, j, slidep, r;
r = [0 = ['x' = 0; 'y' = 0;]; 1 = ['x' = 8 * 300; 'y' = 10.5 * 300;];];
canvas = createwidget (-1, ['type' = 'ps'; 'origin' = r[0]; 'size' = r[1]
;]);
setwidgetattr (canvas, ['window' = wrect;]);
for (i = 0; slides[i]; i = i + 1) {
slidep = slides[i];
if (~slidep.skip)
for (j = 0; slidep.text[j]; j = j + 1)
text (canvas, slidep, slidep.tpos[j], slidep.text[j],
x2ps[fonts[slidep.font][slidep.size]],
slidep.tsiz[j].y, slidep.just, 1);
}
destroywidget (canvas);
canvas=defcanvas;
};
doit = function () {
calc ();
redraw ();
dops ();
};
lefty/tree.lefty 0000644 00000011626 15170512710 0007700 0 ustar 00 load ('def.lefty');
definit ();
#
# initialize window data
#
canvas = defcanvas;
wrect = [0 = ['x' = -5; 'y' = 0;]; 1 = ['x' = 410; 'y' = 500;];];
setwidgetattr (canvas, ['window' = wrect;]);
#
# data structures
#
nodearray = [];
nodenum = 0;
dist = ['x' = 40; 'y' = 40;];
defsize = ['x' = 10; 'y' = 10;];
fontname = 'fixed';
fontsize = 18;
tree = null;
# drawing functions
#
boxnode = function (node) {
local center;
box (canvas, node, node.rect, ['color' = 0; 'fill' = 'on';]);
box (canvas, node, node.rect);
center = [
'x' = (node.rect[0].x + node.rect[1].x) / 2;
'y' = (node.rect[0].y + node.rect[1].y) / 2;
];
if (node.name)
text (canvas, node, center, node.name, fontname, fontsize, 'cc');
};
circlenode = function (node) {
local center, radius;
center = [
'x' = (node.rect[0].x + node.rect[1].x) / 2;
'y' = (node.rect[0].y + node.rect[1].y) / 2;
];
radius = [
'x' = center.x - node.rect[0].x;
'y' = center.y - node.rect[0].y;
];
arc (canvas, node, center, radius, ['color' = 0; 'fill' = 'on';]);
arc (canvas, node, center, radius);
if (node.name)
text (canvas, node, center, node.name, fontname, fontsize, 'cc');
};
drawnode = boxnode;
drawedge = function (node1, node2) {
line (canvas, null,
[
'x' = (node1.rect[1].x + node1.rect[0].x) / 2;
'y' = node1.rect[0].y;
], [
'x' = (node2.rect[1].x + node2.rect[0].x) / 2;
'y' = node2.rect[1].y;
]);
};
drawtree = function (node) {
local i;
for (i in nodearray)
drawnode (nodearray[i]);
drawtreerec (node);
};
drawtreerec = function (node) {
local i, n;
if ((n = tablesize (node.ch)) > 0) {
for (i = 0; i < n; i = i + 1) {
drawedge (node, node.ch[i]);
drawtreerec (node.ch[i]);
}
}
};
redraw = function (c) {
if (tree)
drawtree (tree);
};
# layout functions
#
complayout = function () {
leafx = 0;
leafrank = 0;
dolayout (tree, wrect[1].y - 10);
remove ('leafx');
remove ('leafrank');
};
dolayout = function (node, pary) {
local r, n, i, size, lchp, rchp;
size = nodesize (node);
if (node.chn > 0) {
for (i = 0; i < node.chn; i = i + 1)
dolayout (node.ch[i], pary - size.y - dist.y);
node.rank = (node.ch[0].rank + node.ch[node.chn - 1].rank) / 2;
lchp = node.ch[0].rect;
rchp = node.ch[node.chn - 1].rect;
r[0].x = lchp[0].x + ((rchp[1].x - lchp[0].x) - size.x) / 2;
r[0].y = pary - size.y;
r[1].x = r[0].x + size.x;
r[1].y = pary;
node.rect = r;
} else {
node.rank = leafrank;
r[0].x = leafx;
r[0].y = pary - size.y;
r[1].x = r[0].x + size.x;
r[1].y = pary;
leafrank = leafrank + 1;
leafx = r[1].x + dist.x;
node.rect = r;
}
};
# editing functions
#
inode = function (point, name) {
local i, nnum, size;
nnum = nodenum;
if (~name)
name = ask ('give name of node:');
nodearray[nnum].ch = [];
nodearray[nnum].chn = 0;
nodearray[nnum].name = name;
size = nodesize (nodearray[nnum]);
nodearray[nnum].rect[0] = point;
nodearray[nnum].rect[1] = ['x' = point.x + size.x; 'y' = point.y + size.y;];
nodenum = nodenum + 1;
if (~tree) {
tree = nodearray[nnum];
tree.depth = 0;
complayout ();
drawtree (tree);
} else
drawtree (nodearray[nnum]);
return nodearray[nnum];
};
iedge = function (node1, node2) {
node1.ch[node1.chn] = node2;
node1.chn = node1.chn + 1;
node2.depth = node1.depth + 1;
complayout ();
clear (canvas);
drawtree (tree);
};
fix = function (node, op, np) {
if (node.depth ~= 0)
dist.y = dist.y + (op.y - np.y) / node.depth;
if (node.rank ~= 0)
dist.x = dist.x + (np.x - op.x) / node.rank;
complayout ();
clear (canvas);
drawtree (tree);
};
nodesize = function (node) {
local siz;
if (~(siz = textsize (canvas, node.name, fontname, fontsize)))
siz = defsize;
else {
siz.x = siz.x + 8;
siz.y = siz.y + 8;
}
return siz;
};
changenode = function (nodestyle) {
drawnode = nodestyle;
clear (canvas);
drawtree (tree);
};
# user interface functions
#
leftdown = function (data) {
if (~data.obj)
inode (data.pos, null);
};
leftup = function (data) {
if (data.pobj)
fix (data.pobj, data.ppos, data.pos);
};
middleup = function (data) {
if (data.pobj & data.obj)
iedge (data.pobj, data.obj);
};
dops = function () {
local s;
s = ['x' = 8 * 300; 'y' = 10.5 * 300;];
fontname = 'Times-Roman';
canvas = createwidget (-1, ['type' = 'ps'; 'size' = s;]);
setwidgetattr (canvas, ['window' = wrect;]);
drawtree (tree);
destroywidget (canvas);
canvas=defcanvas;
fontname = 'fixed';
};