X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor_drag.cc;h=00313d06720b41d00cba917179c48c96f185fa18;hb=ad942b104a80c74c689e0c1b5c016d1870850830;hp=0642cc75454c3bc332fa8a2bb3fcf78c888071f2;hpb=ea2648503b520e3da54263ce0bafb388d22a9cd8;p=ardour.git diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index 0642cc7545..00313d0672 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -17,14 +17,23 @@ */ -#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 "gtkmm2ext/utils.h" + #include "ardour/session.h" #include "ardour/dB.h" #include "ardour/region_factory.h" +#include "ardour/operations.h" + #include "editor.h" #include "i18n.h" #include "keyboard.h" @@ -42,11 +51,15 @@ #include "selection.h" #include "midi_selection.h" #include "automation_time_axis.h" +#include "debug.h" +#include "editor_cursors.h" +#include "mouse_cursors.h" using namespace std; using namespace ARDOUR; using namespace PBD; using namespace Gtk; +using namespace Gtkmm2ext; using namespace Editing; using namespace ArdourCanvas; @@ -80,6 +93,8 @@ DragManager::abort () _drags.clear (); + _editor->set_follow_playhead (_old_follow_playhead, false); + _ending = false; } @@ -93,7 +108,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,6 +116,10 @@ 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) { @@ -129,6 +147,8 @@ DragManager::end_grab (GdkEvent* e) _drags.clear (); _ending = false; + + _editor->set_follow_playhead (_old_follow_playhead, false); return r; } @@ -167,6 +187,7 @@ Drag::Drag (Editor* e, ArdourCanvas::Item* i) , _item (i) , _pointer_frame_offset (0) , _move_threshold_passed (false) + , _raw_grab_frame (0) , _grab_frame (0) , _last_pointer_frame (0) { @@ -208,15 +229,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; @@ -256,10 +278,10 @@ Drag::end_grab (GdkEvent* event) 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 +294,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 +304,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())); @@ -326,7 +349,7 @@ Drag::abort () _item->ungrab (0); } - aborted (); + aborted (_move_threshold_passed); _editor->stop_canvas_autoscroll (); _editor->hide_verbose_canvas_cursor (); @@ -363,6 +386,9 @@ RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list::const_iterator i = v.begin(); i != v.end(); ++i) { _views.push_back (DraggingView (*i, this)); @@ -423,15 +449,15 @@ RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) } 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); @@ -450,7 +476,7 @@ RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_ *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; } @@ -517,6 +543,8 @@ RegionMotionDrag::y_movement_allowed (int delta_track, layer_t delta_layer) cons void RegionMotionDrag::motion (GdkEvent* event, bool first_move) { + assert (!_views.empty ()); + /* Find the TimeAxisView that the pointer is now over */ pair const tv = _editor->trackview_by_y_position (_drags->current_pointer_y ()); @@ -688,7 +716,7 @@ RegionMoveDrag::motion (GdkEvent* event, bool first_move) MidiRegionView* mrv = dynamic_cast(rv); const boost::shared_ptr original = rv->region(); - boost::shared_ptr region_copy = RegionFactory::create (original); + boost::shared_ptr region_copy = RegionFactory::create (original, true); region_copy->set_position (original->position(), this); RegionView* nrv; @@ -757,7 +785,9 @@ RegionMoveDrag::finished (GdkEvent *, bool movement_occurred) _x_constrained = !_x_constrained; } - bool const changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position())); + assert (!_views.empty ()); + + 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; @@ -783,11 +813,7 @@ RegionMoveDrag::finished (GdkEvent *, bool movement_occurred) } void -RegionMoveDrag::finished_copy ( - 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; @@ -817,7 +843,7 @@ RegionMoveDrag::finished_copy ( continue; } - nframes64_t where; + framepos_t where; if (changed_position && !_x_constrained) { where = i->view->region()->position() - drag_delta; @@ -881,7 +907,7 @@ 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(); ) { @@ -896,7 +922,7 @@ RegionMoveDrag::finished_no_copy ( continue; } - nframes64_t where; + framepos_t where; if (changed_position && !_x_constrained) { where = rv->region()->position() - drag_delta; @@ -909,7 +935,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) { @@ -997,7 +1023,7 @@ RegionMoveDrag::finished_no_copy ( if (_views.empty()) { - break; + break; } else { i = _views.begin(); } @@ -1108,7 +1134,7 @@ RegionMoveDrag::add_stateful_diff_commands_for_playlists (PlaylistSet const & pl for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) { StatefulDiffCommand* c = new StatefulDiffCommand (*i); if (!c->empty()) { - _editor->session()->add_command (new StatefulDiffCommand (*i)); + _editor->session()->add_command (c); } else { delete c; } @@ -1117,7 +1143,7 @@ RegionMoveDrag::add_stateful_diff_commands_for_playlists (PlaylistSet const & pl void -RegionMoveDrag::aborted () +RegionMoveDrag::aborted (bool movement_occurred) { if (_copy) { @@ -1128,12 +1154,12 @@ RegionMoveDrag::aborted () _views.clear (); } else { - RegionMotionDrag::aborted (); + RegionMotionDrag::aborted (movement_occurred); } } void -RegionMotionDrag::aborted () +RegionMotionDrag::aborted (bool) { for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { RegionView* rv = i->view; @@ -1150,31 +1176,36 @@ RegionMotionDrag::aborted () _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) { + DEBUG_TRACE (DEBUG::Drags, "New RegionMoveDrag\n"); + double speed = 1; 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))); @@ -1201,8 +1232,8 @@ RegionInsertDrag::finished (GdkEvent *, bool) 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 (); @@ -1213,7 +1244,7 @@ RegionInsertDrag::finished (GdkEvent *, bool) } void -RegionInsertDrag::aborted () +RegionInsertDrag::aborted (bool) { delete _primary; _primary = 0; @@ -1223,7 +1254,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 { @@ -1270,7 +1301,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) { @@ -1312,7 +1343,7 @@ RegionSpliceDrag::finished (GdkEvent* event, bool movement_occurred) } void -RegionSpliceDrag::aborted () +RegionSpliceDrag::aborted (bool) { /* XXX: TODO */ } @@ -1321,6 +1352,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); } @@ -1328,31 +1361,58 @@ 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, this); + } + + /* 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); } - - /* 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); } } 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 */ } @@ -1360,16 +1420,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(); @@ -1377,10 +1444,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; } @@ -1418,7 +1485,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); } } @@ -1427,16 +1494,22 @@ 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 */ } +RegionGainDrag::RegionGainDrag (Editor* e, ArdourCanvas::Item* i) + : Drag (e, i) +{ + DEBUG_TRACE (DEBUG::Drags, "New RegionGainDrag\n"); +} + void RegionGainDrag::motion (GdkEvent* /*event*/, bool) { @@ -1450,20 +1523,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* cursor) +TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor*) { double speed = 1.0; TimeAxisView* tvp = &_primary->get_time_axis_view (); @@ -1473,31 +1545,35 @@ TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor* 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); + 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); @@ -1506,6 +1582,10 @@ TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) _editor->show_verbose_time_cursor (pf, 10); break; } + + for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { + i->view->region()->suspend_property_changes (); + } } void @@ -1513,11 +1593,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); @@ -1527,7 +1602,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) { @@ -1546,18 +1621,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 (); } @@ -1579,13 +1652,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; @@ -1597,21 +1670,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; @@ -1619,13 +1692,13 @@ TrimDrag::motion (GdkEvent* event, bool first_move) switch (_operation) { case StartTrim: - _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10); + _editor->show_verbose_time_cursor ((framepos_t) (rv->region()->position() / speed), 10); break; case EndTrim: - _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10); + _editor->show_verbose_time_cursor ((framepos_t) (rv->region()->last_frame() / speed), 10); break; case ContentsTrim: - _editor->show_verbose_time_cursor (pf, 10); + _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10); break; } } @@ -1637,17 +1710,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) { @@ -1655,19 +1750,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 @@ -1676,15 +1776,45 @@ 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); } @@ -1697,8 +1827,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; @@ -1715,15 +1851,19 @@ MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) Drag::start_grab (event, cursor); - _pointer_frame_offset = grab_frame() - _marker->meter().frame(); - _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); @@ -1739,7 +1879,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); @@ -1766,7 +1906,7 @@ MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred) } void -MeterMarkerDrag::aborted () +MeterMarkerDrag::aborted (bool) { _marker->set_position (_marker->meter().frame ()); } @@ -1775,6 +1915,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); } @@ -1782,38 +1924,41 @@ 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); } +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); } @@ -1827,7 +1972,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); @@ -1854,7 +1999,7 @@ TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred) } void -TempoMarkerDrag::aborted () +TempoMarkerDrag::aborted (bool) { _marker->set_position (_marker->tempo().frame()); } @@ -1863,78 +2008,73 @@ 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); - - if (!_stop) { - - nframes64_t where = _editor->event_frame (event, 0, 0); - - _editor->snap_to_with_modifier (where, event); - _editor->playhead_cursor->set_position (where); - + _editor->playhead_cursor->set_position (t); + + 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); } - if (_cursor == _editor->playhead_cursor) { - _editor->_dragging_playhead = true; - - Session* s = _editor->session (); - - if (s) { - if (_was_rolling && _stop) { - s->request_stop (); - } + _editor->show_verbose_time_cursor (t, 10); + _editor->UpdateAllTransportClocks (t); +} - if (s->is_auditioning()) { - s->cancel_audition (); - } +void +CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c) +{ + Drag::start_grab (event, c); - s->request_suspend_timecode_transmission (); + framepos_t where = _editor->event_frame (event, 0, 0); + _editor->snap_to_with_modifier (where, event); - 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); - } + _editor->_dragging_playhead = true; + + Session* s = _editor->session (); + + if (s) { + if (_was_rolling && _stop) { + s->request_stop (); + } + + if (s->is_auditioning()) { + s->cancel_audition (); + } + + 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); + framepos_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); - } + fake_locate (adjusted_frame); - #ifdef GTKOSX _editor->update_canvas_now (); #endif - _editor->UpdateAllTransportClocks (_cursor->current_frame); } void @@ -1948,31 +2088,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 @@ -1980,20 +2118,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); + 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 (); @@ -2014,6 +2160,7 @@ 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); @@ -2026,9 +2173,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 (); @@ -2055,6 +2202,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)); @@ -2064,7 +2212,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); @@ -2074,13 +2222,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 @@ -2088,19 +2237,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 (); - _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); + + arv->show_fade_line(r->length() - r->fade_out()->back()->when); } +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 (); @@ -2123,6 +2281,7 @@ 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); @@ -2135,9 +2294,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 (); @@ -2166,6 +2325,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)); @@ -2175,7 +2335,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); @@ -2185,24 +2345,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 () @@ -2222,8 +2378,6 @@ 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(); @@ -2250,13 +2404,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)); @@ -2289,23 +2443,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); - - nframes64_t next = newframe; + framepos_t const newframe = adjusted_current_frame (event); - if (newframe == last_pointer_frame()) { - return; - } + framepos_t next = newframe; if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) { move_both = true; @@ -2336,13 +2494,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(); @@ -2388,8 +2548,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 @@ -2398,7 +2558,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); @@ -2496,12 +2656,10 @@ 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 */ } @@ -2509,11 +2667,7 @@ MarkerDrag::aborted () void MarkerDrag::update_item (Location* 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) @@ -2521,6 +2675,8 @@ ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i) _cumulative_x_drag (0), _cumulative_y_drag (0) { + DEBUG_TRACE (DEBUG::Drags, "New ControlPointDrag\n"); + _point = reinterpret_cast (_item->get_data ("control_point")); assert (_point); } @@ -2529,7 +2685,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 @@ -2616,11 +2772,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 (); } @@ -2642,8 +2800,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*/) { @@ -2661,7 +2820,7 @@ 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; @@ -2671,7 +2830,7 @@ LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/) return; } - Drag::start_grab (event, _editor->fader_cursor); + Drag::start_grab (event, _editor->cursors()->fader); /* store grab start in parent frame */ @@ -2725,10 +2884,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 (); } @@ -2738,14 +2898,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. */ @@ -2758,15 +2919,15 @@ 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(); @@ -2783,25 +2944,44 @@ FeatureLineDrag::motion (GdkEvent* event, bool) cx = 0; } - _line->property_x1() = cx; - _line->property_x2() = cx; + ArdourCanvas::Points points; + + double x1 = 0, x2 = 0, y1 = 0, y2 = 0; - _before = _line->property_x1(); + _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 *) { @@ -2812,14 +2992,14 @@ RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *) 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); } @@ -2878,19 +3058,16 @@ RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred) Selection::Operation op = ArdourKeyboard::selection_type (event->button.state); - bool committed; _editor->begin_reversible_command (_("rubberband selection")); if (grab_frame() < last_pointer_frame()) { - committed = _editor->select_all_within (grab_frame(), last_pointer_frame() - 1, y1, y2, _editor->track_views, op, false); + _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); + _editor->select_all_within (last_pointer_frame(), grab_frame() - 1, y1, y2, _editor->track_views, op, false); } - if (!committed) { - _editor->commit_reversible_command (); - } + _editor->commit_reversible_command (); } else { if (!getenv("ARDOUR_SAE")) { @@ -2905,11 +3082,17 @@ RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred) } 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* cursor) { @@ -2923,7 +3106,7 @@ 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); @@ -2946,7 +3129,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(); @@ -2970,11 +3153,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 *) @@ -2998,7 +3186,7 @@ ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred) } void -ScrubDrag::aborted () +ScrubDrag::aborted (bool) { /* XXX: TODO */ } @@ -3010,15 +3198,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; } @@ -3032,7 +3217,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; @@ -3040,29 +3225,23 @@ 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); + _editor->show_verbose_time_cursor (_editor->selection->time[_editor->clicked_selection].start, 10); } else { _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10); } @@ -3070,19 +3249,38 @@ SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*) _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 */ @@ -3093,7 +3291,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); @@ -3115,7 +3313,7 @@ SelectionDrag::motion (GdkEvent* event, bool first_move) if (_copy) { /* adding to the selection */ - _editor->set_selected_track_as_side_effect (Selection::Add); + _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; @@ -3123,8 +3321,8 @@ SelectionDrag::motion (GdkEvent* event, bool first_move) /* new selection */ if (_editor->clicked_axisview && !_editor->selection->selected (_editor->clicked_axisview)) { - //_editor->selection->set (_editor->clicked_axisview); - _editor->set_selected_track_as_side_effect (Selection::Set); + //_editor->selection->set (_editor->clicked_axisview); + _editor->set_selected_track_as_side_effect (Selection::Set); } _editor->clicked_selection = _editor->selection->set (start, end); @@ -3133,7 +3331,7 @@ SelectionDrag::motion (GdkEvent* event, bool first_move) /* 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->set_selected_track_as_side_effect (Selection::Add); _editor->selection->add (pending_time_axis.first); _added_time_axes.push_back (pending_time_axis.first); } @@ -3256,7 +3454,7 @@ SelectionDrag::finished (GdkEvent* event, bool movement_occurred) } void -SelectionDrag::aborted () +SelectionDrag::aborted (bool) { /* XXX: TODO */ } @@ -3266,8 +3464,10 @@ RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operat _operation (o), _copy (false) { + 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())); + physical_screen_height (_editor->get_window())); _drag_rect->hide (); _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get(); @@ -3297,7 +3497,7 @@ RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *) } else { _copy = false; } - cursor = _editor->selector_cursor; + cursor = _editor->cursors()->selector; break; } @@ -3309,8 +3509,8 @@ RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *) 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) { @@ -3329,10 +3529,10 @@ 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()) { @@ -3426,16 +3626,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 (); } @@ -3460,7 +3660,7 @@ RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred) } void -RangeMarkerBarDrag::aborted () +RangeMarkerBarDrag::aborted (bool) { /* XXX: TODO */ } @@ -3475,22 +3675,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); + 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; + } + _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10); } 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 */ @@ -3527,18 +3741,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 (); } @@ -3548,6 +3762,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 (); @@ -3614,32 +3830,38 @@ NoteDrag::total_dy () const } } - return ndy; -} - + /* more positive value = higher pitch and higher y-axis position on track, + which is the inverse of the X-centric geometric universe + */ + + return -ndy; +} void NoteDrag::motion (GdkEvent *, bool) { /* Total change in x and y since the start of the drag */ frameoffset_t const dx = total_dx (); - int8_t const dy = total_dy (); + int8_t const dy = -total_dy (); /* 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; 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); + + char buf[12]; + snprintf (buf, sizeof (buf), "%s (%d)", Evoral::midi_note_name (_primary->note()->note() + note_delta).c_str(), + (int) floor (_primary->note()->note() + note_delta)); + _editor->show_verbose_canvas_cursor_with (buf); - } + } } void @@ -3667,25 +3889,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 @@ -3693,80 +3949,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; + 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; } - nframes64_t b = j->end - 64; - if (b < h) { - b = h; + + 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); } + + /* same thing for the end */ - 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); + j = _lines.begin(); + while (j != _lines.end() && (j->range.first > i->end || j->range.second < i->end)) { + ++j; + } + + 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); + } } - uint32_t const N = _line->npoints (); - for (uint32_t i = 0; i < N; ++i) { + _nothing_to_drag = true; + + /* Find all the points that should be dragged and put them in the relevant + points lists in the Line structs. + */ - ControlPoint* p = _line->nth (i); + for (list::iterator i = _lines.begin(); i != _lines.end(); ++i) { - list::const_iterator j = _ranges.begin (); - while (j != _ranges.end() && (j->start >= (*p->model())->when || j->end <= (*p->model())->when)) { - ++j; - } + 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 (j != _ranges.end()) { - points.push_back (p); + if (k != _ranges.end()) { + /* dragging this point */ + _nothing_to_drag = false; + i->points.push_back (p); + } } } } - if (points.empty()) { - _nothing_to_drag = true; + 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 @@ -3777,15 +4088,21 @@ AutomationRangeDrag::finished (GdkEvent* event, bool) } 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, RegionDrag* parent) @@ -3795,4 +4112,62 @@ DraggingView::DraggingView (RegionView* v, RegionDrag* parent) 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->frames_to_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->beats_to_frames (_patch_change->patch()->time()) - region->position() + region->start(); +} +