diff options
-rw-r--r-- | gtk2_ardour/editor.cc | 9 | ||||
-rw-r--r-- | gtk2_ardour/editor.h | 1 | ||||
-rw-r--r-- | gtk2_ardour/editor_drag.cc | 3 | ||||
-rw-r--r-- | gtk2_ardour/editor_mouse.cc | 32 | ||||
-rw-r--r-- | gtk2_ardour/editor_summary.cc | 1 | ||||
-rw-r--r-- | libs/canvas/canvas.cc | 189 | ||||
-rw-r--r-- | libs/canvas/canvas/canvas.h | 58 | ||||
-rw-r--r-- | libs/canvas/group.cc | 2 | ||||
-rw-r--r-- | libs/canvas/item.cc | 1 | ||||
-rw-r--r-- | libs/canvas/types.cc | 2 |
10 files changed, 175 insertions, 123 deletions
diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 7f49c56d7b..6bae2674df 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -517,12 +517,6 @@ Editor::Editor () time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK); time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release)); - /* these enable us to have a dedicated window (for cursor setting, etc.) - for the canvas areas. - */ - - track_canvas_event_box.add (*_track_canvas_viewport); - time_canvas_event_box.add (time_canvas_vbox); time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK); @@ -543,7 +537,7 @@ Editor::Editor () /* time bars canvas */ edit_packer.attach (*_time_bars_canvas_viewport, 2, 3, 1, 2, FILL, FILL, 0, 0); /* track canvas */ - edit_packer.attach (track_canvas_event_box, 2, 3, 2, 3, FILL|EXPAND, FILL|EXPAND, 0, 0); + edit_packer.attach (*_track_canvas_viewport, 2, 3, 2, 3, FILL|EXPAND, FILL|EXPAND, 0, 0); bottom_hbox.set_border_width (2); bottom_hbox.set_spacing (3); @@ -788,6 +782,7 @@ Editor::~Editor() delete button_bindings; delete _routes; delete _route_groups; + delete _time_bars_canvas_viewport; delete _track_canvas_viewport; delete _drags; } diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 43d3fccedf..92f60acefa 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -732,7 +732,6 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD bool track_canvas_motion (GdkEvent*); Gtk::EventBox time_canvas_event_box; - Gtk::EventBox track_canvas_event_box; Gtk::EventBox time_bars_event_box; Gtk::EventBox ruler_label_event_box; diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index 701181d009..8822548ca0 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -496,10 +496,9 @@ RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView _brushing (b), _total_x_delta (0) { - + DEBUG_TRACE (DEBUG::Drags, "New RegionMotionDrag\n"); } - void RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) { diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index de22451422..220178d18a 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -104,7 +104,7 @@ Editor::mouse_frame (framepos_t& where, bool& in_track_canvas) const int x, y; double wx, wy; Gdk::ModifierType mask; - Glib::RefPtr<Gdk::Window> canvas_window = const_cast<Editor*>(this)->_track_canvas_viewport->get_bin_window(); + Glib::RefPtr<Gdk::Window> canvas_window = const_cast<Editor*>(this)->_track_canvas_viewport->get_window(); Glib::RefPtr<const Gdk::Window> pointer_window; if (!canvas_window) { @@ -134,6 +134,8 @@ Editor::mouse_frame (framepos_t& where, bool& in_track_canvas) const framepos_t Editor::event_frame (GdkEvent const * event, double* pcx, double* pcy) const { + using ArdourCanvas::Duple; + Duple d; double cx, cy; if (pcx == 0) { @@ -146,32 +148,36 @@ Editor::event_frame (GdkEvent const * event, double* pcx, double* pcy) const *pcx = 0; *pcy = 0; - /* The event coordinates will be canvas coordinates */ + /* The event coordinates will be window coordinates and we need canvas + * coordinates (units are pixels as with the window, but scrolling is taken into account) + */ switch (event->type) { case GDK_BUTTON_RELEASE: case GDK_BUTTON_PRESS: case GDK_2BUTTON_PRESS: case GDK_3BUTTON_PRESS: - *pcx = event->button.x; - *pcy = event->button.y; - _trackview_group->canvas_to_item (*pcx, *pcy); + d = _track_canvas->window_to_canvas (Duple (event->button.x, event->button.y)); + *pcx = d.x; + *pcy = d.y; break; case GDK_MOTION_NOTIFY: - *pcx = event->motion.x; - *pcy = event->motion.y; - _trackview_group->canvas_to_item (*pcx, *pcy); + d = _track_canvas->window_to_canvas (Duple (event->motion.x, event->motion.y)); + *pcx = d.x; + *pcy = d.y; break; case GDK_ENTER_NOTIFY: case GDK_LEAVE_NOTIFY: - *pcx = event->crossing.x; - *pcy = event->crossing.y; - /* XXX: CANVAS */ -// track_canvas->w2c(event->crossing.x, event->crossing.y, *pcx, *pcy); + d = _track_canvas->window_to_canvas (Duple (event->crossing.x, event->crossing.y)); + *pcx = d.x; + *pcy = d.y; break; case GDK_KEY_PRESS: case GDK_KEY_RELEASE: - // track_canvas->w2c(event->key.x, event->key.y, *pcx, *pcy); + // need to get pointer for this to work + // d = _track_canvas->window_to_canvas (Duple (event->key.x, event->key.y)); + *pcx = 0; + *pcy = 0; break; default: warning << string_compose (_("Editor::event_frame() used on unhandled event type %1"), event->type) << endmsg; diff --git a/gtk2_ardour/editor_summary.cc b/gtk2_ardour/editor_summary.cc index c7aef99389..b1fa984027 100644 --- a/gtk2_ardour/editor_summary.cc +++ b/gtk2_ardour/editor_summary.cc @@ -680,7 +680,6 @@ EditorSummary::on_scroll_event (GdkEventScroll* ev) void EditorSummary::set_editor (double const x, double const y) { - ArdourCanvas::checkpoint ("editor", "-> set editor"); if (_editor->pending_visual_change.idle_handler_id >= 0 && _editor->pending_visual_change.being_handled == true) { /* As a side-effect, the Editor's visual change idle handler processes diff --git a/libs/canvas/canvas.cc b/libs/canvas/canvas.cc index 207011409e..b849894bf0 100644 --- a/libs/canvas/canvas.cc +++ b/libs/canvas/canvas.cc @@ -24,6 +24,7 @@ #include <cassert> #include <gtkmm/adjustment.h> +#include <gtkmm/label.h> #include "pbd/xml++.h" #include "pbd/compose.h" @@ -39,6 +40,8 @@ using namespace ArdourCanvas; Canvas::Canvas () : _root (this) , _log_renders (true) + , _scroll_offset_x (0) + , _scroll_offset_y (0) { set_epoch (); } @@ -49,6 +52,8 @@ Canvas::Canvas () Canvas::Canvas (XMLTree const * tree) : _root (this) , _log_renders (true) + , _scroll_offset_x (0) + , _scroll_offset_y (0) { set_epoch (); @@ -70,6 +75,13 @@ Canvas::Canvas (XMLTree const * tree) } } +void +Canvas::scroll_to (Coord x, Coord y) +{ + _scroll_offset_x = x; + _scroll_offset_y = y; +} + /** Render an area of the canvas. * @param area Area in canvas coordinates. * @param context Cairo context to render to. @@ -85,9 +97,21 @@ Canvas::render (Rect const & area, Cairo::RefPtr<Cairo::Context> const & context } #endif - checkpoint ("render", "-> render"); + // checkpoint ("render", "-> render"); render_count = 0; +#ifdef CANVAS_DEBUG + if (getenv ("ARDOUR_HARLEQUIN_CANVAS")) { + /* light up the canvas to show redraws */ + context->set_source_rgba (random()%255 / 255.0, + random()%255 / 255.0, + random()%255 / 255.0, + 255); + context->rectangle (area.x0, area.y0, area.width(), area.height()); + context->fill (); + } +#endif + context->save (); /* clip to the requested area */ @@ -97,7 +121,7 @@ Canvas::render (Rect const & area, Cairo::RefPtr<Cairo::Context> const & context boost::optional<Rect> root_bbox = _root.bounding_box(); if (!root_bbox) { /* the root has no bounding box, so there's nothing to render */ - checkpoint ("render", "no root bbox"); + // checkpoint ("render", "no root bbox"); context->restore (); return; } @@ -107,7 +131,9 @@ Canvas::render (Rect const & area, Cairo::RefPtr<Cairo::Context> const & context /* there's a common area between the root and the requested area, so render it. */ - checkpoint ("render", "... root"); + // checkpoint ("render", "... root"); + context->stroke (); + _root.render (*draw, context); } @@ -117,7 +143,7 @@ Canvas::render (Rect const & area, Cairo::RefPtr<Cairo::Context> const & context context->restore (); - checkpoint ("render", "<- render"); + // checkpoint ("render", "<- render"); } ostream& @@ -412,52 +438,6 @@ GtkCanvas::item_going_away (Item* item, boost::optional<Rect> bounding_box) } } -/** Construct an ImageCanvas. - * @param size Size in pixels. - */ -ImageCanvas::ImageCanvas (Duple size) - : _surface (Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, size.x, size.y)) -{ - _context = Cairo::Context::create (_surface); -} - -/** Construct an ImageCanvas from an XML tree. - * @param tree XML Tree. - * @param size Size in pixels. - */ -ImageCanvas::ImageCanvas (XMLTree const * tree, Duple size) - : Canvas (tree) - , _surface (Cairo::ImageSurface::create (Cairo::FORMAT_ARGB32, size.x, size.y)) -{ - _context = Cairo::Context::create (_surface); -} - -/** Render the canvas to our pixbuf. - * @param area Area to render, in canvas coordinates. - */ -void -ImageCanvas::render_to_image (Rect const & area) const -{ - render (area, _context); -} - -/** Write our pixbuf to a PNG file. - * @param f PNG file name. - */ -void -ImageCanvas::write_to_png (string const & f) -{ - assert (_surface); - _surface->write_to_png (f); -} - -/** @return Our Cairo context */ -Cairo::RefPtr<Cairo::Context> -ImageCanvas::context () -{ - return _context; -} - /** Handler for GDK expose events. * @param ev Event. * @return true if the event was handled. @@ -465,8 +445,30 @@ ImageCanvas::context () bool GtkCanvas::on_expose_event (GdkEventExpose* ev) { + Cairo::RefPtr<Cairo::Context> c = get_window()->create_cairo_context (); - render (Rect (ev->area.x, ev->area.y, ev->area.x + ev->area.width, ev->area.y + ev->area.height), c); + + /* WINDOW CANVAS + * 0,0 _scroll_offset_x, _scroll_offset_y + */ + + /* render using canvas coordinates */ + + Rect canvas_area (ev->area.x, ev->area.y, ev->area.x + ev->area.width, ev->area.y + ev->area.height); + canvas_area = canvas_area.translate (Duple (_scroll_offset_x, _scroll_offset_y)); + + /* things are going to render to the cairo surface with canvas + * coordinates: + * + * an item at window/cairo 0,0 will have canvas_coords _scroll_offset_x,_scroll_offset_y + * + * let them render at their natural coordinates by using cairo_translate() + */ + + c->translate (-_scroll_offset_x, -_scroll_offset_y); + + render (canvas_area, c); + return true; } @@ -489,10 +491,18 @@ GtkCanvas::context () bool GtkCanvas::on_button_press_event (GdkEventButton* ev) { + /* translate event coordinates from window to canvas */ + + GdkEvent copy = *((GdkEvent*)ev); + Duple where = window_to_canvas (Duple (ev->x, ev->y)); + + copy.button.x = where.x; + copy.button.y = where.y; + /* Coordinates in the event will be canvas coordinates, correctly adjusted for scroll if this GtkCanvas is in a GtkCanvasViewport. */ - return button_handler (ev); + return button_handler ((GdkEventButton*) ©); } /** Handler for GDK button release events. @@ -501,11 +511,19 @@ GtkCanvas::on_button_press_event (GdkEventButton* ev) */ bool GtkCanvas::on_button_release_event (GdkEventButton* ev) -{ +{ + /* translate event coordinates from window to canvas */ + + GdkEvent copy = *((GdkEvent*)ev); + Duple where = window_to_canvas (Duple (ev->x, ev->y)); + + copy.button.x = where.x; + copy.button.y = where.y; + /* Coordinates in the event will be canvas coordinates, correctly adjusted for scroll if this GtkCanvas is in a GtkCanvasViewport. */ - return button_handler (ev); + return button_handler ((GdkEventButton*) ©); } /** Handler for GDK motion events. @@ -515,18 +533,27 @@ GtkCanvas::on_button_release_event (GdkEventButton* ev) bool GtkCanvas::on_motion_notify_event (GdkEventMotion* ev) { + /* translate event coordinates from window to canvas */ + + GdkEvent copy = *((GdkEvent*)ev); + Duple where = window_to_canvas (Duple (ev->x, ev->y)); + + copy.motion.x = where.x; + copy.motion.y = where.y; + /* Coordinates in the event will be canvas coordinates, correctly adjusted for scroll if this GtkCanvas is in a GtkCanvasViewport. */ - return motion_notify_handler (ev); + return motion_notify_handler ((GdkEventMotion*) ©); } /** Called to request a redraw of our canvas. * @param area Area to redraw, in canvas coordinates. */ void -GtkCanvas::request_redraw (Rect const & area) +GtkCanvas::request_redraw (Rect const & request) { + Rect area = canvas_to_window (request); queue_draw_area (floor (area.x0), floor (area.y0), ceil (area.x1) - floor (area.x0), ceil (area.y1) - floor (area.y0)); } @@ -574,17 +601,56 @@ GtkCanvas::ungrab () * @param vadj Adjustment to use for vertica scrolling. */ GtkCanvasViewport::GtkCanvasViewport (Gtk::Adjustment& hadj, Gtk::Adjustment& vadj) - : Viewport (hadj, vadj) + : Alignment (0, 0, 1.0, 1.0) + , hadjustment (hadj) + , vadjustment (vadj) { add (_canvas); + + hadj.signal_value_changed().connect (sigc::mem_fun (*this, &GtkCanvasViewport::scrolled)); + vadj.signal_value_changed().connect (sigc::mem_fun (*this, &GtkCanvasViewport::scrolled)); } +void +GtkCanvasViewport::scrolled () +{ + _canvas.scroll_to (hadjustment.get_value(), vadjustment.get_value()); + queue_draw (); +} + +Duple +GtkCanvas::window_to_canvas (Duple const & d) const +{ + return d.translate (Duple (_scroll_offset_x, _scroll_offset_y)); +} + +Duple +GtkCanvas::canvas_to_window (Duple const & d) const +{ + return d.translate (Duple (-_scroll_offset_x, -_scroll_offset_y)); +} + +Rect +GtkCanvas::window_to_canvas (Rect const & r) const +{ + return r.translate (Duple (_scroll_offset_x, _scroll_offset_y)); +} + +Rect +GtkCanvas::canvas_to_window (Rect const & r) const +{ + return r.translate (Duple (-_scroll_offset_x, -_scroll_offset_y)); +} + /** Handler for when GTK asks us what minimum size we want. * @param req Requsition to fill in. */ void GtkCanvasViewport::on_size_request (Gtk::Requisition* req) { + /* force the canvas to size itself */ + // _canvas.root()->bounding_box(); + req->width = 16; req->height = 16; } @@ -599,15 +665,16 @@ GtkCanvasViewport::on_size_request (Gtk::Requisition* req) void GtkCanvasViewport::window_to_canvas (int wx, int wy, Coord& cx, Coord& cy) const { - cx = wx + get_hadjustment()->get_value (); - cy = wy + get_vadjustment()->get_value (); + Duple d = _canvas.window_to_canvas (Duple (wx, wy)); + cx = d.x; + cy = d.y; } /** @return The visible area of the canvas, in canvas coordinates */ Rect GtkCanvasViewport::visible_area () const { - Distance const xo = get_hadjustment()->get_value (); - Distance const yo = get_vadjustment()->get_value (); + Distance const xo = hadjustment.get_value (); + Distance const yo = vadjustment.get_value (); return Rect (xo, yo, xo + get_allocation().get_width (), yo + get_allocation().get_height ()); } diff --git a/libs/canvas/canvas/canvas.h b/libs/canvas/canvas/canvas.h index 7ddb7d584b..1dd339b0b4 100644 --- a/libs/canvas/canvas/canvas.h +++ b/libs/canvas/canvas/canvas.h @@ -26,7 +26,7 @@ #include <gdkmm/window.h> #include <gtkmm/eventbox.h> -#include <gtkmm/viewport.h> +#include <gtkmm/alignment.h> #include <cairomm/surface.h> #include <cairomm/context.h> #include "pbd/signals.h" @@ -91,6 +91,8 @@ public: _log_renders = log; } + void scroll_to (Coord x, Coord y); + std::string indent() const; std::string render_indent() const; void dump (std::ostream&) const; @@ -103,39 +105,9 @@ protected: mutable std::list<Rect> _renders; bool _log_renders; -}; - -/** A Canvas which renders onto an in-memory pixbuf. In Ardour's context, - * this is most useful for testing. - */ -class ImageCanvas : public Canvas -{ -public: - ImageCanvas (Duple size = Duple (1024, 1024)); - ImageCanvas (XMLTree const *, Duple size = Duple (1024, 1024)); - - void request_redraw (Rect const &) { - /* XXX */ - } - - void request_size (Duple) { - /* XXX */ - } - - void grab (Item *) {} - void ungrab () {} - - void render_to_image (Rect const &) const; - void clear (); - void write_to_png (std::string const &); - Cairo::RefPtr<Cairo::Context> context (); - -private: - /** our Cairo surface */ - Cairo::RefPtr<Cairo::Surface> _surface; - /** our Cairo context */ - Cairo::RefPtr<Cairo::Context> _context; + Coord _scroll_offset_x; + Coord _scroll_offset_y; }; /** A canvas which renders onto a GTK EventBox */ @@ -152,6 +124,12 @@ public: Cairo::RefPtr<Cairo::Context> context (); + Rect canvas_to_window (Rect const&) const; + Rect window_to_canvas (Rect const&) const; + + Duple canvas_to_window (Duple const&) const; + Duple window_to_canvas (Duple const&) const; + protected: bool on_expose_event (GdkEventExpose *); bool on_button_press_event (GdkEventButton *); @@ -166,16 +144,20 @@ private: void item_going_away (Item *, boost::optional<Rect>); bool send_leave_event (Item const *, double, double) const; + /** the item that the mouse is currently over, or 0 */ Item const * _current_item; /** the item that is currently grabbed, or 0 */ Item const * _grabbed_item; }; -/** A GTK::Viewport with a GtkCanvas inside it. This provides a GtkCanvas - * that can be scrolled. +/** A GTK::Alignment with a GtkCanvas inside it plus some Gtk::Adjustments for + * scrolling. + * + * This provides a GtkCanvas that can be scrolled. It does NOT implement the + * Gtk::Scrollable interface. */ -class GtkCanvasViewport : public Gtk::Viewport +class GtkCanvasViewport : public Gtk::Alignment { public: GtkCanvasViewport (Gtk::Adjustment &, Gtk::Adjustment &); @@ -194,6 +176,10 @@ protected: private: /** our GtkCanvas */ GtkCanvas _canvas; + Gtk::Adjustment& hadjustment; + Gtk::Adjustment& vadjustment; + + void scrolled (); }; } diff --git a/libs/canvas/group.cc b/libs/canvas/group.cc index 7ed0f72f74..d12c13169e 100644 --- a/libs/canvas/group.cc +++ b/libs/canvas/group.cc @@ -277,7 +277,7 @@ void Group::dump (ostream& o) const { o << _canvas->indent(); - o << "Group " << this; + o << "Group " << this << " [" << name << ']'; o << " Items: " << _items.size(); o << " Visible ? " << _visible; diff --git a/libs/canvas/item.cc b/libs/canvas/item.cc index 90b53b5bfd..9f34f8c208 100644 --- a/libs/canvas/item.cc +++ b/libs/canvas/item.cc @@ -73,6 +73,7 @@ Item::set_position (Duple p) { boost::optional<Rect> bbox = bounding_box (); boost::optional<Rect> pre_change_parent_bounding_box; + if (bbox) { pre_change_parent_bounding_box = item_to_parent (bbox.get()); } diff --git a/libs/canvas/types.cc b/libs/canvas/types.cc index 8d7fbf1c27..ef5d3bb293 100644 --- a/libs/canvas/types.cc +++ b/libs/canvas/types.cc @@ -52,7 +52,7 @@ Rect Rect::translate (Duple t) const { Rect r; - + r.x0 = safe_add (x0, t.x); r.y0 = safe_add (y0, t.y); r.x1 = safe_add (x1, t.x); |