*/
+#define __STDC_LIMIT_MACROS 1
+#include <stdint.h>
#include "pbd/memento_command.h"
#include "pbd/basename.h"
+#include "pbd/stateful_diff_command.h"
#include "ardour/diskstream.h"
#include "ardour/session.h"
#include "ardour/dB.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)
- , _ending (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;
+ _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)
{
- _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 == _current_pointer_y) ) {
+ (!y_movement_matters() || _last_pointer_y == _drags->current_pointer_y ()) ) {
return false;
}
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 = _current_pointer_x;
- _last_pointer_y = _current_pointer_y;
+ _last_pointer_x = _drags->current_pointer_x ();
+ _last_pointer_y = _drags->current_pointer_y ();
_last_pointer_frame = adjusted_current_frame (event);
return true;
void
Drag::break_drag ()
{
- _ending = true;
-
if (_item) {
_item->ungrab (0);
}
_editor->stop_canvas_autoscroll ();
_editor->hide_verbose_canvas_cursor ();
-
- _ending = false;
-}
-
-pair<nframes64_t, nframes64_t>
-Drag::extent () const
-{
- nframes64_t const f = adjusted_current_frame (0);
- return make_pair (f, f);
}
RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
void
RegionDrag::region_going_away (RegionView* v)
{
- if (!ending ()) {
- _views.remove (v);
- }
-}
-
-pair<nframes64_t, nframes64_t>
-RegionDrag::extent () const
-{
- nframes64_t const f = adjusted_current_frame (0);
- return make_pair (f, f + _primary->region()->length ());
+ _views.remove (v);
}
-
RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
: RegionDrag (e, i, p, v),
_dest_trackview (0),
vector<RegionView*> copies;
boost::shared_ptr<Diskstream> ds;
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 */
}
}
- _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 ();
+ cerr << "Iterate over " << _views.size() << " views\n";
+
for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ) {
RegionView* rv = (*i);
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).
/* 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) {
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 ();
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
{
/* 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;
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;
int dir;
- if ((current_pointer_x() - last_pointer_x()) > 0) {
+ if ((_drags->current_pointer_x() - last_pointer_x()) > 0) {
dir = 1;
} else {
dir = -1;
{
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);
}
}
TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
: RegionDrag (e, i, p, v)
+ , _have_transaction (false)
{
}
for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
(*i)->fake_set_opaque(false);
- (*i)->region()->freeze ();
+ (*i)->region()->clear_history ();
+ (*i)->region()->suspend_property_changes ();
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
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();
}
}
}
- /* XXX i hope to god that we can really conclude this ... */
- _have_transaction = true;
-
if (left_direction) {
frame_delta = (last_pointer_frame() - pf);
} else {
for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
_editor->thaw_region_after_trim (**i);
(*i)->fake_set_opaque (true);
+ if (_have_transaction) {
+ _editor->session()->add_command (new StatefulDiffCommand ((*i)->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
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;
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;
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();
}
void
ScrubDrag::motion (GdkEvent* /*event*/, bool)
{
- _editor->scrub ();
+ _editor->scrub (adjusted_current_frame (0, false), _drags->current_pointer_x ());
}
void
_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);
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);
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 anything */
_line->drag_motion (0, f, true, false);