$search
00001 00002 /*************************************************************************** 00003 * graph_viewport.cpp - FSM Graph Viewport for Skill GUI 00004 * 00005 * Created: Mon Dec 15 15:40:36 2008 00006 * Copyright 2008-2009 Tim Niemueller [www.niemueller.de] 00007 * 00008 ****************************************************************************/ 00009 00010 /* This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. 00014 * 00015 * This program is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 * GNU Library General Public License for more details. 00019 * 00020 * Read the full text in the LICENSE.GPL file in the doc directory. 00021 */ 00022 00023 #include "graph_viewport.h" 00024 #include "gvplugin_skillgui_papyrus.h" 00025 00026 #include <gtk/gtk.h> 00027 00034 SkillGuiGraphViewport::SkillGuiGraphViewport() 00035 { 00036 Cairo::RefPtr<Cairo::SolidPattern> bp = Cairo::SolidPattern::create_rgb(1, 1, 1); 00037 Papyrus::Paint::pointer pp = Papyrus::Paint::create(bp); 00038 00039 Papyrus::Canvas::pointer c = canvas(); 00040 c->set_scroll_anchor(Papyrus::SCROLL_ANCHOR_TOP_LEFT); 00041 c->set_background(pp); 00042 00043 __affine = Papyrus::AffineController::create(); 00044 __affine->insert(c); 00045 __translator = Papyrus::Translator::create(); 00046 add_controller(__translator); 00047 00048 __gvc = gvContext(); 00049 __gvjob = NULL; 00050 00051 __graph_fsm = ""; 00052 __graph = ""; 00053 00054 __bbw = __bbh = __pad_x = __pad_y = 0.0; 00055 __translation_x = __translation_y = 0.0; 00056 __scale = 1.0; 00057 __update_graph = true; 00058 00059 Gtk::Window *w = dynamic_cast<Gtk::Window *>(get_toplevel()); 00060 if (w) { 00061 __fcd = new Gtk::FileChooserDialog(*w, "Save Graph", 00062 Gtk::FILE_CHOOSER_ACTION_SAVE); 00063 __fcd->set_transient_for(*w); 00064 } else { 00065 __fcd = new Gtk::FileChooserDialog("Save Graph", 00066 Gtk::FILE_CHOOSER_ACTION_SAVE); 00067 } 00068 00069 //Add response buttons the the dialog: 00070 __fcd->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); 00071 __fcd->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK); 00072 00073 Gtk::FileFilter *filter_pdf = Gtk::manage(new Gtk::FileFilter()); 00074 filter_pdf->set_name("Portable Document Format (PDF)"); 00075 filter_pdf->add_pattern("*.pdf"); 00076 Gtk::FileFilter *filter_svg = Gtk::manage(new Gtk::FileFilter());; 00077 filter_svg->set_name("Scalable Vector Graphic (SVG)"); 00078 filter_svg->add_pattern("*.svg"); 00079 Gtk::FileFilter *filter_png = Gtk::manage(new Gtk::FileFilter());; 00080 filter_png->set_name("Portable Network Graphic (PNG)"); 00081 filter_png->add_pattern("*.png"); 00082 __fcd->add_filter(*filter_pdf); 00083 __fcd->add_filter(*filter_svg); 00084 __fcd->add_filter(*filter_png); 00085 __fcd->set_filter(*filter_pdf); 00086 00087 gvplugin_skillgui_setup(__gvc, this); 00088 00089 signal_size_allocate().connect_notify(sigc::hide(sigc::mem_fun(*this, &SkillGuiGraphViewport::render))); 00090 signal_expose_event().connect_notify(sigc::mem_fun(*this, &SkillGuiGraphViewport::on_expose)); 00091 } 00092 00093 00095 SkillGuiGraphViewport::~SkillGuiGraphViewport() 00096 { 00097 gvFreeContext(__gvc); 00098 delete __fcd; 00099 } 00100 00101 00105 void 00106 SkillGuiGraphViewport::set_gvjob(GVJ_t *job) 00107 { 00108 __gvjob = job; 00109 } 00110 00111 00115 void 00116 SkillGuiGraphViewport::set_graph_fsm(std::string fsm_name) 00117 { 00118 if ( __graph_fsm != fsm_name ) { 00119 __translator->set_translate(0, 0); 00120 } 00121 __graph_fsm = fsm_name; 00122 } 00123 00124 00128 void 00129 SkillGuiGraphViewport::set_graph(std::string graph) 00130 { 00131 __graph = graph; 00132 } 00133 00134 00139 void 00140 SkillGuiGraphViewport::add_drawable(Papyrus::Drawable::pointer d) 00141 { 00142 canvas()->add(d); 00143 __translator->insert(d); 00144 } 00145 00146 00150 void 00151 SkillGuiGraphViewport::clear() 00152 { 00153 Papyrus::Gtk::Viewport::clear(); 00154 __translator->clear(); 00155 } 00156 00157 00163 void 00164 SkillGuiGraphViewport::set_bb(double bbw, double bbh) 00165 { 00166 __bbw = bbw; 00167 __bbh = bbh; 00168 } 00169 00170 00176 void 00177 SkillGuiGraphViewport::set_pad(double pad_x, double pad_y) 00178 { 00179 __pad_x = pad_x; 00180 __pad_y = pad_y; 00181 } 00182 00183 00189 void 00190 SkillGuiGraphViewport::set_translation(double tx, double ty) 00191 { 00192 __translation_x = tx; 00193 __translation_y = ty; 00194 } 00195 00196 00201 void 00202 SkillGuiGraphViewport::set_scale(double scale) 00203 { 00204 __scale = scale; 00205 } 00206 00210 bool 00211 SkillGuiGraphViewport::get_update_graph() 00212 { 00213 return __update_graph; 00214 } 00215 00216 00220 void 00221 SkillGuiGraphViewport::set_update_graph(bool update) 00222 { 00223 __update_graph = update; 00224 } 00225 00226 00230 void 00231 SkillGuiGraphViewport::zoom_in() 00232 { 00233 double sx, sy; 00234 Gtk::Allocation alloc = get_allocation(); 00235 00236 __affine->get_scale(sx, sy); 00237 sx += 0.1; sy += 0.1; 00238 __affine->set_scale(sx, sy); 00239 __affine->set_translate((alloc.get_width() - __bbw * sx) / 2.0, 00240 (alloc.get_height() - __bbh * sy) / 2.0); 00241 00242 __scale_override = true; 00243 } 00244 00245 00249 void 00250 SkillGuiGraphViewport::zoom_out() 00251 { 00252 double sx, sy; 00253 __affine->get_scale(sx, sy); 00254 if ( (sx > 0.1) && (sy > 0.1) ) { 00255 Gtk::Allocation alloc = get_allocation(); 00256 sx -= 0.1; sy -= 0.1; 00257 __affine->set_scale(sx, sy); 00258 __affine->set_translate((alloc.get_width() - __bbw * sx) / 2.0, 00259 (alloc.get_height() - __bbh * sy) / 2.0); 00260 } 00261 __scale_override = true; 00262 } 00263 00264 00268 void 00269 SkillGuiGraphViewport::zoom_fit() 00270 { 00271 __affine->set_scale(__scale); 00272 __affine->set_translate(__pad_x + __translation_x, __pad_y + __translation_y); 00273 __translator->set_translate(0, 0); 00274 __scale_override = false; 00275 } 00276 00277 00281 void 00282 SkillGuiGraphViewport::zoom_reset() 00283 { 00284 __affine->set_scale(1.0); 00285 if ( __scale == 1.0 ) { 00286 __affine->set_translate(__pad_x + __translation_x, __pad_y + __translation_y); 00287 } else { 00288 __affine->set_translate(__pad_x, __pad_y); 00289 } 00290 __scale_override = true; 00291 } 00292 00293 00297 bool 00298 SkillGuiGraphViewport::scale_override() 00299 { 00300 return __scale_override; 00301 } 00302 00303 00307 Papyrus::AffineController::pointer 00308 SkillGuiGraphViewport::get_affine() 00309 { 00310 return __affine; 00311 } 00312 00314 void 00315 SkillGuiGraphViewport::save() 00316 { 00317 Gtk::Window *w = dynamic_cast<Gtk::Window *>(get_toplevel()); 00318 00319 int result = __fcd->run(); 00320 if (result == Gtk::RESPONSE_OK) { 00321 00322 double old_scale_x, old_scale_y, old_translate_x, old_translate_y; 00323 __affine->get_scale(old_scale_x, old_scale_y); 00324 __affine->get_translate(old_translate_x, old_translate_y); 00325 __affine->set_scale(1); 00326 __affine->set_translate(__pad_x, __pad_y); 00327 00328 Papyrus::Canvas::pointer c = canvas(); 00329 00330 Cairo::RefPtr<Cairo::Surface> surface; 00331 00332 std::string filename = __fcd->get_filename(); 00333 bool write_to_png = false; 00334 if (filename != "") { 00335 Gtk::FileFilter *f = __fcd->get_filter(); 00336 if (f->get_name().find("PDF") != Glib::ustring::npos) { 00337 surface = Cairo::PdfSurface::create(filename, __bbw, __bbh); 00338 } else if (f->get_name().find("SVG") != Glib::ustring::npos) { 00339 surface = Cairo::SvgSurface::create(filename, __bbw, __bbh); 00340 } else if (f->get_name().find("PNG") != Glib::ustring::npos) { 00341 surface = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, __bbw, __bbh); 00342 write_to_png = true; 00343 } 00344 00345 if (surface) { 00346 Cairo::RefPtr<Cairo::Context> context = Cairo::Context::create(surface); 00347 c->render(context); 00348 if (write_to_png) { 00349 surface->write_to_png(filename); 00350 } 00351 } 00352 00353 } else { 00354 Gtk::MessageDialog md(*w, "Invalid filename", 00355 /* markup */ false, Gtk::MESSAGE_ERROR, 00356 Gtk::BUTTONS_OK, /* modal */ true); 00357 md.set_title("Invalid File Name"); 00358 md.run(); 00359 } 00360 00361 __affine->set_scale(old_scale_x, old_scale_y); 00362 __affine->set_translate(old_translate_x, old_translate_y); 00363 } 00364 00365 __fcd->hide(); 00366 } 00367 00368 00370 void 00371 SkillGuiGraphViewport::render() 00372 { 00373 if (! __update_graph) return; 00374 00375 Papyrus::Canvas::pointer c = canvas(); 00376 #ifdef HAVE_TIMS_PAPYRUS_PATCHES 00377 c->set_redraw_enabled(false); 00378 #endif 00379 Agraph_t *g = agmemread((char *)__graph.c_str()); 00380 if (g) { 00381 gvLayout(__gvc, g, (char *)"dot"); 00382 gvRender(__gvc, g, (char *)"skillgui", NULL); 00383 gvFreeLayout(__gvc, g); 00384 agclose(g); 00385 } else { 00386 clear(); 00387 } 00388 #ifdef HAVE_TIMS_PAPYRUS_PATCHES 00389 c->set_redraw_enabled(true); 00390 #endif 00391 } 00392 00393 00397 void 00398 SkillGuiGraphViewport::on_expose(GdkEventExpose *event) 00399 { 00400 if (__scale_override) { 00401 Gtk::Allocation alloc = get_allocation(); 00402 00403 double sx, sy; 00404 __affine->get_scale(sx, sy); 00405 __affine->set_translate(((alloc.get_width() - __bbw * sx) / 2.0) + __pad_x, 00406 ((alloc.get_height() - __bbh * sy) / 2.0) + __pad_y); 00407 00408 } 00409 }