2
# dotty_ui: user interface functions and data structures
4
dotty.protogt.doaction = function (data, s) {
7
vt = dotty.views[data.widget];
8
gt = dotty.graphs[vt.gtid];
9
if (data.obj.nid >= 0) {
10
if (gt.actions.node[s]) {
11
gt.actions.node[s] (gt, vt, data.obj, data);
14
} else if (data.obj.eid >= 0) {
15
if (gt.actions.edge[s]) {
16
gt.actions.edge[s] (gt, vt, data.obj, data);
20
if (gt.actions.general[s])
21
gt.actions.general[s] (gt, vt, data);
23
dotty.protogt.actions.general = [
24
"undo" = function (gt, vt, data) {
27
"paste" = function (gt, vt, data) {
28
gt.paste (gt, data.pos, 1);
30
"do layout" = function (gt, vt, data) {
33
"cancel layout" = function (gt, vt, data) {
36
"redraw" = function (gt, vt, data) {
37
gt.redrawgraph (gt, [vt.vtid = vt;]);
39
"new graph" = function (gt, vt, data) {
40
gt.erasegraph (gt, null, null);
42
"load graph" = function (gt, vt, data) {
45
gt.savegraph (gt, gt.name, 'file', 1);
47
gt.loadgraph (gt, null, 'file', dotty.protogt.graph, 1);
49
"load parent" = function (gt, vt, data) {
51
pname = gt.graph['parent'];
53
if ( ~pname | pname == '' )
58
gt.savegraph (gt, gt.name, gt.type, 1);
61
gt.loadgraph (gt, pname, 'file', dotty.protogt.graph, 1);
63
"reload graph" = function (gt, vt, data) {
64
gt.loadgraph (gt, gt.name, gt.type, gt.graph, 1);
66
"save graph" = function (gt, vt, data) {
68
gt.savegraph (gt, gt.name, gt.type, 1);
70
"save graph as" = function (gt, vt, data) {
72
gt.savegraph (gt, null, 'file', 1);
74
"open view" = function (gt, vt, data) {
75
gt = dotty.protogt.creategraph (null);
76
gt.createview (gt, null);
78
"copy view" = function (gt, vt, data) {
79
gt = gt.copygraph (gt);
80
gt.createview (gt, vt);
82
"birdseye view" = function (gt, vt, data) {
83
gt.createview (gt, dotty.protovt.birdseye);
85
"clone view" = function (gt, vt, data) {
86
gt.createview (gt, vt);
88
"close view" = function (gt, vt, data) {
89
gt.destroyview (gt, vt);
90
if (tablesize (gt.views) == 0)
93
"set graph attr" = function (gt, vt, data) {
94
gt.setattr (gt, ['attr' = gt.graph.graphattr;]);
96
"set node attr" = function (gt, vt, data) {
97
gt.setattr (gt, ['attr' = gt.graph.nodeattr;]);
99
"set edge attr" = function (gt, vt, data) {
100
gt.setattr (gt, ['attr' = gt.graph.edgeattr;]);
102
"zoom in" = function (gt, vt, data) {
103
gt.zoom (gt, vt, 0.5, data.pos);
105
"zoom out" = function (gt, vt, data) {
106
gt.zoom (gt, vt, 2, data.pos);
108
"zoom in slowly" = function (gt, vt, data) {
109
gt.zoom (gt, vt, 0.9, data.pos);
111
"zoom out slowly" = function (gt, vt, data) {
112
gt.zoom (gt, vt, 1.1, data.pos);
114
"move interactively" = function (gt, vt, data) {
115
gt.setviewcenter ([vt.vtid = vt;], data.pos);
116
# gt.redrawgraph (gt, [vt.vtid = vt;]);
118
"fold subgraph" = function (gt, vt, data) {
121
grph = ask( 'Name of subgraph to fold');
122
if ( ~grph | grph == '' | grph == ' ' | ~gt.graph.graphdict[grph] ) {
123
echo('No subgraph found');
126
gt.foldsgraph(gt, gt.views, grph );
128
"add node" = function( gt, vt, data) {
131
newname = ask('Give new node name');
132
if (newname == '' | newname == ' ')
134
gt.insertnode (gt, data.pos, null, newname, null, 1);
136
"add subgraph" = function (gt, vt, data) {
139
newname = ask('Give new subgraph name');
140
if (newname == '' | newname == ' ')
142
gt.insertsgraph (gt, newname, null, 1);
145
"find node" = function (gt, vt, data) {
146
gt.findnode (gt, vt);
148
"print graph" = function (gt, vt, data) {
149
gt.printorsave (gt, vt, null, null, null, null);
151
"text view" = function (gt, vt, data) {
152
if (dotty.txtview == 'on')
153
dotty.txtview = 'off';
155
dotty.txtview = 'on';
156
txtview (dotty.txtview);
158
"quit" = function (gt, vt, data) {
161
reply = ask ('Save graph', 'choice', 'Yes|No|Cancel');
162
if (reply == "Cancel")
164
else if ( reply == "Yes") {
166
gt.savegraph (gt, gt.name, gt.type, 1);
171
dotty.protogt.actions.node = [
172
"cut" = function (gt, vt, obj, data) {
173
gt.cut (gt, obj, 'one', 'support', 'cut');
174
dotty.clipgt.layoutgraph (dotty.clipgt);
176
"Cut" = function (gt, vt, obj, data) {
177
gt.cut (gt, obj, 'reachable', 'support', 'cut');
178
dotty.clipgt.layoutgraph (dotty.clipgt);
180
"copy" = function (gt, vt, obj, data) {
181
gt.cut (gt, obj, 'one', 'support', 'copy');
182
dotty.clipgt.layoutgraph (dotty.clipgt);
184
"Copy" = function (gt, vt, obj, data) {
185
gt.cut (gt, obj, 'reachable', 'support', 'copy');
186
dotty.clipgt.layoutgraph (dotty.clipgt);
188
"group" = function (gt, vt, obj, data) {
191
if ((kv = gt.getattr (gt, obj)))
192
gt.groupnodesbyattr (gt, kv.key, kv.val, [
193
'label' = kv.val; kv.key = kv.val;
196
"Group" = function (gt, vt, obj, data) {
199
if ((kv = gt.getattr (gt, obj)))
200
gt.groupnodesbyattr (gt, kv.key, kv.val, [
201
'label' = kv.val; kv.key = kv.val;
204
"delete" = function (gt, vt, obj, data) {
206
gt.removeedge (gt, obj);
208
gt.removenode (gt, obj);
210
"Delete" = function (gt, vt, obj, data) {
211
gt.removesubtree (gt, obj);
213
"remove" = function (gt, vt, obj, data) {
215
if ((kv = gt.getattr (gt, obj)))
216
gt.removenodesbyattr (gt, kv.key, kv.val);
218
"Remove" = function (gt, vt, obj, data) {
220
if ((kv = gt.getattr (gt, obj)))
221
gt.removesubtreesbyattr (gt, kv.key, kv.val);
223
"fold/unfold subtree" = function (gt, vt, obj, data) {
224
if ( obj.nid >= 0 ) {
225
if ( obj.attr.folded == '0' ) {
226
if ( gt.foldsubtree( gt, obj )) {
227
# gt.layoutgraph (gt);
228
# gt.setviewcenter ([vt.vtid = vt;], obj.pos);
229
gt.drawgraph (gt, [vt.vtid = vt;]);
232
else if ( obj.attr.folded == '1' ) {
233
gt.unfoldsubtree( gt, obj );
235
# Recentering on base node doesn't seem to work in every case...
236
# gt.setviewcenter ([vt.vtid = vt;], obj.pos);
237
# gt.redrawgraph (gt, [vt.vtid = vt;]);
241
echo('Not on a node');
243
"unfold subtree" = function (gt, vt, obj, data) {
244
if ( obj.nid >= 0 ) {
245
gt.unfoldsubtree( gt, obj );
246
gt.drawgraph (gt, [vt.vtid = vt;]);
249
echo('Not on a node', obj.nid);
251
"set attr" = function (gt, vt, obj, data) {
252
gt.setattr (gt, obj);
254
"print attr" = function (gt, vt, obj, data) {
257
attname = ask('What attribute?');
258
echo (obj.attr[attname]);
262
"change label" = function (gt, vt, obj, data) {
264
newname = ask('Enter new label name');
267
if (newname == '' | newname == ' ')
269
if ( obj.nid >= 0 ) {
270
gt.undrawnode (gt, gt.views, obj);
271
obj.attr['label'] = newname;
272
gt.unpacknodeattr (gt, obj);
273
gt.drawnode (gt, gt.views, obj);
275
else if (obj.eid >= 0) {
276
gt.undrawedge (gt, gt.views, obj);
277
obj.attr['label'] = newname;
278
gt.unpackedgeattr (gt, obj);
279
gt.drawedge (gt, gt.views, obj);
283
"load subgraph" = function (gt, vt, obj, data) {
284
local node, fname, pname, ngt, rtn, fd, graph;
287
echo('Invalid node');
292
gt.savegraph (gt, gt.name, gt.type, 1);
295
fname = concat (obj.name, '.dot');
296
ngt = dotty.protogt.creategraph (null);
297
ngt.graphattr.parent = pname;
299
if (~((fd = dotty.openio (fname, 'file', 'r')) >= 0)) {
300
gt.erasegraph (gt, null, null);
301
ngt.createview (ngt, null);
302
gt.destroyview (gt, vt);
303
ngt.redrawgraph (ngt, ngt.views);
304
ngt.insertnode (ngt, ['x' = 30; 'y' = 0;], null, obj.name, null, 1);
305
ngt.savegraph (ngt, fname, 'file', 1);
308
gt.loadgraph (gt, fname, 'file', ngt, 1);
311
dotty.protogt.actions.edge = dotty.protogt.actions.node;
312
dotty.protovt.normal.menus = [
324
10 = "save graph as";
328
14 = "birdseye view";
330
16 = "set graph attr";
331
17 = "set node attr";
332
18 = "set edge attr";
354
13 = "load subgraph";
368
dotty.protovt.normal.keys = [
373
'k' = "cancel layout";
375
'R' = "reload graph";
381
'.' = "zoom in slowly";
382
',' = "zoom out slowly";
383
' ' = "move interactively";
396
'f' = "fold/unfold subtree";
398
'/' = "change label";
399
'-' = "load subgraph";
407
'/' = "change label";
410
dotty.protovt.birdseye.menus = dotty.protovt.normal.menus;
411
dotty.protovt.birdseye.keys = dotty.protovt.normal.keys;
412
dotty.protovt.normal.uifuncs = [
413
'leftdown' = function (data) {
416
gt = dotty.graphs[vt.gtid];
417
vt = dotty.views[data.widget];
418
if (dotty.node2move) {
419
# & (dotty.rp2.x ~= data.pos.x | dotty.rp2.y ~= data.pos.y)) {
420
gt.movenode (gt, dotty.node2move, data.pos);
421
gt.redrawgraph (gt, [vt.vtid = vt;]);
422
# gt.redrawgraph (gt, gt.views);
423
dotty.rp2 = data.pos;
425
else if (data.obj.nid >= 0) {
426
dotty.node2move = data.obj;
427
dotty.movewidget = data.widget;
428
dotty.rp2 = data.pos;
431
'leftmove' = function (data) {
434
gt = dotty.graphs[vt.gtid];
435
vt = dotty.views[data.widget];
436
dotty.node2move = data.obj;
437
dotty.movewidget = data.widget;
438
dotty.rp2 = data.pos;
440
if (dotty.node2move ) {
441
# & (dotty.rp2.x ~= data.pos.x | dotty.rp2.y ~= data.pos.y)) {
442
gt.movenode (gt, dotty.node2move, dotty.rp2);
443
gt.setviewscale ([vt.vtid = vt;], 1);
444
gt.redrawgraph (gt, [vt.vtid = vt;]);
445
# gt.redrawgraph (gt, gt.views);
446
dotty.rp2 = data.pos;
449
'leftup' = function (data) {
452
gt = dotty.graphs[dotty.views[data.widget].gtid];
453
if (dotty.node2move) {
454
if (dotty.movewidget == data.widget)
455
gt.movenode (gt, dotty.node2move, data.pos);
458
# Use 'n' key to create new node
459
# else if (~data.obj)
460
# gt.insertnode (gt, data.pos, null, null, null, 1);
462
'middledown' = function (data) {
463
if (~(data.obj.nid >= 0))
465
dotty.rubberband = 1;
466
dotty.movewidget = data.widget;
467
setgfxattr (data.widget, ['mode' = 'xor';]);
468
# setgfxattr (data.widget, ['mode' = 'src';]);
469
dotty.rp1 = data.pos;
470
dotty.rp2 = data.pos;
471
line (data.widget, null, dotty.rp1, dotty.rp2, ['color' = 1;]);
473
'middlemove' = function (data) {
474
if (dotty.rubberband ~= 1 |
475
(dotty.rp2.x == data.pos.x & dotty.rp2.y == data.pos.y))
477
line (data.widget, null, dotty.rp1, dotty.rp2, ['color' = 1;]);
478
dotty.rp2 = data.pos;
479
line (data.widget, null, dotty.rp1, dotty.rp2, ['color' = 1;]);
481
'middleup' = function (data) {
484
gt = dotty.graphs[dotty.views[data.widget].gtid];
485
if (dotty.rubberband ~= 1)
487
dotty.rubberband = 0;
488
line (dotty.movewidget, null, dotty.rp1, dotty.rp2, ['color' = 1;]);
489
setgfxattr (dotty.movewidget, ['mode' = 'src';]);
490
if (dotty.movewidget ~= data.widget |
491
~(data.pobj.nid >= 0) | ~(data.obj.nid >= 0))
493
if (data.pobj.attr.support)
495
data.obj.nid = data.obj;
496
data.pobj.nid = data.pobj;
497
], data.obj, null, null, null, 1, 1);
498
else if (data.obj.attr.support)
500
data.obj.nid = data.obj;
501
data.pobj.nid = data.pobj;
502
], data.pobj, null, null, null, 1, 1);
504
gt.insertedge (gt, data.pobj, null, data.obj, null, null, 1);
506
'rightdown' = function (data) {
507
local vt, gt, menu, i;
509
vt = dotty.views[data.widget];
510
gt = dotty.graphs[vt.gtid];
512
menu = vt.menus.general;
513
else if (data.obj.nid >= 0)
514
menu = vt.menus.node;
515
else if (data.obj.eid >= 0)
516
menu = vt.menus.edge;
517
if ((i = displaymenu (data.widget, menu)) >= 0)
518
gt.doaction (data, menu[i]);
520
'keyup' = function (data) {
521
local vt, gt, action;
523
vt = dotty.views[data.widget];
524
gt = dotty.graphs[vt.gtid];
525
if (data.obj.nid >= 0) {
526
if (vt.keys.node[data.key])
527
action = vt.keys.node[data.key];
528
} else if (data.obj.eid >= 0) {
529
if (vt.keys.edge[data.key])
530
action = vt.keys.edge[data.key];
533
if (vt.keys.general[data.key])
534
action = vt.keys.general[data.key];
536
gt.doaction (data, action);
538
'redraw' = function (data) {
541
vt = dotty.views[data.widget];
542
gt = dotty.graphs[vt.gtid];
543
gt.drawgraph (gt, [vt.vtid = vt;]);
545
'closeview' = function (data) {
548
vt = dotty.views[data.widget];
549
gt = dotty.graphs[vt.gtid];
550
gt.destroyview (gt, vt);
551
if (tablesize (gt.views) == 0)
552
gt.destroygraph (gt);
555
dotty.protovt.birdseye.uifuncs = [
556
'leftdown' = function (data) {
559
gt = dotty.graphs[dotty.views[data.widget].gtid];
560
for (vid in gt.views) {
562
if (vt.type ~= 'birdseye')
563
gt.setviewcenter ([vid = vt;], data.pos);
566
'leftmove' = function (data) {
569
gt = dotty.graphs[dotty.views[data.widget].gtid];
570
for (vid in gt.views) {
572
if (vt.type ~= 'birdseye')
573
gt.setviewcenter ([vid = vt;], data.pos);
576
'leftup' = function (data) {
579
gt = dotty.graphs[dotty.views[data.widget].gtid];
580
for (vid in gt.views) {
582
if (vt.type ~= 'birdseye')
583
gt.setviewcenter ([vid = vt;], data.pos);
586
'middledown' = dotty.protovt.normal.uifuncs.middledown;
587
'middlemove' = dotty.protovt.normal.uifuncs.middlemove;
588
'middleup' = dotty.protovt.normal.uifuncs.middleup;
589
'rightdown' = dotty.protovt.normal.uifuncs.rightdown;
590
'keyup' = dotty.protovt.normal.uifuncs.keyup;
591
'redraw' = dotty.protovt.normal.uifuncs.redraw;
592
'closeview' = dotty.protovt.normal.uifuncs.closeview;
594
dotty.monitorfile = function (data) {
597
for (gtid in dotty.layoutpending) {
598
lpt = dotty.layoutpending[gtid];
599
if (lpt.fd == data.fd) {
600
gt = dotty.graphs[lpt.gtid];