diff options
author | Carl Hetherington <carl@carlh.net> | 2012-04-22 14:03:07 +0000 |
---|---|---|
committer | Carl Hetherington <carl@carlh.net> | 2012-04-22 14:03:07 +0000 |
commit | a4434809e147d7f091fd488d047c531ff4c344c9 (patch) | |
tree | 2ffc14ef55a0ca310b4f772bcb87d662084a752c /gtk2_ardour/editor_ops.cc | |
parent | 82c867bf2a6f4de102707b812a87d68e3bd6e170 (diff) |
Use a list of ControlPoints to hold the automation selection,
rather than a time range. This makes more sense now that we
display every point on an automation line, rather than just
a subset. Makes the code a fair bit simpler, and should fix
some unexpected behaviours, especially when cutting automation
points.
git-svn-id: svn://localhost/ardour2/branches/3.0@12054 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'gtk2_ardour/editor_ops.cc')
-rw-r--r-- | gtk2_ardour/editor_ops.cc | 90 |
1 files changed, 77 insertions, 13 deletions
diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 6b48311b15..bae511e031 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -63,6 +63,7 @@ #include "route_time_axis.h" #include "audio_time_axis.h" #include "automation_time_axis.h" +#include "control_point.h" #include "streamview.h" #include "audio_streamview.h" #include "audio_region_view.h" @@ -3721,19 +3722,87 @@ Editor::cut_copy (CutCopyOp op) } } +struct AutomationRecord { + AutomationRecord () : state (0) {} + AutomationRecord (XMLNode* s) : state (s) {} + + XMLNode* state; ///< state before any operation + boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer +}; + /** Cut, copy or clear selected automation points. - * @param op Operation (Cut, Copy or Clear) + * @param op Operation (Cut, Copy or Clear) */ void Editor::cut_copy_points (CutCopyOp op) { + if (selection->points.empty ()) { + return; + } + + /* XXX: not ideal, as there may be more than one track involved in the point selection */ + _last_cut_copy_source_track = &selection->points.front()->line().trackview; + + /* Keep a record of the AutomationLists that we end up using in this operation */ + typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists; + Lists lists; + + /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */ for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) { + boost::shared_ptr<AutomationList> al = (*i)->line().the_list(); + if (lists.find (al) == lists.end ()) { + /* We haven't seen this list yet, so make a record for it. This includes + taking a copy of its current state, in case this is needed for undo later. + */ + lists[al] = AutomationRecord (&al->get_state ()); + } + } + + if (op == Cut || op == Copy) { + /* This operation will involve putting things in the cut buffer, so create an empty + ControlList for each of our source lists to put the cut buffer data in. + */ + for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) { + i->second.copy = i->first->create (i->first->parameter ()); + } - AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>((*i).track); - _last_cut_copy_source_track = atv; + /* Add all selected points to the relevant copy ControlLists */ + for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) { + boost::shared_ptr<AutomationList> al = (*i)->line().the_list(); + AutomationList::const_iterator j = (*i)->model (); + lists[al].copy->add ((*j)->when, (*j)->value); + } + + for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) { + /* Correct this copy list so that it starts at time 0 */ + double const start = i->second.copy->front()->when; + for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) { + (*j)->when -= start; + } - if (atv) { - atv->cut_copy_clear_objects (selection->points, op); + /* And add it to the cut buffer */ + cut_buffer->add (i->second.copy); + } + } + + if (op == Delete || op == Cut) { + /* This operation needs to remove things from the main AutomationList, so do that now */ + + for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) { + i->first->freeze (); + } + + /* Remove each selected point from its AutomationList */ + for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) { + boost::shared_ptr<AutomationList> al = (*i)->line().the_list(); + al->erase ((*i)->model ()); + } + + /* Thaw the lists and add undo records for them */ + for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) { + boost::shared_ptr<AutomationList> al = i->first; + al->thaw (); + _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ()))); } } } @@ -4229,18 +4298,13 @@ Editor::duplicate_selection (float times) commit_reversible_command (); } +/** Reset all selected points to the relevant default value */ void Editor::reset_point_selection () { - /* reset all selected points to the relevant default value */ - for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) { - - AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>((*i).track); - - if (atv) { - atv->reset_objects (selection->points); - } + ARDOUR::AutomationList::iterator j = (*i)->model (); + (*j)->value = (*i)->line().the_list()->default_value (); } } |