X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor_drag.cc;h=8869df8cfb41c1571c916f6c9be115062001a779;hb=b49e3982502f5e483422960dc11be967d7c790f4;hp=d451ef4aa941f047822342a41ed2b7dd7abe6437;hpb=4f7d94ea6768fdbd09c04346e0f30c9c11e96ce7;p=ardour.git diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index d451ef4aa9..8869df8cfb 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -32,8 +32,10 @@ #include "ardour/audioengine.h" #include "ardour/audioregion.h" +#include "ardour/audio_track.h" #include "ardour/dB.h" #include "ardour/midi_region.h" +#include "ardour/midi_track.h" #include "ardour/operations.h" #include "ardour/region_factory.h" #include "ardour/session.h" @@ -641,38 +643,40 @@ RegionMotionDrag::y_movement_allowed (int delta_track, double delta_layer) const void RegionMotionDrag::motion (GdkEvent* event, bool first_move) { - assert (!_views.empty ()); + double delta_layer = 0; + int delta_time_axis_view = 0; - /* Find the TimeAxisView that the pointer is now over */ - pair const tv = _editor->trackview_by_y_position (_drags->current_pointer_y ()); + assert (!_views.empty ()); - /* Bail early if we're not over a track */ - RouteTimeAxisView* rtv = dynamic_cast (tv.first); + /* Note: time axis views in this method are often expressed as an index into the _time_axis_views vector */ - if (!rtv || !rtv->is_track()) { - _editor->verbose_cursor()->hide (); - return; - } + /* Find the TimeAxisView that the pointer is now over */ + pair const r = _editor->trackview_by_y_position (_drags->current_pointer_y ()); + TimeAxisView* tv = r.first; - if (first_move && tv.first->view()->layer_display() == Stacked) { - tv.first->view()->set_layer_display (Expanded); - } + if (tv) { - /* Note: time axis views in this method are often expressed as an index into the _time_axis_views vector */ + double layer = r.second; + + if (first_move && tv->view()->layer_display() == Stacked) { + tv->view()->set_layer_display (Expanded); + } - /* 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); - double const current_pointer_layer = tv.first->layer_display() == Overlaid ? 0 : tv.second; + /* 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); + double const current_pointer_layer = tv->layer_display() == Overlaid ? 0 : layer; + + /* Work out the change in y */ + delta_time_axis_view = current_pointer_time_axis_view - _last_pointer_time_axis_view; + delta_layer = current_pointer_layer - _last_pointer_layer; + } + /* Work out the change in x */ framepos_t pending_region_position; double const x_delta = compute_x_delta (event, &pending_region_position); - /* Work out the change in y */ - - int delta_time_axis_view = current_pointer_time_axis_view - _last_pointer_time_axis_view; - double delta_layer = current_pointer_layer - _last_pointer_layer; - + /* Verify change in y */ 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; @@ -725,59 +729,71 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move) this_delta_layer = - i->layer; } - /* The TimeAxisView that this region is now on */ - TimeAxisView* tv = _time_axis_views[i->time_axis_view + delta_time_axis_view]; + if (tv) { - /* Ensure it is moved from stacked -> expanded if appropriate */ - if (tv->view()->layer_display() == Stacked) { - tv->view()->set_layer_display (Expanded); - } + /* The TimeAxisView that this region is now on */ + TimeAxisView* current_tv = _time_axis_views[i->time_axis_view + delta_time_axis_view]; + + /* Ensure it is moved from stacked -> expanded if appropriate */ + if (current_tv->view()->layer_display() == Stacked) { + current_tv->view()->set_layer_display (Expanded); + } - /* We're only allowed to go -ve in layer on Expanded views */ - if (tv->view()->layer_display() != Expanded && (i->layer + this_delta_layer) < 0) { - this_delta_layer = - i->layer; - } + /* We're only allowed to go -ve in layer on Expanded views */ + if (current_tv->view()->layer_display() != Expanded && (i->layer + this_delta_layer) < 0) { + this_delta_layer = - i->layer; + } - /* Set height */ - rv->set_height (tv->view()->child_height ()); + /* Set height */ + rv->set_height (current_tv->view()->child_height ()); - /* Update show/hidden status as the region view may have come from a hidden track, - or have moved to one. - */ - if (tv->hidden ()) { - rv->get_canvas_group()->hide (); - } else { - rv->get_canvas_group()->show (); - } + /* Update show/hidden status as the region view may have come from a hidden track, + or have moved to one. + */ + if (current_tv->hidden ()) { + rv->get_canvas_group()->hide (); + } else { + rv->get_canvas_group()->show (); + } - /* Update the DraggingView */ - i->time_axis_view += delta_time_axis_view; - i->layer += this_delta_layer; + /* 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); - } else { - double x = 0; - double y = 0; + 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 */ - tv->canvas_display()->item_to_canvas (x, y); + /* 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); - /* And adjust for the layer that it should be on */ - StreamView* cv = tv->view (); - switch (cv->layer_display ()) { - case Overlaid: - break; - case Stacked: - y += (cv->layers() - i->layer - 1) * cv->child_height (); - break; - case Expanded: - y += (cv->layers() - i->layer - 0.5) * 2 * cv->child_height (); - break; - } + /* 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 (); + break; + case Expanded: + y += (cv->layers() - i->layer - 0.5) * 2 * cv->child_height (); + break; + } - /* Now move the region view */ + /* Now move the region view */ + rv->move (x_delta, y - rv->get_canvas_group()->position().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; } } /* foreach region */ @@ -927,12 +943,36 @@ RegionMoveDrag::finished (GdkEvent* ev, bool movement_occurred) _editor->maybe_locate_with_edit_preroll (_editor->get_selection().regions.start()); } +RouteTimeAxisView* +RegionMoveDrag::create_destination_time_axis (boost::shared_ptr region) +{ + /* Add a new track of the correct type, and return the RouteTimeAxisView that is created to display the + new track. + */ + + try { + if (boost::dynamic_pointer_cast (region)) { + list > audio_tracks; + audio_tracks = _editor->session()->new_audio_track (region->n_channels(), region->n_channels(), ARDOUR::Normal, 0, 1, region->name()); + return _editor->axis_view_from_route (audio_tracks.front()); + } else { + ChanCount one_midi_port (DataType::MIDI, 1); + list > midi_tracks; + midi_tracks = _editor->session()->new_midi_track (one_midi_port, one_midi_port, boost::shared_ptr(), ARDOUR::Normal, 0, 1, region->name()); + return _editor->axis_view_from_route (midi_tracks.front()); + } + } catch (...) { + error << _("Could not create new track after region placed in the drop zone") << endmsg; + return 0; + } +} + void RegionMoveDrag::finished_copy (bool const changed_position, bool const /*changed_tracks*/, framecnt_t const drag_delta) { RegionSelection new_views; PlaylistSet modified_playlists; - list views_to_delete; + RouteTimeAxisView* new_time_axis_view = 0; if (_brushing) { /* all changes were made during motion event handlers */ @@ -952,7 +992,9 @@ RegionMoveDrag::finished_copy (bool const changed_position, bool const /*changed } /* insert the regions into their new playlists */ - for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { + for (list::const_iterator i = _views.begin(); i != _views.end();) { + + RouteTimeAxisView* dest_rtv = 0; if (i->view->region()->locked() || i->view->region()->video_locked()) { continue; @@ -965,27 +1007,31 @@ RegionMoveDrag::finished_copy (bool const changed_position, bool const /*changed } else { where = i->view->region()->position(); } - - RegionView* new_view = insert_region_into_playlist ( - i->view->region(), dynamic_cast (_time_axis_views[i->time_axis_view]), i->layer, where, modified_playlists - ); - - if (new_view == 0) { - continue; + + if (i->time_axis_view < 0) { + if (!new_time_axis_view) { + new_time_axis_view = create_destination_time_axis (i->view->region()); + } + dest_rtv = new_time_axis_view; + } else { + dest_rtv = dynamic_cast (_time_axis_views[i->time_axis_view]); + } + + if (dest_rtv != 0) { + RegionView* new_view = insert_region_into_playlist (i->view->region(), dest_rtv, i->layer, where, modified_playlists); + if (new_view != 0) { + new_views.push_back (new_view); + } } + + /* Delete the copy of the view that was used for dragging. Need to play safe with the iterator + since deletion will automagically remove it from _views, thus invalidating i as an iterator. + */ - new_views.push_back (new_view); - - /* we don't need the copied RegionView any more */ - views_to_delete.push_back (i->view); - } - - /* Delete views that are no longer needed; we can't do this directly in the iteration over _views - because when views are deleted they are automagically removed from _views, which messes - up the iteration. - */ - for (list::iterator i = views_to_delete.begin(); i != views_to_delete.end(); ++i) { - delete *i; + list::const_iterator next = i; + ++next; + delete i->view; + i = next; } /* If we've created new regions either by copying or moving @@ -1013,6 +1059,7 @@ RegionMoveDrag::finished_no_copy ( PlaylistSet modified_playlists; PlaylistSet frozen_playlists; set views_to_update; + RouteTimeAxisView* new_time_axis_view = 0; if (_brushing) { /* all changes were made during motion event handlers */ @@ -1029,15 +1076,26 @@ RegionMoveDrag::finished_no_copy ( for (list::const_iterator i = _views.begin(); i != _views.end(); ) { RegionView* rv = i->view; - - RouteTimeAxisView* const dest_rtv = dynamic_cast (_time_axis_views[i->time_axis_view]); - double const dest_layer = i->layer; + RouteTimeAxisView* dest_rtv = 0; if (rv->region()->locked() || rv->region()->video_locked()) { ++i; continue; } + + if (i->time_axis_view < 0) { + if (!new_time_axis_view) { + new_time_axis_view = create_destination_time_axis (rv->region()); + } + dest_rtv = new_time_axis_view; + } else { + dest_rtv = dynamic_cast (_time_axis_views[i->time_axis_view]); + } + + assert (dest_rtv); + double const dest_layer = i->layer; + views_to_update.insert (dest_rtv); framepos_t where; @@ -1077,6 +1135,17 @@ RegionMoveDrag::finished_no_copy ( } else { + boost::shared_ptr playlist = dest_rtv->playlist(); + + /* this movement may result in a crossfade being modified, or a layering change, + so we need to get undo data from the playlist as well as the region. + */ + + pair r = modified_playlists.insert (playlist); + if (r.second) { + playlist->clear_changes (); + } + rv->region()->clear_changes (); /* @@ -1090,30 +1159,18 @@ RegionMoveDrag::finished_no_copy ( rv->drag_end (); /* just change the model */ - - boost::shared_ptr playlist = dest_rtv->playlist(); - if (dest_rtv->view()->layer_display() == Stacked || dest_rtv->view()->layer_display() == Expanded) { playlist->set_layer (rv->region(), dest_layer); } /* freeze playlist to avoid lots of relayering in the case of a multi-region drag */ - pair r = frozen_playlists.insert (playlist); + r = frozen_playlists.insert (playlist); if (r.second) { playlist->freeze (); } - /* this movement may result in a crossfade being modified, so we need to get undo - data from the playlist as well as the region. - */ - - r = modified_playlists.insert (playlist); - if (r.second) { - playlist->clear_changes (); - } - rv->region()->set_position (where); _editor->session()->add_command (new StatefulDiffCommand (rv->region())); @@ -1789,9 +1846,10 @@ VideoTimeLineDrag::aborted (bool) TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list const & v, bool preserve_fade_anchor) : RegionDrag (e, i, p, v) + , _preserve_fade_anchor (preserve_fade_anchor) + , _jump_position_when_done (false) { DEBUG_TRACE (DEBUG::Drags, "New TrimDrag\n"); - _preserve_fade_anchor = preserve_fade_anchor; } void @@ -1828,6 +1886,10 @@ TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor*) } } + if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) { + _jump_position_when_done = true; + } + switch (_operation) { case StartTrim: show_verbose_cursor_time (region_start); @@ -1954,8 +2016,7 @@ TrimDrag::motion (GdkEvent* event, bool first_move) case ContentsTrim: { - frame_delta = (adjusted_current_frame(event) - last_pointer_frame()); - // frame_delta = (last_pointer_frame() - adjusted_current_frame(event)); + frame_delta = (last_pointer_frame() - adjusted_current_frame(event)); for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { i->view->move_contents (frame_delta); @@ -2007,6 +2068,9 @@ TrimDrag::finished (GdkEvent* event, bool movement_occurred) ar->set_fade_in_length(new_length); } } + if (_jump_position_when_done) { + i->view->region()->set_position (i->initial_position); + } } } else if (_operation == EndTrim) { for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { @@ -2024,6 +2088,9 @@ TrimDrag::finished (GdkEvent* event, bool movement_occurred) ar->set_fade_out_length(new_length); } } + if (_jump_position_when_done) { + i->view->region()->set_position (i->initial_end - i->view->region()->length()); + } } }