X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fautomation_line.cc;h=a72916191173a202609b0e388837dc3b450c006d;hb=1315ee3dff1e4966ab28bd47e81b5f003cac6e40;hp=44c100fd3760aac4c0eb7c37f341f8bc3105b45e;hpb=ef6b25432d9c46d71b08c0f7d5f2686df428c4e8;p=ardour.git diff --git a/gtk2_ardour/automation_line.cc b/gtk2_ardour/automation_line.cc index 44c100fd37..a729161911 100644 --- a/gtk2_ardour/automation_line.cc +++ b/gtk2_ardour/automation_line.cc @@ -15,15 +15,16 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id$ */ #include #include #include +#include #include #include +#include #include #include @@ -231,6 +232,7 @@ AutomationLine::AutomationLine (const string & name, TimeAxisView& tv, ArdourCan no_draw = false; _visible = true; terminal_points_can_slide = true; + _y_position = 0; _height = 0; group = new ArdourCanvas::Group (parent); @@ -306,17 +308,27 @@ AutomationLine::control_point_box_size () } void -AutomationLine::set_height (guint32 h) +AutomationLine::set_y_position_and_height (guint32 y, guint32 h) { + bool changed = false; + + if (y != _y_position) { + _y_position = y; + changed = true; + } + if (h != _height) { _height = h; - double bsz = control_point_box_size(); + double const bsz = control_point_box_size(); for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { (*i)->set_size (bsz); } + changed = true; + } + if (changed) { reset (); } } @@ -347,13 +359,6 @@ AutomationLine::nth (uint32_t n) } } -void -AutomationLine::modify_view (ControlPoint& cp, double x, double y, bool with_push) -{ - modify_view_point (cp, x, y, with_push); - update_line (); -} - void AutomationLine::modify_view_point (ControlPoint& cp, double x, double y, bool with_push) { @@ -371,7 +376,7 @@ AutomationLine::modify_view_point (ControlPoint& cp, double x, double y, bool wi y = max (0.0, y); y = min (1.0, y); - y = _height - (y * _height); + y = _y_position + _height - (y * _height); if (cp.can_slide) { @@ -416,7 +421,7 @@ AutomationLine::modify_view_point (ControlPoint& cp, double x, double y, bool wi 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; @@ -471,14 +476,10 @@ AutomationLine::modify_view_point (ControlPoint& cp, double x, double y, bool wi void AutomationLine::reset_line_coords (ControlPoint& cp) { - line_points[cp.view_index].set_x (cp.get_x()); - line_points[cp.view_index].set_y (cp.get_y()); -} - -void -AutomationLine::update_line () -{ - line->property_points() = line_points; + if (cp.view_index < line_points.size()) { + line_points[cp.view_index].set_x (cp.get_x()); + line_points[cp.view_index].set_y (cp.get_y()); + } } void @@ -491,10 +492,8 @@ AutomationLine::sync_model_with_view_line (uint32_t start, uint32_t end) for (uint32_t i = start; i <= end; ++i) { p = nth(i); - sync_model_with_view_point(*p); + sync_model_with_view_point (*p, false, 0); } - - } void @@ -506,8 +505,7 @@ AutomationLine::model_representation (ControlPoint& cp, ModelRepresentation& mr) */ mr.xval = (nframes_t) floor (cp.get_x()); - mr.yval = 1.0 - (cp.get_y() / _height); - + mr.yval = 1.0 - ( (cp.get_y() - _y_position) / _height); /* if xval has not changed, set it directly from the model to avoid rounding errors */ @@ -517,7 +515,6 @@ AutomationLine::model_representation (ControlPoint& cp, ModelRepresentation& mr) mr.xval = trackview.editor.unit_to_frame (mr.xval); } - /* virtual call: this will do the right thing for whatever particular type of line we are. */ @@ -566,98 +563,6 @@ AutomationLine::model_representation (ControlPoint& cp, ModelRepresentation& mr) } } -void -AutomationLine::sync_model_from (ControlPoint& cp) -{ - ControlPoint* p; - uint32_t lasti; - - sync_model_with_view_point (cp); - - /* we might have moved all points after `cp' by some amount - if we pressed the with_push modifyer some of the time during the drag - so all subsequent points have to be resynced - */ - - lasti = control_points.size() - 1; - p = nth (lasti); - - update_pending = true; - - while (p != &cp && lasti) { - sync_model_with_view_point (*p); - --lasti; - p = nth (lasti); - } -} - -void -AutomationLine::sync_model_with_view_point (ControlPoint& cp) -{ - ModelRepresentation mr; - double ydelta; - - model_representation (cp, mr); - - /* part 4: how much are we changing the central point by */ - - ydelta = mr.yval - mr.ypos; - - /* IMPORTANT: changing the model when the x-coordinate changes - may invalidate the iterators that we are using. this means that we have - to change the points before+after the one corresponding to the visual CP - first (their x-coordinate doesn't change). then we change the - "main" point. - - apply the full change to the central point, and interpolate - in each direction to cover all model points represented - by the control point. - */ - - /* part 5: change all points before the primary point */ - - for (AutomationList::iterator i = mr.start; i != cp.model; ++i) { - - double delta; - - delta = ydelta * ((*i)->when - mr.xmin) / (mr.xpos - mr.xmin); - - /* x-coordinate (generally time) stays where it is, - y-coordinate moves by a certain amount. - */ - - update_pending = true; - change_model (i, (*i)->when, mr.yval + delta); - } - - /* part 6: change later points */ - - AutomationList::iterator i = cp.model; - - ++i; - - while (i != mr.end) { - - double delta; - - delta = ydelta * (mr.xmax - (*i)->when) / (mr.xmax - mr.xpos); - - /* x-coordinate (generally time) stays where it is, - y-coordinate moves by a certain amount. - */ - - update_pending = true; - change_model (i, (*i)->when, (*i)->value + delta); - - ++i; - } - - /* part 7: change the primary point */ - - update_pending = true; - change_model (cp.model, mr.xval, mr.yval); -} - void AutomationLine::determine_visible_control_points (ALPoints& points) { @@ -748,10 +653,10 @@ AutomationLine::determine_visible_control_points (ALPoints& points) 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)) && /* too close horizontally */ - ((abs ((int)(this_ry - prev_ry)) < (int) (box_size + 2)))))) { /* too close vertically */ + (((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; - } + } /* ok, we should display this point */ @@ -810,7 +715,7 @@ AutomationLine::determine_visible_control_points (ALPoints& points) view_index++; } - + /* discard extra CP's to avoid confusing ourselves */ while (control_points.size() > view_index) { @@ -849,9 +754,11 @@ AutomationLine::determine_visible_control_points (ALPoints& points) if (_visible) { line->show (); } + } set_selected_points (trackview.editor.get_selection().points); + } string @@ -886,7 +793,7 @@ AutomationLine::invalidate_point (ALPoints& p, uint32_t index) } void -AutomationLine::start_drag (ControlPoint* cp, float fraction) +AutomationLine::start_drag (ControlPoint* cp, nframes_t x, float fraction) { if (trackview.editor.current_session() == 0) { /* how? */ return; @@ -901,24 +808,43 @@ AutomationLine::start_drag (ControlPoint* cp, float fraction) } trackview.editor.current_session()->begin_reversible_command (str); - trackview.editor.current_session()->add_command (new MementoCommand(*this, &get_state(), 0)); + trackview.editor.current_session()->add_command (new MementoCommand(alist, &get_state(), 0)); + drag_x = x; + drag_distance = 0; first_drag_fraction = fraction; last_drag_fraction = fraction; drags = 0; + did_push = false; } void AutomationLine::point_drag (ControlPoint& cp, nframes_t x, float fraction, bool with_push) { - modify_view (cp, x, fraction, with_push); + if (x > drag_x) { + drag_distance += (x - drag_x); + } else { + drag_distance -= (drag_x - x); + } + + drag_x = x; + + modify_view_point (cp, x, fraction, with_push); + + if (line_points.size() > 1) { + line->property_points() = line_points; + } + drags++; + did_push = with_push; } void AutomationLine::line_drag (uint32_t i1, uint32_t i2, float fraction, bool with_push) { - double ydelta = fraction - last_drag_fraction; + double const ydelta = fraction - last_drag_fraction; + + did_push = with_push; last_drag_fraction = fraction; @@ -929,10 +855,12 @@ AutomationLine::line_drag (uint32_t i1, uint32_t i2, float fraction, bool with_p 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); + modify_view_point (*cp, trackview.editor.unit_to_frame (cp->get_x()), ((_height - cp->get_y() + _y_position) /_height) + ydelta, with_push); } - update_line (); + if (line_points.size() > 1) { + line->property_points() = line_points; + } drags++; } @@ -940,20 +868,95 @@ AutomationLine::line_drag (uint32_t i1, uint32_t i2, float fraction, bool with_p void AutomationLine::end_drag (ControlPoint* cp) { - if (drags) { + if (!drags) { + return; + } - if (cp) { - sync_model_from (*cp); - } else { - sync_model_with_view_line (line_drag_cp1, line_drag_cp2); + 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); + } + + alist.thaw (); + + update_pending = false; + + trackview.editor.current_session()->add_command (new MementoCommand(alist, 0, &alist.get_state())); + trackview.editor.current_session()->commit_reversible_command (); + trackview.editor.current_session()->set_dirty (); +} + + +void +AutomationLine::sync_model_with_view_point (ControlPoint& cp, bool did_push, int64_t distance) +{ + ModelRepresentation mr; + double ydelta; + + model_representation (cp, mr); + + /* how much are we changing the central point by */ + + ydelta = mr.yval - mr.ypos; + + /* + apply the full change to the central point, and interpolate + on both axes to cover all model points represented + by the control point. + */ + + /* change all points before the primary point */ + + for (AutomationList::iterator i = mr.start; i != cp.model; ++i) { + + double fract = ((*i)->when - mr.xmin) / (mr.xpos - mr.xmin); + double y_delta = ydelta * fract; + double x_delta = distance * fract; + + /* interpolate */ + + if (y_delta || x_delta) { + alist.modify (i, (*i)->when + x_delta, mr.ymin + y_delta); } + } + + /* change the primary point */ - update_pending = false; + update_pending = true; + alist.modify (cp.model, mr.xval, mr.yval); - trackview.editor.current_session()->add_command (new MementoCommand(*this, 0, &get_state())); - trackview.editor.current_session()->commit_reversible_command (); - trackview.editor.current_session()->set_dirty (); + + /* change later points */ + + AutomationList::iterator i = cp.model; + + ++i; + + while (i != mr.end) { + + double delta = ydelta * (mr.xmax - (*i)->when) / (mr.xmax - mr.xpos); + + /* all later points move by the same distance along the x-axis as the main point */ + + if (delta) { + alist.modify (i, (*i)->when + distance, (*i)->value + delta); + } + + ++i; } + + if (did_push) { + + /* move all points after the range represented by the view by the same distance + as the main point moved. + */ + + alist.slide (mr.end, drag_distance); + } + } bool @@ -1027,11 +1030,11 @@ AutomationLine::remove_point (ControlPoint& cp) model_representation (cp, mr); trackview.editor.current_session()->begin_reversible_command (_("remove control point")); - XMLNode &before = get_state(); + XMLNode &before = alist.get_state(); alist.erase (mr.start, mr.end); - trackview.editor.current_session()->add_command(new MementoCommand(*this, &before, &get_state())); + trackview.editor.current_session()->add_command(new MementoCommand(alist, &before, &alist.get_state())); trackview.editor.current_session()->commit_reversible_command (); trackview.editor.current_session()->set_dirty (); } @@ -1049,8 +1052,8 @@ AutomationLine::get_selectables (nframes_t& start, nframes_t& end, /* Curse X11 and its inverted coordinate system! */ - bot = (1.0 - topfrac) * _height; - top = (1.0 - botfrac) * _height; + bot = _y_position + (1.0 - topfrac) * _height; + top = _y_position + (1.0 - botfrac) * _height; nstart = max_frames; nend = 0; @@ -1116,8 +1119,8 @@ AutomationLine::set_selected_points (PointSelection& points) /* Curse X11 and its inverted coordinate system! */ - bot = (1.0 - (*r).high_fract) * _height; - top = (1.0 - (*r).low_fract) * _height; + bot = _y_position + (1.0 - (*r).high_fract) * _height; + top = _y_position + (1.0 - (*r).low_fract) * _height; for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { @@ -1144,13 +1147,18 @@ AutomationLine::set_selected_points (PointSelection& points) } +void AutomationLine::set_colors() { + set_line_color( color_map[cAutomationLine] ); + for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { + (*i)->show_color (false, !points_visible); + } +} + void AutomationLine::show_selection () { TimeSelection& time (trackview.editor.get_selection().time); - // cerr << "show selection\n"; - for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { (*i)->selected = false; @@ -1174,7 +1182,6 @@ AutomationLine::show_selection () void AutomationLine::hide_selection () { - // cerr << "hide selection\n"; // show_selection (); } @@ -1207,7 +1214,7 @@ AutomationLine::reset_callback (const AutomationList& events) model_to_view_y (translated_y); tmp_points.push_back (ALPoint (trackview.editor.frame_to_unit ((*ai)->when), - _height - (translated_y * _height))); + _y_position + _height - (translated_y * _height))); } determine_visible_control_points (tmp_points); @@ -1239,7 +1246,6 @@ AutomationLine::clear () void AutomationLine::change_model (AutomationList::iterator i, double x, double y) { - alist.modify (i, (nframes_t) x, y); } void