~ubuntu-branches/ubuntu/lucid/graphviz/lucid-security

« back to all changes in this revision

Viewing changes to contrib/lefty-grace/lefty-grace/dotty_draw.lefty

  • Committer: Bazaar Package Importer
  • Author(s): Stephen M Moraco
  • Date: 2002-02-05 18:52:12 UTC
  • Revision ID: james.westby@ubuntu.com-20020205185212-8i04c70te00rc40y
Tags: upstream-1.7.16
ImportĀ upstreamĀ versionĀ 1.7.16

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#
 
2
# dotty_draw: drawing functions and data structures
 
3
#
 
4
dotty.protogt.drawgraph = function (gt, views) {
 
5
    local gid, eid, nid, graph;
 
6
 
 
7
    graph = gt.graph;
 
8
    gt.drawsgraph (gt, views, graph);
 
9
    for (gid in graph.graphs)
 
10
        gt.drawsgraph (gt, views, graph.graphs[gid]);
 
11
    for (eid in graph.edges)
 
12
        gt.drawedge (gt, views, graph.edges[eid]);
 
13
    for (nid in graph.nodes)
 
14
        gt.drawnode (gt, views, graph.nodes[nid]);
 
15
};
 
16
dotty.protogt.redrawgraph = function (gt, views) {
 
17
    local vid;
 
18
 
 
19
    for (vid in views)
 
20
        clear (views[vid].canvas);
 
21
    gt.drawgraph (gt, views);
 
22
};
 
23
dotty.protogt.setviewsize = function (views, r) {
 
24
    local vid, vt, w2v, scale, attr;
 
25
 
 
26
    for (vid in views) {
 
27
        vt = views[vid];
 
28
        vt.wrect = copy (r);
 
29
        if (r[1].x == 0 | r[1].y == 0) {
 
30
            attr = getwidgetattr (vt.scroll, [0 = 'size';]);
 
31
            vt.wrect[1] = copy (attr.size);
 
32
        }
 
33
        if (vt.type == 'birdseye') {
 
34
            attr = getwidgetattr (vt.scroll, [0 = 'size';]);
 
35
            scale.x = (vt.wrect[1].x - vt.wrect[0].x) / attr.size.x;
 
36
            scale.y = (vt.wrect[1].y - vt.wrect[0].y) / attr.size.y;
 
37
            if (scale.x > 1 & scale.x > scale.y)
 
38
                vt.w2v = scale.x;
 
39
            else if (scale.y > 1)
 
40
                vt.w2v = scale.y;
 
41
            else
 
42
                vt.w2v = 1;
 
43
        }
 
44
        w2v = vt.w2v;
 
45
        vt.vsize = [
 
46
            'x' = (vt.wrect[1].x - vt.wrect[0].x) / w2v;
 
47
            'y' = (vt.wrect[1].y - vt.wrect[0].y) / w2v;
 
48
        ];
 
49
        setwidgetattr (vt.canvas, [
 
50
            'window' = vt.wrect;
 
51
            'viewport' = vt.vsize;
 
52
        ]);
 
53
    }
 
54
};
 
55
dotty.protogt.setviewscale = function (views, factor) {
 
56
    local vid, vt, w2v;
 
57
 
 
58
    for (vid in views) {
 
59
        vt = views[vid];
 
60
        if ((w2v = vt.w2v * factor) < 0.01) {
 
61
            dotty.message (0, 'cannot zoom any closer');
 
62
            return;
 
63
        }
 
64
        vt.w2v = w2v;
 
65
        vt.vsize = [
 
66
            'x' = (vt.wrect[1].x - vt.wrect[0].x) / w2v;
 
67
            'y' = (vt.wrect[1].y - vt.wrect[0].y) / w2v;
 
68
        ];
 
69
        setwidgetattr (vt.canvas, ['viewport' = vt.vsize;]);
 
70
    }
 
71
};
 
72
dotty.protogt.setviewcenter = function (views, center) {
 
73
    local vid, vt, pos;
 
74
 
 
75
    for (vid in views) {
 
76
        vt = views[vid];
 
77
        pos = [
 
78
            'x' = center.x * vt.vsize.x / (vt.wrect[1].x - vt.wrect[0].x);
 
79
            'y' = (vt.wrect[1].y - center.y) * vt.vsize.y /
 
80
                (vt.wrect[1].y - vt.wrect[0].y);
 
81
        ];
 
82
        setwidgetattr (vt.scroll, ['childcenter' = pos;]);
 
83
    }
 
84
};
 
85
dotty.protogt.foldsgraph = function (gt, views, sgraph) {
 
86
    local nid;
 
87
 
 
88
#   gt.undrawsgraph(gt, views, sgraph);
 
89
    for (nid in sgraph.nodes)
 
90
        gt.undrawnode (gt, views, graph.nodes[nid]);
 
91
};
 
