Use a list of ControlPoints to hold the automation selection,
authorCarl Hetherington <carl@carlh.net>
Sun, 22 Apr 2012 14:03:07 +0000 (14:03 +0000)
committerCarl Hetherington <carl@carlh.net>
Sun, 22 Apr 2012 14:03:07 +0000 (14:03 +0000)
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

13 files changed:
gtk2_ardour/automation_line.cc
gtk2_ardour/automation_line.h
gtk2_ardour/automation_time_axis.cc
gtk2_ardour/automation_time_axis.h
gtk2_ardour/control_point.cc
gtk2_ardour/control_point.h
gtk2_ardour/editor_ops.cc
gtk2_ardour/point_selection.h
gtk2_ardour/selection.cc
gtk2_ardour/selection.h
gtk2_ardour/time_info_box.cc
libs/evoral/evoral/ControlList.hpp
libs/evoral/src/ControlList.cpp

index 2f91c113bd158e22f56456416ec31cab5dfd2e83..2af484b409d3219b159c0f4253f7aea1ecbce9bf 100644 (file)
@@ -731,38 +731,6 @@ AutomationLine::get_inverted_selectables (Selection&, list<Selectable*>& /*resul
        // hmmm ....
 }
 
-/** Take a PointSelection and find ControlPoints that fall within it */
-list<ControlPoint*>
-AutomationLine::point_selection_to_control_points (PointSelection const & s)
-{
-       list<ControlPoint*> cp;
-
-       for (PointSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
-
-               if (i->track != &trackview) {
-                       continue;
-               }
-
-               double const bot = (1 - i->high_fract) * trackview.current_height ();
-               double const top = (1 - i->low_fract) * trackview.current_height ();
-
-               for (vector<ControlPoint*>::iterator j = control_points.begin(); j != control_points.end(); ++j) {
-
-                       double const rstart = trackview.editor().frame_to_unit (_time_converter->to (i->start) - _offset);
-                       double const rend = trackview.editor().frame_to_unit (_time_converter->to (i->end) - _offset);
-
-                       if ((*j)->get_x() >= rstart && (*j)->get_x() <= rend) {
-                               if ((*j)->get_y() >= bot && (*j)->get_y() <= top) {
-                                       cp.push_back (*j);
-                               }
-                       }
-               }
-
-       }
-
-       return cp;
-}
-
 void
 AutomationLine::set_selected_points (PointSelection const & points)
 {
@@ -770,11 +738,8 @@ AutomationLine::set_selected_points (PointSelection const & points)
                (*i)->set_selected (false);
        }
 
-       if (!points.empty()) {
-               list<ControlPoint*> cp = point_selection_to_control_points (points);
-               for (list<ControlPoint*>::iterator i = cp.begin(); i != cp.end(); ++i) {
-                       (*i)->set_selected (true);
-               }
+       for (PointSelection::const_iterator i = points.begin(); i != points.end(); ++i) {
+               (*i)->set_selected (true);
        }
 
        set_colors ();
@@ -1147,13 +1112,19 @@ AutomationLine::get_point_x_range () const
        pair<framepos_t, framepos_t> r (max_framepos, 0);
 
        for (AutomationList::const_iterator i = the_list()->begin(); i != the_list()->end(); ++i) {
-               r.first = min (r.first, _time_converter->to ((*i)->when) + _offset + _time_converter->origin_b ());
-               r.second = max (r.second, _time_converter->to ((*i)->when) + _offset + _time_converter->origin_b ());
+               r.first = min (r.first, session_position (i));
+               r.second = max (r.second, session_position (i));
        }
 
        return r;
 }
 
+framepos_t
+AutomationLine::session_position (AutomationList::const_iterator p) const
+{
+       return _time_converter->to ((*p)->when) + _offset + _time_converter->origin_b ();
+}
+
 void
 AutomationLine::set_offset (framepos_t off)
 {
index 841d7e6f554b27f7b1833bef5855923428b204d4..82debde51b8d9d5c695b42aba8873d363b654307 100644 (file)
@@ -66,7 +66,6 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible
        void reset ();
        void clear ();
 
-       std::list<ControlPoint*> point_selection_to_control_points (PointSelection const &);
        void set_selected_points (PointSelection const &);
        void get_selectables (ARDOUR::framepos_t, ARDOUR::framepos_t, double, double, std::list<Selectable*>&);
        void get_inverted_selectables (Selection&, std::list<Selectable*>& results);
@@ -145,6 +144,8 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible
        void set_offset (ARDOUR::framecnt_t);
        void set_width (ARDOUR::framecnt_t);
 
+       framepos_t session_position (ARDOUR::AutomationList::const_iterator) const;
+
   protected:
 
        std::string    _name;
@@ -153,7 +154,7 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible
 
        boost::shared_ptr<ARDOUR::AutomationList> alist;
        Evoral::TimeConverter<double, ARDOUR::framepos_t>* _time_converter;
-       /** true if _time_converter belongs to us (ie we should delete it) */
+       /** true if _time_converter belongs to us (ie we should delete it on destruction) */
        bool _our_time_converter;
 
        bool    _visible                  : 1;
index 586e2aef185b97fe46276385ba409baa34f9b06a..738e835cce7a3aaaa96f5df5001134fe95c72aaa 100644 (file)
@@ -44,6 +44,7 @@
 #include "rgb_macros.h"
 #include "point_selection.h"
 #include "canvas_impl.h"
+#include "control_point.h"
 #include "utils.h"
 
 #include "i18n.h"
@@ -592,172 +593,6 @@ AutomationTimeAxisView::add_automation_event (GdkEvent* event, framepos_t when,
        _session->set_dirty ();
 }
 
-void
-AutomationTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
-{
-       list<boost::shared_ptr<AutomationLine> > lines;
-       if (_line) {
-               lines.push_back (_line);
-       } else if (_view) {
-               lines = _view->get_lines ();
-       }
-
-       for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
-               cut_copy_clear_one (**i, selection, op);
-       }
-}
-
-void
-AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& selection, CutCopyOp op)
-{
-       boost::shared_ptr<Evoral::ControlList> what_we_got;
-       boost::shared_ptr<AutomationList> alist (line.the_list());
-
-       XMLNode &before = alist->get_state();
-
-       /* convert time selection to automation list model coordinates */
-       const Evoral::TimeConverter<double, ARDOUR::framepos_t>& tc = line.time_converter ();
-       double const start = tc.from (selection.time.front().start - tc.origin_b ());
-       double const end = tc.from (selection.time.front().end - tc.origin_b ());
-
-       switch (op) {
-       case Delete:
-               if (alist->cut (start, end) != 0) {
-                       _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
-               }
-               break;
-
-       case Cut:
-
-               if ((what_we_got = alist->cut (start, end)) != 0) {
-                       _editor.get_cut_buffer().add (what_we_got);
-                       _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
-               }
-               break;
-       case Copy:
-               if ((what_we_got = alist->copy (start, end)) != 0) {
-                       _editor.get_cut_buffer().add (what_we_got);
-               }
-               break;
-
-       case Clear:
-               if ((what_we_got = alist->cut (start, end)) != 0) {
-                       _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
-               }
-               break;
-       }
-
-       if (what_we_got) {
-               for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
-                       double when = (*x)->when;
-                       double val  = (*x)->value;
-                       line.model_to_view_coord (when, val);
-                       (*x)->when = when;
-                       (*x)->value = val;
-               }
-       }
-}
-
-void
-AutomationTimeAxisView::reset_objects (PointSelection& selection)
-{
-       list<boost::shared_ptr<AutomationLine> > lines;
-       if (_line) {
-               lines.push_back (_line);
-       } else if (_view) {
-               lines = _view->get_lines ();
-       }
-
-       for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
-               reset_objects_one (**i, selection);
-       }
-}
-
-void
-AutomationTimeAxisView::reset_objects_one (AutomationLine& line, PointSelection& selection)
-{
-       boost::shared_ptr<AutomationList> alist(line.the_list());
-
-       _session->add_command (new MementoCommand<AutomationList>(*alist.get(), &alist->get_state(), 0));
-
-       for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
-
-               if ((*i).track != this) {
-                       continue;
-               }
-
-               alist->reset_range ((*i).start, (*i).end);
-       }
-}
-
-void
-AutomationTimeAxisView::cut_copy_clear_objects (PointSelection& selection, CutCopyOp op)
-{
-       list<boost::shared_ptr<AutomationLine> > lines;
-       if (_line) {
-               lines.push_back (_line);
-       } else if (_view) {
-               lines = _view->get_lines ();
-       }
-
-       for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
-               cut_copy_clear_objects_one (**i, selection, op);
-       }
-}
-
-void
-AutomationTimeAxisView::cut_copy_clear_objects_one (AutomationLine& line, PointSelection& selection, CutCopyOp op)
-{
-       boost::shared_ptr<Evoral::ControlList> what_we_got;
-       boost::shared_ptr<AutomationList> alist(line.the_list());
-
-       XMLNode &before = alist->get_state();
-
-       for (PointSelection::iterator i = selection.begin(); i != selection.end(); ++i) {
-
-               if ((*i).track != this) {
-                       continue;
-               }
-
-               switch (op) {
-               case Delete:
-                       if (alist->cut ((*i).start, (*i).end) != 0) {
-                               _session->add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
-                       }
-                       break;
-               case Cut:
-                       if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
-                               _editor.get_cut_buffer().add (what_we_got);
-                               _session->add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
-                       }
-                       break;
-               case Copy:
-                       if ((what_we_got = alist->copy ((*i).start, (*i).end)) != 0) {
-                               _editor.get_cut_buffer().add (what_we_got);
-                       }
-                       break;
-
-               case Clear:
-                       if ((what_we_got = alist->cut ((*i).start, (*i).end)) != 0) {
-                               _session->add_command (new MementoCommand<AutomationList>(*alist.get(), new XMLNode (before), &alist->get_state()));
-                       }
-                       break;
-               }
-       }
-
-       delete &before;
-
-       if (what_we_got) {
-               for (AutomationList::iterator x = what_we_got->begin(); x != what_we_got->end(); ++x) {
-                       double when = (*x)->when;
-                       double val  = (*x)->value;
-                       line.model_to_view_coord (when, val);
-                       (*x)->when = when;
-                       (*x)->value = val;
-               }
-       }
-}
-
 /** Paste a selection.
  *  @param pos Position to paste to (session frames).
  *  @param times Number of times to paste.
@@ -794,25 +629,10 @@ AutomationTimeAxisView::paste_one (AutomationLine& line, framepos_t pos, float t
                return false;
        }
 
-       /* Make a copy of the list because we have to scale the
-          values from view coordinates to model coordinates, and we're
-          not supposed to modify the points in the selection.
-       */
-
-       AutomationList copy (**p);
-
-       for (AutomationList::iterator x = copy.begin(); x != copy.end(); ++x) {
-               double when = (*x)->when;
-               double val  = (*x)->value;
-               line.view_to_model_coord (when, val);
-               (*x)->when = when;
-               (*x)->value = val;
-       }
-
        double const model_pos = line.time_converter().from (pos - line.time_converter().origin_b ());
 
        XMLNode &before = alist->get_state();
