+AutomationLine::ContiguousControlPoints::ContiguousControlPoints (AutomationLine& al)
+ : line (al), before_x (0), after_x (DBL_MAX)
+{
+}
+
+void
+AutomationLine::ContiguousControlPoints::compute_x_bounds ()
+{
+ uint32_t sz = size();
+
+ if (sz > 0 && sz < line.npoints()) {
+
+ /* determine the limits on x-axis motion for this
+ contiguous range of control points
+ */
+
+ if (front()->view_index() > 0) {
+ before_x = line.nth (front()->view_index() - 1)->get_x();
+ }
+
+ /* if our last point has a point after it in the line,
+ we have an "after" bound
+ */
+
+ if (back()->view_index() < (line.npoints() - 2)) {
+ after_x = line.nth (back()->view_index() + 1)->get_x();
+ }
+ }
+}
+
+double
+AutomationLine::ContiguousControlPoints::clamp_dx (double dx)
+{
+ if (empty()) {
+ return dx;
+ }
+
+ /* get the maximum distance we can move any of these points along the x-axis
+ */
+
+ double tx; /* possible position a point would move to, given dx */
+ ControlPoint* cp;
+
+ if (dx > 0) {
+ /* check the last point, since we're moving later in time */
+ cp = back();
+ } else {
+ /* check the first point, since we're moving earlier in time */
+ cp = front();
+ }
+
+ tx = cp->get_x() + dx; // new possible position if we just add the motion
+ tx = max (tx, before_x); // can't move later than following point
+ tx = min (tx, after_x); // can't move earlier than preceeding point
+ return tx - cp->get_x ();
+}
+
+void
+AutomationLine::ContiguousControlPoints::move (double dx, double dy)
+{
+ for (std::list<ControlPoint*>::iterator i = begin(); i != end(); ++i) {
+ (*i)->move_to ((*i)->get_x() + dx, (*i)->get_y() - line.height() * dy, ControlPoint::Full);
+ line.reset_line_coords (**i);
+ }
+}
+