92
 
 
93
dotty.protogt.drawsgraph = function (gt, views, sgraph) {
 
94
    local vid, canvas, pos;
 
95
 
 
96
    sgraph.draw = 1;
 
97
    if (~sgraph.rect[0] | sgraph.graphattr.style == 'invis')
 
98
        return;
 
99
    for (vid in views) {
 
100
        canvas = views[vid].canvas;
 
101
        if (~sgraph.type) # 'type' only exists on top level
 
102
            box (canvas, null, sgraph.rect, ['color' = sgraph.color;]);
 
103
        if (sgraph.graphattr.label) {
 
104
            if (sgraph.lp.x >= 0) {
 
105
                pos = sgraph.lp;
 
106
                text (canvas, null, pos, sgraph.graphattr.label,
 
107
                        sgraph.fontname, sgraph.fontsize, 'cc',
 
108
                        ['color' = sgraph.fontcolor;]);
 
109
            } else {
 
110
                pos = ['x' = sgraph.rect[0].x; 'y' = sgraph.rect[1].y;];
 
111
                text (canvas, null, pos, sgraph.graphattr.label,
 
112
                        sgraph.fontname, sgraph.fontsize, 'ld',
 
113
                        ['color' = sgraph.fontcolor;]);
 
114
            }
 
115
        }
 
116
    }
 
117
};
 
118
dotty.protogt.undrawsgraph = function (gt, views, sgraph) {
 
119
    local vid, canvas, pos;
 
120
 
 
121
    if (~sgraph.drawn)
 
122
        return;
 
123
    sgraph.drawn = 0;
 
124
    if (~sgraph.rect[0] | sgraph.graphattr.style == 'invis')
 
125
        return;
 
126
    for (vid in views) {
 
127
        canvas = views[vid].canvas;
 
128
        if (~sgraph.type) # 'type' only exists on top level
 
129
            box (canvas, null, sgraph.rect, ['color' = 0;]);
 
130
        if (sgraph.graphattr.label) {
 
131
            if (sgraph.lp.x >= 0) {
 
132
                pos = sgraph.lp;
 
133
                text (canvas, null, pos, sgraph.graphattr.label,
 
134
                        sgraph.fontname, sgraph.fontsize, 'cc',
 
135
                        ['color' = 0;]);
 
136
            } else {
 
137
                pos = ['x' = sgraph.rect[0].x; 'y' = sgraph.rect[1].y;];
 
138
                text (canvas, null, pos, sgraph.graphattr.label,
 
139
                        sgraph.fontname, sgraph.fontsize, 'ld',
 
140
                        ['color' = 0;]);
 
141
            }
 
142
        }
 
143
        clearpick (canvas, sgraph);
 
144
    }
 
145
};
 
146
dotty.protogt.drawnode = function (gt, views, node) {
 
147
    local vid, func, pos, size, rect;
 
148
 
 
149
    node.drawn = 1;
 
150
    if (~node.pos)
 
151
        return;
 
152
    if (node.attr.style == 'invis') {
 
153
        pos = node.pos;
 
154
        size = node.size;
 
155
        rect[0] = ['x' = pos.x - size.x / 2; 'y' = pos.y - size.y / 2;];
 
156
        rect[1] = ['x' = rect[0].x + size.x; 'y' = rect[0].y + size.y;];
 
157
        for (vid in views)
 
158
            setpick (views[vid].canvas, node, rect);
 
159
        return;
 
160
    }
 
161
 
 
162
    if ( node.attr.folded == '1' )
 
163
        func = gt.shapefunc['Msquare'];
 
164
    else if (~(func = gt.shapefunc[node.attr.shape]))
 
165
        func = gt.shapefunc['box'];
 
166
    for (vid in views)
 
167
        func (gt, views[vid].canvas, node);
 
168
};
 
169
dotty.protogt.undrawnode = function (gt, views, node) {
 
170
    local vid, func, pos, size, rect, color, fontcolor, outlinecolor;
 
171
 
 
172
    if (~node.drawn)
 
173
        return;
 
174
    node.drawn = 0;
 
175
    if (~node.pos)
 
176
        return;
 
177
    if (node.attr.style == 'invis') {
 
178
        pos = node.pos;
 
179
        size = node.size;
 
180
        rect[0] = ['x' = pos.x - size.x / 2; 'y' = pos.y - size.y / 2;];
 
181
        rect[1] = ['x' = rect[0].x + size.x; 'y' = rect[0].y + size.y;];
 
182
        for (vid in views)
 
183
            clearpick (views[vid].canvas, node);
 
184
        return;
 
185
    }
 
186
    color = node.color;
 
187
    node.color = 0;
 
188
    fontcolor = node.fontcolor;
 
189
    node.fontcolor = 0;
 
190
    outlinecolor = dotty.outlinecolor;
 
191
    dotty.outlinecolor = 0;
 
192
    if ( node.attr.folded == '1' )
 
193
        func = gt.shapefunc['Msquare'];
 
194
    else if (~(func = gt.shapefunc[node.attr.shape]))
 
195
        func = gt.shapefunc['box'];
 
196
    for (vid in views) {
 
197
        func (gt, views[vid].canvas, node);
 
198
        clearpick (views[vid].canvas, node);
 
199
    }
 
200
    node.color = color;
 
201
    node.fontcolor = fontcolor;
 
202
    dotty.outlinecolor = outlinecolor;
 
203
};
 
204
dotty.protogt.shapefunc.record = function (gt, canvas, node) {
 
205
    local rect, pos, size;
 
206
 
 
207
    pos = node.pos;
 
208
    size = node.size;
 
209
    rect[0] = ['x' = pos.x - size.x / 2; 'y' = pos.y - size.y / 2;];
 
210
    rect[1] = ['x' = rect[0].x + size.x; 'y' = rect[0].y + size.y;];
 
211
    if (node.attr.style == 'filled') {
 
212
        box (canvas, node, rect, ['color' = node.color; 'fill' = 'on';]);
 
213
        box (canvas, node, rect, ['color' = dotty.outlinecolor;]);
 
214
    }
 
215
    gt.shapefunc.rfields (gt, canvas, node, node.fields);
 
216
    setpick (canvas, node, rect);
 
217
};
 
