diff options
-rw-r--r-- | gtk2_ardour/editor.cc | 24 | ||||
-rw-r--r-- | gtk2_ardour/editor.h | 3 | ||||
-rw-r--r-- | gtk2_ardour/editor_canvas.cc | 6 | ||||
-rw-r--r-- | gtk2_ardour/editor_drag.cc | 74 | ||||
-rw-r--r-- | gtk2_ardour/editor_mouse.cc | 10 | ||||
-rw-r--r-- | gtk2_ardour/editor_ops.cc | 8 | ||||
-rw-r--r-- | gtk2_ardour/region_view.cc | 13 | ||||
-rw-r--r-- | gtk2_ardour/time_axis_view.cc | 5 | ||||
-rw-r--r-- | libs/canvas/canvas.cc | 65 | ||||
-rw-r--r-- | libs/canvas/canvas/canvas.h | 3 | ||||
-rw-r--r-- | libs/canvas/canvas/item.h | 4 | ||||
-rw-r--r-- | libs/canvas/canvas/scroll_group.h | 3 | ||||
-rw-r--r-- | libs/canvas/item.cc | 14 | ||||
-rw-r--r-- | libs/canvas/scroll_group.cc | 26 |
14 files changed, 167 insertions, 91 deletions
diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 5d16b09c02..f38cbb217b 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -2421,21 +2421,31 @@ Editor::get_state () return *node; } - - -/** @param y y offset from the top of all trackviews. +/** @param y y is in canvas coordinate space, in pixel units + * * @return pair: TimeAxisView that y is over, layer index. + * * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is * in stacked or expanded region display mode, otherwise 0. */ std::pair<TimeAxisView *, double> Editor::trackview_by_y_position (double y) { - for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) { + /* convert y into an offset within the trackview group */ + + ArdourCanvas::Duple top_of_trackviews_canvas = _trackview_group->item_to_canvas (ArdourCanvas::Duple (0, 0)); + + if (y >= top_of_trackviews_canvas.y) { + + y -= top_of_trackviews_canvas.y; - std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y); - if (r.first) { - return r; + for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) { + + std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y); + + if (r.first) { + return r; + } } } diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index daa417543b..d486e5b9f0 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -744,9 +744,6 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD /* The group containing all trackviews. */ ArdourCanvas::Group* _trackview_group; - /* The group used for region motion. Sits on top of _trackview_group */ - ArdourCanvas::Group* _region_motion_group; - /* a rect that sits at the bottom of all tracks to act as a drag-no-drop/clickable * target area. */ diff --git a/gtk2_ardour/editor_canvas.cc b/gtk2_ardour/editor_canvas.cc index 836b5356dc..6374481464 100644 --- a/gtk2_ardour/editor_canvas.cc +++ b/gtk2_ardour/editor_canvas.cc @@ -116,12 +116,8 @@ Editor::initialize_canvas () CANVAS_DEBUG_NAME (time_line_group, "time line group"); _trackview_group = new ArdourCanvas::Group (hv_scroll_group); - //_trackview_group->set_scroll_sensitivity (ArdourCanvas::Group::ScrollSensitivity (ArdourCanvas::Group::ScrollsVertically|ArdourCanvas::Group::ScrollsHorizontally)); CANVAS_DEBUG_NAME (_trackview_group, "Canvas TrackViews"); - _region_motion_group = new ArdourCanvas::Group (_trackview_group); - CANVAS_DEBUG_NAME (_region_motion_group, "Canvas Region Motion"); - /* TIME BAR CANVAS */ _time_markers_group = new ArdourCanvas::Group (h_scroll_group); @@ -453,7 +449,7 @@ Editor::drop_paths (const RefPtr<Gdk::DragContext>& context, if (convert_drop_to_paths (paths, context, x, y, data, info, time) == 0) { - /* D-n-D coordinates are window-relative, so convert to "world" coordinates + /* D-n-D coordinates are window-relative, so convert to canvas coordinates */ ev.type = GDK_BUTTON_RELEASE; diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index 1c50d86684..44b50d0131 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -1,4 +1,4 @@ -/* +* Copyright (C) 2009 Paul Davis This program is free software; you can redistribute it and/or modify @@ -40,6 +40,8 @@ #include "ardour/region_factory.h" #include "ardour/session.h" +#include "canvas/scroll_group.h" + #include "editor.h" #include "i18n.h" #include "keyboard.h" @@ -654,7 +656,7 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move) pair<TimeAxisView*, double> const r = _editor->trackview_by_y_position (_drags->current_pointer_y ()); TimeAxisView* tv = r.first; - if (tv) { + if (tv && tv->view()) { double layer = r.second; if (first_move && tv->view()->layer_display() == Stacked) { @@ -700,22 +702,9 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move) } if (first_move) { - rv->drag_start (); - - /* Reparent to a non scrolling group so that we can keep the - region selection above all time axis views. - Reparenting means that we will have to move the region view - within its new parent, as the two parent groups have different coordinates. - */ - - ArdourCanvas::Group* rvg = rv->get_canvas_group(); - Duple rv_canvas_offset = rvg->item_to_canvas (Duple (0,0)); - - rv->get_canvas_group()->reparent (_editor->_region_motion_group); - rv->fake_set_opaque (true); - rvg->set_position (rv_canvas_offset); + rv->raise_to_top (); } /* If we have moved tracks, we'll fudge the layer delta so that the @@ -730,7 +719,13 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move) if (tv) { - /* The TimeAxisView that this region is now on */ + int track_index = i->time_axis_view + delta_time_axis_view; + + if (track_index < 0 || track_index >= (int) _time_axis_views.size()) { + continue; + } + + /* The TimeAxisView that this region is now over */ TimeAxisView* current_tv = _time_axis_views[i->time_axis_view + delta_time_axis_view]; /* Ensure it is moved from stacked -> expanded if appropriate */ @@ -762,39 +757,50 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move) if (_brushing) { _editor->mouse_brush_insert_region (rv, pending_region_position); } else { - double x = 0; - double y = 0; - - /* Get the y coordinate of the top of the track that this region is now on */ - current_tv->canvas_display()->item_to_canvas (x, y); + Duple track_origin; + /* Get the y coordinate of the top of the track that this region is now over */ + track_origin = current_tv->canvas_display()->item_to_canvas (track_origin); + /* And adjust for the layer that it should be on */ StreamView* cv = current_tv->view (); switch (cv->layer_display ()) { case Overlaid: break; case Stacked: - y += (cv->layers() - i->layer - 1) * cv->child_height (); + track_origin.y += (cv->layers() - i->layer - 1) * cv->child_height (); break; case Expanded: - y += (cv->layers() - i->layer - 0.5) * 2 * cv->child_height (); + track_origin.y += (cv->layers() - i->layer - 0.5) * 2 * cv->child_height (); break; } + /* need to get the parent of the regionview + * canvas group and get its position in + * equivalent coordinate space as the trackview + * we are now dragging over. + */ + /* Now move the region view */ - rv->move (x_delta, y - rv->get_canvas_group()->position().y); + rv->move (x_delta, track_origin.y - rv->get_canvas_group()->item_to_canvas (Duple (0, 0)).y); } } else { - double y = 0; - double x = 0; - - TimeAxisView* last = _time_axis_views.back(); - last->canvas_display()->item_to_canvas (x, y); - y += last->effective_height(); - rv->move (x_delta, y - rv->get_canvas_group()->position().y); - i->time_axis_view = -1; - } + /* Only move the region into the empty dropzone at the bottom if the pointer + * is down there. + */ + + if (_drags->current_pointer_y() >= _editor->get_trackview_group()->item_to_canvas (Duple (0,0)).y) { + Duple track_origin; + + TimeAxisView* last = _time_axis_views.back(); + track_origin = last->canvas_display()->item_to_canvas (track_origin); + track_origin.y += last->effective_height(); + rv->move (x_delta, track_origin.y - rv->get_canvas_group()->item_to_canvas (Duple (0,0)).y); + i->time_axis_view = -1; + } + } + } /* foreach region */ _total_x_delta += x_delta; diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index 7eb801400a..935c90272d 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -140,12 +140,6 @@ Editor::window_event_sample (GdkEvent const * event, double* pcx, double* pcy) c return 0; } - /* adjust for scrolling (the canvas used by Ardour has global scroll - * disabled, so we have to do the adjustment explicitly). - */ - - d.translate (ArdourCanvas::Duple (horizontal_adjustment.get_value(), vertical_adjustment.get_value())); - /* event coordinates are in window units, so convert to canvas */ @@ -2710,8 +2704,6 @@ Editor::add_region_drag (ArdourCanvas::Item* item, GdkEvent*, RegionView* region return; } - _region_motion_group->raise_to_top (); - if (Config->get_edit_mode() == Splice) { _drags->add (new RegionSpliceDrag (this, item, region_view, selection->regions.by_layer())); } else { @@ -2728,8 +2720,6 @@ Editor::add_region_copy_drag (ArdourCanvas::Item* item, GdkEvent*, RegionView* r return; } - _region_motion_group->raise_to_top (); - _drags->add (new RegionMoveDrag (this, item, region_view, selection->regions.by_layer(), false, true)); } diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index e6b4fee43e..0c689452de 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -1333,8 +1333,6 @@ Editor::scroll_tracks_up_line () bool Editor::scroll_down_one_track () { - double vertical_pos = vertical_adjustment.get_value () + vertical_adjustment.get_page_size() - 1.0; - TrackViewList::reverse_iterator next = track_views.rend(); std::pair<TimeAxisView*,double> res; @@ -1343,7 +1341,8 @@ Editor::scroll_down_one_track () continue; } - res = (*t)->covers_y_position (vertical_pos); + /* find the trackview at the bottom of the trackview group */ + res = (*t)->covers_y_position (_visible_canvas_height); if (res.first) { break; @@ -1376,7 +1375,8 @@ Editor::scroll_up_one_track () continue; } - res = (*t)->covers_y_position(vertical_pos); + /* find the trackview at the top of the trackview group */ + res = (*t)->covers_y_position (0); if (res.first) { break; diff --git a/gtk2_ardour/region_view.cc b/gtk2_ardour/region_view.cc index 127ce79b84..dfdf0651f6 100644 --- a/gtk2_ardour/region_view.cc +++ b/gtk2_ardour/region_view.cc @@ -694,7 +694,18 @@ RegionView::move (double x_delta, double y_delta) return; } - get_canvas_group()->move (ArdourCanvas::Duple (x_delta, y_delta)); + /* items will not prevent Item::move() moving + * them to a negative x-axis coordinate, which + * is legal, but we don't want that here. + */ + + ArdourCanvas::Item *item = get_canvas_group (); + + if (item->position().x + x_delta < 0) { + x_delta = -item->position().x; /* move it to zero */ + } + + item->move (ArdourCanvas::Duple (x_delta, y_delta)); /* note: ghosts never leave their tracks so y_delta for them is always zero */ diff --git a/gtk2_ardour/time_axis_view.cc b/gtk2_ardour/time_axis_view.cc index f67ca6a3ce..e36b78daaf 100644 --- a/gtk2_ardour/time_axis_view.cc +++ b/gtk2_ardour/time_axis_view.cc @@ -1151,9 +1151,12 @@ TimeAxisView::color_handler () } /** @return Pair: TimeAxisView, layer index. - * TimeAxisView is non-0 if this object covers y, or one of its children does. + * TimeAxisView is non-0 if this object covers @param y, or one of its children + * does. @param y is an offset from the top of the trackview area. + * * If the covering object is a child axis, then the child is returned. * TimeAxisView is 0 otherwise. + * * Layer index is the layer number (possibly fractional) if the TimeAxisView is valid * and is in stacked or expanded * region display mode, otherwise 0. */ diff --git a/libs/canvas/canvas.cc b/libs/canvas/canvas.cc index e6feca6416..8638344966 100644 --- a/libs/canvas/canvas.cc +++ b/libs/canvas/canvas.cc @@ -207,46 +207,63 @@ Canvas::item_changed (Item* item, boost::optional<Rect> pre_change_bounding_box) Duple Canvas::window_to_canvas (Duple const & d) const { + /* Find the scroll group that covers d (a window coordinate). Scroll groups are only allowed + * as children of the root group, so we just scan its first level + * children and see what we can find. + */ + + std::list<Item*> const& root_children (_root.items()); + ScrollGroup* sg = 0; + + for (std::list<Item*>::const_iterator i = root_children.begin(); i != root_children.end(); ++i) { + if (((sg = dynamic_cast<ScrollGroup*>(*i)) != 0) && sg->covers_window (d)) { + break; + } + } + + if (sg) { + return d.translate (sg->scroll_offset()); + } + + /* fallback to global canvas offset ... it would be nice to remove this */ + return d.translate (_scroll_offset); } Duple Canvas::canvas_to_window (Duple const & d, bool rounded) const { - Duple wd = d.translate (-_scroll_offset); + /* Find the scroll group that covers d (a canvas coordinate). Scroll groups are only allowed + * as children of the root group, so we just scan its first level + * children and see what we can find. + */ - /* Note that this intentionally almost always returns integer coordinates */ + std::list<Item*> const& root_children (_root.items()); + ScrollGroup* sg = 0; + Duple wd; - if (rounded) { - wd.x = round (wd.x); - wd.y = round (wd.y); + for (std::list<Item*>::const_iterator i = root_children.begin(); i != root_children.end(); ++i) { + if (((sg = dynamic_cast<ScrollGroup*>(*i)) != 0) && sg->covers_canvas (d)) { + break; + } } + - return wd; -} - -Rect -Canvas::window_to_canvas (Rect const & r) const -{ - return r.translate (Duple (_scroll_offset.x, _scroll_offset.y)); -} - -Rect -Canvas::canvas_to_window (Rect const & r, bool rounded) const -{ - Rect wr = r.translate (Duple (-_scroll_offset.x, -_scroll_offset.y)); + if (sg) { + wd = d.translate (-sg->scroll_offset()); + } else { + wd = d.translate (-_scroll_offset); + } /* Note that this intentionally almost always returns integer coordinates */ if (rounded) { - wr.x0 = round (wr.x0); - wr.x1 = round (wr.x1); - wr.y0 = round (wr.y0); - wr.y1 = round (wr.y1); + wd.x = round (wd.x); + wd.y = round (wd.y); } - return wr; -} + return wd; +} /** Called when an item has moved. * @param item Item that has moved. diff --git a/libs/canvas/canvas/canvas.h b/libs/canvas/canvas/canvas.h index 1f801c3f00..187a773104 100644 --- a/libs/canvas/canvas/canvas.h +++ b/libs/canvas/canvas/canvas.h @@ -90,8 +90,7 @@ public: void item_moved (Item *, boost::optional<Rect>); virtual Cairo::RefPtr<Cairo::Context> context () = 0; - Rect canvas_to_window (Rect const&, bool rounded = true) const; - Rect window_to_canvas (Rect const&) const; + Duple canvas_to_window (Duple const&, bool rounded = true) const; Duple window_to_canvas (Duple const&) const; diff --git a/libs/canvas/canvas/item.h b/libs/canvas/canvas/item.h index fd41ddd4c5..5483c5124c 100644 --- a/libs/canvas/canvas/item.h +++ b/libs/canvas/canvas/item.h @@ -129,6 +129,10 @@ public: return _position; } + Duple window_origin() const; + + ScrollGroup* scroll_parent() const { return _scroll_parent; } + boost::optional<Rect> bounding_box () const; Coord height() const; Coord width() const; diff --git a/libs/canvas/canvas/scroll_group.h b/libs/canvas/canvas/scroll_group.h index 2df491e93b..d33e9b9080 100644 --- a/libs/canvas/canvas/scroll_group.h +++ b/libs/canvas/canvas/scroll_group.h @@ -37,6 +37,9 @@ class LIBCANVAS_API ScrollGroup : public Group void scroll_to (Duple const& d); Duple scroll_offset() const { return _scroll_offset; } + bool covers_canvas (Duple const& d) const; + bool covers_window (Duple const& d) const; + private: ScrollSensitivity _scroll_sensitivity; Duple _scroll_offset; diff --git a/libs/canvas/item.cc b/libs/canvas/item.cc index 3b13a12ca8..ddc05a817a 100644 --- a/libs/canvas/item.cc +++ b/libs/canvas/item.cc @@ -82,6 +82,20 @@ Item::~Item () } } +Duple +Item::window_origin () const +{ + /* This is slightly subtle. Our _position is in the coordinate space of + our parent. So to find out where that is in window coordinates, we + have to ask our parent. + */ + if (_parent) { + return _parent->item_to_window (_position); + } else { + return _parent->item_to_window (Duple (0,0)); + } +} + ArdourCanvas::Rect Item::item_to_parent (ArdourCanvas::Rect const & r) const { diff --git a/libs/canvas/scroll_group.cc b/libs/canvas/scroll_group.cc index 76bca50aee..615be8007c 100644 --- a/libs/canvas/scroll_group.cc +++ b/libs/canvas/scroll_group.cc @@ -49,3 +49,29 @@ ScrollGroup::scroll_to (Duple const& d) _scroll_offset.y = d.y; } } + +bool +ScrollGroup::covers_canvas (Duple const& d) const +{ + boost::optional<Rect> r = bounding_box (); + + if (!r) { + return false; + } + + return r->contains (d); +} + +bool +ScrollGroup::covers_window (Duple const& d) const +{ + boost::optional<Rect> r = bounding_box (); + + if (!r) { + return false; + } + + Rect w = r->translate (-_scroll_offset); + + return w.contains (d); +} |