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);
252 if (alist->parameter().type() == GainAutomation)
253 set_verbose_cursor_uses_gain_mapping (true);
256 AutomationLine::~AutomationLine ()
258 vector_delete (&control_points);
263 AutomationLine::event_handler (GdkEvent* event)
265 return PublicEditor::instance().canvas_line_event (event, line, this);
269 AutomationLine::queue_reset ()
271 if (!update_pending) {
272 update_pending = true;
273 Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &AutomationLine::reset));
278 AutomationLine::show ()
282 if (points_visible) {
283 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
292 AutomationLine::hide ()
295 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
302 AutomationLine::control_point_box_size ()
304 if (_height > TimeAxisView::hLarger) {
306 } else if (_height > (guint32) TimeAxisView::hNormal) {
313 AutomationLine::set_y_position_and_height (guint32 y, guint32 h)
315 bool changed = false;
317 if (y != _y_position) {
325 double const bsz = control_point_box_size();
327 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
328 (*i)->set_size (bsz);
339 AutomationLine::set_line_color (uint32_t color)
342 line->property_fill_color_rgba() = color;
346 AutomationLine::set_verbose_cursor_uses_gain_mapping (bool yn)
348 if (yn != _vc_uses_gain_mapping) {
349 _vc_uses_gain_mapping = yn;
355 AutomationLine::nth (uint32_t n)
357 if (n < control_points.size()) {
358 return control_points[n];
365 AutomationLine::modify_view_point (ControlPoint& cp, double x, double y, bool with_push)
368 uint32_t last_movable = UINT_MAX;
369 double x_limit = DBL_MAX;
371 /* this just changes the current view. it does not alter
372 the model in any way at all.
375 /* clamp y-coord appropriately. y is supposed to be a normalized fraction (0.0-1.0),
376 and needs to be converted to a canvas unit distance.
381 y = _y_position + _height - (y * _height);
385 /* x-coord cannot move beyond adjacent points or the start/end, and is
386 already in frames. it needs to be converted to canvas units.
389 x = trackview.editor.frame_to_unit (x);
391 /* clamp x position using view coordinates */
393 ControlPoint *before;
397 before = nth (cp.view_index - 1);
398 x = max (x, before->get_x()+1.0);
405 if (cp.view_index < control_points.size() - 1) {
407 after = nth (cp.view_index + 1);
409 /*if it is a "spike" leave the x alone */
411 if (after->get_x() - before->get_x() < 2) {
415 x = min (x, after->get_x()-1.0);
425 /* find the first point that can't move */
427 for (uint32_t n = cp.view_index + 1; (after = nth (n)) != 0; ++n) {
428 if (!after->can_slide) {
429 x_limit = after->get_x() - 1.0;
430 last_movable = after->view_index;
435 delta = x - cp.get_x();
440 /* leave the x-coordinate alone */
442 x = trackview.editor.frame_to_unit ((*cp.model)->when);
448 cp.move_to (x, y, ControlPoint::Full);
449 reset_line_coords (cp);
453 uint32_t limit = min (control_points.size(), (size_t)last_movable);
455 /* move the current point to wherever the user told it to go, subject
459 cp.move_to (min (x, x_limit), y, ControlPoint::Full);
460 reset_line_coords (cp);
462 /* now move all subsequent control points, to reflect the motion.
465 for (uint32_t i = cp.view_index + 1; i < limit; ++i) {
466 ControlPoint *p = nth (i);
470 new_x = min (p->get_x() + delta, x_limit);
471 p->move_to (new_x, p->get_y(), ControlPoint::Full);
472 reset_line_coords (*p);
479 AutomationLine::reset_line_coords (ControlPoint& cp)
481 if (cp.view_index < line_points.size()) {
482 line_points[cp.view_index].set_x (cp.get_x());
483 line_points[cp.view_index].set_y (cp.get_y());
488 AutomationLine::sync_model_with_view_line (uint32_t start, uint32_t end)
493 update_pending = true;
495 for (uint32_t i = start; i <= end; ++i) {
497 sync_model_with_view_point (*p, false, 0);
502 AutomationLine::model_representation (ControlPoint& cp, ModelRepresentation& mr)
504 /* part one: find out where the visual control point is.
505 initial results are in canvas units. ask the
506 line to convert them to something relevant.
509 mr.xval = (nframes_t) floor (cp.get_x());
510 mr.yval = 1.0 - ( (cp.get_y() - _y_position) / _height);
512 /* if xval has not changed, set it directly from the model to avoid rounding errors */
514 if (mr.xval == trackview.editor.frame_to_unit((*cp.model)->when)) {
515 mr.xval = (nframes_t) (*cp.model)->when;
517 mr.xval = trackview.editor.unit_to_frame (mr.xval);
520 /* virtual call: this will do the right thing
521 for whatever particular type of line we are.
524 view_to_model_y (mr.yval);
526 /* part 2: find out where the model point is now
529 mr.xpos = (nframes_t) (*cp.model)->when;
530 mr.ypos = (*cp.model)->value;
532 /* part 3: get the position of the visual control
533 points before and after us.
536 ControlPoint* before;
540 before = nth (cp.view_index - 1);
545 after = nth (cp.view_index + 1);
548 mr.xmin = (nframes_t) (*before->model)->when;
549 mr.ymin = (*before->model)->value;
550 mr.start = before->model;
559 mr.end = after->model;
569 AutomationLine::determine_visible_control_points (ALPoints& points)
571 uint32_t view_index, pi, n;
572 AutomationList::iterator model;
574 double last_control_point_x = 0.0;
575 double last_control_point_y = 0.0;
576 uint32_t this_rx = 0;
577 uint32_t prev_rx = 0;
578 uint32_t this_ry = 0;
579 uint32_t prev_ry = 0;
584 /* hide all existing points, and the line */
588 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
595 if (points.empty()) {
599 npoints = points.size();
601 /* compute derivative/slope for the entire line */
603 slope = new double[npoints];
605 for (n = 0; n < npoints - 1; ++n) {
606 double xdelta = points[n+1].x - points[n].x;
607 double ydelta = points[n+1].y - points[n].y;
608 slope[n] = ydelta/xdelta;
611 box_size = (uint32_t) control_point_box_size ();
613 /* read all points and decide which ones to show as control points */
617 for (model = alist->begin(), pi = 0; pi < npoints; ++model, ++pi) {
619 double tx = points[pi].x;
620 double ty = points[pi].y;
622 /* now ensure that the control_points vector reflects the current curve
623 state, but don't plot control points too close together. also, don't
624 plot a series of points all with the same value.
626 always plot the first and last points, of course.
629 if (invalid_point (points, pi)) {
630 /* for some reason, we are supposed to ignore this point,
631 but still keep track of the model index.
636 if (pi > 0 && pi < npoints - 1) {
637 if (slope[pi] == slope[pi-1]) {
639 /* no reason to display this point */
645 /* need to round here. the ultimate coordinates are integer
646 pixels, so tiny deltas in the coords will be eliminated
647 and we end up with "colinear" line segments. since the
648 line rendering code in libart doesn't like this very
649 much, we eliminate them here. don't do this for the first and last
653 this_rx = (uint32_t) rint (tx);
654 this_ry = (uint32_t) rint (ty);
656 if (view_index && pi != npoints && /* not the first, not the last */
657 (((this_rx == prev_rx) && (this_ry == prev_ry)) || /* same point */
658 (((this_rx - prev_rx) < (box_size + 2)) && /* not identical, but still too close horizontally */
659 (abs ((int)(this_ry - prev_ry)) < (int) (box_size + 2))))) { /* too close vertically */
663 /* ok, we should display this point */
665 if (view_index >= cpsize) {
667 /* make sure we have enough control points */
669 ControlPoint* ncp = new ControlPoint (*this);
671 ncp->set_size (box_size);
673 control_points.push_back (ncp);
677 ControlPoint::ShapeType shape;
679 if (!terminal_points_can_slide) {
681 control_points[view_index]->can_slide = false;
683 shape = ControlPoint::Start;
685 shape = ControlPoint::Full;
687 } else if (pi == npoints - 1) {
688 control_points[view_index]->can_slide = false;
689 shape = ControlPoint::End;
691 control_points[view_index]->can_slide = true;
692 shape = ControlPoint::Full;
695 control_points[view_index]->can_slide = true;
696 shape = ControlPoint::Full;
699 last_control_point_x = tx;
700 last_control_point_y = ty;
702 control_points[view_index]->reset (tx, ty, model, view_index, shape);
707 /* finally, control visibility */
709 if (_visible && points_visible) {
710 control_points[view_index]->show ();
711 control_points[view_index]->set_visible (true);
713 if (!points_visible) {
714 control_points[view_index]->set_visible (false);
721 /* discard extra CP's to avoid confusing ourselves */
723 while (control_points.size() > view_index) {
724 ControlPoint* cp = control_points.back();
725 control_points.pop_back ();
729 if (!terminal_points_can_slide) {
730 control_points.back()->can_slide = false;
735 if (view_index > 1) {
737 npoints = view_index;
739 /* reset the line coordinates */
741 while (line_points.size() < npoints) {
742 line_points.push_back (Art::Point (0,0));
745 while (line_points.size() > npoints) {
746 line_points.pop_back ();
749 for (view_index = 0; view_index < npoints; ++view_index) {
750 line_points[view_index].set_x (control_points[view_index]->get_x());
751 line_points[view_index].set_y (control_points[view_index]->get_y());
754 line->property_points() = line_points;
762 set_selected_points (trackview.editor.get_selection().points);
767 AutomationLine::get_verbose_cursor_string (float fraction)
771 if (_vc_uses_gain_mapping) {
772 if (fraction == 0.0) {
773 snprintf (buf, sizeof (buf), "-inf dB");
775 snprintf (buf, sizeof (buf), "%.1fdB", coefficient_to_dB (slider_position_to_gain (fraction)));
778 snprintf (buf, sizeof (buf), "%.2f", fraction);
785 AutomationLine::invalid_point (ALPoints& p, uint32_t index)
787 return p[index].x == max_frames && p[index].y == DBL_MAX;
791 AutomationLine::invalidate_point (ALPoints& p, uint32_t index)
793 p[index].x = max_frames;
794 p[index].y = DBL_MAX;
798 AutomationLine::start_drag (ControlPoint* cp, nframes_t x, float fraction)
800 if (trackview.editor.current_session() == 0) { /* how? */
807 str = _("automation event move");
809 str = _("automation range drag");
812 trackview.editor.current_session()->begin_reversible_command (str);
813 trackview.editor.current_session()->add_command (new MementoCommand<AutomationList>(*alist.get(), &get_state(), 0));
817 first_drag_fraction = fraction;
818 last_drag_fraction = fraction;
824 AutomationLine::point_drag (ControlPoint& cp, nframes_t x, float fraction, bool with_push)
827 drag_distance += (x - drag_x);
829 drag_distance -= (drag_x - x);
834 modify_view_point (cp, x, fraction, with_push);
836 if (line_points.size() > 1) {
837 line->property_points() = line_points;
841 did_push = with_push;
845 AutomationLine::line_drag (uint32_t i1, uint32_t i2, float fraction, bool with_push)
847 double const ydelta = fraction - last_drag_fraction;
849 did_push = with_push;
851 last_drag_fraction = fraction;
858 for (uint32_t i = i1 ; i <= i2; i++) {
860 modify_view_point (*cp, trackview.editor.unit_to_frame (cp->get_x()), ((_height - cp->get_y() + _y_position) /_height) + ydelta, with_push);
863 if (line_points.size() > 1) {
864 line->property_points() = line_points;
871 AutomationLine::end_drag (ControlPoint* cp)
880 sync_model_with_view_point (*cp, did_push, drag_distance);
882 sync_model_with_view_line (line_drag_cp1, line_drag_cp2);
887 update_pending = false;
889 trackview.editor.current_session()->add_command (new MementoCommand<AutomationList>(*alist.get(), 0, &alist->get_state()));
890 trackview.editor.current_session()->commit_reversible_command ();
891 trackview.editor.current_session()->set_dirty ();
896 AutomationLine::sync_model_with_view_point (ControlPoint& cp, bool did_push, int64_t distance)
898 ModelRepresentation mr;
901 model_representation (cp, mr);
903 /* how much are we changing the central point by */
905 ydelta = mr.yval - mr.ypos;
908 apply the full change to the central point, and interpolate
909 on both axes to cover all model points represented
910 by the control point.
913 /* change all points before the primary point */
915 for (AutomationList::iterator i = mr.start; i != cp.model; ++i) {
917 double fract = ((*i)->when - mr.xmin) / (mr.xpos - mr.xmin);
918 double y_delta = ydelta * fract;
919 double x_delta = distance * fract;
923 if (y_delta || x_delta) {
924 alist->modify (i, (*i)->when + x_delta, mr.ymin + y_delta);
928 /* change the primary point */
930 update_pending = true;
931 alist->modify (cp.model, mr.xval, mr.yval);
934 /* change later points */
936 AutomationList::iterator i = cp.model;
940 while (i != mr.end) {
942 double delta = ydelta * (mr.xmax - (*i)->when) / (mr.xmax - mr.xpos);
944 /* all later points move by the same distance along the x-axis as the main point */
947 alist->modify (i, (*i)->when + distance, (*i)->value + delta);
955 /* move all points after the range represented by the view by the same distance
956 as the main point moved.
959 alist->slide (mr.end, drag_distance);
965 AutomationLine::control_points_adjacent (double xval, uint32_t & before, uint32_t& after)
967 ControlPoint *bcp = 0;
968 ControlPoint *acp = 0;
971 /* xval is in frames */
973 unit_xval = trackview.editor.frame_to_unit (xval);
975 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
977 if ((*i)->get_x() <= unit_xval) {
979 if (!bcp || (*i)->get_x() > bcp->get_x()) {
981 before = bcp->view_index;
984 } else if ((*i)->get_x() > unit_xval) {
986 after = acp->view_index;
995 AutomationLine::is_last_point (ControlPoint& cp)
997 ModelRepresentation mr;
999 model_representation (cp, mr);
1001 // If the list is not empty, and the point is the last point in the list
1003 if (!alist->empty() && mr.end == alist->end()) {
1011 AutomationLine::is_first_point (ControlPoint& cp)
1013 ModelRepresentation mr;
1015 model_representation (cp, mr);
1017 // If the list is not empty, and the point is the first point in the list
1019 if (!alist->empty() && mr.start == alist->begin()) {
1026 // This is copied into AudioRegionGainLine
1028 AutomationLine::remove_point (ControlPoint& cp)
1030 ModelRepresentation mr;
1032 model_representation (cp, mr);
1034 trackview.editor.current_session()->begin_reversible_command (_("remove control point"));
1035 XMLNode &before = alist->get_state();
1037 alist->erase (mr.start, mr.end);
1039 trackview.editor.current_session()->add_command(new MementoCommand<AutomationList>(
1040 *alist.get(), &before, &alist->get_state()));
1041 trackview.editor.current_session()->commit_reversible_command ();
1042 trackview.editor.current_session()->set_dirty ();
1046 AutomationLine::get_selectables (nframes_t& start, nframes_t& end,
1047 double botfrac, double topfrac, list<Selectable*>& results)
1054 bool collecting = false;
1056 /* Curse X11 and its inverted coordinate system! */
1058 bot = _y_position + (1.0 - topfrac) * _height;
1059 top = _y_position + (1.0 - botfrac) * _height;
1061 nstart = max_frames;
1064 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
1066 nframes_t when = (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 = _y_position + (1.0 - (*r).high_fract) * _height;
1126 top = _y_position + (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);
1153 void AutomationLine::set_colors() {
1154 set_line_color( ARDOUR_UI::config()->canvasvar_AutomationLine.get() );
1155 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
1156 (*i)->show_color (false, !points_visible);
1161 AutomationLine::show_selection ()
1163 TimeSelection& time (trackview.editor.get_selection().time);
1165 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
1167 (*i)->selected = false;
1169 for (list<AudioRange>::iterator r = time.begin(); r != time.end(); ++r) {
1170 double rstart, rend;
1172 rstart = trackview.editor.frame_to_unit ((*r).start);
1173 rend = trackview.editor.frame_to_unit ((*r).end);
1175 if ((*i)->get_x() >= rstart && (*i)->get_x() <= rend) {
1176 (*i)->selected = true;
1181 (*i)->show_color (false, !points_visible);
1186 AutomationLine::hide_selection ()
1188 // show_selection ();
1192 AutomationLine::list_changed ()
1198 AutomationLine::reset_callback (const AutomationList& events)
1200 ALPoints tmp_points;
1201 uint32_t npoints = events.size();
1204 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
1207 control_points.clear ();
1212 AutomationList::const_iterator ai;
1214 for (ai = events.const_begin(); ai != events.const_end(); ++ai) {
1216 double translated_y = (*ai)->value;
1217 model_to_view_y (translated_y);
1219 tmp_points.push_back (ALPoint (trackview.editor.frame_to_unit ((*ai)->when),
1220 _y_position + _height - (translated_y * _height)));
1223 determine_visible_control_points (tmp_points);
1227 AutomationLine::reset ()
1229 update_pending = false;
1235 alist->apply_to_points (*this, &AutomationLine::reset_callback);
1239 AutomationLine::clear ()
1241 /* parent must create command */
1242 XMLNode &before = get_state();
1244 trackview.editor.current_session()->add_command (new MementoCommand<AutomationLine>(*this, &before, &get_state()));
1245 trackview.editor.current_session()->commit_reversible_command ();
1246 trackview.editor.current_session()->set_dirty ();
1250 AutomationLine::change_model (AutomationList::iterator i, double x, double y)
1255 AutomationLine::change_model_range (AutomationList::iterator start, AutomationList::iterator end, double xdelta, float ydelta)
1257 alist->move_range (start, end, xdelta, ydelta);
1261 AutomationLine::show_all_control_points ()
1263 points_visible = true;
1265 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
1267 (*i)->set_visible (true);
1272 AutomationLine::hide_all_but_selected_control_points ()
1274 points_visible = false;
1276 for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) {
1277 if (!(*i)->selected) {
1278 (*i)->set_visible (false);
1284 AutomationLine::get_state (void)
1286 /* function as a proxy for the model */
1287 return alist->get_state();
1291 AutomationLine::set_state (const XMLNode &node)
1293 /* function as a proxy for the model */
1294 return alist->set_state (node);
1298 AutomationLine::view_to_model_y (double& y)
1300 if (alist->parameter().type() == GainAutomation) {
1301 y = slider_position_to_gain (y);
1304 } else if (alist->parameter().type() == PanAutomation) {
1305 // vertical coordinate axis reversal
1307 } else if (alist->parameter().type() == MidiCCAutomation) {
1308 y = (int)(y * 127.0);
1313 AutomationLine::model_to_view_y (double& y)
1315 if (alist->parameter().type() == GainAutomation) {
1316 y = gain_to_slider_position (y);
1317 } else if (alist->parameter().type() == PanAutomation) {
1318 // vertical coordinate axis reversal
1320 } else if (alist->parameter().type() == MidiCCAutomation) {
1322 } else if (alist->parameter().type() == PluginAutomation) {
1323 y = (y - alist->get_min_y()) / (double)(alist->get_max_y()- alist->get_min_y());