218
dotty.protogt.shapefunc.rfields = function (gt, canvas, node, fields) {
 
219
    local fid, field, pos, label;
 
220
 
 
221
    for (fid in fields) {
 
222
        field = fields[fid];
 
223
        if (field.fields)
 
224
            gt.shapefunc.rfields (gt, canvas, node, field.fields);
 
225
        else {
 
226
            if (node.attr.style == 'filled')
 
227
                box (canvas, null, field.rect, ['color' = dotty.outlinecolor;]);
 
228
            else
 
229
                box (canvas, null, field.rect, ['color' = node.color;]);
 
230
            pos.x = (field.rect[1].x + field.rect[0].x) / 2;
 
231
            pos.y = (field.rect[1].y + field.rect[0].y) / 2;
 
232
            if (~(label = field.text) | label == '\N')
 
233
                label = node.name;
 
234
            text (canvas, null, pos, label, node.fontname, node.fontsize,
 
235
                    'cc', ['color' = node.fontcolor;]);
 
236
        }
 
237
    }
 
238
};
 
239
dotty.protogt.shapefunc.plaintext = function (gt, canvas, node) {
 
240
    local pos, size, label, rect;
 
241
 
 
242
    pos = node.pos;
 
243
    size = node.size;
 
244
    if (~(label = node.attr.label) | label == '\N')
 
245
        label = node.name;
 
246
    rect[0] = ['x' = pos.x - size.x / 2; 'y' = pos.y - size.y / 2;];
 
247
    rect[1] = ['x' = rect[0].x + size.x; 'y' = rect[0].y + size.y;];
 
248
    setpick (canvas, node, rect);
 
249
    text (canvas, null, pos, label, node.fontname, node.fontsize,
 
250
            'cc', ['color' = node.fontcolor;]);
 
251
};
 
252
dotty.protogt.shapefunc.box = function (gt, canvas, node) {
 
253
    local pos, size, label, rect;
 
254
 
 
255
    pos = node.pos;
 
256
    size = node.size;
 
257
    if (~(label = node.attr.label) | label == '\N')
 
258
        label = node.name;
 
259
    rect[0] = ['x' = pos.x - size.x / 2; 'y' = pos.y - size.y / 2;];
 
260
    rect[1] = ['x' = rect[0].x + size.x; 'y' = rect[0].y + size.y;];
 
261
    if (node.attr.style == 'filled') {
 
262
        box (canvas, node, rect, ['color' = node.color; 'fill' = 'on';]);
 
263
        box (canvas, node, rect, ['color' = dotty.outlinecolor;]);
 
264
    } else
 
265
        box (canvas, node, rect, ['color' = node.color;]);
 
266
    text (canvas, null, pos, label, node.fontname, node.fontsize,
 
267
            'cc', ['color' = node.fontcolor;]);
 
268
};
 
269
dotty.protogt.shapefunc.Msquare = function (gt, canvas, node) {
 
270
    local pos, size, label, rect, color;
 
271
 
 
272
    pos = node.pos;
 
273
    size = node.size;
 
274
    if (~(label = node.attr.label) | label == '\N')
 
275
        label = node.name;
 
276
    rect[0] = ['x' = pos.x - size.x / 2; 'y' = pos.y - size.y / 2;];
 
277
    rect[1] = ['x' = rect[0].x + size.x; 'y' = rect[0].y + size.y;];
 
278
    if (node.attr.style == 'filled') {
 
279
        box (canvas, node, rect, ['color' = node.color; 'fill' = 'on';]);
 
280
        color = dotty.outlinecolor;
 
281
        box (canvas, node, rect, ['color' = color;]);
 
282
        line (canvas, null, ['x' = rect[0].x; 'y' = rect[0].y + 10;],
 
283
                ['x' = rect[0].x + 10; 'y' = rect[0].y;], ['color' = color;]);
 
284
        line (canvas, null, ['x' = rect[0].x; 'y' = rect[1].y - 10;],
 
285
                ['x' = rect[0].x + 10; 'y' = rect[1].y;], ['color' = color;]);
 
286
        line (canvas, null, ['x' = rect[1].x; 'y' = rect[0].y + 10;],
 
287
                ['x' = rect[1].x - 10; 'y' = rect[0].y;], ['color' = color;]);
 
288
        line (canvas, null, ['x' = rect[1].x; 'y' = rect[1].y - 10;],
 
289
                ['x' = rect[1].x - 10; 'y' = rect[1].y;], ['color' = color;]);
 
290
    } else {
 
291
        color = node.color;
 
292
        box (canvas, node, rect, ['color' = color;]);
 
293
        line (canvas, null, ['x' = rect[0].x; 'y' = rect[0].y + 10;],
 
294
                ['x' = rect[0].x + 10; 'y' = rect[0].y;], ['color' = color;]);
 
295
        line (canvas, null, ['x' = rect[0].x; 'y' = rect[1].y - 10;],
 
296
                ['x' = rect[0].x + 10; 'y' = rect[1].y;], ['color' = color;]);
 
297
        line (canvas, null, ['x' = rect[1].x; 'y' = rect[0].y + 10;],
 
298
                ['x' = rect[1].x - 10; 'y' = rect[0].y;], ['color' = color;]);
 
299
        line (canvas, null, ['x' = rect[1].x; 'y' = rect[1].y - 10;],
 
300
                ['x' = rect[1].x - 10; 'y' = rect[1].y;], ['color' = color;]);
 
301
    }
 
302
    text (canvas, null, pos, label, node.fontname, node.fontsize,
 
303
            'cc', ['color' = node.fontcolor;]);
 
304
};
 
