$search
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 }