11
'gattr' = 'graphattr';
24
'fcolor' = 'fontcolor';
31
'-*-times-medium-r-*--%d-*-*-*-*-*-*-1';
33
'-*-times-medium-i-*--%d-*-*-*-*-*-*-1';
35
'-*-times-bold-r-*--%d-*-*-*-*-*-*-1';
37
'-*-courier-bold-r-*--%d-*-*-*-*-*-*-1';
39
'-*-courier-bold-r-*--%d-*-*-*-*-*-*-1';
41
'-*-helvetica-medium-r-normal--%d-*-*-*-p-*-iso8859-1';
43
'-*-helvetica-bold-r-normal--%d-*-*-*-p-*-iso8859-1';
46
'Times-Roman' = 'Times-Roman';
47
'Times-Italic' = 'Times-Italic';
48
'Times-Bold' = 'Times-Bold';
49
'Courier' = 'Courier';
50
'Courier-Bold' = 'Courier-Bold';
51
'Helvetica' = 'Helvetica';
52
'Helvetica-Bold' = 'Helvetica-Bold';
57
'Times-Roman' = 'Times New Roman';
58
'Times-Italic' = 'Times New Roman Italic';
59
'Times-Bold' = 'Times New Roman Bold';
60
'Courier' = 'Courier New';
61
'Courier-Bold' = 'Courier New Bold';
62
'Helvetica' = 'Arial';
63
'Helvetica-Bold' = 'Arial Bold';
66
'Times-Roman' = 'Times New Roman';
67
'Times-Italic' = 'Times New Roman Italic';
68
'Times-Bold' = 'Times New Roman Bold';
69
'Courier' = 'Courier New';
70
'Courier-Bold' = 'Courier New Bold';
71
'Helvetica' = 'Arial';
72
'Helvetica-Bold' = 'Arial Bold';
80
'fontname' = 'Times-Roman';
81
'fontcolor' = 'black';
87
'fontname' = 'Times-Roman';
88
'fontcolor' = 'black';
93
'fontname' = 'Times-Roman';
94
'fontcolor' = 'black';
107
'layoutmode' = 'sync';
119
'orig' = ['x' = 1; 'y' = 1;];
120
'size' = ['x' = 420; 'y' = 520;];
122
0 = ['x' = 0; 'y' = 0;];
123
1 = ['x' = 400; 'y' = 500;];
125
'vsize' = ['x' = 400; 'y' = 500;];
130
'name' = 'DOTTY birdseye view';
131
'orig' = ['x' = 1; 'y' = 1;];
132
'size' = ['x' = 220; 'y' = 260;];
134
0 = ['x' = 0; 'y' = 0;];
135
1 = ['x' = 200; 'y' = 250;];
137
'vsize' = ['x' = 200; 'y' = 250;];
142
'8.5x11' = ['x' = 8; 'y' = 10.5;];
143
'11x17' = ['x' = 10.5; 'y' = 16.5;];
144
'36x50' = ['x' = 35.5; 'y' = 49.5;];
147
load ('dotty_draw.lefty');
148
load ('dotty_edit.lefty');
149
load ('dotty_layout.lefty');
150
load ('dotty_ui.lefty');
152
# initialization functions
154
dotty.init = function () {
155
dotty.outlinecolor = 1;
156
dotty.fontmap = dotty.maps[getenv ('LEFTYWINSYS')].fontmap;
157
dotty.clipgt = dotty.protogt.creategraph (['noundo' = 1;]);
160
dotty.simple = function (file) {
161
if (dotty.inited ~= 1)
163
dotty.createviewandgraph (file, 'file', null, null);
169
dotty.protogt.creategraph = function (protogt) {
173
protogt = dotty.protogt;
174
for (gtid = 0; dotty.graphs[gtid]; gtid = gtid + 1)
176
gt = (dotty.graphs[gtid] = []);
177
if (protogt.mode ~= 'replace') {
178
for (id in dotty.protogt)
179
gt[id] = copy (dotty.protogt[id]);
182
gt[id] = copy (protogt[id]);
185
gt.undoarray = ['level' = 0; 'entries' = [];];
189
dotty.protogt.copygraph = function (ogt) {
192
for (gtid = 0; dotty.graphs[gtid]; gtid = gtid + 1)
194
gt = (dotty.graphs[gtid] = []);
196
gt[id] = copy (ogt[id]);
199
gt.undoarray = ['level' = 0; 'entries' = [];];
203
dotty.protogt.destroygraph = function (gt) {
206
if (gt.layoutpending > 0)
207
gt.cancellayout (gt);
208
for (vid in gt.views)
209
vlist[vid] = gt.views[vid];
210
for (vid in gt.views)
211
gt.destroyview (gt, vlist[vid]);
212
remove (gt.gtid, dotty.graphs);
214
dotty.protogt.loadgraph = function (gt, name, type, protograph, layoutflag) {
215
local vid, vt, fd, graph, nid, eid, gid;
217
if (gt.layoutpending > 0)
218
gt.cancellayout (gt);
220
if (~(name = ask ('file name:', 'file', '')))
222
dotty.pushbusy (gt, gt.views);
223
dotty.message (1, 'loading');
225
protograph = dotty.protogt.graph;
226
if (~((fd = dotty.openio (name, type, 'r')) >= 0) |
227
~(graph = readgraph (fd, protograph))) {
228
dotty.message (0, 'cannot load graph');
229
dotty.popbusy (gt, gt.views);
232
for (vid in gt.views) {
240
gt.undoarray = ['level' = 0; 'entries' = [];];
241
if (~(type == 'file' & name == '-'))
243
graph.maxgid = tablesize (graph.graphs);
244
graph.maxnid = tablesize (graph.nodes);
245
graph.maxeid = tablesize (graph.edges);
246
for (nid in graph.nodes)
247
graph.nodes[nid][dotty.keys.nid] = nid;
248
for (eid in graph.edges)
249
graph.edges[eid][dotty.keys.eid] = eid;
250
for (gid in graph.graphs)
251
graph.graphs[gid][dotty.keys.gid] = gid;
254
dotty.message (1, 'generating layout');
257
dotty.popbusy (gt, gt.views);
260
dotty.protogt.savegraph = function (gt, name, type, savecoord) {
261
local fd, graph, gid, sgraph, nid, node, eid, edge, pointi, attr;
264
if (~(name = ask ('file name:', 'file', '')))
267
graph = copy (gt.graph);
268
for (gid in graph.graphs) {
269
sgraph = graph.graphs[gid];
271
sgraph.graphattr.bb = concat (sgraph.rect[0].x, ',',
272
sgraph.rect[0].y, ',', sgraph.rect[1].x, ',',
274
if (sgraph.lp & tablesize (sgraph.lp) > 0)
275
sgraph.graphattr.lp = concat (sgraph.lp.x, ',', sgraph.lp.y);
277
sgraph.graphattr.lp = "";
279
for (nid in graph.nodes) {
280
node = graph.nodes[nid];
281
if (~node.attr.label)
282
node.attr.label = '\N';
284
node.attr.pos = concat (node.pos.x, ',', node.pos.y);
286
node.attr.width = node.size.x / 72;
287
node.attr.height = node.size.y / 72;
290
node.attr.rects = gt.packrecordfields (gt, node.fields);
292
for (eid in graph.edges) {
293
edge = graph.edges[eid];
297
attr = concat ('s,', edge.sp.x, ',', edge.sp.y, ' ');
299
attr = concat (attr, 'e,', edge.ep.x, ',', edge.ep.y, ' ');
300
for (pointi = 0; edge.points[pointi]; pointi = pointi + 1)
301
attr = concat (attr, ' ', edge.points[pointi].x, ',',
302
edge.points[pointi].y);
303
edge.attr.pos = attr;
306
edge.attr.lp = concat (edge.lp.x, ',', edge.lp.y);
310
0 = ['x' = 0; 'y' = 0; ]; 1 = ['x' = 1; 'y' = 1; ];
312
for (nid in graph.nodes) {
313
node = graph.nodes[nid];
314
if (graph.rect[1].x < node.pos.x + node.size.x / 2)
315
graph.rect[1].x = node.pos.x + node.size.x / 2;
316
if (graph.rect[1].y < node.pos.y + node.size.y / 2)
317
graph.rect[1].y = node.pos.y + node.size.y / 2;
320
graph.graphattr.bb = concat (graph.rect[0].x, ',',
321
graph.rect[0].y, ',', graph.rect[1].x, ',',
323
if (graph.lp & tablesize (graph.lp) > 0)
324
graph.graphattr.lp = concat (graph.lp.x, ',', graph.lp.y);
327
if (~((fd = dotty.openio (name, type, 'w')) >= 0) |
328
~writegraph (fd, graph, 0)) {
329
dotty.message (0, 'cannot save graph');
332
if (~(type == 'file' & name == '-'))
335
dotty.protogt.packrecordfields = function (gt, fields) {
336
local attrs, attr, fid, field;
338
for (fid = 0; fields[fid]; fid = fid + 1) {
341
attr = gt.packrecordfields (gt, field.fields);
343
attr = concat (field.rect[0].x, ',', field.rect[0].y,
344
',', field.rect[1].x, ',', field.rect[1].y);
346
attrs = concat (attrs, ' ', attr);
352
dotty.protogt.setgraph = function (gt, graph) {
353
local vid, vt, nid, eid, gid;
355
if (gt.layoutpending > 0)
356
gt.cancellayout (gt);
357
for (vid in gt.views) {
362
gt.graph = copy (graph);
363
gt.undoarray = ['level' = 0; 'entries' = [];];
365
gt.graph.maxgid = tablesize (graph.graphs);
366
gt.graph.maxnid = tablesize (graph.nodes);
367
gt.graph.maxeid = tablesize (graph.edges);
368
for (nid in gt.graph.nodes)
369
gt.graph.nodes[nid][dotty.keys.nid] = nid;
370
for (eid in gt.graph.edges)
371
gt.graph.edges[eid][dotty.keys.eid] = eid;
372
for (gid in gt.graph.graphs)
373
gt.graph.graphs[gid][dotty.keys.gid] = gid;
375
dotty.message (1, 'generating layout');
379
dotty.protogt.erasegraph = function (gt, protogt, protovt) {
382
if (gt.layoutpending > 0)
383
gt.cancellayout (gt);
384
for (vid in gt.views) {
391
protogt = dotty.protogt;
392
gt.graph = copy (protogt.graph);
393
gt.undoarray = ['level' = 0; 'entries' = [];];
395
dotty.protogt.layoutgraph = function (gt) {
396
if (gt.graph.graphattr.bb) {
397
gt.unpacklayout (gt, gt.graph);
398
gt.setviewsize (gt.views, gt.graph.rect);
399
gt.redrawgraph (gt, gt.views);
402
if (gt.layoutmode == 'async') {
407
if (~gt.finishlayout (gt))
409
gt.setviewsize (gt.views, gt.graph.rect);
410
gt.redrawgraph (gt, gt.views);
412
if (~gt.startlayout (gt))
415
while (~gt.finishlayout (gt))
417
gt.setviewsize (gt.views, gt.graph.rect);
418
gt.redrawgraph (gt, gt.views);
421
dotty.protogt.createview = function (gt, protovt) {
422
local vt, ovt, id, t;
428
protovt = dotty.protovt.normal;
429
if (protovt.mode ~= 'replace') {
430
for (id in dotty.protovt[protovt.type])
431
vt[id] = copy (dotty.protovt[protovt.type][id]);
434
vt[id] = copy (protovt[id]);
435
if (~(vt.parent >= 0)) {
436
vt.view = createwidget (-1, [
442
vt.scroll = createwidget (vt.view, ['type' = 'scroll';]);
445
vt.scroll = createwidget (vt.parent, [
450
vt.canvas = createwidget (vt.scroll, [
452
'color' = [0 = protovt.bgcolor; 1 = protovt.fgcolor;];
454
setwidgetattr (vt.canvas, [
456
'viewport' = vt.vsize;
459
dotty.views[vt.canvas] = vt;
462
gt.views[vt.vtid] = vt;
463
dotty.views[vt.scroll] = vt;
465
dotty.views[vt.view] = vt;
466
if (protovt.colors & tablesize (protovt.colors) > 0) {
467
for (id in protovt.colors)
468
if (setwidgetattr (vt.canvas, ['color' = [
469
protovt.colors[id] = id;
472
if (tablesize (t) ~= 3 | setwidgetattr (vt.canvas, [
473
'color' = [protovt.colors[id] = [
474
'h' = ston (t[0]); 's' = ston (t[1]); 'v' = ston (t[2]);
478
concat ('unknown color ', id, ' using #1'));
481
vt.colors = copy (protovt.colors);
482
vt.colorn = protovt.colorn;
483
} else if (tablesize (gt.views) > 1) {
485
if (gt.views[id] ~= vt)
488
for (id in ovt.colors)
489
if (setwidgetattr (vt.canvas, ['color' = [
493
if (tablesize (t) ~= 3 | setwidgetattr (vt.canvas, [
494
'color' = [ovt.colors[id] = [
495
'h' = ston (t[0]); 's' = ston (t[1]); 'v' = ston (t[2]);
499
concat ('unknown color ', id, ' using #1'));
502
vt.colors = copy (ovt.colors);
503
vt.colorn = ovt.colorn;
506
gt.setviewsize ([vt.vtid = vt;], gt.graph.rect);
507
gt.drawgraph (gt, [vt.vtid = vt;]);
508
for (id in vt.uifuncs)
509
if (id == 'closeview')
510
widgets[vt.view][id] = vt.uifuncs[id];
512
widgets[vt.canvas][id] = vt.uifuncs[id];
515
dotty.protogt.destroyview = function (gt, vt) {
516
destroywidget (vt.canvas);
517
destroywidget (vt.scroll);
519
destroywidget (vt.view);
520
remove (vt.view, dotty.views);
522
remove (vt.scroll, dotty.views);
523
remove (vt.canvas, dotty.views);
525
remove (vt.vtid, gt.views);
526
if (tablesize (dotty.views) == 0)
529
dotty.protogt.zoom = function (gt, vt, factor, pos) {
530
gt.setviewscale ([vt.vtid = vt;], factor);
532
gt.setviewcenter ([vt.vtid = vt;], pos);
533
gt.redrawgraph (gt, [vt.vtid = vt;]);
535
dotty.protogt.findnode = function (gt, vt) {
536
local key, node, node1, nid;
538
if (~(key = ask ('give node name or label')))
540
if (gt.graph.nodedict[key] >= 0)
541
node = gt.graph.nodes[gt.graph.nodedict[key]];
542
else if (gt.graph.nodedict[ston (key)] >= 0)
543
node = gt.graph.nodes[gt.graph.nodedict[ston (key)]];
545
for (nid in gt.graph.nodes) {
546
node1 = gt.graph.nodes[nid];
547
if (node1.attr.label == key | node1.attr.label == ston (key)) {
554
dotty.message (0, concat ('cannot find node: ', key));
557
gt.setviewcenter ([vt.vtid = vt;], node.pos);
559
dotty.protogt.setattr = function (gt, obj) {
560
local kv, t, attr, value;
562
if (~(kv = ask ('give attr/value, eg. color=blue')))
568
obj.attr == gt.graph.graphattr |
569
obj.attr == gt.graph.edgeattr |
570
obj.attr == gt.graph.nodeattr
572
obj.attr[attr] = value;
576
gt.undrawnode (gt, gt.views, obj);
577
obj.attr[attr] = value;
578
gt.unpacknodeattr (gt, obj);
579
gt.drawnode (gt, gt.views, obj);
580
} else if (obj.eid >= 0) {
581
gt.undrawedge (gt, gt.views, obj);
582
obj.attr[attr] = value;
583
gt.unpackedgeattr (gt, obj);
584
gt.drawedge (gt, gt.views, obj);
587
dotty.protogt.getattr = function (gt, node) {
590
if (~(kv.key = ask ('give attr name')))
592
if ((kv.val = node.attr[kv.key]))
599
dotty.createviewandgraph = function (name, type, protogt, protovt) {
603
protogt = dotty.protogt;
604
if (protogt.creategraph)
605
gt = protogt.creategraph (protogt);
607
gt = dotty.protogt.creategraph (protogt);
608
vt = gt.createview (gt, protovt);
610
protogt.graph = copy (dotty.protogt.graph);
612
gt.loadgraph (gt, name, type, protogt.graph, 1);
613
return ['gt' = gt; 'vt' = vt;];
615
dotty.openio = function (name, type, mode) {
620
if (type == 'file') {
622
if (mode == 'r' | mode == 'r+')
626
} else if (~((fd = openio ('file', name, mode)) >= 0)) {
627
dotty.message (0, concat ('cannot open file: ', name));
630
} else if (type == 'pipe') {
631
if (~((fd = openio ('pipe', 'ksh', mode,
632
concat ("%e ", name))) >= 0)) {
633
dotty.message (0, concat ('cannot run command: ', name));
640
dotty.pushbusy = function (gt, views) {
644
for (vid in gt.views)
645
setwidgetattr (vid, ['cursor' = 'watch';]);
646
gt.busy = gt.busy + 1;
648
dotty.popbusy = function (gt, views) {
651
gt.busy = gt.busy - 1;
653
for (vid in gt.views)
654
setwidgetattr (vid, ['cursor' = 'default';]);
656
dotty.message = function (level, text) {
657
if (level <= dotty.mlevel)
658
echo ('dotty.lefty: ', text);
661
# printing or saving to file
663
dotty.protogt.printorsave = function (gt, vt, otype, name, mode, ptype) {
664
local pr, wrect, vsize, xy, psize, canvas, pscanvas, cid, cname, t;
665
local graph, edgehandles, fontmap, eid, edge, nid, node, gid, sgraph;
668
if (~(otype = ask ('print to', 'choice', 'file|printer')))
670
if (otype == 'printer') {
671
name = '/tmp/dottyout.ps';
672
if (getenv ('LEFTYWINSYS') ~= 'mswin' & ~pr)
673
if (~(pr = ask ('printer command', 'string', 'lpr')))
677
if (~(name = ask ('postscript file', 'file', 'out.ps')))
680
if (~(ptype = ask ('page size', 'choice', '8.5x11|11x17|36x50')))
683
if (~(mode = ask ('mode', 'choice', 'portrait|landscape|best fit')))
685
wrect = copy (vt.wrect);
686
wrect[0].x = wrect[0].x - 1;
687
wrect[1].x = wrect[1].x + 1;
688
wrect[0].y = wrect[0].y - 1;
689
wrect[1].y = wrect[1].y + 1;
690
vsize = copy (vt.vsize);
695
xy = vsize.x / vsize.y;
696
if (mode == 'best fit') {
702
psize = dotty.pagesizes[ptype];
703
if (mode == 'portrait') {
704
if (xy < psize.x / psize.y) {
705
vsize.y = psize.y * 300;
706
vsize.x = vsize.y * xy;
708
vsize.x = psize.x * 300;
709
vsize.y = vsize.x / xy;
712
if (xy < psize.y / psize.x) {
713
vsize.y = psize.x * 300;
714
vsize.x = vsize.y * xy;
716
vsize.x = psize.y * 300;
717
vsize.y = vsize.x / xy;
720
if (~((pscanvas = createwidget (-1, [
722
'origin' = ['x' = 0; 'y' = 0;];
727
dotty.message (0, 'cannot open printer device');
730
for (cname in vt.colors) {
731
cid = vt.colors[cname];
732
if (setwidgetattr (pscanvas, ['color' = [cid = cname;];]) ~= 1) {
733
t = split (cname, ' ');
734
if (tablesize (t) ~= 3 |
735
setwidgetattr (pscanvas, ['color' = [cid = [
736
'h' = ston (t[0]); 's' = ston (t[1]); 'v' = ston (t[2]);
738
dotty.message (0, concat ('unknown color ',
739
cname, ' using #1'));
743
setwidgetattr (pscanvas, ['window' = wrect;]);
744
graph = copy (gt.graph);
746
vt.canvas = pscanvas;
747
edgehandles = gt.edgehandles;
749
fontmap = dotty.maps[getenv ('LEFTYWINSYS')].psfontmap;
750
for (eid in graph.edges) {
751
edge = graph.edges[eid];
752
edge.fontname = fontmap[edge.attr.fontname];
753
gt.drawedge (gt, [0 = vt;], edge);
755
for (nid in graph.nodes) {
756
node = graph.nodes[nid];
757
node.fontname = fontmap[node.attr.fontname];
758
gt.drawnode (gt, [0 = vt;], node);
760
for (gid in graph.graphs) {
761
sgraph = graph.graphs[gid];
762
sgraph.fontname = fontmap[sgraph.graphattr.fontname];
763
gt.drawsgraph (gt, [0 = vt;], sgraph);
765
gt.edgehandles = edgehandles;
767
destroywidget (pscanvas);
768
if (otype == 'printer' & getenv ('LEFTYWINSYS') ~= 'mswin')
769
system (concat (pr, ' /tmp/dottyout.ps; rm /tmp/dottyout.ps'));