305
dotty.protogt.shapefunc.ellipse = function (gt, canvas, node) {
 
306
    local pos, size, label;
 
307
 
 
308
    pos = node.pos;
 
309
    size.x = node.size.x / 2;
 
310
    size.y = node.size.y / 2;
 
311
    if (~(label = node.attr.label) | label == '\N')
 
312
        label = node.name;
 
313
    if (node.attr.style == 'filled') {
 
314
        if (node.attr.shape == 'doublecircle') {
 
315
            arc (canvas, node, pos, size, ['color' = dotty.outlinecolor;]);
 
316
            size.x = size.x - 4;
 
317
            size.y = size.y - 4;
 
318
        }
 
319
        arc (canvas, node, pos, size, ['color' = node.color; 'fill' = 'on';]);
 
320
        arc (canvas, node, pos, size, ['color' = dotty.outlinecolor;]);
 
321
    } else {
 
322
        if (node.attr.shape == 'doublecircle') {
 
323
            arc (canvas, node, pos, size, ['color' = node.color;]);
 
324
            size.x = size.x - 4;
 
325
            size.y = size.y - 4;
 
326
        }
 
327
        arc (canvas, node, pos, size, ['color' = node.color;]);
 
328
    }
 
329
    text (canvas, null, pos, label, node.fontname, node.fontsize,
 
330
            'cc', ['color' = node.fontcolor;]);
 
331
};
 
332
dotty.protogt.shapefunc.circle = dotty.protogt.shapefunc.ellipse;
 
333
dotty.protogt.shapefunc.doublecircle = dotty.protogt.shapefunc.ellipse;
 
334
dotty.protogt.shapefunc.diamond = function (gt, canvas, node) {
 
335
    local pos, size, label, p, rect;
 
336
 
 
337
    pos = node.pos;
 
338
    size = node.size;
 
339
    if (~(label = node.attr.label) | label == '\N')
 
340
        label = node.name;
 
341
    p[0] = ['x' = pos.x; 'y' = pos.y + size.y / 2;];
 
342
    p[1] = ['x' = pos.x + size.x / 2; 'y' = pos.y;];
 
343
    p[2] = ['x' = pos.x; 'y' = pos.y - size.y / 2;];
 
344
    p[3] = ['x' = pos.x - size.x / 2; 'y' = pos.y;];
 
345
    p[4] = p[0];
 
346
    rect[0] = ['x' = pos.x - size.x / 2; 'y' = pos.y - size.y / 2;];
 
347
    rect[1] = ['x' = rect[0].x + size.x; 'y' = rect[0].y + size.y;];
 
348
    if (node.attr.style == 'filled') {
 
349
        polygon (canvas, node, p, ['color' = node.color; 'fill' = 'on';]);
 
350
        polygon (canvas, node, p, ['color' = dotty.outlinecolor;]);
 
351
    } else
 
352
        polygon (canvas, node, p, ['color' = node.color;]);
 
353
    setpick (canvas, node, rect);
 
354
    text (canvas, null, pos, label, node.fontname, node.fontsize,
 
355
            'cc', ['color' = node.fontcolor;]);
 
356
};
 
357
dotty.protogt.shapefunc.parallelogram = function (gt, canvas, node) {
 
358
    local pos, size, label, rect, color, dx, p;
 
359
 
 
360
    pos = node.pos;
 
361
    size = node.size;
 
362
    if (~(label = node.attr.label) | label == '\N')
 
363
        label = node.name;
 
364
    rect[0] = ['x' = pos.x - size.x / 2; 'y' = pos.y - size.y / 2;];
 
365
    rect[1] = ['x' = rect[0].x + size.x; 'y' = rect[0].y + size.y;];
 
366
    dx = (rect[1].x - rect[0].x) / 5;
 
367
    p[0] = ['x' = rect[0].x; 'y' = rect[0].y;];
 
368
    p[1] = ['x' = rect[1].x - dx; 'y' = rect[0].y;];
 
369
    p[2] = ['x' = rect[1].x; 'y' = rect[1].y;];
 
370
    p[3] = ['x' = rect[0].x + dx; 'y' = rect[1].y;];
 
371
    p[4] = ['x' = rect[0].x; 'y' = rect[0].y;];
 
372
    if (node.attr.style == 'filled') {
 
373
        polygon (canvas, node, p, ['color' = node.color; 'fill' = 'on';]);
 
374
        polygon (canvas, node, p, ['color' = dotty.outlinecolor;]);
 
375
    } else
 
376
        polygon (canvas, node, p, ['color' = node.color;]);
 
377
    setpick (canvas, node, rect);
 
378
    text (canvas, null, pos, label, node.fontname, node.fontsize,
 
379
            'cc', ['color' = node.fontcolor;]);
 
380
};
 
