#include "ardour/session.h"
#include "ardour/dB.h"
#include "ardour/region_factory.h"
+#include "ardour/operations.h"
+
#include "editor.h"
#include "i18n.h"
#include "keyboard.h"
#include "debug.h"
#include "editor_cursors.h"
#include "mouse_cursors.h"
+#include "verbose_cursor.h"
using namespace std;
using namespace ARDOUR;
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::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)
finished (event, _move_threshold_passed);
- _editor->hide_verbose_canvas_cursor();
+ _editor->verbose_cursor()->hide ();
return _move_threshold_passed;
}
if (!from_autoscroll && !_move_threshold_passed) {
- bool const xp = (::llabs (_drags->current_pointer_frame () - _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 ();
+ _editor->verbose_cursor()->hide ();
+}
+
+void
+Drag::show_verbose_cursor_time (framepos_t frame)
+{
+ _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
+ );
+
+ _editor->verbose_cursor()->show ();
+}
+
+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
+Drag::show_verbose_cursor_text (string const & text)
+{
+ _editor->verbose_cursor()->show ();
+
+ _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
+ );
+}
+
+
struct EditorOrderTimeAxisViewSorter {
bool operator() (TimeAxisView* a, TimeAxisView* b) {
RouteTimeAxisView* ra = dynamic_cast<RouteTimeAxisView*> (a);
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
if (!(*i)->hidden()) {
-
+
_time_axis_views.push_back (*i);
TimeAxisView::Children children_list = (*i)->get_child_list ();
/* the list of views can be empty at this point if this is a region list-insert drag
*/
-
+
for (list<RegionView*>::const_iterator i = v.begin(); i != v.end(); ++i) {
_views.push_back (DraggingView (*i, this));
}
-
+
RegionView::RegionViewGoingAway.connect (death_connection, invalidator (*this), ui_bind (&RegionDrag::region_going_away, this, _1), gui_context());
}
if (i == N) {
return -1;
}
-
+
return i;
}
{
Drag::start_grab (event, cursor);
- _editor->show_verbose_time_cursor (_last_frame_position, 10);
+ show_verbose_cursor_time (_last_frame_position);
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);
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 != _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 */
/* not a track, or the wrong type */
return false;
}
-
+
int const l = i->layer + delta_layer;
if (delta_track == 0 && (l < 0 || l >= int (to->view()->layers()))) {
/* Off the top or bottom layer; note that we only refuse if the track hasn't changed.
/* Bail early if we're not over a track */
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv.first);
if (!rtv || !rtv->is_track()) {
- _editor->hide_verbose_canvas_cursor ();
+ _editor->verbose_cursor()->hide ();
return;
}
/* 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 ();
-
+
// 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
region selection above all time axis views.
reparenting means we have to move the rv 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->fake_set_opaque (true);
}
} /* foreach region */
_total_x_delta += x_delta;
-
+
if (first_move) {
_editor->cursor_group->raise_to_top();
}
if (x_delta != 0 && !_brushing) {
- _editor->show_verbose_time_cursor (_last_frame_position, 10);
+ show_verbose_cursor_time (_last_frame_position);
}
_last_pointer_time_axis_view += delta_time_axis_view;
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, true);
- region_copy->set_position (original->position(), this);
-
+ region_copy->set_position (original->position());
+
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
} else {
continue;
}
-
+
nrv->get_canvas_group()->show ();
new_regionviews.push_back (DraggingView (nrv, this));
-
+
/* swap _primary to the copy */
-
+
if (rv == _primary) {
_primary = nrv;
}
-
+
/* ..and deselect the one we copied */
-
+
rv->set_selected (false);
}
-
+
if (!new_regionviews.empty()) {
-
+
/* 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
framecnt_t const drag_delta = _primary->region()->position() - _last_frame_position;
_editor->update_canvas_now ();
-
+
if (_copy) {
-
+
finished_copy (
changed_position,
changed_tracks,
drag_delta
);
-
+
} else {
-
+
finished_no_copy (
changed_position,
changed_tracks,
drag_delta
);
-
+
}
}
}
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 */
RegionView* new_view = insert_region_into_playlist (
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) {
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(); ) {
remove_region_from_playlist (rv->region(), i->initial_playlist, modified_playlists);
} else {
-
+
rv->region()->clear_changes ();
/*
/* 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);
/* 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, (void*) this);
+ 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;
} else {
}
}
- /* 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) {
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_changes () is only called once per playlist.
+ * that clear_changes () is only called once per playlist.
* @return New RegionView, or 0 if no insert was performed.
*/
RegionView *
_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_changes ();
for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
StatefulDiffCommand* c = new StatefulDiffCommand (*i);
if (!c->empty()) {
- _editor->session()->add_command (new StatefulDiffCommand (*i));
+ _editor->session()->add_command (c);
} else {
delete c;
}
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 ();
}
-
+
+/** @param b true to brush, otherwise false.
+ * @param c true to make copies of the regions being moved, otherwise false.
+ */
RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
: RegionMotionDrag (e, i, p, v, b),
_copy (c)
{
DEBUG_TRACE (DEBUG::Drags, "New RegionMoveDrag\n");
-
+
double speed = 1;
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&_primary->get_time_axis_view ());
if (rtv && rtv->is_track()) {
: 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)));
boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
- _editor->begin_reversible_command (_("insert region"));
+ _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));
}
void
-RegionInsertDrag::aborted ()
+RegionInsertDrag::aborted (bool)
{
delete _primary;
_primary = 0;
pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (_drags->current_pointer_y ());
RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
- layer_t 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.
/* To make sure we hide the verbose canvas cursor when the mouse is
not held over and audiotrack.
*/
- _editor->hide_verbose_canvas_cursor ();
+ _editor->verbose_cursor()->hide ();
return;
}
}
void
-RegionSpliceDrag::aborted ()
+RegionSpliceDrag::aborted (bool)
{
/* XXX: TODO */
}
_view (dynamic_cast<MidiTimeAxisView*> (v))
{
DEBUG_TRACE (DEBUG::Drags, "New RegionCreateDrag\n");
-
+
assert (_view);
}
{
if (first_move) {
add_region();
+ _view->playlist()->freeze ();
} else {
if (_region) {
framepos_t const f = adjusted_current_frame (event);
if (f < grab_frame()) {
- _region->set_position (f, this);
+ _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);
}
}
}
{
if (!movement_occurred) {
add_region ();
+ } else {
+ _view->playlist()->thaw ();
}
if (_region) {
}
void
-RegionCreateDrag::aborted ()
+RegionCreateDrag::aborted (bool)
{
+ if (_region) {
+ _view->playlist()->thaw ();
+ }
+
/* XXX */
}
}
void
-NoteResizeDrag::aborted ()
+NoteResizeDrag::aborted (bool)
{
/* XXX: TODO */
}
}
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");
}
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;
}
}
_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->enable_display (false);
- rv->region()->clear_changes ();
+ rv->region()->playlist()->clear_owned_changes ();
AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (rv);
}
framecnt_t frame_delta = 0;
-
+
bool left_direction = false;
if (last_pointer_frame() > adjusted_current_frame(event)) {
left_direction = true;
switch (_operation) {
case StartTrim:
- _editor->show_verbose_time_cursor ((framepos_t) (rv->region()->position() / speed), 10);
+ show_verbose_cursor_time ((framepos_t) (rv->region()->position() / speed));
break;
case EndTrim:
- _editor->show_verbose_time_cursor ((framepos_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 (adjusted_current_frame (event), 10);
+ show_verbose_cursor_time (adjusted_current_frame (event));
break;
}
}
i->view->trim_front_ending ();
}
}
-
+
if (!_editor->selection->selected (_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) {
- i->view->thaw_after_trim ();
+ 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);
}
}
}
}
_editor->motion_frozen_playlists.clear ();
- if (_have_transaction) {
- _editor->commit_reversible_command();
- }
+ _editor->commit_reversible_command();
} else {
/* no mouse movement */
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 ();
}
_copy (c)
{
DEBUG_TRACE (DEBUG::Drags, "New MeterMarkerDrag\n");
-
+
_marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
assert (_marker);
}
MeterMarker* new_marker = new MeterMarker (
*_editor,
*_editor->meter_group,
- *_editor->cursor_group,
ARDOUR_UI::config()->canvasvar_MeterMarker.get(),
name,
*new MeterSection (_marker->meter())
Drag::start_grab (event, cursor);
- _editor->show_verbose_time_cursor (adjusted_current_frame(event), 10);
+ show_verbose_cursor_time (adjusted_current_frame(event));
}
void
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
}
void
-MeterMarkerDrag::aborted ()
+MeterMarkerDrag::aborted (bool)
{
_marker->set_position (_marker->meter().frame ());
}
_copy (c)
{
DEBUG_TRACE (DEBUG::Drags, "New TempoMarkerDrag\n");
-
+
_marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
assert (_marker);
}
TempoMarker* new_marker = new TempoMarker (
*_editor,
*_editor->tempo_group,
- *_editor->cursor_group,
ARDOUR_UI::config()->canvasvar_TempoMarker.get(),
name,
*new TempoSection (_marker->tempo())
Drag::start_grab (event, cursor);
- _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)
{
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
}
void
-TempoMarkerDrag::aborted ()
+TempoMarkerDrag::aborted (bool)
{
_marker->set_position (_marker->tempo().frame());
}
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_full_time_code (f);
}
- _editor->show_verbose_time_cursor (t, 10);
+ show_verbose_cursor_time (t);
_editor->UpdateAllTransportClocks (t);
}
{
Drag::start_grab (event, c);
+ _grab_zoom = _editor->frames_per_unit;
+
framepos_t where = _editor->event_frame (event, 0, 0);
_editor->snap_to_with_modifier (where, event);
_editor->_dragging_playhead = true;
-
+
Session* s = _editor->session ();
-
+
if (s) {
if (_was_rolling && _stop) {
s->request_stop ();
}
-
+
if (s->is_auditioning()) {
s->cancel_audition ();
}
-
+
s->request_suspend_timecode_transmission ();
while (!s->timecode_transmission_suspended ()) {
/* twiddle our thumbs */
}
}
-
+
fake_locate (where);
}
void
CursorDrag::motion (GdkEvent* event, bool)
{
- framepos_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 */
+
+ /* 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;
+
+ /* current dy */
+ double dy = _drags->current_pointer_y() - grab_y();
+
+ 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);
+ }
}
- fake_locate (adjusted_frame);
-
+ 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
+ }
}
void
}
void
-CursorDrag::aborted ()
+CursorDrag::aborted (bool)
{
if (_editor->_dragging_playhead) {
_editor->session()->request_resume_timecode_transmission ();
_editor->_dragging_playhead = false;
}
-
+
_editor->playhead_cursor->set_position (adjusted_frame (grab_frame (), 0, false));
}
AudioRegionView* arv = dynamic_cast<AudioRegionView*> (_primary);
boost::shared_ptr<AudioRegion> const r = arv->audio_region ();
- _editor->show_verbose_duration_cursor (r->position(), r->position() + r->fade_in()->back()->when, 10);
-
+ show_verbose_cursor_duration (r->position(), r->position() + r->fade_in()->back()->when, 32);
+
arv->show_fade_line((framepos_t) r->fade_in()->back()->when);
}
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
}
void
-FadeInDrag::aborted ()
+FadeInDrag::aborted (bool)
{
for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
AudioRegionView* arv = dynamic_cast<AudioRegionView*> (_primary);
boost::shared_ptr<AudioRegion> r = arv->audio_region ();
- _editor->show_verbose_duration_cursor (r->last_frame() - r->fade_out()->back()->when, r->last_frame(), 10);
-
+ 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);
}
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)
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
}
void
-FadeOutDrag::aborted ()
+FadeOutDrag::aborted (bool)
{
for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
: 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 ()
// _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);
framepos_t next = newframe;
- if (newframe == last_pointer_frame()) {
- return;
- }
-
if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
move_both = true;
}
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)
{
- 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);
}
_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 ();
}
uint32_t before;
uint32_t after;
-
+
if (!_line->control_points_adjacent (frame_within_region, before, after)) {
/* no adjacent points */
return;
_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
}
void
-LineDrag::aborted ()
+LineDrag::aborted (bool)
{
_line->reset ();
}
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());
}
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*, 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::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
_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 ();
}
{
Drag::start_grab (event, cursor);
- _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
+ show_verbose_cursor_time (adjusted_current_frame (event));
}
void
rv->get_time_axis_view().show_timestretch (rv->region()->position(), pf);
}
- _editor->show_verbose_time_cursor (pf, 10);
+ show_verbose_cursor_time (pf);
}
void
}
#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 ();
}
}
void
-ScrubDrag::aborted ()
+ScrubDrag::aborted (bool)
{
/* XXX: TODO */
}
}
if (_operation == SelectionMove) {
- _editor->show_verbose_time_cursor (_editor->selection->time[_editor->clicked_selection].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 ();
if (pending_time_axis.first == 0) {
return;
}
-
+
framepos_t const pending_position = adjusted_current_frame (event);
/* only alter selection if things have changed */
//_editor->selection->set (_editor->clicked_axisview);
_editor->set_selected_track_as_side_effect (Selection::Set);
}
-
+
_editor->clicked_selection = _editor->selection->set (start, end);
}
}
/* 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 */
}
_copy (false)
{
DEBUG_TRACE (DEBUG::Drags, "New RangeMarkerBarDrag\n");
-
- _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0,
+
+ _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::start_grab (event, cursor);
- _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
+ show_verbose_cursor_time (adjusted_current_frame (event));
}
void
if (_operation == CreateRangeMarker || _operation == CreateTransportMarker || _operation == CreateCDMarker) {
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));
}
void
-RangeMarkerBarDrag::aborted ()
+RangeMarkerBarDrag::aborted (bool)
{
/* XXX: TODO */
}
Drag::start_grab (event, _editor->cursors()->zoom_in);
_zoom_out = false;
}
-
- _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
+
+ show_verbose_cursor_time (adjusted_current_frame (event));
}
void
_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 (_zoom_out, 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 ();
}
/* 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 st = n + dx;
+
+ /* prevent the note being dragged earlier than the region's position */
+ if (st < 0) {
+ st = 0;
+ }
/* snap and return corresponding delta */
return _region->snap_frame_to_frame (st) - n;
}
/* more positive value = higher pitch and higher y-axis position on track,
- which is the inverse of the X-centric geometric universe
+ which is the inverse of the X-centric geometric universe
*/
- return -ndy;
-}
+ return -ndy;
+}
void
NoteDrag::motion (GdkEvent *, bool)
char buf[12];
snprintf (buf, sizeof (buf), "%s (%d)", Evoral::midi_note_name (_primary->note()->note() + note_delta).c_str(),
(int) floor (_primary->note()->note() + note_delta));
-
- _editor->show_verbose_canvas_cursor_with (buf);
+
+ show_verbose_cursor_text (buf);
}
}
}
void
-NoteDrag::aborted ()
+NoteDrag::aborted (bool)
{
/* XXX: TODO */
}
, _nothing_to_drag (false)
{
DEBUG_TRACE (DEBUG::Drags, "New AutomationRangeDrag\n");
-
+
_atav = reinterpret_cast<AutomationTimeAxisView*> (_item->get_data ("trackview"));
assert (_atav);
i->points.push_back (i->line->nth (j));
}
}
-
+
} else {
for (list<AudioRange>::const_iterator i = _ranges.begin(); i != _ranges.end(); ++i) {
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)) {
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.
*/
}
/* same thing for the end */
-
+
j = _lines.begin();
while (j != _lines.end() && (j->range.first > i->end || j->range.second < i->end)) {
++j;
if (j != _lines.end()) {
boost::shared_ptr<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));
if (_nothing_to_drag) {
return;
}
-
+
motion (event, false);
for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) {
i->line->end_drag ();
}
void
-AutomationRangeDrag::aborted ()
+AutomationRangeDrag::aborted (bool)
{
for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) {
i->line->clear_always_in_view ();
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);
}
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->frames_to_beats (f - r->position() - r->start())
}
void
-PatchChangeDrag::aborted ()
+PatchChangeDrag::aborted (bool)
{
_patch_change->move (-_cumulative_dx, 0);
}