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>
27 #include <ardour/automation_event.h>
28 #include <ardour/curve.h>
29 #include <ardour/dB.h>
31 #include "canvas-simplerect.h"
32 #include "automation_line.h"
33 #include "rgb_macros.h"
34 #include "ardour_ui.h"
35 #include "public_editor.h"
37 #include "selection.h"
38 #include "time_axis_view.h"
39 #include "point_selection.h"
40 #include "automation_selectable.h"
41 #include "automation_time_axis.h"
42 #include "public_editor.h"
44 #include <ardour/session.h>
49 using namespace ARDOUR;
50 using namespace Editing;
52 ControlPoint::ControlPoint (AutomationLine& al, gint (*event_handler)(GtkCanvasItem*, GdkEvent*, gpointer))
55 model = al.the_list().end();
64 item = gtk_canvas_item_new (line.canvas_group(),
65 gtk_canvas_simplerect_get_type(),
66 "draw", (gboolean) TRUE,
67 "fill", (gboolean) FALSE,
68 "fill_color_rgba", color_map[cControlPointFill],
69 "outline_color_rgba", color_map[cControlPointOutline],
70 "outline_pixels", (gint) 1,
73 gtk_object_set_data (GTK_OBJECT(item), "control_point", this);
74 gtk_signal_connect (GTK_OBJECT(item), "event", (GtkSignalFunc) event_handler, this);
80 ControlPoint::ControlPoint (const ControlPoint& other, bool dummy_arg_to_force_special_copy_constructor)
88 view_index = other.view_index;
89 can_slide = other.can_slide;
92 _shape = other._shape;
96 item = gtk_canvas_item_new (line.canvas_group(),
97 gtk_canvas_simplerect_get_type(),
98 "fill", (gboolean) FALSE,
99 "outline_color_rgba", color_map[cEnteredControlPointOutline],
100 "outline_pixels", (gint) 1,
103 /* NOTE: no event handling in copied ControlPoints */
109 ControlPoint::~ControlPoint ()
111 gtk_object_destroy (GTK_OBJECT(item));
115 ControlPoint::hide ()
117 gtk_canvas_item_hide (item);
123 gtk_canvas_item_show (item);
127 ControlPoint::set_visible (bool yn)
129 gtk_canvas_item_set (item, "draw", (gboolean) yn, NULL);
133 ControlPoint::reset (double x, double y, AutomationList::iterator mi, uint32_t vi, ShapeType shape)
137 move_to (x, y, shape);
141 ControlPoint::show_color (bool entered, bool hide_too)
145 gtk_canvas_item_set (item, "outline_color_rgba", color_map[cEnteredControlPointSelected], NULL);
148 gtk_canvas_item_set (item, "outline_color_rgba", color_map[cEnteredControlPoint], NULL);
156 gtk_canvas_item_set (item, "outline_color_rgba", color_map[cControlPointSelected], NULL);
159 gtk_canvas_item_set (item, "outline_color_rgba", color_map[cControlPoint], NULL);
168 ControlPoint::set_size (double sz)
174 gtk_canvas_item_set (item,
175 "fill", (gboolean) TRUE,
178 gtk_canvas_item_set (item,
179 "fill", (gboolean) FALSE,
184 move_to (_x, _y, _shape);
188 ControlPoint::move_to (double x, double y, ShapeType shape)
192 double half_size = rint(_size/2.0);
209 gtk_canvas_item_set (item,
223 AutomationLine::AutomationLine (string name, TimeAxisView& tv, GtkCanvasItem* parent, AutomationList& al,
224 gint (*point_handler)(GtkCanvasItem*, GdkEvent*, gpointer),
225 gint (*line_handler)(GtkCanvasItem*, GdkEvent*, gpointer))
231 points_visible = false;
232 update_pending = false;
233 _vc_uses_gain_mapping = false;
236 point_callback = point_handler;
237 _parent_group = parent;
238 terminal_points_can_slide = true;
241 group = gtk_canvas_item_new (GTK_CANVAS_GROUP(parent),
242 gtk_canvas_group_get_type(),
247 line = gtk_canvas_item_new (GTK_CANVAS_GROUP(group),
248 gtk_canvas_line_get_type(),
249 "width_pixels", (guint) 1,
252 // cerr << _name << " line @ " << line << endl;
254 gtk_object_set_data (GTK_OBJECT(line), "line", this);
255 gtk_signal_connect (GTK_OBJECT(line), "event", (GtkSignalFunc) line_handler, this);
257 alist.StateChanged.connect (mem_fun(*this, &AutomationLine::list_changed));
260 AutomationLine::~AutomationLine ()
263 gtk_canvas_points_unref (point_coords);
266 vector_delete (&control_points);
268 gtk_object_destroy (GTK_OBJECT(group));
272 AutomationLine::queue_reset ()
274 if (!update_pending) {
275 update_pending = true;
276 Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &AutomationLine::reset));
281 AutomationLine::set_point_size (double sz)
283 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
289 AutomationLine::show ()
291 gtk_canvas_item_show (line);
293 if (points_visible) {
294 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
303 AutomationLine::hide ()
305 gtk_canvas_item_hide (line);
306 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
313 AutomationLine::set_height (guint32 h)
318 if (_height > (guint32) TimeAxisView::Larger) {
319 set_point_size (8.0);
320 } else if (_height > (guint32) TimeAxisView::Normal) {
321 set_point_size (6.0);
323 set_point_size (4.0);
331 AutomationLine::set_line_color (uint32_t color)
334 gtk_canvas_item_set (line, "fill_color_rgba", color, NULL);
338 AutomationLine::set_verbose_cursor_uses_gain_mapping (bool yn)
340 if (yn != _vc_uses_gain_mapping) {
341 _vc_uses_gain_mapping = yn;
347 AutomationLine::nth (uint32_t n)
349 if (n < control_points.size()) {
350 return control_points[n];
357 AutomationLine::modify_view (ControlPoint& cp, double x, double y, bool with_push)
359 modify_view_point (cp, x, y, with_push);
364 AutomationLine::modify_view_point (ControlPoint& cp, double x, double y, bool with_push)
367 uint32_t last_movable = UINT_MAX;
368 double x_limit = DBL_MAX;
370 /* this just changes the current view. it does not alter
371 the model in any way at all.
374 /* clamp y-coord appropriately. y is supposed to be a normalized fraction (0.0-1.0),
375 and needs to be converted to a canvas unit distance.
380 y = _height - (y * _height);
384 /* x-coord cannot move beyond adjacent points or the start/end, and is
385 already in frames. it needs to be converted to canvas units.
388 x = trackview.editor.frame_to_unit (x);
390 /* clamp x position using view coordinates */
392 ControlPoint *before;
396 before = nth (cp.view_index - 1);
397 x = max (x, before->get_x()+1.0);
404 if (cp.view_index < control_points.size() - 1) {
406 after = nth (cp.view_index + 1);
408 /*if it is a "spike" leave the x alone */
410 if (after->get_x() - before->get_x() < 2) {
414 x = min (x, after->get_x()-1.0);
424 /* find the first point that can't move */
426 for (uint32_t n = cp.view_index + 1; (after = nth (n)) != 0; ++n) {
427 if (!after->can_slide) {
428 x_limit = after->get_x() - 1.0;
429 last_movable = after->view_index;
434 delta = x - cp.get_x();
439 /* leave the x-coordinate alone */
441 x = trackview.editor.frame_to_unit ((*cp.model)->when);
447 cp.move_to (x, y, ControlPoint::Full);
448 reset_line_coords (cp);
452 uint32_t limit = min (control_points.size(), (size_t)last_movable);
454 /* move the current point to wherever the user told it to go, subject
458 cp.move_to (min (x, x_limit), y, ControlPoint::Full);
459 reset_line_coords (cp);
461 /* now move all subsequent control points, to reflect the motion.
464 for (uint32_t i = cp.view_index + 1; i < limit; ++i) {
465 ControlPoint *p = nth (i);
469 new_x = min (p->get_x() + delta, x_limit);
470 p->move_to (new_x, p->get_y(), ControlPoint::Full);
471 reset_line_coords (*p);
478 AutomationLine::reset_line_coords (ControlPoint& cp)
481 point_coords->coords[cp.view_index*2] = cp.get_x();
482 point_coords->coords[(cp.view_index*2) + 1] = cp.get_y();
487 AutomationLine::update_line ()
489 gtk_canvas_item_set (line, "points", point_coords, NULL);
493 AutomationLine::sync_model_with_view_line (uint32_t start, uint32_t end)
498 update_pending = true;
500 for (uint32_t i = start; i <= end; ++i) {
502 sync_model_with_view_point(*p);
509 AutomationLine::model_representation (ControlPoint& cp, ModelRepresentation& mr)
511 /* part one: find out where the visual control point is.
512 initial results are in canvas units. ask the
513 line to convert them to something relevant.
516 mr.xval = (jack_nframes_t) floor (cp.get_x());
517 mr.yval = 1.0 - (cp.get_y() / _height);
520 /* if xval has not changed, set it directly from the model to avoid rounding errors */
522 if (mr.xval == trackview.editor.frame_to_unit((*cp.model)->when)) {
523 mr.xval = (jack_nframes_t) (*cp.model)->when;
525 mr.xval = trackview.editor.unit_to_frame (mr.xval);
529 /* virtual call: this will do the right thing
530 for whatever particular type of line we are.
533 view_to_model_y (mr.yval);
535 /* part 2: find out where the model point is now
538 mr.xpos = (jack_nframes_t) (*cp.model)->when;
539 mr.ypos = (*cp.model)->value;
541 /* part 3: get the position of the visual control
542 points before and after us.
545 ControlPoint* before;
549 before = nth (cp.view_index - 1);
554 after = nth (cp.view_index + 1);
557 mr.xmin = (jack_nframes_t) (*before->model)->when;
558 mr.ymin = (*before->model)->value;
559 mr.start = before->model;
568 mr.end = after->model;
578 AutomationLine::sync_model_from (ControlPoint& cp)
583 sync_model_with_view_point (cp);
585 /* we might have moved all points after `cp' by some amount
586 if we pressed the with_push modifyer some of the time during the drag
587 so all subsequent points have to be resynced
590 lasti = control_points.size() - 1;
593 update_pending = true;
595 while (p != &cp && lasti) {
596 sync_model_with_view_point (*p);
603 AutomationLine::sync_model_with_view_point (ControlPoint& cp)
605 ModelRepresentation mr;
608 model_representation (cp, mr);
610 /* part 4: how much are we changing the central point by */
612 ydelta = mr.yval - mr.ypos;
614 /* IMPORTANT: changing the model when the x-coordinate changes
615 may invalidate the iterators that we are using. this means that we have
616 to change the points before+after the one corresponding to the visual CP
617 first (their x-coordinate doesn't change). then we change the
620 apply the full change to the central point, and interpolate
621 in each direction to cover all model points represented
622 by the control point.
625 /* part 5: change all points before the primary point */
627 for (AutomationList::iterator i = mr.start; i != cp.model; ++i) {
631 delta = ydelta * ((*i)->when - mr.xmin) / (mr.xpos - mr.xmin);
633 /* x-coordinate (generally time) stays where it is,
634 y-coordinate moves by a certain amount.
637 update_pending = true;
638 change_model (i, (*i)->when, mr.yval + delta);
641 /* part 6: change later points */
643 AutomationList::iterator i = cp.model;
647 while (i != mr.end) {
651 delta = ydelta * (mr.xmax - (*i)->when) / (mr.xmax - mr.xpos);
653 /* x-coordinate (generally time) stays where it is,
654 y-coordinate moves by a certain amount.
657 update_pending = true;
658 change_model (i, (*i)->when, (*i)->value + delta);
663 /* part 7: change the primary point */
665 update_pending = true;
666 change_model (cp.model, mr.xval, mr.yval);
670 AutomationLine::determine_visible_control_points (GtkCanvasPoints* points)
672 uint32_t xi, yi, view_index, pi;
674 AutomationList::iterator model;
675 uint32_t npoints = points->num_points;
676 double last_control_point_x = 0.0;
677 double last_control_point_y = 0.0;
678 uint32_t this_rx = 0;
679 uint32_t prev_rx = 0;
680 uint32_t this_ry = 0;
681 uint32_t prev_ry = 0;
684 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
687 gtk_canvas_item_hide (line);
689 if (points == 0 || points->num_points == 0) {
693 /* compute derivative/slope for the entire line */
695 slope = new double[npoints];
697 for (n = 0, xi = 2, yi = 3, view_index = 0; n < points->num_points - 1; xi += 2, yi +=2, ++n, ++view_index) {
700 xdelta = points->coords[xi] - points->coords[xi-2];
701 ydelta = points->coords[yi] - points->coords[yi-2];
702 slope[view_index] = ydelta/xdelta;
705 /* read all points and decide which ones to show as control points */
707 for (model = alist.begin(), pi = 0, xi = 0, yi = 1, view_index = 0; pi < npoints; ++model, xi += 2, yi +=2, ++pi) {
709 /* now ensure that the control_points vector reflects the current curve
710 state, but don't plot control points too close together. also, don't
711 plot a series of points all with the same value.
713 always plot the first and last points, of course.
716 if (invalid_point (points, pi)) {
717 /* for some reason, we are supposed to ignore this point,
718 but still keep track of the model index.
723 if (pi > 0 && pi < npoints - 1) {
724 if (slope[pi] == slope[pi-1]) {
726 /* no reason to display this point */
732 /* need to round here. the ultimate coordinates are integer
733 pixels, so tiny deltas in the coords will be eliminated
734 and we end up with "colinear" line segments. since the
735 line rendering code in libart doesn't like this very
736 much, we eliminate them here. don't do this for the first and last
740 this_rx = (uint32_t) rint (points->coords[xi]);
741 this_ry = (unsigned long) rint (points->coords[yi]);
743 if (view_index && pi != npoints && (this_rx == prev_rx) && (this_ry == prev_ry)) {
748 /* ok, we should display this point */
750 if (view_index >= control_points.size()) {
751 /* make sure we have enough control points */
753 ControlPoint* ncp = new ControlPoint (*this, point_callback);
755 if (_height > (guint32) TimeAxisView::Larger) {
757 } else if (_height > (guint32) TimeAxisView::Normal) {
763 control_points.push_back (ncp);
766 ControlPoint::ShapeType shape;
768 if (!terminal_points_can_slide) {
770 control_points[view_index]->can_slide = false;
771 if (points->coords[xi] == 0) {
772 shape = ControlPoint::Start;
774 shape = ControlPoint::Full;
776 } else if (pi == npoints - 1) {
777 control_points[view_index]->can_slide = false;
778 shape = ControlPoint::End;
780 control_points[view_index]->can_slide = true;
781 shape = ControlPoint::Full;
784 control_points[view_index]->can_slide = true;
785 shape = ControlPoint::Full;
788 control_points[view_index]->reset (points->coords[xi], points->coords[yi], model, view_index, shape);
790 last_control_point_x = points->coords[xi];
791 last_control_point_y = points->coords[yi];
796 /* finally, control visibility */
798 if (_visible && points_visible) {
799 control_points[view_index]->show ();
800 control_points[view_index]->set_visible (true);
802 if (!points_visible) {
803 control_points[view_index]->set_visible (false);
810 /* discard extra CP's to avoid confusing ourselves */
812 while (control_points.size() > view_index) {
813 ControlPoint* cp = control_points.back();
814 control_points.pop_back ();
818 if (!terminal_points_can_slide) {
819 control_points.back()->can_slide = false;
824 /* Now make sure the "point_coords" array is large enough
825 to represent all the visible points.
828 if (view_index > 1) {
830 npoints = view_index;
833 if (point_coords->num_points < (int) npoints) {
834 gtk_canvas_points_unref (point_coords);
835 point_coords = get_canvas_points ("autoline", npoints);
837 point_coords->num_points = npoints;
840 point_coords = get_canvas_points ("autoline", npoints);
843 /* reset the line coordinates */
847 for (pci = 0, view_index = 0; view_index < npoints; ++view_index) {
848 point_coords->coords[pci++] = control_points[view_index]->get_x();
849 point_coords->coords[pci++] = control_points[view_index]->get_y();
852 // cerr << "set al2 points, nc = " << point_coords->num_points << endl;
853 gtk_canvas_item_set (line, "points", point_coords, NULL);
856 gtk_canvas_item_show (line);
860 set_selected_points (trackview.editor.get_selection().points);
864 AutomationLine::get_verbose_cursor_string (float fraction)
868 if (_vc_uses_gain_mapping) {
869 if (fraction == 0.0) {
870 snprintf (buf, sizeof (buf), "-inf dB");
872 snprintf (buf, sizeof (buf), "%.1fdB", coefficient_to_dB (slider_position_to_gain (fraction)));
875 snprintf (buf, sizeof (buf), "%.2f", fraction);
882 AutomationLine::invalid_point (GtkCanvasPoints* p, uint32_t index)
884 return p->coords[index*2] == max_frames && p->coords[(index*2)+1] == DBL_MAX;
888 AutomationLine::invalidate_point (GtkCanvasPoints* p, uint32_t index)
890 p->coords[index*2] = max_frames;
891 p->coords[(index*2)+1] = DBL_MAX;
895 AutomationLine::start_drag (ControlPoint* cp, float fraction)
897 if (trackview.editor.current_session() == 0) { /* how? */
904 str = _("automation event move");
906 str = _("automation range drag");
909 trackview.editor.current_session()->begin_reversible_command (str);
910 trackview.editor.current_session()->add_undo (get_memento());
912 first_drag_fraction = fraction;
913 last_drag_fraction = fraction;
918 AutomationLine::point_drag (ControlPoint& cp, jack_nframes_t x, float fraction, bool with_push)
920 modify_view (cp, x, fraction, with_push);
925 AutomationLine::line_drag (uint32_t i1, uint32_t i2, float fraction, bool with_push)
927 double ydelta = fraction - last_drag_fraction;
929 last_drag_fraction = fraction;
936 for (uint32_t i = i1 ; i <= i2; i++) {
938 modify_view_point (*cp, trackview.editor.unit_to_frame (cp->get_x()), ((_height - cp->get_y()) /_height) + ydelta, with_push);
947 AutomationLine::end_drag (ControlPoint* cp)
952 sync_model_from (*cp);
954 sync_model_with_view_line (line_drag_cp1, line_drag_cp2);
957 update_pending = false;
959 trackview.editor.current_session()->add_redo_no_execute (get_memento());
960 trackview.editor.current_session()->commit_reversible_command ();
961 trackview.editor.current_session()->set_dirty ();
966 AutomationLine::control_points_adjacent (double xval, uint32_t & before, uint32_t& after)
968 ControlPoint *bcp = 0;
969 ControlPoint *acp = 0;
972 /* xval is in frames */
974 unit_xval = trackview.editor.frame_to_unit (xval);
976 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
978 if ((*i)->get_x() <= unit_xval) {
980 if (!bcp || (*i)->get_x() > bcp->get_x()) {
982 before = bcp->view_index;
985 } else if ((*i)->get_x() > unit_xval) {
987 after = acp->view_index;
996 AutomationLine::is_last_point (ControlPoint& cp)
998 ModelRepresentation mr;
1000 model_representation (cp, mr);
1002 // If the list is not empty, and the point is the last point in the list
1004 if (!alist.empty() && mr.end == alist.end()) {
1012 AutomationLine::is_first_point (ControlPoint& cp)
1014 ModelRepresentation mr;
1016 model_representation (cp, mr);
1018 // If the list is not empty, and the point is the first point in the list
1020 if (!alist.empty() && mr.start == alist.begin()) {
1027 // This is copied into AudioRegionGainLine
1029 AutomationLine::remove_point (ControlPoint& cp)
1031 ModelRepresentation mr;
1033 model_representation (cp, mr);
1035 trackview.editor.current_session()->begin_reversible_command (_("remove control point"));
1036 trackview.editor.current_session()->add_undo (get_memento());
1038 alist.erase (mr.start, mr.end);
1040 trackview.editor.current_session()->add_redo_no_execute (get_memento());
1041 trackview.editor.current_session()->commit_reversible_command ();
1042 trackview.editor.current_session()->set_dirty ();
1046 AutomationLine::get_selectables (jack_nframes_t& start, jack_nframes_t& end,
1047 double botfrac, double topfrac, list<Selectable*>& results)
1052 jack_nframes_t nstart;
1053 jack_nframes_t nend;
1054 bool collecting = false;
1056 /* Curse X11 and its inverted coordinate system! */
1058 bot = (1.0 - topfrac) * _height;
1059 top = (1.0 - botfrac) * _height;
1061 nstart = max_frames;
1064 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
1066 jack_nframes_t when = (jack_nframes_t) (*(*i)->model)->when;
1068 if (when >= start && when <= end) {
1070 if ((*i)->get_y() >= bot && (*i)->get_y() <= top) {
1073 (*i)->set_visible(true);
1075 nstart = min (nstart, when);
1076 nend = max (nend, when);
1082 results.push_back (new AutomationSelectable (nstart, nend, botfrac, topfrac, trackview));
1084 nstart = max_frames;
1092 results.push_back (new AutomationSelectable (nstart, nend, botfrac, topfrac, trackview));
1098 AutomationLine::get_inverted_selectables (Selection&, list<Selectable*>& results)
1104 AutomationLine::set_selected_points (PointSelection& points)
1109 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
1110 (*i)->selected = false;
1113 if (points.empty()) {
1117 for (PointSelection::iterator r = points.begin(); r != points.end(); ++r) {
1119 if (&(*r).track != &trackview) {
1123 /* Curse X11 and its inverted coordinate system! */
1125 bot = (1.0 - (*r).high_fract) * _height;
1126 top = (1.0 - (*r).low_fract) * _height;
1128 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
1130 double rstart, rend;
1132 rstart = trackview.editor.frame_to_unit ((*r).start);
1133 rend = trackview.editor.frame_to_unit ((*r).end);
1135 if ((*i)->get_x() >= rstart && (*i)->get_x() <= rend) {
1137 if ((*i)->get_y() >= bot && (*i)->get_y() <= top) {
1139 (*i)->selected = true;
1147 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
1148 (*i)->show_color (false, !points_visible);
1154 AutomationLine::show_selection ()
1156 TimeSelection& time (trackview.editor.get_selection().time);
1158 // cerr << "show selection\n";
1160 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
1162 (*i)->selected = false;
1164 for (list<AudioRange>::iterator r = time.begin(); r != time.end(); ++r) {
1165 double rstart, rend;
1167 rstart = trackview.editor.frame_to_unit ((*r).start);
1168 rend = trackview.editor.frame_to_unit ((*r).end);
1170 if ((*i)->get_x() >= rstart && (*i)->get_x() <= rend) {
1171 (*i)->selected = true;
1176 (*i)->show_color (false, !points_visible);
1181 AutomationLine::hide_selection ()
1183 // cerr << "hide selection\n";
1184 // show_selection ();
1188 // This is copied into AudioRegionGainLine
1190 AutomationLine::get_memento ()
1192 return alist.get_memento();
1196 AutomationLine::list_changed (Change ignored)
1202 AutomationLine::reset_callback (const AutomationList& events)
1204 GtkCanvasPoints *tmp_points;
1205 uint32_t npoints = events.size();
1208 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
1211 control_points.clear ();
1212 gtk_canvas_item_hide (line);
1216 tmp_points = get_canvas_points ("autoline reset", max (npoints, (uint32_t) 2));
1219 AutomationList::const_iterator ai;
1221 for (ai = events.const_begin(), xi = 0, yi = 1; ai != events.const_end(); xi += 2, yi +=2, ++ai) {
1223 tmp_points->coords[xi] = trackview.editor.frame_to_unit ((*ai)->when);
1224 double translated_y;
1226 translated_y = (*ai)->value;
1227 model_to_view_y (translated_y);
1228 tmp_points->coords[yi] = _height - (translated_y * _height);
1231 tmp_points->num_points = npoints;
1233 determine_visible_control_points (tmp_points);
1234 gtk_canvas_points_unref (tmp_points);
1238 AutomationLine::reset ()
1240 update_pending = false;
1246 alist.apply_to_points (*this, &AutomationLine::reset_callback);
1250 AutomationLine::clear ()
1252 /* parent must create command */
1253 trackview.editor.current_session()->add_undo (get_memento());
1255 trackview.editor.current_session()->add_redo_no_execute (get_memento());
1256 trackview.editor.current_session()->commit_reversible_command ();
1257 trackview.editor.current_session()->set_dirty ();
1261 AutomationLine::change_model (AutomationList::iterator i, double x, double y)
1263 alist.modify (i, (jack_nframes_t) x, y);
1267 AutomationLine::change_model_range (AutomationList::iterator start, AutomationList::iterator end, double xdelta, float ydelta)
1269 alist.move_range (start, end, xdelta, ydelta);
1273 AutomationLine::show_all_control_points ()
1275 points_visible = true;
1277 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
1279 (*i)->set_visible (true);
1284 AutomationLine::hide_all_but_selected_control_points ()
1286 points_visible = false;
1288 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
1289 if (!(*i)->selected) {
1290 (*i)->set_visible (false);