+Selection::add (ControlPoint* cp)
+{
+ cp->set_selected (true);
+ set_point_selection_from_line (cp->line ());
+}
+
+void
+Selection::add (vector<ControlPoint*> const & cps)
+{
+ for (vector<ControlPoint*>::const_iterator i = cps.begin(); i != cps.end(); ++i) {
+ (*i)->set_selected (true);
+ }
+
+ set_point_selection_from_line (cps.front()->line ());
+}
+
+void
+Selection::set (ControlPoint* cp)
+{
+ if (cp->get_selected()) {
+ 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);
+}
+
+void
+Selection::set (Marker* m)
+{
+ clear_markers ();
+ add (m);
+}
+
+void
+Selection::toggle (Marker* m)
+{
+ MarkerSelection::iterator i;
+
+ if ((i = find (markers.begin(), markers.end(), m)) == markers.end()) {
+ add (m);
+ } else {
+ remove (m);
+ }
+}
+
+void
+Selection::remove (Marker* m)
+{
+ MarkerSelection::iterator i;
+
+ if ((i = find (markers.begin(), markers.end(), m)) != markers.end()) {
+ markers.erase (i);
+ MarkersChanged();
+ }
+}
+
+void
+Selection::add (Marker* m)
+{
+ if (find (markers.begin(), markers.end(), m) == markers.end()) {
+ markers.push_back (m);
+ MarkersChanged();
+ }
+}
+
+void
+Selection::add (const list<Marker*>& m)
+{
+ markers.insert (markers.end(), m.begin(), m.end());
+ MarkersChanged ();
+}
+
+void
+MarkerSelection::range (framepos_t& s, framepos_t& e)
+{
+ s = max_framepos;
+ e = 0;
+
+ for (MarkerSelection::iterator i = begin(); i != end(); ++i) {
+
+ if ((*i)->position() < s) {
+ s = (*i)->position();
+ }
+
+ if ((*i)->position() > e) {
+ e = (*i)->position();
+ }
+ }
+
+ s = std::min (s, 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)