-       alist->paste (copy, model_pos, times);
+       alist->paste (**p, model_pos, times);
        _session->add_command (new MementoCommand<AutomationList>(*alist.get(), &before, &alist->get_state()));
 
        return true;
index 7706ed7ee31469bb97f4429468857c03d8232dfa..913cd1b467a57ff4660d45e4dff1936051feb768 100644 (file)
@@ -91,10 +91,7 @@ class AutomationTimeAxisView : public TimeAxisView {
 
        /* editing operations */
 
-       void cut_copy_clear (Selection&, Editing::CutCopyOp);
-       void cut_copy_clear_objects (PointSelection&, Editing::CutCopyOp);
        bool paste (ARDOUR::framepos_t, float times, Selection&, size_t nth);
-       void reset_objects (PointSelection&);
 
        int  set_state (const XMLNode&, int version);
 
@@ -169,10 +166,7 @@ class AutomationTimeAxisView : public TimeAxisView {
 
        void build_display_menu ();
 
-       void cut_copy_clear_one (AutomationLine&, Selection&, Editing::CutCopyOp);
-       void cut_copy_clear_objects_one (AutomationLine&, PointSelection&, Editing::CutCopyOp);
        bool paste_one (AutomationLine&, ARDOUR::framepos_t, float times, Selection&, size_t nth);
-       void reset_objects_one (AutomationLine&, PointSelection&);
        void route_going_away ();
 
        void set_automation_state (ARDOUR::AutoState);
index bc7301dc1cdeffa3d40d09a4d74a1c6f0b00780f..d869e094aad16ffc3fd52494b35244165d97814c 100644 (file)
@@ -30,6 +30,8 @@ using namespace ARDOUR;
 using namespace PBD;
 using namespace Gnome; // for Canvas
 
+PBD::Signal1<void, ControlPoint *> ControlPoint::CatchDeletion;
+
 ControlPoint::ControlPoint (AutomationLine& al)
        : _line (al)
 {
@@ -82,6 +84,8 @@ ControlPoint::ControlPoint (const ControlPoint& other, bool /*dummy_arg_to_force
 
 ControlPoint::~ControlPoint ()
 {
+       CatchDeletion (this); /* EMIT SIGNAL */
+       
        delete _item;
 }
 
index 603d062ec40273cf1b3e73a5412b87885d4a7fdf..0c2bf1e01d6d7682ebda600ee4bcda6b790d8fe5 100644 (file)
@@ -83,6 +83,8 @@ class ControlPoint : public Selectable
        ARDOUR::AutomationList::iterator model() const { return _model; }
        AutomationLine&                  line()  const { return _line; }
 
+       static PBD::Signal1<void, ControlPoint *> CatchDeletion;
+       
   private:
        ArdourCanvas::SimpleRect*        _item;
        AutomationLine&                  _line;
index 6b48311b159bf04e1cc8fcb2f5650b9bca0bfefd..bae511e031e748a2ca73d39805a09a20b48f40e9 100644 (file)
@@ -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 ();
        }
 }
 
index 85acc90ec8fc57eb16e83d3ea191bb85608f9c3b..5ed5ae1573c29a7ee45b568387c8a5cf489ab79c 100644 (file)
 #define __ardour_gtk_point_selection_h__
 
 #include <list>
-#include <boost/noncopyable.hpp>
 
-#include "automation_range.h"
+class ControlPoint;
 
-struct PointSelection : public std::list<AutomationRange>
+struct PointSelection : public std::list<ControlPoint *>
 {
 };
 
index 4d9262bb3a7179035637f201852c16d55a9de627..afc13f1b411244935e052363a45a44d86158d291 100644 (file)
@@ -62,6 +62,9 @@ Selection::Selection (const PublicEditor* e)
 
        void (Selection::*marker_remove)(Marker*) = &Selection::remove;
        Marker::CatchDeletion.connect (*this, MISSING_INVALIDATOR, ui_bind (marker_remove, this, _1), gui_context());
+
+       void (Selection::*point_remove)(ControlPoint*) = &Selection::remove;
+       ControlPoint::CatchDeletion.connect (*this, MISSING_INVALIDATOR, ui_bind (point_remove, this, _1), gui_context());
 }
 
 #if 0
