2 Copyright (C) 2002-2003 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include <pbd/stl_delete.h>
26 #include <pbd/memento_command.h>
27 #include <pbd/stacktrace.h>
29 #include <ardour/automation_event.h>
30 #include <ardour/curve.h>
31 #include <ardour/dB.h>
33 #include "simplerect.h"
34 #include "automation_line.h"
35 #include "rgb_macros.h"
36 #include "ardour_ui.h"
37 #include "public_editor.h"
39 #include "selection.h"
40 #include "time_axis_view.h"
41 #include "point_selection.h"
42 #include "automation_selectable.h"
43 #include "automation_time_axis.h"
44 #include "public_editor.h"
46 #include <ardour/session.h>
52 using namespace ARDOUR;
54 using namespace Editing;
55 using namespace Gnome; // for Canvas
57 ControlPoint::ControlPoint (AutomationLine& al)
60 model = al.the_list()->end();
69 item = new Canvas::SimpleRect (line.canvas_group());
70 item->property_draw() = true;
71 item->property_fill() = false;
72 item->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_ControlPointFill.get();
73 item->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_ControlPointOutline.get();
74 item->property_outline_pixels() = 1;
75 item->set_data ("control_point", this);
76 item->signal_event().connect (mem_fun (this, &ControlPoint::event_handler));
82 ControlPoint::ControlPoint (const ControlPoint& other, bool dummy_arg_to_force_special_copy_constructor)
90 view_index = other.view_index;
91 can_slide = other.can_slide;
94 _shape = other._shape;
98 item = new Canvas::SimpleRect (line.canvas_group());
99 item->property_fill() = false;
100 item->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_EnteredControlPointOutline.get();
101 item->property_outline_pixels() = 1;
103 /* NOTE: no event handling in copied ControlPoints */
109 ControlPoint::~ControlPoint ()
115 ControlPoint::event_handler (GdkEvent* event)
117 return PublicEditor::instance().canvas_control_point_event (event, item, this);
121 ControlPoint::hide ()
133 ControlPoint::set_visible (bool yn)
135 item->property_draw() = (gboolean) yn;
139 ControlPoint::reset (double x, double y, AutomationList::iterator mi, uint32_t vi, ShapeType shape)
143 move_to (x, y, shape);
147 ControlPoint::show_color (bool entered, bool hide_too)
151 item->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_EnteredControlPointSelected.get();
154 item->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_EnteredControlPoint.get();
162 item->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_ControlPointSelected.get();
165 item->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_ControlPoint.get();
174 ControlPoint::set_size (double sz)
180 item->property_fill() = (gboolean) TRUE;
182 item->property_fill() = (gboolean) FALSE;
186 move_to (_x, _y, _shape);
190 ControlPoint::move_to (double x, double y, ShapeType shape)
194 double half_size = rint(_size/2.0);
211 item->property_x1() = x1;
212 item->property_x2() = x2;
213 item->property_y1() = y - half_size;
214 item->property_y2() = y + half_size;
223 AutomationLine::AutomationLine (const string & name, TimeAxisView& tv, ArdourCanvas::Group& parent, boost::shared_ptr<AutomationList> al)
227 _parent_group (parent)
229 points_visible = false;
230 update_pending = false;
231 _vc_uses_gain_mapping = false;
234 terminal_points_can_slide = true;
238 group = new ArdourCanvas::Group (parent);
239 group->property_x() = 0.0;
240 group->property_y() = 0.0;
242 line = new ArdourCanvas::Line (*group);
243 line->property_width_pixels() = (guint)1;
244 line->set_data ("line", this);
246 line->signal_event().connect (mem_fun (*this, &AutomationLine::event_handler));
248 alist->StateChanged.connect (mem_fun(*this, &AutomationLine::list_changed));
250 trackview.session().register_with_memento_command_factory(alist->id(), this);
253 AutomationLine::~AutomationLine ()
255 vector_delete (&control_points);
260 AutomationLine::event_handler (GdkEvent* event)
262 return PublicEditor::instance().canvas_line_event (event, line, this);
266 AutomationLine::queue_reset ()
268 if (!update_pending) {
269 update_pending = true;
270 Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &AutomationLine::reset));
275 AutomationLine::show ()
279 if (points_visible) {
280 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
289 AutomationLine::hide ()
292 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
299 AutomationLine::control_point_box_size ()
301 if (_height > TimeAxisView::hLarger) {
303 } else if (_height > (guint32) TimeAxisView::hNormal) {
310 AutomationLine::set_y_position_and_height (guint32 y, guint32 h)
312 bool changed = false;
314 if (y != _y_position) {
322 double const bsz = control_point_box_size();
324 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
325 (*i)->set_size (bsz);
336 AutomationLine::set_line_color (uint32_t color)
339 line->property_fill_color_rgba() = color;
343 AutomationLine::set_verbose_cursor_uses_gain_mapping (bool yn)
345 if (yn != _vc_uses_gain_mapping) {
346 _vc_uses_gain_mapping = yn;
352 AutomationLine::nth (uint32_t n)
354 if (n < control_points.size()) {
355 return control_points[n];
362 AutomationLine::modify_view_point (ControlPoint& cp, double x, double y, bool with_push)
365 uint32_t last_movable = UINT_MAX;
366 double x_limit = DBL_MAX;
368 /* this just changes the current view. it does not alter
369 the model in any way at all.
372 /* clamp y-coord appropriately. y is supposed to be a normalized fraction (0.0-1.0),
373 and needs to be converted to a canvas unit distance.
378 y = _y_position + _height - (y * _height);
382 /* x-coord cannot move beyond adjacent points or the start/end, and is
383 already in frames. it needs to be converted to canvas units.
386 x = trackview.editor.frame_to_unit (x);
388 /* clamp x position using view coordinates */
390 ControlPoint *before;
394 before = nth (cp.view_index - 1);
395 x = max (x, before->get_x()+1.0);
402 if (cp.view_index < control_points.size() - 1) {
404 after = nth (cp.view_index + 1);
406 /*if it is a "spike" leave the x alone */
408 if (after->get_x() - before->get_x() < 2) {
412 x = min (x, after->get_x()-1.0);
422 /* find the first point that can't move */
424 for (uint32_t n = cp.view_index + 1; (after = nth (n)) != 0; ++n) {
425 if (!after->can_slide) {
426 x_limit = after->get_x() - 1.0;
427 last_movable = after->view_index;
432 delta = x - cp.get_x();
437 /* leave the x-coordinate alone */
439 x = trackview.editor.frame_to_unit ((*cp.model)->when);
445 cp.move_to (x, y, ControlPoint::Full);
446 reset_line_coords (cp);
450 uint32_t limit = min (control_points.size(), (size_t)last_movable);
452 /* move the current point to wherever the user told it to go, subject
456 cp.move_to (min (x, x_limit), y, ControlPoint::Full);
457 reset_line_coords (cp);
459 /* now move all subsequent control points, to reflect the motion.
462 for (uint32_t i = cp.view_index + 1; i < limit; ++i) {
463 ControlPoint *p = nth (i);
467 new_x = min (p->get_x() + delta, x_limit);
468 p->move_to (new_x, p->get_y(), ControlPoint::Full);
469 reset_line_coords (*p);
476 AutomationLine::reset_line_coords (ControlPoint& cp)
478 if (cp.view_index < line_points.size()) {
479 line_points[cp.view_index].set_x (cp.get_x());
480 line_points[cp.view_index].set_y (cp.get_y());
485 AutomationLine::sync_model_with_view_line (uint32_t start, uint32_t end)
490 update_pending = true;
492 for (uint32_t i = start; i <= end; ++i) {
494 sync_model_with_view_point (*p, false, 0);
499 AutomationLine::model_representation (ControlPoint& cp, ModelRepresentation& mr)
501 /* part one: find out where the visual control point is.
502 initial results are in canvas units. ask the
503 line to convert them to something relevant.
506 mr.xval = (nframes_t) floor (cp.get_x());
507 mr.yval = 1.0 - ( (cp.get_y() - _y_position) / _height);
509 /* if xval has not changed, set it directly from the model to avoid rounding errors */
511 if (mr.xval == trackview.editor.frame_to_unit((*cp.model)->when)) {
512 mr.xval = (nframes_t) (*cp.model)->when;
514 mr.xval = trackview.editor.unit_to_frame (mr.xval);
517 /* virtual call: this will do the right thing
518 for whatever particular type of line we are.
521 view_to_model_y (mr.yval);
523 /* part 2: find out where the model point is now
526 mr.xpos = (nframes_t) (*cp.model)->when;
527 mr.ypos = (*cp.model)->value;
529 /* part 3: get the position of the visual control
530 points before and after us.
533 ControlPoint* before;
537 before = nth (cp.view_index - 1);
542 after = nth (cp.view_index + 1);
545 mr.xmin = (nframes_t) (*before->model)->when;
546 mr.ymin = (*before->model)->value;
547 mr.start = before->model;
556 mr.end = after->model;
566 AutomationLine::determine_visible_control_points (ALPoints& points)
568 uint32_t view_index, pi, n;
569 AutomationList::iterator model;
571 double last_control_point_x = 0.0;
572 double last_control_point_y = 0.0;
573 uint32_t this_rx = 0;
574 uint32_t prev_rx = 0;
575 uint32_t this_ry = 0;
576 uint32_t prev_ry = 0;
581 /* hide all existing points, and the line */
585 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
592 if (points.empty()) {
596 npoints = points.size();
598 /* compute derivative/slope for the entire line */
600 slope = new double[npoints];
602 for (n = 0; n < npoints - 1; ++n) {
603 double xdelta = points[n+1].x - points[n].x;
604 double ydelta = points[n+1].y - points[n].y;
605 slope[n] = ydelta/xdelta;
608 box_size = (uint32_t) control_point_box_size ();
610 /* read all points and decide which ones to show as control points */
614 for (model = alist->begin(), pi = 0; pi < npoints; ++model, ++pi) {
616 double tx = points[pi].x;
617 double ty = points[pi].y;
619 /* now ensure that the control_points vector reflects the current curve
620 state, but don't plot control points too close together. also, don't
621 plot a series of points all with the same value.
623 always plot the first and last points, of course.
626 if (invalid_point (points, pi)) {
627 /* for some reason, we are supposed to ignore this point,
628 but still keep track of the model index.
633 if (pi > 0 && pi < npoints - 1) {
634 if (slope[pi] == slope[pi-1]) {
636 /* no reason to display this point */
642 /* need to round here. the ultimate coordinates are integer
643 pixels, so tiny deltas in the coords will be eliminated
644 and we end up with "colinear" line segments. since the
645 line rendering code in libart doesn't like this very
646 much, we eliminate them here. don't do this for the first and last
650 this_rx = (uint32_t) rint (tx);
651 this_ry = (uint32_t) rint (ty);
653 if (view_index && pi != npoints && /* not the first, not the last */
654 (((this_rx == prev_rx) && (this_ry == prev_ry)) || /* same point */
655 (((this_rx - prev_rx) < (box_size + 2)) && /* not identical, but still too close horizontally */
656 (abs ((int)(this_ry - prev_ry)) < (int) (box_size + 2))))) { /* too close vertically */
660 /* ok, we should display this point */
662 if (view_index >= cpsize) {
664 /* make sure we have enough control points */
666 ControlPoint* ncp = new ControlPoint (*this);
668 ncp->set_size (box_size);
670 control_points.push_back (ncp);
674 ControlPoint::ShapeType shape;
676 if (!terminal_points_can_slide) {
678 control_points[view_index]->can_slide = false;
680 shape = ControlPoint::Start;
682 shape = ControlPoint::Full;
684 } else if (pi == npoints - 1) {
685 control_points[view_index]->can_slide = false;
686 shape = ControlPoint::End;
688 control_points[view_index]->can_slide = true;
689 shape = ControlPoint::Full;
692 control_points[view_index]->can_slide = true;
693 shape = ControlPoint::Full;
696 last_control_point_x = tx;
697 last_control_point_y = ty;
699 control_points[view_index]->reset (tx, ty, model, view_index, shape);
704 /* finally, control visibility */
706 if (_visible && points_visible) {
707 control_points[view_index]->show ();
708 control_points[view_index]->set_visible (true);
710 if (!points_visible) {
711 control_points[view_index]->set_visible (false);
718 /* discard extra CP's to avoid confusing ourselves */
720 while (control_points.size() > view_index) {
721 ControlPoint* cp = control_points.back();
722 control_points.pop_back ();
726 if (!terminal_points_can_slide) {
727 control_points.back()->can_slide = false;
732 if (view_index > 1) {
734 npoints = view_index;
736 /* reset the line coordinates */
738 while (line_points.size() < npoints) {
739 line_points.push_back (Art::Point (0,0));
742 while (line_points.size() > npoints) {
743 line_points.pop_back ();
746 for (view_index = 0; view_index < npoints; ++view_index) {
747 line_points[view_index].set_x (control_points[view_index]->get_x());
748 line_points[view_index].set_y (control_points[view_index]->get_y());
751 line->property_points() = line_points;
759 set_selected_points (trackview.editor.get_selection().points);
764 AutomationLine::get_verbose_cursor_string (float fraction)
768 if (_vc_uses_gain_mapping) {
769 if (fraction == 0.0) {
770 snprintf (buf, sizeof (buf), "-inf dB");
772 snprintf (buf, sizeof (buf), "%.1fdB", coefficient_to_dB (slider_position_to_gain (fraction)));
775 snprintf (buf, sizeof (buf), "%.2f", fraction);
782 AutomationLine::invalid_point (ALPoints& p, uint32_t index)
784 return p[index].x == max_frames && p[index].y == DBL_MAX;
788 AutomationLine::invalidate_point (ALPoints& p, uint32_t index)
790 p[index].x = max_frames;
791 p[index].y = DBL_MAX;
795 AutomationLine::start_drag (ControlPoint* cp, nframes_t x, float fraction)
797 if (trackview.editor.current_session() == 0) { /* how? */
804 str = _("automation event move");
806 str = _("automation range drag");
809 trackview.editor.current_session()->begin_reversible_command (str);
810 trackview.editor.current_session()->add_command (new MementoCommand<AutomationList>(*alist.get(), &get_state(), 0));
814 first_drag_fraction = fraction;
815 last_drag_fraction = fraction;
821 AutomationLine::point_drag (ControlPoint& cp, nframes_t x, float fraction, bool with_push)
824 drag_distance += (x - drag_x);
826 drag_distance -= (drag_x - x);
831 modify_view_point (cp, x, fraction, with_push);
833 if (line_points.size() > 1) {
834 line->property_points() = line_points;
838 did_push = with_push;
842 AutomationLine::line_drag (uint32_t i1, uint32_t i2, float fraction, bool with_push)
844 double const ydelta = fraction - last_drag_fraction;
846 did_push = with_push;
848 last_drag_fraction = fraction;
855 for (uint32_t i = i1 ; i <= i2; i++) {
857 modify_view_point (*cp, trackview.editor.unit_to_frame (cp->get_x()), ((_height - cp->get_y() + _y_position) /_height) + ydelta, with_push);
860 if (line_points.size() > 1) {
861 line->property_points() = line_points;
868 AutomationLine::end_drag (ControlPoint* cp)
877 sync_model_with_view_point (*cp, did_push, drag_distance);
879 sync_model_with_view_line (line_drag_cp1, line_drag_cp2);
884 update_pending = false;
886 trackview.editor.current_session()->add_command (new MementoCommand<AutomationList>(*alist.get(), 0, &alist->get_state()));
887 trackview.editor.current_session()->commit_reversible_command ();
888 trackview.editor.current_session()->set_dirty ();
893 AutomationLine::sync_model_with_view_point (ControlPoint& cp, bool did_push, int64_t distance)
895 ModelRepresentation mr;
898 model_representation (cp, mr);
900 /* how much are we changing the central point by */
902 ydelta = mr.yval - mr.ypos;
905 apply the full change to the central point, and interpolate
906 on both axes to cover all model points represented
907 by the control point.
910 /* change all points before the primary point */
912 for (AutomationList::iterator i = mr.start; i != cp.model; ++i) {
914 double fract = ((*i)->when - mr.xmin) / (mr.xpos - mr.xmin);
915 double y_delta = ydelta * fract;
916 double x_delta = distance * fract;
920 if (y_delta || x_delta) {
921 alist->modify (i, (*i)->when + x_delta, mr.ymin + y_delta);
925 /* change the primary point */
927 update_pending = true;
928 alist->modify (cp.model, mr.xval, mr.yval);
931 /* change later points */
933 AutomationList::iterator i = cp.model;
937 while (i != mr.end) {
939 double delta = ydelta * (mr.xmax - (*i)->when) / (mr.xmax - mr.xpos);
941 /* all later points move by the same distance along the x-axis as the main point */
944 alist->modify (i, (*i)->when + distance, (*i)->value + delta);
952 /* move all points after the range represented by the view by the same distance
953 as the main point moved.
956 alist->slide (mr.end, drag_distance);
962 AutomationLine::control_points_adjacent (double xval, uint32_t & before, uint32_t& after)
964 ControlPoint *bcp = 0;
965 ControlPoint *acp = 0;
968 /* xval is in frames */
970 unit_xval = trackview.editor.frame_to_unit (xval);
972 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
974 if ((*i)->get_x() <= unit_xval) {
976 if (!bcp || (*i)->get_x() > bcp->get_x()) {
978 before = bcp->view_index;
981 } else if ((*i)->get_x() > unit_xval) {
983 after = acp->view_index;
992 AutomationLine::is_last_point (ControlPoint& cp)
994 ModelRepresentation mr;
996 model_representation (cp, mr);
998 // If the list is not empty, and the point is the last point in the list
1000 if (!alist->empty() && mr.end == alist->end()) {
1008 AutomationLine::is_first_point (ControlPoint& cp)
1010 ModelRepresentation mr;
1012 model_representation (cp, mr);
1014 // If the list is not empty, and the point is the first point in the list
1016 if (!alist->empty() && mr.start == alist->begin()) {
1023 // This is copied into AudioRegionGainLine
1025 AutomationLine::remove_point (ControlPoint& cp)
1027 ModelRepresentation mr;
1029 model_representation (cp, mr);
1031 trackview.editor.current_session()->begin_reversible_command (_("remove control point"));
1032 XMLNode &before = alist->get_state();
1034 alist->erase (mr.start, mr.end);
1036 trackview.editor.current_session()->add_command(new MementoCommand<AutomationList>(
1037 *alist.get(), &before, &alist->get_state()));
1038 trackview.editor.current_session()->commit_reversible_command ();
1039 trackview.editor.current_session()->set_dirty ();
1043 AutomationLine::get_selectables (nframes_t& start, nframes_t& end,
1044 double botfrac, double topfrac, list<Selectable*>& results)
1051 bool collecting = false;
1053 /* Curse X11 and its inverted coordinate system! */
1055 bot = _y_position + (1.0 - topfrac) * _height;
1056 top = _y_position + (1.0 - botfrac) * _height;
1058 nstart = max_frames;
1061 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
1063 nframes_t when = (nframes_t) (*(*i)->model)->when;
1065 if (when >= start && when <= end) {
1067 if ((*i)->get_y() >= bot && (*i)->get_y() <= top) {
1070 (*i)->set_visible(true);
1072 nstart = min (nstart, when);
1073 nend = max (nend, when);
1079 results.push_back (new AutomationSelectable (nstart, nend, botfrac, topfrac, trackview));
1081 nstart = max_frames;
1089 results.push_back (new AutomationSelectable (nstart, nend, botfrac, topfrac, trackview));
1095 AutomationLine::get_inverted_selectables (Selection&, list<Selectable*>& results)
1101 AutomationLine::set_selected_points (PointSelection& points)
1106 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
1107 (*i)->selected = false;
1110 if (points.empty()) {
1114 for (PointSelection::iterator r = points.begin(); r != points.end(); ++r) {
1116 if (&(*r).track != &trackview) {
1120 /* Curse X11 and its inverted coordinate system! */
1122 bot = _y_position + (1.0 - (*r).high_fract) * _height;
1123 top = _y_position + (1.0 - (*r).low_fract) * _height;
1125 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
1127 double rstart, rend;
1129 rstart = trackview.editor.frame_to_unit ((*r).start);
1130 rend = trackview.editor.frame_to_unit ((*r).end);
1132 if ((*i)->get_x() >= rstart && (*i)->get_x() <= rend) {
1134 if ((*i)->get_y() >= bot && (*i)->get_y() <= top) {
1136 (*i)->selected = true;
1144 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
1145 (*i)->show_color (false, !points_visible);
1150 void AutomationLine::set_colors() {
1151 set_line_color( ARDOUR_UI::config()->canvasvar_AutomationLine.get() );
1152 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
1153 (*i)->show_color (false, !points_visible);
1158 AutomationLine::show_selection ()
1160 TimeSelection& time (trackview.editor.get_selection().time);
1162 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
1164 (*i)->selected = false;
1166 for (list<AudioRange>::iterator r = time.begin(); r != time.end(); ++r) {
1167 double rstart, rend;
1169 rstart = trackview.editor.frame_to_unit ((*r).start);
1170 rend = trackview.editor.frame_to_unit ((*r).end);
1172 if ((*i)->get_x() >= rstart && (*i)->get_x() <= rend) {
1173 (*i)->selected = true;
1178 (*i)->show_color (false, !points_visible);
1183 AutomationLine::hide_selection ()
1185 // show_selection ();
1189 AutomationLine::list_changed ()
1195 AutomationLine::reset_callback (const AutomationList& events)
1197 ALPoints tmp_points;
1198 uint32_t npoints = events.size();
1201 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
1204 control_points.clear ();
1209 AutomationList::const_iterator ai;
1211 for (ai = events.const_begin(); ai != events.const_end(); ++ai) {
1213 double translated_y = (*ai)->value;
1214 model_to_view_y (translated_y);
1216 tmp_points.push_back (ALPoint (trackview.editor.frame_to_unit ((*ai)->when),
1217 _y_position + _height - (translated_y * _height)));
1220 determine_visible_control_points (tmp_points);
1224 AutomationLine::reset ()
1226 update_pending = false;
1232 alist->apply_to_points (*this, &AutomationLine::reset_callback);
1236 AutomationLine::clear ()
1238 /* parent must create command */
1239 XMLNode &before = get_state();
1241 trackview.editor.current_session()->add_command (new MementoCommand<AutomationLine>(*this, &before, &get_state()));
1242 trackview.editor.current_session()->commit_reversible_command ();
1243 trackview.editor.current_session()->set_dirty ();
1247 AutomationLine::change_model (AutomationList::iterator i, double x, double y)
1252 AutomationLine::change_model_range (AutomationList::iterator start, AutomationList::iterator end, double xdelta, float ydelta)
1254 alist->move_range (start, end, xdelta, ydelta);
1258 AutomationLine::show_all_control_points ()
1260 points_visible = true;
1262 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
1264 (*i)->set_visible (true);
1269 AutomationLine::hide_all_but_selected_control_points ()
1271 points_visible = false;
1273 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
1274 if (!(*i)->selected) {
1275 (*i)->set_visible (false);
1281 AutomationLine::get_state (void)
1283 /* function as a proxy for the model */
1284 return alist->get_state();
1288 AutomationLine::set_state (const XMLNode &node)
1290 /* function as a proxy for the model */
1291 return alist->set_state (node);