Graphviz  2.31.20130522.0446
plugin/core/gvrender_core_tk.c
Go to the documentation of this file.
00001 /* $Id$ $Revision$ */
00002 /* vim:set shiftwidth=4 ts=8: */
00003 
00004 /*************************************************************************
00005  * Copyright (c) 2011 AT&T Intellectual Property 
00006  * All rights reserved. This program and the accompanying materials
00007  * are made available under the terms of the Eclipse Public License v1.0
00008  * which accompanies this distribution, and is available at
00009  * http://www.eclipse.org/legal/epl-v10.html
00010  *
00011  * Contributors: See CVS logs. Details at http://www.graphviz.org/
00012  *************************************************************************/
00013 
00014 #ifdef HAVE_CONFIG_H
00015 #include "config.h"
00016 #endif
00017 
00018 #include <stdarg.h>
00019 #include <stdlib.h>
00020 #include <string.h>
00021 
00022 #include "macros.h"
00023 #include "const.h"
00024 
00025 #include "gvplugin_render.h"
00026 #include "gvplugin_device.h"
00027 #include "gvio.h"
00028 #include "gvcint.h"
00029 
00030 typedef enum { FORMAT_TK, } format_type;
00031 
00032 static char *tkgen_string(char *s)
00033 {
00034     return s;
00035 }
00036 
00037 static void tkgen_print_color(GVJ_t * job, gvcolor_t color)
00038 {
00039     switch (color.type) {
00040     case COLOR_STRING:
00041         gvputs(job, color.u.string);
00042         break;
00043     case RGBA_BYTE:
00044         if (color.u.rgba[3] == 0) /* transparent */
00045             gvputs(job, "\"\"");
00046         else
00047             gvprintf(job, "#%02x%02x%02x",
00048                 color.u.rgba[0], color.u.rgba[1], color.u.rgba[2]);
00049         break;
00050     default:
00051         assert(0);              /* internal error */
00052     }
00053 }
00054 
00055 static void tkgen_print_tags(GVJ_t *job)
00056 {
00057     char *ObjType, *ObjPart;
00058     unsigned int ObjId;
00059     obj_state_t *obj = job->obj;
00060     int ObjFlag;
00061 #ifndef WITH_CGRAPH
00062     int ObjHandle;
00063 #endif
00064 
00065     switch (obj->emit_state) {
00066     case EMIT_NDRAW:
00067         ObjType = "node";
00068         ObjPart = "shape";
00069         ObjFlag = 1;
00070         ObjId = AGSEQ(obj->u.n);
00071 #ifndef WITH_CGRAPH
00072         ObjHandle = obj->u.n->handle;
00073 #endif
00074         break;
00075     case EMIT_NLABEL:
00076         ObjType = "node";
00077         ObjPart = "label";
00078         ObjFlag = 0;
00079         ObjId = AGSEQ(obj->u.n);
00080 #ifndef WITH_CGRAPH
00081         ObjHandle = obj->u.n->handle;
00082 #endif
00083         break;
00084     case EMIT_EDRAW:
00085     case EMIT_TDRAW:
00086     case EMIT_HDRAW:
00087         ObjType = "edge";
00088         ObjPart = "shape";
00089         ObjFlag = 1;
00090         ObjId = AGSEQ(obj->u.e);
00091 #ifndef WITH_CGRAPH
00092         ObjHandle = obj->u.e->handle;
00093 #endif
00094         break;
00095     case EMIT_ELABEL:
00096     case EMIT_TLABEL:
00097     case EMIT_HLABEL:
00098         ObjType = "edge";
00099         ObjPart = "label";
00100         ObjFlag = 0;
00101         ObjId = AGSEQ(obj->u.e);
00102 #ifndef WITH_CGRAPH
00103         ObjHandle = obj->u.e->handle;
00104 #endif
00105         break;
00106     case EMIT_GDRAW:
00107         ObjType = "graph";
00108         ObjPart = "shape";
00109         ObjFlag = 1;
00110         ObjId = -1;  /* hack! */
00111 #ifndef WITH_CGRAPH
00112         ObjHandle = obj->u.g->handle;
00113 #endif
00114         break;
00115     case EMIT_GLABEL:
00116         ObjType = "graph";
00117         ObjPart = "label";
00118         ObjFlag = 0;
00119         ObjType = "graph label";
00120         ObjId = -1;  /* hack! */
00121 #ifndef WITH_CGRAPH
00122         ObjHandle = obj->u.g->handle;
00123 #endif
00124         break;
00125     case EMIT_CDRAW:
00126         ObjType = "graph";
00127         ObjPart = "shape";
00128         ObjFlag = 1;
00129 #ifndef WITH_CGRAPH
00130         ObjId = obj->u.sg->meta_node->id;
00131         ObjHandle = obj->u.sg->handle;
00132 #else
00133         ObjId = AGSEQ(obj->u.sg);
00134 #endif
00135         break;
00136     case EMIT_CLABEL:
00137         ObjType = "graph";
00138         ObjPart = "label";
00139         ObjFlag = 0;
00140 #ifndef WITH_CGRAPH
00141         ObjId = obj->u.sg->meta_node->id;
00142         ObjHandle = obj->u.sg->handle;
00143 #else
00144         ObjId = AGSEQ(obj->u.sg);
00145 #endif
00146         break;
00147     default:
00148         assert (0);
00149         break;
00150     }
00151 #ifndef WITH_CGRAPH
00152     gvprintf(job, " -tags {%d%s%d}", ObjFlag, ObjType, ObjHandle);
00153 #else
00154     gvprintf(job, " -tags {%d%s%d}", ObjFlag, ObjType, ObjId);
00155 #endif
00156 }
00157 
00158 static void tkgen_canvas(GVJ_t * job)
00159 {
00160    if (job->external_context) 
00161         gvputs(job, job->imagedata);
00162    else
00163         gvputs(job, "$c");
00164 }
00165 
00166 static void tkgen_comment(GVJ_t * job, char *str)
00167 {
00168     gvputs(job, "# ");
00169     gvputs(job, tkgen_string(str));
00170     gvputs(job, "\n");
00171 }
00172 
00173 static void tkgen_begin_job(GVJ_t * job)
00174 {
00175     gvputs(job, "# Generated by ");
00176     gvputs(job, tkgen_string(job->common->info[0]));
00177     gvputs(job, " version ");
00178     gvputs(job, tkgen_string(job->common->info[1]));
00179     gvputs(job, " (");
00180     gvputs(job, tkgen_string(job->common->info[2]));
00181     gvputs(job, ")\n");
00182 }
00183 
00184 static void tkgen_begin_graph(GVJ_t * job)
00185 {
00186     obj_state_t *obj = job->obj;
00187 
00188     gvputs(job, "#");
00189     if (agnameof(obj->u.g)[0]) {
00190         gvputs(job, " Title: ");
00191         gvputs(job, tkgen_string(agnameof(obj->u.g)));
00192     }
00193     gvprintf(job, " Pages: %d\n", job->pagesArraySize.x * job->pagesArraySize.y);
00194 }
00195 
00196 static int first_periphery;
00197 
00198 static void tkgen_begin_node(GVJ_t * job)
00199 {
00200         first_periphery = 1;     /* FIXME - this is an ugly hack! */
00201 }
00202 
00203 static void tkgen_begin_edge(GVJ_t * job)
00204 {
00205         first_periphery = -1;     /* FIXME - this is an ugly ugly hack!  Need this one for arrowheads. */
00206 }
00207 
00208 static void tkgen_textpara(GVJ_t * job, pointf p, textpara_t * para)
00209 {
00210     obj_state_t *obj = job->obj;
00211     const char *font;
00212     int size;
00213 
00214     if (obj->pen != PEN_NONE) {
00215         /* determine font size */
00216         /* round fontsize down, better too small than too big */
00217         size = (int)(para->fontsize * job->zoom);
00218         /* don't even bother if fontsize < 1 point */
00219         if (size)  {
00220             tkgen_canvas(job);
00221             gvputs(job, " create text ");
00222             p.y -= size * 0.55; /* cl correction */
00223             gvprintpointf(job, p);
00224             gvputs(job, " -text {");
00225             gvputs(job, para->str);
00226             gvputs(job, "}");
00227             gvputs(job, " -fill ");
00228             tkgen_print_color(job, obj->pencolor);
00229             gvputs(job, " -font {");
00230             /* tk doesn't like PostScript font names like "Times-Roman" */
00231             /*    so use family names */
00232             if (para->postscript_alias)
00233                 font = para->postscript_alias->family;
00234             else
00235                 font = para->fontname;
00236             gvputs(job, "\"");
00237             gvputs(job, font);
00238             gvputs(job, "\"");
00239             /* use -ve fontsize to indicate pixels  - see "man n font" */
00240             gvprintf(job, " %d}", size);
00241             switch (para->just) {
00242             case 'l':
00243                 gvputs(job, " -anchor w");
00244                 break;
00245             case 'r':
00246                 gvputs(job, " -anchor e");
00247                 break;
00248             default:
00249             case 'n':
00250                 break;
00251             }
00252             tkgen_print_tags(job);
00253             gvputs(job, "\n");
00254         }
00255     }
00256 }
00257 
00258 static void tkgen_ellipse(GVJ_t * job, pointf * A, int filled)
00259 {
00260     obj_state_t *obj = job->obj;
00261     pointf r;
00262 
00263     if (obj->pen != PEN_NONE) {
00264     /* A[] contains 2 points: the center and top right corner. */
00265         r.x = A[1].x - A[0].x;
00266         r.y = A[1].y - A[0].y;
00267         A[0].x -= r.x;
00268         A[0].y -= r.y;
00269         tkgen_canvas(job);
00270         gvputs(job, " create oval ");
00271         gvprintpointflist(job, A, 2);
00272         gvputs(job, " -fill ");
00273         if (filled)
00274             tkgen_print_color(job, obj->fillcolor);
00275         else if (first_periphery)
00276             /* tk ovals default to no fill, some fill
00277              * is necessary else "canvas find overlapping" doesn't
00278              * work as expected, use white instead */
00279             gvputs(job, "white");
00280         else 
00281             gvputs(job, "\"\"");
00282         if (first_periphery == 1)
00283             first_periphery = 0;
00284         gvputs(job, " -width ");
00285         gvprintdouble(job, obj->penwidth);
00286         gvputs(job, " -outline ");
00287         tkgen_print_color(job, obj->pencolor);
00288         if (obj->pen == PEN_DASHED)
00289             gvputs(job, " -dash 5");
00290         if (obj->pen == PEN_DOTTED)
00291             gvputs(job, " -dash 2");
00292         tkgen_print_tags(job);
00293         gvputs(job, "\n");
00294     }
00295 }
00296 
00297 static void
00298 tkgen_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
00299               int arrow_at_end, int filled)
00300 {
00301     obj_state_t *obj = job->obj;
00302 
00303     if (obj->pen != PEN_NONE) {
00304         tkgen_canvas(job);
00305         gvputs(job, " create line ");
00306         gvprintpointflist(job, A, n);
00307         gvputs(job, " -fill ");
00308         tkgen_print_color(job, obj->pencolor);
00309         gvputs(job, " -width ");
00310         gvprintdouble(job, obj->penwidth);
00311         if (obj->pen == PEN_DASHED)
00312             gvputs(job, " -dash 5");
00313         if (obj->pen == PEN_DOTTED)
00314             gvputs(job, " -dash 2");
00315         gvputs(job, " -smooth bezier ");
00316         tkgen_print_tags(job);
00317         gvputs(job, "\n");
00318     }
00319 }
00320 
00321 static void tkgen_polygon(GVJ_t * job, pointf * A, int n, int filled)
00322 {
00323     obj_state_t *obj = job->obj;
00324 
00325     if (obj->pen != PEN_NONE) {
00326         tkgen_canvas(job);
00327         gvputs(job, " create polygon ");
00328         gvprintpointflist(job, A, n);
00329         gvputs(job, " -fill ");
00330         if (filled)
00331             tkgen_print_color(job, obj->fillcolor);
00332         else if (first_periphery)
00333             /* tk polygons default to black fill, some fill
00334              * is necessary else "canvas find overlapping" doesn't
00335              * work as expected, use white instead */
00336             gvputs(job, "white");
00337         else
00338             gvputs(job, "\"\"");
00339         if (first_periphery == 1) 
00340             first_periphery = 0;
00341         gvputs(job, " -width ");
00342         gvprintdouble(job, obj->penwidth);
00343         gvputs(job, " -outline ");
00344         tkgen_print_color(job, obj->pencolor);
00345         if (obj->pen == PEN_DASHED)
00346             gvputs(job, " -dash 5");
00347         if (obj->pen == PEN_DOTTED)
00348             gvputs(job, " -dash 2");
00349         tkgen_print_tags(job);
00350         gvputs(job, "\n");
00351     }
00352 }
00353 
00354 static void tkgen_polyline(GVJ_t * job, pointf * A, int n)
00355 {
00356     obj_state_t *obj = job->obj;
00357 
00358     if (obj->pen != PEN_NONE) {
00359         tkgen_canvas(job);
00360         gvputs(job, " create line ");
00361         gvprintpointflist(job, A, n);
00362         gvputs(job, " -fill ");
00363         tkgen_print_color(job, obj->pencolor);
00364         if (obj->pen == PEN_DASHED)
00365             gvputs(job, " -dash 5");
00366         if (obj->pen == PEN_DOTTED)
00367             gvputs(job, " -dash 2");
00368         tkgen_print_tags(job);
00369         gvputs(job, "\n");
00370     }
00371 }
00372 
00373 gvrender_engine_t tkgen_engine = {
00374     tkgen_begin_job,
00375     0,                          /* tkgen_end_job */
00376     tkgen_begin_graph,
00377     0,                          /* tkgen_end_graph */
00378     0,                          /* tkgen_begin_layer */
00379     0,                          /* tkgen_end_layer */
00380     0,                          /* tkgen_begin_page */
00381     0,                          /* tkgen_end_page */
00382     0,                          /* tkgen_begin_cluster */
00383     0,                          /* tkgen_end_cluster */
00384     0,                          /* tkgen_begin_nodes */
00385     0,                          /* tkgen_end_nodes */
00386     0,                          /* tkgen_begin_edges */
00387     0,                          /* tkgen_end_edges */
00388     tkgen_begin_node,
00389     0,                          /* tkgen_end_node */
00390     tkgen_begin_edge,
00391     0,                          /* tkgen_end_edge */
00392     0,                          /* tkgen_begin_anchor */
00393     0,                          /* tkgen_end_anchor */
00394     0,                          /* tkgen_begin_label */
00395     0,                          /* tkgen_end_label */
00396     tkgen_textpara,
00397     0,                          /* tkgen_resolve_color */
00398     tkgen_ellipse,
00399     tkgen_polygon,
00400     tkgen_bezier,
00401     tkgen_polyline,
00402     tkgen_comment,
00403     0,                          /* tkgen_library_shape */
00404 };
00405 
00406 gvrender_features_t render_features_tk = {
00407     GVRENDER_Y_GOES_DOWN
00408         | GVRENDER_NO_WHITE_BG, /* flags */
00409     4.,                         /* default pad - graph units */
00410     NULL,                       /* knowncolors */
00411     0,                          /* sizeof knowncolors */
00412     COLOR_STRING,               /* color_type */
00413 };
00414 
00415 gvdevice_features_t device_features_tk = {
00416     0,                          /* flags */
00417     {0.,0.},                    /* default margin - points */
00418     {0.,0.},                    /* default page width, height - points */
00419     {96.,96.},                  /* default dpi */
00420 };
00421 
00422 gvplugin_installed_t gvrender_tk_types[] = {
00423     {FORMAT_TK, "tk", 1, &tkgen_engine, &render_features_tk},
00424     {0, NULL, 0, NULL, NULL}
00425 };
00426 
00427 gvplugin_installed_t gvdevice_tk_types[] = {
00428     {FORMAT_TK, "tk:tk", 1, NULL, &device_features_tk},
00429     {0, NULL, 0, NULL, NULL}
00430 };