@@ -516,7 +519,6 @@ Selection::add (boost::shared_ptr<Evoral::ControlList> cl)
        if (!al) {
                warning << "Programming error: Selected list is not an ARDOUR::AutomationList" << endmsg;
                return;
-               return;
        }
        if (find (lines.begin(), lines.end(), al) == lines.end()) {
                lines.push_back (al);
@@ -536,6 +538,15 @@ Selection::remove (TimeAxisView* track)
        }
 }
 
+void
+Selection::remove (ControlPoint* p)
+{
+       PointSelection::iterator i = find (points.begin(), points.end(), p);
+       if (i != points.end ()) {
+               points.erase (i);
+       }
+}
+
 void
 Selection::remove (const TrackViewList& track_list)
 {
@@ -879,17 +890,22 @@ void
 Selection::toggle (ControlPoint* cp)
 {
        cp->set_selected (!cp->get_selected ());
-       set_point_selection_from_line (cp->line ());
+       PointSelection::iterator i = find (points.begin(), points.end(), cp);
+       if (i == points.end()) {
+               points.push_back (cp);
+       } else {
+               points.erase (i);
+       }
+
+       PointsChanged (); /* EMIT SIGNAL */
 }
 
 void
 Selection::toggle (vector<ControlPoint*> const & cps)
 {
        for (vector<ControlPoint*>::const_iterator i = cps.begin(); i != cps.end(); ++i) {
-               (*i)->set_selected (!(*i)->get_selected ());
+               toggle (*i);
        }
-
-       set_point_selection_from_line (cps.front()->line ());
 }
 
 void
@@ -935,6 +951,13 @@ Selection::set (list<Selectable*> const & selectables)
        add (selectables);
 }
 
