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