Graphviz  2.35.20130930.0449
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  int ObjFlag;
61 #ifndef WITH_CGRAPH
62  int ObjHandle;
63 #endif
64 
65  switch (obj->emit_state) {
66  case EMIT_NDRAW:
67  ObjType = "node";
68  ObjFlag = 1;
69  ObjId = AGSEQ(obj->u.n);
70 #ifndef WITH_CGRAPH
71  ObjHandle = obj->u.n->handle;
72 #endif
73  break;
74  case EMIT_NLABEL:
75  ObjType = "node";
76  ObjFlag = 0;
77  ObjId = AGSEQ(obj->u.n);
78 #ifndef WITH_CGRAPH
79  ObjHandle = obj->u.n->handle;
80 #endif
81  break;
82  case EMIT_EDRAW:
83  case EMIT_TDRAW:
84  case EMIT_HDRAW:
85  ObjType = "edge";
86  ObjFlag = 1;
87  ObjId = AGSEQ(obj->u.e);
88 #ifndef WITH_CGRAPH
89  ObjHandle = obj->u.e->handle;
90 #endif
91  break;
92  case EMIT_ELABEL:
93  case EMIT_TLABEL:
94  case EMIT_HLABEL:
95  ObjType = "edge";
96  ObjFlag = 0;
97  ObjId = AGSEQ(obj->u.e);
98 #ifndef WITH_CGRAPH
99  ObjHandle = obj->u.e->handle;
100 #endif
101  break;
102  case EMIT_GDRAW:
103  ObjType = "graph";
104  ObjFlag = 1;
105  ObjId = -1; /* hack! */
106 #ifndef WITH_CGRAPH
107  ObjHandle = obj->u.g->handle;
108 #endif
109  break;
110  case EMIT_GLABEL:
111  ObjFlag = 0;
112  ObjType = "graph label";
113  ObjId = -1; /* hack! */
114 #ifndef WITH_CGRAPH
115  ObjHandle = obj->u.g->handle;
116 #endif
117  break;
118  case EMIT_CDRAW:
119  ObjType = "graph";
120  ObjFlag = 1;
121 #ifndef WITH_CGRAPH
122  ObjId = obj->u.sg->meta_node->id;
123  ObjHandle = obj->u.sg->handle;
124 #else
125  ObjId = AGSEQ(obj->u.sg);
126 #endif
127  break;
128  case EMIT_CLABEL:
129  ObjType = "graph";
130  ObjFlag = 0;
131 #ifndef WITH_CGRAPH
132  ObjId = obj->u.sg->meta_node->id;
133  ObjHandle = obj->u.sg->handle;
134 #else
135  ObjId = AGSEQ(obj->u.sg);
136 #endif
137  break;
138  default:
139  assert (0);
140  break;
141  }
142 #ifndef WITH_CGRAPH
143  gvprintf(job, " -tags {%d%s%d}", ObjFlag, ObjType, ObjHandle);
144 #else
145  gvprintf(job, " -tags {%d%s%d}", ObjFlag, ObjType, ObjId);
146 #endif
147 }
148 
149 static void tkgen_canvas(GVJ_t * job)
150 {
151  if (job->external_context)
152  gvputs(job, job->imagedata);
153  else
154  gvputs(job, "$c");
155 }
156 
157 static void tkgen_comment(GVJ_t * job, char *str)
158 {
159  gvputs(job, "# ");
160  gvputs(job, tkgen_string(str));
161  gvputs(job, "\n");
162 }
163 
164 static void tkgen_begin_job(GVJ_t * job)
165 {
166  gvputs(job, "# Generated by ");
167  gvputs(job, tkgen_string(job->common->info[0]));
168  gvputs(job, " version ");
169  gvputs(job, tkgen_string(job->common->info[1]));
170  gvputs(job, " (");
171  gvputs(job, tkgen_string(job->common->info[2]));
172  gvputs(job, ")\n");
173 }
174 
175 static void tkgen_begin_graph(GVJ_t * job)
176 {
177  obj_state_t *obj = job->obj;
178 
179  gvputs(job, "#");
180  if (agnameof(obj->u.g)[0]) {
181  gvputs(job, " Title: ");
182  gvputs(job, tkgen_string(agnameof(obj->u.g)));
183  }
184  gvprintf(job, " Pages: %d\n", job->pagesArraySize.x * job->pagesArraySize.y);
185 }
186 
187 static int first_periphery;
188 
189 static void tkgen_begin_node(GVJ_t * job)
190 {
191  first_periphery = 1; /* FIXME - this is an ugly hack! */
192 }
193 
194 static void tkgen_begin_edge(GVJ_t * job)
195 {
196  first_periphery = -1; /* FIXME - this is an ugly ugly hack! Need this one for arrowheads. */
197 }
198 
199 static void tkgen_textpara(GVJ_t * job, pointf p, textpara_t * para)
200 {
201  obj_state_t *obj = job->obj;
202  const char *font;
203  int size;
204 
205  if (obj->pen != PEN_NONE) {
206  /* determine font size */
207  /* round fontsize down, better too small than too big */
208  size = (int)(para->fontsize * job->zoom);
209  /* don't even bother if fontsize < 1 point */
210  if (size) {
211  tkgen_canvas(job);
212  gvputs(job, " create text ");
213  p.y -= size * 0.55; /* cl correction */
214  gvprintpointf(job, p);
215  gvputs(job, " -text {");
216  gvputs(job, para->str);
217  gvputs(job, "}");
218  gvputs(job, " -fill ");
219  tkgen_print_color(job, obj->pencolor);
220  gvputs(job, " -font {");
221  /* tk doesn't like PostScript font names like "Times-Roman" */
222  /* so use family names */
223  if (para->postscript_alias)
224  font = para->postscript_alias->family;
225  else
226  font = para->fontname;
227  gvputs(job, "\"");
228  gvputs(job, font);
229  gvputs(job, "\"");
230  /* use -ve fontsize to indicate pixels - see "man n font" */
231  gvprintf(job, " %d}", size);
232  switch (para->just) {
233  case 'l':
234  gvputs(job, " -anchor w");
235  break;
236  case 'r':
237  gvputs(job, " -anchor e");
238  break;
239  default:
240  case 'n':
241  break;
242  }
243  tkgen_print_tags(job);
244  gvputs(job, "\n");
245  }
246  }
247 }
248 
249 static void tkgen_ellipse(GVJ_t * job, pointf * A, int filled)
250 {
251  obj_state_t *obj = job->obj;
252  pointf r;
253 
254  if (obj->pen != PEN_NONE) {
255  /* A[] contains 2 points: the center and top right corner. */
256  r.x = A[1].x - A[0].x;
257  r.y = A[1].y - A[0].y;
258  A[0].x -= r.x;
259  A[0].y -= r.y;
260  tkgen_canvas(job);
261  gvputs(job, " create oval ");
262  gvprintpointflist(job, A, 2);
263  gvputs(job, " -fill ");
264  if (filled)
265  tkgen_print_color(job, obj->fillcolor);
266  else if (first_periphery)
267  /* tk ovals default to no fill, some fill
268  * is necessary else "canvas find overlapping" doesn't
269  * work as expected, use white instead */
270  gvputs(job, "white");
271  else
272  gvputs(job, "\"\"");
273  if (first_periphery == 1)
274  first_periphery = 0;
275  gvputs(job, " -width ");
276  gvprintdouble(job, obj->penwidth);
277  gvputs(job, " -outline ");
278  tkgen_print_color(job, obj->pencolor);
279  if (obj->pen == PEN_DASHED)
280  gvputs(job, " -dash 5");
281  if (obj->pen == PEN_DOTTED)
282  gvputs(job, " -dash 2");
283  tkgen_print_tags(job);
284  gvputs(job, "\n");
285  }
286 }
287 
288 static void
289 tkgen_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
290  int arrow_at_end, int filled)
291 {
292  obj_state_t *obj = job->obj;
293 
294  if (obj->pen != PEN_NONE) {
295  tkgen_canvas(job);
296  gvputs(job, " create line ");
297  gvprintpointflist(job, A, n);
298  gvputs(job, " -fill ");
299  tkgen_print_color(job, obj->pencolor);
300  gvputs(job, " -width ");
301  gvprintdouble(job, obj->penwidth);
302  if (obj->pen == PEN_DASHED)
303  gvputs(job, " -dash 5");
304  if (obj->pen == PEN_DOTTED)
305  gvputs(job, " -dash 2");
306  gvputs(job, " -smooth bezier ");
307  tkgen_print_tags(job);
308  gvputs(job, "\n");
309  }
310 }
311 
312 static void tkgen_polygon(GVJ_t * job, pointf * A, int n, int filled)
313 {
314  obj_state_t *obj = job->obj;
315 
316  if (obj->pen != PEN_NONE) {
317  tkgen_canvas(job);
318  gvputs(job, " create polygon ");
319  gvprintpointflist(job, A, n);
320  gvputs(job, " -fill ");
321  if (filled)
322  tkgen_print_color(job, obj->fillcolor);
323  else if (first_periphery)
324  /* tk polygons default to black fill, some fill
325  * is necessary else "canvas find overlapping" doesn't
326  * work as expected, use white instead */
327  gvputs(job, "white");
328  else
329  gvputs(job, "\"\"");
330  if (first_periphery == 1)
331  first_periphery = 0;
332  gvputs(job, " -width ");
333  gvprintdouble(job, obj->penwidth);
334  gvputs(job, " -outline ");
335  tkgen_print_color(job, obj->pencolor);
336  if (obj->pen == PEN_DASHED)
337  gvputs(job, " -dash 5");
338  if (obj->pen == PEN_DOTTED)
339  gvputs(job, " -dash 2");
340  tkgen_print_tags(job);
341  gvputs(job, "\n");
342  }
343 }
344 
345 static void tkgen_polyline(GVJ_t * job, pointf * A, int n)
346 {
347  obj_state_t *obj = job->obj;
348 
349  if (obj->pen != PEN_NONE) {
350  tkgen_canvas(job);
351  gvputs(job, " create line ");
352  gvprintpointflist(job, A, n);
353  gvputs(job, " -fill ");
354  tkgen_print_color(job, obj->pencolor);
355  if (obj->pen == PEN_DASHED)
356  gvputs(job, " -dash 5");
357  if (obj->pen == PEN_DOTTED)
358  gvputs(job, " -dash 2");
359  tkgen_print_tags(job);
360  gvputs(job, "\n");
361  }
362 }
363 
365  tkgen_begin_job,
366  0, /* tkgen_end_job */
367  tkgen_begin_graph,
368  0, /* tkgen_end_graph */
369  0, /* tkgen_begin_layer */
370  0, /* tkgen_end_layer */
371  0, /* tkgen_begin_page */
372  0, /* tkgen_end_page */
373  0, /* tkgen_begin_cluster */
374  0, /* tkgen_end_cluster */
375  0, /* tkgen_begin_nodes */
376  0, /* tkgen_end_nodes */
377  0, /* tkgen_begin_edges */
378  0, /* tkgen_end_edges */
379  tkgen_begin_node,
380  0, /* tkgen_end_node */
381  tkgen_begin_edge,
382  0, /* tkgen_end_edge */
383  0, /* tkgen_begin_anchor */
384  0, /* tkgen_end_anchor */
385  0, /* tkgen_begin_label */
386  0, /* tkgen_end_label */
387  tkgen_textpara,
388  0, /* tkgen_resolve_color */
389  tkgen_ellipse,
390  tkgen_polygon,
391  tkgen_bezier,
392  tkgen_polyline,
393  tkgen_comment,
394  0, /* tkgen_library_shape */
395 };
396 
399  | GVRENDER_NO_WHITE_BG, /* flags */
400  4., /* default pad - graph units */
401  NULL, /* knowncolors */
402  0, /* sizeof knowncolors */
403  COLOR_STRING, /* color_type */
404 };
405 
407  0, /* flags */
408  {0.,0.}, /* default margin - points */
409  {0.,0.}, /* default page width, height - points */
410  {96.,96.}, /* default dpi */
411 };
412 
414  {FORMAT_TK, "tk", 1, &tkgen_engine, &render_features_tk},
415  {0, NULL, 0, NULL, NULL}
416 };
417 
419  {FORMAT_TK, "tk:tk", 1, NULL, &device_features_tk},
420  {0, NULL, 0, NULL, NULL}
421 };