From 132db18b8c327fe3b008990b32cfe79424bf94fd Mon Sep 17 00:00:00 2001 From: tchernobog Date: Fri, 4 Aug 2006 20:08:55 +0000 Subject: [PATCH] - Split between abstract base class (sgpem::CairoWidget) and derived widget - Add History::set_notify_enabled() for usage by the frontend (for example, when loading from file, you'll want to call set_notify_enabled(false) before starting) git-svn-id: svn://svn.gna.org/svn/sgpemv2/trunk@823 3ecf2c5c-341e-0410-92b4-d18e462d057c --- Makefile.am | 2 + src/backend/history.cc | 18 ++++ src/backend/history.hh | 16 +++- src/cairo_elements.cc | 2 + src/cairo_widget.cc | 178 +++++++++++++++++++++++++++++++++++++ src/cairo_widget.hh | 68 ++++++++++++++ src/schedulables_widget.cc | 151 ++----------------------------- src/schedulables_widget.hh | 27 +----- 8 files changed, 292 insertions(+), 170 deletions(-) create mode 100644 src/cairo_widget.cc create mode 100644 src/cairo_widget.hh diff --git a/Makefile.am b/Makefile.am index b457143..5870425 100644 --- a/Makefile.am +++ b/Makefile.am @@ -280,6 +280,7 @@ sgpemv2_LDADD = \ # Please keep this in sorted order: sgpemv2_SOURCES = \ src/cairo_elements.cc \ + src/cairo_widget.cc \ src/gui_builder.cc \ src/main.cc \ src/parse_opts.cc \ @@ -288,6 +289,7 @@ sgpemv2_SOURCES = \ noinst_HEADERS += \ src/cairo_elements.hh \ + src/cairo_widget.hh \ src/gui_builder.hh \ src/main.hh \ src/parse_opts.hh \ diff --git a/src/backend/history.cc b/src/backend/history.cc index 438085b..f0a13f0 100644 --- a/src/backend/history.cc +++ b/src/backend/history.cc @@ -28,6 +28,13 @@ using namespace sgpem; using namespace std; + +History::History() + : _notify(true) +{ +} + + History::~History() { } @@ -52,7 +59,18 @@ History::detach(const HistoryObserver& observer) void History::notify_change() { + if(!_notify) return; + for(RegisteredObservers::iterator it =_observers.begin(); it != _observers.end(); it++) (*it)->update(*this); } + + +bool +History::set_notify_enabled(bool enabled) +{ + bool r = _notify; + _notify = enabled; + return r; +} diff --git a/src/backend/history.hh b/src/backend/history.hh index 77a1c76..28af8ef 100644 --- a/src/backend/history.hh +++ b/src/backend/history.hh @@ -64,6 +64,7 @@ namespace sgpem typedef Environment::resource_key_t resource_key_t; typedef const std::pair ResourcePair; + History(); virtual ~History() = 0; virtual size_t get_size() const = 0; @@ -102,13 +103,26 @@ namespace sgpem virtual void attach(HistoryObserver& observer); virtual void detach(const HistoryObserver& observer); + + /** \brief Enable/disable notifications to registered observers + * + * This is quite useful to disable momentarily notification while you + * do a bunch of insertions and/or deletions in one go, in order to + * speed up things. + * + * \return The old value + */ + virtual bool set_notify_enabled(bool enabled = true); protected: typedef std::vector RegisteredObservers; RegisteredObservers _observers; virtual void notify_change(); - + + private: + bool _notify; + }; //~ class History }//~ namespace sgpem diff --git a/src/cairo_elements.cc b/src/cairo_elements.cc index 37612d8..5290f2e 100644 --- a/src/cairo_elements.cc +++ b/src/cairo_elements.cc @@ -128,8 +128,10 @@ CairoElements::draw_container(const Rectangle& area) cairo_set_source_rgb(cr, 1, 1, 0.9); cairo_fill_preserve(cr); + cairo_set_line_width(cr, .005); cairo_set_source_rgb(cr, 0, 0, 0); + cairo_stroke(cr); cairo_restore(cr); } diff --git a/src/cairo_widget.cc b/src/cairo_widget.cc new file mode 100644 index 0000000..4656efd --- /dev/null +++ b/src/cairo_widget.cc @@ -0,0 +1,178 @@ +// src/cairo_widget.cc - Copyright 2005, 2006, University +// of Padova, dept. of Pure and Applied +// Mathematics +// +// This file is part of SGPEMv2. +// +// This is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// SGPEMv2 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with SGPEMv2; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +#include "cairo_elements.hh" +#include "cairo_widget.hh" + +#include "backend/history.hh" +#include "backend/simulation.hh" + +#include + +#include +#include + + +using namespace sgpem; + + +CairoWidget::CairoWidget() + : Glib::ObjectBase("sgpem_CairoWidget"), + Gtk::Widget(), _h(1), _buf(NULL) +{ + set_flags(Gtk::NO_WINDOW); + // Register this observer: + Simulation::get_instance().get_history().attach(*this); +} + + +CairoWidget::~CairoWidget() +{ + Simulation::get_instance().get_history().detach(*this); +} + + +void +CairoWidget::update(const History& history) +{ + // get_window() returns a null pointer + // if the widget has not been realized + if(!is_realized()) + return; // Nowhere to draw to. + + // Determine the final height before to start drawing + unsigned int w = get_allocation().get_width(); + _h = calc_height(history); + + _buf = Gdk::Pixmap::create(get_window(), w, _h); + + // Draw the widget background as the first thing. + // I've seen this is how it's done in the very Gtk+ toolkit + // for the GtkProgressBar widget. + GtkStyle* gStyle = get_style()->gobj(); + gtk_paint_box(gStyle, _buf->gobj(), + GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_IN, + NULL, this->gobj(), "through", + 0, 0, w, _h); + + cairo_t* ctx = gdk_cairo_create(_buf->gobj()); + + // do the drawing... + draw_widget(ctx); + + cairo_scale(ctx, w, _h); + + // manually force an expose_event? + cairo_destroy(ctx); + + queue_draw(); +} + + +void +CairoWidget::on_realize() +{ + if(is_realized()) return; + + Gtk::Widget::on_realize(); + ensure_style(); + + GdkWindowAttr attributes; + memset(&attributes, 0, sizeof(attributes)); + + Gtk::Allocation alloc = get_allocation(); + + attributes.x = alloc.get_x(); + attributes.y = alloc.get_y(); + attributes.width = alloc.get_width(); + attributes.height = alloc.get_height(); + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.event_mask = get_events() | GDK_EXPOSURE_MASK; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.visual = get_visual()->gobj(); + attributes.colormap = get_colormap()->gobj(); + + static const gint attributes_mask = Gdk::WA_X | Gdk::WA_Y | Gdk::WA_WMCLASS + | Gdk::WA_VISUAL | Gdk::WA_COLORMAP; + + Glib::RefPtr window = Gdk::Window::create(get_parent_window(), + &attributes, + attributes_mask); + + unset_flags(Gtk::NO_WINDOW); + set_window(window); + window->set_user_data(gobj()); + + // Not sure if the following line is needed: + gtk_style_attach(get_style()->gobj(), window->gobj()); + get_style()->set_background(window, Gtk::STATE_ACTIVE); +} + +void +CairoWidget::on_size_request(Gtk::Requisition* requisition) +{ + // FIXME: take correct measures, consider also using a viewport(?) + *requisition = Gtk::Requisition(); + requisition->width = get_allocation().get_width(); + requisition->height = _h; +} + + +void +CairoWidget::on_size_allocate(const Gtk::Allocation& allocation) +{ + set_allocation(allocation); + + if(is_realized()) + get_window()->move_resize(allocation.get_x(), allocation.get_y(), + allocation.get_width(), allocation.get_height()); +} + + +bool +CairoWidget::on_expose_event(GdkEventExpose* event) +{ + if(event == NULL || event->count > 0) + return false; + + // calculated dinamically: + int w = get_allocation().get_width(); + set_size_request(w, _h); + + // Clip to redraw only the smallest possible area + // Use double buffering or we're CPU-dead + // Copy from the buffer to the screen + if(_buf) + get_window()->draw_drawable(get_style()->get_black_gc(), _buf, + event->area.x, event->area.y, + event->area.x, event->area.y, + event->area.width, event->area.height); + + return true; +} + + +bool +CairoWidget::on_button_press_event(GdkEventButton* event) +{ + // Not here. Yet. + return false; +} + diff --git a/src/cairo_widget.hh b/src/cairo_widget.hh new file mode 100644 index 0000000..aa085fe --- /dev/null +++ b/src/cairo_widget.hh @@ -0,0 +1,68 @@ +// src/cairo_widget.hh - Copyright 2005, 2006, University +// of Padova, dept. of Pure and Applied +// Mathematics +// +// This file is part of SGPEMv2. +// +// This is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// SGPEMv2 is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with SGPEMv2; if not, write to the Free Software +// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +#ifndef CAIRO_WIDGET_HH +#define CAIRO_WIDGET_HH 1 + +#include "config.h" + +#include "backend/history_observer.hh" + +#include +#include +#include + +namespace sgpem +{ + class CairoWidget : public Gtk::Widget, public HistoryObserver + { + public: + CairoWidget(); + virtual ~CairoWidget(); + + void update(const History& history); + + protected: + virtual void on_realize(); + virtual void on_size_allocate(const Gtk::Allocation& allocation); + virtual void on_size_request(Gtk::Requisition* requisition); + virtual bool on_expose_event(GdkEventExpose* event); + virtual bool on_button_press_event(GdkEventButton* event); + virtual void draw_widget(cairo_t* ctx) = 0; + virtual unsigned int calc_height(const History& history) const = 0; + + typedef Gdk::Rectangle area_t; + typedef sigc::mem_functor0 method0_t; + typedef std::pair area_callback_t; + typedef std::vector areas_vect_t; + + private: + // The height the widget will assume, must be determined + // before starting drawing by calc_height() + unsigned int _h; + + // The offscreen pixmap we use for double-buffering + Glib::RefPtr _buf; + }; + +} //~ namespace sgpem + + +#endif //~ CAIRO_WIDGET_HH diff --git a/src/schedulables_widget.cc b/src/schedulables_widget.cc index fffdf7e..3d8de68 100644 --- a/src/schedulables_widget.cc +++ b/src/schedulables_widget.cc @@ -18,72 +18,23 @@ // along with SGPEMv2; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -#include "cairo_elements.hh" #include "schedulables_widget.hh" -#include "backend/history.hh" -#include "backend/simulation.hh" - -#include +#include "cairo_elements.hh" #include -#include -#include - using namespace sgpem; SchedulablesWidget::SchedulablesWidget() - : Glib::ObjectBase("sgpem_CairoWidget"), - Gtk::Widget(), _h(1), _buf(NULL) + : Glib::ObjectBase("sgpem_SchedulablesWidget"), CairoWidget() { - set_flags(Gtk::NO_WINDOW); - // Register this observer: - Simulation::get_instance().get_history().attach(*this); } SchedulablesWidget::~SchedulablesWidget() { - Simulation::get_instance().get_history().detach(*this); -} - - -void -SchedulablesWidget::update(const History& history) -{ - // get_window() returns a null pointer - // if the widget has not been realized - if(!is_realized()) - return; // Nowhere to draw to. - - // Determine the final height before to start drawing - unsigned int w = get_allocation().get_width(); - _h = calc_height(history); - - _buf = Gdk::Pixmap::create(get_window(), w, _h); - - // Draw the widget background as the first thing. - // I've seen this is how it's done in the very Gtk+ toolkit - // for the GtkProgressBar widget. - GtkStyle* gStyle = get_style()->gobj(); - gtk_paint_box(gStyle, _buf->gobj(), - GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_IN, - NULL, this->gobj(), "through", - 0, 0, w, _h); - - cairo_t* ctx = gdk_cairo_create(_buf->gobj()); - - // do the drawing... - draw_widget(ctx); - - cairo_scale(ctx, w, _h); - - // manually force an expose_event? - cairo_destroy(ctx); - - queue_draw(); } @@ -92,10 +43,14 @@ SchedulablesWidget::draw_widget(cairo_t* ctx) { // NOTE: just to try CairoElements ce(ctx); + + Rectangle area = { 30, 30, 100, 100 }; + ce.draw_container(area); + Color red = { 1, 0, 0 }; Point center = { 25, 25 }; - ce.draw_3dsphere(center, 25, red); + ce.draw_3dsphere(center, 20, red); } @@ -105,95 +60,3 @@ SchedulablesWidget::calc_height(const History& history) const // FIXME: write me return 400; } - - -void -SchedulablesWidget::on_realize() -{ - if(is_realized()) return; - - Gtk::Widget::on_realize(); - ensure_style(); - - GdkWindowAttr attributes; - memset(&attributes, 0, sizeof(attributes)); - - Gtk::Allocation alloc = get_allocation(); - - attributes.x = alloc.get_x(); - attributes.y = alloc.get_y(); - attributes.width = alloc.get_width(); - attributes.height = alloc.get_height(); - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.event_mask = get_events() | GDK_EXPOSURE_MASK; - attributes.window_type = GDK_WINDOW_CHILD; - attributes.visual = get_visual()->gobj(); - attributes.colormap = get_colormap()->gobj(); - - static const gint attributes_mask = Gdk::WA_X | Gdk::WA_Y | Gdk::WA_WMCLASS - | Gdk::WA_VISUAL | Gdk::WA_COLORMAP; - - Glib::RefPtr window = Gdk::Window::create(get_parent_window(), - &attributes, - attributes_mask); - - unset_flags(Gtk::NO_WINDOW); - set_window(window); - window->set_user_data(gobj()); - - // Not sure if the following line is needed: - gtk_style_attach(get_style()->gobj(), window->gobj()); - get_style()->set_background(window, Gtk::STATE_ACTIVE); -} - -void -SchedulablesWidget::on_size_request(Gtk::Requisition* requisition) -{ - // FIXME: take correct measures, consider also using a viewport(?) - *requisition = Gtk::Requisition(); - requisition->width = get_allocation().get_width(); - requisition->height = _h; -} - - -void -SchedulablesWidget::on_size_allocate(const Gtk::Allocation& allocation) -{ - set_allocation(allocation); - - if(is_realized()) - get_window()->move_resize(allocation.get_x(), allocation.get_y(), - allocation.get_width(), allocation.get_height()); -} - - -bool -SchedulablesWidget::on_expose_event(GdkEventExpose* event) -{ - if(event == NULL || event->count > 0) - return false; - - // calculated dinamically: - int w = get_allocation().get_width(); - set_size_request(w, _h); - - // Clip to redraw only the smallest possible area - // Use double buffering or we're CPU-dead - // Copy from the buffer to the screen - if(_buf) - get_window()->draw_drawable(get_style()->get_black_gc(), _buf, - event->area.x, event->area.y, - event->area.x, event->area.y, - event->area.width, event->area.height); - - return true; -} - - -bool -SchedulablesWidget::on_button_press_event(GdkEventButton* event) -{ - // Not here. Yet. - return false; -} - diff --git a/src/schedulables_widget.hh b/src/schedulables_widget.hh index 9dd5a54..6ee92c4 100644 --- a/src/schedulables_widget.hh +++ b/src/schedulables_widget.hh @@ -23,42 +23,19 @@ #include "config.h" -#include "backend/history_observer.hh" - -#include -#include -#include +#include "cairo_widget.hh" namespace sgpem { - class SchedulablesWidget : public Gtk::Widget, public HistoryObserver + class SchedulablesWidget : public CairoWidget { public: SchedulablesWidget(); virtual ~SchedulablesWidget(); - void update(const History& history); - protected: - virtual void on_realize(); - virtual void on_size_allocate(const Gtk::Allocation& allocation); - virtual void on_size_request(Gtk::Requisition* requisition); - virtual bool on_expose_event(GdkEventExpose* event); - virtual bool on_button_press_event(GdkEventButton* event); virtual void draw_widget(cairo_t* ctx); virtual unsigned int calc_height(const History& history) const; - - // The height the widget will assume, must be determined - // before starting drawing by calc_height(). - unsigned int _h; - - private: - typedef Gdk::Rectangle area_t; - typedef sigc::mem_functor0 method0_t; - typedef std::pair area_callback_t; - typedef std::vector areas_vect_t; - - Glib::RefPtr _buf; }; } //~ namespace sgpem