X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fautomation_line.cc;h=844063a22726ac7b6a3d04b75c1a6885482b063c;hb=50dd880d7e75b49e7c80c79f32165a756839651c;hp=3e89826cad2d4fb7bd0039bfc0c3f910083be0e9;hpb=8713667ec1a6cc9ba56c07f763e5a422cc47fbef;p=ardour.git diff --git a/gtk2_ardour/automation_line.cc b/gtk2_ardour/automation_line.cc index 3e89826cad..844063a227 100644 --- a/gtk2_ardour/automation_line.cc +++ b/gtk2_ardour/automation_line.cc @@ -33,6 +33,7 @@ #include "simplerect.h" #include "automation_line.h" #include "control_point.h" +#include "gui_thread.h" #include "rgb_macros.h" #include "ardour_ui.h" #include "public_editor.h" @@ -50,7 +51,6 @@ #include "i18n.h" using namespace std; -using namespace sigc; using namespace ARDOUR; using namespace PBD; using namespace Editing; @@ -84,11 +84,11 @@ AutomationLine::AutomationLine (const string& name, TimeAxisView& tv, ArdourCanv line->property_width_pixels() = (guint)1; line->set_data ("line", this); - line->signal_event().connect (mem_fun (*this, &AutomationLine::event_handler)); + line->signal_event().connect (sigc::mem_fun (*this, &AutomationLine::event_handler)); - alist->StateChanged.connect (mem_fun(*this, &AutomationLine::list_changed)); + alist->StateChanged.connect (_state_connection, invalidator (*this), boost::bind (&AutomationLine::list_changed, this), gui_context()); - trackview.session().register_with_memento_command_factory(alist->id(), this); + trackview.session()->register_with_memento_command_factory(alist->id(), this); if (alist->parameter().type() == GainAutomation || alist->parameter().type() == EnvelopeAutomation) { @@ -115,7 +115,7 @@ AutomationLine::queue_reset () { if (!update_pending) { update_pending = true; - Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &AutomationLine::reset)); + Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&AutomationLine::reset, this)); } } @@ -216,8 +216,8 @@ AutomationLine::modify_point_y (ControlPoint& cp, double y) double const x = trackview.editor().frame_to_unit (_time_converter.to((*cp.model())->when)); - trackview.editor().current_session()->begin_reversible_command (_("automation event move")); - trackview.editor().current_session()->add_command (new MementoCommand(*alist.get(), &get_state(), 0)); + trackview.editor().session()->begin_reversible_command (_("automation event move")); + trackview.editor().session()->add_command (new MementoCommand(*alist.get(), &get_state(), 0)); cp.move_to (x, y, ControlPoint::Full); reset_line_coords (cp); @@ -232,124 +232,9 @@ AutomationLine::modify_point_y (ControlPoint& cp, double y) update_pending = false; - trackview.editor().current_session()->add_command (new MementoCommand(*alist.get(), 0, &alist->get_state())); - trackview.editor().current_session()->commit_reversible_command (); - trackview.editor().current_session()->set_dirty (); -} - - -void -AutomationLine::modify_view_point (ControlPoint& cp, double x, double y, bool with_push) -{ - double delta = 0.0; - uint32_t last_movable = UINT_MAX; - double x_limit = DBL_MAX; - - /* this just changes the current view. it does not alter - the model in any way at all. - */ - - /* clamp y-coord appropriately. y is supposed to be a normalized fraction (0.0-1.0), - and needs to be converted to a canvas unit distance. - */ - - y = max (0.0, y); - y = min (1.0, y); - y = _height - (y * _height); - - if (cp.can_slide()) { - - /* x-coord cannot move beyond adjacent points or the start/end, and is - already in frames. it needs to be converted to canvas units. - */ - - x = trackview.editor().frame_to_unit (x); - - /* clamp x position using view coordinates */ - - ControlPoint *before; - ControlPoint *after; - - if (cp.view_index()) { - before = nth (cp.view_index() - 1); - x = max (x, before->get_x()+1.0); - } else { - before = &cp; - } - - - if (!with_push) { - if (cp.view_index() < control_points.size() - 1) { - - after = nth (cp.view_index() + 1); - - /*if it is a "spike" leave the x alone */ - - if (after->get_x() - before->get_x() < 2) { - x = cp.get_x(); - - } else { - x = min (x, after->get_x()-1.0); - } - } else { - after = &cp; - } - - } else { - - ControlPoint* after; - - /* find the first point that can't move */ - - for (uint32_t n = cp.view_index() + 1; (after = nth (n)) != 0; ++n) { - if (!after->can_slide()) { - x_limit = after->get_x() - 1.0; - last_movable = after->view_index(); - break; - } - } - - delta = x - cp.get_x(); - } - - } else { - - /* leave the x-coordinate alone */ - - x = trackview.editor().frame_to_unit (_time_converter.to((*cp.model())->when)); - - } - - if (!with_push) { - - cp.move_to (x, y, ControlPoint::Full); - reset_line_coords (cp); - - } else { - - uint32_t limit = min (control_points.size(), (size_t)last_movable); - - /* move the current point to wherever the user told it to go, subject - to x_limit. - */ - - cp.move_to (min (x, x_limit), y, ControlPoint::Full); - reset_line_coords (cp); - - /* now move all subsequent control points, to reflect the motion. - */ - - for (uint32_t i = cp.view_index() + 1; i < limit; ++i) { - ControlPoint *p = nth (i); - double new_x; - - if (p->can_slide()) { - new_x = min (p->get_x() + delta, x_limit); - p->move_to (new_x, p->get_y(), ControlPoint::Full); - reset_line_coords (*p); - } - } - } + trackview.editor().session()->add_command (new MementoCommand(*alist.get(), 0, &alist->get_state())); + trackview.editor().session()->commit_reversible_command (); + trackview.editor().session()->set_dirty (); } void @@ -362,15 +247,12 @@ AutomationLine::reset_line_coords (ControlPoint& cp) } void -AutomationLine::sync_model_with_view_line (uint32_t start, uint32_t end) +AutomationLine::sync_model_with_view_points (list cp, bool did_push, int64_t distance) { - ControlPoint *p; - update_pending = true; - for (uint32_t i = start; i <= end; ++i) { - p = nth(i); - sync_model_with_view_point (*p, false, 0); + for (list::iterator i = cp.begin(); i != cp.end(); ++i) { + sync_model_with_view_point (**i, did_push, distance); } } @@ -446,23 +328,17 @@ AutomationLine::determine_visible_control_points (ALPoints& points) uint32_t view_index, pi, n; AutomationList::iterator model; uint32_t npoints; - double last_control_point_x = 0.0; - double last_control_point_y = 0.0; uint32_t this_rx = 0; uint32_t prev_rx = 0; uint32_t this_ry = 0; - uint32_t prev_ry = 0; + uint32_t prev_ry = 0; double* slope; uint32_t box_size; - uint32_t cpsize; /* hide all existing points, and the line */ - cpsize = 0; - for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { (*i)->hide(); - ++cpsize; } line->hide (); @@ -494,6 +370,14 @@ AutomationLine::determine_visible_control_points (ALPoints& points) double tx = points[pi].x; double ty = points[pi].y; + if (find (_always_in_view.begin(), _always_in_view.end(), (*model)->when) != _always_in_view.end()) { + add_visible_control_point (view_index, pi, tx, ty, model, npoints); + prev_rx = this_rx; + prev_ry = this_ry; + ++view_index; + continue; + } + if (isnan (tx) || isnan (ty)) { warning << string_compose (_("Ignoring illegal points on AutomationLine \"%1\""), _name) << endmsg; @@ -532,70 +416,22 @@ AutomationLine::determine_visible_control_points (ALPoints& points) */ this_rx = (uint32_t) rint (tx); - this_ry = (uint32_t) rint (ty); + this_ry = (uint32_t) rint (ty); - if (view_index && pi != npoints && /* not the first, not the last */ + if (view_index && pi != npoints && /* not the first, not the last */ (((this_rx == prev_rx) && (this_ry == prev_ry)) || /* same point */ (((this_rx - prev_rx) < (box_size + 2)) && /* not identical, but still too close horizontally */ (abs ((int)(this_ry - prev_ry)) < (int) (box_size + 2))))) { /* too close vertically */ - continue; + continue; } /* ok, we should display this point */ - if (view_index >= cpsize) { - - /* make sure we have enough control points */ - - ControlPoint* ncp = new ControlPoint (*this); - - ncp->set_size (box_size); - - control_points.push_back (ncp); - ++cpsize; - } - - ControlPoint::ShapeType shape; - - if (!terminal_points_can_slide) { - if (pi == 0) { - control_points[view_index]->set_can_slide(false); - if (tx == 0) { - shape = ControlPoint::Start; - } else { - shape = ControlPoint::Full; - } - } else if (pi == npoints - 1) { - control_points[view_index]->set_can_slide(false); - shape = ControlPoint::End; - } else { - control_points[view_index]->set_can_slide(true); - shape = ControlPoint::Full; - } - } else { - control_points[view_index]->set_can_slide(true); - shape = ControlPoint::Full; - } - - last_control_point_x = tx; - last_control_point_y = ty; - - control_points[view_index]->reset (tx, ty, model, view_index, shape); - + add_visible_control_point (view_index, pi, tx, ty, model, npoints); + prev_rx = this_rx; prev_ry = this_ry; - /* finally, control visibility */ - - if (_visible && points_visible) { - control_points[view_index]->show (); - control_points[view_index]->set_visible (true); - } else { - if (!points_visible) { - control_points[view_index]->set_visible (false); - } - } - view_index++; } @@ -641,7 +477,6 @@ AutomationLine::determine_visible_control_points (ALPoints& points) } set_selected_points (trackview.editor().get_selection().points); - } string @@ -721,87 +556,191 @@ AutomationLine::invalidate_point (ALPoints& p, uint32_t index) p[index].y = DBL_MAX; } +/** Start dragging a single point, possibly adding others if the supplied point is selected and there + * are other selected points. + * + * @param cp Point to drag. + * @param x Initial x position (units). + * @param fraction Initial y position (as a fraction of the track height, where 0 is the bottom and 1 the top) + */ void -AutomationLine::start_drag (ControlPoint* cp, nframes_t x, float fraction) +AutomationLine::start_drag_single (ControlPoint* cp, double x, float fraction) { - if (trackview.editor().current_session() == 0) { /* how? */ - return; - } + trackview.editor().session()->begin_reversible_command (_("automation event move")); + trackview.editor().session()->add_command (new MementoCommand(*alist.get(), &get_state(), 0)); - string str; + _drag_points.clear (); + _drag_points.push_back (cp); - if (cp) { - str = _("automation event move"); - } else { - str = _("automation range drag"); + if (cp->selected ()) { + for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { + if (*i != cp && (*i)->selected()) { + _drag_points.push_back (*i); + } + } } + + start_drag_common (x, fraction); +} - trackview.editor().current_session()->begin_reversible_command (str); - trackview.editor().current_session()->add_command (new MementoCommand(*alist.get(), &get_state(), 0)); +/** Start dragging a line vertically (with no change in x) + * @param i1 Control point index of the `left' point on the line. + * @param i2 Control point index of the `right' point on the line. + * @param fraction Initial y position (as a fraction of the track height, where 0 is the bottom and 1 the top) + */ +void +AutomationLine::start_drag_line (uint32_t i1, uint32_t i2, float fraction) +{ + trackview.editor().session()->begin_reversible_command (_("automation range move")); + trackview.editor().session()->add_command (new MementoCommand(*alist.get(), &get_state(), 0)); - drag_x = x; - drag_distance = 0; - first_drag_fraction = fraction; - last_drag_fraction = fraction; - drags = 0; - did_push = false; + _drag_points.clear (); + for (uint32_t i = i1; i <= i2; i++) { + _drag_points.push_back (nth (i)); + } + + start_drag_common (0, fraction); } +/** Start dragging multiple points (with no change in x) + * @param cp Points to drag. + * @param fraction Initial y position (as a fraction of the track height, where 0 is the bottom and 1 the top) + */ void -AutomationLine::point_drag (ControlPoint& cp, nframes_t x, float fraction, bool with_push) +AutomationLine::start_drag_multiple (list cp, float fraction, XMLNode* state) { - if (x > drag_x) { - drag_distance += (x - drag_x); - } else { - drag_distance -= (drag_x - x); - } + trackview.editor().session()->begin_reversible_command (_("automation range move")); + trackview.editor().session()->add_command (new MementoCommand(*alist.get(), state, 0)); - drag_x = x; + _drag_points = cp; + start_drag_common (0, fraction); +} - modify_view_point (cp, x, fraction, with_push); - if (line_points.size() > 1) { - line->property_points() = line_points; +struct ControlPointSorter +{ + bool operator() (ControlPoint const * a, ControlPoint const * b) { + return a->get_x() < b->get_x(); } +}; - drags++; - did_push = with_push; -} - +/** Common parts of starting a drag. + * @param x Starting x position in units, or 0 if x is being ignored. + * @param fraction Starting y position (as a fraction of the track height, where 0 is the bottom and 1 the top) + */ void -AutomationLine::line_drag (uint32_t i1, uint32_t i2, float fraction, bool with_push) +AutomationLine::start_drag_common (double x, float fraction) { - double ydelta = fraction - last_drag_fraction; + _drag_x = x; + _drag_distance = 0; + _last_drag_fraction = fraction; + _drag_had_movement = false; + did_push = false; - did_push = with_push; + _drag_points.sort (ControlPointSorter ()); - last_drag_fraction = fraction; + /* find the additional points that will be dragged when the user is holding + the "push" modifier + */ - line_drag_cp1 = i1; - line_drag_cp2 = i2; + uint32_t i = _drag_points.back()->view_index () + 1; + ControlPoint* p = 0; + _push_points.clear (); + while ((p = nth (i)) != 0 && p->can_slide()) { + _push_points.push_back (p); + ++i; + } +} + +/** Should be called to indicate motion during a drag. + * @param x New x position of the drag in units, or undefined if ignore_x == true. + * @param fraction New y fraction. + * @return x position and y fraction that were actually used (once clamped). + */ +pair +AutomationLine::drag_motion (double x, float fraction, bool ignore_x, bool with_push) +{ + /* setup the points that are to be moved this time round */ + list points = _drag_points; + if (with_push) { + copy (_push_points.begin(), _push_points.end(), back_inserter (points)); + points.sort (ControlPointSorter ()); + } + + double dx = ignore_x ? 0 : (x - _drag_x); + double dy = fraction - _last_drag_fraction; - //check if one of the control points on the line is in a selected range - bool range_found = false; - ControlPoint *cp; + /* find x limits */ + ControlPoint* before = 0; + ControlPoint* after = 0; - for (uint32_t i = i1 ; i <= i2; i++) { - cp = nth (i); - if (cp->selected()) { - range_found = true; + for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { + if ((*i)->get_x() < points.front()->get_x()) { + before = *i; + } + if ((*i)->get_x() > points.back()->get_x() && after == 0) { + after = *i; } } - if (range_found) { - for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { - if ((*i)->selected()) { - modify_view_point (*(*i), trackview.editor().unit_to_frame ((*i)->get_x()), ((_height - (*i)->get_y()) /_height) + ydelta, with_push); + double const before_x = before ? before->get_x() : 0; + double const after_x = after ? after->get_x() : DBL_MAX; + + /* clamp x */ + for (list::iterator i = points.begin(); i != points.end(); ++i) { + + if ((*i)->can_slide() && !ignore_x) { + + /* clamp min x */ + double const a = (*i)->get_x() + dx; + double const b = before_x + 1; + if (a < b) { + dx += b - a; + } + + /* clamp max x */ + if (after) { + + if (after_x - before_x < 2) { + /* after and before are very close, so just leave this alone */ + dx = 0; + } else { + double const a = (*i)->get_x() + dx; + double const b = after_x - 1; + if (a > b) { + dx -= a - b; + } + } } } - } else { - ControlPoint *cp; - for (uint32_t i = i1 ; i <= i2; i++) { - cp = nth (i); - modify_view_point (*cp, trackview.editor().unit_to_frame (cp->get_x()), ((_height - cp->get_y()) /_height) + ydelta, with_push); + } + + /* clamp y */ + for (list::iterator i = points.begin(); i != points.end(); ++i) { + double const y = ((_height - (*i)->get_y()) / _height) + dy; + if (y < 0) { + dy -= y; + } + if (y > 1) { + dy -= (y - 1); + } + } + + pair const clamped (_drag_x + dx, _last_drag_fraction + dy); + _drag_distance += dx; + _drag_x = x; + _last_drag_fraction = fraction; + + for (list::iterator i = _drag_points.begin(); i != _drag_points.end(); ++i) { + (*i)->move_to ((*i)->get_x() + dx, (*i)->get_y() - _height * dy, ControlPoint::Full); + reset_line_coords (**i); + } + + if (with_push) { + /* move push points, preserving their y */ + for (list::iterator i = _push_points.begin(); i != _push_points.end(); ++i) { + (*i)->move_to ((*i)->get_x() + dx, (*i)->get_y(), ControlPoint::Full); + reset_line_coords (**i); } } @@ -809,34 +748,40 @@ AutomationLine::line_drag (uint32_t i1, uint32_t i2, float fraction, bool with_p line->property_points() = line_points; } - drags++; + _drag_had_movement = true; + did_push = with_push; + + return clamped; } +/** Should be called to indicate the end of a drag */ void -AutomationLine::end_drag (ControlPoint* cp) +AutomationLine::end_drag () { - if (!drags) { + if (!_drag_had_movement) { return; } alist->freeze (); - if (cp) { - sync_model_with_view_point (*cp, did_push, drag_distance); - } else { - sync_model_with_view_line (line_drag_cp1, line_drag_cp2); + /* set up the points that were moved this time round */ + list points = _drag_points; + if (did_push) { + copy (_push_points.begin(), _push_points.end(), back_inserter (points)); + points.sort (ControlPointSorter ()); } + + sync_model_with_view_points (points, did_push, rint (_drag_distance * trackview.editor().get_current_zoom ())); alist->thaw (); update_pending = false; - trackview.editor().current_session()->add_command (new MementoCommand(*alist.get(), 0, &alist->get_state())); - trackview.editor().current_session()->commit_reversible_command (); - trackview.editor().current_session()->set_dirty (); + trackview.editor().session()->add_command (new MementoCommand(*alist.get(), 0, &alist->get_state())); + trackview.editor().session()->commit_reversible_command (); + trackview.editor().session()->set_dirty (); } - void AutomationLine::sync_model_with_view_point (ControlPoint& cp, bool did_push, int64_t distance) { @@ -901,9 +846,8 @@ AutomationLine::sync_model_with_view_point (ControlPoint& cp, bool did_push, int as the main point moved. */ - alist->slide (mr.end, drag_distance); + alist->slide (mr.end, distance); } - } bool @@ -974,15 +918,15 @@ AutomationLine::remove_point (ControlPoint& cp) model_representation (cp, mr); - trackview.editor().current_session()->begin_reversible_command (_("remove control point")); + trackview.editor().session()->begin_reversible_command (_("remove control point")); XMLNode &before = alist->get_state(); alist->erase (mr.start, mr.end); - trackview.editor().current_session()->add_command(new MementoCommand( + trackview.editor().session()->add_command(new MementoCommand( *alist.get(), &before, &alist->get_state())); - trackview.editor().current_session()->commit_reversible_command (); - trackview.editor().current_session()->set_dirty (); + trackview.editor().session()->commit_reversible_command (); + trackview.editor().session()->set_dirty (); } void @@ -1021,7 +965,7 @@ AutomationLine::get_selectables (nframes_t& start, nframes_t& end, if (collecting) { - results.push_back (new AutomationSelectable (nstart, nend, botfrac, topfrac, trackview)); + results.push_back (new AutomationSelectable (nstart, nend, botfrac, topfrac, &trackview)); collecting = false; nstart = max_frames; nend = 0; @@ -1031,7 +975,7 @@ AutomationLine::get_selectables (nframes_t& start, nframes_t& end, } if (collecting) { - results.push_back (new AutomationSelectable (nstart, nend, botfrac, topfrac, trackview)); + results.push_back (new AutomationSelectable (nstart, nend, botfrac, topfrac, &trackview)); } } @@ -1042,92 +986,63 @@ AutomationLine::get_inverted_selectables (Selection&, list& /*resul // hmmm .... } -void -AutomationLine::set_selected_points (PointSelection& points) +/** Take a PointSelection and find ControlPoints that fall within it */ +list +AutomationLine::point_selection_to_control_points (PointSelection const & s) { - double top; - double bot; - - for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { - (*i)->set_selected(false); - } - - if (points.empty()) { - goto out; - } + list cp; + + for (PointSelection::const_iterator i = s.begin(); i != s.end(); ++i) { - for (PointSelection::iterator r = points.begin(); r != points.end(); ++r) { - - if (&(*r).track != &trackview) { + if (i->track != &trackview) { continue; } /* Curse X11 and its inverted coordinate system! */ - bot = (1.0 - (*r).high_fract) * _height; - top = (1.0 - (*r).low_fract) * _height; - - for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { - - double rstart, rend; - - rstart = trackview.editor().frame_to_unit ((*r).start); - rend = trackview.editor().frame_to_unit ((*r).end); + double const bot = (1.0 - i->high_fract) * _height; + double const top = (1.0 - i->low_fract) * _height; - if ((*i)->get_x() >= rstart && (*i)->get_x() <= rend) { + for (vector::iterator j = control_points.begin(); j != control_points.end(); ++j) { - if ((*i)->get_y() >= bot && (*i)->get_y() <= top) { + double const rstart = trackview.editor().frame_to_unit (i->start); + double const rend = trackview.editor().frame_to_unit (i->end); - (*i)->set_selected(true); + if ((*j)->get_x() >= rstart && (*j)->get_x() <= rend) { + if ((*j)->get_y() >= bot && (*j)->get_y() <= top) { + cp.push_back (*j); } } - } - } - out: - for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { - (*i)->show_color (false, !points_visible); } -} - -void AutomationLine::set_colors() { - set_line_color( ARDOUR_UI::config()->canvasvar_AutomationLine.get() ); - for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { - (*i)->show_color (false, !points_visible); - } + return cp; } void -AutomationLine::show_selection () +AutomationLine::set_selected_points (PointSelection& points) { - TimeSelection& time (trackview.editor().get_selection().time); - for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { + (*i)->set_selected (false); + } - (*i)->set_selected(false); - - for (list::iterator r = time.begin(); r != time.end(); ++r) { - double rstart, rend; - - rstart = trackview.editor().frame_to_unit ((*r).start); - rend = trackview.editor().frame_to_unit ((*r).end); - - if ((*i)->get_x() >= rstart && (*i)->get_x() <= rend) { - (*i)->set_selected(true); - break; - } + if (!points.empty()) { + list cp = point_selection_to_control_points (points); + for (list::iterator i = cp.begin(); i != cp.end(); ++i) { + (*i)->set_selected (true); } - - (*i)->show_color (false, !points_visible); } + + set_colors (); } -void -AutomationLine::hide_selection () +void AutomationLine::set_colors () { -// show_selection (); + set_line_color (ARDOUR_UI::config()->canvasvar_AutomationLine.get()); + for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { + (*i)->set_color (); + } } void @@ -1191,10 +1106,10 @@ AutomationLine::clear () /* parent must create command */ XMLNode &before = get_state(); alist->clear(); - trackview.editor().current_session()->add_command ( + trackview.editor().session()->add_command ( new MementoCommand(*this, &before, &get_state())); - trackview.editor().current_session()->commit_reversible_command (); - trackview.editor().current_session()->set_dirty (); + trackview.editor().session()->commit_reversible_command (); + trackview.editor().session()->set_dirty (); } void @@ -1215,9 +1130,10 @@ AutomationLine::show_all_control_points () points_visible = true; for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { - (*i)->show_color((_interpolation != AutomationList::Discrete), false); - (*i)->show (); - (*i)->set_visible (true); + if (!(*i)->visible()) { + (*i)->show (); + (*i)->set_visible (true); + } } } @@ -1260,7 +1176,7 @@ AutomationLine::get_state (void) return alist->get_state(); } -int +int AutomationLine::set_state (const XMLNode &node, int version) { /* function as a proxy for the model */ @@ -1322,3 +1238,66 @@ AutomationLine::set_interpolation(AutomationList::InterpolationStyle style) } } +void +AutomationLine::add_visible_control_point (uint32_t view_index, uint32_t pi, double tx, double ty, AutomationList::iterator model, uint32_t npoints) +{ + if (view_index >= control_points.size()) { + + /* make sure we have enough control points */ + + ControlPoint* ncp = new ControlPoint (*this); + ncp->set_size (control_point_box_size ()); + + control_points.push_back (ncp); + } + + ControlPoint::ShapeType shape; + + if (!terminal_points_can_slide) { + if (pi == 0) { + control_points[view_index]->set_can_slide(false); + if (tx == 0) { + shape = ControlPoint::Start; + } else { + shape = ControlPoint::Full; + } + } else if (pi == npoints - 1) { + control_points[view_index]->set_can_slide(false); + shape = ControlPoint::End; + } else { + control_points[view_index]->set_can_slide(true); + shape = ControlPoint::Full; + } + } else { + control_points[view_index]->set_can_slide(true); + shape = ControlPoint::Full; + } + + control_points[view_index]->reset (tx, ty, model, view_index, shape); + + /* finally, control visibility */ + + if (_visible && points_visible) { + control_points[view_index]->show (); + control_points[view_index]->set_visible (true); + } else { + if (!points_visible) { + control_points[view_index]->set_visible (false); + } + } +} + +void +AutomationLine::add_always_in_view (double x) +{ + _always_in_view.push_back (x); + alist->apply_to_points (*this, &AutomationLine::reset_callback); +} + +void +AutomationLine::clear_always_in_view () +{ + _always_in_view.clear (); + alist->apply_to_points (*this, &AutomationLine::reset_callback); +} +