Fix binding of automation list undo records to MIDI sources. Should fix the remainder of #3203.
git-svn-id: svn://localhost/ardour2/branches/3.0@7411 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
5ce47b52da
commit
66062a85b6
@ -218,7 +218,9 @@ AutomationLine::modify_point_y (ControlPoint& cp, double y)
|
||||
double const x = trackview.editor().frame_to_unit (_time_converter.to((*cp.model())->when));
|
||||
|
||||
trackview.editor().session()->begin_reversible_command (_("automation event move"));
|
||||
trackview.editor().session()->add_command (new MementoCommand<AutomationList>(*alist.get(), &get_state(), 0));
|
||||
trackview.editor().session()->add_command (
|
||||
new MementoCommand<AutomationList> (memento_command_binder(), &get_state(), 0)
|
||||
);
|
||||
|
||||
cp.move_to (x, y, ControlPoint::Full);
|
||||
reset_line_coords (cp);
|
||||
@ -233,7 +235,10 @@ AutomationLine::modify_point_y (ControlPoint& cp, double y)
|
||||
|
||||
update_pending = false;
|
||||
|
||||
trackview.editor().session()->add_command (new MementoCommand<AutomationList>(*alist.get(), 0, &alist->get_state()));
|
||||
trackview.editor().session()->add_command (
|
||||
new MementoCommand<AutomationList> (memento_command_binder(), 0, &alist->get_state())
|
||||
);
|
||||
|
||||
trackview.editor().session()->commit_reversible_command ();
|
||||
trackview.editor().session()->set_dirty ();
|
||||
}
|
||||
@ -568,7 +573,9 @@ void
|
||||
AutomationLine::start_drag_single (ControlPoint* cp, double x, float fraction)
|
||||
{
|
||||
trackview.editor().session()->begin_reversible_command (_("automation event move"));
|
||||
trackview.editor().session()->add_command (new MementoCommand<AutomationList>(*alist.get(), &get_state(), 0));
|
||||
trackview.editor().session()->add_command (
|
||||
new MementoCommand<AutomationList> (memento_command_binder(), &get_state(), 0)
|
||||
);
|
||||
|
||||
_drag_points.clear ();
|
||||
_drag_points.push_back (cp);
|
||||
@ -593,7 +600,9 @@ void
|
||||
AutomationLine::start_drag_line (uint32_t i1, uint32_t i2, float fraction)
|
||||
{
|
||||
trackview.editor().session()->begin_reversible_command (_("automation range move"));
|
||||
trackview.editor().session()->add_command (new MementoCommand<AutomationList>(*alist.get(), &get_state(), 0));
|
||||
trackview.editor().session()->add_command (
|
||||
new MementoCommand<AutomationList> (memento_command_binder (), &get_state(), 0)
|
||||
);
|
||||
|
||||
_drag_points.clear ();
|
||||
for (uint32_t i = i1; i <= i2; i++) {
|
||||
@ -611,7 +620,9 @@ void
|
||||
AutomationLine::start_drag_multiple (list<ControlPoint*> cp, float fraction, XMLNode* state)
|
||||
{
|
||||
trackview.editor().session()->begin_reversible_command (_("automation range move"));
|
||||
trackview.editor().session()->add_command (new MementoCommand<AutomationList>(*alist.get(), state, 0));
|
||||
trackview.editor().session()->add_command (
|
||||
new MementoCommand<AutomationList> (memento_command_binder(), state, 0)
|
||||
);
|
||||
|
||||
_drag_points = cp;
|
||||
start_drag_common (0, fraction);
|
||||
@ -778,7 +789,10 @@ AutomationLine::end_drag ()
|
||||
|
||||
update_pending = false;
|
||||
|
||||
trackview.editor().session()->add_command (new MementoCommand<AutomationList>(*alist.get(), 0, &alist->get_state()));
|
||||
trackview.editor().session()->add_command (
|
||||
new MementoCommand<AutomationList>(memento_command_binder (), 0, &alist->get_state())
|
||||
);
|
||||
|
||||
trackview.editor().session()->commit_reversible_command ();
|
||||
trackview.editor().session()->set_dirty ();
|
||||
}
|
||||
@ -924,8 +938,10 @@ AutomationLine::remove_point (ControlPoint& cp)
|
||||
|
||||
alist->erase (mr.start, mr.end);
|
||||
|
||||
trackview.editor().session()->add_command(new MementoCommand<AutomationList>(
|
||||
*alist.get(), &before, &alist->get_state()));
|
||||
trackview.editor().session()->add_command(
|
||||
new MementoCommand<AutomationList> (memento_command_binder (), &before, &alist->get_state())
|
||||
);
|
||||
|
||||
trackview.editor().session()->commit_reversible_command ();
|
||||
trackview.editor().session()->set_dirty ();
|
||||
}
|
||||
@ -1107,7 +1123,11 @@ AutomationLine::clear ()
|
||||
/* parent must create command */
|
||||
XMLNode &before = alist->get_state();
|
||||
alist->clear();
|
||||
trackview.editor().session()->add_command (new MementoCommand<AutomationList>(*(alist.get()), &before, &alist->get_state()));
|
||||
|
||||
trackview.editor().session()->add_command (
|
||||
new MementoCommand<AutomationList> (memento_command_binder (), &before, &alist->get_state())
|
||||
);
|
||||
|
||||
trackview.editor().session()->commit_reversible_command ();
|
||||
trackview.editor().session()->set_dirty ();
|
||||
}
|
||||
@ -1311,3 +1331,9 @@ AutomationLine::connect_to_list ()
|
||||
_list_connections, invalidator (*this), boost::bind (&AutomationLine::interpolation_changed, this, _1), gui_context()
|
||||
);
|
||||
}
|
||||
|
||||
MementoCommandBinder<AutomationList>*
|
||||
AutomationLine::memento_command_binder ()
|
||||
{
|
||||
return new SimpleMementoCommandBinder<AutomationList> (*alist.get());
|
||||
}
|
||||
|
@ -34,6 +34,7 @@
|
||||
|
||||
#include "pbd/undo.h"
|
||||
#include "pbd/statefuldestructible.h"
|
||||
#include "pbd/memento_command.h"
|
||||
|
||||
#include "ardour/automation_list.h"
|
||||
#include "ardour/types.h"
|
||||
@ -131,6 +132,8 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible
|
||||
void add_always_in_view (double);
|
||||
void clear_always_in_view ();
|
||||
|
||||
virtual MementoCommandBinder<ARDOUR::AutomationList>* memento_command_binder ();
|
||||
|
||||
protected:
|
||||
|
||||
std::string _name;
|
||||
|
@ -22,10 +22,13 @@
|
||||
#include "ardour/event_type_map.h"
|
||||
#include "ardour/session.h"
|
||||
#include "ardour/source.h"
|
||||
#include "ardour/midi_automation_list_binder.h"
|
||||
#include "ardour/midi_region.h"
|
||||
|
||||
#include "automation_region_view.h"
|
||||
#include "gui_thread.h"
|
||||
#include "public_editor.h"
|
||||
#include "midi_automation_line.h"
|
||||
|
||||
#include "i18n.h"
|
||||
|
||||
@ -71,9 +74,12 @@ AutomationRegionView::init (Gdk::Color const & basic_color, bool /*wfd*/)
|
||||
void
|
||||
AutomationRegionView::create_line (boost::shared_ptr<ARDOUR::AutomationList> list)
|
||||
{
|
||||
_line = boost::shared_ptr<AutomationLine>(new AutomationLine(
|
||||
_line = boost::shared_ptr<AutomationLine> (new MidiAutomationLine(
|
||||
ARDOUR::EventTypeMap::instance().to_symbol(list->parameter()),
|
||||
trackview, *get_canvas_group(), list, &_time_converter));
|
||||
trackview, *get_canvas_group(), list,
|
||||
boost::dynamic_pointer_cast<ARDOUR::MidiRegion> (_region),
|
||||
_parameter,
|
||||
&_time_converter));
|
||||
_line->set_colors();
|
||||
_line->set_height ((uint32_t)rint(trackview.current_height() - NAME_HIGHLIGHT_SIZE));
|
||||
_line->show();
|
||||
@ -130,8 +136,15 @@ AutomationRegionView::add_automation_event (GdkEvent *, nframes_t when, double y
|
||||
_line->the_list()->add (when_d, y);
|
||||
|
||||
XMLNode& after = _line->the_list()->get_state();
|
||||
view->session()->commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(
|
||||
*_line->the_list(), &before, &after));
|
||||
|
||||
/* XXX: hack! */
|
||||
boost::shared_ptr<ARDOUR::MidiRegion> mr = boost::dynamic_pointer_cast<ARDOUR::MidiRegion> (_region);
|
||||
assert (mr);
|
||||
|
||||
view->session()->commit_reversible_command (
|
||||
new MementoCommand<ARDOUR::AutomationList> (new ARDOUR::MidiAutomationListBinder (mr->midi_source(), _parameter), &before, &after)
|
||||
);
|
||||
|
||||
|
||||
view->session()->set_dirty ();
|
||||
}
|
||||
|
@ -127,6 +127,7 @@ gtk2_ardour_sources = [
|
||||
'location_ui.cc',
|
||||
'main.cc',
|
||||
'marker.cc',
|
||||
'midi_automation_line.cc',
|
||||
'midi_channel_selector.cc',
|
||||
'midi_cut_buffer.cc',
|
||||
'midi_list_editor.cc',
|
||||
|
@ -1204,8 +1204,11 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
|
||||
/* SOURCES */
|
||||
|
||||
mutable Glib::Mutex source_lock;
|
||||
|
||||
public:
|
||||
typedef std::map<PBD::ID,boost::shared_ptr<Source> > SourceMap;
|
||||
|
||||
private:
|
||||
SourceMap sources;
|
||||
|
||||
public:
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "ardour/midi_region.h"
|
||||
#include "ardour/session_playlists.h"
|
||||
#include "ardour/region_factory.h"
|
||||
#include "ardour/midi_automation_list_binder.h"
|
||||
#include "pbd/error.h"
|
||||
#include "pbd/id.h"
|
||||
#include "pbd/statefuldestructible.h"
|
||||
@ -58,7 +59,12 @@ Session::memento_command_factory(XMLNode *n)
|
||||
XMLNode *child = 0;
|
||||
|
||||
/* get id */
|
||||
|
||||
/* XXX: HACK! */
|
||||
bool have_id = n->property("obj-id") != 0;
|
||||
if (have_id) {
|
||||
id = PBD::ID(n->property("obj-id")->value());
|
||||
}
|
||||
|
||||
/* get before/after */
|
||||
|
||||
@ -121,11 +127,20 @@ Session::memento_command_factory(XMLNode *n)
|
||||
}
|
||||
|
||||
} else if (obj_T == "Evoral::Curve" || obj_T == "ARDOUR::AutomationList") {
|
||||
if (have_id) {
|
||||
std::map<PBD::ID, AutomationList*>::iterator i = automation_lists.find(id);
|
||||
if (i != automation_lists.end()) {
|
||||
return new MementoCommand<AutomationList>(*i->second, before, after);
|
||||
}
|
||||
} else {
|
||||
return new MementoCommand<AutomationList> (
|
||||
new MidiAutomationListBinder (n, sources),
|
||||
before, after
|
||||
);
|
||||
}
|
||||
|
||||
cerr << "Alist not found\n";
|
||||
|
||||
} else if (registry.count(id)) { // For Editor and AutomationLine which are off-limits herea
|
||||
return new MementoCommand<PBD::StatefulDestructible>(*registry[id], before, after);
|
||||
}
|
||||
|
@ -112,6 +112,7 @@ libardour_sources = [
|
||||
'location.cc',
|
||||
'location_importer.cc',
|
||||
'meter.cc',
|
||||
'midi_automation_list_binder.cc',
|
||||
'midi_buffer.cc',
|
||||
'midi_clock_slave.cc',
|
||||
'midi_diskstream.cc',
|
||||
|
@ -31,6 +31,56 @@
|
||||
#include <sigc++/slot.h>
|
||||
#include <typeinfo>
|
||||
|
||||
/** A class that can return a Stateful object which is the subject of a MementoCommand.
|
||||
*
|
||||
* The existence of this class means that the undo record can refer to objects which
|
||||
* don't exist in the session file. Currently this is just used for MIDI automation;
|
||||
* when MIDI automation is edited, undo records are written for the AutomationList being
|
||||
* changed. However this AutomationList is a temporary structure, built by a MidiModel,
|
||||
* which doesn't get written to the session file. Hence we need to be able to go from
|
||||
* a MidiSource and Parameter to an AutomationList. This Binder mechanism allows this
|
||||
* through MidiAutomationListBinder; the undo record stores the source and parameter,
|
||||
* and these are bound to an AutomationList by the Binder.
|
||||
*/
|
||||
template <class obj_T>
|
||||
class MementoCommandBinder : public PBD::Destructible
|
||||
{
|
||||
public:
|
||||
/** @return Stateful object to operate on */
|
||||
virtual obj_T* get () = 0;
|
||||
|
||||
/** Add our own state to an XMLNode */
|
||||
virtual void add_state (XMLNode *) = 0;
|
||||
};
|
||||
|
||||
/** A simple MementoCommandBinder which binds directly to an object */
|
||||
template <class obj_T>
|
||||
class SimpleMementoCommandBinder : public MementoCommandBinder<obj_T>
|
||||
{
|
||||
public:
|
||||
SimpleMementoCommandBinder (obj_T& o)
|
||||
: _object (o)
|
||||
{
|
||||
_object.Destroyed.connect_same_thread (_object_death_connection, boost::bind (&SimpleMementoCommandBinder::object_died, this));
|
||||
}
|
||||
|
||||
obj_T* get () {
|
||||
return &_object;
|
||||
}
|
||||
|
||||
void add_state (XMLNode* node) {
|
||||
node->add_property ("obj_id", _object.id().to_s());
|
||||
}
|
||||
|
||||
void object_died () {
|
||||
this->drop_references ();
|
||||
}
|
||||
|
||||
private:
|
||||
obj_T& _object;
|
||||
PBD::ScopedConnection _object_death_connection;
|
||||
};
|
||||
|
||||
/** This command class is initialized with before and after mementos
|
||||
* (from Stateful::get_state()), so undo becomes restoring the before
|
||||
* memento, and redo is restoring the after memento.
|
||||
@ -40,31 +90,37 @@ class MementoCommand : public Command
|
||||
{
|
||||
public:
|
||||
MementoCommand (obj_T& a_object, XMLNode* a_before, XMLNode* a_after)
|
||||
: obj(a_object), before(a_before), after(a_after)
|
||||
: _binder (new SimpleMementoCommandBinder<obj_T> (a_object)), before (a_before), after (a_after)
|
||||
{
|
||||
/* if the object dies, make sure that we die and that everyone knows about it */
|
||||
obj.Destroyed.connect_same_thread (obj_death_connection, boost::bind (&MementoCommand::object_died, this));
|
||||
_binder->Destroyed.connect_same_thread (_binder_death_connection, boost::bind (&MementoCommand::binder_died, this));
|
||||
}
|
||||
|
||||
MementoCommand (MementoCommandBinder<obj_T>* b, XMLNode* a_before, XMLNode* a_after)
|
||||
: _binder (b), before (a_before), after (a_after)
|
||||
{
|
||||
_binder->Destroyed.connect_same_thread (_binder_death_connection, boost::bind (&MementoCommand::binder_died, this));
|
||||
}
|
||||
|
||||
~MementoCommand () {
|
||||
drop_references ();
|
||||
delete before;
|
||||
delete after;
|
||||
delete _binder;
|
||||
}
|
||||
|
||||
void object_died () {
|
||||
void binder_died () {
|
||||
delete this;
|
||||
}
|
||||
|
||||
void operator() () {
|
||||
if (after) {
|
||||
obj.set_state(*after, Stateful::current_state_version);
|
||||
_binder->get()->set_state(*after, Stateful::current_state_version);
|
||||
}
|
||||
}
|
||||
|
||||
void undo() {
|
||||
if (before) {
|
||||
obj.set_state(*before, Stateful::current_state_version);
|
||||
_binder->get()->set_state(*before, Stateful::current_state_version);
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,9 +135,9 @@ public:
|
||||
}
|
||||
|
||||
XMLNode* node = new XMLNode(name);
|
||||
_binder->add_state (node);
|
||||
|
||||
node->add_property("obj_id", obj.id().to_s());
|
||||
node->add_property("type_name", demangled_name (obj));
|
||||
node->add_property("type_name", demangled_name (*_binder->get()));
|
||||
|
||||
if (before) {
|
||||
node->add_child_copy(*before);
|
||||
@ -95,10 +151,10 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
obj_T& obj;
|
||||
MementoCommandBinder<obj_T>* _binder;
|
||||
XMLNode* before;
|
||||
XMLNode* after;
|
||||
PBD::ScopedConnection obj_death_connection;
|
||||
PBD::ScopedConnection _binder_death_connection;
|
||||
};
|
||||
|
||||
#endif // __lib_pbd_memento_h__
|
||||
|
Loading…
Reference in New Issue
Block a user