381
dotty.protogt.shapefunc.trapezium = function (gt, canvas, node) {
 
382
    local pos, size, label, rect, color, dx, p;
 
383
 
 
384
    pos = node.pos;
 
385
    size = node.size;
 
386
    if (~(label = node.attr.label) | label == '\N')
 
387
        label = node.name;
 
388
    rect[0] = ['x' = pos.x - size.x / 2; 'y' = pos.y - size.y / 2;];
 
389
    rect[1] = ['x' = rect[0].x + size.x; 'y' = rect[0].y + size.y;];
 
390
    dx = (rect[1].x - rect[0].x) / 5;
 
391
    p[0] = ['x' = rect[0].x; 'y' = rect[0].y;];
 
392
    p[1] = ['x' = rect[1].x; 'y' = rect[0].y;];
 
393
    p[2] = ['x' = rect[1].x - dx; 'y' = rect[1].y;];
 
394
    p[3] = ['x' = rect[0].x + dx; 'y' = rect[1].y;];
 
395
    p[4] = ['x' = rect[0].x; 'y' = rect[0].y;];
 
396
    if (node.attr.style == 'filled') {
 
397
        polygon (canvas, node, p, ['color' = node.color; 'fill' = 'on';]);
 
398
        polygon (canvas, node, p, ['color' = dotty.outlinecolor;]);
 
399
    } else
 
400
        polygon (canvas, node, p, ['color' = node.color;]);
 
401
    setpick (canvas, node, rect);
 
402
    text (canvas, null, pos, label, node.fontname, node.fontsize,
 
403
            'cc', ['color' = node.fontcolor;]);
 
404
};
 
405
dotty.protogt.shapefunc.triangle = function (gt, canvas, node) {
 
406
    local pos, size, label, rect, color, dx, dy, p;
 
407
 
 
408
    pos = node.pos;
 
409
    size = node.size;
 
410
    if (~(label = node.attr.label) | label == '\N')
 
411
        label = node.name;
 
412
    rect[0] = ['x' = pos.x - size.x / 2; 'y' = pos.y - size.y / 2;];
 
413
    rect[1] = ['x' = rect[0].x + size.x; 'y' = rect[0].y + size.y;];
 
414
    if (node.attr.orientation ~= -90) {
 
415
        dx = size.x / 2;
 
416
        dy = size.y / 4;
 
417
        p[0] = ['x' = pos.x - dx; 'y' = pos.y - dy;];
 
418
        p[1] = ['x' = pos.x + dx; 'y' = pos.y - dy;];
 
419
        p[2] = ['x' = pos.x;      'y' = rect[1].y;];
 
420
        p[3] = ['x' = pos.x - dx; 'y' = pos.y - dy;];
 
421
    } else {
 
422
        dx = size.x / 4;
 
423
        dy = size.y / 2;
 
424
        p[0] = ['x' = pos.x - dx; 'y' = pos.y - dy;];
 
425
        p[1] = ['x' = pos.x - dx; 'y' = pos.y + dy;];
 
426
        p[2] = ['x' = pos.x + dx * 2; 'y' = pos.y;];
 
427
        p[3] = ['x' = pos.x - dx; 'y' = pos.y - dy;];
 
428
    }
 
429
    if (node.attr.style == 'filled') {
 
430
        polygon (canvas, node, p, ['color' = node.color; 'fill' = 'on';]);
 
431
        polygon (canvas, node, p, ['color' = dotty.outlinecolor;]);
 
432
    } else
 
433
        polygon (canvas, node, p, ['color' = node.color;]);
 
434
    setpick (canvas, node, rect);
 
435
    text (canvas, null, pos, label, node.fontname, node.fontsize,
 
436
            'cc', ['color' = node.fontcolor;]);
 
437
};
 
438
dotty.protogt.movenode = function (gt, node, pos) {
 
439
    local ppos, eid, edge, p, fp, lp;
 
440
 
 
441
    ppos = copy (node.pos);
 
442
    gt.undrawnode (gt, gt.views, node);
 
443
    node.pos.x = pos.x;
 
444
    node.pos.y = pos.y;
 
445
    if (node.attr.shape == 'record')
 
446
        gt.moverecordfields (gt, node.fields, pos.x - ppos.x, pos.y - ppos.y);
 
447
    for (eid in node.edges) {
 
448
        edge = node.edges[eid];
 
449
        if (~edge.dir & edge.head ~= edge.tail) {
 
450
            p = edge.tail.pos;
 
451
            fp = edge.points[0];
 
452
            lp = edge.points[tablesize (edge.points)  - 1];
 
453
            if (((p.x - fp.x) * (p.x - fp.x) + (p.y - fp.y) * (p.y - fp.y)) <
 
454
                    ((p.x - lp.x) * (p.x - lp.x) + (p.y - lp.y) * (p.y - lp.y)))
 
455
                edge.dir = 1;
 
456
            else
 
457
                edge.dir = -1;
 
458
        }
 
459
        gt.moveedge (gt, edge, node, ppos, pos);
 
460
    }
 
461
    gt.drawnode (gt, gt.views, node);
 
462
};
 
463
dotty.protogt.moverecordfields = function (gt, fields, dx, dy) {
 
464
    local fid, field;
 
465
 
 
466
    for (fid in fields) {
 
467
        field = fields[fid];
 
468
        if (field.fields)
 
469
            gt.moverecordfields (gt, field.fields, dx, dy);
 
470
        else {
 
471
            field.rect[0].x = field.rect[0].x + dx;
 
472
            field.rect[0].y = field.rect[0].y + dy;
 
473
            field.rect[1].x = field.rect[1].x + dx;
 
474
            field.rect[1].y = field.rect[1].y + dy;
 
475
        }
 
476
    }
 
477
};
 
