#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"
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<TimeAxisView*, double> 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<RouteTimeAxisView*> (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<TimeAxisView*, double> 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;
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 */
_editor->maybe_locate_with_edit_preroll (_editor->get_selection().regions.start());
}
+RouteTimeAxisView*
+RegionMoveDrag::create_destination_time_axis (boost::shared_ptr<Region> 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<AudioRegion> (region)) {
+ list<boost::shared_ptr<AudioTrack> > 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<boost::shared_ptr<MidiTrack> > midi_tracks;
+ midi_tracks = _editor->session()->new_midi_track (one_midi_port, one_midi_port, boost::shared_ptr<ARDOUR::PluginInfo>(), 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<RegionView*> views_to_delete;
+ RouteTimeAxisView* new_time_axis_view = 0;
if (_brushing) {
/* all changes were made during motion event handlers */
}
/* insert the regions into their new playlists */
- for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+ for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end();) {
+
+ RouteTimeAxisView* dest_rtv = 0;
if (i->view->region()->locked() || i->view->region()->video_locked()) {
continue;
} else {
where = i->view->region()->position();
}
-
- RegionView* new_view = insert_region_into_playlist (
- i->view->region(), dynamic_cast<RouteTimeAxisView*> (_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<RouteTimeAxisView*> (_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<RegionView*>::iterator i = views_to_delete.begin(); i != views_to_delete.end(); ++i) {
- delete *i;
+ list<DraggingView>::const_iterator next = i;
+ ++next;
+ delete i->view;
+ i = next;
}
/* If we've created new regions either by copying or moving
PlaylistSet modified_playlists;
PlaylistSet frozen_playlists;
set<RouteTimeAxisView*> views_to_update;
+ RouteTimeAxisView* new_time_axis_view = 0;
if (_brushing) {
/* all changes were made during motion event handlers */
for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ) {
RegionView* rv = i->view;
-
- RouteTimeAxisView* const dest_rtv = dynamic_cast<RouteTimeAxisView*> (_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<RouteTimeAxisView*> (_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;
} else {
+ boost::shared_ptr<Playlist> 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<PlaylistSet::iterator, bool> r = modified_playlists.insert (playlist);
+ if (r.second) {
+ playlist->clear_changes ();
+ }
+
rv->region()->clear_changes ();
/*
rv->drag_end ();
/* just change the model */
-
- boost::shared_ptr<Playlist> 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<PlaylistSet::iterator, bool> 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()));
TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> 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
}
}
+ 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);
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<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
i->view->move_contents (frame_delta);
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<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
ar->set_fade_out_length(new_length);
}
}
+ if (_jump_position_when_done) {
+ i->view->region()->set_position (i->initial_end - i->view->region()->length());
+ }
}
}