Graphviz 16.0.0~dev.20260810.2334
Loading...
Searching...
No Matches
gvrender_core_tk.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include "config.h"
12#include <math.h>
13#include <stdarg.h>
14#include <stdint.h>
15#include <stdlib.h>
16#include <string.h>
17
18#include <common/macros.h>
19#include <common/const.h>
20
21#include <gvc/gvplugin_render.h>
22#include <gvc/gvplugin_device.h>
23#include <gvc/gvio.h>
24#include <gvc/gvcint.h>
25#include <util/unreachable.h>
26#include "tcl_context.h"
27
28enum { FORMAT_TK, };
29
31{
32 switch (color.type) {
33 case COLOR_STRING:
34 gvputs(job, color.u.string);
35 break;
36 case RGBA_BYTE:
37 if (color.u.rgba[3] == 0) /* transparent */
38 gvputs(job, "\"\"");
39 else
40 gvprintf(job, "#%02x%02x%02x",
41 color.u.rgba[0], color.u.rgba[1], color.u.rgba[2]);
42 break;
43 default:
44 UNREACHABLE(); // internal error
45 }
46}
47
48static void tkgen_print_tags(GVJ_t *job)
49{
50 char *ObjType;
51 void *ObjId;
52 obj_state_t *obj = job->obj;
53 int ObjFlag;
54
55 switch (obj->emit_state) {
56 case EMIT_NDRAW:
57 ObjType = "node";
58 ObjFlag = 1;
59 ObjId = &AGTAG(obj->u.n);
60 break;
61 case EMIT_NLABEL:
62 ObjType = "node";
63 ObjFlag = 0;
64 ObjId = &AGTAG(obj->u.n);
65 break;
66 case EMIT_EDRAW:
67 case EMIT_TDRAW:
68 case EMIT_HDRAW:
69 ObjType = "edge";
70 ObjFlag = 1;
71 ObjId = &AGTAG(obj->u.e);
72 break;
73 case EMIT_ELABEL:
74 case EMIT_TLABEL:
75 case EMIT_HLABEL:
76 ObjType = "edge";
77 ObjFlag = 0;
78 ObjId = &AGTAG(obj->u.e);
79 break;
80 case EMIT_GDRAW:
81 ObjType = "graph";
82 ObjFlag = 1;
83 ObjId = &AGTAG(obj->u.g);
84 break;
85 case EMIT_GLABEL:
86 ObjFlag = 0;
87 ObjType = "graph label";
88 ObjId = &AGTAG(obj->u.g);
89 break;
90 case EMIT_CDRAW:
91 ObjType = "graph";
92 ObjFlag = 1;
93 ObjId = &AGTAG(obj->u.sg);
94 break;
95 case EMIT_CLABEL:
96 ObjType = "graph";
97 ObjFlag = 0;
98 ObjId = &AGTAG(obj->u.sg);
99 break;
100 default:
101 UNREACHABLE();
102 }
103 gvprintf(job, " -tags {%d%s%p}", ObjFlag, ObjType, ObjId);
104}
105
106static void tkgen_canvas(GVJ_t * job)
107{
108 if (job->external_context) {
109 tcldot_context_t *context = job->context;
110 gvputs(job, context->canvas);
111 } else
112 gvputs(job, "$c");
113}
114
115static void tkgen_comment(GVJ_t * job, char *str)
116{
117 gvprintf(job, "# %s\n", str);
118}
119
120static void tkgen_begin_job(GVJ_t * job)
121{
122 gvprintf(job, "# Generated by %s version %s (%s)\n", job->common->info[0],
123 job->common->info[1], job->common->info[2]);
124}
125
126// constants stored in `window` to note what we are traversing
127static const uintptr_t WITHIN_NODE = 1;
128static const uintptr_t WITHIN_EDGE = 2;
129
130static void tkgen_begin_graph(GVJ_t * job)
131{
132 obj_state_t *obj = job->obj;
133
134 gvputs(job, "#");
135 if (agnameof(obj->u.g)[0]) {
136 gvprintf(job, " Title: %s", agnameof(obj->u.g));
137 }
138 gvprintf(job, " Pages: %d\n", job->pagesArraySize.x * job->pagesArraySize.y);
139
140 job->window = 0;
141}
142
143static void tkgen_begin_node(GVJ_t * job)
144{
145 job->window = (void *)WITHIN_NODE;
146}
147
148static void tkgen_begin_edge(GVJ_t * job)
149{
150 job->window = (void *)WITHIN_EDGE;
151}
152
153static void tkgen_textspan(GVJ_t * job, pointf p, textspan_t * span)
154{
155 obj_state_t *obj = job->obj;
156 const char *font;
157 PostscriptAlias *pA;
158
159 if (obj->pen != PEN_NONE) {
160 /* determine font size */
161 /* round fontsize down, better too small than too big */
162 const double size = trunc(span->font->size * job->zoom);
163 /* don't even bother if fontsize < 1 point */
164 if (size > 0) {
165 tkgen_canvas(job);
166 gvputs(job, " create text ");
167 p.y -= size * 0.55; /* cl correction */
168 gvprintpointf(job, p);
169 gvprintf(job, " -text {%s} -fill ", span->str);
170 tkgen_print_color(job, obj->pencolor);
171 gvputs(job, " -font {");
172 /* tk doesn't like PostScript font names like "Times-Roman" */
173 /* so use family names */
174 pA = span->font->postscript_alias;
175 if (pA)
176 font = pA->family;
177 else
178 font = span->font->name;
179 gvputs(job, "\"");
180 gvputs(job, font);
181 gvputs(job, "\"");
182 /* use -ve fontsize to indicate pixels - see "man n font" */
183 gvprintf(job, " %.0f}", size);
184 switch (span->just) {
185 case 'l':
186 gvputs(job, " -anchor w");
187 break;
188 case 'r':
189 gvputs(job, " -anchor e");
190 break;
191 default:
192 case 'n':
193 break;
194 }
195 tkgen_print_tags(job);
196 gvputs(job, "\n");
197 }
198 }
199}
200
201static void tkgen_ellipse(GVJ_t * job, pointf * A, int filled)
202{
203 obj_state_t *obj = job->obj;
204 pointf r;
205
206 if (obj->pen != PEN_NONE) {
207 /* A[] contains 2 points: the center and top right corner. */
208 r.x = A[1].x - A[0].x;
209 r.y = A[1].y - A[0].y;
210 A[0].x -= r.x;
211 A[0].y -= r.y;
212 tkgen_canvas(job);
213 gvputs(job, " create oval ");
214 gvprintpointflist(job, A, 2);
215 gvputs(job, " -fill ");
216 if (filled)
217 tkgen_print_color(job, obj->fillcolor);
218 else if ((uintptr_t)job->window == WITHIN_NODE ||
219 (uintptr_t)job->window == WITHIN_EDGE)
220 /* tk ovals default to no fill, some fill
221 * is necessary else "canvas find overlapping" doesn't
222 * work as expected, use white instead */
223 gvputs(job, "white");
224 else
225 gvputs(job, "\"\"");
226 if ((uintptr_t)job->window == WITHIN_NODE)
227 job->window = 0;
228 gvputs(job, " -width ");
229 gvprintdouble(job, obj->penwidth);
230 gvputs(job, " -outline ");
231 tkgen_print_color(job, obj->pencolor);
232 if (obj->pen == PEN_DASHED)
233 gvputs(job, " -dash 5");
234 if (obj->pen == PEN_DOTTED)
235 gvputs(job, " -dash 2");
236 tkgen_print_tags(job);
237 gvputs(job, "\n");
238 }
239}
240
241static void tkgen_bezier(GVJ_t *job, pointf *A, size_t n, int filled) {
242 (void)filled;
243
244 obj_state_t *obj = job->obj;
245
246 if (obj->pen != PEN_NONE) {
247 tkgen_canvas(job);
248 gvputs(job, " create line ");
249 gvprintpointflist(job, A, n);
250 gvputs(job, " -fill ");
251 tkgen_print_color(job, obj->pencolor);
252 gvputs(job, " -width ");
253 gvprintdouble(job, obj->penwidth);
254 if (obj->pen == PEN_DASHED)
255 gvputs(job, " -dash 5");
256 if (obj->pen == PEN_DOTTED)
257 gvputs(job, " -dash 2");
258 gvputs(job, " -smooth bezier ");
259 tkgen_print_tags(job);
260 gvputs(job, "\n");
261 }
262}
263
264static void tkgen_polygon(GVJ_t *job, pointf *A, size_t n, int filled) {
265 obj_state_t *obj = job->obj;
266
267 if (obj->pen != PEN_NONE) {
268 tkgen_canvas(job);
269 gvputs(job, " create polygon ");
270 gvprintpointflist(job, A, n);
271 gvputs(job, " -fill ");
272 if (filled)
273 tkgen_print_color(job, obj->fillcolor);
274 else if ((uintptr_t)job->window == WITHIN_NODE ||
275 (uintptr_t)job->window == WITHIN_EDGE)
276 /* tk polygons default to black fill, some fill
277 * is necessary else "canvas find overlapping" doesn't
278 * work as expected, use white instead */
279 gvputs(job, "white");
280 else
281 gvputs(job, "\"\"");
282 if ((uintptr_t)job->window == WITHIN_NODE)
283 job->window = 0;
284 gvputs(job, " -width ");
285 gvprintdouble(job, obj->penwidth);
286 gvputs(job, " -outline ");
287 tkgen_print_color(job, obj->pencolor);
288 if (obj->pen == PEN_DASHED)
289 gvputs(job, " -dash 5");
290 if (obj->pen == PEN_DOTTED)
291 gvputs(job, " -dash 2");
292 tkgen_print_tags(job);
293 gvputs(job, "\n");
294 }
295}
296
297static void tkgen_polyline(GVJ_t *job, pointf *A, size_t n) {
298 obj_state_t *obj = job->obj;
299
300 if (obj->pen != PEN_NONE) {
301 tkgen_canvas(job);
302 gvputs(job, " create line ");
303 gvprintpointflist(job, A, n);
304 gvputs(job, " -fill ");
305 tkgen_print_color(job, obj->pencolor);
306 if (obj->pen == PEN_DASHED)
307 gvputs(job, " -dash 5");
308 if (obj->pen == PEN_DOTTED)
309 gvputs(job, " -dash 2");
310 tkgen_print_tags(job);
311 gvputs(job, "\n");
312 }
313}
314
317 0, /* tkgen_end_job */
319 0, /* tkgen_end_graph */
320 0, /* tkgen_begin_layer */
321 0, /* tkgen_end_layer */
322 0, /* tkgen_begin_page */
323 0, /* tkgen_end_page */
324 0, /* tkgen_begin_cluster */
325 0, /* tkgen_end_cluster */
326 0, /* tkgen_begin_nodes */
327 0, /* tkgen_end_nodes */
328 0, /* tkgen_begin_edges */
329 0, /* tkgen_end_edges */
331 0, /* tkgen_end_node */
333 0, /* tkgen_end_edge */
334 0, /* tkgen_begin_anchor */
335 0, /* tkgen_end_anchor */
336 0, /* tkgen_begin_label */
337 0, /* tkgen_end_label */
339 0, /* tkgen_resolve_color */
345 0, /* tkgen_library_shape */
346};
347
350 | GVRENDER_NO_WHITE_BG, /* flags */
351 4., /* default pad - graph units */
352 NULL, /* knowncolors */
353 0, /* sizeof knowncolors */
354 COLOR_STRING, /* color_type */
355};
356
358 0, /* flags */
359 {0.,0.}, /* default margin - points */
360 {0.,0.}, /* default page width, height - points */
361 {96.,96.}, /* default dpi */
362};
363
368
370 {FORMAT_TK, "tk:tk", 1, NULL, &device_features_tk},
371 {0, NULL, 0, NULL, NULL}
372};
@ RGBA_BYTE
Definition color.h:26
@ COLOR_STRING
Definition color.h:27
#define A(n, t)
Definition expr.h:76
node NULL
Definition grammar.y:181
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:145
#define AGTAG(obj)
Definition cgraph.h:215
@ PEN_NONE
Definition gvcjob.h:35
@ PEN_DOTTED
Definition gvcjob.h:35
@ PEN_DASHED
Definition gvcjob.h:35
#define GVRENDER_NO_WHITE_BG
Definition gvcjob.h:106
@ EMIT_CDRAW
Definition gvcjob.h:174
@ EMIT_NDRAW
Definition gvcjob.h:176
@ EMIT_TDRAW
Definition gvcjob.h:174
@ EMIT_HDRAW
Definition gvcjob.h:174
@ EMIT_HLABEL
Definition gvcjob.h:175
@ EMIT_GDRAW
Definition gvcjob.h:174
@ EMIT_NLABEL
Definition gvcjob.h:176
@ EMIT_GLABEL
Definition gvcjob.h:175
@ EMIT_ELABEL
Definition gvcjob.h:176
@ EMIT_EDRAW
Definition gvcjob.h:176
@ EMIT_CLABEL
Definition gvcjob.h:175
@ EMIT_TLABEL
Definition gvcjob.h:175
#define GVRENDER_Y_GOES_DOWN
Definition gvcjob.h:94
static void color(Agraph_t *g)
Definition gvcolor.c:118
int gvputs(GVJ_t *job, const char *s)
Definition gvdevice.c:266
void gvprintpointflist(GVJ_t *job, pointf *p, size_t n)
Definition gvdevice.c:544
void gvprintpointf(GVJ_t *job, pointf p)
Definition gvdevice.c:530
void gvprintf(GVJ_t *job, const char *format,...)
Definition gvdevice.c:402
void gvprintdouble(GVJ_t *job, double num)
Definition gvdevice.c:513
static void tkgen_textspan(GVJ_t *job, pointf p, textspan_t *span)
static void tkgen_begin_graph(GVJ_t *job)
gvplugin_installed_t gvdevice_tk_types[]
static void tkgen_comment(GVJ_t *job, char *str)
@ FORMAT_TK
gvplugin_installed_t gvrender_tk_types[]
static void tkgen_begin_edge(GVJ_t *job)
static gvrender_engine_t tkgen_engine
static gvdevice_features_t device_features_tk
static void tkgen_print_color(GVJ_t *job, gvcolor_t color)
static gvrender_features_t render_features_tk
static void tkgen_print_tags(GVJ_t *job)
static const uintptr_t WITHIN_EDGE
static void tkgen_ellipse(GVJ_t *job, pointf *A, int filled)
static void tkgen_bezier(GVJ_t *job, pointf *A, size_t n, int filled)
static void tkgen_polyline(GVJ_t *job, pointf *A, size_t n)
static void tkgen_polygon(GVJ_t *job, pointf *A, size_t n, int filled)
static void tkgen_canvas(GVJ_t *job)
static void tkgen_begin_job(GVJ_t *job)
static const uintptr_t WITHIN_NODE
static void tkgen_begin_node(GVJ_t *job)
textitem scanner parser str
Definition htmlparse.y:218
$2 font
Definition htmlparse.y:294
char ** info
Definition gvcommon.h:20
point pagesArraySize
Definition gvcjob.h:304
obj_state_t * obj
Definition gvcjob.h:269
void * context
Definition gvcjob.h:295
bool external_context
Definition gvcjob.h:296
GVCOMMON_t * common
Definition gvcjob.h:267
double zoom
Definition gvcjob.h:318
void * window
Definition gvcjob.h:353
ingroup plugin_api
Definition gvplugin.h:35
graph_t * g
Definition gvcjob.h:186
edge_t * e
Definition gvcjob.h:189
gvcolor_t fillcolor
Definition gvcjob.h:194
pen_type pen
Definition gvcjob.h:197
node_t * n
Definition gvcjob.h:188
union obj_state_s::@65 u
graph_t * sg
Definition gvcjob.h:187
gvcolor_t pencolor
Definition gvcjob.h:194
emit_state_t emit_state
Definition gvcjob.h:192
double penwidth
Definition gvcjob.h:199
int y
Definition geom.h:27
int x
Definition geom.h:27
double x
Definition geom.h:29
double y
Definition geom.h:29
context used to convey information between commands and a renderer
Definition tcl_context.h:14
const char * canvas
TCL canvas to render to.
Definition tcl_context.h:15
char * name
Definition textspan.h:56
PostscriptAlias * postscript_alias
Definition textspan.h:58
double size
Definition textspan.h:59
char * str
Definition textspan.h:68
char just
'l' 'n' 'r'
Definition textspan.h:74
textfont_t * font
Definition textspan.h:69
data that is shared between the TK renderer and TCL bindings
#define UNREACHABLE()
Definition unreachable.h:30