+void
+Selection::add (PointSelection const & s)
+{
+       for (PointSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
+               points.push_back (*i);
+       }
+}
 
 void
 Selection::add (list<Selectable*> const & selectables)
@@ -979,17 +1002,16 @@ void
 Selection::add (ControlPoint* cp)
 {
        cp->set_selected (true);
-       set_point_selection_from_line (cp->line ());
+       points.push_back (cp);
+       PointsChanged (); /* EMIT SIGNAL */
 }
 
 void
 Selection::add (vector<ControlPoint*> const & cps)
 {
        for (vector<ControlPoint*>::const_iterator i = cps.begin(); i != cps.end(); ++i) {
-               (*i)->set_selected (true);
+               add (*i);
        }
-
-       set_point_selection_from_line (cps.front()->line ());
 }
 
 void
@@ -999,18 +1021,11 @@ Selection::set (ControlPoint* cp)
                return;
        }
 
-       /* We're going to set up the PointSelection from the selected ControlPoints
-          on this point's line, so we need to deselect all ControlPoints before
-          we re-add this one.
-       */
-
        for (uint32_t i = 0; i < cp->line().npoints(); ++i) {
                cp->line().nth (i)->set_selected (false);
        }
 
-       vector<ControlPoint*> cps;
-       cps.push_back (cp);
-       add (cps);
+       add (cp);
 }
 
 void
