// 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; }