From 37dd777c9acf3d80a6fb0f2b20e10fb0de61414d Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 11 Jan 2010 19:36:29 +0000 Subject: Fix confusion about last_pointer_* variables under snap. Update verbose canvas cursor correctly when automation point drags are clamped. Clamp multi-point automation drags horizontally. git-svn-id: svn://localhost/ardour2/branches/3.0@6474 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/automation_line.cc | 272 ++++++++++++++++------------------------ gtk2_ardour/automation_line.h | 12 +- gtk2_ardour/editor_drag.cc | 25 ++-- gtk2_ardour/region_gain_line.cc | 2 +- gtk2_ardour/region_gain_line.h | 2 +- 5 files changed, 131 insertions(+), 182 deletions(-) diff --git a/gtk2_ardour/automation_line.cc b/gtk2_ardour/automation_line.cc index 03df016adf..f01d1f3edd 100644 --- a/gtk2_ardour/automation_line.cc +++ b/gtk2_ardour/automation_line.cc @@ -237,119 +237,6 @@ AutomationLine::modify_point_y (ControlPoint& cp, double y) trackview.editor().session()->set_dirty (); } -/** Move a view point to a new position (without changing the model) - * @param y New y position as a normalised fraction (0.0-1.0) - */ -void -AutomationLine::modify_view_point (ControlPoint& cp, double x, double y, bool keep_x, bool with_push) -{ - double delta = 0.0; - uint32_t last_movable = UINT_MAX; - double x_limit = DBL_MAX; - - /* 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() && !keep_x) { - - /* 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); - } - } - } -} - void AutomationLine::reset_line_coords (ControlPoint& cp) { @@ -673,11 +560,11 @@ AutomationLine::invalidate_point (ALPoints& p, uint32_t index) * are other selected points. * * @param cp Point to drag. - * @param x Initial x position (frames). + * @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_single (ControlPoint* cp, nframes_t x, float fraction) +AutomationLine::start_drag_single (ControlPoint* cp, double x, float fraction) { trackview.editor().session()->begin_reversible_command (_("automation event move")); trackview.editor().session()->add_command (new MementoCommand(*alist.get(), &get_state(), 0)); @@ -708,28 +595,8 @@ AutomationLine::start_drag_line (uint32_t i1, uint32_t i2, float fraction) trackview.editor().session()->add_command (new MementoCommand(*alist.get(), &get_state(), 0)); _drag_points.clear (); - - // check if one of the control points on the line is in a selected range - bool range_found = false; - ControlPoint *cp; - - for (uint32_t i = i1 ; i <= i2; i++) { - cp = nth (i); - if (cp->selected()) { - range_found = true; - } - } - - if (range_found) { - for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { - if ((*i)->selected()) { - _drag_points.push_back (*i); - } - } - } else { - for (uint32_t i = i1 ; i <= i2; i++) { - _drag_points.push_back (nth (i)); - } + for (uint32_t i = i1; i <= i2; i++) { + _drag_points.push_back (nth (i)); } start_drag_common (0, fraction); @@ -749,36 +616,108 @@ AutomationLine::start_drag_multiple (list cp, float fraction, XML start_drag_common (0, fraction); } + +struct ControlPointSorter +{ + bool operator() (ControlPoint const * a, ControlPoint const * b) { + return a->get_x() < b->get_x(); + } +}; + /** Common parts of starting a drag. * @param d Description of the drag. - * @param x Starting x position in frames, or 0 if x is being ignored. + * @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::start_drag_common (nframes_t x, float fraction) +AutomationLine::start_drag_common (double x, float fraction) { - drag_x = x; - drag_distance = 0; + _drag_x = x; + _drag_distance = 0; _last_drag_fraction = fraction; _drag_had_movement = false; did_push = false; + + _drag_points.sort (ControlPointSorter ()); + + /* find the additional points that will be dragged when the user is holding + the "push" modifier + */ + + 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 frames, or 0 if x is being ignored. + * @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 (nframes_t x, float fraction, bool with_push) +pair +AutomationLine::drag_motion (double x, float fraction, bool ignore_x, bool with_push) { - int64_t const dx = x - drag_x; + /* 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; - /* clamp y so that the "lowest" point hits the bottom but goes no further - and similarly with the "highest" and the top - */ - for (list::iterator i = _drag_points.begin(); i != _drag_points.end(); ++i) { + /* find x limits */ + ControlPoint* before = 0; + ControlPoint* after = 0; + + 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; + } + } + + 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; + } + } + } + } + } + + /* 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; @@ -788,20 +727,22 @@ AutomationLine::drag_motion (nframes_t x, float fraction, bool with_push) } } - pair const clamped (drag_x + dx, _last_drag_fraction + dy); - drag_distance += dx; - drag_x += dx; - _last_drag_fraction += dy; + 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); + } - modify_view_point ( - **i, - trackview.editor().unit_to_frame ((*i)->get_x()) + dx, - ((_height - (*i)->get_y()) / _height) + dy, - (x == 0), - with_push - ); + 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); + } } if (line_points.size() > 1) { @@ -824,7 +765,14 @@ AutomationLine::end_drag () alist->freeze (); - sync_model_with_view_points (_drag_points, did_push, drag_distance); + /* 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 (); @@ -899,7 +847,7 @@ 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); } } diff --git a/gtk2_ardour/automation_line.h b/gtk2_ardour/automation_line.h index 7f33481e55..3e0f0f4bb3 100644 --- a/gtk2_ardour/automation_line.h +++ b/gtk2_ardour/automation_line.h @@ -75,10 +75,10 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible bool control_points_adjacent (double xval, uint32_t& before, uint32_t& after); /* dragging API */ - virtual void start_drag_single (ControlPoint*, nframes_t x, float); + virtual void start_drag_single (ControlPoint*, double, float); virtual void start_drag_line (uint32_t, uint32_t, float); virtual void start_drag_multiple (std::list, float, XMLNode *); - virtual std::pair drag_motion (nframes_t, float, bool); + virtual std::pair drag_motion (double, float, bool, bool); virtual void end_drag (); ControlPoint* nth (uint32_t); @@ -168,7 +168,7 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible void determine_visible_control_points (ALPoints&); void sync_model_with_view_point (ControlPoint&, bool, int64_t); void sync_model_with_view_points (std::list, bool, int64_t); - void start_drag_common (nframes_t, float); + void start_drag_common (double, float); virtual void change_model (ARDOUR::AutomationList::iterator, double x, double y); @@ -181,16 +181,16 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulDestructible private: std::list _drag_points; ///< points we are dragging + std::list _push_points; ///< additional points we are dragging if "push" is enabled bool _drag_had_movement; ///< true if the drag has seen movement, otherwise false - nframes64_t drag_x; ///< last x position of the drag, in frames - nframes64_t drag_distance; ///< total x movement of the drag, in frames + double _drag_x; ///< last x position of the drag, in units + double _drag_distance; ///< total x movement of the drag, in units double _last_drag_fraction; ///< last y position of the drag, as a fraction std::list _always_in_view; const Evoral::TimeConverter& _time_converter; ARDOUR::AutomationList::InterpolationStyle _interpolation; - void modify_view_point (ControlPoint&, double, double, bool, bool with_push); void reset_line_coords (ControlPoint&); void add_visible_control_point (uint32_t, uint32_t, double, double, ARDOUR::AutomationList::iterator, uint32_t); diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index 66932e4097..6db97fde4c 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -181,9 +181,6 @@ Drag::adjusted_current_frame (GdkEvent const * event, bool snap) const bool Drag::motion_handler (GdkEvent* event, bool from_autoscroll) { - _last_pointer_x = _current_pointer_x; - _last_pointer_y = _current_pointer_y; - _last_pointer_frame = adjusted_current_frame (event); _current_pointer_frame = _editor->event_frame (event, &_current_pointer_x, &_current_pointer_y); /* check to see if we have moved in any way that matters since the last motion event */ @@ -212,6 +209,11 @@ Drag::motion_handler (GdkEvent* event, bool from_autoscroll) } motion (event, _move_threshold_passed != old_move_threshold_passed); + + _last_pointer_x = _current_pointer_x; + _last_pointer_y = _current_pointer_y; + _last_pointer_frame = adjusted_current_frame (event); + return true; } } @@ -2619,11 +2621,10 @@ ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/) // the point doesn't 'jump' to the mouse after the first drag _time_axis_view_grab_x = _point->get_x(); _time_axis_view_grab_y = _point->get_y(); - nframes64_t grab_frame = _editor->pixel_to_frame (_time_axis_view_grab_x); float const fraction = 1 - (_point->get_y() / _point->line().height()); - _point->line().start_drag_single (_point, grab_frame, fraction); + _point->line().start_drag_single (_point, _time_axis_view_grab_x, fraction); _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction), event->button.x + 10, event->button.y + 10); @@ -2679,9 +2680,9 @@ ControlPointDrag::motion (GdkEvent* event, bool) bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier); - pair const c = _point->line().drag_motion (cx_frames, fraction, push); + _point->line().drag_motion (_editor->frame_to_unit (cx_frames), fraction, false, push); - _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (c.second)); + _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction)); } void @@ -2796,10 +2797,10 @@ LineDrag::motion (GdkEvent* event, bool) push = true; } - /* we are ignoring x position for this drag, so we can just pass in 0 */ - pair const c = _line->drag_motion (0, fraction, push); + /* we are ignoring x position for this drag, so we can just pass in anything */ + _line->drag_motion (0, fraction, true, push); - _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (c.second)); + _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction)); } void @@ -3814,8 +3815,8 @@ AutomationRangeDrag::motion (GdkEvent* event, bool first_move) float const f = 1 - (current_pointer_y() / _line->height()); - /* we are ignoring x position for this drag, so we can just pass in 0 */ - _line->drag_motion (0, f, false); + /* we are ignoring x position for this drag, so we can just pass in anything */ + _line->drag_motion (0, f, true, false); } void diff --git a/gtk2_ardour/region_gain_line.cc b/gtk2_ardour/region_gain_line.cc index a2c5cffa5a..827562524e 100644 --- a/gtk2_ardour/region_gain_line.cc +++ b/gtk2_ardour/region_gain_line.cc @@ -50,7 +50,7 @@ AudioRegionGainLine::AudioRegionGainLine (const string & name, AudioRegionView& } void -AudioRegionGainLine::start_drag_single (ControlPoint* cp, nframes_t x, float fraction) +AudioRegionGainLine::start_drag_single (ControlPoint* cp, double x, float fraction) { AutomationLine::start_drag_single (cp, x, fraction); diff --git a/gtk2_ardour/region_gain_line.h b/gtk2_ardour/region_gain_line.h index 0f16372287..c781f20228 100644 --- a/gtk2_ardour/region_gain_line.h +++ b/gtk2_ardour/region_gain_line.h @@ -38,7 +38,7 @@ class AudioRegionGainLine : public AutomationLine public: AudioRegionGainLine (const std::string & name, AudioRegionView&, ArdourCanvas::Group& parent, boost::shared_ptr); - void start_drag_single (ControlPoint*, nframes_t x, float fraction); + void start_drag_single (ControlPoint*, double, float); void end_drag (); void remove_point (ControlPoint&); -- cgit v1.2.3