478
dotty.protogt.drawedge = function (gt, views, edge) {
 
479
    local vid, canvas;
 
480
 
 
481
    edge.drawn = 1;
 
482
    if (~edge.points)
 
483
        return;
 
484
    if (edge.attr.style == 'invis') {
 
485
        if (gt.edgehandles == 0)
 
486
            return;
 
487
        for (vid in views) {
 
488
            arc (views[vid].canvas, edge, [
 
489
                'x' = (edge.points[1].x + edge.points[2].x) / 2;
 
490
                'y' = (edge.points[1].y + edge.points[2].y) / 2;
 
491
            ], ['x' = 5; 'y' = 5;], ['color' = 1;]);
 
492
        }
 
493
        return;
 
494
    }
 
495
    for (vid in views) {
 
496
        canvas = views[vid].canvas;
 
497
        if (edge.attr.style == 'bold')
 
498
            setgfxattr (canvas, ['width' = 3;]);
 
499
        splinegon (canvas, null, edge.points,
 
500
                ['color' = edge.color; 'style' = edge.attr.style;]);
 
501
        if (edge.sp)
 
502
            arrow (canvas, null, edge.points[0],
 
503
                    edge.sp, ['color' = edge.color;]);
 
504
        if (edge.ep)
 
505
            arrow (canvas, null, edge.points[tablesize (edge.points) - 1],
 
506
                    edge.ep, ['color' = edge.color;]);
 
507
        if (edge.attr.style == 'bold')
 
508
            setgfxattr (canvas, ['width' = 0;]);
 
509
        if (edge.lp)
 
510
            text (canvas, null, edge.lp, edge.attr.label, edge.fontname,
 
511
                    edge.fontsize, 'cc', ['color' = edge.fontcolor;]);
 
512
        if (gt.edgehandles == 0)
 
513
            continue;
 
514
        arc (canvas, edge, [
 
515
            'x' = (edge.points[1].x + edge.points[2].x) / 2;
 
516
            'y' = (edge.points[1].y + edge.points[2].y) / 2;
 
517
        ], ['x' = 5; 'y' = 5;], ['color' = 1;]);
 
518
    }
 
519
};
 
520
dotty.protogt.undrawedge = function (gt, views, edge) {
 
521
    local vid, canvas;
 
522
 
 
523
    if (~edge.drawn)
 
524
        return;
 
525
    edge.drawn = 0;
 
526
    if (~edge.points)
 
527
        return;
 
528
    if (edge.attr.style == 'invis') {
 
529
        if (gt.edgehandles == 0)
 
530
            return;
 
531
        for (vid in views) {
 
532
            arc (views[vid].canvas, edge, [
 
533
                'x' = (edge.points[1].x + edge.points[2].x) / 2;
 
534
                'y' = (edge.points[1].y + edge.points[2].y) / 2;
 
535
            ], ['x' = 5; 'y' = 5;], ['color' = 0;]);
 
536
            clearpick (views[vid].canvas, edge);
 
537
        }
 
538
        return;
 
539
    }
 
540
    for (vid in views) {
 
541
        canvas = views[vid].canvas;
 
542
        if (edge.attr.style == 'bold')
 
543
            setgfxattr (canvas, ['width' = 3;]);
 
544
        splinegon (canvas, null, edge.points, ['color' = 0;]);
 
545
        if (edge.sp)
 
546
            arrow (canvas, null, edge.points[0],
 
547
                    edge.sp, ['color' = 0;]);
 
548
        if (edge.ep)
 
549
            arrow (canvas, null, edge.points[tablesize (edge.points) - 1],
 
550
                    edge.ep, ['color' = 0;]);
 
551
        if (edge.attr.style == 'bold')
 
552
            setgfxattr (canvas, ['width' = 0;]);
 
553
        if (edge.lp)
 
554
            text (canvas, null, edge.lp, edge.attr.label, edge.fontname,
 
555
                    edge.fontsize, 'cc', ['color' = 0;]);
 
556
        if (gt.edgehandles == 0)
 
557
            continue;
 
558
        arc (canvas, edge, [
 
559
            'x' = (edge.points[1].x + edge.points[2].x) / 2;
 
560
            'y' = (edge.points[1].y + edge.points[2].y) / 2;
 
561
        ], ['x' = 5; 'y' = 5;], ['color' = 0;]);
 
562
        clearpick (canvas, edge);
 
563
    }
 
564
};
 