@@ -1083,73 +1098,6 @@ MarkerSelection::range (framepos_t& s, framepos_t& e)
        e = std::max (s, e);
 }
 
-/** Automation control point selection is mostly manipulated using the selected state
- *  of the ControlPoints themselves.  For example, to add a point to a selection, its
- *  ControlPoint is marked as selected and then this method is called.  It sets up
- *  our PointSelection from the selected ControlPoints of a given AutomationLine.
- *
- *  We can't use ControlPoints directly in the selection, as we need to express a
- *  selection of not just a visible ControlPoint but also (possibly) some invisible
- *  points nearby.  Hence the selection stores AutomationRanges, and these are synced
- *  with ControlPoint selection state using AutomationLine::set_selected_points.
- */
-
-void
-Selection::set_point_selection_from_line (AutomationLine const & line)
-{
-       points.clear ();
-
-       AutomationRange current (DBL_MAX, 0, 1, 0, &line.trackview);
-
-       for (uint32_t i = 0; i < line.npoints(); ++i) {
-               ControlPoint const * cp = line.nth (i);
-
-               if (cp->get_selected()) {
-                       /* x and y position of this control point in coordinates suitable for
-                          an AutomationRange (ie model time and fraction of track height)
-                       */
-                       double const x = (*(cp->model()))->when;
-                       double const y = 1 - (cp->get_y() / line.trackview.current_height ());
-
-                       /* work out the position of a rectangle the size of a control point centred
-                          on this point
-                       */
-
-                       double const size = cp->size ();
-                       double const x_size = line.time_converter().from (line.trackview.editor().pixel_to_frame (size));
-                       double const y_size = size / line.trackview.current_height ();
-
-                       double const x1 = max (0.0, x - x_size / 2);
-                       double const x2 = x + x_size / 2;
-                       double const y1 = max (0.0, y - y_size / 2);
-                       double const y2 = y + y_size / 2;
-
-                       /* extend the current AutomationRange to put this point in */
-                       current.start = min (current.start, x1);
-                       current.end = max (current.end, x2);
-                       current.low_fract = min (current.low_fract, y1);
-                       current.high_fract = max (current.high_fract, y2);
-
-               } else {
-                       /* this point isn't selected; if the current AutomationRange has some
-                          stuff in it, push it onto the list and make a new one
-                       */
-                       if (current.start < DBL_MAX) {
-                               points.push_back (current);
-                               current = AutomationRange (DBL_MAX, 0, 1, 0, &line.trackview);
-                       }
-               }
-       }
-
-       /* Maybe push the current AutomationRange, as above */
-       if (current.start < DBL_MAX) {
-               points.push_back (current);
-               current = AutomationRange (DBL_MAX, 0, 1, 0, &line.trackview);
-       }
-
-       PointsChanged (); /* EMIT SIGNAL */
-}
-
 XMLNode&
 Selection::get_state () const
 {
index c474faa5b2a23613f639fbdc0b41d10d50bbdcfc..df7212593f599b5a1eb1b90a5c496ab8c70f5f71 100644 (file)
@@ -165,6 +165,7 @@ class Selection : public sigc::trackable, public PBD::ScopedConnectionList
        void add (Marker*);
        void add (const std::list<Marker*>&);
        void add (const RegionSelection&);
+       void add (const PointSelection&);
        void remove (TimeAxisView*);
        void remove (const TrackViewList&);
        void remove (const MidiNoteSelection&);
@@ -178,6 +179,7 @@ class Selection : public sigc::trackable, public PBD::ScopedConnectionList
        void remove (const std::list<boost::shared_ptr<ARDOUR::Playlist> >&);
        void remove (const std::list<Selectable*>&);
        void remove (Marker*);
+       void remove (ControlPoint *);
 
        void remove_regions (TimeAxisView *);
 
@@ -202,8 +204,6 @@ class Selection : public sigc::trackable, public PBD::ScopedConnectionList
        int set_state (XMLNode const &, int);
 
   private:
-       void set_point_selection_from_line (AutomationLine const &);
-
        PublicEditor const * editor;
        uint32_t next_time_id;
        bool _no_tracks_changed;
index 00b760952cff4a9d3930d81a53c303cc6e0efd23..12cc8d7571f7d2eb88f25c7057e57ff4f076abca 100644 (file)
@@ -32,6 +32,8 @@
 #include "time_info_box.h"
 #include "audio_clock.h"
 #include "editor.h"
+#include "control_point.h"
+#include "automation_line.h"
 
 #include "i18n.h"
 
@@ -267,8 +269,9 @@ TimeInfoBox::selection_changed ()
                                        s = max_framepos;
                                        e = 0;
                                        for (PointSelection::iterator i = selection.points.begin(); i != selection.points.end(); ++i) {
-                                               s = min (s, (framepos_t) i->start);
-                                               e = max (e, (framepos_t) i->end);
+                                               framepos_t const p = (*i)->line().session_position ((*i)->model ());
+                                               s = min (s, p);
+                                               e = max (e, p);
                                        }
                                        selection_start->set_off (false);
                                        selection_end->set_off (false);
index 324d03cc28ee9e0a63f3bde392d34d89bd235525..30b9fca4307d594035f3034644b64f9fd2da3178 100644 (file)
@@ -123,7 +123,6 @@ public:
        void fast_simple_add (double when, double value);
        void merge_nascent (double when);
 
-       void reset_range (double start, double end);
        void erase_range (double start, double end);
        void erase (iterator);
        void erase (iterator, iterator);
index e90b28c1479fa0598942e490c77284cf17b42151..9c38f67b299315e66e713f8ed583fdf7ff73022a 100644 (file)
@@ -557,37 +557,6 @@ ControlList::erase (double when, double value)
        maybe_signal_changed ();
 }
 
-void
-ControlList::reset_range (double start, double endt)
-{
-       bool reset = false;
-
-       {
-               Glib::Mutex::Lock lm (_lock);
-               ControlEvent cp (start, 0.0f);
-               iterator s;
-               iterator e;
-
-               if ((s = lower_bound (_events.begin(), _events.end(), &cp, time_comparator)) != _events.end()) {
-
-                       cp.when = endt;
-                       e = upper_bound (_events.begin(), _events.end(), &cp, time_comparator);
-
-                       for (iterator i = s; i != e; ++i) {
-                               (*i)->value = _default_value;
-                       }
-
-                       reset = true;
-
-                       mark_dirty ();
-               }
-       }
-
-       if (reset) {
-               maybe_signal_changed ();
-       }
-}
-
 void
 ControlList::erase_range (double start, double endt)
 {