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