#include "ardour/region_factory.h"
#include "ardour/session.h"
+#include "canvas/scroll_group.h"
+
#include "editor.h"
#include "i18n.h"
#include "keyboard.h"
#include "ardour_ui.h"
#include "gui_thread.h"
#include "control_point.h"
-#include "utils.h"
#include "region_gain_line.h"
#include "editor_drag.h"
#include "audio_time_axis.h"
{
bool r = false;
- _current_pointer_frame = _editor->canvas_event_sample (e, &_current_pointer_x, &_current_pointer_y);
-
- for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
- bool const t = (*i)->motion_handler (e, from_autoscroll);
- if (t) {
- r = true;
- }
-
- }
-
- return r;
-}
-
-bool
-DragManager::window_motion_handler (GdkEvent* e, bool from_autoscroll)
-{
- bool r = false;
+ /* calling this implies that we expect the event to have canvas
+ * coordinates
+ *
+ * Can we guarantee that this is true?
+ */
_current_pointer_frame = _editor->canvas_event_sample (e, &_current_pointer_x, &_current_pointer_y);
for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
bool const t = (*i)->motion_handler (e, from_autoscroll);
+ /* run all handlers; return true if at least one of them
+ returns true (indicating that the event has been handled).
+ */
if (t) {
r = true;
}
return j != _drags.end ();
}
-Drag::Drag (Editor* e, ArdourCanvas::Item* i)
+Drag::Drag (Editor* e, ArdourCanvas::Item* i, bool trackview_only)
: _editor (e)
, _item (i)
, _pointer_frame_offset (0)
+ , _trackview_only (trackview_only)
, _move_threshold_passed (false)
, _was_double_click (false)
, _raw_grab_frame (0)
_grab_frame = adjusted_frame (_raw_grab_frame, event);
_last_pointer_frame = _grab_frame;
_last_pointer_x = _grab_x;
+
+ if (_trackview_only) {
+ _grab_y = _grab_y - _editor->get_trackview_group()->canvas_origin().y;
+ }
+
_last_pointer_y = _grab_y;
if (cursor == 0) {
_item->grab ();
-
} else {
/* CAIROCANVAS need a variant here that passes *cursor */
_item->grab ();
-
+ _editor->push_canvas_cursor (cursor);
}
if (_editor->session() && _editor->session()->transport_rolling()) {
finished (event, _move_threshold_passed);
_editor->verbose_cursor()->hide ();
+ _editor->pop_canvas_cursor ();
return _move_threshold_passed;
}
return adjusted_frame (_drags->current_pointer_frame (), event, snap);
}
+double
+Drag::current_pointer_y () const
+{
+ if (!_trackview_only) {
+ return _drags->current_pointer_y ();
+ }
+
+ return _drags->current_pointer_y () - _editor->get_trackview_group()->canvas_origin().y;
+}
+
bool
Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
{
/* check to see if we have moved in any way that matters since the last motion event */
if (_move_threshold_passed &&
(!x_movement_matters() || _last_pointer_frame == adjusted_current_frame (event)) &&
- (!y_movement_matters() || _last_pointer_y == _drags->current_pointer_y ()) ) {
+ (!y_movement_matters() || _last_pointer_y == current_pointer_y ()) ) {
return false;
}
if (!from_autoscroll && !_move_threshold_passed) {
bool const xp = (::llabs (_drags->current_pointer_frame () - _raw_grab_frame) >= threshold.first);
- bool const yp = (::fabs ((_drags->current_pointer_y () - _grab_y)) >= threshold.second);
+ bool const yp = (::fabs ((current_pointer_y () - _grab_y)) >= threshold.second);
_move_threshold_passed = ((xp && x_movement_matters()) || (yp && y_movement_matters()));
}
motion (event, _move_threshold_passed != old_move_threshold_passed);
_last_pointer_x = _drags->current_pointer_x ();
- _last_pointer_y = _drags->current_pointer_y ();
+ _last_pointer_y = current_pointer_y ();
_last_pointer_frame = adjusted_current_frame (event);
}
return true;
}
}
+
return false;
}
void
Drag::show_verbose_cursor_time (framepos_t frame)
{
- _editor->verbose_cursor()->set_time (
- frame,
- _drags->current_pointer_x() + 10,
- _drags->current_pointer_y() + 10
- );
-
+ _editor->verbose_cursor()->set_time (frame);
_editor->verbose_cursor()->show ();
}
void
-Drag::show_verbose_cursor_duration (framepos_t start, framepos_t end, double xoffset)
+Drag::show_verbose_cursor_duration (framepos_t start, framepos_t end, double /*xoffset*/)
{
- _editor->verbose_cursor()->show (xoffset);
-
- _editor->verbose_cursor()->set_duration (
- start, end,
- _drags->current_pointer_x() + 10,
- _drags->current_pointer_y() + 10
- );
+ _editor->verbose_cursor()->set_duration (start, end);
+ _editor->verbose_cursor()->show ();
}
void
Drag::show_verbose_cursor_text (string const & text)
{
+ _editor->verbose_cursor()->set (text);
_editor->verbose_cursor()->show ();
-
- _editor->verbose_cursor()->set (
- text,
- _drags->current_pointer_x() + 10,
- _drags->current_pointer_y() + 10
- );
}
boost::shared_ptr<Region>
*/
for (list<RegionView*>::const_iterator i = v.begin(); i != v.end(); ++i) {
- _views.push_back (DraggingView (*i, this));
+ _views.push_back (DraggingView (*i, this, &(*i)->get_time_axis_view()));
}
RegionView::RegionViewGoingAway.connect (death_connection, invalidator (*this), boost::bind (&RegionDrag::region_going_away, this, _1), gui_context());
show_verbose_cursor_time (_last_frame_position);
- pair<TimeAxisView*, double> const tv = _editor->trackview_by_y_position (_drags->current_pointer_y ());
+ pair<TimeAxisView*, double> const tv = _editor->trackview_by_y_position (current_pointer_y ());
if (tv.first) {
_last_pointer_time_axis_view = find_time_axis_view (tv.first);
_last_pointer_layer = tv.first->layer_display() == Overlaid ? 0 : tv.second;
}
}
- _last_frame_position = *pending_region_position;
}
return dx;
/* Note: time axis views in this method are often expressed as an index into the _time_axis_views vector */
/* Find the TimeAxisView that the pointer is now over */
- pair<TimeAxisView*, double> const r = _editor->trackview_by_y_position (_drags->current_pointer_y ());
+ pair<TimeAxisView*, double> const r = _editor->trackview_by_y_position (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) {
tv->view()->set_layer_display (Expanded);
}
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);
+ _last_frame_position = pending_region_position;
/* Verify change in y */
if (!y_movement_allowed (delta_time_axis_view, delta_layer)) {
delta_layer = 0;
}
- if (x_delta == 0 && delta_time_axis_view == 0 && delta_layer == 0 && !first_move) {
+ if (x_delta == 0 && (tv && tv->view() && 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.
*/
}
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.
+ /* reparent the regionview into a group above all
+ * others
+ */
+
+ ArdourCanvas::Item* rvg = rv->get_canvas_group();
+ Duple rv_canvas_offset = rvg->parent()->canvas_origin ();
+ Duple dmg_canvas_offset = _editor->_drag_motion_group->canvas_origin ();
+ rv->get_canvas_group()->reparent (_editor->_drag_motion_group);
+ /* move the item so that it continues to appear at the
+ same location now that its parent has changed.
*/
-
- 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);
+ rvg->move (rv_canvas_offset - dmg_canvas_offset);
}
/* If we have moved tracks, we'll fudge the layer delta so that the
if (tv) {
- /* The TimeAxisView that this region is now on */
- TimeAxisView* current_tv = _time_axis_views[i->time_axis_view + delta_time_axis_view];
+ int track_index;
+
+ if (i->time_axis_view >= 0) {
+ track_index = i->time_axis_view + delta_time_axis_view;
+ } else {
+ track_index = _time_axis_views.size() - 1 + 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[track_index];
/* Ensure it is moved from stacked -> expanded if appropriate */
if (current_tv->view()->layer_display() == Stacked) {
}
/* Update the DraggingView */
- i->time_axis_view += delta_time_axis_view;
+ i->time_axis_view = track_index;
i->layer += this_delta_layer;
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()->canvas_origin().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 (current_pointer_y() >= 0) {
+
+ Coord last_track_bottom_edge;
+ if (!_time_axis_views.empty()) {
+ TimeAxisView* last = _time_axis_views.back();
+ last_track_bottom_edge = last->canvas_display()->canvas_origin ().y + last->effective_height();
+ } else {
+ last_track_bottom_edge = 0;
+ }
+
+ rv->move (x_delta, last_track_bottom_edge - rv->get_canvas_group()->canvas_origin().y);
+ i->time_axis_view = -1;
+ }
+ }
+
} /* foreach region */
_total_x_delta += x_delta;
}
nrv->get_canvas_group()->show ();
- new_regionviews.push_back (DraggingView (nrv, this));
+ new_regionviews.push_back (DraggingView (nrv, this, i->initial_time_axis_view));
/* swap _primary to the copy */
}
RouteTimeAxisView*
-RegionMoveDrag::create_destination_time_axis (boost::shared_ptr<Region> region)
+RegionMoveDrag::create_destination_time_axis (boost::shared_ptr<Region> region, TimeAxisView* original)
{
/* Add a new track of the correct type, and return the RouteTimeAxisView that is created to display the
new track.
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());
+ RouteTimeAxisView* rtav = _editor->axis_view_from_route (audio_tracks.front());
+ if (rtav) {
+ rtav->set_height (original->current_height());
+ }
+ return rtav;
} 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());
+ RouteTimeAxisView* rtav = _editor->axis_view_from_route (midi_tracks.front());
+ if (rtav) {
+ rtav->set_height (original->current_height());
+ }
+ return rtav;
}
} catch (...) {
error << _("Could not create new track after region placed in the drop zone") << endmsg;
if (i->time_axis_view < 0) {
if (!new_time_axis_view) {
- new_time_axis_view = create_destination_time_axis (i->view->region());
+ new_time_axis_view = create_destination_time_axis (i->view->region(), i->initial_time_axis_view);
}
dest_rtv = new_time_axis_view;
} else {
if (i->time_axis_view < 0) {
if (!new_time_axis_view) {
- new_time_axis_view = create_destination_time_axis (rv->region());
+ new_time_axis_view = create_destination_time_axis (rv->region(), i->initial_time_axis_view);
}
dest_rtv = new_time_axis_view;
} else {
visible.
*/
rv->hide_region_editor();
- rv->fake_set_opaque (false);
+
remove_region_from_playlist (rv->region(), i->initial_playlist, modified_playlists);
playlist->clear_changes ();
}
- playlist->remove_region (region);
+ playlist->remove_region (region); // should be no need to ripple; we better already have rippled the playlist in RegionRippleDrag
}
rv->get_canvas_group()->reparent (rtv->view()->canvas_item());
rv->get_canvas_group()->set_y_position (0);
rv->drag_end ();
- rv->fake_set_opaque (false);
rv->move (-_total_x_delta, 0);
rv->set_height (rtv->view()->child_height ());
}
_primary->get_canvas_group()->show ();
_primary->set_position (pos, 0);
- _views.push_back (DraggingView (_primary, this));
+ _views.push_back (DraggingView (_primary, this, v));
_last_frame_position = pos;
_editor->begin_reversible_command (Operations::insert_region);
playlist->clear_changes ();
playlist->add_region (_primary->region (), _last_frame_position);
+
+ // Mixbus doesn't seem to ripple when inserting regions from the list: should we? yes, probably
+ if (Config->get_edit_mode() == Ripple) {
+ playlist->ripple (_last_frame_position, _primary->region()->length(), _primary->region());
+ }
+
_editor->session()->add_command (new StatefulDiffCommand (playlist));
_editor->commit_reversible_command ();
{
/* Which trackview is this ? */
- pair<TimeAxisView*, double> const tvp = _editor->trackview_by_y_position (_drags->current_pointer_y ());
+ pair<TimeAxisView*, double> const tvp = _editor->trackview_by_y_position (current_pointer_y ());
RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
/* The region motion is only processed if the pointer is over
if (!tv || !tv->is_track()) {
/* To make sure we hide the verbose canvas cursor when the mouse is
- not held over and audiotrack.
+ not held over an audio track.
*/
_editor->verbose_cursor()->hide ();
return;
+ } else {
+ _editor->verbose_cursor()->show ();
}
int dir;
dir = -1;
}
- RegionSelection copy (_editor->selection->regions);
-
- RegionSelectionByPosition cmp;
- copy.sort (cmp);
+ RegionSelection copy;
+ _editor->selection->regions.by_position(copy);
framepos_t const pf = adjusted_current_frame (event);
/* XXX: TODO */
}
+/***
+ * ripple mode...
+ */
+
+void
+RegionRippleDrag::add_all_after_to_views(TimeAxisView *tav, framepos_t where, const RegionSelection &exclude, bool drag_in_progress)
+{
+ RegionSelection to_ripple;
+ TrackViewList tracks;
+ tracks.push_back (tav);
+ _editor->get_regions_after (to_ripple, where, tracks);
+
+ for (RegionSelection::iterator i = to_ripple.begin(); i != to_ripple.end(); ++i) {
+ if (!exclude.contains (*i)) {
+ // the selection has already been added to _views
+
+ if (drag_in_progress) {
+ // do the same things that RegionMotionDrag::motion does when
+ // first_move is true, for the region views that we're adding
+ // to _views this time
+
+ (*i)->drag_start();
+ ArdourCanvas::Item* rvg = (*i)->get_canvas_group();
+ Duple rv_canvas_offset = rvg->item_to_canvas (Duple (0,0));
+ Duple dmg_canvas_offset = _editor->_drag_motion_group->canvas_origin ();
+ rvg->reparent (_editor->_drag_motion_group);
+
+ // we only need to move in the y direction
+ Duple fudge = rv_canvas_offset - dmg_canvas_offset;
+ fudge.x = 0;
+ rvg->move (fudge);
+
+ }
+ _views.push_back (DraggingView (*i, this, tav));
+ }
+ }
+}
+
+void
+RegionRippleDrag::remove_unselected_from_views(framecnt_t amount, bool move_regions)
+{
+
+ for (std::list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ) {
+ // we added all the regions after the selection
+
+ std::list<DraggingView>::iterator to_erase = i++;
+ if (!_editor->selection->regions.contains (to_erase->view)) {
+ // restore the non-selected regions to their original playlist & positions,
+ // and then ripple them back by the length of the regions that were dragged away
+ // do the same things as RegionMotionDrag::aborted
+
+ RegionView *rv = to_erase->view;
+ TimeAxisView* tv = &(rv->get_time_axis_view ());
+ RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
+ assert (rtv);
+
+ // plonk them back onto their own track
+ rv->get_canvas_group()->reparent(rtv->view()->canvas_item());
+ rv->get_canvas_group()->set_y_position (0);
+ rv->drag_end ();
+
+ if (move_regions) {
+ // move the underlying region to match the view
+ rv->region()->set_position (rv->region()->position() + amount);
+ } else {
+ // restore the view to match the underlying region's original position
+ rv->move(-amount, 0); // second parameter is y delta - seems 0 is OK
+ }
+
+ rv->set_height (rtv->view()->child_height ());
+ _views.erase (to_erase);
+ }
+ }
+}
+
+bool
+RegionRippleDrag::y_movement_allowed (int delta_track, double delta_layer) const
+{
+ if (RegionMotionDrag::y_movement_allowed (delta_track, delta_layer)) {
+ if (delta_track) {
+ return allow_moves_across_tracks;
+ } else {
+ return true;
+ }
+ }
+ return false;
+}
+
+RegionRippleDrag::RegionRippleDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
+ : RegionMoveDrag (e, i, p, v, false, false)
+{
+ DEBUG_TRACE (DEBUG::Drags, "New RegionRippleDrag\n");
+ // compute length of selection
+ RegionSelection selected_regions = _editor->selection->regions;
+ selection_length = selected_regions.end_frame() - selected_regions.start();
+
+ // we'll only allow dragging to another track in ripple mode if all the regions
+ // being dragged start off on the same track
+ allow_moves_across_tracks = (selected_regions.playlists().size() == 1);
+ prev_tav = NULL;
+ prev_amount = 0;
+ exclude = new RegionList;
+ for (RegionSelection::iterator i =selected_regions.begin(); i != selected_regions.end(); ++i) {
+ exclude->push_back((*i)->region());
+ }
+
+ // also add regions before start of selection to exclude, to be consistent with how Mixbus does ripple
+ RegionSelection copy;
+ selected_regions.by_position(copy); // get selected regions sorted by position into copy
+
+ std::set<boost::shared_ptr<ARDOUR::Playlist> > playlists = copy.playlists();
+ std::set<boost::shared_ptr<ARDOUR::Playlist> >::const_iterator pi;
+
+ for (pi = playlists.begin(); pi != playlists.end(); ++pi) {
+ // find ripple start point on each applicable playlist
+ RegionView *first_selected_on_this_track = NULL;
+ for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
+ if ((*i)->region()->playlist() == (*pi)) {
+ // region is on this playlist - it's the first, because they're sorted
+ first_selected_on_this_track = *i;
+ break;
+ }
+ }
+ assert (first_selected_on_this_track); // we should always find the region in one of the playlists...
+ add_all_after_to_views (
+ &first_selected_on_this_track->get_time_axis_view(),
+ first_selected_on_this_track->region()->position() + first_selected_on_this_track->region()->length(),
+ selected_regions, false);
+ }
+
+ if (allow_moves_across_tracks) {
+ orig_tav = &(*selected_regions.begin())->get_time_axis_view();
+ } else {
+ orig_tav = NULL;
+ }
+
+}
+
+void
+RegionRippleDrag::motion (GdkEvent* event, bool first_move)
+{
+ /* Which trackview is this ? */
+
+ pair<TimeAxisView*, double> const tvp = _editor->trackview_by_y_position (current_pointer_y ());
+ RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
+
+ /* 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 an audiotrack.
+ */
+ _editor->verbose_cursor()->hide ();
+ return;
+ }
+
+ framepos_t where = adjusted_current_frame (event);
+ assert (where >= 0);
+ framepos_t after;
+ double delta = compute_x_delta (event, &after);
+
+ framecnt_t amount = _editor->pixel_to_sample (delta);
+
+ if (allow_moves_across_tracks) {
+ // all the originally selected regions were on the same track
+
+ framecnt_t adjust = 0;
+ if (prev_tav && tv != prev_tav) {
+ // dragged onto a different track
+ // remove the unselected regions from _views, restore them to their original positions
+ // and add the regions after the drop point on the new playlist to _views instead.
+ // undo the effect of rippling the previous playlist, and include the effect of removing
+ // the dragged region(s) from this track
+
+ remove_unselected_from_views (prev_amount, false);
+ // ripple previous playlist according to the regions that have been removed onto the new playlist
+ prev_tav->playlist()->ripple(prev_position, -selection_length, exclude);
+ prev_amount = 0;
+
+ // move just the selected regions
+ RegionMoveDrag::motion(event, first_move);
+
+ // ensure that the ripple operation on the new playlist inserts selection_length time
+ adjust = selection_length;
+ // ripple the new current playlist
+ tv->playlist()->ripple (where, amount+adjust, exclude);
+
+ // add regions after point where drag entered this track to subsequent ripples
+ add_all_after_to_views (tv, where, _editor->selection->regions, true);
+
+ } else {
+ // motion on same track
+ RegionMoveDrag::motion(event, first_move);
+ }
+ prev_tav = tv;
+
+ // remember what we've done to this playlist so we can undo it if the selection is dragged to another track
+ prev_position = where;
+ } else {
+ // selection encompasses multiple tracks - just drag
+ // cross-track drags are forbidden
+ RegionMoveDrag::motion(event, first_move);
+ }
+
+ if (!_x_constrained) {
+ prev_amount += amount;
+ }
+
+ _last_frame_position = after;
+}
+
+void
+RegionRippleDrag::finished (GdkEvent* event, bool movement_occurred)
+{
+ if (!movement_occurred) {
+ return;
+ }
+
+ _editor->begin_reversible_command(_("Ripple drag"));
+
+ // remove the regions being rippled from the dragging view, updating them to
+ // their new positions
+ remove_unselected_from_views (prev_amount, true);
+
+ if (allow_moves_across_tracks) {
+ if (orig_tav) {
+ // if regions were dragged across tracks, we've rippled any later
+ // regions on the track the regions were dragged off, so we need
+ // to add the original track to the undo record
+ orig_tav->playlist()->clear_changes();
+ vector<Command*> cmds;
+ orig_tav->playlist()->rdiff (cmds);
+ _editor->session()->add_commands (cmds);
+ }
+ if (prev_tav && prev_tav != orig_tav) {
+ prev_tav->playlist()->clear_changes();
+ vector<Command*> cmds;
+ prev_tav->playlist()->rdiff (cmds);
+ _editor->session()->add_commands (cmds);
+ }
+ } else {
+ // selection spanned multiple tracks - all will need adding to undo record
+
+ std::set<boost::shared_ptr<ARDOUR::Playlist> > playlists = _editor->selection->regions.playlists();
+ std::set<boost::shared_ptr<ARDOUR::Playlist> >::const_iterator pi;
+
+ for (pi = playlists.begin(); pi != playlists.end(); ++pi) {
+ (*pi)->clear_changes();
+ vector<Command*> cmds;
+ (*pi)->rdiff (cmds);
+ _editor->session()->add_commands (cmds);
+ }
+ }
+
+ // other modified playlists are added to undo by RegionMoveDrag::finished()
+ RegionMoveDrag::finished (event, movement_occurred);
+ _editor->commit_reversible_command();
+}
+
+void
+RegionRippleDrag::aborted (bool movement_occurred)
+{
+ RegionMoveDrag::aborted (movement_occurred);
+ _views.clear ();
+}
+
+
RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
: Drag (e, i),
_view (dynamic_cast<MidiTimeAxisView*> (v))
Timecode::Time timecode;
_editor->session()->sample_to_timecode(abs(_startdrag_video_offset), timecode, true /* use_offset */, false /* use_subframes */ );
snprintf (buf, sizeof (buf), "Video Start:\n%c%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32, (_startdrag_video_offset<0?'-':' '), timecode.hours, timecode.minutes, timecode.seconds, timecode.frames);
- _editor->verbose_cursor()->set(buf, event->button.x + 10, event->button.y + 10);
- _editor->verbose_cursor()->show ();
+ show_verbose_cursor_text (buf);
}
void
DEBUG_TRACE (DEBUG::Drags, string_compose("SHIFT REGION at %1 by %2\n", i->initial_position, dt));
if (first_move) {
rv->drag_start ();
- rv->fake_set_opaque (true);
rv->region()->clear_changes ();
rv->region()->suspend_property_changes();
}
, _("Diff:"),
(dt<0?'-':' '), timediff.hours, timediff.minutes, timediff.seconds, timediff.frames
);
- _editor->verbose_cursor()->set(buf, event->button.x + 10, event->button.y + 10);
- _editor->verbose_cursor()->show ();
+ show_verbose_cursor_text (buf);
}
void
for (list<AVDraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
i->view->drag_end();
- i->view->fake_set_opaque (false);
i->view->region()->resume_property_changes ();
_editor->session()->add_command (new StatefulDiffCommand (i->view->region()));
if (pf < (region_start + region_length/2)) {
/* closer to front */
_operation = StartTrim;
- Drag::start_grab (event, _editor->cursors()->left_side_trim);
+
+ if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
+ Drag::start_grab (event, _editor->cursors()->anchored_left_side_trim);
+ } else {
+ Drag::start_grab (event, _editor->cursors()->left_side_trim);
+ }
} else {
/* closer to end */
_operation = EndTrim;
- Drag::start_grab (event, _editor->cursors()->right_side_trim);
+ if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
+ Drag::start_grab (event, _editor->cursors()->anchored_right_side_trim);
+ } else {
+ Drag::start_grab (event, _editor->cursors()->right_side_trim);
+ }
}
}
for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
RegionView* rv = i->view;
- rv->fake_set_opaque (false);
rv->enable_display (false);
rv->region()->playlist()->clear_owned_changes ();
for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
i->view->thaw_after_trim ();
i->view->enable_display (true);
- i->view->fake_set_opaque (true);
/* Trimming one region may affect others on the playlist, so we need
to get undo Commands from the whole playlist rather than just the
}
CursorDrag::CursorDrag (Editor* e, EditorCursor& c, bool s)
- : Drag (e, &c.track_canvas_item())
+ : Drag (e, &c.track_canvas_item(), false)
, _cursor (c)
, _stop (s)
{
_point->line().start_drag_single (_point, _fixed_grab_x, fraction);
- _editor->verbose_cursor()->set (_point->line().get_verbose_cursor_string (fraction),
- event->button.x + 10, event->button.y + 10);
-
- _editor->verbose_cursor()->show ();
+ show_verbose_cursor_text (_point->line().get_verbose_cursor_string (fraction));
_pushing = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
ControlPointDrag::motion (GdkEvent* event, bool)
{
double dx = _drags->current_pointer_x() - last_pointer_x();
- double dy = _drags->current_pointer_y() - last_pointer_y();
+ double dy = current_pointer_y() - last_pointer_y();
if (event->button.state & Keyboard::SecondaryModifier) {
dx *= 0.1;
_point->line().drag_motion (_editor->sample_to_pixel_unrounded (cx_frames), fraction, false, _pushing, _final_index);
- _editor->verbose_cursor()->set_text (_point->line().get_verbose_cursor_string (fraction));
+ show_verbose_cursor_text (_point->line().get_verbose_cursor_string (fraction));
}
void
_line->start_drag_line (before, after, fraction);
- _editor->verbose_cursor()->set (_line->get_verbose_cursor_string (fraction),
- event->button.x + 10, event->button.y + 10);
-
- _editor->verbose_cursor()->show ();
+ show_verbose_cursor_text (_line->get_verbose_cursor_string (fraction));
}
void
LineDrag::motion (GdkEvent* event, bool)
{
- double dy = _drags->current_pointer_y() - last_pointer_y();
+ double dy = current_pointer_y() - last_pointer_y();
if (event->button.state & Keyboard::SecondaryModifier) {
dy *= 0.1;
/* we are ignoring x position for this drag, so we can just pass in anything */
_line->drag_motion (0, fraction, true, false, ignored);
- _editor->verbose_cursor()->set_text (_line->get_verbose_cursor_string (fraction));
+ show_verbose_cursor_text (_line->get_verbose_cursor_string (fraction));
}
void
start = grab;
}
- if (_drags->current_pointer_y() < grab_y()) {
- y1 = _drags->current_pointer_y();
+ if (current_pointer_y() < grab_y()) {
+ y1 = current_pointer_y();
y2 = grab_y();
} else {
- y2 = _drags->current_pointer_y();
+ y2 = current_pointer_y();
y1 = grab_y();
}
-
if (start != end || y1 != y2) {
double x1 = _editor->sample_to_pixel (start);
double x2 = _editor->sample_to_pixel (end);
const double min_dimension = 2.0;
- _editor->rubberband_rect->set_x0 (x1);
if (_vertical_only) {
/* fixed 10 pixel width */
- _editor->rubberband_rect->set_x1 (x1 + 10);
+ x2 = x1 + 10;
} else {
if (x2 < x1) {
x2 = min (x1 - min_dimension, x2);
} else {
x2 = max (x1 + min_dimension, x2);
}
- _editor->rubberband_rect->set_x1 (x2);
}
- _editor->rubberband_rect->set_y0 (y1);
if (y2 < y1) {
y2 = min (y1 - min_dimension, y2);
} else {
y2 = max (y1 + min_dimension, y2);
}
- _editor->rubberband_rect->set_y1 (y2);
-
+ /* translate rect into item space and set */
+
+ ArdourCanvas::Rect r (x1, y1, x2, y2);
+
+ /* this drag is a _trackview_only == true drag, so the y1 and
+ * y2 (computed using current_pointer_y() and grab_y()) will be
+ * relative to the top of the trackview group). The
+ * rubberband rect has the same parent/scroll offset as the
+ * the trackview group, so we can use the "r" rect directly
+ * to set the shape of the rubberband.
+ */
+
+ _editor->rubberband_rect->set (r);
_editor->rubberband_rect->show();
_editor->rubberband_rect->raise_to_top();
double y1;
double y2;
- if (_drags->current_pointer_y() < grab_y()) {
- y1 = _drags->current_pointer_y();
+ if (current_pointer_y() < grab_y()) {
+ y1 = current_pointer_y();
y2 = grab_y();
} else {
- y2 = _drags->current_pointer_y();
+ y2 = current_pointer_y();
y1 = grab_y();
}
show_verbose_cursor_time (adjusted_current_frame (event));
}
- _original_pointer_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ()).first->order ();
+ _original_pointer_time_axis = _editor->trackview_by_y_position (current_pointer_y ()).first->order ();
}
void
TrackViewList to_be_removed_from_selection;
TrackViewList& all_tracks (_editor->track_views);
- for (TrackViewList::const_iterator i = all_tracks.begin(); i != all_tracks.end(); ++i) {
+ ArdourCanvas::Coord const top = grab_y();
+ ArdourCanvas::Coord const bottom = current_pointer_y();
+
+ if (top >= 0 && bottom >= 0) {
+
+ for (TrackViewList::const_iterator i = all_tracks.begin(); i != all_tracks.end(); ++i) {
- if ((*i)->covered_by_y_range (grab_y(), _drags->current_pointer_y())) {
- if (!(*i)->get_selected()) {
- to_be_added_to_selection.push_back (*i);
- }
- } else {
- if ((*i)->get_selected()) {
- to_be_removed_from_selection.push_back (*i);
+ if ((*i)->covered_by_y_range (top, bottom)) {
+ if (!(*i)->get_selected()) {
+ to_be_added_to_selection.push_back (*i);
+ }
+ } else {
+ if ((*i)->get_selected()) {
+ to_be_removed_from_selection.push_back (*i);
+ }
}
}
- }
- if (!to_be_added_to_selection.empty()) {
- _editor->selection->add (to_be_added_to_selection);
- }
-
- if (!to_be_removed_from_selection.empty()) {
- _editor->selection->remove (to_be_removed_from_selection);
+ if (!to_be_added_to_selection.empty()) {
+ _editor->selection->add (to_be_added_to_selection);
+ }
+
+ if (!to_be_removed_from_selection.empty()) {
+ _editor->selection->remove (to_be_removed_from_selection);
+ }
}
}
break;
}
RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
- : Drag (e, i),
+ : Drag (e, i, false),
_operation (o),
_copy (false)
{
MidiStreamView* msv = _region->midi_stream_view ();
double const y = _region->midi_view()->y_position ();
/* new current note */
- uint8_t n = msv->y_to_note (_drags->current_pointer_y () - y);
+ uint8_t n = msv->y_to_note (current_pointer_y () - y);
/* clamp */
n = max (msv->lowest_note(), n);
n = min (msv->highest_note(), n);
/* Get line states before we start changing things */
for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) {
i->state = &i->line->get_state ();
- i->original_fraction = y_fraction (i->line, _drags->current_pointer_y());
+ i->original_fraction = y_fraction (i->line, current_pointer_y());
}
if (_ranges.empty()) {
}
for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) {
- i->line->start_drag_multiple (i->points, y_fraction (i->line, _drags->current_pointer_y()), i->state);
+ i->line->start_drag_multiple (i->points, y_fraction (i->line, current_pointer_y()), i->state);
}
}
}
for (list<Line>::iterator l = _lines.begin(); l != _lines.end(); ++l) {
- float const f = y_fraction (l->line, _drags->current_pointer_y());
+ float const f = y_fraction (l->line, current_pointer_y());
/* we are ignoring x position for this drag, so we can just pass in anything */
uint32_t ignored;
l->line->drag_motion (0, f, true, false, ignored);
}
}
-DraggingView::DraggingView (RegionView* v, RegionDrag* parent)
+DraggingView::DraggingView (RegionView* v, RegionDrag* parent, TimeAxisView* itav)
: view (v)
+ , initial_time_axis_view (itav)
{
+ /* note that time_axis_view may be null if the regionview was created
+ * as part of a copy operation.
+ */
time_axis_view = parent->find_time_axis_view (&v->get_time_axis_view ());
layer = v->region()->layer ();
initial_y = v->get_canvas_group()->position().y;