565
dotty.protogt.moveedge = function (gt, edge, node, pb, pc) {
 
566
    local dx, dy, tp, hp, pid, p, pa, da, lab, lac, s, ce, se, n, x, y, dir;
 
567
 
 
568
    gt.undrawedge (gt, gt.views, edge);
 
569
    dx = pc.x - pb.x; dy = pc.y - pb.y;
 
570
    tp = edge.sp;
 
571
    hp = edge.ep;
 
572
    if (edge.tail == node) {
 
573
        if (edge.head == node) {
 
574
            for (pid in edge.points) {
 
575
                p = edge.points[pid];
 
576
                p.x = p.x + dx; p.y = p.y + dy;
 
577
            }
 
578
            if (tp) {
 
579
                tp.x = tp.x + dx; tp.y = tp.y + dy;
 
580
            }
 
581
            if (hp) {
 
582
                hp.x = hp.x + dx; hp.y = hp.y + dy;
 
583
            }
 
584
            if (edge.lp) {
 
585
                edge.lp.x = edge.lp.x + dx;
 
586
                edge.lp.y = edge.lp.y + dy;
 
587
            }
 
588
            gt.drawedge (gt, gt.views, edge);
 
589
            return;
 
590
        }
 
591
        pa = edge.head.pos;
 
592
        dir = 1;
 
593
    } else {
 
594
        pa = edge.tail.pos;
 
595
        dir = -1;
 
596
    }
 
597
    dir = edge.dir * dir;
 
598
    da = atan (pc.y - pa.y, pc.x - pa.x) - atan (pb.y - pa.y, pb.x - pa.x);
 
599
    lab = sqrt ((pb.y - pa.y) * (pb.y - pa.y) +
 
600
            (pb.x - pa.x) * (pb.x - pa.x));
 
601
    lac = sqrt ((pc.y - pa.y) * (pc.y - pa.y) +
 
602
            (pc.x - pa.x) * (pc.x - pa.x));
 
603
    s = lac / lab;
 
604
    ce = cos (da);
 
605
    se = sin (da);
 
606
    n = tablesize (edge.points);
 
607
    for (pid = 1; pid < n - 1; pid = pid + 1) {
 
608
        p = edge.points[pid];
 
609
        x = p.x - pa.x;
 
610
        y = p.y - pa.y;
 
611
        p.x = pa.x + (ce * x - se * y) * s;
 
612
        p.y = pa.y + (se * x + ce * y) * s;
 
613
    }
 
614
    if (dir == 1) {
 
615
        p = edge.points[0];
 
616
        p.x = p.x + dx; p.y = p.y + dy;
 
617
        if (tp) {
 
618
            tp.x = tp.x + dx; tp.y = tp.y + dy;
 
619
        }
 
620
    } else {
 
621
        p = edge.points[n - 1];
 
622
        p.x = p.x + dx; p.y = p.y + dy;
 
623
        if (hp) {
 
624
            hp.x = hp.x + dx; hp.y = hp.y + dy;
 
625
        }
 
626
    }
 
627
    if (edge.lp) {
 
628
        x = edge.lp.x - pa.x;
 
629
        y = edge.lp.y - pa.y;
 
630
        edge.lp.x = pa.x + (ce * x - se * y) * s;
 
631
        edge.lp.y = pa.y + (se * x + ce * y) * s;
 
632
    }
 
633
    gt.drawedge (gt, gt.views, edge);
 
634
};
 
635
dotty.protogt.getcolor = function (views, name) {
 
636
    local vid, vt, color, t;
 
637
 
 
638
    for (vid in views) {
 
639
        vt = views[vid];
 
640
        if (~(color >= 0)) {
 
641
            if (~(vt.colors[name] >= 0))
 
642
                color = (vt.colors[name] = vt.colorn);
 
643
            else {
 
644
                color = vt.colors[name];
 
645
                break;
 
646
            }
 
647
        } else if (~(vt.colors[name] >= 0))
 
648
            vt.colors[name] = color;
 
649
        else if (vt.colors[name] ~= color)
 
650
            dotty.message (0, concat ('inconsistent color ids for ', name));
 
651
        if (setwidgetattr (vt.canvas, ['color' = [color = name;];]) ~= 1) {
 
652
            t = split (name, ' ');
 
653
            if (tablesize (t) ~= 3 |
 
654
                    setwidgetattr (vt.canvas, ['color' = [color = [
 
655
                        'h' = ston (t[0]); 's' = ston (t[1]); 'v' = ston (t[2]);
 
656
                    ];];]) ~= 1) {
 
657
                dotty.message (0, concat ('unknown color ', name, ' using #1'));
 
658
                return 1;
 
659
            }
 
660
        }
 
661
        vt.colorn = color + 1;
 
662
    }
 
663
    return color;
 
664
};
 
665
dotty.protogt.unpacksgraphattr = function (gt, sgraph) {
 
666
    local attr;
 
667
 
 
668
    attr = sgraph.graphattr;
 
669
    if (dotty.fontmap[attr.fontname])
 
670
        sgraph[dotty.keys.fname] = dotty.fontmap[attr.fontname];
 
671
    else
 
672
        sgraph[dotty.keys.fname] = attr.fontname;
 
673
    sgraph[dotty.keys.fsize] = ston (attr.fontsize);
 
674
    sgraph[dotty.keys.fcolor] = gt.getcolor (gt.views, attr.fontcolor);
 
675
    if (attr.style == 'filled' & attr.color == 'black')
 
676
        sgraph[dotty.keys.color] = gt.getcolor (gt.views, 'grey');
 
677
    else
 
678
        sgraph[dotty.keys.color] = gt.getcolor (gt.views, attr.color);
 
679
};
 
680
dotty.protogt.unpacknodeattr = function (gt, node) {
 
681
    local attr;
 
682
 
 
683
    attr = node.attr;
 
684
    if (dotty.fontmap[attr.fontname])
 
685
        node[dotty.keys.fname] = dotty.fontmap[attr.fontname];
 
686
    else
 
687
        node[dotty.keys.fname] = attr.fontname;
 
688
    node[dotty.keys.fsize] = ston (attr.fontsize);
 
689
    node[dotty.keys.fcolor] = gt.getcolor (gt.views, attr.fontcolor);
 
690
    if (attr.style == 'filled' & attr.color == 'black')
 
691
        node[dotty.keys.color] = gt.getcolor (gt.views, 'grey');
 
692
    else
 
693
        node[dotty.keys.color] = gt.getcolor (gt.views, attr.color);
 
694
};
 
