*/
+#define __STDC_LIMIT_MACROS 1
+#include <stdint.h>
#include "pbd/memento_command.h"
#include "pbd/basename.h"
-#include "ardour/diskstream.h"
+#include "pbd/stateful_diff_command.h"
#include "ardour/session.h"
#include "ardour/dB.h"
#include "ardour/region_factory.h"
-#include "ardour/midi_diskstream.h"
#include "editor.h"
#include "i18n.h"
#include "keyboard.h"
double const ControlPointDrag::_zero_gain_fraction = gain_to_slider_position (dB_to_coefficient (0.0));
+DragManager::DragManager (Editor* e)
+ : _editor (e)
+ , _ending (false)
+ , _current_pointer_frame (0)
+{
+
+}
+
+DragManager::~DragManager ()
+{
+ abort ();
+}
+
+void
+DragManager::abort ()
+{
+ for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
+ (*i)->end_grab (0);
+ delete *i;
+ }
+
+ _drags.clear ();
+}
+
+void
+DragManager::break_drag ()
+{
+ _ending = true;
+
+ for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
+ (*i)->break_drag ();
+ delete *i;
+ }
+
+ _drags.clear ();
+
+ _ending = false;
+}
+
+void
+DragManager::add (Drag* d)
+{
+ d->set_manager (this);
+ _drags.push_back (d);
+}
+
+void
+DragManager::set (Drag* d, GdkEvent* e, Gdk::Cursor* c)
+{
+ assert (_drags.empty ());
+ d->set_manager (this);
+ _drags.push_back (d);
+ start_grab (e);
+}
+
+void
+DragManager::start_grab (GdkEvent* e)
+{
+ _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);
+ }
+}
+
+bool
+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);
+ if (t) {
+ r = true;
+ }
+ delete *i;
+ }
+
+ _drags.clear ();
+
+ _ending = false;
+
+ return r;
+}
+
+bool
+DragManager::motion_handler (GdkEvent* e, bool from_autoscroll)
+{
+ bool r = false;
+
+ _current_pointer_frame = _editor->event_frame (e, &_current_pointer_x, &_current_pointer_y);
+
+ for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
+ bool const t = (*i)->motion_handler (e, from_autoscroll);
+ if (t) {
+ r = true;
+ }
+
+ }
+
+ return r;
+}
+
+bool
+DragManager::have_item (ArdourCanvas::Item* i) const
+{
+ list<Drag*>::const_iterator j = _drags.begin ();
+ while (j != _drags.end() && (*j)->item () != i) {
+ ++j;
+ }
+
+ return j != _drags.end ();
+}
+
Drag::Drag (Editor* e, ArdourCanvas::Item* i)
: _editor (e)
, _item (i)
, _pointer_frame_offset (0)
- , _have_transaction (false)
, _move_threshold_passed (false)
, _grab_frame (0)
, _last_pointer_frame (0)
- , _current_pointer_frame (0)
{
}
_grab_frame = _editor->event_frame (event, &_grab_x, &_grab_y);
_grab_frame = adjusted_frame (_grab_frame, event);
_last_pointer_frame = _grab_frame;
- _current_pointer_frame = _grab_frame;
- _current_pointer_x = _grab_x;
- _current_pointer_y = _grab_y;
- _last_pointer_x = _current_pointer_x;
- _last_pointer_y = _current_pointer_y;
-
- _original_x = 0;
- _original_y = 0;
- _item->i2w (_original_x, _original_y);
+ _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,
bool
Drag::end_grab (GdkEvent* event)
{
- _ending = true;
-
_editor->stop_canvas_autoscroll ();
_item->ungrab (event ? event->button.time : 0);
- _last_pointer_x = _current_pointer_x;
- _last_pointer_y = _current_pointer_y;
finished (event, _move_threshold_passed);
_editor->hide_verbose_canvas_cursor();
- _ending = false;
-
return _move_threshold_passed;
}
nframes64_t
Drag::adjusted_current_frame (GdkEvent const * event, bool snap) const
{
- return adjusted_frame (_current_pointer_frame, event, snap);
+ return adjusted_frame (_drags->current_pointer_frame (), event, snap);
}
bool
Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
{
- _last_pointer_x = _current_pointer_x;
- _last_pointer_y = _current_pointer_y;
- _last_pointer_frame = adjusted_current_frame (event);
- _current_pointer_frame = _editor->event_frame (event, &_current_pointer_x, &_current_pointer_y);
+ /* 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 ()) ) {
+ return false;
+ }
pair<nframes64_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 yp = (::fabs ((_current_pointer_y - _grab_y)) >= threshold.second);
+ bool const yp = (::fabs ((_drags->current_pointer_y () - _grab_y)) >= threshold.second);
_move_threshold_passed = ((xp && x_movement_matters()) || (yp && y_movement_matters()));
}
}
motion (event, _move_threshold_passed != old_move_threshold_passed);
+
+ _last_pointer_x = _drags->current_pointer_x ();
+ _last_pointer_y = _drags->current_pointer_y ();
+ _last_pointer_frame = adjusted_current_frame (event);
+
return true;
}
}
return false;
}
-
void
Drag::break_drag ()
{
- _editor->stop_canvas_autoscroll ();
- _editor->hide_verbose_canvas_cursor ();
-
if (_item) {
_item->ungrab (0);
+ }
- /* put it back where it came from */
+ aborted ();
- double cxw, cyw;
- cxw = 0;
- cyw = 0;
- _item->i2w (cxw, cyw);
- _item->move (_original_x - cxw, _original_y - cyw);
- }
+ _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),
- _views (v)
+ _primary (p)
{
- RegionView::RegionViewGoingAway.connect (death_connection, ui_bind (&RegionDrag::region_going_away, this, _1), gui_context());
+ 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());
}
void
RegionDrag::region_going_away (RegionView* v)
{
- _views.remove (v);
+ list<DraggingView>::iterator i = _views.begin ();
+ while (i != _views.end() && i->view != v) {
+ ++i;
+ }
+
+ if (i != _views.end()) {
+ _views.erase (i);
+ }
}
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)
+ _brushing (b),
+ _total_x_delta (0)
{
}
}
}
- for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+ for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
- RegionView* rv = (*i);
+ RegionView* rv = i->view;
if (rv->region()->locked()) {
continue;
if (*pending_region_position <= _last_frame_position) {
- for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+ for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
- RegionView* rv = (*i);
+ RegionView* rv = i->view;
// If any regionview is at zero, we need to know so we can stop further leftward motion.
pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
- for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+ for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
- RegionView* rv = (*i);
+ RegionView* rv = i->view;
if (rv->region()->locked()) {
continue;
} /* foreach region */
+ _total_x_delta += x_delta;
+
if (first_move) {
_editor->cursor_group->raise_to_top();
}
RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
{
vector<RegionView*> copies;
- boost::shared_ptr<Diskstream> ds;
+ boost::shared_ptr<Track> tr;
boost::shared_ptr<Playlist> from_playlist;
+ boost::shared_ptr<Playlist> to_playlist;
RegionSelection new_views;
typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
PlaylistSet modified_playlists;
bool changed_tracks, changed_position;
map<RegionView*, pair<RouteTimeAxisView*, int> > final;
RouteTimeAxisView* source_tv;
+ vector<StatefulDiffCommand*> sdc;
if (!movement_occurred) {
/* just a click */
/* all changes were made during motion event handlers */
if (_copy) {
- for (list<RegionView*>::iterator i = _views.begin(); i != _views.end(); ++i) {
- copies.push_back (*i);
+ for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
+ copies.push_back (i->view);
}
}
}
}
- _have_transaction = true;
-
changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
/* make a list of where each region ended up */
final = find_time_axis_views_and_layers ();
- for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ) {
+ cerr << "Iterate over " << _views.size() << " views\n";
+
+ for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ) {
- RegionView* rv = (*i);
- RouteTimeAxisView* dest_rtv = final[*i].first;
- layer_t dest_layer = final[*i].second;
+ RegionView* rv = i->view;
+ RouteTimeAxisView* dest_rtv = final[rv].first;
+ layer_t dest_layer = final[rv].second;
nframes64_t where;
+ from_playlist.reset ();
+ to_playlist.reset ();
+
if (rv->region()->locked()) {
++i;
continue;
if (changed_tracks || _copy) {
- boost::shared_ptr<Playlist> to_playlist = dest_rtv->playlist();
+ to_playlist = dest_rtv->playlist();
if (!to_playlist) {
++i;
insert_result = modified_playlists.insert (to_playlist);
if (insert_result.second) {
- _editor->session()->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
+ to_playlist->clear_history ();
}
+ cerr << "To playlist " << to_playlist->name() << " region history contains "
+ << to_playlist->region_list().change().added.size() << " adds and "
+ << to_playlist->region_list().change().removed.size() << " removes\n";
+
+ cerr << "Adding new region " << new_region->id() << " based on "
+ << rv->region()->id() << endl;
+
to_playlist->add_region (new_region, where);
+
if (dest_rtv->view()->layer_display() == Stacked) {
new_region->set_layer (dest_layer);
new_region->set_pending_explicit_relayer (true);
}
} else {
+ rv->region()->clear_history ();
+
/*
motion on the same track. plonk the previously reparented region
back to its original canvas group (its streamview).
*/
rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
- rv->get_canvas_group()->property_y() = 0;
+ rv->get_canvas_group()->property_y() = i->initial_y;
+ rv->get_time_axis_view().reveal_dependent_views (*rv);
/* 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 */
- insert_result = modified_playlists.insert (playlist);
-
- if (insert_result.second) {
- _editor->session()->add_command (new MementoCommand<Playlist>(*playlist, &playlist->get_state(), 0));
- }
- /* freeze to avoid lots of relayering in the case of a multi-region drag */
frozen_insert_result = frozen_playlists.insert(playlist);
if (frozen_insert_result.second) {
playlist->freeze();
}
+ cerr << "Moving region " << rv->region()->id() << endl;
+
rv->region()->set_position (where, (void*) this);
+
+ sdc.push_back (new StatefulDiffCommand (rv->region()));
}
if (changed_tracks && !_copy) {
*/
source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
- ds = source_tv->get_diskstream();
- from_playlist = ds->playlist();
+ tr = source_tv->track();
+ from_playlist = tr->playlist();
assert (source_tv);
- assert (ds);
+ assert (tr);
assert (from_playlist);
/* moved to a different audio track, without copying */
insert_result = modified_playlists.insert (from_playlist);
if (insert_result.second) {
- _editor->session()->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));
+ from_playlist->clear_history ();
}
+
+ cerr << "From playlist " << from_playlist->name() << " region history contains "
+ << from_playlist->region_list().change().added.size() << " adds and "
+ << from_playlist->region_list().change().removed.size() << " removes\n";
+ cerr << "removing region " << rv->region() << endl;
+
from_playlist->remove_region (rv->region());
/* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
*/
if (_views.empty()) {
- break;
+ if (to_playlist) {
+ sdc.push_back (new StatefulDiffCommand (to_playlist));
+ cerr << "Saved diff for to:" << to_playlist->name() << endl;
+ }
+
+ if (from_playlist && (from_playlist != to_playlist)) {
+ sdc.push_back (new StatefulDiffCommand (from_playlist));
+ cerr << "Saved diff for from:" << from_playlist->name() << endl;
+ }
+ break;
} else {
i = _views.begin();
}
if (_copy) {
copies.push_back (rv);
}
+
+ cerr << "Done with TV, top = " << to_playlist << " from = " << from_playlist << endl;
+
+ if (to_playlist) {
+ sdc.push_back (new StatefulDiffCommand (to_playlist));
+ cerr << "Saved diff for to:" << to_playlist->name() << endl;
+ }
+
+ if (from_playlist && (from_playlist != to_playlist)) {
+ sdc.push_back (new StatefulDiffCommand (from_playlist));
+ cerr << "Saved diff for from:" << from_playlist->name() << endl;
+ }
}
+
/*
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) {
_editor->selection->set (new_views);
}
}
out:
- for (set<boost::shared_ptr<Playlist> >::iterator p = modified_playlists.begin(); p != modified_playlists.end(); ++p) {
- _editor->session()->add_command (new MementoCommand<Playlist>(*(*p), 0, &(*p)->get_state()));
- }
+ for (vector<StatefulDiffCommand*>::iterator i = sdc.begin(); i != sdc.end(); ++i) {
+ _editor->session()->add_command (*i);
+ }
_editor->commit_reversible_command ();
}
}
+void
+RegionMoveDrag::aborted ()
+{
+ if (_copy) {
+
+ for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+ delete i->view;
+ }
+
+ _views.clear ();
+
+ } else {
+ RegionMotionDrag::aborted ();
+ }
+}
+
+void
+RegionMotionDrag::aborted ()
+{
+ for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+ RegionView* rv = i->view;
+ TimeAxisView* tv = &(rv->get_time_axis_view ());
+ RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
+ assert (rtv);
+ rv->get_canvas_group()->reparent (*rtv->view()->canvas_item());
+ rv->get_canvas_group()->property_y() = 0;
+ rv->get_time_axis_view().reveal_dependent_views (*rv);
+ rv->fake_set_opaque (false);
+ rv->move (-_total_x_delta, 0);
+ rv->set_height (rtv->view()->child_height ());
+ }
+
+ _editor->update_canvas_now ();
+}
+
bool
RegionMotionDrag::x_move_allowed () const
{
/* duplicate the regionview(s) and region(s) */
- list<RegionView*> new_regionviews;
+ list<DraggingView> new_regionviews;
- for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+ for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
- RegionView* rv = (*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
}
nrv->get_canvas_group()->show ();
- new_regionviews.push_back (nrv);
+ new_regionviews.push_back (DraggingView (nrv));
/* swap _primary to the copy */
_views = new_regionviews;
- swap_grab (new_regionviews.front()->get_canvas_group (), 0, event ? event->motion.time : 0);
+ 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 raking so long?
+ something to do with regionview creation taking so long?
*/
_editor->update_canvas_now();
}
{
/* Which trackview is this ? */
- pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (current_pointer_y ());
+ pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (_drags->current_pointer_y ());
(*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
(*layer) = tvp.second;
double speed = 1;
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
if (rtv && rtv->is_track()) {
- speed = rtv->get_diskstream()->speed ();
+ speed = rtv->track()->speed ();
}
_last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
_primary->get_canvas_group()->show ();
_primary->set_position (pos, 0);
- _views.push_back (_primary);
+ _views.push_back (DraggingView (_primary));
_last_frame_position = pos;
{
map<RegionView*, pair<RouteTimeAxisView*, int> > tav;
- for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+ for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
double ix1, ix2, iy1, iy2;
- (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
- (*i)->get_canvas_frame()->i2w (ix1, iy1);
+ 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[*i] = make_pair (dynamic_cast<RouteTimeAxisView*> (tv.first), tv.second);
+ tav[rv] = make_pair (dynamic_cast<RouteTimeAxisView*> (tv.first), tv.second);
}
return tav;
boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
_editor->begin_reversible_command (_("insert region"));
- XMLNode& before = playlist->get_state ();
+ playlist->clear_history ();
playlist->add_region (_primary->region (), _last_frame_position);
- _editor->session()->add_command (new MementoCommand<Playlist> (*playlist, &before, &playlist->get_state()));
+ _editor->session()->add_command (new StatefulDiffCommand (playlist));
_editor->commit_reversible_command ();
delete _primary;
_views.clear ();
}
+void
+RegionInsertDrag::aborted ()
+{
+ /* XXX: TODO */
+}
+
RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
: RegionMoveDrag (e, i, p, v, false, false)
{
int dir;
- if ((current_pointer_x() - last_pointer_x()) > 0) {
+ if ((_drags->current_pointer_x() - last_pointer_x()) > 0) {
dir = 1;
} else {
dir = -1;
}
+void
+RegionSpliceDrag::aborted ()
+{
+ /* XXX: TODO */
+}
RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
: Drag (e, i),
}
}
+void
+RegionCreateDrag::aborted ()
+{
+ /* XXX: TODO */
+}
+
NoteResizeDrag::NoteResizeDrag (Editor* e, ArdourCanvas::Item* i)
: Drag (e, i)
, region (0)
{
MidiRegionSelection& ms (_editor->get_selection().midi_regions);
for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
- (*r)->update_resizing (at_front, current_pointer_x() - grab_x(), relative);
+ (*r)->update_resizing (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 (at_front, current_pointer_x() - grab_x(), relative);
+ (*r)->commit_resizing (at_front, _drags->current_pointer_x() - grab_x(), relative);
}
}
+void
+NoteResizeDrag::aborted ()
+{
+ /* XXX: TODO */
+}
+
void
RegionGainDrag::motion (GdkEvent* /*event*/, bool)
{
}
+void
+RegionGainDrag::aborted ()
+{
+ /* XXX: TODO */
+}
+
TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
: RegionDrag (e, i, p, v)
+ , _have_transaction (false)
{
}
RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
if (tv && tv->is_track()) {
- speed = tv->get_diskstream()->speed();
+ speed = tv->track()->speed();
}
nframes64_t region_start = (nframes64_t) (_primary->region()->position() / speed);
nframes64_t frame_delta = 0;
bool left_direction;
- bool obey_snap = !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier());
+ bool obey_snap = event ? !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) : false;
/* snap modifier works differently here..
its current state has to be passed to the
pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
if (tv && tv->is_track()) {
- speed = tv->get_diskstream()->speed();
+ speed = tv->track()->speed();
}
nframes64_t const pf = adjusted_current_frame (event);
_editor->begin_reversible_command (trim_type);
_have_transaction = true;
- for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
- (*i)->fake_set_opaque(false);
- (*i)->region()->freeze ();
+ for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+ RegionView* rv = i->view;
+ rv->fake_set_opaque(false);
+ rv->region()->clear_history ();
+ rv->region()->suspend_property_changes ();
- AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
+ AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (rv);
if (arv){
arv->temporarily_hide_envelope ();
}
- boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
+ boost::shared_ptr<Playlist> pl = rv->region()->playlist();
insert_result = _editor->motion_frozen_playlists.insert (pl);
if (insert_result.second) {
- _editor->session()->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
pl->freeze();
}
}
}
- if (pf == last_pointer_frame()) {
- return;
- }
-
- /* XXX i hope to god that we can really conclude this ... */
- _have_transaction = true;
-
if (left_direction) {
frame_delta = (last_pointer_frame() - pf);
} else {
bool non_overlap_trim = false;
- if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
+ if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
non_overlap_trim = true;
}
break;
} else {
- for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
- _editor->single_start_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
+ for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+ _editor->single_start_trim (*i->view, frame_delta, left_direction, obey_snap, non_overlap_trim);
}
break;
}
break;
} else {
- for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
- _editor->single_end_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
+ for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+ _editor->single_end_trim (*i->view, frame_delta, left_direction, obey_snap, non_overlap_trim);
}
break;
}
{
bool swap_direction = false;
- if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
+ if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
swap_direction = true;
}
- for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
- _editor->single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
+ for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+ _editor->single_contents_trim (*i->view, frame_delta, left_direction, swap_direction, obey_snap);
}
}
break;
_editor->thaw_region_after_trim (*_primary);
} else {
- for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
- _editor->thaw_region_after_trim (**i);
- (*i)->fake_set_opaque (true);
+ for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+ _editor->thaw_region_after_trim (*i->view);
+ i->view->fake_set_opaque (true);
+ if (_have_transaction) {
+ _editor->session()->add_command (new StatefulDiffCommand (i->view->region()));
+ }
}
}
for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
(*p)->thaw ();
- if (_have_transaction) {
- _editor->session()->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
- }
}
_editor->motion_frozen_playlists.clear ();
} else {
/* no mouse movement */
- _editor->point_trim (event);
+ _editor->point_trim (event, adjusted_current_frame (event));
+ }
+}
+
+void
+TrimDrag::aborted ()
+{
+ /* Our motion method is changing model state, so use the Undo system
+ to cancel. Perhaps not ideal, as this will leave an Undo point
+ behind which may be slightly odd from the user's point of view.
+ */
+
+ finished (0, true);
+
+ if (_have_transaction) {
+ _editor->undo ();
}
}
{
nframes64_t const pf = adjusted_current_frame (event);
- if (pf == last_pointer_frame()) {
- return;
- }
-
_marker->set_position (pf);
_editor->show_verbose_time_cursor (pf, 10);
}
}
+void
+MeterMarkerDrag::aborted ()
+{
+ _marker->set_position (_marker->meter().frame ());
+}
+
TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
: Drag (e, i),
_copy (c)
TempoMarkerDrag::motion (GdkEvent* event, bool)
{
nframes64_t const pf = adjusted_current_frame (event);
-
- if (pf == last_pointer_frame()) {
- return;
- }
-
- /* OK, we've moved far enough to make it worth actually move the thing. */
-
_marker->set_position (pf);
-
_editor->show_verbose_time_cursor (pf, 10);
}
}
}
+void
+TempoMarkerDrag::aborted ()
+{
+ _marker->set_position (_marker->tempo().frame());
+}
CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
: Drag (e, i),
}
}
+ _pointer_frame_offset = grab_frame() - _cursor->current_frame;
+
_editor->show_verbose_time_cursor (_cursor->current_frame, 10);
}
}
}
+void
+CursorDrag::aborted ()
+{
+ _editor->_dragging_playhead = false;
+ _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)
{
fade_length = pos - region->position();
}
- for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
+ for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
- AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
+ AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
if (!tmp) {
continue;
_editor->begin_reversible_command (_("change fade in length"));
- for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
+ for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
- AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
+ AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
if (!tmp) {
continue;
_editor->commit_reversible_command ();
}
+void
+FadeInDrag::aborted ()
+{
+ for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
+ AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
+
+ if (!tmp) {
+ continue;
+ }
+
+ tmp->reset_fade_in_shape_width (tmp->audio_region()->fade_in()->back()->when);
+ }
+}
+
FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
: RegionDrag (e, i, p, v)
{
fade_length = region->last_frame() - pos;
}
- for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
+ for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
- AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
+ AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
if (!tmp) {
continue;
_editor->begin_reversible_command (_("change fade out length"));
- for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
+ for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
- AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
+ AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
if (!tmp) {
continue;
_editor->commit_reversible_command ();
}
+void
+FadeOutDrag::aborted ()
+{
+ for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
+ AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
+
+ if (!tmp) {
+ continue;
+ }
+
+ tmp->reset_fade_out_shape_width (tmp->audio_region()->fade_out()->back()->when);
+ }
+}
+
MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
: Drag (e, i)
{
break;
}
- /* set up copies for us to manipulate during the drag */
+ /* Set up copies for us to manipulate during the drag */
for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
- Location *l = _editor->find_location_from_marker (*i, is_start);
+ Location* l = _editor->find_location_from_marker (*i, is_start);
_copied_locations.push_back (new Location (*l));
}
}
bool is_start;
bool move_both = false;
Marker* marker;
- Location *real_location;
+ Location *real_location;
Location *copy_location = 0;
nframes64_t const newframe = adjusted_current_frame (event);
if (copy_location->is_mark()) {
- /* just move it */
+ /* now move it */
copy_location->set_start (copy_location->start() + f_delta);
_line->hide();
}
+void
+MarkerDrag::aborted ()
+{
+ /* XXX: TODO */
+}
+
void
MarkerDrag::update_item (Location* location)
{
// the point doesn't 'jump' to the mouse after the first drag
_time_axis_view_grab_x = _point->get_x();
_time_axis_view_grab_y = _point->get_y();
- nframes64_t grab_frame = _editor->pixel_to_frame (_time_axis_view_grab_x);
float const fraction = 1 - (_point->get_y() / _point->line().height());
- _point->line().start_drag_single (_point, grab_frame, fraction);
+ _point->line().start_drag_single (_point, _time_axis_view_grab_x, fraction);
_editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
event->button.x + 10, event->button.y + 10);
void
ControlPointDrag::motion (GdkEvent* event, bool)
{
- double dx = current_pointer_x() - last_pointer_x();
- double dy = current_pointer_y() - last_pointer_y();
+ double dx = _drags->current_pointer_x() - last_pointer_x();
+ double dy = _drags->current_pointer_y() - last_pointer_y();
if (event->button.state & Keyboard::SecondaryModifier) {
dx *= 0.1;
bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
- _point->line().drag_motion (cx_frames, fraction, push);
+ _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));
}
_point->line().end_drag ();
}
+void
+ControlPointDrag::aborted ()
+{
+ _point->line().reset ();
+}
+
bool
ControlPointDrag::active (Editing::MouseMode m)
{
void
LineDrag::motion (GdkEvent* event, bool)
{
- double dy = current_pointer_y() - last_pointer_y();
+ double dy = _drags->current_pointer_y() - last_pointer_y();
if (event->button.state & Keyboard::SecondaryModifier) {
dy *= 0.1;
push = true;
}
- /* we are ignoring x position for this drag, so we can just pass in 0 */
- _line->drag_motion (0, fraction, push);
+ /* 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));
}
_line->end_drag ();
}
+void
+LineDrag::aborted ()
+{
+ _line->reset ();
+}
+
void
RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
{
double y1;
double y2;
- /* use a bigger drag threshold than the default */
-
nframes64_t const pf = adjusted_current_frame (event, Config->get_rubberbanding_snaps_to_grid ());
- if (abs ((int) (pf - grab_frame())) < 8) {
- return;
- }
-
nframes64_t grab = grab_frame ();
if (Config->get_rubberbanding_snaps_to_grid ()) {
_editor->snap_to_with_modifier (grab, event);
start = grab;
}
- if (current_pointer_y() < grab_y()) {
- y1 = current_pointer_y();
+ if (_drags->current_pointer_y() < grab_y()) {
+ y1 = _drags->current_pointer_y();
y2 = grab_y();
} else {
- y2 = current_pointer_y();
+ y2 = _drags->current_pointer_y();
y1 = grab_y();
}
motion (event, false);
double y1,y2;
- if (current_pointer_y() < grab_y()) {
- y1 = current_pointer_y();
+ if (_drags->current_pointer_y() < grab_y()) {
+ y1 = _drags->current_pointer_y();
y2 = grab_y();
} else {
- y2 = current_pointer_y();
+ y2 = _drags->current_pointer_y();
y1 = grab_y();
}
_editor->rubberband_rect->hide();
}
+void
+RubberbandSelectDrag::aborted ()
+{
+ _editor->rubberband_rect->hide ();
+}
+
void
TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
{
nframes64_t const pf = adjusted_current_frame (event);
- if (pf == last_pointer_frame()) {
- return;
- }
-
if (pf > rv->region()->position()) {
rv->get_time_axis_view().show_timestretch (rv->region()->position(), pf);
}
}
}
+void
+TimeFXDrag::aborted ()
+{
+ _primary->get_time_axis_view().hide_timestretch ();
+}
+
+
void
ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
{
void
ScrubDrag::motion (GdkEvent* /*event*/, bool)
{
- _editor->scrub ();
+ _editor->scrub (adjusted_current_frame (0, false), _drags->current_pointer_x ());
}
void
}
}
+void
+ScrubDrag::aborted ()
+{
+ /* XXX: TODO */
+}
+
SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
: Drag (e, i)
, _operation (o)
_editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
}
- _original_pointer_time_axis = _editor->trackview_by_y_position (current_pointer_y ()).first->order ();
+ _original_pointer_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ()).first->order ();
}
void
nframes64_t end = 0;
nframes64_t length;
- pair<TimeAxisView*, int> const pending_time_axis = _editor->trackview_by_y_position (current_pointer_y ());
+ pair<TimeAxisView*, int> const pending_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ());
if (pending_time_axis.first == 0) {
return;
}
if (first_move) {
- _editor->begin_reversible_command (_("range selection"));
- _have_transaction = true;
-
if (_copy) {
/* adding to the selection */
_editor->selection->add (_editor->clicked_axisview);
case SelectionStartTrim:
- if (first_move) {
- _editor->begin_reversible_command (_("trim selection start"));
- _have_transaction = true;
- }
-
start = _editor->selection->time[_editor->clicked_selection].start;
end = _editor->selection->time[_editor->clicked_selection].end;
case SelectionEndTrim:
- if (first_move) {
- _editor->begin_reversible_command (_("trim selection end"));
- _have_transaction = true;
- }
-
start = _editor->selection->time[_editor->clicked_selection].start;
end = _editor->selection->time[_editor->clicked_selection].end;
case SelectionMove:
- if (first_move) {
- _editor->begin_reversible_command (_("move selection"));
- _have_transaction = true;
- }
-
start = _editor->selection->time[_editor->clicked_selection].start;
end = _editor->selection->time[_editor->clicked_selection].end;
_editor->selection->TimeChanged ();
}
- if (_have_transaction) {
- _editor->commit_reversible_command ();
- }
-
/* XXX what if its a music time selection? */
if (s && (s->config.get_auto_play() || (s->get_play_range() && s->transport_rolling()))) {
s->request_play_range (&_editor->selection->time, true);
_editor->stop_canvas_autoscroll ();
}
+void
+SelectionDrag::aborted ()
+{
+ /* XXX: TODO */
+}
+
RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
: Drag (e, i),
_operation (o),
nframes64_t const pf = adjusted_current_frame (event);
- /* only alter selection if the current frame is
- different from the last frame position.
- */
-
- if (pf == last_pointer_frame()) {
- return;
- }
-
if (_operation == CreateRangeMarker || _operation == CreateTransportMarker || _operation == CreateCDMarker) {
nframes64_t grab = grab_frame ();
_editor->snap_to (grab);
_editor->stop_canvas_autoscroll ();
}
-
+void
+RangeMarkerBarDrag::aborted ()
+{
+ /* XXX: TODO */
+}
void
RangeMarkerBarDrag::update_item (Location* location)
nframes64_t const pf = adjusted_current_frame (event);
- if (pf == last_pointer_frame()) {
- return;
- }
-
nframes64_t grab = grab_frame ();
_editor->snap_to_with_modifier (grab, event);
_editor->zoom_rect->hide();
}
+void
+MouseZoomDrag::aborted ()
+{
+ _editor->zoom_rect->hide ();
+}
+
NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
: Drag (e, i)
{
double event_x;
double event_y;
- event_x = current_pointer_x();
- event_y = current_pointer_y();
+ event_x = _drags->current_pointer_x();
+ event_y = _drags->current_pointer_y();
_item->property_parent().get_value()->w2i(event_x, event_y);
double event_x;
double event_y;
- event_x = current_pointer_x();
- event_y = current_pointer_y();
+ event_x = _drags->current_pointer_x();
+ event_y = _drags->current_pointer_y();
_item->property_parent().get_value()->w2i(event_x, event_y);
}
}
+void
+NoteDrag::aborted ()
+{
+ /* XXX: TODO */
+}
+
AutomationRangeDrag::AutomationRangeDrag (Editor* e, ArdourCanvas::Item* i, list<AudioRange> const & r)
: Drag (e, i)
, _ranges (r)
return;
}
- _line->start_drag_multiple (points, 1 - (current_pointer_y() / _line->height ()), state);
+ _line->start_drag_multiple (points, 1 - (_drags->current_pointer_y() / _line->height ()), state);
}
void
return;
}
- float const f = 1 - (current_pointer_y() / _line->height());
+ float const f = 1 - (_drags->current_pointer_y() / _line->height());
- /* we are ignoring x position for this drag, so we can just pass in 0 */
- _line->drag_motion (0, f, false);
+ /* we are ignoring x position for this drag, so we can just pass in anything */
+ _line->drag_motion (0, f, true, false);
}
void
_line->end_drag ();
_line->clear_always_in_view ();
}
+
+void
+AutomationRangeDrag::aborted ()
+{
+ _line->clear_always_in_view ();
+ _line->reset ();
+}
+
+DraggingView::DraggingView (RegionView* v)
+ : view (v)
+{
+ initial_y = v->get_canvas_group()->property_y ();
+}