diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index 7f53a1733d..0725f543fe 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -7243,6 +7243,8 @@ FreehandLineDrag::FreehandLineDrag (Editor* edito , edge_x (0) , did_snap (false) , line_break_pending (false) + , line_start_x (-1) + , line_start_y (-1) { DEBUG_TRACE (DEBUG::Drags, "New FreehandLinDrag\n"); } @@ -7305,6 +7307,11 @@ FreehandLineDrag::maybe_add_point (GdkEvent* ev, double x = pointer_x - r.x0; double y = ev->motion.y - r.y0; + if (drawn_points.empty()) { + line_start_x = x; + line_start_y = y; + } + if (x < 0) { dragging_line->clear (); drawn_points.clear (); @@ -7319,12 +7326,12 @@ FreehandLineDrag::maybe_add_point (GdkEvent* ev, bool add_point = false; bool pop_point = false; - const bool line = Keyboard::modifier_state_equals (ev->motion.state, Keyboard::PrimaryModifier); + const bool straight_line = Keyboard::modifier_state_equals (ev->motion.state, Keyboard::PrimaryModifier); if (direction > 0) { - if (x < r.width() && (line || (pointer_x > edge_x) || (pointer_x == edge_x && ev->motion.y != last_pointer_y()))) { + if (x < r.width() && (straight_line || (pointer_x > edge_x) || (pointer_x == edge_x && ev->motion.y != last_pointer_y()))) { - if (line && dragging_line->get().size() > 1) { + if (straight_line && dragging_line->get().size() > 1) { pop_point = true; } @@ -7333,9 +7340,9 @@ FreehandLineDrag::maybe_add_point (GdkEvent* ev, } else if (direction < 0) { - if (x >= 0. && (line || (pointer_x < edge_x) || (pointer_x == edge_x && ev->motion.y != last_pointer_y()))) { + if (x >= 0. && (straight_line || (pointer_x < edge_x) || (pointer_x == edge_x && ev->motion.y != last_pointer_y()))) { - if (line && dragging_line->get().size() > 1) { + if (straight_line && dragging_line->get().size() > 1) { pop_point = true; } @@ -7343,6 +7350,13 @@ FreehandLineDrag::maybe_add_point (GdkEvent* ev, } } + if (straight_line) { + if (dragging_line->get().size() > 1) { + pop_point = true; + } + add_point = true; + } + bool child_call = false; if (pop_point) { @@ -7364,7 +7378,11 @@ FreehandLineDrag::maybe_add_point (GdkEvent* ev, } if (child_call) { - point_added (ArdourCanvas::Duple (pointer_x, y), base_rect, first_move ? -1 : edge_x); + if (straight_line && !first_move) { + line_extended (ArdourCanvas::Duple (line_start_x, line_start_y), ArdourCanvas::Duple (pointer_x, y), base_rect, first_move ? -1 : edge_x); + } else { + point_added (ArdourCanvas::Duple (pointer_x, y), base_rect, first_move ? -1 : edge_x); + } } if (add_point) { @@ -7483,6 +7501,12 @@ VelocityLineDrag::point_added (Duple const & d, ArdourCanvas::Rectangle const & drag_did_change |= grv->line_draw_motion (d, r, last_x); } +void +VelocityLineDrag::line_extended (Duple const & from, Duple const & to, ArdourCanvas::Rectangle const & r, double last_x) +{ + drag_did_change |= grv->line_extended (from, to, r, last_x); +} + void VelocityLineDrag::finished (GdkEvent* event, bool motion_occured) { diff --git a/gtk2_ardour/editor_drag.h b/gtk2_ardour/editor_drag.h index 805e7138a1..46f97a6810 100644 --- a/gtk2_ardour/editor_drag.h +++ b/gtk2_ardour/editor_drag.h @@ -1582,6 +1582,9 @@ class FreehandLineDrag : public Drag void finished (GdkEvent*, bool); bool mid_drag_key_event (GdkEventKey*); virtual void point_added (ArdourCanvas::Duple const & d, ArdourCanvas::Rectangle const & r, double last_x) {} + virtual void line_extended (ArdourCanvas::Duple const & from, ArdourCanvas::Duple const & to, ArdourCanvas::Rectangle const & r, double last_x) { + point_added (to, r, last_x); + } protected: ArdourCanvas::Item* parent; /* we do not own this. If null, use base_rect as the parent */ @@ -1592,6 +1595,8 @@ class FreehandLineDrag : public Drag bool did_snap; bool line_break_pending; OrderedPointList drawn_points; + ArdourCanvas::Coord line_start_x; + ArdourCanvas::Coord line_start_y; void maybe_add_point (GdkEvent*, Temporal::timepos_t const &, bool first_move); }; @@ -1616,6 +1621,7 @@ class VelocityLineDrag : public FreehandLineDrag notes, std::vector velocities) +{ + assert (notes.size() == velocities.size()); + + /* Does not use selection, used when drawing/dragging in velocity lane */ + + bool changed = false; + + auto notei = notes.begin(); + auto veloi = velocities.begin(); + + while (notei != notes.end()) { + + int delta = (*veloi) - (*notei)->note()->velocity(); + + if (delta) { + changed = true; + change_note_velocity (*notei, delta, true); + } + + ++notei; + ++veloi; + } + + return changed; +} + bool MidiRegionView::set_velocity_for_notes (std::vector notes, int velocity) { diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h index 14065da87b..c70f1295d2 100644 --- a/gtk2_ardour/midi_region_view.h +++ b/gtk2_ardour/midi_region_view.h @@ -185,6 +185,7 @@ public: void end_drag_edit (bool apply); void display_model(std::shared_ptr model); + std::shared_ptr model() const { return _model; } /* note_diff commands should start here; this initiates an undo record */ void start_note_diff_command (std::string name = "midi edit"); @@ -295,6 +296,7 @@ public: void change_velocities (bool up, bool fine, bool allow_smush, bool all_together); void set_velocity (NoteBase* primary, int velocity); bool set_velocity_for_notes (std::vector notes, int velocity); + bool set_velocities_for_notes (std::vector notes, std::vector velocities); void transpose (bool up, bool fine, bool allow_smush); void nudge_notes (bool forward, bool fine); void channel_edit (); diff --git a/gtk2_ardour/note_base.h b/gtk2_ardour/note_base.h index f7a6463e7a..ee2d677ba5 100644 --- a/gtk2_ardour/note_base.h +++ b/gtk2_ardour/note_base.h @@ -132,7 +132,7 @@ class NoteBase : public sigc::trackable /// hue circle divided into 16 equal-looking parts, courtesy Thorsten Wilms static const uint32_t midi_channel_colors[16]; - + bool mouse_near_ends () const; virtual bool big_enough_to_trim () const; diff --git a/gtk2_ardour/velocity_ghost_region.cc b/gtk2_ardour/velocity_ghost_region.cc index 848287927b..9f1cea4a45 100644 --- a/gtk2_ardour/velocity_ghost_region.cc +++ b/gtk2_ardour/velocity_ghost_region.cc @@ -86,14 +86,51 @@ VelocityGhostRegion::line_draw_motion (ArdourCanvas::Duple const & d, ArdourCanv lollis_between (d.x, last_x, affected_lollis); } - bool ret = false; - - if (!affected_lollis.empty()) { - int velocity = y_position_to_velocity (r.height() - (r.y1() - d.y)); - ret = mrv->set_velocity_for_notes (affected_lollis, velocity); - mrv->mid_drag_edit (); + if (affected_lollis.empty()) { + return false; } + int velocity = y_position_to_velocity (r.height() - (r.y1() - d.y)); + bool ret = mrv->set_velocity_for_notes (affected_lollis, velocity); + mrv->mid_drag_edit (); + + return ret; +} + +bool +VelocityGhostRegion::line_extended (ArdourCanvas::Duple const & from, ArdourCanvas::Duple const & to, ArdourCanvas::Rectangle const & r, double last_x) +{ + std::vector affected_lollis; + + lollis_between (from.x, to.x, affected_lollis); + + if (affected_lollis.empty()) { + return false; + } + + if (to.x == from.x) { + /* no x-axis motion */ + return false; + } + + double slope = (to.y - from.y) / (to.x - from.x); + std::vector velocities; + + for (auto const & nb : affected_lollis) { + ArdourCanvas::Item* it = nb->item(); + ArdourCanvas::Duple pos = it->item_to_canvas (ArdourCanvas::Duple (nb->x0(), 0.0)); + int y = from.y + (slope * (pos.x - from.x)); + int velocity = y_position_to_velocity (r.height() - (r.y1() - y)); + velocities.push_back (velocity); + } + + MidiRegionView* mrv = dynamic_cast (&parent_rv); + bool ret = mrv->set_velocities_for_notes (affected_lollis, velocities); + + mrv->mid_drag_edit (); + + model_changed (); + return ret; } diff --git a/gtk2_ardour/velocity_ghost_region.h b/gtk2_ardour/velocity_ghost_region.h index 638e3ccaf0..e00376ede5 100644 --- a/gtk2_ardour/velocity_ghost_region.h +++ b/gtk2_ardour/velocity_ghost_region.h @@ -50,6 +50,8 @@ public: void set_selected (bool); bool line_draw_motion (ArdourCanvas::Duple const & d, ArdourCanvas::Rectangle const & r, double last_x); + bool line_extended (ArdourCanvas::Duple const & from, ArdourCanvas::Duple const & to, ArdourCanvas::Rectangle const & r, double last_x); + void start_line_drag (); void end_line_drag (bool did_change);