695
dotty.protogt.unpackedgeattr = function (gt, edge) {
 
696
    local attr, n;
 
697
 
 
698
    attr = edge.attr;
 
699
    if (dotty.fontmap[attr.fontname])
 
700
        edge[dotty.keys.fname] = dotty.fontmap[attr.fontname];
 
701
    else
 
702
        edge[dotty.keys.fname] = attr.fontname;
 
703
    edge[dotty.keys.fsize] = ston (attr.fontsize);
 
704
    edge[dotty.keys.fcolor] = gt.getcolor (gt.views, attr.fontcolor);
 
705
    if (attr.style == 'filled' & attr.color == 'black')
 
706
        edge[dotty.keys.color] = gt.getcolor (gt.views, 'grey');
 
707
    else
 
708
        edge[dotty.keys.color] = gt.getcolor (gt.views, attr.color);
 
709
    if (attr.label & attr.label ~= '' & ~edge.lp & edge.points) {
 
710
        if ((n = tablesize (edge.points)) > 4)
 
711
            edge.lp = [
 
712
                'x' = edge.points[toint (n / 2)].x + 5;
 
713
                'y' = edge.points[toint (n / 2)].y + 5;
 
714
            ];
 
715
        else
 
716
            edge.lp = [
 
717
                'x' = (edge.points[1].x + edge.points[2].x) / 2 + 5;
 
718
                'y' = (edge.points[1].y + edge.points[2].y) / 2 + 5;
 
719
            ];
 
720
    }
 
721
};
 
722
dotty.protogt.unpackattr = function (gt) {
 
723
    local gid, sgraph, nid, node, eid, edge, graph, attr;
 
724
 
 
725
    graph = gt.graph;
 
726
    attr = graph.graphattr;
 
727
    if (dotty.fontmap[attr.fontname])
 
728
        graph[dotty.keys.fname] = dotty.fontmap[attr.fontname];
 
729
    else
 
730
        graph[dotty.keys.fname] = attr.fontname;
 
731
    graph[dotty.keys.fsize] = ston (attr.fontsize);
 
732
    graph[dotty.keys.fcolor] = gt.getcolor (gt.views, attr.fontcolor);
 
733
    if (attr.style == 'filled' & attr.color == 'black')
 
734
        graph[dotty.keys.color] = gt.getcolor (gt.views, 'grey');
 
735
    else
 
736
        graph[dotty.keys.color] = gt.getcolor (gt.views, attr.color);
 
737
 
 
738
#  Does this work?  Want to save/restore parent filename in graph specification
 
739
    graph[dotty.keys.parent] = attr.parent;
 
740
    for (gid in graph.graphdict) {
 
741
        sgraph = graph.graphs[graph.graphdict[gid]];
 
742
        attr = sgraph.graphattr;
 
743
        if (dotty.fontmap[attr.fontname])
 
744
            sgraph[dotty.keys.fname] = dotty.fontmap[attr.fontname];
 
745
        else
 
746
            sgraph[dotty.keys.fname] = attr.fontname;
 
747
        sgraph[dotty.keys.fsize] = ston (attr.fontsize);
 
748
        sgraph[dotty.keys.fcolor] = gt.getcolor (gt.views, attr.fontcolor);
 
749
        if (attr.style == 'filled' & attr.color == 'black')
 
750
            sgraph[dotty.keys.color] = gt.getcolor (gt.views, 'grey');
 
751
        else
 
752
            sgraph[dotty.keys.color] = gt.getcolor (gt.views, attr.color);
 
753
    }
 
754
    for (nid in graph.nodedict) {
 
755
        node = graph.nodes[graph.nodedict[nid]];
 
756
        attr = node.attr;
 
757
        if (dotty.fontmap[attr.fontname])
 
758
            node[dotty.keys.fname] = dotty.fontmap[attr.fontname];
 
759
        else
 
760
            node[dotty.keys.fname] = attr.fontname;
 
761
        node[dotty.keys.fsize] = ston (attr.fontsize);
 
762
        node[dotty.keys.fcolor] = gt.getcolor (gt.views, attr.fontcolor);
 
763
        if (attr.style == 'filled' & attr.color == 'black')
 
764
            node[dotty.keys.color] = gt.getcolor (gt.views, 'grey');
 
765
        else
 
766
            node[dotty.keys.color] = gt.getcolor (gt.views, attr.color);
 
767
    }
 
768
    for (eid in graph.edges) {
 
769
        edge = graph.edges[eid];
 
770
        attr = edge.attr;
 
771
        if (dotty.fontmap[attr.fontname])
 
772
            edge[dotty.keys.fname] = dotty.fontmap[attr.fontname];
 
773
        else
 
774
            edge[dotty.keys.fname] = attr.fontname;
 
775
        edge[dotty.keys.fsize] = ston (attr.fontsize);
 
776
        edge[dotty.keys.fcolor] = gt.getcolor (gt.views, attr.fontcolor);
 
777
        edge[dotty.keys.color] = gt.getcolor (gt.views, attr.color);
 
778
    }
 
779
};