X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor_drag.cc;h=b06545c32bbca06cb3f44de1f1ee0830928da3bb;hb=b12beab67c70045269d6ec5dc735c2f4af67c4f9;hp=0463061f19bd637792aacec725c48c90845186a9;hpb=5462d30076ad146cbdf2831db131011b7a0acc4f;p=ardour.git diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index 0463061f19..b06545c32b 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" @@ -43,11 +52,14 @@ #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; @@ -81,6 +93,8 @@ DragManager::abort () _drags.clear (); + _editor->set_follow_playhead (_old_follow_playhead, false); + _ending = false; } @@ -94,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); @@ -103,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) { @@ -130,6 +147,8 @@ DragManager::end_grab (GdkEvent* e) _drags.clear (); _ending = false; + + _editor->set_follow_playhead (_old_follow_playhead, false); return r; } @@ -211,14 +230,15 @@ Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor) } _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; @@ -284,8 +304,9 @@ 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; } @@ -295,7 +316,7 @@ Drag::motion_handler (GdkEvent* event, bool from_autoscroll) 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 () - _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())); @@ -328,7 +349,7 @@ Drag::abort () _item->ungrab (0); } - aborted (); + aborted (_move_threshold_passed); _editor->stop_canvas_autoscroll (); _editor->hide_verbose_canvas_cursor (); @@ -366,8 +387,8 @@ 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)); @@ -792,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; @@ -890,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(); ) { @@ -1006,7 +1023,7 @@ RegionMoveDrag::finished_no_copy ( if (_views.empty()) { - break; + break; } else { i = _views.begin(); } @@ -1117,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; } @@ -1126,7 +1143,7 @@ RegionMoveDrag::add_stateful_diff_commands_for_playlists (PlaylistSet const & pl void -RegionMoveDrag::aborted () +RegionMoveDrag::aborted (bool movement_occurred) { if (_copy) { @@ -1137,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; @@ -1176,10 +1193,8 @@ RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, } void -RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c) +RegionMoveDrag::setup_pointer_frame_offset () { - RegionMotionDrag::start_grab (event, c); - _pointer_frame_offset = raw_grab_frame() - _last_frame_position; } @@ -1214,8 +1229,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 (); @@ -1226,7 +1241,7 @@ RegionInsertDrag::finished (GdkEvent *, bool) } void -RegionInsertDrag::aborted () +RegionInsertDrag::aborted (bool) { delete _primary; _primary = 0; @@ -1325,7 +1340,7 @@ RegionSpliceDrag::finished (GdkEvent* event, bool movement_occurred) } void -RegionSpliceDrag::aborted () +RegionSpliceDrag::aborted (bool) { /* XXX: TODO */ } @@ -1343,50 +1358,50 @@ void RegionCreateDrag::motion (GdkEvent* event, bool first_move) { if (first_move) { - add_region(); + add_region(); } else { - if (_region) { - 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) { - add_region (); + add_region (); } - if (_region) { - _editor->commit_reversible_command (); - } + if (_region) { + _editor->commit_reversible_command (); + } } void 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); - } + 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 () +RegionCreateDrag::aborted (bool) { /* XXX */ } @@ -1402,9 +1417,16 @@ 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(); @@ -1412,10 +1434,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; } @@ -1453,7 +1475,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); } } @@ -1462,12 +1484,12 @@ 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 */ } @@ -1491,20 +1513,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 (); @@ -1521,24 +1542,28 @@ TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) 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); @@ -1547,6 +1572,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 @@ -1554,11 +1583,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); @@ -1568,7 +1592,7 @@ TrimDrag::motion (GdkEvent* event, bool first_move) speed = tv->track()->speed(); } - framepos_t const pf = adjusted_current_frame (event); + framecnt_t const dt = adjusted_current_frame (event) - raw_grab_frame () + _pointer_frame_offset; if (first_move) { @@ -1587,18 +1611,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 (); } @@ -1620,13 +1642,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; @@ -1641,18 +1663,18 @@ TrimDrag::motion (GdkEvent* event, bool first_move) 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; @@ -1660,13 +1682,13 @@ TrimDrag::motion (GdkEvent* event, bool first_move) switch (_operation) { case StartTrim: - _editor->show_verbose_time_cursor((framepos_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((framepos_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; } } @@ -1678,17 +1700,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) { @@ -1696,19 +1740,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 @@ -1717,9 +1766,37 @@ 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) @@ -1740,8 +1817,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; @@ -1758,11 +1841,15 @@ MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) Drag::start_grab (event, cursor); - _pointer_frame_offset = raw_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) { @@ -1782,7 +1869,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); @@ -1809,7 +1896,7 @@ MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred) } void -MeterMarkerDrag::aborted () +MeterMarkerDrag::aborted (bool) { _marker->set_position (_marker->meter().frame ()); } @@ -1827,34 +1914,37 @@ 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 = raw_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) { @@ -1872,7 +1962,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); @@ -1899,7 +1989,7 @@ TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred) } void -TempoMarkerDrag::aborted () +TempoMarkerDrag::aborted (bool) { _marker->set_position (_marker->tempo().frame()); } @@ -1909,52 +1999,56 @@ CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s) _stop (s) { DEBUG_TRACE (DEBUG::Drags, "New CursorDrag\n"); - - _cursor = reinterpret_cast (_item->get_data ("cursor")); - assert (_cursor); } +/** 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) { - - framepos_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 ()) { - framepos_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 = raw_grab_frame() - _cursor->current_frame; - - _editor->show_verbose_time_cursor (_cursor->current_frame, 10); + + fake_locate (where); } void @@ -1966,22 +2060,11 @@ CursorDrag::motion (GdkEvent* event, bool) 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 ()) { - framepos_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 @@ -1995,25 +2078,23 @@ 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) @@ -2030,12 +2111,19 @@ FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) 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()); _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) { @@ -2114,7 +2202,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); @@ -2142,12 +2230,19 @@ FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) 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()); _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) { @@ -2230,7 +2325,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); @@ -2254,13 +2349,6 @@ MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i) _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 () @@ -2280,8 +2368,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 = raw_grab_frame() - (is_start ? location->start() : location->end()); - update_item (location); // _drag_line->show(); @@ -2347,6 +2433,14 @@ 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) { @@ -2394,13 +2488,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(); @@ -2456,7 +2552,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); @@ -2554,12 +2650,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 */ } @@ -2567,11 +2661,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) @@ -2589,7 +2679,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 @@ -2682,7 +2772,7 @@ ControlPointDrag::finished (GdkEvent* event, bool movement_occurred) } void -ControlPointDrag::aborted () +ControlPointDrag::aborted (bool) { _point->line().reset (); } @@ -2734,7 +2824,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 */ @@ -2792,7 +2882,7 @@ LineDrag::finished (GdkEvent* event, bool) } void -LineDrag::aborted () +LineDrag::aborted (bool) { _line->reset (); } @@ -2831,7 +2921,7 @@ FeatureLineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/) } void -FeatureLineDrag::motion (GdkEvent* event, bool) +FeatureLineDrag::motion (GdkEvent*, bool) { double dx = _drags->current_pointer_x() - last_pointer_x(); @@ -2855,14 +2945,14 @@ FeatureLineDrag::motion (GdkEvent* event, bool) } void -FeatureLineDrag::finished (GdkEvent* event, bool) +FeatureLineDrag::finished (GdkEvent*, bool) { _arv = reinterpret_cast (_item->get_data ("regionview")); _arv->update_transient(_before, _line->property_x1()); } void -FeatureLineDrag::aborted () +FeatureLineDrag::aborted (bool) { //_line->reset (); } @@ -2949,20 +3039,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); - } - - if (!committed) { - _editor->commit_reversible_command (); + _editor->select_all_within (last_pointer_frame(), grab_frame() - 1, y1, y2, _editor->track_views, op, false); } + _editor->commit_reversible_command (); } else { if (!getenv("ARDOUR_SAE")) { _editor->selection->clear_tracks(); @@ -2976,7 +3062,7 @@ RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred) } void -RubberbandSelectDrag::aborted () +RubberbandSelectDrag::aborted (bool) { _editor->rubberband_rect->hide (); } @@ -3047,7 +3133,7 @@ TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred) } void -TimeFXDrag::aborted () +TimeFXDrag::aborted (bool) { _primary->get_time_axis_view().hide_timestretch (); } @@ -3080,7 +3166,7 @@ ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred) } void -ScrubDrag::aborted () +ScrubDrag::aborted (bool) { /* XXX: TODO */ } @@ -3098,9 +3184,6 @@ SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o) void SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*) { - framepos_t start = 0; - framepos_t end = 0; - if (_editor->session() == 0) { return; } @@ -3114,7 +3197,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; @@ -3122,29 +3205,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 = raw_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 = raw_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 = raw_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); } @@ -3152,6 +3229,25 @@ 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) { @@ -3197,7 +3293,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; @@ -3205,8 +3301,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); @@ -3215,7 +3311,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); } @@ -3338,7 +3434,7 @@ SelectionDrag::finished (GdkEvent* event, bool movement_occurred) } void -SelectionDrag::aborted () +SelectionDrag::aborted (bool) { /* XXX: TODO */ } @@ -3351,7 +3447,7 @@ RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operat 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(); @@ -3381,7 +3477,7 @@ RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *) } else { _copy = false; } - cursor = _editor->selector_cursor; + cursor = _editor->cursors()->selector; break; } @@ -3544,7 +3640,7 @@ RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred) } void -RangeMarkerBarDrag::aborted () +RangeMarkerBarDrag::aborted (bool) { /* XXX: TODO */ } @@ -3561,6 +3657,7 @@ RangeMarkerBarDrag::update_item (Location* location) MouseZoomDrag::MouseZoomDrag (Editor* e, ArdourCanvas::Item* i) : Drag (e, i) + , _zoom_out (false) { DEBUG_TRACE (DEBUG::Drags, "New MouseZoomDrag\n"); } @@ -3568,7 +3665,14 @@ MouseZoomDrag::MouseZoomDrag (Editor* e, ArdourCanvas::Item* i) 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); } @@ -3617,18 +3721,14 @@ 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()); - */ + _editor->temporal_zoom_to_frame (_zoom_out, grab_frame()); } _editor->zoom_rect->hide(); } void -MouseZoomDrag::aborted () +MouseZoomDrag::aborted (bool) { _editor->zoom_rect->hide (); } @@ -3706,9 +3806,9 @@ NoteDrag::total_dy () const } } - /* more positive value = higher pitch and higher y-axis position on track, - which is the inverse of the X-centric geometric universe - */ + /* more positive value = higher pitch and higher y-axis position on track, + which is the inverse of the X-centric geometric universe + */ return -ndy; } @@ -3728,16 +3828,16 @@ NoteDrag::motion (GdkEvent *, bool) _cumulative_dx += tdx; _cumulative_dy += tdy; - int8_t note_delta = total_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)); + 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 @@ -3765,12 +3865,12 @@ 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 */ } @@ -3942,7 +4042,7 @@ AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) } void -AutomationRangeDrag::motion (GdkEvent* event, bool first_move) +AutomationRangeDrag::motion (GdkEvent*, bool /*first_move*/) { if (_nothing_to_drag) { return; @@ -3973,7 +4073,7 @@ AutomationRangeDrag::finished (GdkEvent* event, bool) } void -AutomationRangeDrag::aborted () +AutomationRangeDrag::aborted (bool) { for (list::iterator i = _lines.begin(); i != _lines.end(); ++i) { i->line->clear_always_in_view (); @@ -3988,4 +4088,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(); +} +