Fawkes API Fawkes Development Version

gvplugin_skillgui_papyrus.cpp

00001 
00002 /***************************************************************************
00003  *  gvplugin_skillgui_papyrus.cpp - Graphviz plugin for Skill GUI using
00004  *                                  the Cairo-based Papyrus scene graph lib
00005  *
00006  *  Created: Tue Dec 16 14:36:51 2008
00007  *  Copyright  2008-2009  Tim Niemueller [www.niemueller.de]
00008  *
00009  ****************************************************************************/
00010 
00011 /*  This program is free software; you can redistribute it and/or modify
00012  *  it under the terms of the GNU General Public License as published by
00013  *  the Free Software Foundation; either version 2 of the License, or
00014  *  (at your option) any later version.
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL file in the doc directory.
00022  */
00023 
00024 #include "gvplugin_skillgui_papyrus.h"
00025 
00026 #include <utils/math/angle.h>
00027 #include <utils/time/tracker.h>
00028 
00029 #include <gvplugin_device.h>
00030 #include <gvplugin_render.h>
00031 
00032 #include <algorithm>
00033 #include <cstdio>
00034 
00035 #define NOEXPORT __attribute__ ((visibility("hidden")))
00036 
00037 NOEXPORT SkillGuiGraphViewport *__sggvp = NULL;
00038 
00039 NOEXPORT std::valarray<double> __skillgui_render_dashed(6., 1);
00040 NOEXPORT std::valarray<double> __skillgui_render_dotted((double[]){2., 6.}, 2);
00041 
00042 #ifdef USE_GVPLUGIN_TIMETRACKER
00043 NOEXPORT fawkes::TimeTracker __tt;
00044 NOEXPORT unsigned int __ttc_page = __tt.add_class("Page");
00045 NOEXPORT unsigned int __ttc_beginpage = __tt.add_class("Begin Page");
00046 NOEXPORT unsigned int __ttc_ellipse = __tt.add_class("Ellipse");
00047 NOEXPORT unsigned int __ttc_bezier = __tt.add_class("Bezier");
00048 NOEXPORT unsigned int __ttc_polygon = __tt.add_class("Polygon");
00049 NOEXPORT unsigned int __ttc_polyline = __tt.add_class("Polyline");
00050 NOEXPORT unsigned int __ttc_text = __tt.add_class("Text");
00051 NOEXPORT unsigned int __ttc_text_1 = __tt.add_class("Text 1");
00052 NOEXPORT unsigned int __ttc_text_2 = __tt.add_class("Text 2");
00053 NOEXPORT unsigned int __ttc_text_3 = __tt.add_class("Text 3");
00054 NOEXPORT unsigned int __ttc_text_4 = __tt.add_class("Text 4");
00055 NOEXPORT unsigned int __ttc_text_5 = __tt.add_class("Text 5");
00056 NOEXPORT unsigned int __tt_count = 0;
00057 NOEXPORT unsigned int __num_ellipse = 0;
00058 NOEXPORT unsigned int __num_bezier = 0;
00059 NOEXPORT unsigned int __num_polygon = 0;
00060 NOEXPORT unsigned int __num_polyline = 0;
00061 NOEXPORT unsigned int __num_text = 0;
00062 #endif
00063 
00064 static void
00065 skillgui_device_init(GVJ_t *firstjob)
00066 {
00067   Glib::RefPtr<const Gdk::Screen> s = __sggvp->get_screen();
00068   firstjob->device_dpi.x = s->get_resolution();
00069   firstjob->device_dpi.y = s->get_resolution();
00070   firstjob->device_sets_dpi = true;
00071 
00072   Gtk::Allocation alloc      = __sggvp->get_allocation();
00073   firstjob->width            = alloc.get_width();
00074   firstjob->height           = alloc.get_height();
00075 
00076   firstjob->fit_mode = TRUE;
00077 }
00078 
00079 static void
00080 skillgui_device_finalize(GVJ_t *firstjob)
00081 {
00082   __sggvp->set_gvjob(firstjob);
00083 
00084   firstjob->context = (void *)__sggvp;
00085   firstjob->external_context = TRUE;
00086 
00087   // Render!
00088   (firstjob->callbacks->refresh)(firstjob);
00089 }
00090 
00091 
00092 static inline Papyrus::Fill::pointer
00093 skillgui_render_solidpattern(gvcolor_t *color)
00094 {
00095   Cairo::RefPtr< Cairo::SolidPattern > pattern;
00096   pattern = Cairo::SolidPattern::create_rgba(color->u.RGBA[0],
00097                                              color->u.RGBA[1],
00098                                              color->u.RGBA[2],
00099                                              color->u.RGBA[3]);
00100   return Papyrus::Fill::create(pattern);
00101 }
00102 
00103 
00104 static inline Papyrus::Stroke::pointer
00105 skillgui_render_stroke(obj_state_t *obj)
00106 {
00107   Papyrus::Stroke::pointer stroke;
00108 
00109   Cairo::RefPtr< Cairo::SolidPattern > pattern;
00110   pattern = Cairo::SolidPattern::create_rgba(obj->pencolor.u.RGBA[0],
00111                                              obj->pencolor.u.RGBA[1],
00112                                              obj->pencolor.u.RGBA[2],
00113                                              obj->pencolor.u.RGBA[3]);
00114 
00115   stroke = Papyrus::Stroke::create(pattern, obj->penwidth);
00116 
00117   if (obj->pen == PEN_DASHED) {
00118     stroke->set_dash(__skillgui_render_dashed);
00119   } else if (obj->pen == PEN_DOTTED) {
00120     stroke->set_dash(__skillgui_render_dotted);
00121   }
00122 
00123   return stroke;
00124 }
00125 
00126 static void
00127 skillgui_render_begin_page(GVJ_t *job)
00128 {
00129 #ifdef USE_GVPLUGIN_TIMETRACKER
00130   __tt.ping_start(__ttc_page);
00131   __tt.ping_start(__ttc_beginpage);
00132 #endif
00133   SkillGuiGraphViewport *gvp = (SkillGuiGraphViewport *)job->context;
00134   gvp->clear();
00135   Gtk::Allocation alloc = __sggvp->get_allocation();
00136   float bbwidth  = job->bb.UR.x - job->bb.LL.x;
00137   float bbheight = job->bb.UR.y - job->bb.LL.y;
00138   float avwidth  = alloc.get_width();
00139   float avheight = alloc.get_height();
00140   float zoom_w = avwidth  / bbwidth;
00141   float zoom_h = avheight / bbheight;
00142   float zoom   = std::min(zoom_w, zoom_h);
00143 
00144   float translate_x = 0;
00145   float translate_y = 0;
00146 
00147   if (bbwidth > avwidth || bbheight > avheight) {
00148     float zwidth  = bbwidth * zoom;
00149     float zheight = bbheight * zoom;
00150     translate_x += (avwidth  - zwidth ) / 2.;
00151     translate_y += (avheight - zheight) / 2.;
00152   } else {
00153     zoom = 1.0;
00154     translate_x += (avwidth  - bbwidth)  / 2.;
00155     translate_y += (avheight - bbheight) / 2.;      
00156   }
00157 
00158   gvp->set_bb(bbwidth, bbheight);
00159   gvp->set_pad(job->pad.x, job->pad.y);
00160   gvp->set_scale(zoom);
00161   gvp->set_translation(translate_x, translate_y);
00162 
00163   if (! gvp->scale_override()) {
00164     gvp->get_affine()->set_translate(translate_x + job->pad.x,
00165                                      translate_y + job->pad.y);
00166     gvp->get_affine()->set_scale(zoom);
00167   }
00168 
00169   /*
00170   char *graph_translate_x = agget(obj->u.g, (char *)"trans_x");
00171   if (graph_translate_x && (strlen(graph_translate_x) > 0)) {
00172     float translate_x = atof(graph_translate_x) * zoom;
00173     float translate_y = atof(graph_translate_y) * job->scale.x;
00174   }
00175   */
00176 #ifdef USE_GVPLUGIN_TIMETRACKER
00177   __num_ellipse = 0;
00178   __num_bezier = 0;
00179   __num_polygon = 0;
00180   __num_polyline = 0;
00181   __num_text = 0;
00182 
00183   __tt.ping_end(__ttc_beginpage);
00184 #endif
00185 }
00186 
00187 static void
00188 skillgui_render_end_page(GVJ_t * job)
00189 {
00190   //SkillGuiGraphViewport *gvp = (SkillGuiGraphViewport *)job->context;
00191   //gvp->queue_draw();  
00192 #ifdef USE_GVPLUGIN_TIMETRACKER
00193   __tt.ping_end(__ttc_page);
00194   if ( ++__tt_count >= 10 ) {
00195     __tt_count = 0;
00196     __tt.print_to_stdout();
00197 
00198     printf("Num Ellipse:   %u\n"
00199            "Num Bezier:    %u\n"
00200            "Num Polygon:   %u\n"
00201            "Num Polyline:  %u\n"
00202            "Num Text:      %u\n", __num_ellipse, __num_bezier,
00203            __num_polygon, __num_polyline, __num_text);
00204   }
00205 #endif
00206 }
00207 
00208 static void
00209 skillgui_render_textpara(GVJ_t *job, pointf p, textpara_t *para)
00210 {
00211 #ifdef USE_GVPLUGIN_TIMETRACKER
00212   __tt.ping_start(__ttc_text);
00213   ++__num_text;
00214 #endif
00215   SkillGuiGraphViewport *gvp = (SkillGuiGraphViewport *)job->context;
00216   obj_state_t *obj = job->obj;
00217 
00218   switch (para->just) {
00219   case 'r':
00220     p.x -= para->width;
00221     break;
00222   case 'l':
00223     p.x -= 0.0;
00224     break;
00225   case 'n':
00226   default:
00227     p.x -= para->width / 2.0;
00228     break;
00229   }
00230 
00231   p.y += para->height / 2.0 + para->yoffset_centerline;
00232   //p.y -= para->yoffset_centerline;
00233   //p.y += para->yoffset_centerline; // + para->yoffset_layout;
00234 
00235   Glib::RefPtr<Pango::Layout> pl = Glib::wrap((PangoLayout *)para->layout,
00236                                               /* copy */ true);
00237   Pango::FontDescription fd = pl->get_font_description();
00238   Cairo::FontSlant slant = Cairo::FONT_SLANT_NORMAL;
00239   if (fd.get_style() == Pango::STYLE_OBLIQUE ) {
00240     slant = Cairo::FONT_SLANT_OBLIQUE;
00241   } else if (fd.get_style() == Pango::STYLE_ITALIC ) {
00242     slant = Cairo::FONT_SLANT_ITALIC;
00243   }
00244   Cairo::FontWeight weight = Cairo::FONT_WEIGHT_NORMAL;
00245   if ( fd.get_weight() == Pango::WEIGHT_BOLD ) {
00246     weight = Cairo::FONT_WEIGHT_BOLD;
00247   }
00248 
00249   double offsetx = 0.0;
00250   double offsety = 0.0;
00251   double rotate  = 0.0;
00252 
00253   if ( (obj->type == EDGE_OBJTYPE) && (strcmp(para->str, obj->headlabel) == 0) ) {
00254     char *labelrotate = agget(obj->u.e, (char *)"labelrotate");
00255     if (labelrotate && (strlen(labelrotate) > 0)) {
00256       rotate = fawkes::deg2rad(atof(labelrotate));
00257     }
00258     char *labeloffsetx = agget(obj->u.e, (char *)"labeloffsetx");
00259     if (labeloffsetx && (strlen(labeloffsetx) > 0)) {
00260       offsetx = atof(labeloffsetx) * job->scale.x;
00261     }
00262     char *labeloffsety = agget(obj->u.e, (char *)"labeloffsety");
00263     if (labeloffsety && (strlen(labeloffsety) > 0)) {
00264       offsety = atof(labeloffsety) * job->scale.y;
00265     }
00266   }
00267   //__tt.ping_start(__ttc_text_1);
00268 
00269   Papyrus::Text::pointer t = Papyrus::Text::create(para->str, para->fontsize,
00270                                                    fd.get_family(), slant, weight);
00271   //t->set_stroke(skillgui_render_stroke(&(obj->pencolor)));
00272   //__tt.ping_end(__ttc_text_1);
00273   //__tt.ping_start(__ttc_text_2);
00274 #ifdef HAVE_TIMS_PAPYRUS_PATCHES
00275   t->set_fill(skillgui_render_solidpattern(&(obj->pencolor)), false);
00276 #else
00277   t->set_fill(skillgui_render_solidpattern(&(obj->pencolor)));
00278 #endif
00279   //__tt.ping_end(__ttc_text_2);
00280   //__tt.ping_start(__ttc_text_3);
00281   t->translate(p.x + offsetx, p.y + offsety, false);
00282   //__tt.ping_end(__ttc_text_3);
00283   //__tt.ping_start(__ttc_text_4);
00284   if (rotate != 0.0)  t->set_rotation(rotate, Papyrus::RADIANS, false);
00285   //__tt.ping_end(__ttc_text_4);
00286   //__tt.ping_start(__ttc_text_5);
00287   gvp->add_drawable(t);  
00288 
00289   //__tt.ping_end(__ttc_text_5);
00290 #ifdef USE_GVPLUGIN_TIMETRACKER
00291   __tt.ping_end(__ttc_text);
00292 #endif
00293 }
00294 
00295 static void
00296 skillgui_render_ellipse(GVJ_t *job, pointf *A, int filled)
00297 {
00298 #ifdef USE_GVPLUGIN_TIMETRACKER
00299   __tt.ping_start(__ttc_ellipse);
00300   ++__num_ellipse;
00301 #endif
00302   //printf("Render ellipse\n");
00303   SkillGuiGraphViewport *gvp = (SkillGuiGraphViewport *)job->context;
00304   obj_state_t *obj = job->obj;
00305 
00306   double rx = fabs(A[1].x - A[0].x);
00307   double ry = fabs(A[1].y - A[0].y);
00308 
00309   Papyrus::Circle::pointer e = Papyrus::Circle::create(rx);
00310   e->set_stroke(skillgui_render_stroke(obj));
00311   if ( filled )  e->set_fill(skillgui_render_solidpattern(&(obj->fillcolor)));
00312   e->translate(A[0].x, A[0].y);
00313   e->set_scale_y(ry / rx);
00314 
00315   gvp->add_drawable(e);
00316 #ifdef USE_GVPLUGIN_TIMETRACKER
00317   __tt.ping_end(__ttc_ellipse);
00318 #endif
00319 }
00320 
00321 static void
00322 skillgui_render_polygon(GVJ_t *job, pointf *A, int n, int filled)
00323 {
00324 #ifdef USE_GVPLUGIN_TIMETRACKER
00325   __tt.ping_start(__ttc_polygon);
00326   ++__num_polygon;
00327 #endif
00328   //printf("Polygon\n");
00329   SkillGuiGraphViewport *gvp = (SkillGuiGraphViewport *)job->context;
00330   obj_state_t *obj = job->obj;
00331 
00332   Papyrus::Vertices v;
00333   for (int i = 0; i < n; ++i) {
00334     v.push_back(Papyrus::Vertex(A[i].x, A[i].y));
00335   }
00336 
00337   Papyrus::Polygon::pointer p = Papyrus::Polygon::create(v);
00338   p->set_stroke(skillgui_render_stroke(obj));
00339   if ( filled )  p->set_fill(skillgui_render_solidpattern(&(obj->fillcolor)));
00340   gvp->add_drawable(p);
00341 #ifdef USE_GVPLUGIN_TIMETRACKER
00342   __tt.ping_end(__ttc_polygon);
00343 #endif
00344 }
00345 
00346 static void
00347 skillgui_render_bezier(GVJ_t * job, pointf * A, int n, int arrow_at_start,
00348                 int arrow_at_end, int filled)
00349 {
00350 #ifdef USE_GVPLUGIN_TIMETRACKER
00351   __tt.ping_start(__ttc_bezier);
00352   ++__num_bezier;
00353 #endif
00354   //printf("Bezier\n");
00355   SkillGuiGraphViewport *gvp = (SkillGuiGraphViewport *)job->context;
00356   obj_state_t *obj = job->obj;
00357 
00358   Papyrus::BezierVertices v;
00359   v.push_back(Papyrus::BezierVertex(A[0].x, A[0].y,
00360                                     A[0].x, A[0].y,
00361                                     A[1].x, A[1].y));
00362   for (int i = 1; i < n; i += 3) {
00363     if ( i < (n - 4) ) {
00364       v.push_back(Papyrus::BezierVertex(A[i+2].x, A[i+2].y,
00365                                         A[i+1].x, A[i+1].y,
00366                                         A[i+3].x, A[i+3].y));
00367     } else {
00368       v.push_back(Papyrus::BezierVertex(A[i+2].x, A[i+2].y,
00369                                         A[i+1].x, A[i+1].y,
00370                                         A[i+2].x, A[i+2].y));
00371     }
00372   }
00373 
00374   Papyrus::Bezierline::pointer p = Papyrus::Bezierline::create(v);
00375   p->set_stroke(skillgui_render_stroke(obj));
00376   if ( filled )  p->set_fill(skillgui_render_solidpattern(&(obj->fillcolor)));
00377   gvp->add_drawable(p);
00378 #ifdef USE_GVPLUGIN_TIMETRACKER
00379   __tt.ping_end(__ttc_bezier);
00380 #endif
00381 }
00382 
00383 static void
00384 skillgui_render_polyline(GVJ_t * job, pointf * A, int n)
00385 {
00386 #ifdef USE_GVPLUGIN_TIMETRACKER
00387   __tt.ping_start(__ttc_polyline);
00388   ++__num_polyline;
00389 #endif
00390   //printf("Polyline\n");
00391   SkillGuiGraphViewport *gvp = (SkillGuiGraphViewport *)job->context;
00392   obj_state_t *obj = job->obj;
00393 
00394   Papyrus::Vertices v;
00395   for (int i = 0; i < n; ++i) {
00396     v.push_back(Papyrus::Vertex(A[i].x, A[i].y));
00397   }
00398 
00399   Papyrus::Polyline::pointer p = Papyrus::Polyline::create(v);
00400   p->set_stroke(skillgui_render_stroke(obj));
00401   gvp->add_drawable(p);
00402 #ifdef USE_GVPLUGIN_TIMETRACKER
00403   __tt.ping_end(__ttc_polyline);
00404 #endif
00405 }
00406 
00407 
00408 static gvrender_engine_t skillgui_render_engine = {
00409     0,                          /* skillgui_render_begin_job */
00410     0,                          /* skillgui_render_end_job */
00411     0,                          /* skillgui_render_begin_graph */
00412     0,                          /* skillgui_render_end_graph */
00413     0,                          /* skillgui_render_begin_layer */
00414     0,                          /* skillgui_render_end_layer */
00415     skillgui_render_begin_page,
00416     skillgui_render_end_page,
00417     0,                          /* skillgui_render_begin_cluster */
00418     0,                          /* skillgui_render_end_cluster */
00419     0,                          /* skillgui_render_begin_nodes */
00420     0,                          /* skillgui_render_end_nodes */
00421     0,                          /* skillgui_render_begin_edges */
00422     0,                          /* skillgui_render_end_edges */
00423     0,                          /* skillgui_render_begin_node */
00424     0,                          /* skillgui_render_end_node */
00425     0,                          /* skillgui_render_begin_edge */
00426     0,                          /* skillgui_render_end_edge */
00427     0,                          /* skillgui_render_begin_anchor */
00428     0,                          /* skillgui_render_end_anchor */
00429     0,                          /* skillgui_begin_label */
00430     0,                          /* skillgui_end_label */
00431     skillgui_render_textpara,
00432     0,                          /* skillgui_render_resolve_color */
00433     skillgui_render_ellipse,
00434     skillgui_render_polygon,
00435     skillgui_render_bezier,
00436     skillgui_render_polyline,
00437     0,                          /* skillgui_render_comment */
00438     0,                          /* skillgui_render_library_shape */
00439 };
00440 
00441 static gvdevice_engine_t skillgui_device_engine = {
00442     skillgui_device_init,
00443     NULL,                       /* skillgui_device_format */
00444     skillgui_device_finalize,
00445 };
00446 
00447 
00448 #ifdef __cplusplus
00449 extern "C" {
00450 #endif
00451 
00452 
00453 static gvrender_features_t skillgui_render_features = {
00454   GVRENDER_Y_GOES_DOWN | GVRENDER_DOES_LABELS |
00455   GVRENDER_DOES_TRANSFORM,                      /* flags, for Cairo: GVRENDER_DOES_TRANSFORM */
00456   8,                                            /* default pad - graph units */
00457   0,                                            /* knowncolors */
00458   0,                                            /* sizeof knowncolors */
00459   RGBA_DOUBLE,                                  /* color_type */
00460 };
00461 
00462 
00463 static gvdevice_features_t skillgui_device_features = {
00464   GVDEVICE_DOES_TRUECOLOR | GVDEVICE_EVENTS,    /* flags */
00465   {0.,0.},                                      /* default margin - points */
00466   {0.,0.},                                      /* default page width, height - points */
00467   {96.,96.},                                    /* dpi */
00468 };
00469 
00470 gvplugin_installed_t gvdevice_types_skillgui[] = {
00471   {0, ( char *)"skillgui:skillgui", 0, &skillgui_device_engine, &skillgui_device_features},
00472   {0, NULL, 0, NULL, NULL}
00473 };
00474 
00475 gvplugin_installed_t gvrender_types_skillgui[] = {
00476   {0, (char *)"skillgui", 10, &skillgui_render_engine, &skillgui_render_features},
00477   {0, NULL, 0, NULL, NULL}
00478 };
00479 
00480 static gvplugin_api_t apis[] = {
00481   {API_device, gvdevice_types_skillgui},
00482   {API_render, gvrender_types_skillgui},
00483   {(api_t)0, 0},
00484 };
00485 
00486 gvplugin_library_t gvplugin_skillgui_LTX_library = { (char *)"skillgui", apis };
00487 
00488 #ifdef __cplusplus
00489 }
00490 #endif
00491 
00492 
00493 void
00494 gvplugin_skillgui_setup(GVC_t *gvc, SkillGuiGraphViewport *sggvp)
00495 {
00496   __sggvp = sggvp;
00497   gvAddLibrary(gvc, &gvplugin_skillgui_LTX_library);
00498 }
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends