graph_viewport.cpp

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 
00028 /** @class SkillGuiGraphViewport "graph_viewport.h"
00029  * Skill FSM Graph Viewport.
00030  * @author Tim Niemueller
00031  */
00032 
00033 /** Constructor. */
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 
00094 /** Destructor. */
00095 SkillGuiGraphViewport::~SkillGuiGraphViewport()
00096 {
00097   gvFreeContext(__gvc);
00098   delete __fcd;
00099 }
00100 
00101 
00102 /** Set current Graphviz job.
00103  * @param job current Graphviz job
00104  */
00105 void
00106 SkillGuiGraphViewport::set_gvjob(GVJ_t *job)
00107 {
00108   __gvjob = job;
00109 }
00110 
00111 
00112 /** Set graph's FSM name.
00113  * @param fsm_name name of FSM the graph belongs to
00114  */
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 
00125 /** Set graph.
00126  * @param graph string representation of the current graph in the dot language.
00127  */
00128 void
00129 SkillGuiGraphViewport::set_graph(std::string graph)
00130 {
00131   __graph = graph;
00132 }
00133 
00134 
00135 /** Add a drawable.
00136  * To be called only by the Graphviz plugin.
00137  * @param d drawable to add
00138  */
00139 void
00140 SkillGuiGraphViewport::add_drawable(Papyrus::Drawable::pointer d)
00141 {
00142   canvas()->add(d);
00143   __translator->insert(d);
00144 }
00145 
00146 
00147 /** Clear all drawables.
00148  * To be called only by the Graphviz plugin.
00149  */
00150 void
00151 SkillGuiGraphViewport::clear()
00152 {
00153   Papyrus::Gtk::Viewport::clear();
00154   __translator->clear();
00155 }
00156 
00157 
00158 /** Set bounding box.
00159  * To be called only by the Graphviz plugin.
00160  * @param bbw bounding box width
00161  * @param bbh bounding box height
00162  */
00163 void
00164 SkillGuiGraphViewport::set_bb(double bbw, double bbh)
00165 {
00166   __bbw = bbw;
00167   __bbh = bbh;
00168 }
00169 
00170 
00171 /** Set padding.
00172  * To be called only by the Graphviz plugin.
00173  * @param pad_x padding in x
00174  * @param pad_y padding in y
00175  */
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 
00184 /** Set translation.
00185  * To be called only by the Graphviz plugin.
00186  * @param tx translation in x
00187  * @param ty translation in y
00188  */
00189 void
00190 SkillGuiGraphViewport::set_translation(double tx, double ty)
00191 {
00192   __translation_x = tx;
00193   __translation_y = ty;
00194 }
00195 
00196 
00197 /** Set scale.
00198  * To be called only by the Graphviz plugin.
00199  * @param scale scale value
00200  */
00201 void
00202 SkillGuiGraphViewport::set_scale(double scale)
00203 {
00204   __scale = scale;
00205 }
00206 
00207 /** Check if graph is being updated.
00208  * @return true if the graph will be update if new data is received, false otherwise
00209  */
00210 bool
00211 SkillGuiGraphViewport::get_update_graph()
00212 {
00213   return __update_graph;
00214 }
00215 
00216 
00217 /** Set if the graph should be updated on new data.
00218  * @param update true to update on new data, false to disable update
00219  */
00220 void
00221 SkillGuiGraphViewport::set_update_graph(bool update)
00222 {
00223   __update_graph = update;
00224 }
00225 
00226 
00227 /** Zoom in.
00228  * Sets scale override and increases the scale by 0.1.
00229  */
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 
00246 /** Zoom out.
00247  * Sets scale override and decreases the scale by 0.1.
00248  */
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 
00265 /** Zoom to fit.
00266  * Disables scale override and draws with values suggested by Graphviz plugin.
00267  */
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 
00278 /** Zoom reset.
00279  * Reset zoom to 1. Enables scale override.
00280  */
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 
00294 /** Check if scale override is enabled.
00295  * @return true if scale override is enabled, false otherwise
00296  */
00297 bool
00298 SkillGuiGraphViewport::scale_override()
00299 {
00300   return __scale_override;
00301 }
00302 
00303 
00304 /** Get scaler.
00305  * @return scaler controller
00306  */
00307 Papyrus::AffineController::pointer
00308 SkillGuiGraphViewport::get_affine()
00309 {
00310   return __affine;
00311 }
00312 
00313 /** Render current graph. */
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 
00369 /** Render current graph. */
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 
00394 /** Called on explose.
00395  * @param event Gdk event structure
00396  */
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 }

Generated on 1 Mar 2011 for Fawkes API by  doxygen 1.6.1