X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor_drag.cc;h=0b5b789e9e6e1e2943ae0e6b11ae6a3cb97f2742;hb=5ef06dd439088226683beff5c6fc1d5af55a014b;hp=f2acf2e7a8e44a43ea151d16efebf065e272cf79;hpb=f30402d073aeae5d24462416407e73d1e0314e71;p=ardour.git diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index f2acf2e7a8..0b5b789e9e 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -17,14 +17,25 @@ */ -#define __STDC_LIMIT_MACROS 1 +#ifdef WAF_BUILD +#include "gtk2ardour-config.h" +#endif + #include + #include "pbd/memento_command.h" #include "pbd/basename.h" #include "pbd/stateful_diff_command.h" -#include "ardour/session.h" + +#include "gtkmm2ext/utils.h" + +#include "ardour/audioregion.h" #include "ardour/dB.h" +#include "ardour/midi_region.h" +#include "ardour/operations.h" #include "ardour/region_factory.h" +#include "ardour/session.h" + #include "editor.h" #include "i18n.h" #include "keyboard.h" @@ -42,24 +53,28 @@ #include "selection.h" #include "midi_selection.h" #include "automation_time_axis.h" +#include "debug.h" +#include "editor_cursors.h" +#include "mouse_cursors.h" +#include "verbose_cursor.h" using namespace std; using namespace ARDOUR; using namespace PBD; using namespace Gtk; +using namespace Gtkmm2ext; using namespace Editing; using namespace ArdourCanvas; using Gtkmm2ext::Keyboard; -double const ControlPointDrag::_zero_gain_fraction = gain_to_slider_position (dB_to_coefficient (0.0)); +double ControlPointDrag::_zero_gain_fraction = -1.0; DragManager::DragManager (Editor* e) : _editor (e) , _ending (false) , _current_pointer_frame (0) { - } DragManager::~DragManager () @@ -72,12 +87,16 @@ void DragManager::abort () { _ending = true; - + for (list::const_iterator i = _drags.begin(); i != _drags.end(); ++i) { (*i)->abort (); delete *i; } + if (!_drags.empty ()) { + _editor->set_follow_playhead (_old_follow_playhead, false); + } + _drags.clear (); _ending = false; @@ -93,7 +112,6 @@ DragManager::add (Drag* d) void DragManager::set (Drag* d, GdkEvent* e, Gdk::Cursor* c) { - assert (_drags.empty ()); d->set_manager (this); _drags.push_back (d); start_grab (e, c); @@ -102,8 +120,12 @@ DragManager::set (Drag* d, GdkEvent* e, Gdk::Cursor* c) void DragManager::start_grab (GdkEvent* e, Gdk::Cursor* c) { + /* Prevent follow playhead during the drag to be nice to the user */ + _old_follow_playhead = _editor->follow_playhead (); + _editor->set_follow_playhead (false); + _current_pointer_frame = _editor->event_frame (e, &_current_pointer_x, &_current_pointer_y); - + for (list::const_iterator i = _drags.begin(); i != _drags.end(); ++i) { (*i)->start_grab (e, c); } @@ -116,7 +138,7 @@ bool DragManager::end_grab (GdkEvent* e) { _ending = true; - + bool r = false; for (list::iterator i = _drags.begin(); i != _drags.end(); ++i) { bool const t = (*i)->end_grab (e); @@ -129,7 +151,9 @@ DragManager::end_grab (GdkEvent* e) _drags.clear (); _ending = false; - + + _editor->set_follow_playhead (_old_follow_playhead, false); + return r; } @@ -139,13 +163,13 @@ DragManager::motion_handler (GdkEvent* e, bool from_autoscroll) bool r = false; _current_pointer_frame = _editor->event_frame (e, &_current_pointer_x, &_current_pointer_y); - + for (list::iterator i = _drags.begin(); i != _drags.end(); ++i) { bool const t = (*i)->motion_handler (e, from_autoscroll); if (t) { r = true; } - + } return r; @@ -162,11 +186,12 @@ DragManager::have_item (ArdourCanvas::Item* i) const return j != _drags.end (); } -Drag::Drag (Editor* e, ArdourCanvas::Item* i) +Drag::Drag (Editor* e, ArdourCanvas::Item* i) : _editor (e) , _item (i) , _pointer_frame_offset (0) , _move_threshold_passed (false) + , _raw_grab_frame (0) , _grab_frame (0) , _last_pointer_frame (0) { @@ -208,15 +233,16 @@ Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor) _y_constrained = false; } - _grab_frame = _editor->event_frame (event, &_grab_x, &_grab_y); - _grab_frame = adjusted_frame (_grab_frame, event); + _raw_grab_frame = _editor->event_frame (event, &_grab_x, &_grab_y); + setup_pointer_frame_offset (); + _grab_frame = adjusted_frame (_raw_grab_frame, event); _last_pointer_frame = _grab_frame; _last_pointer_x = _grab_x; _last_pointer_y = _grab_y; _item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK, - *cursor, - event->button.time); + *cursor, + event->button.time); if (_editor->session() && _editor->session()->transport_rolling()) { _was_rolling = true; @@ -251,15 +277,15 @@ Drag::end_grab (GdkEvent* event) finished (event, _move_threshold_passed); - _editor->hide_verbose_canvas_cursor(); + _editor->verbose_cursor()->hide (); return _move_threshold_passed; } -nframes64_t -Drag::adjusted_frame (nframes64_t f, GdkEvent const * event, bool snap) const +framepos_t +Drag::adjusted_frame (framepos_t f, GdkEvent const * event, bool snap) const { - nframes64_t pos = 0; + framepos_t pos = 0; if (f > _pointer_frame_offset) { pos = f - _pointer_frame_offset; @@ -272,7 +298,7 @@ Drag::adjusted_frame (nframes64_t f, GdkEvent const * event, bool snap) const return pos; } -nframes64_t +framepos_t Drag::adjusted_current_frame (GdkEvent const * event, bool snap) const { return adjusted_frame (_drags->current_pointer_frame (), event, snap); @@ -282,18 +308,19 @@ 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 ( (!x_movement_matters() || _last_pointer_frame == adjusted_current_frame (event)) && - (!y_movement_matters() || _last_pointer_y == _drags->current_pointer_y ()) ) { + if (_move_threshold_passed && + (!x_movement_matters() || _last_pointer_frame == adjusted_current_frame (event)) && + (!y_movement_matters() || _last_pointer_y == _drags->current_pointer_y ()) ) { return false; } - pair const threshold = move_threshold (); + pair const threshold = move_threshold (); bool const old_move_threshold_passed = _move_threshold_passed; if (!from_autoscroll && !_move_threshold_passed) { - bool const xp = (::llabs (adjusted_current_frame (event) - _grab_frame) >= threshold.first); + 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); _move_threshold_passed = ((xp && x_movement_matters()) || (yp && y_movement_matters())); @@ -311,7 +338,7 @@ Drag::motion_handler (GdkEvent* event, bool from_autoscroll) _last_pointer_x = _drags->current_pointer_x (); _last_pointer_y = _drags->current_pointer_y (); _last_pointer_frame = adjusted_current_frame (event); - + return true; } } @@ -326,228 +353,189 @@ Drag::abort () _item->ungrab (0); } - aborted (); + aborted (_move_threshold_passed); _editor->stop_canvas_autoscroll (); - _editor->hide_verbose_canvas_cursor (); -} - -RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list const & v) - : Drag (e, i), - _primary (p) -{ - for (list::const_iterator i = v.begin(); i != v.end(); ++i) { - _views.push_back (DraggingView (*i)); - } - - RegionView::RegionViewGoingAway.connect (death_connection, invalidator (*this), ui_bind (&RegionDrag::region_going_away, this, _1), gui_context()); + _editor->verbose_cursor()->hide (); } void -RegionDrag::region_going_away (RegionView* v) +Drag::show_verbose_cursor_time (framepos_t frame) { - list::iterator i = _views.begin (); - while (i != _views.end() && i->view != v) { - ++i; - } + _editor->verbose_cursor()->set_time ( + frame, + _drags->current_pointer_x() + 10 - _editor->horizontal_position(), + _drags->current_pointer_y() + 10 - _editor->vertical_adjustment.get_value() + _editor->canvas_timebars_vsize + ); - if (i != _views.end()) { - _views.erase (i); - } + _editor->verbose_cursor()->show (); } -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) +void +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 - _editor->horizontal_position(), + _drags->current_pointer_y() + 10 - _editor->vertical_adjustment.get_value() + _editor->canvas_timebars_vsize + ); } - void -RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor *) +Drag::show_verbose_cursor_text (string const & text) { - Drag::start_grab (event); + _editor->verbose_cursor()->show (); - _editor->show_verbose_time_cursor (_last_frame_position, 10); + _editor->verbose_cursor()->set ( + text, + _drags->current_pointer_x() + 10 - _editor->horizontal_position(), + _drags->current_pointer_y() + 10 - _editor->vertical_adjustment.get_value() + _editor->canvas_timebars_vsize + ); } -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 */ +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")); + } +}; - for (TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) { - RouteTimeAxisView* rtv = dynamic_cast (*i); - TimeAxisView::Children children_list; +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); - /* zeroes are audio/MIDI tracks. ones are other types. */ + /* Make a list of tracks to refer to during the drag; we include hidden tracks, + as some of the regions we are dragging may be on such tracks. + */ - if (!rtv->hidden()) { + TrackViewList track_views = _editor->track_views; + track_views.sort (EditorOrderTimeAxisViewSorter ()); - if (!rtv->is_track()) { - /* not an audio nor MIDI track */ - sum.tracks = sum.tracks |= (0x01 << rtv->order()); - } + for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { + _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()); + } + } - sum.height_list[rtv->order()] = (*i)->current_height(); - children = 1; + /* the list of views can be empty at this point if this is a region list-insert drag + */ - 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++; - } - } - } + for (list::const_iterator i = v.begin(); i != v.end(); ++i) { + _views.push_back (DraggingView (*i, this)); } - return sum; + RegionView::RegionViewGoingAway.connect (death_connection, invalidator (*this), ui_bind (&RegionDrag::region_going_away, this, _1), gui_context()); } -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 - ) +void +RegionDrag::region_going_away (RegionView* v) { - if (_brushing) { - *pointer_order_span = 0; - *pointer_layer_span = 0; - return true; + list::iterator i = _views.begin (); + while (i != _views.end() && i->view != v) { + ++i; } - 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; - } + if (i != _views.end()) { + _views.erase (i); + } +} - 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; +/** Given a TimeAxisView, return the index of it into the _time_axis_views vector, + * or -1 if it is not found. + */ +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; + } - /* 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); + if (i == N) { + return -1; + } - /* XXX: not sure that we should be passing canvas_pointer_order_span in here, - as surely this is a per-region thing... */ + return i; +} - clamp_y_axis = y_movement_disallowed ( - rtv->order(), last_pointer_view->order(), *canvas_pointer_order_span, tavs - ); +RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list const & v, bool b) + : RegionDrag (e, i, p, v), + _brushing (b), + _total_x_delta (0) +{ - 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; - } - } +void +RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) +{ + Drag::start_grab (event, cursor); - if (!clamp_y_axis) { - _dest_trackview = current_pointer_view; - _dest_layer = current_pointer_layer; - } + show_verbose_cursor_time (_last_frame_position); - 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) +RegionMotionDrag::compute_x_delta (GdkEvent const * event, framepos_t* pending_region_position) { /* compute the amount of pointer motion in frames, and where the region would be if we moved it by that much. */ *pending_region_position = adjusted_current_frame (event); - nframes64_t sync_frame; - nframes64_t sync_offset; + framepos_t sync_frame; + framecnt_t sync_offset; int32_t sync_dir; - + sync_offset = _primary->region()->sync_offset (sync_dir); - + /* we don't handle a sync point that lies before zero. */ if (sync_dir >= 0 || (sync_dir < 0 && *pending_region_position >= sync_offset)) { - + sync_frame = *pending_region_position + (sync_dir*sync_offset); - + _editor->snap_to_with_modifier (sync_frame, event); - + *pending_region_position = _primary->region()->adjust_to_sync (sync_frame); - + } else { *pending_region_position = _last_frame_position; } - if (*pending_region_position > max_frames - _primary->region()->length()) { + if (*pending_region_position > max_framepos - _primary->region()->length()) { *pending_region_position = _last_frame_position; } 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 */ + /* x movement since last time (in pixels) */ dx = (static_cast (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit; /* total x movement */ framecnt_t total_dx = *pending_region_position; if (regions_came_from_canvas()) { - total_dx = total_dx - grab_frame () + _pointer_frame_offset; + total_dx = total_dx - grab_frame (); } /* check that no regions have gone off the start of the session */ @@ -565,67 +553,80 @@ 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; + } + + 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; + } + } - TimeAxisViewSummary tavs = get_time_axis_view_summary (); + /* all regions being dragged are ok with this change */ + return true; +} - vector::iterator j; +void +RegionMotionDrag::motion (GdkEvent* event, bool first_move) +{ + assert (!_views.empty ()); - /* *pointer* variables reflect things about the pointer; as we may be moving - multiple regions, much detail must be computed per-region */ + /* 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->verbose_cursor()->hide (); 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; + /* Note: time axis views in this method are often expressed as an index into the _time_axis_views vector */ - int32_t pointer_order_span; - int32_t pointer_layer_span; - int32_t 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; - 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 - ); - - 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 (!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 && pointer_order_span == 0 && pointer_layer_span == 0 && !first_move) { + 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,181 +634,162 @@ 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) { - // 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 + + /* 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. + Reparenting means that we will have to move the region view + later, 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); + + if (!rv->get_time_axis_view().hidden()) { + /* the track that this region view is on is hidden, so hide the region too */ + rv->get_canvas_group()->hide (); + } } - /* current view for this particular region */ - pair pos = _editor->trackview_by_y_position (iy1); - RouteTimeAxisView* rtv = dynamic_cast (pos.first); + /* 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; + } - if (pointer_order_span != 0 && !clamp_y_axis) { + /* The TimeAxisView that this region is now on */ + TimeAxisView* tv = _time_axis_views[i->time_axis_view + delta_time_axis_view]; + + /* Set height */ + rv->set_height (tv->view()->child_height ()); - /* INTER-TRACK MOVEMENT */ + /* 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 (); + } - /* 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; - } + /* Update the DraggingView */ + i->time_axis_view += delta_time_axis_view; + i->layer += this_delta_layer; - y_delta = 0; - int32_t temp_pointer_order_span = canvas_pointer_order_span; + if (_brushing) { + _editor->mouse_brush_insert_region (rv, pending_region_position); + } else { + double x = 0; + double y = 0; - if (j != tavs.height_list.end ()) { + /* Get the y coordinate of the top of the track that this region is now on */ + tv->canvas_display()->i2w (x, y); + y += _editor->get_trackview_group_vertical_offset(); + + /* And adjust for the layer that it should be on */ + StreamView* cv = tv->view (); + if (cv->layer_display() == Stacked) { + y += (cv->layers() - i->layer - 1) * cv->child_height (); + } + + /* Now move the region view */ + rv->move (x_delta, y - rv->get_canvas_group()->property_y()); + } - /* 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. */ + } /* foreach region */ - StreamView* lv = last_pointer_view->view (); - assert (lv); + _total_x_delta += x_delta; - /* move to the top of the last trackview */ - if (lv->layer_display () == Stacked) { - y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height (); - } + if (first_move) { + _editor->cursor_group->raise_to_top(); + } - StreamView* cv = current_pointer_view->view (); - assert (cv); + if (x_delta != 0 && !_brushing) { + show_verbose_cursor_time (_last_frame_position); + } - /* 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 (); - } + _last_pointer_time_axis_view += delta_time_axis_view; + _last_pointer_layer += delta_layer; +} - /* 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--; - } +void +RegionMoveDrag::motion (GdkEvent* event, bool first_move) +{ + if (_copy && first_move) { - while (temp_pointer_order_span < 0) { + /* duplicate the regionview(s) and region(s) */ - y_delta += (*j); + list new_regionviews; - if (x != last_pointer_order) { - if ((*j) == 0) { - --temp_pointer_order_span; - } - } + for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { - if (j != tavs.height_list.end()) { - j++; - } + RegionView* rv = i->view; + AudioRegionView* arv = dynamic_cast(rv); + MidiRegionView* mrv = dynamic_cast(rv); - temp_pointer_order_span++; - } + const boost::shared_ptr original = rv->region(); + boost::shared_ptr region_copy = RegionFactory::create (original, true); + region_copy->set_position (original->position()); + RegionView* nrv; + if (arv) { + boost::shared_ptr audioregion_copy + = boost::dynamic_pointer_cast(region_copy); - /* find out where we'll be when we move and set height accordingly */ + 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; + } - 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()); + nrv->get_canvas_group()->show (); + new_regionviews.push_back (DraggingView (nrv, this)); - /* 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. - */ + /* swap _primary to the copy */ - //const GdkColor& col (temp_rtv->view->get_region_color()); - //rv->set_color (const_cast(col)); + if (rv == _primary) { + _primary = nrv; } - } - if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) { + /* ..and deselect the one we copied */ - /* INTER-LAYER MOVEMENT in the same track */ - y_delta = rtv->view()->child_height () * pointer_layer_span; + rv->set_selected (false); } - if (_brushing) { - _editor->mouse_brush_insert_region (rv, pending_region_position); - } else { - rv->move (x_delta, y_delta); - } + if (!new_regionviews.empty()) { - } /* foreach region */ + /* reflect the fact that we are dragging the copies */ - _total_x_delta += x_delta; - - if (first_move) { - _editor->cursor_group->raise_to_top(); - } + _views = new_regionviews; - if (x_delta != 0 && !_brushing) { - _editor->show_verbose_time_cursor (_last_frame_position, 10); - } -} + swap_grab (new_regionviews.front().view->get_canvas_group (), 0, event ? event->motion.time : 0); -void -RegionMoveDrag::motion (GdkEvent* event, bool first_move) -{ - if (_copy && first_move) { - copy_regions (event); + /* + 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 */ @@ -822,40 +804,43 @@ RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred) _x_constrained = !_x_constrained; } - bool const changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position())); - bool const changed_tracks = (_dest_trackview != &_primary->get_time_axis_view()); - framecnt_t const drag_delta = _primary->region()->position() - _last_frame_position; + assert (!_views.empty ()); - _editor->update_canvas_now (); + /* We might have hidden region views so that they weren't visible during the drag + (when they have been reparented). Now everything can be shown again, as region + views are back in their track parent groups. + */ + for (list::iterator i = _views.begin(); i != _views.end(); ++i) { + i->view->get_canvas_group()->show (); + } + bool const changed_position = (_last_frame_position != _primary->region()->position()); + 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 (); + if (_copy) { - + finished_copy ( - find_time_axis_views_and_layers (), changed_position, changed_tracks, drag_delta ); - + } else { - + finished_no_copy ( - find_time_axis_views_and_layers (), changed_position, changed_tracks, drag_delta ); - + } } void -RegionMoveDrag::finished_copy ( - map > const & final, - bool const changed_position, - bool const changed_tracks, - framecnt_t const drag_delta - ) +RegionMoveDrag::finished_copy (bool const changed_position, bool const /*changed_tracks*/, framecnt_t const drag_delta) { RegionSelection new_views; PlaylistSet modified_playlists; @@ -873,39 +858,36 @@ RegionMoveDrag::finished_copy ( } if (_x_constrained) { - _editor->begin_reversible_command (_("fixed time region copy")); + _editor->begin_reversible_command (Operations::fixed_time_region_copy); } else { - _editor->begin_reversible_command (_("region copy")); + _editor->begin_reversible_command (Operations::region_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; } + framepos_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) { continue; } new_views.push_back (new_view); - + /* we don't need the copied RegionView any more */ views_to_delete.push_back (i->view); } @@ -918,8 +900,8 @@ RegionMoveDrag::finished_copy ( delete *i; } - /* If we've created new regions either by copying or moving - to a new track, we want to replace the old selection with the new ones + /* If we've created new regions either by copying or moving + to a new track, we want to replace the old selection with the new ones */ if (new_views.size() > 0) { @@ -934,7 +916,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 @@ -953,25 +934,22 @@ RegionMoveDrag::finished_no_copy ( if (_x_constrained) { _editor->begin_reversible_command (_("fixed time region drag")); } else { - _editor->begin_reversible_command (_("region drag")); + _editor->begin_reversible_command (Operations::region_drag); } for (list::const_iterator i = _views.begin(); i != _views.end(); ) { 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; continue; } - nframes64_t where; + framepos_t where; if (changed_position && !_x_constrained) { where = rv->region()->position() - drag_delta; @@ -984,7 +962,7 @@ RegionMoveDrag::finished_no_copy ( /* insert into new playlist */ RegionView* new_view = insert_region_into_playlist ( - RegionFactory::create (rv->region ()), dest_rtv, dest_layer, where, modified_playlists + RegionFactory::create (rv->region (), true), dest_rtv, dest_layer, where, modified_playlists ); if (new_view == 0) { @@ -1007,7 +985,7 @@ RegionMoveDrag::finished_no_copy ( remove_region_from_playlist (rv->region(), i->initial_playlist, modified_playlists); } else { - + rv->region()->clear_changes (); /* @@ -1023,12 +1001,12 @@ RegionMoveDrag::finished_no_copy ( /* just change the model */ boost::shared_ptr playlist = dest_rtv->playlist(); - + if (dest_rtv->view()->layer_display() == Stacked) { rv->region()->set_layer (dest_layer); rv->region()->set_pending_explicit_relayer (true); } - + /* freeze playlist to avoid lots of relayering in the case of a multi-region drag */ pair r = frozen_playlists.insert (playlist); @@ -1037,13 +1015,22 @@ RegionMoveDrag::finished_no_copy ( playlist->freeze (); } - rv->region()->set_position (where, (void*) this); + /* 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())); } if (changed_tracks) { - + /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region was selected in all of them, then removing it from a playlist will have removed all trace of it from _views (i.e. there were N regions selected, we removed 1, @@ -1061,9 +1048,9 @@ RegionMoveDrag::finished_no_copy ( we can just iterate. */ - + if (_views.empty()) { - break; + break; } else { i = _views.begin(); } @@ -1073,8 +1060,8 @@ RegionMoveDrag::finished_no_copy ( } } - /* If we've created new regions either by copying or moving - to a new track, we want to replace the old selection with the new ones + /* If we've created new regions either by copying or moving + to a new track, we want to replace the old selection with the new ones */ if (new_views.size() > 0) { @@ -1112,7 +1099,7 @@ RegionMoveDrag::remove_region_from_playlist ( playlist->remove_region (region); } - + /** Insert a region into a playlist, handling the recovery of the resulting new RegionView, and * clearing the playlist's diff history first if necessary. @@ -1121,7 +1108,7 @@ RegionMoveDrag::remove_region_from_playlist ( * @param dest_layer Destination layer. * @param where Destination position. * @param modified_playlists The playlist will be added to this if it is not there already; used to ensure - * that clear_changes () is only called once per playlist. + * that clear_changes () is only called once per playlist. * @return New RegionView, or 0 if no insert was performed. */ RegionView * @@ -1142,7 +1129,7 @@ RegionMoveDrag::insert_region_into_playlist ( _new_region_view = 0; sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &RegionMoveDrag::collect_new_region_view)); - /* clear history for the playlist we are about to insert to, provided we haven't already done so */ + /* clear history for the playlist we are about to insert to, provided we haven't already done so */ pair r = modified_playlists.insert (dest_playlist); if (r.second) { dest_playlist->clear_changes (); @@ -1172,270 +1159,80 @@ void RegionMoveDrag::add_stateful_diff_commands_for_playlists (PlaylistSet const & playlists) { for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) { - _editor->session()->add_command (new StatefulDiffCommand (*i)); - } -} - - -void -RegionMoveDrag::aborted () -{ - if (_copy) { - - for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { - delete i->view; - } - - _views.clear (); - - } else { - RegionMotionDrag::aborted (); - } -} - -void -RegionMotionDrag::aborted () -{ - for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { - RegionView* rv = i->view; - TimeAxisView* tv = &(rv->get_time_axis_view ()); - RouteTimeAxisView* rtv = dynamic_cast (tv); - assert (rtv); - rv->get_canvas_group()->reparent (*rtv->view()->canvas_item()); - rv->get_canvas_group()->property_y() = 0; - rv->get_time_axis_view().reveal_dependent_views (*rv); - rv->fake_set_opaque (false); - rv->move (-_total_x_delta, 0); - rv->set_height (rtv->view()->child_height ()); - } - - _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); + StatefulDiffCommand* c = new StatefulDiffCommand (*i); + if (!c->empty()) { + _editor->session()->add_command (c); } else { - continue; - } - - nrv->get_canvas_group()->show (); - new_regionviews.push_back (DraggingView (nrv)); - - /* swap _primary to the copy */ - - if (rv == _primary) { - _primary = nrv; + delete c; } - - /* ..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 { +void +RegionMoveDrag::aborted (bool movement_occurred) +{ + if (_copy) { - /* moving beyond the highest visible track; disallow */ - return true; - } + for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { + delete i->view; } - } else { + _views.clear (); - /* this is the pointer's track */ + } else { + RegionMotionDrag::aborted (movement_occurred); + } +} - 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; - } +void +RegionMotionDrag::aborted (bool) +{ + for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { + RegionView* rv = i->view; + TimeAxisView* tv = &(rv->get_time_axis_view ()); + RouteTimeAxisView* rtv = dynamic_cast (tv); + assert (rtv); + rv->get_canvas_group()->reparent (*rtv->view()->canvas_item()); + rv->get_canvas_group()->property_y() = 0; + rv->get_time_axis_view().reveal_dependent_views (*rv); + rv->fake_set_opaque (false); + rv->move (-_total_x_delta, 0); + rv->set_height (rtv->view()->child_height ()); } - return false; + _editor->update_canvas_now (); } - +/** @param b true to brush, otherwise false. + * @param c true to make copies of the regions being moved, otherwise 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 (); - } + DEBUG_TRACE (DEBUG::Drags, "New RegionMoveDrag\n"); 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 (); } - _last_frame_position = static_cast (_primary->region()->position() / speed); + _last_frame_position = static_cast (_primary->region()->position() / speed); } void -RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c) +RegionMoveDrag::setup_pointer_frame_offset () { - RegionMotionDrag::start_grab (event, c); - - _pointer_frame_offset = grab_frame() - _last_frame_position; + _pointer_frame_offset = raw_grab_frame() - _last_frame_position; } -RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr r, RouteTimeAxisView* v, nframes64_t pos) +RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr r, RouteTimeAxisView* v, framepos_t pos) : RegionMotionDrag (e, 0, 0, list (), false) { + DEBUG_TRACE (DEBUG::Drags, "New RegionInsertDrag\n"); + assert ((boost::dynamic_pointer_cast (r) && dynamic_cast (v)) || (boost::dynamic_pointer_cast (r) && dynamic_cast (v))); @@ -1443,52 +1240,27 @@ 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; boost::shared_ptr playlist = dest_rtv->playlist(); - _editor->begin_reversible_command (_("insert region")); - playlist->clear_changes (); + _editor->begin_reversible_command (Operations::insert_region); + playlist->clear_changes (); playlist->add_region (_primary->region (), _last_frame_position); _editor->session()->add_command (new StatefulDiffCommand (playlist)); _editor->commit_reversible_command (); @@ -1499,7 +1271,7 @@ RegionInsertDrag::finished (GdkEvent* /*event*/, bool /*movement_occurred*/) } void -RegionInsertDrag::aborted () +RegionInsertDrag::aborted (bool) { delete _primary; _primary = 0; @@ -1509,7 +1281,7 @@ RegionInsertDrag::aborted () RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list const & v) : RegionMoveDrag (e, i, p, v, false, false) { - + DEBUG_TRACE (DEBUG::Drags, "New RegionSpliceDrag\n"); } struct RegionSelectionByPosition { @@ -1521,10 +1293,20 @@ 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); + + /* 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->verbose_cursor()->hide (); return; } @@ -1541,7 +1323,7 @@ RegionSpliceDrag::motion (GdkEvent* event, bool) RegionSelectionByPosition cmp; copy.sort (cmp); - nframes64_t const pf = adjusted_current_frame (event); + framepos_t const pf = adjusted_current_frame (event); for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) { @@ -1577,13 +1359,13 @@ RegionSpliceDrag::motion (GdkEvent* event, bool) } void -RegionSpliceDrag::finished (GdkEvent* /*event*/, bool) +RegionSpliceDrag::finished (GdkEvent* event, bool movement_occurred) { - + RegionMoveDrag::finished (event, movement_occurred); } void -RegionSpliceDrag::aborted () +RegionSpliceDrag::aborted (bool) { /* XXX: TODO */ } @@ -1592,6 +1374,8 @@ RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisVi : Drag (e, i), _view (dynamic_cast (v)) { + DEBUG_TRACE (DEBUG::Drags, "New RegionCreateDrag\n"); + assert (_view); } @@ -1599,31 +1383,64 @@ void RegionCreateDrag::motion (GdkEvent* event, bool first_move) { if (first_move) { - /* don't use a zero-length region otherwise its region view will be hidden when it is created */ - _region = _view->add_region (grab_frame(), 1, false); + add_region(); + _view->playlist()->freeze (); } else { - framepos_t const f = adjusted_current_frame (event); - if (f < grab_frame()) { - _region->set_position (f, this); - } + if (_region) { + framepos_t const f = adjusted_current_frame (event); + if (f < grab_frame()) { + _region->set_position (f); + } - /* again, don't use a zero-length region (see above) */ - framecnt_t const len = abs (f - grab_frame ()); - _region->set_length (len < 1 ? 1 : len, this); + /* Don't use a zero-length region, and subtract 1 frame from the snapped length + so that if this region is duplicated, its duplicate starts on + a snap point rather than 1 frame after a snap point. Otherwise things get + a bit confusing as if a region starts 1 frame after a snap point, one cannot + place snapped notes at the start of the region. + */ + + framecnt_t const len = abs (f - grab_frame () - 1); + _region->set_length (len < 1 ? 1 : len); + } } } void -RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred) +RegionCreateDrag::finished (GdkEvent*, bool movement_occurred) { - if (movement_occurred) { + if (!movement_occurred) { + add_region (); + } else { + _view->playlist()->thaw (); + } + + if (_region) { _editor->commit_reversible_command (); } } void -RegionCreateDrag::aborted () +RegionCreateDrag::add_region () +{ + if (_editor->session()) { + const TempoMap& map (_editor->session()->tempo_map()); + framecnt_t pos = grab_frame(); + const Meter& m = map.meter_at (pos); + /* not that the frame rate used here can be affected by pull up/down which + might be wrong. + */ + framecnt_t len = m.frames_per_bar (map.tempo_at (pos), _editor->session()->frame_rate()); + _region = _view->add_region (grab_frame(), len, false); + } +} + +void +RegionCreateDrag::aborted (bool) { + if (_region) { + _view->playlist()->thaw (); + } + /* XXX */ } @@ -1631,16 +1448,23 @@ NoteResizeDrag::NoteResizeDrag (Editor* e, ArdourCanvas::Item* i) : Drag (e, i) , region (0) { - + DEBUG_TRACE (DEBUG::Drags, "New NoteResizeDrag\n"); } void NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*ignored*/) { Gdk::Cursor* cursor; - ArdourCanvas::CanvasNote* cnote = dynamic_cast(_item); + ArdourCanvas::CanvasNoteEvent* cnote = dynamic_cast(_item); + float x_fraction = cnote->mouse_x_fraction (); - Drag::start_grab (event); + if (x_fraction > 0.0 && x_fraction < 0.25) { + cursor = _editor->cursors()->left_side_trim; + } else { + cursor = _editor->cursors()->right_side_trim; + } + + Drag::start_grab (event, cursor); region = &cnote->region_view(); @@ -1648,10 +1472,10 @@ NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*ignored*/) double const middle_point = region_start + cnote->x1() + (cnote->x2() - cnote->x1()) / 2.0L; if (grab_x() <= middle_point) { - cursor = _editor->left_side_trim_cursor; + cursor = _editor->cursors()->left_side_trim; at_front = true; } else { - cursor = _editor->right_side_trim_cursor; + cursor = _editor->cursors()->right_side_trim; at_front = false; } @@ -1689,7 +1513,7 @@ NoteResizeDrag::motion (GdkEvent* /*event*/, bool /*first_move*/) { MidiRegionSelection& ms (_editor->get_selection().midi_regions); for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) { - (*r)->update_resizing (dynamic_cast(_item), at_front, _drags->current_pointer_x() - grab_x(), relative); + (*r)->update_resizing (dynamic_cast(_item), at_front, _drags->current_pointer_x() - grab_x(), relative); } } @@ -1698,14 +1522,23 @@ NoteResizeDrag::finished (GdkEvent*, bool /*movement_occurred*/) { MidiRegionSelection& ms (_editor->get_selection().midi_regions); for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) { - (*r)->commit_resizing (dynamic_cast(_item), at_front, _drags->current_pointer_x() - grab_x(), relative); + (*r)->commit_resizing (dynamic_cast(_item), at_front, _drags->current_pointer_x() - grab_x(), relative); } } void -NoteResizeDrag::aborted () +NoteResizeDrag::aborted (bool) { - /* XXX: TODO */ + MidiRegionSelection& ms (_editor->get_selection().midi_regions); + for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) { + (*r)->abort_resizing (); + } +} + +RegionGainDrag::RegionGainDrag (Editor* e, ArdourCanvas::Item* i) + : Drag (e, i) +{ + DEBUG_TRACE (DEBUG::Drags, "New RegionGainDrag\n"); } void @@ -1721,20 +1554,19 @@ RegionGainDrag::finished (GdkEvent *, bool) } void -RegionGainDrag::aborted () +RegionGainDrag::aborted (bool) { /* XXX: TODO */ } TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list const & v) : RegionDrag (e, i, p, v) - , _have_transaction (false) { - + DEBUG_TRACE (DEBUG::Drags, "New TrimDrag\n"); } void -TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *) +TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor*) { double speed = 1.0; TimeAxisView* tvp = &_primary->get_time_axis_view (); @@ -1744,39 +1576,47 @@ TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *) speed = tv->track()->speed(); } - nframes64_t const region_start = (nframes64_t) (_primary->region()->position() / speed); - nframes64_t const region_end = (nframes64_t) (_primary->region()->last_frame() / speed); - nframes64_t const region_length = (nframes64_t) (_primary->region()->length() / speed); + framepos_t const region_start = (framepos_t) (_primary->region()->position() / speed); + framepos_t const region_end = (framepos_t) (_primary->region()->last_frame() / speed); + framecnt_t const region_length = (framecnt_t) (_primary->region()->length() / speed); - nframes64_t const pf = adjusted_current_frame (event); + framepos_t const pf = adjusted_current_frame (event); if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) { + /* Move the contents of the region around without changing the region bounds */ _operation = ContentsTrim; - Drag::start_grab (event, _editor->trimmer_cursor); + Drag::start_grab (event, _editor->cursors()->trimmer); } else { /* These will get overridden for a point trim.*/ if (pf < (region_start + region_length/2)) { - /* closer to start */ + /* closer to front */ _operation = StartTrim; - Drag::start_grab (event, _editor->left_side_trim_cursor); + Drag::start_grab (event, _editor->cursors()->left_side_trim); } else { /* closer to end */ _operation = EndTrim; - Drag::start_grab (event, _editor->right_side_trim_cursor); - } + Drag::start_grab (event, _editor->cursors()->right_side_trim); + } } switch (_operation) { case StartTrim: - _editor->show_verbose_time_cursor (region_start, 10); + show_verbose_cursor_time (region_start); + for (list::iterator i = _views.begin(); i != _views.end(); ++i) { + i->view->trim_front_starting (); + } break; case EndTrim: - _editor->show_verbose_time_cursor (region_end, 10); + show_verbose_cursor_time (region_end); break; case ContentsTrim: - _editor->show_verbose_time_cursor (pf, 10); + show_verbose_cursor_time (pf); break; } + + for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { + i->view->region()->suspend_property_changes (); + } } void @@ -1784,11 +1624,6 @@ TrimDrag::motion (GdkEvent* event, bool first_move) { RegionView* rv = _primary; - /* snap modifier works differently here.. - its current state has to be passed to the - various trim functions in order to work properly - */ - double speed = 1.0; TimeAxisView* tvp = &_primary->get_time_axis_view (); RouteTimeAxisView* tv = dynamic_cast(tvp); @@ -1798,7 +1633,7 @@ TrimDrag::motion (GdkEvent* event, bool first_move) speed = tv->track()->speed(); } - nframes64_t const pf = adjusted_current_frame (event); + framecnt_t const dt = adjusted_current_frame (event) - raw_grab_frame () + _pointer_frame_offset; if (first_move) { @@ -1817,18 +1652,16 @@ TrimDrag::motion (GdkEvent* event, bool first_move) } _editor->begin_reversible_command (trim_type); - _have_transaction = true; for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { RegionView* rv = i->view; - rv->fake_set_opaque(false); + rv->fake_set_opaque (false); rv->enable_display (false); - rv->region()->clear_changes (); - rv->region()->suspend_property_changes (); + rv->region()->playlist()->clear_owned_changes (); AudioRegionView* const arv = dynamic_cast (rv); - if (arv){ + if (arv) { arv->temporarily_hide_envelope (); } @@ -1850,13 +1683,13 @@ TrimDrag::motion (GdkEvent* event, bool first_move) switch (_operation) { case StartTrim: for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { - _editor->single_start_trim (*i->view, pf, non_overlap_trim); + i->view->trim_front (i->initial_position + dt, non_overlap_trim); } break; case EndTrim: for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { - _editor->single_end_trim (*i->view, pf, non_overlap_trim); + i->view->trim_end (i->initial_end + dt, non_overlap_trim); } break; @@ -1868,21 +1701,21 @@ TrimDrag::motion (GdkEvent* event, bool first_move) swap_direction = true; } - nframes64_t frame_delta = 0; - + framecnt_t frame_delta = 0; + bool left_direction = false; - if (last_pointer_frame() > pf) { + if (last_pointer_frame() > adjusted_current_frame(event)) { left_direction = true; } if (left_direction) { - frame_delta = (last_pointer_frame() - pf); + frame_delta = (last_pointer_frame() - adjusted_current_frame(event)); } else { - frame_delta = (pf - last_pointer_frame()); + frame_delta = (adjusted_current_frame(event) - last_pointer_frame()); } for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { - _editor->single_contents_trim (*i->view, frame_delta, left_direction, swap_direction); + i->view->trim_contents (frame_delta, left_direction, swap_direction); } } break; @@ -1890,13 +1723,13 @@ TrimDrag::motion (GdkEvent* event, bool first_move) switch (_operation) { case StartTrim: - _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10); + show_verbose_cursor_time ((framepos_t) (rv->region()->position() / speed)); break; case EndTrim: - _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10); + show_verbose_cursor_time ((framepos_t) (rv->region()->last_frame() / speed)); break; case ContentsTrim: - _editor->show_verbose_time_cursor (pf, 10); + show_verbose_cursor_time (adjusted_current_frame (event)); break; } } @@ -1908,17 +1741,39 @@ TrimDrag::finished (GdkEvent* event, bool movement_occurred) if (movement_occurred) { motion (event, false); + /* This must happen before the region's StatefulDiffCommand is created, as it may + `correct' (ahem) the region's _start from being negative to being zero. It + needs to be zero in the undo record. + */ + if (_operation == StartTrim) { + for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { + i->view->trim_front_ending (); + } + } + if (!_editor->selection->selected (_primary)) { - _editor->thaw_region_after_trim (*_primary); + _primary->thaw_after_trim (); } else { + set > diffed_playlists; + for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { - _editor->thaw_region_after_trim (*i->view); + i->view->thaw_after_trim (); i->view->enable_display (true); i->view->fake_set_opaque (true); - if (_have_transaction) { - _editor->session()->add_command (new StatefulDiffCommand (i->view->region())); - } + + /* Trimming one region may affect others on the playlist, so we need + to get undo Commands from the whole playlist rather than just the + region. Use diffed_playlists to make sure we don't diff a given + playlist more than once. + */ + boost::shared_ptr p = i->view->region()->playlist (); + if (diffed_playlists.find (p) == diffed_playlists.end()) { + vector cmds; + p->rdiff (cmds); + _editor->session()->add_commands (cmds); + diffed_playlists.insert (p); + } } } for (set >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) { @@ -1926,19 +1781,24 @@ TrimDrag::finished (GdkEvent* event, bool movement_occurred) } _editor->motion_frozen_playlists.clear (); - - if (_have_transaction) { - _editor->commit_reversible_command(); - } + _editor->commit_reversible_command(); } else { /* no mouse movement */ _editor->point_trim (event, adjusted_current_frame (event)); } + + for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { + if (_operation == StartTrim) { + i->view->trim_front_ending (); + } + + i->view->region()->resume_property_changes (); + } } void -TrimDrag::aborted () +TrimDrag::aborted (bool movement_occurred) { /* Our motion method is changing model state, so use the Undo system to cancel. Perhaps not ideal, as this will leave an Undo point @@ -1946,16 +1806,46 @@ TrimDrag::aborted () */ finished (0, true); - - if (_have_transaction) { + + if (movement_occurred) { _editor->undo (); } + + for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { + i->view->region()->resume_property_changes (); + } +} + +void +TrimDrag::setup_pointer_frame_offset () +{ + list::iterator i = _views.begin (); + while (i != _views.end() && i->view != _primary) { + ++i; + } + + if (i == _views.end()) { + return; + } + + switch (_operation) { + case StartTrim: + _pointer_frame_offset = raw_grab_frame() - i->initial_position; + break; + case EndTrim: + _pointer_frame_offset = raw_grab_frame() - i->initial_end; + break; + case ContentsTrim: + break; + } } MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c) : Drag (e, i), _copy (c) { + DEBUG_TRACE (DEBUG::Drags, "New MeterMarkerDrag\n"); + _marker = reinterpret_cast (_item->get_data ("marker")); assert (_marker); } @@ -1968,8 +1858,14 @@ MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) // The actual copying is not done before we reach the finish callback. char name[64]; snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ()); - MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name, - *new MeterSection (_marker->meter())); + + MeterMarker* new_marker = new MeterMarker ( + *_editor, + *_editor->meter_group, + ARDOUR_UI::config()->canvasvar_MeterMarker.get(), + name, + *new MeterSection (_marker->meter()) + ); _item = &new_marker->the_item (); _marker = new_marker; @@ -1986,19 +1882,23 @@ MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) Drag::start_grab (event, cursor); - _pointer_frame_offset = grab_frame() - _marker->meter().frame(); + show_verbose_cursor_time (adjusted_current_frame(event)); +} - _editor->show_verbose_time_cursor (adjusted_current_frame(event), 10); +void +MeterMarkerDrag::setup_pointer_frame_offset () +{ + _pointer_frame_offset = raw_grab_frame() - _marker->meter().frame(); } void MeterMarkerDrag::motion (GdkEvent* event, bool) { - nframes64_t const pf = adjusted_current_frame (event); + framepos_t const pf = adjusted_current_frame (event); _marker->set_position (pf); - - _editor->show_verbose_time_cursor (pf, 10); + + show_verbose_cursor_time (pf); } void @@ -2010,7 +1910,7 @@ MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred) motion (event, false); - BBT_Time when; + Timecode::BBT_Time when; TempoMap& map (_editor->session()->tempo_map()); map.bbt_time (last_pointer_frame(), when); @@ -2037,7 +1937,7 @@ MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred) } void -MeterMarkerDrag::aborted () +MeterMarkerDrag::aborted (bool) { _marker->set_position (_marker->meter().frame ()); } @@ -2046,6 +1946,8 @@ TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c) : Drag (e, i), _copy (c) { + DEBUG_TRACE (DEBUG::Drags, "New TempoMarkerDrag\n"); + _marker = reinterpret_cast (_item->get_data ("marker")); assert (_marker); } @@ -2053,40 +1955,43 @@ TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c) void TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) { - if (_copy) { // create a dummy marker for visual representation of moving the copy. // The actual copying is not done before we reach the finish callback. char name[64]; snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute()); - TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name, - *new TempoSection (_marker->tempo())); + + TempoMarker* new_marker = new TempoMarker ( + *_editor, + *_editor->tempo_group, + ARDOUR_UI::config()->canvasvar_TempoMarker.get(), + name, + *new TempoSection (_marker->tempo()) + ); _item = &new_marker->the_item (); _marker = new_marker; - } else { - - MetricSection& section (_marker->tempo()); - - if (!section.movable()) { - return; - } } Drag::start_grab (event, cursor); - _pointer_frame_offset = grab_frame() - _marker->tempo().frame(); - _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10); + show_verbose_cursor_time (adjusted_current_frame (event)); +} + +void +TempoMarkerDrag::setup_pointer_frame_offset () +{ + _pointer_frame_offset = raw_grab_frame() - _marker->tempo().frame(); } void TempoMarkerDrag::motion (GdkEvent* event, bool) { - nframes64_t const pf = adjusted_current_frame (event); + framepos_t const pf = adjusted_current_frame (event); _marker->set_position (pf); - _editor->show_verbose_time_cursor (pf, 10); + show_verbose_cursor_time (pf); } void @@ -2098,7 +2003,7 @@ TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred) motion (event, false); - BBT_Time when; + Timecode::BBT_Time when; TempoMap& map (_editor->session()->tempo_map()); map.bbt_time (last_pointer_frame(), when); @@ -2125,7 +2030,7 @@ TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred) } void -TempoMarkerDrag::aborted () +TempoMarkerDrag::aborted (bool) { _marker->set_position (_marker->tempo().frame()); } @@ -2134,78 +2039,71 @@ CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s) : Drag (e, i), _stop (s) { - _cursor = reinterpret_cast (_item->get_data ("cursor")); - assert (_cursor); + DEBUG_TRACE (DEBUG::Drags, "New CursorDrag\n"); } +/** Do all the things we do when dragging the playhead to make it look as though + * we have located, without actually doing the locate (because that would cause + * the diskstream buffers to be refilled, which is too slow). + */ void -CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c) +CursorDrag::fake_locate (framepos_t t) { - Drag::start_grab (event, c); + _editor->playhead_cursor->set_position (t); - if (!_stop) { + Session* s = _editor->session (); + if (s->timecode_transmission_suspended ()) { + framepos_t const f = _editor->playhead_cursor->current_frame; + s->send_mmc_locate (f); + s->send_full_time_code (f); + } - nframes64_t where = _editor->event_frame (event, 0, 0); + show_verbose_cursor_time (t); + _editor->UpdateAllTransportClocks (t); +} - _editor->snap_to_with_modifier (where, event); - _editor->playhead_cursor->set_position (where); +void +CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c) +{ + Drag::start_grab (event, c); - } + _grab_zoom = _editor->frames_per_unit; - if (_cursor == _editor->playhead_cursor) { - _editor->_dragging_playhead = true; + framepos_t where = _editor->event_frame (event, 0, 0); + _editor->snap_to_with_modifier (where, event); - Session* s = _editor->session (); + _editor->_dragging_playhead = true; - if (s) { - if (_was_rolling && _stop) { - s->request_stop (); - } + Session* s = _editor->session (); - if (s->is_auditioning()) { - s->cancel_audition (); - } + if (s) { + if (_was_rolling && _stop) { + s->request_stop (); + } - s->request_suspend_timecode_transmission (); + if (s->is_auditioning()) { + s->cancel_audition (); + } - if (s->timecode_transmission_suspended ()) { - nframes64_t const f = _editor->playhead_cursor->current_frame; - s->send_mmc_locate (f); - s->send_full_time_code (f); - } + s->request_suspend_timecode_transmission (); + while (!s->timecode_transmission_suspended ()) { + /* twiddle our thumbs */ } } - _pointer_frame_offset = grab_frame() - _cursor->current_frame; - - _editor->show_verbose_time_cursor (_cursor->current_frame, 10); + fake_locate (where); } void CursorDrag::motion (GdkEvent* event, bool) { - nframes64_t const adjusted_frame = adjusted_current_frame (event); - - if (adjusted_frame == last_pointer_frame()) { - return; - } - - _cursor->set_position (adjusted_frame); - - _editor->show_verbose_time_cursor (_cursor->current_frame, 10); - - Session* s = _editor->session (); - if (s && _item == &_editor->playhead_cursor->canvas_item && s->timecode_transmission_suspended ()) { - nframes64_t const f = _editor->playhead_cursor->current_frame; - s->send_mmc_locate (f); - s->send_full_time_code (f); - } - - + framepos_t const adjusted_frame = adjusted_current_frame (event); + if (adjusted_frame != last_pointer_frame()) { + fake_locate (adjusted_frame); #ifdef GTKOSX - _editor->update_canvas_now (); + _editor->update_canvas_now (); #endif - _editor->UpdateAllTransportClocks (_cursor->current_frame); + } } void @@ -2219,31 +2117,29 @@ CursorDrag::finished (GdkEvent* event, bool movement_occurred) motion (event, false); - if (_item == &_editor->playhead_cursor->canvas_item) { - Session* s = _editor->session (); - if (s) { - s->request_locate (_editor->playhead_cursor->current_frame, _was_rolling); - _editor->_pending_locate_request = true; - s->request_resume_timecode_transmission (); - } + Session* s = _editor->session (); + if (s) { + s->request_locate (_editor->playhead_cursor->current_frame, _was_rolling); + _editor->_pending_locate_request = true; + s->request_resume_timecode_transmission (); } } void -CursorDrag::aborted () +CursorDrag::aborted (bool) { if (_editor->_dragging_playhead) { _editor->session()->request_resume_timecode_transmission (); _editor->_dragging_playhead = false; } - - _cursor->set_position (adjusted_frame (grab_frame (), 0, false)); + + _editor->playhead_cursor->set_position (adjusted_frame (grab_frame (), 0, false)); } FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list const & v) : RegionDrag (e, i, p, v) { - + DEBUG_TRACE (DEBUG::Drags, "New FadeInDrag\n"); } void @@ -2251,20 +2147,28 @@ FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) { Drag::start_grab (event, cursor); - AudioRegionView* a = dynamic_cast (_primary); - boost::shared_ptr const r = a->audio_region (); + AudioRegionView* arv = dynamic_cast (_primary); + boost::shared_ptr const r = arv->audio_region (); - _pointer_frame_offset = grab_frame() - ((nframes64_t) r->fade_in()->back()->when + r->position()); - _editor->show_verbose_duration_cursor (r->position(), r->position() + r->fade_in()->back()->when, 10); - + show_verbose_cursor_duration (r->position(), r->position() + r->fade_in()->back()->when, 32); + + arv->show_fade_line((framepos_t) r->fade_in()->back()->when); +} + +void +FadeInDrag::setup_pointer_frame_offset () +{ + AudioRegionView* arv = dynamic_cast (_primary); + boost::shared_ptr const r = arv->audio_region (); + _pointer_frame_offset = raw_grab_frame() - ((framecnt_t) r->fade_in()->back()->when + r->position()); } void FadeInDrag::motion (GdkEvent* event, bool) { - nframes64_t fade_length; + framecnt_t fade_length; - nframes64_t const pos = adjusted_current_frame (event); + framepos_t const pos = adjusted_current_frame (event); boost::shared_ptr region = _primary->region (); @@ -2285,9 +2189,10 @@ FadeInDrag::motion (GdkEvent* event, bool) } tmp->reset_fade_in_shape_width (fade_length); + tmp->show_fade_line((framecnt_t) fade_length); } - _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10); + show_verbose_cursor_duration (region->position(), region->position() + fade_length, 32); } void @@ -2297,9 +2202,9 @@ FadeInDrag::finished (GdkEvent* event, bool movement_occurred) return; } - nframes64_t fade_length; + framecnt_t fade_length; - nframes64_t const pos = adjusted_current_frame (event); + framepos_t const pos = adjusted_current_frame (event); boost::shared_ptr region = _primary->region (); @@ -2326,6 +2231,7 @@ FadeInDrag::finished (GdkEvent* event, bool movement_occurred) tmp->audio_region()->set_fade_in_length (fade_length); tmp->audio_region()->set_fade_in_active (true); + tmp->hide_fade_line(); XMLNode &after = alist->get_state(); _editor->session()->add_command(new MementoCommand(*alist.get(), &before, &after)); @@ -2335,7 +2241,7 @@ FadeInDrag::finished (GdkEvent* event, bool movement_occurred) } void -FadeInDrag::aborted () +FadeInDrag::aborted (bool) { for (list::iterator i = _views.begin(); i != _views.end(); ++i) { AudioRegionView* tmp = dynamic_cast (i->view); @@ -2345,13 +2251,14 @@ FadeInDrag::aborted () } tmp->reset_fade_in_shape_width (tmp->audio_region()->fade_in()->back()->when); + tmp->hide_fade_line(); } } FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list const & v) : RegionDrag (e, i, p, v) { - + DEBUG_TRACE (DEBUG::Drags, "New FadeOutDrag\n"); } void @@ -2359,19 +2266,28 @@ FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) { Drag::start_grab (event, cursor); - AudioRegionView* a = dynamic_cast (_primary); - boost::shared_ptr r = a->audio_region (); + AudioRegionView* arv = dynamic_cast (_primary); + boost::shared_ptr r = arv->audio_region (); + + show_verbose_cursor_duration (r->last_frame() - r->fade_out()->back()->when, r->last_frame()); + + arv->show_fade_line(r->length() - r->fade_out()->back()->when); +} - _pointer_frame_offset = grab_frame() - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position()); - _editor->show_verbose_duration_cursor (r->last_frame() - r->fade_out()->back()->when, r->last_frame(), 10); +void +FadeOutDrag::setup_pointer_frame_offset () +{ + AudioRegionView* arv = dynamic_cast (_primary); + boost::shared_ptr r = arv->audio_region (); + _pointer_frame_offset = raw_grab_frame() - (r->length() - (framecnt_t) r->fade_out()->back()->when + r->position()); } void FadeOutDrag::motion (GdkEvent* event, bool) { - nframes64_t fade_length; + framecnt_t fade_length; - nframes64_t const pos = adjusted_current_frame (event); + framepos_t const pos = adjusted_current_frame (event); boost::shared_ptr region = _primary->region (); @@ -2394,9 +2310,10 @@ FadeOutDrag::motion (GdkEvent* event, bool) } tmp->reset_fade_out_shape_width (fade_length); + tmp->show_fade_line(region->length() - fade_length); } - _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10); + show_verbose_cursor_duration (region->last_frame() - fade_length, region->last_frame()); } void @@ -2406,9 +2323,9 @@ FadeOutDrag::finished (GdkEvent* event, bool movement_occurred) return; } - nframes64_t fade_length; + framecnt_t fade_length; - nframes64_t const pos = adjusted_current_frame (event); + framepos_t const pos = adjusted_current_frame (event); boost::shared_ptr region = _primary->region (); @@ -2437,6 +2354,7 @@ FadeOutDrag::finished (GdkEvent* event, bool movement_occurred) tmp->audio_region()->set_fade_out_length (fade_length); tmp->audio_region()->set_fade_out_active (true); + tmp->hide_fade_line(); XMLNode &after = alist->get_state(); _editor->session()->add_command(new MementoCommand(*alist.get(), &before, &after)); @@ -2446,7 +2364,7 @@ FadeOutDrag::finished (GdkEvent* event, bool movement_occurred) } void -FadeOutDrag::aborted () +FadeOutDrag::aborted (bool) { for (list::iterator i = _views.begin(); i != _views.end(); ++i) { AudioRegionView* tmp = dynamic_cast (i->view); @@ -2456,24 +2374,20 @@ FadeOutDrag::aborted () } tmp->reset_fade_out_shape_width (tmp->audio_region()->fade_out()->back()->when); + tmp->hide_fade_line(); } } MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i) : Drag (e, i) { + DEBUG_TRACE (DEBUG::Drags, "New MarkerDrag\n"); + _marker = reinterpret_cast (_item->get_data ("marker")); assert (_marker); _points.push_back (Gnome::Art::Point (0, 0)); _points.push_back (Gnome::Art::Point (0, physical_screen_height (_editor->get_window()))); - - _line = new ArdourCanvas::Line (*_editor->timebar_group); - _line->property_width_pixels() = 1; - _line->property_points () = _points; - _line->hide (); - - _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get(); } MarkerDrag::~MarkerDrag () @@ -2493,17 +2407,15 @@ MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) Location *location = _editor->find_location_from_marker (_marker, is_start); _editor->_dragging_edit_point = true; - _pointer_frame_offset = grab_frame() - (is_start ? location->start() : location->end()); - update_item (location); // _drag_line->show(); // _line->raise_to_top(); if (is_start) { - _editor->show_verbose_time_cursor (location->start(), 10); + show_verbose_cursor_time (location->start()); } else { - _editor->show_verbose_time_cursor (location->end(), 10); + show_verbose_cursor_time (location->end()); } Selection::Operation op = ArdourKeyboard::selection_type (event->button.state); @@ -2521,13 +2433,13 @@ MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) { Locations::LocationList ll; list to_add; - nframes64_t s, e; + framepos_t s, e; _editor->selection->markers.range (s, e); s = min (_marker->position(), s); e = max (_marker->position(), e); s = min (s, e); e = max (s, e); - if (e < max_frames) { + if (e < max_framepos) { ++e; } _editor->session()->locations()->find_all_between (s, e, ll, Location::Flags (0)); @@ -2560,23 +2472,27 @@ MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) } } +void +MarkerDrag::setup_pointer_frame_offset () +{ + bool is_start; + Location *location = _editor->find_location_from_marker (_marker, is_start); + _pointer_frame_offset = raw_grab_frame() - (is_start ? location->start() : location->end()); +} + void MarkerDrag::motion (GdkEvent* event, bool) { - nframes64_t f_delta = 0; + framecnt_t f_delta = 0; bool is_start; bool move_both = false; Marker* marker; Location *real_location; Location *copy_location = 0; - nframes64_t const newframe = adjusted_current_frame (event); + framepos_t const newframe = adjusted_current_frame (event); - nframes64_t next = newframe; - - if (newframe == last_pointer_frame()) { - return; - } + framepos_t next = newframe; if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) { move_both = true; @@ -2607,13 +2523,15 @@ MarkerDrag::motion (GdkEvent* event, bool) switch (marker->type()) { - case Marker::Start: + case Marker::SessionStart: + case Marker::RangeStart: case Marker::LoopStart: case Marker::PunchIn: f_delta = newframe - copy_location->start(); break; - case Marker::End: + case Marker::SessionEnd: + case Marker::RangeEnd: case Marker::LoopEnd: case Marker::PunchOut: f_delta = newframe - copy_location->end(); @@ -2659,8 +2577,8 @@ MarkerDrag::motion (GdkEvent* event, bool) } else { - nframes64_t new_start = copy_location->start() + f_delta; - nframes64_t new_end = copy_location->end() + f_delta; + framepos_t new_start = copy_location->start() + f_delta; + framepos_t new_end = copy_location->end() + f_delta; if (is_start) { // start-of-range marker @@ -2669,7 +2587,7 @@ MarkerDrag::motion (GdkEvent* event, bool) copy_location->set_end (new_end); } else if (new_start < copy_location->end()) { copy_location->set_start (new_start); - } else { + } else if (newframe > 0) { _editor->snap_to (next, 1, true); copy_location->set_end (next); copy_location->set_start (newframe); @@ -2701,7 +2619,7 @@ MarkerDrag::motion (GdkEvent* event, bool) assert (!_copied_locations.empty()); - _editor->show_verbose_time_cursor (newframe, 10); + show_verbose_cursor_time (newframe); #ifdef GTKOSX _editor->update_canvas_now (); @@ -2767,24 +2685,18 @@ MarkerDrag::finished (GdkEvent* event, bool movement_occurred) XMLNode &after = _editor->session()->locations()->get_state(); _editor->session()->add_command(new MementoCommand(*(_editor->session()->locations()), &before, &after)); _editor->commit_reversible_command (); - - _line->hide(); } void -MarkerDrag::aborted () +MarkerDrag::aborted (bool) { /* XXX: TODO */ } void -MarkerDrag::update_item (Location* location) +MarkerDrag::update_item (Location*) { - double const x1 = _editor->frame_to_pixel (location->start()); - - _points.front().set_x(x1); - _points.back().set_x(x1); - _line->property_points() = _points; + /* noop */ } ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i) @@ -2792,6 +2704,12 @@ ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i) _cumulative_x_drag (0), _cumulative_y_drag (0) { + if (_zero_gain_fraction < 0.0) { + _zero_gain_fraction = gain_to_slider_position_with_max (dB_to_coefficient (0.0), Config->get_max_gain()); + } + + DEBUG_TRACE (DEBUG::Drags, "New ControlPointDrag\n"); + _point = reinterpret_cast (_item->get_data ("control_point")); assert (_point); } @@ -2800,7 +2718,7 @@ ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i) void ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/) { - Drag::start_grab (event, _editor->fader_cursor); + Drag::start_grab (event, _editor->cursors()->fader); // start the grab at the center of the control point so // the point doesn't 'jump' to the mouse after the first drag @@ -2811,10 +2729,10 @@ ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/) _point->line().start_drag_single (_point, _fixed_grab_x, fraction); - _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction), - event->button.x + 10, event->button.y + 10); + _editor->verbose_cursor()->set (_point->line().get_verbose_cursor_string (fraction), + event->button.x + 10, event->button.y + 10); - _editor->show_verbose_canvas_cursor (); + _editor->verbose_cursor()->show (); } void @@ -2857,7 +2775,7 @@ ControlPointDrag::motion (GdkEvent* event, bool) cy = min ((double) _point->line().height(), cy); framepos_t cx_frames = _editor->unit_to_frame (cx); - + if (!_x_constrained) { _editor->snap_to_with_modifier (cx_frames, event); } @@ -2870,7 +2788,7 @@ ControlPointDrag::motion (GdkEvent* event, bool) _point->line().drag_motion (_editor->frame_to_unit (cx_frames), fraction, false, push); - _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction)); + _editor->verbose_cursor()->set_text (_point->line().get_verbose_cursor_string (fraction)); } void @@ -2887,11 +2805,13 @@ ControlPointDrag::finished (GdkEvent* event, bool movement_occurred) } else { motion (event, false); } + _point->line().end_drag (); + _editor->session()->commit_reversible_command (); } void -ControlPointDrag::aborted () +ControlPointDrag::aborted (bool) { _point->line().reset (); } @@ -2913,8 +2833,9 @@ LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i) _line (0), _cumulative_y_drag (0) { - + DEBUG_TRACE (DEBUG::Drags, "New LineDrag\n"); } + void LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/) { @@ -2932,17 +2853,17 @@ LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/) _line->parent_group().w2i (cx, cy); - nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit); + framecnt_t const frame_within_region = (framecnt_t) floor (cx * _editor->frames_per_unit); uint32_t before; uint32_t after; - + if (!_line->control_points_adjacent (frame_within_region, before, after)) { /* no adjacent points */ return; } - Drag::start_grab (event, _editor->fader_cursor); + Drag::start_grab (event, _editor->cursors()->fader); /* store grab start in parent frame */ @@ -2953,10 +2874,10 @@ LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/) _line->start_drag_line (before, after, fraction); - _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction), - event->button.x + 10, event->button.y + 10); + _editor->verbose_cursor()->set (_line->get_verbose_cursor_string (fraction), + event->button.x + 10, event->button.y + 10); - _editor->show_verbose_canvas_cursor (); + _editor->verbose_cursor()->show (); } void @@ -2988,7 +2909,7 @@ LineDrag::motion (GdkEvent* event, bool) /* we are ignoring x position for this drag, so we can just pass in anything */ _line->drag_motion (0, fraction, true, push); - _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction)); + _editor->verbose_cursor()->set_text (_line->get_verbose_cursor_string (fraction)); } void @@ -2996,10 +2917,11 @@ LineDrag::finished (GdkEvent* event, bool) { motion (event, false); _line->end_drag (); + _editor->session()->commit_reversible_command (); } void -LineDrag::aborted () +LineDrag::aborted (bool) { _line->reset (); } @@ -3009,15 +2931,15 @@ FeatureLineDrag::FeatureLineDrag (Editor* e, ArdourCanvas::Item* i) _line (0), _cumulative_x_drag (0) { - + DEBUG_TRACE (DEBUG::Drags, "New FeatureLineDrag\n"); } + void FeatureLineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/) { - Drag::start_grab (event); - - _line = reinterpret_cast (_item); + + _line = reinterpret_cast (_item); assert (_line); /* need to get x coordinate in terms of parent (AudioRegionView) origin. */ @@ -3029,69 +2951,88 @@ FeatureLineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/) /* store grab start in parent frame */ _region_view_grab_x = cx; - - _before = _line->property_x1(); - + + _before = *(float*) _item->get_data ("position"); + _arv = reinterpret_cast (_item->get_data ("regionview")); - + _max_x = _editor->frame_to_pixel(_arv->get_duration()); } void -FeatureLineDrag::motion (GdkEvent* event, bool) +FeatureLineDrag::motion (GdkEvent*, bool) { double dx = _drags->current_pointer_x() - last_pointer_x(); - + double cx = _region_view_grab_x + _cumulative_x_drag + dx; - + _cumulative_x_drag += dx; - + /* Clamp the min and max extent of the drag to keep it within the region view bounds */ - + if (cx > _max_x){ cx = _max_x; } else if(cx < 0){ cx = 0; } - - _line->property_x1() = cx; - _line->property_x2() = cx; - _before = _line->property_x1(); + ArdourCanvas::Points points; + + double x1 = 0, x2 = 0, y1 = 0, y2 = 0; + + _line->get_bounds(x1, y2, x2, y2); + + points.push_back(Gnome::Art::Point(cx, 2.0)); // first x-coord needs to be a non-normal value + points.push_back(Gnome::Art::Point(cx, y2 - y1)); + + _line->property_points() = points; + + float *pos = new float; + *pos = cx; + + _line->set_data ("position", pos); + + _before = cx; } void -FeatureLineDrag::finished (GdkEvent* event, bool) +FeatureLineDrag::finished (GdkEvent*, bool) { _arv = reinterpret_cast (_item->get_data ("regionview")); - _arv->update_transient(_before, _line->property_x1()); + _arv->update_transient(_before, _before); } void -FeatureLineDrag::aborted () +FeatureLineDrag::aborted (bool) { //_line->reset (); } +RubberbandSelectDrag::RubberbandSelectDrag (Editor* e, ArdourCanvas::Item* i) + : Drag (e, i) +{ + DEBUG_TRACE (DEBUG::Drags, "New RubberbandSelectDrag\n"); +} + void RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *) { Drag::start_grab (event); - _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10); + show_verbose_cursor_time (adjusted_current_frame (event)); } void RubberbandSelectDrag::motion (GdkEvent* event, bool) { - nframes64_t start; - nframes64_t end; + framepos_t start; + framepos_t end; double y1; double y2; - nframes64_t const pf = adjusted_current_frame (event, Config->get_rubberbanding_snaps_to_grid ()); + framepos_t const pf = adjusted_current_frame (event, Config->get_rubberbanding_snaps_to_grid ()); - nframes64_t grab = grab_frame (); + framepos_t grab = grab_frame (); if (Config->get_rubberbanding_snaps_to_grid ()) { _editor->snap_to_with_modifier (grab, event); } @@ -3128,66 +3069,75 @@ RubberbandSelectDrag::motion (GdkEvent* event, bool) _editor->rubberband_rect->show(); _editor->rubberband_rect->raise_to_top(); - _editor->show_verbose_time_cursor (pf, 10); + show_verbose_cursor_time (pf); + + do_select_things (event, true); } } void -RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred) +RubberbandSelectDrag::do_select_things (GdkEvent* event, bool drag_in_progress) { - if (movement_occurred) { - - motion (event, false); + framepos_t x1; + framepos_t x2; + + if (grab_frame() < last_pointer_frame()) { + x1 = grab_frame (); + x2 = last_pointer_frame (); + } else { + x2 = grab_frame (); + x1 = last_pointer_frame (); + } - double y1,y2; - if (_drags->current_pointer_y() < grab_y()) { - y1 = _drags->current_pointer_y(); - y2 = grab_y(); - } else { - y2 = _drags->current_pointer_y(); - y1 = grab_y(); - } + double y1; + double y2; + + if (_drags->current_pointer_y() < grab_y()) { + y1 = _drags->current_pointer_y(); + y2 = grab_y(); + } else { + y2 = _drags->current_pointer_y(); + y1 = grab_y(); + } + select_things (event->button.state, x1, x2, y1, y2, drag_in_progress); +} - Selection::Operation op = ArdourKeyboard::selection_type (event->button.state); - bool committed; +void +RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred) +{ + if (movement_occurred) { - _editor->begin_reversible_command (_("rubberband selection")); + motion (event, false); + do_select_things (event, false); - if (grab_frame() < last_pointer_frame()) { - committed = _editor->select_all_within (grab_frame(), last_pointer_frame() - 1, y1, y2, _editor->track_views, op, false); - } else { - committed = _editor->select_all_within (last_pointer_frame(), grab_frame() - 1, y1, y2, _editor->track_views, op, false); - } + } else { - if (!committed) { - _editor->commit_reversible_command (); - } + deselect_things (); - } else { - if (!getenv("ARDOUR_SAE")) { - _editor->selection->clear_tracks(); - } - _editor->selection->clear_regions(); - _editor->selection->clear_points (); - _editor->selection->clear_lines (); } _editor->rubberband_rect->hide(); } void -RubberbandSelectDrag::aborted () +RubberbandSelectDrag::aborted (bool) { _editor->rubberband_rect->hide (); } +TimeFXDrag::TimeFXDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, std::list const & v) + : RegionDrag (e, i, p, v) +{ + DEBUG_TRACE (DEBUG::Drags, "New TimeFXDrag\n"); +} + 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); + show_verbose_cursor_time (adjusted_current_frame (event)); } void @@ -3195,13 +3145,13 @@ TimeFXDrag::motion (GdkEvent* event, bool) { RegionView* rv = _primary; - nframes64_t const pf = adjusted_current_frame (event); + framepos_t const pf = adjusted_current_frame (event); if (pf > rv->region()->position()) { rv->get_time_axis_view().show_timestretch (rv->region()->position(), pf); } - _editor->show_verbose_time_cursor (pf, 10); + show_verbose_cursor_time (pf); } void @@ -3218,7 +3168,7 @@ TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred) return; } - nframes64_t newlen = last_pointer_frame() - _primary->region()->position(); + framecnt_t newlen = last_pointer_frame() - _primary->region()->position(); float percentage = (double) newlen / (double) _primary->region()->length(); @@ -3229,8 +3179,6 @@ TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred) } #endif - _editor->begin_reversible_command (_("timestretch")); - // XXX how do timeFX on multiple regions ? RegionSelection rs; @@ -3242,11 +3190,16 @@ TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred) } void -TimeFXDrag::aborted () +TimeFXDrag::aborted (bool) { _primary->get_time_axis_view().hide_timestretch (); } +ScrubDrag::ScrubDrag (Editor* e, ArdourCanvas::Item* i) + : Drag (e, i) +{ + DEBUG_TRACE (DEBUG::Drags, "New ScrubDrag\n"); +} void ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *) @@ -3270,7 +3223,7 @@ ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred) } void -ScrubDrag::aborted () +ScrubDrag::aborted (bool) { /* XXX: TODO */ } @@ -3282,15 +3235,12 @@ SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o) , _original_pointer_time_axis (-1) , _last_pointer_time_axis (-1) { - + DEBUG_TRACE (DEBUG::Drags, "New SelectionDrag\n"); } void SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*) { - nframes64_t start = 0; - nframes64_t end = 0; - if (_editor->session() == 0) { return; } @@ -3304,7 +3254,7 @@ SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*) } else { _copy = false; } - cursor = _editor->selector_cursor; + cursor = _editor->cursors()->selector; Drag::start_grab (event, cursor); break; @@ -3312,49 +3262,62 @@ SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*) if (_editor->clicked_axisview) { _editor->clicked_axisview->order_selection_trims (_item, true); } - Drag::start_grab (event, _editor->left_side_trim_cursor); - start = _editor->selection->time[_editor->clicked_selection].start; - _pointer_frame_offset = grab_frame() - start; + Drag::start_grab (event, _editor->cursors()->left_side_trim); break; case SelectionEndTrim: if (_editor->clicked_axisview) { _editor->clicked_axisview->order_selection_trims (_item, false); } - Drag::start_grab (event, _editor->right_side_trim_cursor); - end = _editor->selection->time[_editor->clicked_selection].end; - _pointer_frame_offset = grab_frame() - end; + Drag::start_grab (event, _editor->cursors()->right_side_trim); break; case SelectionMove: - start = _editor->selection->time[_editor->clicked_selection].start; Drag::start_grab (event, cursor); - _pointer_frame_offset = grab_frame() - start; break; } if (_operation == SelectionMove) { - _editor->show_verbose_time_cursor (start, 10); + show_verbose_cursor_time (_editor->selection->time[_editor->clicked_selection].start); } else { - _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10); + show_verbose_cursor_time (adjusted_current_frame (event)); } _original_pointer_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ()).first->order (); } +void +SelectionDrag::setup_pointer_frame_offset () +{ + switch (_operation) { + case CreateSelection: + _pointer_frame_offset = 0; + break; + + case SelectionStartTrim: + case SelectionMove: + _pointer_frame_offset = raw_grab_frame() - _editor->selection->time[_editor->clicked_selection].start; + break; + + case SelectionEndTrim: + _pointer_frame_offset = raw_grab_frame() - _editor->selection->time[_editor->clicked_selection].end; + break; + } +} + void SelectionDrag::motion (GdkEvent* event, bool first_move) { - nframes64_t start = 0; - nframes64_t end = 0; - nframes64_t length; + framepos_t start = 0; + framepos_t end = 0; + framecnt_t length; pair const pending_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ()); if (pending_time_axis.first == 0) { return; } - - nframes64_t const pending_position = adjusted_current_frame (event); + + framepos_t const pending_position = adjusted_current_frame (event); /* only alter selection if things have changed */ @@ -3365,7 +3328,7 @@ SelectionDrag::motion (GdkEvent* event, bool first_move) switch (_operation) { case CreateSelection: { - nframes64_t grab = grab_frame (); + framepos_t grab = grab_frame (); if (first_move) { _editor->snap_to (grab); @@ -3387,22 +3350,25 @@ SelectionDrag::motion (GdkEvent* event, bool first_move) if (_copy) { /* adding to the selection */ - _editor->selection->add (_editor->clicked_axisview); + _editor->set_selected_track_as_side_effect (Selection::Add); + //_editor->selection->add (_editor->clicked_axisview); _editor->clicked_selection = _editor->selection->add (start, end); _copy = false; } else { /* new selection */ if (_editor->clicked_axisview && !_editor->selection->selected (_editor->clicked_axisview)) { - _editor->selection->set (_editor->clicked_axisview); + //_editor->selection->set (_editor->clicked_axisview); + _editor->set_selected_track_as_side_effect (Selection::Set); } - + _editor->clicked_selection = _editor->selection->set (start, end); } } /* select the track that we're in */ if (find (_added_time_axes.begin(), _added_time_axes.end(), pending_time_axis.first) == _added_time_axes.end()) { + // _editor->set_selected_track_as_side_effect (Selection::Add); _editor->selection->add (pending_time_axis.first); _added_time_axes.push_back (pending_time_axis.first); } @@ -3410,7 +3376,7 @@ SelectionDrag::motion (GdkEvent* event, bool first_move) /* deselect any tracks that this drag no longer includes, being careful to only deselect tracks that we selected in the first place. */ - + int min_order = min (_original_pointer_time_axis, pending_time_axis.first->order()); int max_order = max (_original_pointer_time_axis, pending_time_axis.first->order()); @@ -3419,7 +3385,7 @@ SelectionDrag::motion (GdkEvent* event, bool first_move) list::iterator tmp = i; ++tmp; - + if ((*i)->order() < min_order || (*i)->order() > max_order) { _editor->selection->remove (*i); _added_time_axes.remove (*i); @@ -3480,9 +3446,9 @@ SelectionDrag::motion (GdkEvent* event, bool first_move) } if (_operation == SelectionMove) { - _editor->show_verbose_time_cursor(start, 10); + show_verbose_cursor_time(start); } else { - _editor->show_verbose_time_cursor(pending_position, 10); + show_verbose_cursor_time(pending_position); } } @@ -3514,7 +3480,7 @@ SelectionDrag::finished (GdkEvent* event, bool movement_occurred) if (_editor->clicked_axisview && !_editor->selection->selected (_editor->clicked_axisview)) { _editor->selection->set (_editor->clicked_axisview); } - + if (s && s->get_play_range () && s->transport_rolling()) { s->request_stop (false, false); } @@ -3525,7 +3491,7 @@ SelectionDrag::finished (GdkEvent* event, bool movement_occurred) } void -SelectionDrag::aborted () +SelectionDrag::aborted (bool) { /* XXX: TODO */ } @@ -3535,8 +3501,10 @@ RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operat _operation (o), _copy (false) { - _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, - physical_screen_height (_editor->get_window())); + DEBUG_TRACE (DEBUG::Drags, "New RangeMarkerBarDrag\n"); + + _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, + physical_screen_height (_editor->get_window())); _drag_rect->hide (); _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get(); @@ -3566,20 +3534,20 @@ RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *) } else { _copy = false; } - cursor = _editor->selector_cursor; + cursor = _editor->cursors()->selector; break; } Drag::start_grab (event, cursor); - _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10); + show_verbose_cursor_time (adjusted_current_frame (event)); } void RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move) { - nframes64_t start = 0; - nframes64_t end = 0; + framepos_t start = 0; + framepos_t end = 0; ArdourCanvas::SimpleRect *crect; switch (_operation) { @@ -3598,12 +3566,12 @@ RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move) break; } - nframes64_t const pf = adjusted_current_frame (event); + framepos_t const pf = adjusted_current_frame (event); if (_operation == CreateRangeMarker || _operation == CreateTransportMarker || _operation == CreateCDMarker) { - nframes64_t grab = grab_frame (); + framepos_t grab = grab_frame (); _editor->snap_to (grab); - + if (pf < grab_frame()) { start = pf; end = grab; @@ -3644,7 +3612,7 @@ RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move) update_item (_editor->temp_location); } - _editor->show_verbose_time_cursor (pf, 10); + show_verbose_cursor_time (pf); } @@ -3677,7 +3645,7 @@ RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred) newloc = new Location ( *_editor->session(), _editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags ); - + _editor->session()->locations()->add (newloc, true); XMLNode &after = _editor->session()->locations()->get_state(); _editor->session()->add_command(new MementoCommand(*(_editor->session()->locations()), &before, &after)); @@ -3695,16 +3663,16 @@ RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred) if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) { - nframes64_t start; - nframes64_t end; + framepos_t start; + framepos_t end; _editor->session()->locations()->marks_either_side (grab_frame(), start, end); - if (end == max_frames) { + if (end == max_framepos) { end = _editor->session()->current_end_frame (); } - if (start == max_frames) { + if (start == max_framepos) { start = _editor->session()->current_start_frame (); } @@ -3729,7 +3697,7 @@ RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred) } void -RangeMarkerBarDrag::aborted () +RangeMarkerBarDrag::aborted (bool) { /* XXX: TODO */ } @@ -3744,22 +3712,36 @@ RangeMarkerBarDrag::update_item (Location* location) _drag_rect->property_x2() = x2; } +MouseZoomDrag::MouseZoomDrag (Editor* e, ArdourCanvas::Item* i) + : Drag (e, i) + , _zoom_out (false) +{ + DEBUG_TRACE (DEBUG::Drags, "New MouseZoomDrag\n"); +} + void MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *) { - Drag::start_grab (event, _editor->zoom_cursor); - _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10); + if (Keyboard::the_keyboard().key_is_down (GDK_Control_L)) { + Drag::start_grab (event, _editor->cursors()->zoom_out); + _zoom_out = true; + } else { + Drag::start_grab (event, _editor->cursors()->zoom_in); + _zoom_out = false; + } + + show_verbose_cursor_time (adjusted_current_frame (event)); } void MouseZoomDrag::motion (GdkEvent* event, bool first_move) { - nframes64_t start; - nframes64_t end; + framepos_t start; + framepos_t end; - nframes64_t const pf = adjusted_current_frame (event); + framepos_t const pf = adjusted_current_frame (event); - nframes64_t grab = grab_frame (); + framepos_t grab = grab_frame (); _editor->snap_to_with_modifier (grab, event); /* base start and end on initial click position */ @@ -3780,7 +3762,7 @@ MouseZoomDrag::motion (GdkEvent* event, bool first_move) _editor->reposition_zoom_rect(start, end); - _editor->show_verbose_time_cursor (pf, 10); + show_verbose_cursor_time (pf); } } @@ -3796,18 +3778,18 @@ MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred) _editor->temporal_zoom_by_frame (last_pointer_frame(), grab_frame(), "mouse zoom"); } } else { - _editor->temporal_zoom_to_frame (false, grab_frame()); - /* - temporal_zoom_step (false); - center_screen (grab_frame()); - */ + if (Keyboard::the_keyboard().key_is_down (GDK_Shift_L)) { + _editor->tav_zoom_step (_zoom_out); + } else { + _editor->temporal_zoom_to_frame (_zoom_out, grab_frame()); + } } _editor->zoom_rect->hide(); } void -MouseZoomDrag::aborted () +MouseZoomDrag::aborted (bool) { _editor->zoom_rect->hide (); } @@ -3817,6 +3799,8 @@ NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i) , _cumulative_dx (0) , _cumulative_dy (0) { + DEBUG_TRACE (DEBUG::Drags, "New NoteDrag\n"); + _primary = dynamic_cast (_item); _region = &_primary->region_view (); _note_height = _region->midi_stream_view()->note_height (); @@ -3856,36 +3840,26 @@ NoteDrag::total_dx () const frameoffset_t const dx = _editor->unit_to_frame (_drags->current_pointer_x() - grab_x()); /* primary note time */ - frameoffset_t const n = _region->beats_to_frames (_primary->note()->time ()); - - /* new time of the primary note relative to the region position */ - frameoffset_t const st = n + dx; + frameoffset_t const n = _region->source_beats_to_absolute_frames (_primary->note()->time ()); + + /* new time of the primary note in session frames */ + frameoffset_t st = n + dx; + + framepos_t const rp = _region->region()->position (); + + /* prevent the note being dragged earlier than the region's position */ + st = max (st, rp); /* snap and return corresponding delta */ - return _region->snap_frame_to_frame (st) - n; + return _region->snap_frame_to_frame (st - rp) + rp - n; } -/** @return Current total drag y change in notes */ +/** @return Current total drag y change in note number */ int8_t NoteDrag::total_dy () const { - /* this is `backwards' to make increasing note number go in the right direction */ - double const dy = _drags->current_pointer_y() - grab_y(); - - /* dy in notes */ - int8_t ndy = 0; - - if (abs (dy) >= _note_height) { - if (dy > 0) { - ndy = (int8_t) ceil (dy / _note_height / 2.0); - } else { - ndy = (int8_t) floor (dy / _note_height / 2.0); - } - } - - return ndy; + return ((int8_t) (grab_y() / _note_height)) - ((int8_t) (_drags->current_pointer_y() / _note_height)); } - void NoteDrag::motion (GdkEvent *, bool) @@ -3896,19 +3870,30 @@ NoteDrag::motion (GdkEvent *, bool) /* Now work out what we have to do to the note canvas items to set this new drag delta */ double const tdx = _editor->frame_to_unit (dx) - _cumulative_dx; - double const tdy = dy * _note_height - _cumulative_dy; + double const tdy = -dy * _note_height - _cumulative_dy; if (tdx || tdy) { - _region->move_selection (tdx, tdy); _cumulative_dx += tdx; _cumulative_dy += tdy; - char buf[12]; - snprintf (buf, sizeof (buf), "%s (%d)", Evoral::midi_note_name (_primary->note()->note() + dy).c_str(), - (int) floor (_primary->note()->note() + dy)); + int8_t note_delta = total_dy(); + + _region->move_selection (tdx, tdy, note_delta); + + /* the new note value may be the same as the old one, but we + * don't know what that means because the selection may have + * involved more than one note and we might be doing something + * odd with them. so show the note value anyway, always. + */ + + char buf[12]; + uint8_t new_note = min (max (_primary->note()->note() + note_delta, 0), 127); - _editor->show_verbose_canvas_cursor_with (buf); - } + snprintf (buf, sizeof (buf), "%s (%d)", Evoral::midi_note_name (new_note).c_str(), + (int) floor (new_note)); + + show_verbose_cursor_text (buf); + } } void @@ -3936,25 +3921,59 @@ NoteDrag::finished (GdkEvent* ev, bool moved) } } } else { - _region->note_dropped (_primary, total_dx(), - total_dy()); + _region->note_dropped (_primary, total_dx(), total_dy()); } } void -NoteDrag::aborted () +NoteDrag::aborted (bool) { /* XXX: TODO */ } -AutomationRangeDrag::AutomationRangeDrag (Editor* e, ArdourCanvas::Item* i, list const & r) - : Drag (e, i) +AutomationRangeDrag::AutomationRangeDrag (Editor* editor, ArdourCanvas::Item* item, list const & r) + : Drag (editor, item) , _ranges (r) , _nothing_to_drag (false) { + DEBUG_TRACE (DEBUG::Drags, "New AutomationRangeDrag\n"); + _atav = reinterpret_cast (_item->get_data ("trackview")); assert (_atav); - _line = _atav->line (); + /* get all lines in the automation view */ + list > lines = _atav->lines (); + + /* find those that overlap the ranges being dragged */ + list >::iterator i = lines.begin (); + while (i != lines.end ()) { + list >::iterator j = i; + ++j; + + pair const r = (*i)->get_point_x_range (); + + /* check this range against all the AudioRanges that we are using */ + list::const_iterator k = _ranges.begin (); + while (k != _ranges.end()) { + if (k->coverage (r.first, r.second) != OverlapNone) { + break; + } + ++k; + } + + /* add it to our list if it overlaps at all */ + if (k != _ranges.end()) { + Line n; + n.line = *i; + n.state = 0; + n.range = r; + _lines.push_back (n); + } + + i = j; + } + + /* Now ::lines contains the AutomationLines that somehow overlap our drag */ } void @@ -3962,80 +3981,135 @@ AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) { Drag::start_grab (event, cursor); - list points; + /* Get line states before we start changing things */ + for (list::iterator i = _lines.begin(); i != _lines.end(); ++i) { + i->state = &i->line->get_state (); + } - XMLNode* state = &_line->get_state (); - if (_ranges.empty()) { - - uint32_t const N = _line->npoints (); - for (uint32_t i = 0; i < N; ++i) { - points.push_back (_line->nth (i)); + + /* No selected time ranges: drag all points */ + for (list::iterator i = _lines.begin(); i != _lines.end(); ++i) { + uint32_t const N = i->line->npoints (); + for (uint32_t j = 0; j < N; ++j) { + i->points.push_back (i->line->nth (j)); + } } - + } else { - boost::shared_ptr the_list = _line->the_list (); - for (list::const_iterator j = _ranges.begin(); j != _ranges.end(); ++j) { + for (list::const_iterator i = _ranges.begin(); i != _ranges.end(); ++i) { - /* fade into and out of the region that we're dragging; - 64 samples length plucked out of thin air. - */ - nframes64_t const h = (j->start + j->end) / 2; - nframes64_t a = j->start + 64; - if (a > h) { - a = h; - } - nframes64_t b = j->end - 64; - if (b < h) { - b = h; + framecnt_t const half = (i->start + i->end) / 2; + + /* find the line that this audio range starts in */ + list::iterator j = _lines.begin(); + while (j != _lines.end() && (j->range.first > i->start || j->range.second < i->start)) { + ++j; } - - the_list->add (j->start, the_list->eval (j->start)); - _line->add_always_in_view (j->start); - the_list->add (a, the_list->eval (a)); - _line->add_always_in_view (a); - the_list->add (b, the_list->eval (b)); - _line->add_always_in_view (b); - the_list->add (j->end, the_list->eval (j->end)); - _line->add_always_in_view (j->end); - } - uint32_t const N = _line->npoints (); - for (uint32_t i = 0; i < N; ++i) { + if (j != _lines.end()) { + boost::shared_ptr the_list = j->line->the_list (); + + /* j is the line that this audio range starts in; fade into it; + 64 samples length plucked out of thin air. + */ + + framepos_t a = i->start + 64; + if (a > half) { + a = half; + } + + double const p = j->line->time_converter().from (i->start - j->line->time_converter().origin_b ()); + double const q = j->line->time_converter().from (a - j->line->time_converter().origin_b ()); + + the_list->add (p, the_list->eval (p)); + j->line->add_always_in_view (p); + the_list->add (q, the_list->eval (q)); + j->line->add_always_in_view (q); + } - ControlPoint* p = _line->nth (i); + /* same thing for the end */ - list::const_iterator j = _ranges.begin (); - while (j != _ranges.end() && (j->start >= (*p->model())->when || j->end <= (*p->model())->when)) { + j = _lines.begin(); + while (j != _lines.end() && (j->range.first > i->end || j->range.second < i->end)) { ++j; } - if (j != _ranges.end()) { - points.push_back (p); + if (j != _lines.end()) { + boost::shared_ptr the_list = j->line->the_list (); + + /* j is the line that this audio range starts in; fade out of it; + 64 samples length plucked out of thin air. + */ + + framepos_t b = i->end - 64; + if (b < half) { + b = half; + } + + double const p = j->line->time_converter().from (b - j->line->time_converter().origin_b ()); + double const q = j->line->time_converter().from (i->end - j->line->time_converter().origin_b ()); + + the_list->add (p, the_list->eval (p)); + j->line->add_always_in_view (p); + the_list->add (q, the_list->eval (q)); + j->line->add_always_in_view (q); } } - } - if (points.empty()) { _nothing_to_drag = true; + + /* Find all the points that should be dragged and put them in the relevant + points lists in the Line structs. + */ + + for (list::iterator i = _lines.begin(); i != _lines.end(); ++i) { + + uint32_t const N = i->line->npoints (); + for (uint32_t j = 0; j < N; ++j) { + + /* here's a control point on this line */ + ControlPoint* p = i->line->nth (j); + double const w = i->line->time_converter().to ((*p->model())->when) + i->line->time_converter().origin_b (); + + /* see if it's inside a range */ + list::const_iterator k = _ranges.begin (); + while (k != _ranges.end() && (k->start >= w || k->end <= w)) { + ++k; + } + + if (k != _ranges.end()) { + /* dragging this point */ + _nothing_to_drag = false; + i->points.push_back (p); + } + } + } + } + + if (_nothing_to_drag) { return; } - _line->start_drag_multiple (points, 1 - (_drags->current_pointer_y() / _line->height ()), state); + for (list::iterator i = _lines.begin(); i != _lines.end(); ++i) { + i->line->start_drag_multiple (i->points, 1 - (_drags->current_pointer_y() / i->line->height ()), i->state); + } } void -AutomationRangeDrag::motion (GdkEvent* event, bool first_move) +AutomationRangeDrag::motion (GdkEvent*, bool /*first_move*/) { if (_nothing_to_drag) { return; } - - float const f = 1 - (_drags->current_pointer_y() / _line->height()); - /* we are ignoring x position for this drag, so we can just pass in anything */ - _line->drag_motion (0, f, true, false); + for (list::iterator i = _lines.begin(); i != _lines.end(); ++i) { + float const f = 1 - (_drags->current_pointer_y() / i->line->height()); + + /* we are ignoring x position for this drag, so we can just pass in anything */ + i->line->drag_motion (0, f, true, false); + } } void @@ -4044,22 +4118,152 @@ AutomationRangeDrag::finished (GdkEvent* event, bool) if (_nothing_to_drag) { return; } - + motion (event, false); - _line->end_drag (); - _line->clear_always_in_view (); + for (list::iterator i = _lines.begin(); i != _lines.end(); ++i) { + i->line->end_drag (); + i->line->clear_always_in_view (); + } + + _editor->session()->commit_reversible_command (); } void -AutomationRangeDrag::aborted () +AutomationRangeDrag::aborted (bool) { - _line->clear_always_in_view (); - _line->reset (); + for (list::iterator i = _lines.begin(); i != _lines.end(); ++i) { + i->line->clear_always_in_view (); + i->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 (); + initial_position = v->region()->position (); + initial_end = v->region()->position () + v->region()->length (); +} + +PatchChangeDrag::PatchChangeDrag (Editor* e, CanvasPatchChange* i, MidiRegionView* r) + : Drag (e, i) + , _region_view (r) + , _patch_change (i) + , _cumulative_dx (0) +{ + DEBUG_TRACE (DEBUG::Drags, "New PatchChangeDrag\n"); +} + +void +PatchChangeDrag::motion (GdkEvent* ev, bool) +{ + framepos_t f = adjusted_current_frame (ev); + boost::shared_ptr r = _region_view->region (); + f = max (f, r->position ()); + f = min (f, r->last_frame ()); + + framecnt_t const dxf = f - grab_frame(); + double const dxu = _editor->frame_to_unit (dxf); + _patch_change->move (dxu - _cumulative_dx, 0); + _cumulative_dx = dxu; +} + +void +PatchChangeDrag::finished (GdkEvent* ev, bool movement_occurred) +{ + if (!movement_occurred) { + return; + } + + boost::shared_ptr r (_region_view->region ()); + + framepos_t f = adjusted_current_frame (ev); + f = max (f, r->position ()); + f = min (f, r->last_frame ()); + + _region_view->move_patch_change ( + *_patch_change, + _region_view->region_frames_to_region_beats (f - r->position() - r->start()) + ); +} + +void +PatchChangeDrag::aborted (bool) +{ + _patch_change->move (-_cumulative_dx, 0); +} + +void +PatchChangeDrag::setup_pointer_frame_offset () +{ + boost::shared_ptr region = _region_view->region (); + _pointer_frame_offset = raw_grab_frame() - _region_view->source_beats_to_absolute_frames (_patch_change->patch()->time()); +} + +MidiRubberbandSelectDrag::MidiRubberbandSelectDrag (Editor* e, MidiRegionView* rv) + : RubberbandSelectDrag (e, rv->get_canvas_frame ()) + , _region_view (rv) +{ + +} + +void +MidiRubberbandSelectDrag::select_things (int button_state, framepos_t x1, framepos_t x2, double y1, double y2, bool drag_in_progress) +{ + framepos_t const p = _region_view->region()->position (); + double const y = _region_view->midi_view()->y_position (); + + x1 = max ((framepos_t) 0, x1 - p); + x2 = max ((framepos_t) 0, x2 - p); + y1 = max (0.0, y1 - y); + y2 = max (0.0, y2 - y); + + _region_view->update_drag_selection ( + _editor->frame_to_pixel (x1), + _editor->frame_to_pixel (x2), + y1, + y2, + Keyboard::modifier_state_contains (button_state, Keyboard::TertiaryModifier) + ); +} + +void +MidiRubberbandSelectDrag::deselect_things () +{ + /* XXX */ +} + +EditorRubberbandSelectDrag::EditorRubberbandSelectDrag (Editor* e, ArdourCanvas::Item* i) + : RubberbandSelectDrag (e, i) +{ + +} + +void +EditorRubberbandSelectDrag::select_things (int button_state, framepos_t x1, framepos_t x2, double y1, double y2, bool drag_in_progress) +{ + if (drag_in_progress) { + /* We just want to select things at the end of the drag, not during it */ + return; + } + + Selection::Operation op = ArdourKeyboard::selection_type (button_state); + + _editor->begin_reversible_command (_("rubberband selection")); + _editor->select_all_within (x1, x2 - 1, y1, y2, _editor->track_views, op, false); + _editor->commit_reversible_command (); +} + +void +EditorRubberbandSelectDrag::deselect_things () +{ + if (!getenv("ARDOUR_SAE")) { + _editor->selection->clear_tracks(); + } + _editor->selection->clear_regions(); + _editor->selection->clear_points (); + _editor->selection->clear_lines (); }