From ea2648503b520e3da54263ce0bafb388d22a9cd8 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 6 Sep 2010 12:34:11 +0000 Subject: Cleanup of region drag code to be a bit more efficient and shorter. Fixes crashes when dragging regions to the wrong track type. git-svn-id: svn://localhost/ardour2/branches/3.0@7744 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/canvas-hit.cc | 2 +- gtk2_ardour/canvas-note.cc | 2 +- gtk2_ardour/edit_note_dialog.cc | 4 +- gtk2_ardour/editor_drag.cc | 828 ++++++++++++------------------------- gtk2_ardour/editor_drag.h | 45 +- gtk2_ardour/editor_ops.cc | 4 +- gtk2_ardour/editor_selection.cc | 4 +- gtk2_ardour/region_selection.cc | 6 +- gtk2_ardour/selection.cc | 16 +- gtk2_ardour/time_axis_view_item.cc | 2 +- gtk2_ardour/time_axis_view_item.h | 4 +- libs/ardour/ardour/audio_track.h | 4 + libs/ardour/ardour/midi_track.h | 4 + libs/ardour/ardour/track.h | 2 + 14 files changed, 324 insertions(+), 603 deletions(-) diff --git a/gtk2_ardour/canvas-hit.cc b/gtk2_ardour/canvas-hit.cc index 6fcc68f599..03b7a04043 100644 --- a/gtk2_ardour/canvas-hit.cc +++ b/gtk2_ardour/canvas-hit.cc @@ -26,7 +26,7 @@ bool CanvasHit::on_event(GdkEvent* ev) { if (!CanvasNoteEvent::on_event (ev)) { - return _region.get_trackview().editor().canvas_note_event (ev, this); + return _region.get_time_axis_view().editor().canvas_note_event (ev, this); } return true; } diff --git a/gtk2_ardour/canvas-note.cc b/gtk2_ardour/canvas-note.cc index 35f7ace581..e130791f08 100644 --- a/gtk2_ardour/canvas-note.cc +++ b/gtk2_ardour/canvas-note.cc @@ -23,7 +23,7 @@ bool CanvasNote::on_event(GdkEvent* ev) { if (!CanvasNoteEvent::on_event (ev)) { - return _region.get_trackview().editor().canvas_note_event (ev, this); + return _region.get_time_axis_view().editor().canvas_note_event (ev, this); } return true; diff --git a/gtk2_ardour/edit_note_dialog.cc b/gtk2_ardour/edit_note_dialog.cc index fe45093057..b84be45413 100644 --- a/gtk2_ardour/edit_note_dialog.cc +++ b/gtk2_ardour/edit_note_dialog.cc @@ -80,7 +80,7 @@ EditNoteDialog::EditNoteDialog (MidiRegionView* rv, Gnome::Canvas::CanvasNoteEve table->attach (_time_clock, 1, 2, r, r + 1); ++r; - _time_clock.set_session (_region_view->get_trackview().session ()); + _time_clock.set_session (_region_view->get_time_axis_view().session ()); _time_clock.set_mode (AudioClock::BBT); _time_clock.set (_region_view->time_converter().to (ev->note()->time ()), true); @@ -90,7 +90,7 @@ EditNoteDialog::EditNoteDialog (MidiRegionView* rv, Gnome::Canvas::CanvasNoteEve table->attach (_length_clock, 1, 2, r, r + 1); ++r; - _length_clock.set_session (_region_view->get_trackview().session ()); + _length_clock.set_session (_region_view->get_time_axis_view().session ()); _length_clock.set_mode (AudioClock::BBT); _length_clock.set (_region_view->time_converter().to (ev->note()->length ()), true); diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index 90e67d77af..0642cc7545 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -332,12 +332,40 @@ Drag::abort () _editor->hide_verbose_canvas_cursor (); } +struct EditorOrderTimeAxisViewSorter { + bool operator() (TimeAxisView* a, TimeAxisView* b) { + RouteTimeAxisView* ra = dynamic_cast (a); + RouteTimeAxisView* rb = dynamic_cast (b); + assert (ra && rb); + return ra->route()->order_key (N_ ("editor")) < rb->route()->order_key (N_ ("editor")); + } +}; + RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list const & v) : Drag (e, i), _primary (p) { + _editor->visible_order_range (&_visible_y_low, &_visible_y_high); + + /* Make a list of non-hidden tracks to refer to during the drag */ + + TrackViewList track_views = _editor->track_views; + track_views.sort (EditorOrderTimeAxisViewSorter ()); + + for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { + if (!(*i)->hidden()) { + + _time_axis_views.push_back (*i); + + TimeAxisView::Children children_list = (*i)->get_child_list (); + for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) { + _time_axis_views.push_back (j->get()); + } + } + } + for (list::const_iterator i = v.begin(); i != v.end(); ++i) { - _views.push_back (DraggingView (*i)); + _views.push_back (DraggingView (*i, this)); } RegionView::RegionViewGoingAway.connect (death_connection, invalidator (*this), ui_bind (&RegionDrag::region_going_away, this, _1), gui_context()); @@ -356,10 +384,25 @@ RegionDrag::region_going_away (RegionView* v) } } +/** Given a non-hidden TimeAxisView, return the index of it into the _time_axis_views vector */ +int +RegionDrag::find_time_axis_view (TimeAxisView* t) const +{ + int i = 0; + int const N = _time_axis_views.size (); + while (i < N && _time_axis_views[i] != t) { + ++i; + } + + if (i == N) { + return -1; + } + + return i; +} + RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list const & v, bool b) : RegionDrag (e, i, p, v), - _dest_trackview (0), - _dest_layer (0), _brushing (b), _total_x_delta (0) { @@ -368,143 +411,17 @@ RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView void -RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor *) +RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) { - Drag::start_grab (event); + Drag::start_grab (event, cursor); _editor->show_verbose_time_cursor (_last_frame_position, 10); -} - -RegionMotionDrag::TimeAxisViewSummary -RegionMotionDrag::get_time_axis_view_summary () -{ - int32_t children = 0; - TimeAxisViewSummary sum; - - _editor->visible_order_range (&sum.visible_y_low, &sum.visible_y_high); - - /* get a bitmask representing the visible tracks */ - - for (TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) { - RouteTimeAxisView* rtv = dynamic_cast (*i); - TimeAxisView::Children children_list; - - /* zeroes are audio/MIDI tracks. ones are other types. */ - - if (!rtv->hidden()) { - - if (!rtv->is_track()) { - /* not an audio nor MIDI track */ - sum.tracks = sum.tracks |= (0x01 << rtv->order()); - } - - sum.height_list[rtv->order()] = (*i)->current_height(); - children = 1; - - if ((children_list = rtv->get_child_list()).size() > 0) { - for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) { - sum.tracks = sum.tracks |= (0x01 << (rtv->order() + children)); - sum.height_list[rtv->order() + children] = (*j)->current_height(); - children++; - } - } - } - } - - return sum; -} - -bool -RegionMotionDrag::compute_y_delta ( - TimeAxisView const * last_pointer_view, TimeAxisView* current_pointer_view, - int32_t last_pointer_layer, int32_t current_pointer_layer, - TimeAxisViewSummary const & tavs, - int32_t* pointer_order_span, int32_t* pointer_layer_span, - int32_t* canvas_pointer_order_span - ) -{ - if (_brushing) { - *pointer_order_span = 0; - *pointer_layer_span = 0; - return true; - } - - bool clamp_y_axis = false; - - /* the change in track order between this callback and the last */ - *pointer_order_span = last_pointer_view->order() - current_pointer_view->order(); - /* the change in layer between this callback and the last; - only meaningful if pointer_order_span == 0 (ie we've not moved tracks) */ - *pointer_layer_span = last_pointer_layer - current_pointer_layer; - - if (*pointer_order_span != 0) { - - /* find the actual pointer span, in terms of the number of visible tracks; - to do this, we reduce |pointer_order_span| by the number of hidden tracks - over the span */ - - *canvas_pointer_order_span = *pointer_order_span; - if (last_pointer_view->order() >= current_pointer_view->order()) { - for (int32_t y = current_pointer_view->order(); y < last_pointer_view->order(); y++) { - if (tavs.height_list[y] == 0) { - *canvas_pointer_order_span--; - } - } - } else { - for (int32_t y = last_pointer_view->order(); y <= current_pointer_view->order(); y++) { - if (tavs.height_list[y] == 0) { - *canvas_pointer_order_span++; - } - } - } - - for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { - - RegionView* rv = i->view; - if (rv->region()->locked()) { - continue; - } - - double ix1, ix2, iy1, iy2; - rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2); - rv->get_canvas_frame()->i2w (ix1, iy1); - iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize; - - /* get the new trackview for this particular region */ - pair const tvp = _editor->trackview_by_y_position (iy1); - assert (tvp.first); - RouteTimeAxisView* rtv = dynamic_cast (tvp.first); - - /* XXX: not sure that we should be passing canvas_pointer_order_span in here, - as surely this is a per-region thing... */ - - clamp_y_axis = y_movement_disallowed ( - rtv->order(), last_pointer_view->order(), *canvas_pointer_order_span, tavs - ); - - if (clamp_y_axis) { - break; - } - } - - } else if (_dest_trackview == current_pointer_view) { - - if (current_pointer_layer == last_pointer_layer) { - /* No movement; clamp */ - clamp_y_axis = true; - } - } - - if (!clamp_y_axis) { - _dest_trackview = current_pointer_view; - _dest_layer = current_pointer_layer; - } - - return clamp_y_axis; + pair const tv = _editor->trackview_by_y_position (_drags->current_pointer_y ()); + _last_pointer_time_axis_view = find_time_axis_view (tv.first); + _last_pointer_layer = tv.first->layer_display() == Overlaid ? 0 : tv.second; } - double RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_region_position) { @@ -539,7 +456,10 @@ RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_ double dx = 0; - if ((*pending_region_position != _last_frame_position) && x_move_allowed ()) { + /* in locked edit mode, reverse the usual meaning of _x_constrained */ + bool const x_move_allowed = Config->get_edit_mode() == Lock ? _x_constrained : !_x_constrained; + + if ((*pending_region_position != _last_frame_position) && x_move_allowed) { /* x movement since last time */ dx = (static_cast (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit; @@ -565,67 +485,78 @@ RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_ return dx; } -void -RegionMotionDrag::motion (GdkEvent* event, bool first_move) +bool +RegionMotionDrag::y_movement_allowed (int delta_track, layer_t delta_layer) const { - double y_delta = 0; + for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { + int const n = i->time_axis_view + delta_track; + if (n < 0 || n >= int (_time_axis_views.size())) { + /* off the top or bottom track */ + return false; + } - TimeAxisViewSummary tavs = get_time_axis_view_summary (); + RouteTimeAxisView const * to = dynamic_cast (_time_axis_views[n]); + if (to == 0 || !to->is_track() || to->track()->data_type() != i->view->region()->data_type()) { + /* not a track, or the wrong type */ + return false; + } + + int const l = i->layer + delta_layer; + if (delta_track == 0 && (l < 0 || l >= int (to->view()->layers()))) { + /* Off the top or bottom layer; note that we only refuse if the track hasn't changed. + If it has, the layers will be munged later anyway, so it's ok. + */ + return false; + } + } - vector::iterator j; + /* all regions being dragged are ok with this change */ + return true; +} - /* *pointer* variables reflect things about the pointer; as we may be moving - multiple regions, much detail must be computed per-region */ +void +RegionMotionDrag::motion (GdkEvent* event, bool first_move) +{ + /* Find the TimeAxisView that the pointer is now over */ + pair const tv = _editor->trackview_by_y_position (_drags->current_pointer_y ()); - /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and - current_pointer_layer the current layer on that TimeAxisView; in this code layer numbers - are with respect to how the view's layers are displayed; if we are in Overlaid mode, layer - is always 0 regardless of what the region's "real" layer is */ - RouteTimeAxisView* current_pointer_view; - layer_t current_pointer_layer; - if (!check_possible (¤t_pointer_view, ¤t_pointer_layer)) { + /* Bail early if we're not over a track */ + RouteTimeAxisView* rtv = dynamic_cast (tv.first); + if (!rtv || !rtv->is_track()) { + _editor->hide_verbose_canvas_cursor (); return; } - /* TimeAxisView that we were pointing at last time we entered this method */ - TimeAxisView const * const last_pointer_view = _dest_trackview; - /* the order of the track that we were pointing at last time we entered this method */ - int32_t const last_pointer_order = last_pointer_view->order (); - /* the layer that we were pointing at last time we entered this method */ - layer_t const last_pointer_layer = _dest_layer; - - int32_t pointer_order_span; - int32_t pointer_layer_span; - int32_t canvas_pointer_order_span; + /* Note: time axis views in this method are often expressed as an index into the _time_axis_views vector */ - bool const clamp_y_axis = compute_y_delta ( - last_pointer_view, current_pointer_view, - last_pointer_layer, current_pointer_layer, tavs, - &pointer_order_span, &pointer_layer_span, - &canvas_pointer_order_span - ); + /* Here's the current pointer position in terms of time axis view and layer */ + int const current_pointer_time_axis_view = find_time_axis_view (tv.first); + layer_t const current_pointer_layer = tv.first->layer_display() == Overlaid ? 0 : tv.second; - nframes64_t pending_region_position; + /* Work out the change in x */ + framepos_t pending_region_position; double const x_delta = compute_x_delta (event, &pending_region_position); - /************************************************************* - PREPARE TO MOVE - ************************************************************/ + /* Work out the change in y */ + int delta_time_axis_view = current_pointer_time_axis_view - _last_pointer_time_axis_view; + int delta_layer = current_pointer_layer - _last_pointer_layer; - if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0 && !first_move) { + if (!y_movement_allowed (delta_time_axis_view, delta_layer)) { + /* this y movement is not allowed, so do no y movement this time */ + delta_time_axis_view = 0; + delta_layer = 0; + } + + if (x_delta == 0 && delta_time_axis_view == 0 && delta_layer == 0 && !first_move) { /* haven't reached next snap point, and we're not switching trackviews nor layers. nothing to do. */ return; } - /************************************************************* - MOTION - ************************************************************/ - pair >::iterator,bool> insert_result; - for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { + for (list::iterator i = _views.begin(); i != _views.end(); ++i) { RegionView* rv = i->view; @@ -633,149 +564,91 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move) continue; } - /* here we are calculating the y distance from the - top of the first track view to the top of the region - area of the track view that we're working on */ - - /* this x value is just a dummy value so that we have something - to pass to i2w () */ - - double ix1 = 0; - - /* distance from the top of this track view to the region area - of our track view is always 1 */ - - double iy1 = 1; - - /* convert to world coordinates, ie distance from the top of - the ruler section */ - - rv->get_canvas_frame()->i2w (ix1, iy1); - - /* compensate for the ruler section and the vertical scrollbar position */ - iy1 += _editor->get_trackview_group_vertical_offset (); - if (first_move) { + /* here we are calculating the y distance from the + top of the first track view to the top of the region + area of the track view that we're working on */ + + /* this x value is just a dummy value so that we have something + to pass to i2w () */ + + double ix1 = 0; + + /* distance from the top of this track view to the region area + of our track view is always 1 */ + + double iy1 = 1; + + /* convert to world coordinates, ie distance from the top of + the ruler section */ + + rv->get_canvas_frame()->i2w (ix1, iy1); + + /* compensate for the ruler section and the vertical scrollbar position */ + iy1 += _editor->get_trackview_group_vertical_offset (); + // hide any dependent views - + rv->get_time_axis_view().hide_dependent_views (*rv); - + /* - reparent to a non scrolling group so that we can keep the - region selection above all time axis views. - reparenting means we have to move the rv as the two - parent groups have different coordinates. + reparent to a non scrolling group so that we can keep the + region selection above all time axis views. + reparenting means we have to move the rv as the two + parent groups have different coordinates. */ - + rv->get_canvas_group()->property_y() = iy1 - 1; - rv->get_canvas_group()->reparent(*(_editor->_region_motion_group)); - + rv->get_canvas_group()->reparent (*(_editor->_region_motion_group)); + rv->fake_set_opaque (true); } - /* current view for this particular region */ - pair pos = _editor->trackview_by_y_position (iy1); - RouteTimeAxisView* rtv = dynamic_cast (pos.first); - - if (pointer_order_span != 0 && !clamp_y_axis) { - - /* INTER-TRACK MOVEMENT */ + /* Work out the change in y position of this region view */ - /* move through the height list to the track that the region is currently on */ - vector::iterator j = tavs.height_list.begin (); - int32_t x = 0; - while (j != tavs.height_list.end () && x != rtv->order ()) { - ++x; - ++j; - } + double y_delta = 0; - y_delta = 0; - int32_t temp_pointer_order_span = canvas_pointer_order_span; - - if (j != tavs.height_list.end ()) { - - /* Account for layers in the original and - destination tracks. If we're moving around in layers we assume - that only one track is involved, so it's ok to use *pointer* - variables here. */ - - StreamView* lv = last_pointer_view->view (); - assert (lv); - - /* move to the top of the last trackview */ - if (lv->layer_display () == Stacked) { - y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height (); - } - - StreamView* cv = current_pointer_view->view (); - assert (cv); - - /* move to the right layer on the current trackview */ - if (cv->layer_display () == Stacked) { - y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height (); - } - - /* And for being on a non-topmost layer on the new - track */ - - while (temp_pointer_order_span > 0) { - /* we're moving up canvas-wise, - so we need to find the next track height - */ - if (j != tavs.height_list.begin()) { - j--; - } - - if (x != last_pointer_order) { - if ((*j) == 0) { - ++temp_pointer_order_span; - } - } - - y_delta -= (*j); - temp_pointer_order_span--; - } - - while (temp_pointer_order_span < 0) { - - y_delta += (*j); - - if (x != last_pointer_order) { - if ((*j) == 0) { - --temp_pointer_order_span; - } - } - - if (j != tavs.height_list.end()) { - j++; - } - - temp_pointer_order_span++; - } - - - /* find out where we'll be when we move and set height accordingly */ + /* If we have moved tracks, we'll fudge the layer delta so that the + region gets moved back onto layer 0 on its new track; this avoids + confusion when dragging regions from non-zero layers onto different + tracks. + */ + int this_delta_layer = delta_layer; + if (delta_time_axis_view != 0) { + this_delta_layer = - i->layer; + } - pair const pos = _editor->trackview_by_y_position (iy1 + y_delta); - RouteTimeAxisView const * temp_rtv = dynamic_cast (pos.first); - rv->set_height (temp_rtv->view()->child_height()); + /* Move this region to layer 0 on its old track */ + StreamView* lv = _time_axis_views[i->time_axis_view]->view (); + if (lv->layer_display() == Stacked) { + y_delta -= (lv->layers() - i->layer - 1) * lv->child_height (); + } - /* if you un-comment the following, the region colours will follow - the track colours whilst dragging; personally - i think this can confuse things, but never mind. - */ + /* Now move it to its right layer on the current track */ + StreamView* cv = _time_axis_views[i->time_axis_view + delta_time_axis_view]->view (); + if (cv->layer_display() == Stacked) { + y_delta += (cv->layers() - (i->layer + this_delta_layer) - 1) * cv->child_height (); + } - //const GdkColor& col (temp_rtv->view->get_region_color()); - //rv->set_color (const_cast(col)); + /* Move tracks */ + if (delta_time_axis_view > 0) { + for (int j = 0; j < delta_time_axis_view; ++j) { + y_delta += _time_axis_views[i->time_axis_view + j]->current_height (); + } + } else { + /* start by subtracting the height of the track above where we are now */ + for (int j = 1; j <= -delta_time_axis_view; ++j) { + y_delta -= _time_axis_views[i->time_axis_view - j]->current_height (); } } - if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) { + /* Set height */ + rv->set_height (_time_axis_views[i->time_axis_view + delta_time_axis_view]->view()->child_height ()); - /* INTER-LAYER MOVEMENT in the same track */ - y_delta = rtv->view()->child_height () * pointer_layer_span; - } + /* Update the DraggingView */ + i->time_axis_view += delta_time_axis_view; + i->layer += this_delta_layer; if (_brushing) { _editor->mouse_brush_insert_region (rv, pending_region_position); @@ -794,20 +667,82 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move) if (x_delta != 0 && !_brushing) { _editor->show_verbose_time_cursor (_last_frame_position, 10); } + + _last_pointer_time_axis_view += delta_time_axis_view; + _last_pointer_layer += delta_layer; } void RegionMoveDrag::motion (GdkEvent* event, bool first_move) { if (_copy && first_move) { - copy_regions (event); + + /* duplicate the regionview(s) and region(s) */ + + list new_regionviews; + + for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { + + RegionView* rv = i->view; + AudioRegionView* arv = dynamic_cast(rv); + MidiRegionView* mrv = dynamic_cast(rv); + + const boost::shared_ptr original = rv->region(); + boost::shared_ptr region_copy = RegionFactory::create (original); + region_copy->set_position (original->position(), this); + + RegionView* nrv; + if (arv) { + boost::shared_ptr audioregion_copy + = boost::dynamic_pointer_cast(region_copy); + + nrv = new AudioRegionView (*arv, audioregion_copy); + } else if (mrv) { + boost::shared_ptr midiregion_copy + = boost::dynamic_pointer_cast(region_copy); + nrv = new MidiRegionView (*mrv, midiregion_copy); + } else { + continue; + } + + nrv->get_canvas_group()->show (); + new_regionviews.push_back (DraggingView (nrv, this)); + + /* swap _primary to the copy */ + + if (rv == _primary) { + _primary = nrv; + } + + /* ..and deselect the one we copied */ + + rv->set_selected (false); + } + + if (!new_regionviews.empty()) { + + /* reflect the fact that we are dragging the copies */ + + _views = new_regionviews; + + swap_grab (new_regionviews.front().view->get_canvas_group (), 0, event ? event->motion.time : 0); + + /* + sync the canvas to what we think is its current state + without it, the canvas seems to + "forget" to update properly after the upcoming reparent() + ..only if the mouse is in rapid motion at the time of the grab. + something to do with regionview creation taking so long? + */ + _editor->update_canvas_now(); + } } RegionMotionDrag::motion (event, first_move); } void -RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred) +RegionMoveDrag::finished (GdkEvent *, bool movement_occurred) { if (!movement_occurred) { /* just a click */ @@ -823,7 +758,7 @@ RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred) } bool const changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position())); - bool const changed_tracks = (_dest_trackview != &_primary->get_time_axis_view()); + bool const changed_tracks = (_time_axis_views[_views.front().time_axis_view] != &_views.front().view->get_time_axis_view()); framecnt_t const drag_delta = _primary->region()->position() - _last_frame_position; _editor->update_canvas_now (); @@ -831,7 +766,6 @@ RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred) if (_copy) { finished_copy ( - find_time_axis_views_and_layers (), changed_position, changed_tracks, drag_delta @@ -840,7 +774,6 @@ RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred) } else { finished_no_copy ( - find_time_axis_views_and_layers (), changed_position, changed_tracks, drag_delta @@ -851,7 +784,6 @@ RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred) void RegionMoveDrag::finished_copy ( - map > const & final, bool const changed_position, bool const changed_tracks, framecnt_t const drag_delta @@ -881,23 +813,20 @@ RegionMoveDrag::finished_copy ( /* insert the regions into their new playlists */ for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { - nframes64_t where; - if (i->view->region()->locked()) { continue; } + nframes64_t where; + if (changed_position && !_x_constrained) { where = i->view->region()->position() - drag_delta; } else { where = i->view->region()->position(); } - map >::const_iterator j = final.find (i->view); - assert (j != final.end()); - RegionView* new_view = insert_region_into_playlist ( - i->view->region(), j->second.first, j->second.second, where, modified_playlists + i->view->region(), dynamic_cast (_time_axis_views[i->time_axis_view]), i->layer, where, modified_playlists ); if (new_view == 0) { @@ -934,7 +863,6 @@ RegionMoveDrag::finished_copy ( void RegionMoveDrag::finished_no_copy ( - map > const & final, bool const changed_position, bool const changed_tracks, framecnt_t const drag_delta @@ -960,11 +888,8 @@ RegionMoveDrag::finished_no_copy ( RegionView* rv = i->view; - map >::const_iterator j = final.find (rv); - assert (j != final.end()); - - RouteTimeAxisView* dest_rtv = j->second.first; - layer_t dest_layer = j->second.second; + RouteTimeAxisView* const dest_rtv = dynamic_cast (_time_axis_views[i->time_axis_view]); + layer_t const dest_layer = i->layer; if (rv->region()->locked()) { ++i; @@ -1226,212 +1151,12 @@ RegionMotionDrag::aborted () _editor->update_canvas_now (); } - -bool -RegionMotionDrag::x_move_allowed () const -{ - if (Config->get_edit_mode() == Lock) { - /* in locked edit mode, reverse the usual meaning of _x_constrained */ - return _x_constrained; - } - - return !_x_constrained; -} - -void -RegionMotionDrag::copy_regions (GdkEvent* event) -{ - /* duplicate the regionview(s) and region(s) */ - - list new_regionviews; - - for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { - - RegionView* rv = i->view; - AudioRegionView* arv = dynamic_cast(rv); - MidiRegionView* mrv = dynamic_cast(rv); - - const boost::shared_ptr original = rv->region(); - boost::shared_ptr region_copy = RegionFactory::create (original); - region_copy->set_position (original->position(), this); - - RegionView* nrv; - if (arv) { - boost::shared_ptr audioregion_copy - = boost::dynamic_pointer_cast(region_copy); - - nrv = new AudioRegionView (*arv, audioregion_copy); - } else if (mrv) { - boost::shared_ptr midiregion_copy - = boost::dynamic_pointer_cast(region_copy); - nrv = new MidiRegionView (*mrv, midiregion_copy); - } else { - continue; - } - - nrv->get_canvas_group()->show (); - new_regionviews.push_back (DraggingView (nrv)); - - /* swap _primary to the copy */ - - if (rv == _primary) { - _primary = nrv; - } - - /* ..and deselect the one we copied */ - - rv->set_selected (false); - } - - if (new_regionviews.empty()) { - return; - } - - /* reflect the fact that we are dragging the copies */ - - _views = new_regionviews; - - swap_grab (new_regionviews.front().view->get_canvas_group (), 0, event ? event->motion.time : 0); - - /* - sync the canvas to what we think is its current state - without it, the canvas seems to - "forget" to update properly after the upcoming reparent() - ..only if the mouse is in rapid motion at the time of the grab. - something to do with regionview creation taking so long? - */ - _editor->update_canvas_now(); -} - -bool -RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer) -{ - /* Which trackview is this ? */ - - pair const tvp = _editor->trackview_by_y_position (_drags->current_pointer_y ()); - (*tv) = dynamic_cast (tvp.first); - (*layer) = tvp.second; - - if (*tv && (*tv)->layer_display() == Overlaid) { - *layer = 0; - } - - /* The region motion is only processed if the pointer is over - an audio track. - */ - - if (!(*tv) || !(*tv)->is_track()) { - /* To make sure we hide the verbose canvas cursor when the mouse is - not held over and audiotrack. - */ - _editor->hide_verbose_canvas_cursor (); - return false; - } - - return true; -} - -/** @param new_order New track order. - * @param old_order Old track order. - * @param visible_y_low Lowest visible order. - * @return true if y movement should not happen, otherwise false. - */ -bool -RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const -{ - if (new_order != old_order) { - - /* this isn't the pointer track */ - - if (y_span > 0) { - - /* moving up the canvas */ - if ( (new_order - y_span) >= tavs.visible_y_low) { - - int32_t n = 0; - - /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */ - int32_t visible_tracks = 0; - while (visible_tracks < y_span ) { - visible_tracks++; - while (tavs.height_list[new_order - (visible_tracks - n)] == 0) { - /* passing through a hidden track */ - n--; - } - } - - if (tavs.tracks[new_order - (y_span - n)] != 0x00) { - /* moving to a non-track; disallow */ - return true; - } - - - } else { - /* moving beyond the lowest visible track; disallow */ - return true; - } - - } else if (y_span < 0) { - - /* moving down the canvas */ - if ((new_order - y_span) <= tavs.visible_y_high) { - - int32_t visible_tracks = 0; - int32_t n = 0; - while (visible_tracks > y_span ) { - visible_tracks--; - - while (tavs.height_list[new_order - (visible_tracks - n)] == 0) { - /* passing through a hidden track */ - n++; - } - } - - if (tavs.tracks[new_order - (y_span - n)] != 0x00) { - /* moving to a non-track; disallow */ - return true; - } - - - } else { - - /* moving beyond the highest visible track; disallow */ - return true; - } - } - - } else { - - /* this is the pointer's track */ - - if ((new_order - y_span) > tavs.visible_y_high) { - /* we will overflow */ - return true; - } else if ((new_order - y_span) < tavs.visible_y_low) { - /* we will overflow */ - return true; - } - } - - return false; -} - - RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list const & v, bool b, bool c) : RegionMotionDrag (e, i, p, v, b), _copy (c) { - TimeAxisView* const tv = &_primary->get_time_axis_view (); - - _dest_trackview = tv; - if (tv->layer_display() == Overlaid) { - _dest_layer = 0; - } else { - _dest_layer = _primary->region()->layer (); - } - double speed = 1; - RouteTimeAxisView* rtv = dynamic_cast (tv); + RouteTimeAxisView* rtv = dynamic_cast (&_primary->get_time_axis_view ()); if (rtv && rtv->is_track()) { speed = rtv->track()->speed (); } @@ -1457,44 +1182,19 @@ RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr r, Rout _primary->get_canvas_group()->show (); _primary->set_position (pos, 0); - _views.push_back (DraggingView (_primary)); + _views.push_back (DraggingView (_primary, this)); _last_frame_position = pos; _item = _primary->get_canvas_group (); - _dest_trackview = v; - _dest_layer = _primary->region()->layer (); } -map > -RegionMotionDrag::find_time_axis_views_and_layers () -{ - map > tav; - - for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { - - double ix1, ix2, iy1, iy2; - RegionView* rv = i->view; - rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2); - rv->get_canvas_frame()->i2w (ix1, iy1); - iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize; - - pair tv = _editor->trackview_by_y_position (iy1); - tav[rv] = make_pair (dynamic_cast (tv.first), tv.second); - } - - return tav; -} - - void -RegionInsertDrag::finished (GdkEvent* /*event*/, bool /*movement_occurred*/) +RegionInsertDrag::finished (GdkEvent *, bool) { _editor->update_canvas_now (); - map > final = find_time_axis_views_and_layers (); - - RouteTimeAxisView* dest_rtv = final[_primary].first; + RouteTimeAxisView* dest_rtv = dynamic_cast (_time_axis_views[_views.front().time_axis_view]); _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item()); _primary->get_canvas_group()->property_y() = 0; @@ -1535,10 +1235,25 @@ struct RegionSelectionByPosition { void RegionSpliceDrag::motion (GdkEvent* event, bool) { - RouteTimeAxisView* tv; - layer_t layer; + /* Which trackview is this ? */ + + pair const tvp = _editor->trackview_by_y_position (_drags->current_pointer_y ()); + RouteTimeAxisView* tv = dynamic_cast (tvp.first); + layer_t layer = tvp.second; + + if (tv && tv->layer_display() == Overlaid) { + layer = 0; + } + + /* The region motion is only processed if the pointer is over + an audio track. + */ - if (!check_possible (&tv, &layer)) { + if (!tv || !tv->is_track()) { + /* To make sure we hide the verbose canvas cursor when the mouse is + not held over and audiotrack. + */ + _editor->hide_verbose_canvas_cursor (); return; } @@ -1591,9 +1306,9 @@ RegionSpliceDrag::motion (GdkEvent* event, bool) } void -RegionSpliceDrag::finished (GdkEvent* /*event*/, bool) +RegionSpliceDrag::finished (GdkEvent* event, bool movement_occurred) { - + RegionMoveDrag::finished (event, movement_occurred); } void @@ -1748,7 +1463,7 @@ TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, listget_time_axis_view (); @@ -3028,7 +2743,6 @@ FeatureLineDrag::FeatureLineDrag (Editor* e, ArdourCanvas::Item* i) void FeatureLineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/) { - Drag::start_grab (event); _line = reinterpret_cast (_item); @@ -3197,9 +2911,9 @@ RubberbandSelectDrag::aborted () } void -TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *) +TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) { - Drag::start_grab (event); + Drag::start_grab (event, cursor); _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10); } @@ -4074,9 +3788,11 @@ AutomationRangeDrag::aborted () _line->reset (); } -DraggingView::DraggingView (RegionView* v) +DraggingView::DraggingView (RegionView* v, RegionDrag* parent) : view (v) { + time_axis_view = parent->find_time_axis_view (&v->get_time_axis_view ()); + layer = v->region()->layer (); initial_y = v->get_canvas_group()->property_y (); initial_playlist = v->region()->playlist (); } diff --git a/gtk2_ardour/editor_drag.h b/gtk2_ardour/editor_drag.h index 0d0da70450..49d131b52b 100644 --- a/gtk2_ardour/editor_drag.h +++ b/gtk2_ardour/editor_drag.h @@ -221,11 +221,18 @@ private: nframes64_t _last_pointer_frame; ///< adjusted_frame the last time a motion occurred }; +class RegionDrag; + +/** Container for details about a region being dragged */ struct DraggingView { - DraggingView (RegionView* v); + DraggingView (RegionView *, RegionDrag *); RegionView* view; ///< the view + /** index into RegionDrag::_time_axis_views of the view that this region is currently beind displayed on */ + int time_axis_view; + /** layer that this region is currently being displayed on */ + ARDOUR::layer_t layer; double initial_y; ///< the initial y position of the view before any reparenting boost::shared_ptr initial_playlist; }; @@ -242,7 +249,17 @@ protected: RegionView* _primary; ///< the view that was clicked on (or whatever) to start the drag std::list _views; ///< information about all views that are being dragged + /** a list of the non-hidden TimeAxisViews sorted by editor order key */ + std::vector _time_axis_views; + int find_time_axis_view (TimeAxisView *) const; + + int _visible_y_low; + int _visible_y_high; + + friend class DraggingView; + private: + void region_going_away (RegionView *); PBD::ScopedConnection death_connection; }; @@ -267,33 +284,15 @@ public: virtual bool regions_came_from_canvas () const = 0; protected: - struct TimeAxisViewSummary { - TimeAxisViewSummary () : height_list(512) {} - std::bitset<512> tracks; - std::vector height_list; - int visible_y_low; - int visible_y_high; - }; - - void copy_regions (GdkEvent *); - bool y_movement_disallowed (int, int, int, TimeAxisViewSummary const &) const; - std::map > find_time_axis_views_and_layers (); double compute_x_delta (GdkEvent const *, nframes64_t *); - bool compute_y_delta ( - TimeAxisView const *, TimeAxisView*, int32_t, int32_t, TimeAxisViewSummary const &, - int32_t *, int32_t *, int32_t * - ); - - TimeAxisViewSummary get_time_axis_view_summary (); - bool x_move_allowed () const; + bool y_movement_allowed (int, ARDOUR::layer_t) const; - TimeAxisView* _dest_trackview; - ARDOUR::layer_t _dest_layer; - bool check_possible (RouteTimeAxisView **, ARDOUR::layer_t *); bool _brushing; nframes64_t _last_frame_position; ///< last position of the thing being dragged double _total_x_delta; + int _last_pointer_time_axis_view; + ARDOUR::layer_t _last_pointer_layer; }; @@ -323,14 +322,12 @@ private: typedef std::set > PlaylistSet; void finished_no_copy ( - std::map > const &, bool const, bool const, ARDOUR::framecnt_t const ); void finished_copy ( - std::map > const &, bool const, bool const, ARDOUR::framecnt_t const diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 12ebeacdd8..6ea2aede45 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -4131,7 +4131,7 @@ Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs) } } - TimeAxisView* tv = &(*x)->get_trackview(); + TimeAxisView* tv = &(*x)->get_time_axis_view(); vector::iterator z; for (z = pmap.begin(); z != pmap.end(); ++z) { @@ -4154,7 +4154,7 @@ Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs) continue; } - TimeAxisView& tv = (*x)->get_trackview(); + TimeAxisView& tv = (*x)->get_time_axis_view(); boost::shared_ptr npl; RegionSelection::iterator tmp; diff --git a/gtk2_ardour/editor_selection.cc b/gtk2_ardour/editor_selection.cc index 065145c417..806efaa66a 100644 --- a/gtk2_ardour/editor_selection.cc +++ b/gtk2_ardour/editor_selection.cc @@ -430,7 +430,7 @@ Editor::mapped_get_equivalent_regions (RouteTimeAxisView& tv, uint32_t, RegionVi void Editor::get_equivalent_regions (RegionView* basis, vector& equivalent_regions, PBD::PropertyID property) const { - mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), basis, &equivalent_regions), &basis->get_trackview(), property); + mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), basis, &equivalent_regions), &basis->get_time_axis_view(), property); /* add clicked regionview since we skipped all other regions in the same track as the one it was in */ @@ -448,7 +448,7 @@ Editor::get_equivalent_regions (RegionSelection & basis, PBD::PropertyID prop) c mapover_tracks ( sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_regions), *i, &eq), - &(*i)->get_trackview(), prop + &(*i)->get_time_axis_view(), prop ); for (vector::iterator j = eq.begin(); j != eq.end(); ++j) { diff --git a/gtk2_ardour/region_selection.cc b/gtk2_ardour/region_selection.cc index 9ac96d682b..1a5a556514 100644 --- a/gtk2_ardour/region_selection.cc +++ b/gtk2_ardour/region_selection.cc @@ -253,10 +253,10 @@ struct RegionSortByTrack { /* really, track and position */ - if (a->get_trackview().order() == b->get_trackview().order()) { + if (a->get_time_axis_view().order() == b->get_time_axis_view().order()) { return a->region()->position() < b->region()->position(); } else { - return a->get_trackview().order() < b->get_trackview().order(); + return a->get_time_axis_view().order() < b->get_time_axis_view().order(); } } }; @@ -298,7 +298,7 @@ bool RegionSelection::involves (const TimeAxisView& tv) const { for (RegionSelection::const_iterator i = begin(); i != end(); ++i) { - if (&(*i)->get_trackview() == &tv) { + if (&(*i)->get_time_axis_view() == &tv) { return true; } } diff --git a/gtk2_ardour/selection.cc b/gtk2_ardour/selection.cc index d04c986092..59928dc303 100644 --- a/gtk2_ardour/selection.cc +++ b/gtk2_ardour/selection.cc @@ -400,7 +400,7 @@ Selection::add (vector& v) if (find (regions.begin(), regions.end(), (*i)) == regions.end()) { changed = regions.add ((*i)); if (Config->get_link_region_and_track_selection() && changed) { - add (&(*i)->get_trackview()); + add (&(*i)->get_time_axis_view()); } } } @@ -422,7 +422,7 @@ Selection::add (const RegionSelection& rs) if (find (regions.begin(), regions.end(), (*i)) == regions.end()) { changed = regions.add ((*i)); if (Config->get_link_region_and_track_selection() && changed) { - add (&(*i)->get_trackview()); + add (&(*i)->get_time_axis_view()); } } } @@ -438,7 +438,7 @@ Selection::add (RegionView* r) if (find (regions.begin(), regions.end(), r) == regions.end()) { regions.add (r); if (Config->get_link_region_and_track_selection()) { - add (&r->get_trackview()); + add (&r->get_time_axis_view()); } RegionsChanged (); } @@ -452,7 +452,7 @@ Selection::add (MidiRegionView* mrv) /* XXX should we do this? */ #if 0 if (Config->get_link_region_and_track_selection()) { - add (&mrv->get_trackview()); + add (&mrv->get_time_axis_view()); } #endif MidiRegionsChanged (); @@ -610,8 +610,8 @@ Selection::remove (RegionView* r) RegionsChanged (); } - if (Config->get_link_region_and_track_selection() && !regions.involves (r->get_trackview())) { - remove (&r->get_trackview()); + if (Config->get_link_region_and_track_selection() && !regions.involves (r->get_time_axis_view())) { + remove (&r->get_time_axis_view()); } } @@ -627,8 +627,8 @@ Selection::remove (MidiRegionView* mrv) #if 0 /* XXX fix this up ? */ - if (Config->get_link_region_and_track_selection() && !regions.involves (r->get_trackview())) { - remove (&r->get_trackview()); + if (Config->get_link_region_and_track_selection() && !regions.involves (r->get_time_axis_view())) { + remove (&r->get_time_axis_view()); } #endif } diff --git a/gtk2_ardour/time_axis_view_item.cc b/gtk2_ardour/time_axis_view_item.cc index 309b4dd1cb..b4f32f4d6a 100644 --- a/gtk2_ardour/time_axis_view_item.cc +++ b/gtk2_ardour/time_axis_view_item.cc @@ -472,7 +472,7 @@ TimeAxisViewItem::set_should_show_selection (bool yn) /** @return the TimeAxisView that this item is on */ TimeAxisView& -TimeAxisViewItem::get_time_axis_view() +TimeAxisViewItem::get_time_axis_view () const { return trackview; } diff --git a/gtk2_ardour/time_axis_view_item.h b/gtk2_ardour/time_axis_view_item.h index 65f112bc90..79111bf28f 100644 --- a/gtk2_ardour/time_axis_view_item.h +++ b/gtk2_ardour/time_axis_view_item.h @@ -61,7 +61,7 @@ class TimeAxisViewItem : public Selectable, public PBD::ScopedConnectionList virtual void set_should_show_selection (bool yn); void set_sensitive (bool yn) { _sensitive = yn; } bool sensitive () const { return _sensitive; } - TimeAxisView& get_time_axis_view(); + TimeAxisView& get_time_axis_view () const; void set_name_text(const Glib::ustring&); virtual void set_height(double h); void set_y (double); @@ -72,8 +72,6 @@ class TimeAxisViewItem : public Selectable, public PBD::ScopedConnectionList ArdourCanvas::Item* get_name_highlight(); ArdourCanvas::Pixbuf* get_name_pixbuf(); - TimeAxisView& get_trackview() const { return trackview; } - virtual void set_samples_per_unit(double spu); double get_samples_per_unit(); diff --git a/libs/ardour/ardour/audio_track.h b/libs/ardour/ardour/audio_track.h index c2428339c7..ecd88b94e5 100644 --- a/libs/ardour/ardour/audio_track.h +++ b/libs/ardour/ardour/audio_track.h @@ -45,6 +45,10 @@ class AudioTrack : public Track void use_new_diskstream (); void set_diskstream (boost::shared_ptr); + DataType data_type () const { + return DataType::AUDIO; + } + int export_stuff (BufferSet& bufs, sframes_t start_frame, nframes_t nframes, bool enable_processing = true); void freeze_me (InterThreadInfo&); diff --git a/libs/ardour/ardour/midi_track.h b/libs/ardour/ardour/midi_track.h index 7e0525608d..ea2b0804f8 100644 --- a/libs/ardour/ardour/midi_track.h +++ b/libs/ardour/ardour/midi_track.h @@ -48,6 +48,10 @@ public: void set_diskstream (boost::shared_ptr); void set_record_enabled (bool yn, void *src); + DataType data_type () const { + return DataType::MIDI; + } + void set_latency_delay (nframes_t); int export_stuff (BufferSet& bufs, nframes_t nframes, sframes_t end_frame); diff --git a/libs/ardour/ardour/track.h b/libs/ardour/ardour/track.h index e40f197436..dfdc409659 100644 --- a/libs/ardour/ardour/track.h +++ b/libs/ardour/ardour/track.h @@ -60,6 +60,8 @@ class Track : public Route, public PublicDiskstream bool needs_butler() const { return _needs_butler; } void toggle_monitor_input (); + virtual DataType data_type () const = 0; + bool can_record(); virtual void use_new_diskstream () = 0; -- cgit v1.2.3