*/
-#define __STDC_LIMIT_MACROS 1
+#ifdef WAF_BUILD
+#include "gtk2ardour-config.h"
+#endif
+
#include <stdint.h>
+
#include "pbd/memento_command.h"
#include "pbd/basename.h"
#include "pbd/stateful_diff_command.h"
-#include "ardour/session.h"
+
+#include "gtkmm2ext/utils.h"
+
+#include "ardour/audioregion.h"
#include "ardour/dB.h"
+#include "ardour/midi_region.h"
+#include "ardour/operations.h"
#include "ardour/region_factory.h"
+#include "ardour/session.h"
+
#include "editor.h"
#include "i18n.h"
#include "keyboard.h"
#include "selection.h"
#include "midi_selection.h"
#include "automation_time_axis.h"
+#include "debug.h"
+#include "editor_cursors.h"
+#include "mouse_cursors.h"
+#include "verbose_cursor.h"
using namespace std;
using namespace ARDOUR;
using namespace PBD;
using namespace Gtk;
+using namespace Gtkmm2ext;
using namespace Editing;
using namespace ArdourCanvas;
using Gtkmm2ext::Keyboard;
-double const ControlPointDrag::_zero_gain_fraction = gain_to_slider_position (dB_to_coefficient (0.0));
+double ControlPointDrag::_zero_gain_fraction = -1.0;
DragManager::DragManager (Editor* e)
: _editor (e)
, _ending (false)
, _current_pointer_frame (0)
{
-
}
DragManager::~DragManager ()
DragManager::abort ()
{
_ending = true;
-
+
for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
(*i)->abort ();
delete *i;
}
+ if (!_drags.empty ()) {
+ _editor->set_follow_playhead (_old_follow_playhead, false);
+ }
+
_drags.clear ();
_ending = false;
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);
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<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
(*i)->start_grab (e, c);
}
DragManager::end_grab (GdkEvent* e)
{
_ending = true;
-
+
bool r = false;
for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
bool const t = (*i)->end_grab (e);
_drags.clear ();
_ending = false;
-
+
+ _editor->set_follow_playhead (_old_follow_playhead, false);
+
return r;
}
bool r = false;
_current_pointer_frame = _editor->event_frame (e, &_current_pointer_x, &_current_pointer_y);
-
+
for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
bool const t = (*i)->motion_handler (e, from_autoscroll);
if (t) {
r = true;
}
-
+
}
return r;
return j != _drags.end ();
}
-Drag::Drag (Editor* e, ArdourCanvas::Item* i)
+Drag::Drag (Editor* e, ArdourCanvas::Item* i)
: _editor (e)
, _item (i)
, _pointer_frame_offset (0)
, _move_threshold_passed (false)
+ , _raw_grab_frame (0)
, _grab_frame (0)
, _last_pointer_frame (0)
{
_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;
finished (event, _move_threshold_passed);
- _editor->hide_verbose_canvas_cursor();
+ _editor->verbose_cursor()->hide ();
return _move_threshold_passed;
}
-nframes64_t
-Drag::adjusted_frame (nframes64_t f, GdkEvent const * event, bool snap) const
+framepos_t
+Drag::adjusted_frame (framepos_t f, GdkEvent const * event, bool snap) const
{
- nframes64_t pos = 0;
+ framepos_t pos = 0;
if (f > _pointer_frame_offset) {
pos = f - _pointer_frame_offset;
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);
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<nframes64_t, int> const threshold = move_threshold ();
+ pair<framecnt_t, int> 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()));
_last_pointer_x = _drags->current_pointer_x ();
_last_pointer_y = _drags->current_pointer_y ();
_last_pointer_frame = adjusted_current_frame (event);
-
+
return true;
}
}
_item->ungrab (0);
}
- aborted ();
+ aborted (_move_threshold_passed);
_editor->stop_canvas_autoscroll ();
- _editor->hide_verbose_canvas_cursor ();
-}
-
-RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
- : Drag (e, i),
- _primary (p)
-{
- for (list<RegionView*>::const_iterator i = v.begin(); i != v.end(); ++i) {
- _views.push_back (DraggingView (*i));
- }
-
- RegionView::RegionViewGoingAway.connect (death_connection, invalidator (*this), ui_bind (&RegionDrag::region_going_away, this, _1), gui_context());
+ _editor->verbose_cursor()->hide ();
}
void
-RegionDrag::region_going_away (RegionView* v)
+Drag::show_verbose_cursor_time (framepos_t frame)
{
- list<DraggingView>::iterator i = _views.begin ();
- while (i != _views.end() && i->view != v) {
- ++i;
- }
+ _editor->verbose_cursor()->set_time (
+ frame,
+ _drags->current_pointer_x() + 10 - _editor->horizontal_position(),
+ _drags->current_pointer_y() + 10 - _editor->vertical_adjustment.get_value() + _editor->canvas_timebars_vsize
+ );
- if (i != _views.end()) {
- _views.erase (i);
- }
+ _editor->verbose_cursor()->show ();
}
-RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
- : RegionDrag (e, i, p, v),
- _dest_trackview (0),
- _dest_layer (0),
- _brushing (b),
- _total_x_delta (0)
+void
+Drag::show_verbose_cursor_duration (framepos_t start, framepos_t end, double xoffset)
{
+ _editor->verbose_cursor()->show (xoffset);
+ _editor->verbose_cursor()->set_duration (
+ start, end,
+ _drags->current_pointer_x() + 10 - _editor->horizontal_position(),
+ _drags->current_pointer_y() + 10 - _editor->vertical_adjustment.get_value() + _editor->canvas_timebars_vsize
+ );
}
-
void
-RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
+Drag::show_verbose_cursor_text (string const & text)
{
- Drag::start_grab (event);
+ _editor->verbose_cursor()->show ();
- _editor->show_verbose_time_cursor (_last_frame_position, 10);
+ _editor->verbose_cursor()->set (
+ text,
+ _drags->current_pointer_x() + 10 - _editor->horizontal_position(),
+ _drags->current_pointer_y() + 10 - _editor->vertical_adjustment.get_value() + _editor->canvas_timebars_vsize
+ );
}
-RegionMotionDrag::TimeAxisViewSummary
-RegionMotionDrag::get_time_axis_view_summary ()
-{
- int32_t children = 0;
- TimeAxisViewSummary sum;
-
- _editor->visible_order_range (&sum.visible_y_low, &sum.visible_y_high);
- /* get a bitmask representing the visible tracks */
+struct EditorOrderTimeAxisViewSorter {
+ bool operator() (TimeAxisView* a, TimeAxisView* b) {
+ RouteTimeAxisView* ra = dynamic_cast<RouteTimeAxisView*> (a);
+ RouteTimeAxisView* rb = dynamic_cast<RouteTimeAxisView*> (b);
+ assert (ra && rb);
+ return ra->route()->order_key (N_ ("editor")) < rb->route()->order_key (N_ ("editor"));
+ }
+};
- for (TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
- RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
- TimeAxisView::Children children_list;
+RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
+ : Drag (e, i),
+ _primary (p)
+{
+ _editor->visible_order_range (&_visible_y_low, &_visible_y_high);
- /* zeroes are audio/MIDI tracks. ones are other types. */
+ /* Make a list of tracks to refer to during the drag; we include hidden tracks,
+ as some of the regions we are dragging may be on such tracks.
+ */
- if (!rtv->hidden()) {
+ TrackViewList track_views = _editor->track_views;
+ track_views.sort (EditorOrderTimeAxisViewSorter ());
- if (!rtv->is_track()) {
- /* not an audio nor MIDI track */
- sum.tracks = sum.tracks |= (0x01 << rtv->order());
- }
+ for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
+ _time_axis_views.push_back (*i);
+
+ TimeAxisView::Children children_list = (*i)->get_child_list ();
+ for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
+ _time_axis_views.push_back (j->get());
+ }
+ }
- sum.height_list[rtv->order()] = (*i)->current_height();
- children = 1;
+ /* the list of views can be empty at this point if this is a region list-insert drag
+ */
- if ((children_list = rtv->get_child_list()).size() > 0) {
- for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
- sum.tracks = sum.tracks |= (0x01 << (rtv->order() + children));
- sum.height_list[rtv->order() + children] = (*j)->current_height();
- children++;
- }
- }
- }
+ for (list<RegionView*>::const_iterator i = v.begin(); i != v.end(); ++i) {
+ _views.push_back (DraggingView (*i, this));
}
- return sum;
+ RegionView::RegionViewGoingAway.connect (death_connection, invalidator (*this), ui_bind (&RegionDrag::region_going_away, this, _1), gui_context());
}
-bool
-RegionMotionDrag::compute_y_delta (
- TimeAxisView const * last_pointer_view, TimeAxisView* current_pointer_view,
- int32_t last_pointer_layer, int32_t current_pointer_layer,
- TimeAxisViewSummary const & tavs,
- int32_t* pointer_order_span, int32_t* pointer_layer_span,
- int32_t* canvas_pointer_order_span
- )
+void
+RegionDrag::region_going_away (RegionView* v)
{
- if (_brushing) {
- *pointer_order_span = 0;
- *pointer_layer_span = 0;
- return true;
+ list<DraggingView>::iterator i = _views.begin ();
+ while (i != _views.end() && i->view != v) {
+ ++i;
}
- bool clamp_y_axis = false;
-
- /* the change in track order between this callback and the last */
- *pointer_order_span = last_pointer_view->order() - current_pointer_view->order();
- /* the change in layer between this callback and the last;
- only meaningful if pointer_order_span == 0 (ie we've not moved tracks) */
- *pointer_layer_span = last_pointer_layer - current_pointer_layer;
-
- if (*pointer_order_span != 0) {
-
- /* find the actual pointer span, in terms of the number of visible tracks;
- to do this, we reduce |pointer_order_span| by the number of hidden tracks
- over the span */
-
- *canvas_pointer_order_span = *pointer_order_span;
- if (last_pointer_view->order() >= current_pointer_view->order()) {
- for (int32_t y = current_pointer_view->order(); y < last_pointer_view->order(); y++) {
- if (tavs.height_list[y] == 0) {
- *canvas_pointer_order_span--;
- }
- }
- } else {
- for (int32_t y = last_pointer_view->order(); y <= current_pointer_view->order(); y++) {
- if (tavs.height_list[y] == 0) {
- *canvas_pointer_order_span++;
- }
- }
- }
-
- for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
-
- RegionView* rv = i->view;
-
- if (rv->region()->locked()) {
- continue;
- }
+ if (i != _views.end()) {
+ _views.erase (i);
+ }
+}
- double ix1, ix2, iy1, iy2;
- rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
- rv->get_canvas_frame()->i2w (ix1, iy1);
- iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
+/** Given a TimeAxisView, return the index of it into the _time_axis_views vector,
+ * or -1 if it is not found.
+ */
+int
+RegionDrag::find_time_axis_view (TimeAxisView* t) const
+{
+ int i = 0;
+ int const N = _time_axis_views.size ();
+ while (i < N && _time_axis_views[i] != t) {
+ ++i;
+ }
- /* get the new trackview for this particular region */
- pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (iy1);
- assert (tvp.first);
- RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
+ if (i == N) {
+ return -1;
+ }
- /* XXX: not sure that we should be passing canvas_pointer_order_span in here,
- as surely this is a per-region thing... */
+ return i;
+}
- clamp_y_axis = y_movement_disallowed (
- rtv->order(), last_pointer_view->order(), *canvas_pointer_order_span, tavs
- );
+RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
+ : RegionDrag (e, i, p, v),
+ _brushing (b),
+ _total_x_delta (0)
+{
- if (clamp_y_axis) {
- break;
- }
- }
+}
- } else if (_dest_trackview == current_pointer_view) {
- if (current_pointer_layer == last_pointer_layer) {
- /* No movement; clamp */
- clamp_y_axis = true;
- }
- }
+void
+RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
+{
+ Drag::start_grab (event, cursor);
- if (!clamp_y_axis) {
- _dest_trackview = current_pointer_view;
- _dest_layer = current_pointer_layer;
- }
+ show_verbose_cursor_time (_last_frame_position);
- return clamp_y_axis;
+ pair<TimeAxisView*, int> const tv = _editor->trackview_by_y_position (_drags->current_pointer_y ());
+ _last_pointer_time_axis_view = find_time_axis_view (tv.first);
+ _last_pointer_layer = tv.first->layer_display() == Overlaid ? 0 : tv.second;
}
-
double
-RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_region_position)
+RegionMotionDrag::compute_x_delta (GdkEvent const * event, framepos_t* pending_region_position)
{
/* compute the amount of pointer motion in frames, and where
the region would be if we moved it by that much.
*/
*pending_region_position = adjusted_current_frame (event);
- nframes64_t sync_frame;
- nframes64_t sync_offset;
+ framepos_t sync_frame;
+ framecnt_t sync_offset;
int32_t sync_dir;
-
+
sync_offset = _primary->region()->sync_offset (sync_dir);
-
+
/* we don't handle a sync point that lies before zero.
*/
if (sync_dir >= 0 || (sync_dir < 0 && *pending_region_position >= sync_offset)) {
-
+
sync_frame = *pending_region_position + (sync_dir*sync_offset);
-
+
_editor->snap_to_with_modifier (sync_frame, event);
-
+
*pending_region_position = _primary->region()->adjust_to_sync (sync_frame);
-
+
} else {
*pending_region_position = _last_frame_position;
}
- if (*pending_region_position > max_frames - _primary->region()->length()) {
+ if (*pending_region_position > max_framepos - _primary->region()->length()) {
*pending_region_position = _last_frame_position;
}
double dx = 0;
- if ((*pending_region_position != _last_frame_position) && x_move_allowed ()) {
+ /* in locked edit mode, reverse the usual meaning of _x_constrained */
+ bool const x_move_allowed = Config->get_edit_mode() == Lock ? _x_constrained : !_x_constrained;
+
+ if ((*pending_region_position != _last_frame_position) && x_move_allowed) {
- /* x movement since last time */
+ /* x movement since last time (in pixels) */
dx = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit;
/* total x movement */
framecnt_t total_dx = *pending_region_position;
if (regions_came_from_canvas()) {
- total_dx = total_dx - grab_frame () + _pointer_frame_offset;
+ total_dx = total_dx - grab_frame ();
}
/* check that no regions have gone off the start of the session */
return dx;
}
-void
-RegionMotionDrag::motion (GdkEvent* event, bool first_move)
+bool
+RegionMotionDrag::y_movement_allowed (int delta_track, layer_t delta_layer) const
{
- double y_delta = 0;
+ for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+ int const n = i->time_axis_view + delta_track;
+ if (n < 0 || n >= int (_time_axis_views.size())) {
+ /* off the top or bottom track */
+ return false;
+ }
- TimeAxisViewSummary tavs = get_time_axis_view_summary ();
+ RouteTimeAxisView const * to = dynamic_cast<RouteTimeAxisView const *> (_time_axis_views[n]);
+ if (to == 0 || !to->is_track() || to->track()->data_type() != i->view->region()->data_type()) {
+ /* not a track, or the wrong type */
+ return false;
+ }
- vector<int32_t>::iterator j;
+ int const l = i->layer + delta_layer;
+ if (delta_track == 0 && (l < 0 || l >= int (to->view()->layers()))) {
+ /* Off the top or bottom layer; note that we only refuse if the track hasn't changed.
+ If it has, the layers will be munged later anyway, so it's ok.
+ */
+ return false;
+ }
+ }
- /* *pointer* variables reflect things about the pointer; as we may be moving
- multiple regions, much detail must be computed per-region */
+ /* all regions being dragged are ok with this change */
+ return true;
+}
- /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
- current_pointer_layer the current layer on that TimeAxisView; in this code layer numbers
- are with respect to how the view's layers are displayed; if we are in Overlaid mode, layer
- is always 0 regardless of what the region's "real" layer is */
- RouteTimeAxisView* current_pointer_view;
- layer_t current_pointer_layer;
- if (!check_possible (¤t_pointer_view, ¤t_pointer_layer)) {
+void
+RegionMotionDrag::motion (GdkEvent* event, bool first_move)
+{
+ assert (!_views.empty ());
+
+ /* Find the TimeAxisView that the pointer is now over */
+ pair<TimeAxisView*, int> const tv = _editor->trackview_by_y_position (_drags->current_pointer_y ());
+
+ /* Bail early if we're not over a track */
+ RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv.first);
+ if (!rtv || !rtv->is_track()) {
+ _editor->verbose_cursor()->hide ();
return;
}
- /* TimeAxisView that we were pointing at last time we entered this method */
- TimeAxisView const * const last_pointer_view = _dest_trackview;
- /* the order of the track that we were pointing at last time we entered this method */
- int32_t const last_pointer_order = last_pointer_view->order ();
- /* the layer that we were pointing at last time we entered this method */
- layer_t const last_pointer_layer = _dest_layer;
+ /* Note: time axis views in this method are often expressed as an index into the _time_axis_views vector */
- int32_t pointer_order_span;
- int32_t pointer_layer_span;
- int32_t canvas_pointer_order_span;
-
- bool const clamp_y_axis = compute_y_delta (
- last_pointer_view, current_pointer_view,
- last_pointer_layer, current_pointer_layer, tavs,
- &pointer_order_span, &pointer_layer_span,
- &canvas_pointer_order_span
- );
+ /* Here's the current pointer position in terms of time axis view and layer */
+ int const current_pointer_time_axis_view = find_time_axis_view (tv.first);
+ layer_t const current_pointer_layer = tv.first->layer_display() == Overlaid ? 0 : tv.second;
- nframes64_t pending_region_position;
+ /* Work out the change in x */
+ framepos_t pending_region_position;
double const x_delta = compute_x_delta (event, &pending_region_position);
- /*************************************************************
- PREPARE TO MOVE
- ************************************************************/
+ /* Work out the change in y */
+ int delta_time_axis_view = current_pointer_time_axis_view - _last_pointer_time_axis_view;
+ int delta_layer = current_pointer_layer - _last_pointer_layer;
- if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0 && !first_move) {
+ if (!y_movement_allowed (delta_time_axis_view, delta_layer)) {
+ /* this y movement is not allowed, so do no y movement this time */
+ delta_time_axis_view = 0;
+ delta_layer = 0;
+ }
+
+ if (x_delta == 0 && delta_time_axis_view == 0 && delta_layer == 0 && !first_move) {
/* haven't reached next snap point, and we're not switching
trackviews nor layers. nothing to do.
*/
return;
}
- /*************************************************************
- MOTION
- ************************************************************/
-
pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
- for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+ for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
RegionView* rv = i->view;
continue;
}
- /* here we are calculating the y distance from the
- top of the first track view to the top of the region
- area of the track view that we're working on */
-
- /* this x value is just a dummy value so that we have something
- to pass to i2w () */
-
- double ix1 = 0;
-
- /* distance from the top of this track view to the region area
- of our track view is always 1 */
-
- double iy1 = 1;
-
- /* convert to world coordinates, ie distance from the top of
- the ruler section */
-
- rv->get_canvas_frame()->i2w (ix1, iy1);
-
- /* compensate for the ruler section and the vertical scrollbar position */
- iy1 += _editor->get_trackview_group_vertical_offset ();
-
if (first_move) {
- // hide any dependent views
-
rv->get_time_axis_view().hide_dependent_views (*rv);
-
- /*
- reparent to a non scrolling group so that we can keep the
+
+ /* Reparent to a non scrolling group so that we can keep the
region selection above all time axis views.
- reparenting means we have to move the rv as the two
- parent groups have different coordinates.
+ Reparenting means that we will have to move the region view
+ later, as the two parent groups have different coordinates.
*/
-
- rv->get_canvas_group()->property_y() = iy1 - 1;
- rv->get_canvas_group()->reparent(*(_editor->_region_motion_group));
-
+
+ rv->get_canvas_group()->reparent (*(_editor->_region_motion_group));
+
rv->fake_set_opaque (true);
+
+ if (!rv->get_time_axis_view().hidden()) {
+ /* the track that this region view is on is hidden, so hide the region too */
+ rv->get_canvas_group()->hide ();
+ }
}
- /* current view for this particular region */
- pair<TimeAxisView*, int> pos = _editor->trackview_by_y_position (iy1);
- RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
+ /* If we have moved tracks, we'll fudge the layer delta so that the
+ region gets moved back onto layer 0 on its new track; this avoids
+ confusion when dragging regions from non-zero layers onto different
+ tracks.
+ */
+ int this_delta_layer = delta_layer;
+ if (delta_time_axis_view != 0) {
+ this_delta_layer = - i->layer;
+ }
- if (pointer_order_span != 0 && !clamp_y_axis) {
+ /* The TimeAxisView that this region is now on */
+ TimeAxisView* tv = _time_axis_views[i->time_axis_view + delta_time_axis_view];
+
+ /* Set height */
+ rv->set_height (tv->view()->child_height ());
- /* INTER-TRACK MOVEMENT */
+ /* Update show/hidden status as the region view may have come from a hidden track,
+ or have moved to one.
+ */
+ if (tv->hidden ()) {
+ rv->get_canvas_group()->hide ();
+ } else {
+ rv->get_canvas_group()->show ();
+ }
- /* move through the height list to the track that the region is currently on */
- vector<int32_t>::iterator j = tavs.height_list.begin ();
- int32_t x = 0;
- while (j != tavs.height_list.end () && x != rtv->order ()) {
- ++x;
- ++j;
- }
+ /* Update the DraggingView */
+ i->time_axis_view += delta_time_axis_view;
+ i->layer += this_delta_layer;
- y_delta = 0;
- int32_t temp_pointer_order_span = canvas_pointer_order_span;
+ if (_brushing) {
+ _editor->mouse_brush_insert_region (rv, pending_region_position);
+ } else {
+ double x = 0;
+ double y = 0;
- if (j != tavs.height_list.end ()) {
+ /* Get the y coordinate of the top of the track that this region is now on */
+ tv->canvas_display()->i2w (x, y);
+ y += _editor->get_trackview_group_vertical_offset();
+
+ /* And adjust for the layer that it should be on */
+ StreamView* cv = tv->view ();
+ if (cv->layer_display() == Stacked) {
+ y += (cv->layers() - i->layer - 1) * cv->child_height ();
+ }
+
+ /* Now move the region view */
+ rv->move (x_delta, y - rv->get_canvas_group()->property_y());
+ }
- /* Account for layers in the original and
- destination tracks. If we're moving around in layers we assume
- that only one track is involved, so it's ok to use *pointer*
- variables here. */
+ } /* foreach region */
- StreamView* lv = last_pointer_view->view ();
- assert (lv);
+ _total_x_delta += x_delta;
- /* move to the top of the last trackview */
- if (lv->layer_display () == Stacked) {
- y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height ();
- }
+ if (first_move) {
+ _editor->cursor_group->raise_to_top();
+ }
- StreamView* cv = current_pointer_view->view ();
- assert (cv);
+ if (x_delta != 0 && !_brushing) {
+ show_verbose_cursor_time (_last_frame_position);
+ }
- /* move to the right layer on the current trackview */
- if (cv->layer_display () == Stacked) {
- y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height ();
- }
+ _last_pointer_time_axis_view += delta_time_axis_view;
+ _last_pointer_layer += delta_layer;
+}
- /* And for being on a non-topmost layer on the new
- track */
-
- while (temp_pointer_order_span > 0) {
- /* we're moving up canvas-wise,
- so we need to find the next track height
- */
- if (j != tavs.height_list.begin()) {
- j--;
- }
-
- if (x != last_pointer_order) {
- if ((*j) == 0) {
- ++temp_pointer_order_span;
- }
- }
-
- y_delta -= (*j);
- temp_pointer_order_span--;
- }
+void
+RegionMoveDrag::motion (GdkEvent* event, bool first_move)
+{
+ if (_copy && first_move) {
- while (temp_pointer_order_span < 0) {
+ /* duplicate the regionview(s) and region(s) */
- y_delta += (*j);
+ list<DraggingView> new_regionviews;
- if (x != last_pointer_order) {
- if ((*j) == 0) {
- --temp_pointer_order_span;
- }
- }
+ for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
- if (j != tavs.height_list.end()) {
- j++;
- }
+ RegionView* rv = i->view;
+ AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
+ MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
- temp_pointer_order_span++;
- }
+ const boost::shared_ptr<const Region> original = rv->region();
+ boost::shared_ptr<Region> region_copy = RegionFactory::create (original, true);
+ region_copy->set_position (original->position());
+ RegionView* nrv;
+ if (arv) {
+ boost::shared_ptr<AudioRegion> audioregion_copy
+ = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
- /* find out where we'll be when we move and set height accordingly */
+ nrv = new AudioRegionView (*arv, audioregion_copy);
+ } else if (mrv) {
+ boost::shared_ptr<MidiRegion> midiregion_copy
+ = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
+ nrv = new MidiRegionView (*mrv, midiregion_copy);
+ } else {
+ continue;
+ }
- pair<TimeAxisView*, int> const pos = _editor->trackview_by_y_position (iy1 + y_delta);
- RouteTimeAxisView const * temp_rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
- rv->set_height (temp_rtv->view()->child_height());
+ nrv->get_canvas_group()->show ();
+ new_regionviews.push_back (DraggingView (nrv, this));
- /* if you un-comment the following, the region colours will follow
- the track colours whilst dragging; personally
- i think this can confuse things, but never mind.
- */
+ /* swap _primary to the copy */
- //const GdkColor& col (temp_rtv->view->get_region_color());
- //rv->set_color (const_cast<GdkColor&>(col));
+ if (rv == _primary) {
+ _primary = nrv;
}
- }
- if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) {
+ /* ..and deselect the one we copied */
- /* INTER-LAYER MOVEMENT in the same track */
- y_delta = rtv->view()->child_height () * pointer_layer_span;
+ rv->set_selected (false);
}
- if (_brushing) {
- _editor->mouse_brush_insert_region (rv, pending_region_position);
- } else {
- rv->move (x_delta, y_delta);
- }
+ if (!new_regionviews.empty()) {
- } /* foreach region */
+ /* reflect the fact that we are dragging the copies */
- _total_x_delta += x_delta;
-
- if (first_move) {
- _editor->cursor_group->raise_to_top();
- }
+ _views = new_regionviews;
- if (x_delta != 0 && !_brushing) {
- _editor->show_verbose_time_cursor (_last_frame_position, 10);
- }
-}
+ swap_grab (new_regionviews.front().view->get_canvas_group (), 0, event ? event->motion.time : 0);
-void
-RegionMoveDrag::motion (GdkEvent* event, bool first_move)
-{
- if (_copy && first_move) {
- copy_regions (event);
+ /*
+ sync the canvas to what we think is its current state
+ without it, the canvas seems to
+ "forget" to update properly after the upcoming reparent()
+ ..only if the mouse is in rapid motion at the time of the grab.
+ something to do with regionview creation taking so long?
+ */
+ _editor->update_canvas_now();
+ }
}
RegionMotionDrag::motion (event, first_move);
}
void
-RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
+RegionMoveDrag::finished (GdkEvent *, bool movement_occurred)
{
if (!movement_occurred) {
/* just a click */
_x_constrained = !_x_constrained;
}
- bool const changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
- bool const changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
+ 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;
_editor->update_canvas_now ();
-
+
if (_copy) {
-
+
finished_copy (
- find_time_axis_views_and_layers (),
changed_position,
changed_tracks,
drag_delta
);
-
+
} else {
-
+
finished_no_copy (
- find_time_axis_views_and_layers (),
changed_position,
changed_tracks,
drag_delta
);
-
+
}
}
void
-RegionMoveDrag::finished_copy (
- map<RegionView*, pair<RouteTimeAxisView*, int> > const & final,
- bool const changed_position,
- bool const changed_tracks,
- framecnt_t const drag_delta
- )
+RegionMoveDrag::finished_copy (bool const changed_position, bool const /*changed_tracks*/, framecnt_t const drag_delta)
{
RegionSelection new_views;
PlaylistSet modified_playlists;
}
if (_x_constrained) {
- _editor->begin_reversible_command (_("fixed time region copy"));
+ _editor->begin_reversible_command (Operations::fixed_time_region_copy);
} else {
- _editor->begin_reversible_command (_("region copy"));
+ _editor->begin_reversible_command (Operations::region_copy);
}
/* insert the regions into their new playlists */
for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
- nframes64_t where;
-
if (i->view->region()->locked()) {
continue;
}
+ framepos_t where;
+
if (changed_position && !_x_constrained) {
where = i->view->region()->position() - drag_delta;
} else {
where = i->view->region()->position();
}
- map<RegionView*, pair<RouteTimeAxisView*, int> >::const_iterator j = final.find (i->view);
- assert (j != final.end());
-
RegionView* new_view = insert_region_into_playlist (
- i->view->region(), j->second.first, j->second.second, where, modified_playlists
+ i->view->region(), dynamic_cast<RouteTimeAxisView*> (_time_axis_views[i->time_axis_view]), i->layer, where, modified_playlists
);
-
+
if (new_view == 0) {
continue;
}
new_views.push_back (new_view);
-
+
/* we don't need the copied RegionView any more */
views_to_delete.push_back (i->view);
}
delete *i;
}
- /* If we've created new regions either by copying or moving
- to a new track, we want to replace the old selection with the new ones
+ /* If we've created new regions either by copying or moving
+ to a new track, we want to replace the old selection with the new ones
*/
if (new_views.size() > 0) {
void
RegionMoveDrag::finished_no_copy (
- map<RegionView*, pair<RouteTimeAxisView*, int> > const & final,
bool const changed_position,
bool const changed_tracks,
framecnt_t const drag_delta
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<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ) {
RegionView* rv = i->view;
- map<RegionView*, pair<RouteTimeAxisView*, int> >::const_iterator j = final.find (rv);
- assert (j != final.end());
-
- RouteTimeAxisView* dest_rtv = j->second.first;
- layer_t dest_layer = j->second.second;
+ RouteTimeAxisView* const dest_rtv = dynamic_cast<RouteTimeAxisView*> (_time_axis_views[i->time_axis_view]);
+ layer_t const dest_layer = i->layer;
if (rv->region()->locked()) {
++i;
continue;
}
- nframes64_t where;
+ framepos_t where;
if (changed_position && !_x_constrained) {
where = rv->region()->position() - drag_delta;
/* 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) {
remove_region_from_playlist (rv->region(), i->initial_playlist, modified_playlists);
} else {
-
- rv->region()->clear_history ();
+
+ rv->region()->clear_changes ();
/*
motion on the same track. plonk the previously reparented region
/* just change the model */
boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
-
+
if (dest_rtv->view()->layer_display() == Stacked) {
rv->region()->set_layer (dest_layer);
rv->region()->set_pending_explicit_relayer (true);
}
-
+
/* freeze playlist to avoid lots of relayering in the case of a multi-region drag */
pair<PlaylistSet::iterator, bool> r = frozen_playlists.insert (playlist);
playlist->freeze ();
}
- rv->region()->set_position (where, (void*) this);
+ /* this movement may result in a crossfade being modified, so we need to get undo
+ data from the playlist as well as the region.
+ */
+
+ r = modified_playlists.insert (playlist);
+ if (r.second) {
+ playlist->clear_changes ();
+ }
+
+ rv->region()->set_position (where);
_editor->session()->add_command (new StatefulDiffCommand (rv->region()));
}
if (changed_tracks) {
-
+
/* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
was selected in all of them, then removing it from a playlist will have removed all
trace of it from _views (i.e. there were N regions selected, we removed 1,
we can just iterate.
*/
-
+
if (_views.empty()) {
- break;
+ break;
} else {
i = _views.begin();
}
}
}
- /* If we've created new regions either by copying or moving
- to a new track, we want to replace the old selection with the new ones
+ /* If we've created new regions either by copying or moving
+ to a new track, we want to replace the old selection with the new ones
*/
if (new_views.size() > 0) {
* @param region Region to remove.
* @param playlist playlist To remove from.
* @param modified_playlists The playlist will be added to this if it is not there already; used to ensure
- * that clear_history () is only called once per playlist.
+ * that clear_changes () is only called once per playlist.
*/
void
RegionMoveDrag::remove_region_from_playlist (
pair<set<boost::shared_ptr<Playlist> >::iterator, bool> r = modified_playlists.insert (playlist);
if (r.second) {
- playlist->clear_history ();
+ playlist->clear_changes ();
}
playlist->remove_region (region);
}
-
+
/** Insert a region into a playlist, handling the recovery of the resulting new RegionView, and
* clearing the playlist's diff history first if necessary.
* @param dest_layer Destination layer.
* @param where Destination position.
* @param modified_playlists The playlist will be added to this if it is not there already; used to ensure
- * that clear_history () is only called once per playlist.
+ * that clear_changes () is only called once per playlist.
* @return New RegionView, or 0 if no insert was performed.
*/
RegionView *
_new_region_view = 0;
sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &RegionMoveDrag::collect_new_region_view));
- /* clear history for the playlist we are about to insert to, provided we haven't already done so */
+ /* clear history for the playlist we are about to insert to, provided we haven't already done so */
pair<PlaylistSet::iterator, bool> r = modified_playlists.insert (dest_playlist);
if (r.second) {
- dest_playlist->clear_history ();
+ dest_playlist->clear_changes ();
}
dest_playlist->add_region (region, where);
RegionMoveDrag::add_stateful_diff_commands_for_playlists (PlaylistSet const & playlists)
{
for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
- _editor->session()->add_command (new StatefulDiffCommand (*i));
+ StatefulDiffCommand* c = new StatefulDiffCommand (*i);
+ if (!c->empty()) {
+ _editor->session()->add_command (c);
+ } else {
+ delete c;
+ }
}
}
void
-RegionMoveDrag::aborted ()
+RegionMoveDrag::aborted (bool movement_occurred)
{
if (_copy) {
_views.clear ();
} else {
- RegionMotionDrag::aborted ();
+ RegionMotionDrag::aborted (movement_occurred);
}
}
void
-RegionMotionDrag::aborted ()
+RegionMotionDrag::aborted (bool)
{
for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
RegionView* rv = i->view;
_editor->update_canvas_now ();
}
-
-
-bool
-RegionMotionDrag::x_move_allowed () const
-{
- if (Config->get_edit_mode() == Lock) {
- /* in locked edit mode, reverse the usual meaning of _x_constrained */
- return _x_constrained;
- }
-
- return !_x_constrained;
-}
-
-void
-RegionMotionDrag::copy_regions (GdkEvent* event)
-{
- /* duplicate the regionview(s) and region(s) */
-
- list<DraggingView> new_regionviews;
-
- for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
-
- RegionView* rv = i->view;
- AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
- MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
-
- const boost::shared_ptr<const Region> original = rv->region();
- boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
- region_copy->set_position (original->position(), this);
-
- RegionView* nrv;
- if (arv) {
- boost::shared_ptr<AudioRegion> audioregion_copy
- = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
-
- nrv = new AudioRegionView (*arv, audioregion_copy);
- } else if (mrv) {
- boost::shared_ptr<MidiRegion> midiregion_copy
- = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
- nrv = new MidiRegionView (*mrv, midiregion_copy);
- } else {
- continue;
- }
-
- nrv->get_canvas_group()->show ();
- new_regionviews.push_back (DraggingView (nrv));
-
- /* swap _primary to the copy */
-
- if (rv == _primary) {
- _primary = nrv;
- }
-
- /* ..and deselect the one we copied */
-
- rv->set_selected (false);
- }
-
- if (new_regionviews.empty()) {
- return;
- }
-
- /* reflect the fact that we are dragging the copies */
-
- _views = new_regionviews;
-
- swap_grab (new_regionviews.front().view->get_canvas_group (), 0, event ? event->motion.time : 0);
-
- /*
- sync the canvas to what we think is its current state
- without it, the canvas seems to
- "forget" to update properly after the upcoming reparent()
- ..only if the mouse is in rapid motion at the time of the grab.
- something to do with regionview creation taking so long?
- */
- _editor->update_canvas_now();
-}
-
-bool
-RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
-{
- /* Which trackview is this ? */
-
- pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (_drags->current_pointer_y ());
- (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
- (*layer) = tvp.second;
-
- if (*tv && (*tv)->layer_display() == Overlaid) {
- *layer = 0;
- }
-
- /* The region motion is only processed if the pointer is over
- an audio track.
- */
-
- if (!(*tv) || !(*tv)->is_track()) {
- /* To make sure we hide the verbose canvas cursor when the mouse is
- not held over and audiotrack.
- */
- _editor->hide_verbose_canvas_cursor ();
- return false;
- }
-
- return true;
-}
-/** @param new_order New track order.
- * @param old_order Old track order.
- * @param visible_y_low Lowest visible order.
- * @return true if y movement should not happen, otherwise false.
+/** @param b true to brush, otherwise false.
+ * @param c true to make copies of the regions being moved, otherwise false.
*/
-bool
-RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
-{
- if (new_order != old_order) {
-
- /* this isn't the pointer track */
-
- if (y_span > 0) {
-
- /* moving up the canvas */
- if ( (new_order - y_span) >= tavs.visible_y_low) {
-
- int32_t n = 0;
-
- /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
- int32_t visible_tracks = 0;
- while (visible_tracks < y_span ) {
- visible_tracks++;
- while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
- /* passing through a hidden track */
- n--;
- }
- }
-
- if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
- /* moving to a non-track; disallow */
- return true;
- }
-
-
- } else {
- /* moving beyond the lowest visible track; disallow */
- return true;
- }
-
- } else if (y_span < 0) {
-
- /* moving down the canvas */
- if ((new_order - y_span) <= tavs.visible_y_high) {
-
- int32_t visible_tracks = 0;
- int32_t n = 0;
- while (visible_tracks > y_span ) {
- visible_tracks--;
-
- while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
- /* passing through a hidden track */
- n++;
- }
- }
-
- if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
- /* moving to a non-track; disallow */
- return true;
- }
-
-
- } else {
-
- /* moving beyond the highest visible track; disallow */
- return true;
- }
- }
-
- } else {
-
- /* this is the pointer's track */
-
- if ((new_order - y_span) > tavs.visible_y_high) {
- /* we will overflow */
- return true;
- } else if ((new_order - y_span) < tavs.visible_y_low) {
- /* we will overflow */
- return true;
- }
- }
-
- return false;
-}
-
-
RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
: RegionMotionDrag (e, i, p, v, b),
_copy (c)
{
- TimeAxisView* const tv = &_primary->get_time_axis_view ();
-
- _dest_trackview = tv;
- if (tv->layer_display() == Overlaid) {
- _dest_layer = 0;
- } else {
- _dest_layer = _primary->region()->layer ();
- }
+ DEBUG_TRACE (DEBUG::Drags, "New RegionMoveDrag\n");
double speed = 1;
- RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
+ RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&_primary->get_time_axis_view ());
if (rtv && rtv->is_track()) {
speed = rtv->track()->speed ();
}
- _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
+ _last_frame_position = static_cast<framepos_t> (_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<Region> r, RouteTimeAxisView* v, nframes64_t pos)
+RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, framepos_t pos)
: RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
{
+ DEBUG_TRACE (DEBUG::Drags, "New RegionInsertDrag\n");
+
assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
(boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
_primary->get_canvas_group()->show ();
_primary->set_position (pos, 0);
- _views.push_back (DraggingView (_primary));
+ _views.push_back (DraggingView (_primary, this));
_last_frame_position = pos;
_item = _primary->get_canvas_group ();
- _dest_trackview = v;
- _dest_layer = _primary->region()->layer ();
-}
-
-map<RegionView*, pair<RouteTimeAxisView*, int> >
-RegionMotionDrag::find_time_axis_views_and_layers ()
-{
- map<RegionView*, pair<RouteTimeAxisView*, int> > tav;
-
- for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
-
- double ix1, ix2, iy1, iy2;
- RegionView* rv = i->view;
- rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
- rv->get_canvas_frame()->i2w (ix1, iy1);
- iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
-
- pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
- tav[rv] = make_pair (dynamic_cast<RouteTimeAxisView*> (tv.first), tv.second);
- }
-
- return tav;
}
-
void
-RegionInsertDrag::finished (GdkEvent* /*event*/, bool /*movement_occurred*/)
+RegionInsertDrag::finished (GdkEvent *, bool)
{
_editor->update_canvas_now ();
- map<RegionView*, pair<RouteTimeAxisView*, int> > final = find_time_axis_views_and_layers ();
-
- RouteTimeAxisView* dest_rtv = final[_primary].first;
+ RouteTimeAxisView* dest_rtv = dynamic_cast<RouteTimeAxisView*> (_time_axis_views[_views.front().time_axis_view]);
_primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
_primary->get_canvas_group()->property_y() = 0;
boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
- _editor->begin_reversible_command (_("insert region"));
- playlist->clear_history ();
+ _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 ();
}
void
-RegionInsertDrag::aborted ()
+RegionInsertDrag::aborted (bool)
{
delete _primary;
_primary = 0;
RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
: RegionMoveDrag (e, i, p, v, false, false)
{
-
+ DEBUG_TRACE (DEBUG::Drags, "New RegionSpliceDrag\n");
}
struct RegionSelectionByPosition {
void
RegionSpliceDrag::motion (GdkEvent* event, bool)
{
- RouteTimeAxisView* tv;
- layer_t layer;
+ /* Which trackview is this ? */
+
+ pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (_drags->current_pointer_y ());
+ RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
+
+ /* The region motion is only processed if the pointer is over
+ an audio track.
+ */
- if (!check_possible (&tv, &layer)) {
+ if (!tv || !tv->is_track()) {
+ /* To make sure we hide the verbose canvas cursor when the mouse is
+ not held over and audiotrack.
+ */
+ _editor->verbose_cursor()->hide ();
return;
}
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) {
}
void
-RegionSpliceDrag::finished (GdkEvent* /*event*/, bool)
+RegionSpliceDrag::finished (GdkEvent* event, bool movement_occurred)
{
-
+ RegionMoveDrag::finished (event, movement_occurred);
}
void
-RegionSpliceDrag::aborted ()
+RegionSpliceDrag::aborted (bool)
{
/* XXX: TODO */
}
: Drag (e, i),
_view (dynamic_cast<MidiTimeAxisView*> (v))
{
+ DEBUG_TRACE (DEBUG::Drags, "New RegionCreateDrag\n");
+
assert (_view);
}
RegionCreateDrag::motion (GdkEvent* event, bool first_move)
{
if (first_move) {
- /* don't use a zero-length region otherwise its region view will be hidden when it is created */
- _region = _view->add_region (grab_frame(), 1, false);
+ add_region();
+ _view->playlist()->freeze ();
} else {
- framepos_t const f = adjusted_current_frame (event);
- if (f < grab_frame()) {
- _region->set_position (f, this);
- }
+ if (_region) {
+ framepos_t const f = adjusted_current_frame (event);
+ if (f < grab_frame()) {
+ _region->set_position (f);
+ }
- /* again, don't use a zero-length region (see above) */
- framecnt_t const len = abs (f - grab_frame ());
- _region->set_length (len < 1 ? 1 : len, this);
+ /* Don't use a zero-length region, and subtract 1 frame from the snapped length
+ so that if this region is duplicated, its duplicate starts on
+ a snap point rather than 1 frame after a snap point. Otherwise things get
+ a bit confusing as if a region starts 1 frame after a snap point, one cannot
+ place snapped notes at the start of the region.
+ */
+
+ framecnt_t const len = abs (f - grab_frame () - 1);
+ _region->set_length (len < 1 ? 1 : len);
+ }
}
}
void
-RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred)
+RegionCreateDrag::finished (GdkEvent*, bool movement_occurred)
{
- if (movement_occurred) {
+ if (!movement_occurred) {
+ add_region ();
+ } else {
+ _view->playlist()->thaw ();
+ }
+
+ if (_region) {
_editor->commit_reversible_command ();
}
}
void
-RegionCreateDrag::aborted ()
+RegionCreateDrag::add_region ()
+{
+ if (_editor->session()) {
+ const TempoMap& map (_editor->session()->tempo_map());
+ framecnt_t pos = grab_frame();
+ const Meter& m = map.meter_at (pos);
+ /* not that the frame rate used here can be affected by pull up/down which
+ might be wrong.
+ */
+ framecnt_t len = m.frames_per_bar (map.tempo_at (pos), _editor->session()->frame_rate());
+ _region = _view->add_region (grab_frame(), len, false);
+ }
+}
+
+void
+RegionCreateDrag::aborted (bool)
{
+ if (_region) {
+ _view->playlist()->thaw ();
+ }
+
/* XXX */
}
: 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<ArdourCanvas::CanvasNote*>(_item);
+ ArdourCanvas::CanvasNoteEvent* cnote = dynamic_cast<ArdourCanvas::CanvasNoteEvent*>(_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();
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;
}
{
MidiRegionSelection& ms (_editor->get_selection().midi_regions);
for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
- (*r)->update_resizing (dynamic_cast<ArdourCanvas::CanvasNote*>(_item), at_front, _drags->current_pointer_x() - grab_x(), relative);
+ (*r)->update_resizing (dynamic_cast<ArdourCanvas::CanvasNoteEvent*>(_item), at_front, _drags->current_pointer_x() - grab_x(), relative);
}
}
{
MidiRegionSelection& ms (_editor->get_selection().midi_regions);
for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
- (*r)->commit_resizing (dynamic_cast<ArdourCanvas::CanvasNote*>(_item), at_front, _drags->current_pointer_x() - grab_x(), relative);
+ (*r)->commit_resizing (dynamic_cast<ArdourCanvas::CanvasNoteEvent*>(_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)
{
}
void
-RegionGainDrag::aborted ()
+RegionGainDrag::aborted (bool)
{
/* XXX: TODO */
}
TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
: RegionDrag (e, i, p, v)
- , _have_transaction (false)
{
-
+ DEBUG_TRACE (DEBUG::Drags, "New TrimDrag\n");
}
void
-TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
+TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
{
double speed = 1.0;
TimeAxisView* tvp = &_primary->get_time_axis_view ();
speed = tv->track()->speed();
}
- nframes64_t const region_start = (nframes64_t) (_primary->region()->position() / speed);
- nframes64_t const region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
- nframes64_t const region_length = (nframes64_t) (_primary->region()->length() / speed);
+ framepos_t const region_start = (framepos_t) (_primary->region()->position() / speed);
+ framepos_t const region_end = (framepos_t) (_primary->region()->last_frame() / speed);
+ framecnt_t const region_length = (framecnt_t) (_primary->region()->length() / speed);
- nframes64_t const pf = adjusted_current_frame (event);
+ framepos_t const pf = adjusted_current_frame (event);
if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
+ /* Move the contents of the region around without changing the region bounds */
_operation = ContentsTrim;
- Drag::start_grab (event, _editor->trimmer_cursor);
+ Drag::start_grab (event, _editor->cursors()->trimmer);
} else {
/* These will get overridden for a point trim.*/
if (pf < (region_start + region_length/2)) {
- /* closer to start */
+ /* closer to front */
_operation = StartTrim;
- Drag::start_grab (event, _editor->left_side_trim_cursor);
+ Drag::start_grab (event, _editor->cursors()->left_side_trim);
} else {
/* closer to end */
_operation = EndTrim;
- Drag::start_grab (event, _editor->right_side_trim_cursor);
- }
+ Drag::start_grab (event, _editor->cursors()->right_side_trim);
+ }
}
switch (_operation) {
case StartTrim:
- _editor->show_verbose_time_cursor (region_start, 10);
+ show_verbose_cursor_time (region_start);
+ for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
+ i->view->trim_front_starting ();
+ }
break;
case EndTrim:
- _editor->show_verbose_time_cursor (region_end, 10);
+ show_verbose_cursor_time (region_end);
break;
case ContentsTrim:
- _editor->show_verbose_time_cursor (pf, 10);
+ show_verbose_cursor_time (pf);
break;
}
+
+ for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+ i->view->region()->suspend_property_changes ();
+ }
}
void
{
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<RouteTimeAxisView*>(tvp);
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) {
}
_editor->begin_reversible_command (trim_type);
- _have_transaction = true;
for (list<DraggingView>::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_history ();
- rv->region()->suspend_property_changes ();
+ rv->region()->playlist()->clear_owned_changes ();
AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (rv);
- if (arv){
+ if (arv) {
arv->temporarily_hide_envelope ();
}
switch (_operation) {
case StartTrim:
for (list<DraggingView>::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<DraggingView>::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;
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<DraggingView>::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;
switch (_operation) {
case StartTrim:
- _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
+ show_verbose_cursor_time ((framepos_t) (rv->region()->position() / speed));
break;
case EndTrim:
- _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
+ show_verbose_cursor_time ((framepos_t) (rv->region()->last_frame() / speed));
break;
case ContentsTrim:
- _editor->show_verbose_time_cursor (pf, 10);
+ show_verbose_cursor_time (adjusted_current_frame (event));
break;
}
}
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<DraggingView>::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<boost::shared_ptr<Playlist> > diffed_playlists;
+
for (list<DraggingView>::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<Playlist> p = i->view->region()->playlist ();
+ if (diffed_playlists.find (p) == diffed_playlists.end()) {
+ vector<Command*> cmds;
+ p->rdiff (cmds);
+ _editor->session()->add_commands (cmds);
+ diffed_playlists.insert (p);
+ }
}
}
for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
}
_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<DraggingView>::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
*/
finished (0, true);
-
- if (_have_transaction) {
+
+ if (movement_occurred) {
_editor->undo ();
}
+
+ for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+ i->view->region()->resume_property_changes ();
+ }
+}
+
+void
+TrimDrag::setup_pointer_frame_offset ()
+{
+ list<DraggingView>::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<MeterMarker*> (_item->get_data ("marker"));
assert (_marker);
}
// 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;
Drag::start_grab (event, cursor);
- _pointer_frame_offset = grab_frame() - _marker->meter().frame();
+ show_verbose_cursor_time (adjusted_current_frame(event));
+}
- _editor->show_verbose_time_cursor (adjusted_current_frame(event), 10);
+void
+MeterMarkerDrag::setup_pointer_frame_offset ()
+{
+ _pointer_frame_offset = raw_grab_frame() - _marker->meter().frame();
}
void
MeterMarkerDrag::motion (GdkEvent* event, bool)
{
- nframes64_t const pf = adjusted_current_frame (event);
+ framepos_t const pf = adjusted_current_frame (event);
_marker->set_position (pf);
-
- _editor->show_verbose_time_cursor (pf, 10);
+
+ show_verbose_cursor_time (pf);
}
void
motion (event, false);
- BBT_Time when;
+ Timecode::BBT_Time when;
TempoMap& map (_editor->session()->tempo_map());
map.bbt_time (last_pointer_frame(), when);
}
void
-MeterMarkerDrag::aborted ()
+MeterMarkerDrag::aborted (bool)
{
_marker->set_position (_marker->meter().frame ());
}
: Drag (e, i),
_copy (c)
{
+ DEBUG_TRACE (DEBUG::Drags, "New TempoMarkerDrag\n");
+
_marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
assert (_marker);
}
void
TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
{
-
if (_copy) {
// create a dummy marker for visual representation of moving the copy.
// The actual copying is not done before we reach the finish callback.
char name[64];
snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
- TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
- *new TempoSection (_marker->tempo()));
+
+ TempoMarker* new_marker = new TempoMarker (
+ *_editor,
+ *_editor->tempo_group,
+ ARDOUR_UI::config()->canvasvar_TempoMarker.get(),
+ name,
+ *new TempoSection (_marker->tempo())
+ );
_item = &new_marker->the_item ();
_marker = new_marker;
- } else {
-
- MetricSection& section (_marker->tempo());
-
- if (!section.movable()) {
- return;
- }
}
Drag::start_grab (event, cursor);
- _pointer_frame_offset = grab_frame() - _marker->tempo().frame();
- _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
+ show_verbose_cursor_time (adjusted_current_frame (event));
+}
+
+void
+TempoMarkerDrag::setup_pointer_frame_offset ()
+{
+ _pointer_frame_offset = raw_grab_frame() - _marker->tempo().frame();
}
void
TempoMarkerDrag::motion (GdkEvent* event, bool)
{
- nframes64_t const pf = adjusted_current_frame (event);
+ framepos_t const pf = adjusted_current_frame (event);
_marker->set_position (pf);
- _editor->show_verbose_time_cursor (pf, 10);
+ show_verbose_cursor_time (pf);
}
void
motion (event, false);
- BBT_Time when;
+ Timecode::BBT_Time when;
TempoMap& map (_editor->session()->tempo_map());
map.bbt_time (last_pointer_frame(), when);
}
void
-TempoMarkerDrag::aborted ()
+TempoMarkerDrag::aborted (bool)
{
_marker->set_position (_marker->tempo().frame());
}
-CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
- : Drag (e, i),
- _stop (s)
-{
- _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
- assert (_cursor);
+CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
+ : Drag (e, i),
+ _stop (s)
+{
+ 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::fake_locate (framepos_t t)
+{
+ _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);
+ }
+
+ show_verbose_cursor_time (t);
+ _editor->UpdateAllTransportClocks (t);
}
void
{
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);
-
- }
+ _grab_zoom = _editor->frames_per_unit;
- if (_cursor == _editor->playhead_cursor) {
- _editor->_dragging_playhead = true;
+ framepos_t where = _editor->event_frame (event, 0, 0);
+ _editor->snap_to_with_modifier (where, event);
- Session* s = _editor->session ();
+ _editor->_dragging_playhead = true;
- if (s) {
- if (_was_rolling && _stop) {
- s->request_stop ();
- }
+ Session* s = _editor->session ();
- if (s->is_auditioning()) {
- s->cancel_audition ();
- }
+ if (s) {
+ if (_was_rolling && _stop) {
+ s->request_stop ();
+ }
- s->request_suspend_timecode_transmission ();
+ if (s->is_auditioning()) {
+ s->cancel_audition ();
+ }
- if (s->timecode_transmission_suspended ()) {
- nframes64_t const f = _editor->playhead_cursor->current_frame;
- s->send_mmc_locate (f);
- s->send_full_time_code (f);
- }
+ s->request_suspend_timecode_transmission ();
+ while (!s->timecode_transmission_suspended ()) {
+ /* twiddle our thumbs */
}
}
- _pointer_frame_offset = grab_frame() - _cursor->current_frame;
-
- _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
+ fake_locate (where);
}
void
CursorDrag::motion (GdkEvent* event, bool)
{
- nframes64_t const adjusted_frame = adjusted_current_frame (event);
+ if (_drags->current_pointer_y() != last_pointer_y()) {
- if (adjusted_frame == last_pointer_frame()) {
- return;
- }
+ /* zoom when we move the pointer up and down */
- _cursor->set_position (adjusted_frame);
+ /* y range to operate over (pixels) */
+ double const y_range = 512;
+ /* we will multiply the grab zoom by a factor between scale_range and scale_range^-1 */
+ double const scale_range = 4;
+ /* dead zone around the grab point in which to do no zooming (pixels) */
+ double const dead_zone = 100;
- _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
+ /* current dy */
+ double dy = _drags->current_pointer_y() - grab_y();
- 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);
+ if (dy < -dead_zone || dy > dead_zone) {
+ /* we are outside the dead zone; remove it from our calculation */
+ if (dy < 0) {
+ dy += dead_zone;
+ } else {
+ dy -= dead_zone;
+ }
+
+ /* get a number from -1 to 1 as dy ranges from -y_range to y_range */
+ double udy = max (min (dy / y_range, 1.0), -1.0);
+
+ /* and zoom, using playhead focus temporarily */
+ Editing::ZoomFocus const zf = _editor->get_zoom_focus ();
+ _editor->set_zoom_focus (Editing::ZoomFocusPlayhead);
+ _editor->temporal_zoom (_grab_zoom * pow (scale_range, -udy));
+ _editor->set_zoom_focus (zf);
+ }
}
-
+ framepos_t const adjusted_frame = adjusted_current_frame (event);
+ if (adjusted_frame != last_pointer_frame()) {
+ fake_locate (adjusted_frame);
#ifdef GTKOSX
- _editor->update_canvas_now ();
+ _editor->update_canvas_now ();
#endif
- _editor->UpdateAllTransportClocks (_cursor->current_frame);
+ }
}
void
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<RegionView*> const & v)
: RegionDrag (e, i, p, v)
{
-
+ DEBUG_TRACE (DEBUG::Drags, "New FadeInDrag\n");
}
void
{
Drag::start_grab (event, cursor);
- AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
- boost::shared_ptr<AudioRegion> const r = a->audio_region ();
+ AudioRegionView* arv = dynamic_cast<AudioRegionView*> (_primary);
+ boost::shared_ptr<AudioRegion> const r = arv->audio_region ();
+
+ show_verbose_cursor_duration (r->position(), r->position() + r->fade_in()->back()->when, 32);
- _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<AudioRegionView*> (_primary);
+ boost::shared_ptr<AudioRegion> 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> region = _primary->region ();
}
tmp->reset_fade_in_shape_width (fade_length);
+ tmp->show_fade_line((framecnt_t) fade_length);
}
- _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
+ show_verbose_cursor_duration (region->position(), region->position() + fade_length, 32);
}
void
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> region = _primary->region ();
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<AutomationList>(*alist.get(), &before, &after));
}
void
-FadeInDrag::aborted ()
+FadeInDrag::aborted (bool)
{
for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
}
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<RegionView*> const & v)
: RegionDrag (e, i, p, v)
{
-
+ DEBUG_TRACE (DEBUG::Drags, "New FadeOutDrag\n");
}
void
{
Drag::start_grab (event, cursor);
- AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
- boost::shared_ptr<AudioRegion> r = a->audio_region ();
+ AudioRegionView* arv = dynamic_cast<AudioRegionView*> (_primary);
+ boost::shared_ptr<AudioRegion> r = arv->audio_region ();
+
+ show_verbose_cursor_duration (r->last_frame() - r->fade_out()->back()->when, r->last_frame());
+
+ arv->show_fade_line(r->length() - r->fade_out()->back()->when);
+}
- _pointer_frame_offset = grab_frame() - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
- _editor->show_verbose_duration_cursor (r->last_frame() - r->fade_out()->back()->when, r->last_frame(), 10);
+void
+FadeOutDrag::setup_pointer_frame_offset ()
+{
+ AudioRegionView* arv = dynamic_cast<AudioRegionView*> (_primary);
+ boost::shared_ptr<AudioRegion> 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> region = _primary->region ();
}
tmp->reset_fade_out_shape_width (fade_length);
+ tmp->show_fade_line(region->length() - fade_length);
}
- _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
+ show_verbose_cursor_duration (region->last_frame() - fade_length, region->last_frame());
}
void
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> region = _primary->region ();
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<AutomationList>(*alist.get(), &before, &after));
}
void
-FadeOutDrag::aborted ()
+FadeOutDrag::aborted (bool)
{
for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
}
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<Marker*> (_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 ()
Location *location = _editor->find_location_from_marker (_marker, is_start);
_editor->_dragging_edit_point = true;
- _pointer_frame_offset = grab_frame() - (is_start ? location->start() : location->end());
-
update_item (location);
// _drag_line->show();
// _line->raise_to_top();
if (is_start) {
- _editor->show_verbose_time_cursor (location->start(), 10);
+ show_verbose_cursor_time (location->start());
} else {
- _editor->show_verbose_time_cursor (location->end(), 10);
+ show_verbose_cursor_time (location->end());
}
Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
{
Locations::LocationList ll;
list<Marker*> 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));
}
}
+void
+MarkerDrag::setup_pointer_frame_offset ()
+{
+ bool is_start;
+ Location *location = _editor->find_location_from_marker (_marker, is_start);
+ _pointer_frame_offset = raw_grab_frame() - (is_start ? location->start() : location->end());
+}
+
void
MarkerDrag::motion (GdkEvent* event, bool)
{
- nframes64_t f_delta = 0;
+ framecnt_t f_delta = 0;
bool is_start;
bool move_both = false;
Marker* marker;
Location *real_location;
Location *copy_location = 0;
- nframes64_t const newframe = adjusted_current_frame (event);
+ framepos_t const newframe = adjusted_current_frame (event);
- nframes64_t next = newframe;
-
- if (newframe == last_pointer_frame()) {
- return;
- }
+ framepos_t next = newframe;
if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
move_both = true;
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();
} 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
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);
assert (!_copied_locations.empty());
- _editor->show_verbose_time_cursor (newframe, 10);
+ show_verbose_cursor_time (newframe);
#ifdef GTKOSX
_editor->update_canvas_now ();
XMLNode &after = _editor->session()->locations()->get_state();
_editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
_editor->commit_reversible_command ();
-
- _line->hide();
}
void
-MarkerDrag::aborted ()
+MarkerDrag::aborted (bool)
{
/* XXX: TODO */
}
void
-MarkerDrag::update_item (Location* location)
+MarkerDrag::update_item (Location*)
{
- double const x1 = _editor->frame_to_pixel (location->start());
-
- _points.front().set_x(x1);
- _points.back().set_x(x1);
- _line->property_points() = _points;
+ /* noop */
}
ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
_cumulative_x_drag (0),
_cumulative_y_drag (0)
{
+ if (_zero_gain_fraction < 0.0) {
+ _zero_gain_fraction = gain_to_slider_position_with_max (dB_to_coefficient (0.0), Config->get_max_gain());
+ }
+
+ DEBUG_TRACE (DEBUG::Drags, "New ControlPointDrag\n");
+
_point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
assert (_point);
}
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
_point->line().start_drag_single (_point, _fixed_grab_x, fraction);
- _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
- event->button.x + 10, event->button.y + 10);
+ _editor->verbose_cursor()->set (_point->line().get_verbose_cursor_string (fraction),
+ event->button.x + 10, event->button.y + 10);
- _editor->show_verbose_canvas_cursor ();
+ _editor->verbose_cursor()->show ();
}
void
cy = min ((double) _point->line().height(), cy);
framepos_t cx_frames = _editor->unit_to_frame (cx);
-
+
if (!_x_constrained) {
_editor->snap_to_with_modifier (cx_frames, event);
}
_point->line().drag_motion (_editor->frame_to_unit (cx_frames), fraction, false, push);
- _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
+ _editor->verbose_cursor()->set_text (_point->line().get_verbose_cursor_string (fraction));
}
void
} else {
motion (event, false);
}
+
_point->line().end_drag ();
+ _editor->session()->commit_reversible_command ();
}
void
-ControlPointDrag::aborted ()
+ControlPointDrag::aborted (bool)
{
_point->line().reset ();
}
_line (0),
_cumulative_y_drag (0)
{
-
+ DEBUG_TRACE (DEBUG::Drags, "New LineDrag\n");
}
+
void
LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
{
_line->parent_group().w2i (cx, cy);
- nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
+ framecnt_t const frame_within_region = (framecnt_t) floor (cx * _editor->frames_per_unit);
uint32_t before;
uint32_t after;
-
+
if (!_line->control_points_adjacent (frame_within_region, before, after)) {
/* no adjacent points */
return;
}
- Drag::start_grab (event, _editor->fader_cursor);
+ Drag::start_grab (event, _editor->cursors()->fader);
/* store grab start in parent frame */
_line->start_drag_line (before, after, fraction);
- _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
- event->button.x + 10, event->button.y + 10);
+ _editor->verbose_cursor()->set (_line->get_verbose_cursor_string (fraction),
+ event->button.x + 10, event->button.y + 10);
- _editor->show_verbose_canvas_cursor ();
+ _editor->verbose_cursor()->show ();
}
void
/* we are ignoring x position for this drag, so we can just pass in anything */
_line->drag_motion (0, fraction, true, push);
- _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
+ _editor->verbose_cursor()->set_text (_line->get_verbose_cursor_string (fraction));
}
void
{
motion (event, false);
_line->end_drag ();
+ _editor->session()->commit_reversible_command ();
}
void
-LineDrag::aborted ()
+LineDrag::aborted (bool)
{
_line->reset ();
}
_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<SimpleLine*> (_item);
+
+ _line = reinterpret_cast<Line*> (_item);
assert (_line);
/* need to get x coordinate in terms of parent (AudioRegionView) origin. */
/* store grab start in parent frame */
_region_view_grab_x = cx;
-
- _before = _line->property_x1();
-
+
+ _before = *(float*) _item->get_data ("position");
+
_arv = reinterpret_cast<AudioRegionView*> (_item->get_data ("regionview"));
-
+
_max_x = _editor->frame_to_pixel(_arv->get_duration());
}
void
-FeatureLineDrag::motion (GdkEvent* event, bool)
+FeatureLineDrag::motion (GdkEvent*, bool)
{
double dx = _drags->current_pointer_x() - last_pointer_x();
-
+
double cx = _region_view_grab_x + _cumulative_x_drag + dx;
-
+
_cumulative_x_drag += dx;
-
+
/* Clamp the min and max extent of the drag to keep it within the region view bounds */
-
+
if (cx > _max_x){
cx = _max_x;
}
else if(cx < 0){
cx = 0;
}
-
- _line->property_x1() = cx;
- _line->property_x2() = cx;
- _before = _line->property_x1();
+ ArdourCanvas::Points points;
+
+ double x1 = 0, x2 = 0, y1 = 0, y2 = 0;
+
+ _line->get_bounds(x1, y2, x2, y2);
+
+ points.push_back(Gnome::Art::Point(cx, 2.0)); // first x-coord needs to be a non-normal value
+ points.push_back(Gnome::Art::Point(cx, y2 - y1));
+
+ _line->property_points() = points;
+
+ float *pos = new float;
+ *pos = cx;
+
+ _line->set_data ("position", pos);
+
+ _before = cx;
}
void
-FeatureLineDrag::finished (GdkEvent* event, bool)
+FeatureLineDrag::finished (GdkEvent*, bool)
{
_arv = reinterpret_cast<AudioRegionView*> (_item->get_data ("regionview"));
- _arv->update_transient(_before, _line->property_x1());
+ _arv->update_transient(_before, _before);
}
void
-FeatureLineDrag::aborted ()
+FeatureLineDrag::aborted (bool)
{
//_line->reset ();
}
+RubberbandSelectDrag::RubberbandSelectDrag (Editor* e, ArdourCanvas::Item* i)
+ : Drag (e, i)
+{
+ DEBUG_TRACE (DEBUG::Drags, "New RubberbandSelectDrag\n");
+}
+
void
RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
{
Drag::start_grab (event);
- _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
+ show_verbose_cursor_time (adjusted_current_frame (event));
}
void
RubberbandSelectDrag::motion (GdkEvent* event, bool)
{
- nframes64_t start;
- nframes64_t end;
+ framepos_t start;
+ framepos_t end;
double y1;
double y2;
- nframes64_t const pf = adjusted_current_frame (event, Config->get_rubberbanding_snaps_to_grid ());
+ framepos_t const pf = adjusted_current_frame (event, Config->get_rubberbanding_snaps_to_grid ());
- nframes64_t grab = grab_frame ();
+ framepos_t grab = grab_frame ();
if (Config->get_rubberbanding_snaps_to_grid ()) {
_editor->snap_to_with_modifier (grab, event);
}
_editor->rubberband_rect->show();
_editor->rubberband_rect->raise_to_top();
- _editor->show_verbose_time_cursor (pf, 10);
+ show_verbose_cursor_time (pf);
}
}
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")) {
}
void
-RubberbandSelectDrag::aborted ()
+RubberbandSelectDrag::aborted (bool)
{
_editor->rubberband_rect->hide ();
}
+TimeFXDrag::TimeFXDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, std::list<RegionView*> const & v)
+ : RegionDrag (e, i, p, v)
+{
+ DEBUG_TRACE (DEBUG::Drags, "New TimeFXDrag\n");
+}
+
void
-TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
+TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
{
- Drag::start_grab (event);
+ Drag::start_grab (event, cursor);
- _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
+ show_verbose_cursor_time (adjusted_current_frame (event));
}
void
{
RegionView* rv = _primary;
- nframes64_t const pf = adjusted_current_frame (event);
+ framepos_t const pf = adjusted_current_frame (event);
if (pf > rv->region()->position()) {
rv->get_time_axis_view().show_timestretch (rv->region()->position(), pf);
}
- _editor->show_verbose_time_cursor (pf, 10);
+ show_verbose_cursor_time (pf);
}
void
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();
}
#endif
- _editor->begin_reversible_command (_("timestretch"));
-
// XXX how do timeFX on multiple regions ?
RegionSelection rs;
}
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 *)
}
void
-ScrubDrag::aborted ()
+ScrubDrag::aborted (bool)
{
/* XXX: TODO */
}
, _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;
}
} else {
_copy = false;
}
- cursor = _editor->selector_cursor;
+ cursor = _editor->cursors()->selector;
Drag::start_grab (event, cursor);
break;
if (_editor->clicked_axisview) {
_editor->clicked_axisview->order_selection_trims (_item, true);
}
- Drag::start_grab (event, _editor->left_side_trim_cursor);
- start = _editor->selection->time[_editor->clicked_selection].start;
- _pointer_frame_offset = grab_frame() - start;
+ Drag::start_grab (event, _editor->cursors()->left_side_trim);
break;
case SelectionEndTrim:
if (_editor->clicked_axisview) {
_editor->clicked_axisview->order_selection_trims (_item, false);
}
- Drag::start_grab (event, _editor->right_side_trim_cursor);
- end = _editor->selection->time[_editor->clicked_selection].end;
- _pointer_frame_offset = grab_frame() - end;
+ Drag::start_grab (event, _editor->cursors()->right_side_trim);
break;
case SelectionMove:
- start = _editor->selection->time[_editor->clicked_selection].start;
Drag::start_grab (event, cursor);
- _pointer_frame_offset = grab_frame() - start;
break;
}
if (_operation == SelectionMove) {
- _editor->show_verbose_time_cursor (start, 10);
+ show_verbose_cursor_time (_editor->selection->time[_editor->clicked_selection].start);
} else {
- _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
+ show_verbose_cursor_time (adjusted_current_frame (event));
}
_original_pointer_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ()).first->order ();
}
+void
+SelectionDrag::setup_pointer_frame_offset ()
+{
+ switch (_operation) {
+ case CreateSelection:
+ _pointer_frame_offset = 0;
+ break;
+
+ case SelectionStartTrim:
+ case SelectionMove:
+ _pointer_frame_offset = raw_grab_frame() - _editor->selection->time[_editor->clicked_selection].start;
+ break;
+
+ case SelectionEndTrim:
+ _pointer_frame_offset = raw_grab_frame() - _editor->selection->time[_editor->clicked_selection].end;
+ break;
+ }
+}
+
void
SelectionDrag::motion (GdkEvent* event, bool first_move)
{
- nframes64_t start = 0;
- nframes64_t end = 0;
- nframes64_t length;
+ framepos_t start = 0;
+ framepos_t end = 0;
+ framecnt_t length;
pair<TimeAxisView*, int> 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 */
switch (_operation) {
case CreateSelection:
{
- nframes64_t grab = grab_frame ();
+ framepos_t grab = grab_frame ();
if (first_move) {
_editor->snap_to (grab);
if (_copy) {
/* adding to the selection */
- _editor->selection->add (_editor->clicked_axisview);
+ _editor->set_selected_track_as_side_effect (Selection::Add);
+ //_editor->selection->add (_editor->clicked_axisview);
_editor->clicked_selection = _editor->selection->add (start, end);
_copy = false;
} else {
/* new selection */
if (_editor->clicked_axisview && !_editor->selection->selected (_editor->clicked_axisview)) {
- _editor->selection->set (_editor->clicked_axisview);
+ //_editor->selection->set (_editor->clicked_axisview);
+ _editor->set_selected_track_as_side_effect (Selection::Set);
}
-
+
_editor->clicked_selection = _editor->selection->set (start, end);
}
}
/* select the track that we're in */
if (find (_added_time_axes.begin(), _added_time_axes.end(), pending_time_axis.first) == _added_time_axes.end()) {
+ // _editor->set_selected_track_as_side_effect (Selection::Add);
_editor->selection->add (pending_time_axis.first);
_added_time_axes.push_back (pending_time_axis.first);
}
/* deselect any tracks that this drag no longer includes, being careful to only deselect
tracks that we selected in the first place.
*/
-
+
int min_order = min (_original_pointer_time_axis, pending_time_axis.first->order());
int max_order = max (_original_pointer_time_axis, pending_time_axis.first->order());
list<TimeAxisView*>::iterator tmp = i;
++tmp;
-
+
if ((*i)->order() < min_order || (*i)->order() > max_order) {
_editor->selection->remove (*i);
_added_time_axes.remove (*i);
}
if (_operation == SelectionMove) {
- _editor->show_verbose_time_cursor(start, 10);
+ show_verbose_cursor_time(start);
} else {
- _editor->show_verbose_time_cursor(pending_position, 10);
+ show_verbose_cursor_time(pending_position);
}
}
if (_editor->clicked_axisview && !_editor->selection->selected (_editor->clicked_axisview)) {
_editor->selection->set (_editor->clicked_axisview);
}
-
+
if (s && s->get_play_range () && s->transport_rolling()) {
s->request_stop (false, false);
}
}
void
-SelectionDrag::aborted ()
+SelectionDrag::aborted (bool)
{
/* XXX: TODO */
}
_operation (o),
_copy (false)
{
- _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0,
- physical_screen_height (_editor->get_window()));
+ DEBUG_TRACE (DEBUG::Drags, "New RangeMarkerBarDrag\n");
+
+ _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0,
+ physical_screen_height (_editor->get_window()));
_drag_rect->hide ();
_drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
} else {
_copy = false;
}
- cursor = _editor->selector_cursor;
+ cursor = _editor->cursors()->selector;
break;
}
Drag::start_grab (event, cursor);
- _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
+ show_verbose_cursor_time (adjusted_current_frame (event));
}
void
RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
{
- nframes64_t start = 0;
- nframes64_t end = 0;
+ framepos_t start = 0;
+ framepos_t end = 0;
ArdourCanvas::SimpleRect *crect;
switch (_operation) {
break;
}
- nframes64_t const pf = adjusted_current_frame (event);
+ framepos_t const pf = adjusted_current_frame (event);
if (_operation == CreateRangeMarker || _operation == CreateTransportMarker || _operation == CreateCDMarker) {
- nframes64_t grab = grab_frame ();
+ framepos_t grab = grab_frame ();
_editor->snap_to (grab);
-
+
if (pf < grab_frame()) {
start = pf;
end = grab;
update_item (_editor->temp_location);
}
- _editor->show_verbose_time_cursor (pf, 10);
+ show_verbose_cursor_time (pf);
}
newloc = new Location (
*_editor->session(), _editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags
);
-
+
_editor->session()->locations()->add (newloc, true);
XMLNode &after = _editor->session()->locations()->get_state();
_editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
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 ();
}
}
void
-RangeMarkerBarDrag::aborted ()
+RangeMarkerBarDrag::aborted (bool)
{
/* XXX: TODO */
}
_drag_rect->property_x2() = x2;
}
+MouseZoomDrag::MouseZoomDrag (Editor* e, ArdourCanvas::Item* i)
+ : Drag (e, i)
+ , _zoom_out (false)
+{
+ DEBUG_TRACE (DEBUG::Drags, "New MouseZoomDrag\n");
+}
+
void
MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
{
- Drag::start_grab (event, _editor->zoom_cursor);
- _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
+ if (Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
+ Drag::start_grab (event, _editor->cursors()->zoom_out);
+ _zoom_out = true;
+ } else {
+ Drag::start_grab (event, _editor->cursors()->zoom_in);
+ _zoom_out = false;
+ }
+
+ show_verbose_cursor_time (adjusted_current_frame (event));
}
void
MouseZoomDrag::motion (GdkEvent* event, bool first_move)
{
- nframes64_t start;
- nframes64_t end;
+ framepos_t start;
+ framepos_t end;
- nframes64_t const pf = adjusted_current_frame (event);
+ framepos_t const pf = adjusted_current_frame (event);
- nframes64_t grab = grab_frame ();
+ framepos_t grab = grab_frame ();
_editor->snap_to_with_modifier (grab, event);
/* base start and end on initial click position */
_editor->reposition_zoom_rect(start, end);
- _editor->show_verbose_time_cursor (pf, 10);
+ show_verbose_cursor_time (pf);
}
}
_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 ();
}
, _cumulative_dx (0)
, _cumulative_dy (0)
{
+ DEBUG_TRACE (DEBUG::Drags, "New NoteDrag\n");
+
_primary = dynamic_cast<CanvasNoteEvent*> (_item);
_region = &_primary->region_view ();
_note_height = _region->midi_stream_view()->note_height ();
frameoffset_t const dx = _editor->unit_to_frame (_drags->current_pointer_x() - grab_x());
/* primary note time */
- frameoffset_t const n = _region->beats_to_frames (_primary->note()->time ());
-
- /* new time of the primary note relative to the region position */
- frameoffset_t const st = n + dx;
+ frameoffset_t const n = _region->source_beats_to_absolute_frames (_primary->note()->time ());
+
+ /* new time of the primary note in session frames */
+ frameoffset_t st = n + dx;
+
+ framepos_t const rp = _region->region()->position ();
+
+ /* prevent the note being dragged earlier than the region's position */
+ st = max (st, rp);
/* snap and return corresponding delta */
- return _region->snap_frame_to_frame (st) - n;
+ return _region->snap_frame_to_frame (st - rp) + rp - n;
}
-/** @return Current total drag y change in notes */
+/** @return Current total drag y change in note number */
int8_t
NoteDrag::total_dy () const
{
- /* this is `backwards' to make increasing note number go in the right direction */
- double const dy = _drags->current_pointer_y() - grab_y();
-
- /* dy in notes */
- int8_t ndy = 0;
-
- if (abs (dy) >= _note_height) {
- if (dy > 0) {
- ndy = (int8_t) ceil (dy / _note_height / 2.0);
- } else {
- ndy = (int8_t) floor (dy / _note_height / 2.0);
- }
- }
-
- return ndy;
+ return ((int8_t) (grab_y() / _note_height)) - ((int8_t) (_drags->current_pointer_y() / _note_height));
}
-
void
NoteDrag::motion (GdkEvent *, bool)
/* Now work out what we have to do to the note canvas items to set this new drag delta */
double const tdx = _editor->frame_to_unit (dx) - _cumulative_dx;
- double const tdy = dy * _note_height - _cumulative_dy;
+ double const tdy = -dy * _note_height - _cumulative_dy;
if (tdx || tdy) {
- _region->move_selection (tdx, tdy);
_cumulative_dx += tdx;
_cumulative_dy += tdy;
- char buf[12];
- snprintf (buf, sizeof (buf), "%s (%d)", Evoral::midi_note_name (_primary->note()->note() + dy).c_str(),
- (int) floor (_primary->note()->note() + dy));
+ int8_t note_delta = total_dy();
+
+ _region->move_selection (tdx, tdy, note_delta);
+
+ /* the new note value may be the same as the old one, but we
+ * don't know what that means because the selection may have
+ * involved more than one note and we might be doing something
+ * odd with them. so show the note value anyway, always.
+ */
+
+ char buf[12];
+ uint8_t new_note = min (max (_primary->note()->note() + note_delta, 0), 127);
- _editor->show_verbose_canvas_cursor_with (buf);
- }
+ snprintf (buf, sizeof (buf), "%s (%d)", Evoral::midi_note_name (new_note).c_str(),
+ (int) floor (new_note));
+
+ show_verbose_cursor_text (buf);
+ }
}
void
}
}
} 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<AudioRange> const & r)
- : Drag (e, i)
+AutomationRangeDrag::AutomationRangeDrag (Editor* editor, ArdourCanvas::Item* item, list<AudioRange> const & r)
+ : Drag (editor, item)
, _ranges (r)
, _nothing_to_drag (false)
{
+ DEBUG_TRACE (DEBUG::Drags, "New AutomationRangeDrag\n");
+
_atav = reinterpret_cast<AutomationTimeAxisView*> (_item->get_data ("trackview"));
assert (_atav);
- _line = _atav->line ();
+ /* get all lines in the automation view */
+ list<boost::shared_ptr<AutomationLine> > lines = _atav->lines ();
+
+ /* find those that overlap the ranges being dragged */
+ list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin ();
+ while (i != lines.end ()) {
+ list<boost::shared_ptr<AutomationLine> >::iterator j = i;
+ ++j;
+
+ pair<framepos_t, framepos_t> const r = (*i)->get_point_x_range ();
+
+ /* check this range against all the AudioRanges that we are using */
+ list<AudioRange>::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
{
Drag::start_grab (event, cursor);
- list<ControlPoint*> points;
+ /* Get line states before we start changing things */
+ for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) {
+ i->state = &i->line->get_state ();
+ }
- 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<Line>::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<AutomationList> the_list = _line->the_list ();
- for (list<AudioRange>::const_iterator j = _ranges.begin(); j != _ranges.end(); ++j) {
+ for (list<AudioRange>::const_iterator i = _ranges.begin(); i != _ranges.end(); ++i) {
- /* fade into and out of the region that we're dragging;
- 64 samples length plucked out of thin air.
- */
- nframes64_t const h = (j->start + j->end) / 2;
- nframes64_t a = j->start + 64;
- if (a > h) {
- a = h;
- }
- nframes64_t b = j->end - 64;
- if (b < h) {
- b = h;
+ framecnt_t const half = (i->start + i->end) / 2;
+
+ /* find the line that this audio range starts in */
+ list<Line>::iterator j = _lines.begin();
+ while (j != _lines.end() && (j->range.first > i->start || j->range.second < i->start)) {
+ ++j;
}
-
- the_list->add (j->start, the_list->eval (j->start));
- _line->add_always_in_view (j->start);
- the_list->add (a, the_list->eval (a));
- _line->add_always_in_view (a);
- the_list->add (b, the_list->eval (b));
- _line->add_always_in_view (b);
- the_list->add (j->end, the_list->eval (j->end));
- _line->add_always_in_view (j->end);
- }
- uint32_t const N = _line->npoints ();
- for (uint32_t i = 0; i < N; ++i) {
+ if (j != _lines.end()) {
+ boost::shared_ptr<AutomationList> the_list = j->line->the_list ();
+
+ /* j is the line that this audio range starts in; fade into it;
+ 64 samples length plucked out of thin air.
+ */
+
+ framepos_t a = i->start + 64;
+ if (a > half) {
+ a = half;
+ }
+
+ double const p = j->line->time_converter().from (i->start - j->line->time_converter().origin_b ());
+ double const q = j->line->time_converter().from (a - j->line->time_converter().origin_b ());
+
+ the_list->add (p, the_list->eval (p));
+ j->line->add_always_in_view (p);
+ the_list->add (q, the_list->eval (q));
+ j->line->add_always_in_view (q);
+ }
- ControlPoint* p = _line->nth (i);
+ /* same thing for the end */
- list<AudioRange>::const_iterator j = _ranges.begin ();
- while (j != _ranges.end() && (j->start >= (*p->model())->when || j->end <= (*p->model())->when)) {
+ j = _lines.begin();
+ while (j != _lines.end() && (j->range.first > i->end || j->range.second < i->end)) {
++j;
}
- if (j != _ranges.end()) {
- points.push_back (p);
+ if (j != _lines.end()) {
+ boost::shared_ptr<AutomationList> the_list = j->line->the_list ();
+
+ /* j is the line that this audio range starts in; fade out of it;
+ 64 samples length plucked out of thin air.
+ */
+
+ framepos_t b = i->end - 64;
+ if (b < half) {
+ b = half;
+ }
+
+ double const p = j->line->time_converter().from (b - j->line->time_converter().origin_b ());
+ double const q = j->line->time_converter().from (i->end - j->line->time_converter().origin_b ());
+
+ the_list->add (p, the_list->eval (p));
+ j->line->add_always_in_view (p);
+ the_list->add (q, the_list->eval (q));
+ j->line->add_always_in_view (q);
}
}
- }
- if (points.empty()) {
_nothing_to_drag = true;
+
+ /* Find all the points that should be dragged and put them in the relevant
+ points lists in the Line structs.
+ */
+
+ for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) {
+
+ uint32_t const N = i->line->npoints ();
+ for (uint32_t j = 0; j < N; ++j) {
+
+ /* here's a control point on this line */
+ ControlPoint* p = i->line->nth (j);
+ double const w = i->line->time_converter().to ((*p->model())->when) + i->line->time_converter().origin_b ();
+
+ /* see if it's inside a range */
+ list<AudioRange>::const_iterator k = _ranges.begin ();
+ while (k != _ranges.end() && (k->start >= w || k->end <= w)) {
+ ++k;
+ }
+
+ if (k != _ranges.end()) {
+ /* dragging this point */
+ _nothing_to_drag = false;
+ i->points.push_back (p);
+ }
+ }
+ }
+ }
+
+ if (_nothing_to_drag) {
return;
}
- _line->start_drag_multiple (points, 1 - (_drags->current_pointer_y() / _line->height ()), state);
+ for (list<Line>::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<Line>::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
if (_nothing_to_drag) {
return;
}
-
+
motion (event, false);
- _line->end_drag ();
- _line->clear_always_in_view ();
+ for (list<Line>::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<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) {
+ i->line->clear_always_in_view ();
+ i->line->reset ();
+ }
}
-DraggingView::DraggingView (RegionView* v)
+DraggingView::DraggingView (RegionView* v, RegionDrag* parent)
: view (v)
{
+ time_axis_view = parent->find_time_axis_view (&v->get_time_axis_view ());
+ layer = v->region()->layer ();
initial_y = v->get_canvas_group()->property_y ();
initial_playlist = v->region()->playlist ();
+ initial_position = v->region()->position ();
+ initial_end = v->region()->position () + v->region()->length ();
+}
+
+PatchChangeDrag::PatchChangeDrag (Editor* e, CanvasPatchChange* i, MidiRegionView* r)
+ : Drag (e, i)
+ , _region_view (r)
+ , _patch_change (i)
+ , _cumulative_dx (0)
+{
+ DEBUG_TRACE (DEBUG::Drags, "New PatchChangeDrag\n");
+}
+
+void
+PatchChangeDrag::motion (GdkEvent* ev, bool)
+{
+ framepos_t f = adjusted_current_frame (ev);
+ boost::shared_ptr<Region> 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<Region> r (_region_view->region ());
+
+ framepos_t f = adjusted_current_frame (ev);
+ f = max (f, r->position ());
+ f = min (f, r->last_frame ());
+
+ _region_view->move_patch_change (
+ *_patch_change,
+ _region_view->region_frames_to_region_beats (f - r->position() - r->start())
+ );
+}
+
+void
+PatchChangeDrag::aborted (bool)
+{
+ _patch_change->move (-_cumulative_dx, 0);
+}
+
+void
+PatchChangeDrag::setup_pointer_frame_offset ()
+{
+ boost::shared_ptr<Region> region = _region_view->region ();
+ _pointer_frame_offset = raw_grab_frame() - _region_view->source_beats_to_absolute_frames (_patch_change->patch()->time());
}
+