23 #include "graph_drawing_area.h"
25 #include "gvplugin_skillgui_cairo.h"
27 #include <core/exception.h>
42 add_events(Gdk::SCROLL_MASK | Gdk::BUTTON_MOTION_MASK);
49 bbw_ = bbh_ = pad_x_ = pad_y_ = 0.0;
50 translation_x_ = translation_y_ = 0.0;
52 scale_override_ =
false;
56 gvplugin_skillgui_cairo_setup(gvc_,
this);
58 fcd_save_ =
new Gtk::FileChooserDialog(
"Save Graph", Gtk::FILE_CHOOSER_ACTION_SAVE);
59 fcd_open_ =
new Gtk::FileChooserDialog(
"Load Graph", Gtk::FILE_CHOOSER_ACTION_OPEN);
61 new Gtk::FileChooserDialog(
"Recording Directory", Gtk::FILE_CHOOSER_ACTION_CREATE_FOLDER);
64 fcd_save_->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
65 fcd_save_->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
66 fcd_open_->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
67 fcd_open_->add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK);
68 fcd_recording_->add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
69 fcd_recording_->add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
71 #if GTK_VERSION_GE(3, 0)
72 filter_pdf_ = Gtk::FileFilter::create();
73 filter_svg_ = Gtk::FileFilter::create();
74 filter_png_ = Gtk::FileFilter::create();
75 filter_dot_ = Gtk::FileFilter::create();
77 filter_pdf_ =
new Gtk::FileFilter();
78 filter_svg_ =
new Gtk::FileFilter();
79 filter_png_ =
new Gtk::FileFilter();
80 filter_dot_ =
new Gtk::FileFilter();
82 filter_pdf_->set_name(
"Portable Document Format (PDF)");
83 filter_pdf_->add_pattern(
"*.pdf");
84 filter_svg_->set_name(
"Scalable Vector Graphic (SVG)");
85 filter_svg_->add_pattern(
"*.svg");
86 filter_png_->set_name(
"Portable Network Graphic (PNG)");
87 filter_png_->add_pattern(
"*.png");
88 filter_dot_->set_name(
"DOT Graph");
89 filter_dot_->add_pattern(
"*.dot");
90 #if GTK_VERSION_GE(3, 0)
91 fcd_save_->add_filter(filter_pdf_);
92 fcd_save_->add_filter(filter_svg_);
93 fcd_save_->add_filter(filter_png_);
94 fcd_save_->add_filter(filter_dot_);
95 fcd_save_->set_filter(filter_pdf_);
97 fcd_open_->add_filter(filter_dot_);
98 fcd_open_->set_filter(filter_dot_);
100 fcd_save_->add_filter(*filter_pdf_);
101 fcd_save_->add_filter(*filter_svg_);
102 fcd_save_->add_filter(*filter_png_);
103 fcd_save_->add_filter(*filter_dot_);
104 fcd_save_->set_filter(*filter_pdf_);
106 fcd_open_->add_filter(*filter_dot_);
107 fcd_open_->set_filter(*filter_dot_);
110 add_events(Gdk::SCROLL_MASK | Gdk::BUTTON_MOTION_MASK | Gdk::BUTTON_PRESS_MASK);
112 #if GTK_VERSION_LT(3, 0)
115 signal_button_press_event().connect(
117 signal_motion_notify_event().connect(
130 SkillGuiGraphDrawingArea::~SkillGuiGraphDrawingArea()
136 delete fcd_recording_;
137 #if GTK_VERSION_GE(3, 0)
156 return signal_update_disabled_;
166 if (graph_fsm_ != fsm_name) {
167 scale_override_ =
false;
169 graph_fsm_ = fsm_name;
171 nonupd_graph_fsm_ = fsm_name;
185 nonupd_graph_ = graph;
190 #if defined(__MACH__) && defined(__APPLE__)
192 if (gettimeofday(&t, NULL) == 0) {
193 long int nsec = t.tv_usec * 1000;
196 if (clock_gettime(CLOCK_REALTIME, &t) == 0) {
197 long int nsec = t.tv_nsec;
200 localtime_r(&t.tv_sec, &tms);
203 "%s/%s_%04i%02i%02i-%02i%02i%02i.%09li.dot",
204 record_directory_.c_str(),
218 printf(
"Warning: Could not create file name for recording, skipping graph\n");
221 printf(
"Warning: Could not time recording, skipping graph\n");
258 if (scale_override_) {
316 Gtk::Allocation alloc = get_allocation();
317 width = alloc.get_width();
318 height = alloc.get_height();
327 Gtk::Allocation alloc = get_allocation();
329 scale_override_ =
true;
330 translation_x_ = (alloc.get_width() - bbw_ * scale_) / 2.0;
331 translation_y_ = (alloc.get_height() - bbh_ * scale_) / 2.0 + bbh_ * scale_;
341 scale_override_ =
true;
343 Gtk::Allocation alloc = get_allocation();
345 translation_x_ = (alloc.get_width() - bbw_ * scale_) / 2.0;
346 translation_y_ = (alloc.get_height() - bbh_ * scale_) / 2.0 + bbh_ * scale_;
357 scale_override_ =
false;
367 Gtk::Allocation alloc = get_allocation();
369 scale_override_ =
true;
370 translation_x_ = (alloc.get_width() - bbw_) / 2.0 + pad_x_;
371 translation_y_ = (alloc.get_height() - bbh_) / 2.0 + bbh_ - pad_y_;
381 return scale_override_;
389 Cairo::RefPtr<Cairo::Context>
401 return update_graph_;
410 if (update && !update_graph_) {
411 if (graph_fsm_ != nonupd_graph_fsm_) {
412 scale_override_ =
false;
414 graph_ = nonupd_graph_;
415 graph_fsm_ = nonupd_graph_fsm_;
418 update_graph_ = update;
422 SkillGuiGraphDrawingArea::save_dotfile(
const char *filename)
424 FILE *f = fopen(filename,
"w");
426 if (fwrite(graph_.c_str(), graph_.length(), 1, f) != 1) {
428 printf(
"Failed to write dot file '%s'\n", filename);
444 Gtk::Window *w =
dynamic_cast<Gtk::Window *
>(get_toplevel());
445 fcd_recording_->set_transient_for(*w);
446 int result = fcd_recording_->run();
447 if (result == Gtk::RESPONSE_OK) {
448 record_directory_ = fcd_recording_->get_filename();
451 fcd_recording_->hide();
462 Gtk::Window *w =
dynamic_cast<Gtk::Window *
>(get_toplevel());
463 fcd_save_->set_transient_for(*w);
465 int result = fcd_save_->run();
466 if (result == Gtk::RESPONSE_OK) {
467 #if GTK_VERSION_GE(3, 0)
468 Glib::RefPtr<Gtk::FileFilter> f = fcd_save_->get_filter();
470 Gtk::FileFilter *f = fcd_save_->get_filter();
472 std::string filename = fcd_save_->get_filename();
473 if (filename !=
"") {
474 if (f == filter_dot_) {
475 save_dotfile(filename.c_str());
477 Cairo::RefPtr<Cairo::Surface> surface;
479 bool write_to_png =
false;
480 if (f == filter_pdf_) {
481 surface = Cairo::PdfSurface::create(filename, bbw_, bbh_);
482 }
else if (f == filter_svg_) {
483 surface = Cairo::SvgSurface::create(filename, bbw_, bbh_);
484 }
else if (f == filter_png_) {
486 Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, (
int)ceilf(bbw_), (
int)ceilf(bbh_));
491 cairo_ = Cairo::Context::create(surface);
493 bool old_scale_override = scale_override_;
494 double old_tx = translation_x_;
495 double old_ty = translation_y_;
496 double old_scale = scale_;
497 translation_x_ = pad_x_;
498 translation_y_ = bbh_ - pad_y_;
500 scale_override_ =
true;
502 Agraph_t *g = agmemread((
char *)graph_.c_str());
504 gvLayout(gvc_, g, (
char *)
"dot");
505 gvRender(gvc_, g, (
char *)
"skillguicairo", NULL);
506 gvFreeLayout(gvc_, g);
511 surface->write_to_png(filename);
516 translation_x_ = old_tx;
517 translation_y_ = old_ty;
519 scale_override_ = old_scale_override;
524 Gtk::MessageDialog md(*w,
530 md.set_title(
"Invalid File Name");
542 Gtk::Window *w =
dynamic_cast<Gtk::Window *
>(get_toplevel());
543 fcd_open_->set_transient_for(*w);
545 int result = fcd_open_->run();
546 if (result == Gtk::RESPONSE_OK) {
547 update_graph_ =
false;
549 char *basec = strdup(fcd_open_->get_filename().c_str());
550 char *basen = basename(basec);
554 FILE *f = fopen(fcd_open_->get_filename().c_str(),
"r");
558 if ((s = fread(tmp, 1, 4096, f)) > 0) {
559 graph_.append(tmp, s);
563 signal_update_disabled_.emit();
570 #if GTK_VERSION_GE(3, 0)
576 SkillGuiGraphDrawingArea::on_draw(
const Cairo::RefPtr<Cairo::Context> &cr)
587 Glib::RefPtr<Gdk::Window> window = get_window();
597 #if GTK_VERSION_LT(3, 0)
598 cairo_ = window->create_cairo_context();
602 cairo_->set_source_rgb(1, 1, 1);
605 Agraph_t *g = agmemread((
char *)graph_.c_str());
607 gvLayout(gvc_, g, (
char *)
"dot");
608 gvRender(gvc_, g, (
char *)
"skillguicairo", NULL);
609 gvFreeLayout(gvc_, g);
626 if (event->direction == GDK_SCROLL_UP) {
628 }
else if (event->direction == GDK_SCROLL_DOWN) {
641 last_mouse_x_ =
event->x;
642 last_mouse_y_ =
event->y;
653 scale_override_ =
true;
654 translation_x_ -= last_mouse_x_ -
event->x;
655 translation_y_ -= last_mouse_y_ -
event->y;
656 last_mouse_x_ =
event->x;
657 last_mouse_y_ =
event->y;