diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index c3ec5321df..6dd7377b1e 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -1702,6 +1702,7 @@ private: bool canvas_scroll_event (GdkEventScroll* event, bool from_canvas); bool canvas_control_point_event (GdkEvent* event,ArdourCanvas::Item*, ControlPoint*); bool canvas_velocity_event (GdkEvent* event,ArdourCanvas::Item*); + bool canvas_velocity_base_event (GdkEvent* event,ArdourCanvas::Item*); bool canvas_line_event (GdkEvent* event,ArdourCanvas::Item*, AutomationLine*); bool canvas_selection_rect_event (GdkEvent* event,ArdourCanvas::Item*, SelectionRect*); bool canvas_selection_start_trim_event (GdkEvent* event,ArdourCanvas::Item*, SelectionRect*); diff --git a/gtk2_ardour/editor_canvas_events.cc b/gtk2_ardour/editor_canvas_events.cc index ca475bf40d..8f97062b4f 100644 --- a/gtk2_ardour/editor_canvas_events.cc +++ b/gtk2_ardour/editor_canvas_events.cc @@ -693,10 +693,15 @@ Editor::canvas_control_point_event (GdkEvent *event, ArdourCanvas::Item* item, C bool Editor::canvas_velocity_event (GdkEvent *event, ArdourCanvas::Item* item) { - // std::cerr << "Velocity event: " << Gtkmm2ext::event_type_string (event->type) << std::endl; return typed_event (item, event, VelocityItem); } +bool +Editor::canvas_velocity_base_event (GdkEvent *event, ArdourCanvas::Item* item) +{ + return typed_event (item, event, VelocityBaseItem); +} + bool Editor::canvas_line_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationLine* al) { diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index adaee1b65c..e6c0d234dd 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -7199,6 +7199,7 @@ LollipopDrag::LollipopDrag (Editor* ed, ArdourCanvas::Item* l) : Drag (ed, l, Temporal::BeatTime) , _primary (dynamic_cast (l)) { + DEBUG_TRACE (DEBUG::Drags, "New LollipopDrag\n"); _region = reinterpret_cast (_item->get_data ("ghostregionview")); } @@ -7257,7 +7258,10 @@ LollipopDrag::setup_pointer_offset () _pointer_offset = _region->parent_rv.region()->source_beats_to_absolute_time (note->note()->time ()).distance (raw_grab_time ()); } -AutomationDrawDrag::AutomationDrawDrag (Editor* editor, ArdourCanvas::Rectangle& r, Temporal::TimeDomain time_domain) +/********/ + +template +FreehandLineDrag::FreehandLineDrag (Editor* editor, ArdourCanvas::Rectangle& r, Temporal::TimeDomain time_domain) : Drag (editor, &r, time_domain) , base_rect (r) , dragging_line (nullptr) @@ -7269,13 +7273,15 @@ AutomationDrawDrag::AutomationDrawDrag (Editor* editor, ArdourCanvas::Rectangle& DEBUG_TRACE (DEBUG::Drags, "New AutomationDrawDrag\n"); } -AutomationDrawDrag::~AutomationDrawDrag () +template +FreehandLineDrag::~FreehandLineDrag () { delete dragging_line; } +template void -AutomationDrawDrag::motion (GdkEvent* ev, bool first_move) +FreehandLineDrag::motion (GdkEvent* ev, bool first_move) { if (first_move) { dragging_line = new ArdourCanvas::PolyLine (item()); @@ -7293,14 +7299,15 @@ AutomationDrawDrag::motion (GdkEvent* ev, bool first_move) /* Add a point correspding to the start of the drag */ - maybe_add_point (ev, raw_grab_time()); + maybe_add_point (ev, raw_grab_time(), true); } - maybe_add_point (ev, _drags->current_pointer_time()); + maybe_add_point (ev, _drags->current_pointer_time(), first_move); } +template void -AutomationDrawDrag::maybe_add_point (GdkEvent* ev, timepos_t const & cpos) +FreehandLineDrag::maybe_add_point (GdkEvent* ev, timepos_t const & cpos, bool first_move) { timepos_t pos (cpos); @@ -7347,24 +7354,91 @@ AutomationDrawDrag::maybe_add_point (GdkEvent* ev, timepos_t const & cpos) } } + bool child_call = false; + if (pop_point) { if (line_break_pending) { line_break_pending = false; } else { dragging_line->pop_back(); drawn_points.pop_back (); + child_call = true; } } if (add_point) { if (drawn_points.empty() || (pos != drawn_points.back().when)) { dragging_line->add_point (ArdourCanvas::Duple (x, y)); - drawn_points.push_back (Evoral::ControlList::OrderedPoint (pos, y)); + drawn_points.push_back (OrderedPoint (pos, y)); + child_call = true; } + } + + if (child_call) { + point_added (ArdourCanvas::Duple (pointer_x, y), base_rect, first_move ? -1 : edge_x); + } + + if (add_point) { edge_x = pointer_x; } } +template +void +FreehandLineDrag::finished (GdkEvent* event, bool motion_occured) +{ + if (!motion_occured) { + /* DragManager will tell editor that no motion happened, and + Editor::button_release_handler() will do the right thing. + */ + return; + } + + if (drawn_points.empty()) { + return; + } + + /* Points must be in time order, so if the user draw right to left, fix + * that here + */ + + if (drawn_points.front().when > drawn_points.back().when) { + std::reverse (drawn_points.begin(), drawn_points.end()); + } +} + +template +bool +FreehandLineDrag::mid_drag_key_event (GdkEventKey* ev) +{ + if (ev->type == GDK_KEY_PRESS) { + switch (ev->keyval) { + + case GDK_Alt_R: + case GDK_Alt_L: + line_break_pending = true; + return true; + + default: + break; + } + } + + return false; +} + +/**********************/ + +AutomationDrawDrag::AutomationDrawDrag (Editor* editor, ArdourCanvas::Rectangle& r, Temporal::TimeDomain time_domain) + : FreehandLineDrag (editor, r, time_domain) +{ + DEBUG_TRACE (DEBUG::Drags, "New AutomationDrawDrag\n"); +} + +AutomationDrawDrag::~AutomationDrawDrag () +{ +} + void AutomationDrawDrag::finished (GdkEvent* event, bool motion_occured) { @@ -7384,37 +7458,58 @@ AutomationDrawDrag::finished (GdkEvent* event, bool motion_occured) return; } - /* Points must be in time order, so if the user draw right to left, fix - * that here - */ - - if (drawn_points.front().when > drawn_points.back().when) { - std::reverse (drawn_points.begin(), drawn_points.end()); - } + FreehandLineDrag::finished (event, motion_occured); atv->merge_drawn_line (drawn_points, !did_snap); } -void -AutomationDrawDrag::aborted (bool) +/*****************/ + +VelocityLineDrag::VelocityLineDrag (Editor* editor, ArdourCanvas::Rectangle& r, Temporal::TimeDomain time_domain) + : FreehandLineDrag (editor, r, time_domain) + , grv (static_cast (r.get_data ("ghostregionview"))) + , drag_did_change (false) +{ + DEBUG_TRACE (DEBUG::Drags, "New VelocityLineDrag\n"); + assert (grv); +} + +VelocityLineDrag::~VelocityLineDrag () { } -bool -AutomationDrawDrag::mid_drag_key_event (GdkEventKey* ev) +void +VelocityLineDrag::start_grab (GdkEvent* ev, Gdk::Cursor* c) { - if (ev->type == GDK_KEY_PRESS) { - switch (ev->keyval) { + FreehandLineDrag::start_grab (ev, c); + grv->start_line_drag (); +} - case GDK_Alt_R: - case GDK_Alt_L: - line_break_pending = true; - return true; +void +VelocityLineDrag::point_added (Duple const & d, Rectangle const & r, double last_x) +{ + drag_did_change |= grv->line_draw_motion (d, r, last_x); +} - default: - break; - } +void +VelocityLineDrag::finished (GdkEvent* event, bool motion_occured) +{ + if (!motion_occured) { + /* DragManager will tell editor that no motion happened, and + Editor::button_release_handler() will do the right thing. + */ + return; } - return false; + /* no need to call FreehandLineDrag::finished(), because we do not use + * drawn_points + */ + + grv->end_line_drag (drag_did_change); +} + +void +VelocityLineDrag::aborted (bool) +{ + grv->end_line_drag (false); } diff --git a/gtk2_ardour/editor_drag.h b/gtk2_ardour/editor_drag.h index 6ae70539a3..d9eb0ed49e 100644 --- a/gtk2_ardour/editor_drag.h +++ b/gtk2_ardour/editor_drag.h @@ -1583,27 +1583,56 @@ class LollipopDrag : public Drag ArdourCanvas::Lollipop* _primary; }; -class AutomationDrawDrag : public Drag +template +class FreehandLineDrag : public Drag +{ + public: + FreehandLineDrag (Editor*, ArdourCanvas::Rectangle&, Temporal::TimeDomain); + ~FreehandLineDrag (); + + void motion (GdkEvent*, bool); + 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) {} + + protected: + ArdourCanvas::Rectangle& base_rect; /* we do not own this */ + ArdourCanvas::PolyLine* dragging_line; + int direction; + int edge_x; + bool did_snap; + bool line_break_pending; + OrderedPointList drawn_points; + + void maybe_add_point (GdkEvent*, Temporal::timepos_t const &, bool first_move); +}; + +class AutomationDrawDrag : public FreehandLineDrag { public: AutomationDrawDrag (Editor*, ArdourCanvas::Rectangle&, Temporal::TimeDomain); ~AutomationDrawDrag (); - void motion (GdkEvent*, bool); void finished (GdkEvent*, bool); - void aborted (bool); - bool mid_drag_key_event (GdkEventKey*); - -private: - ArdourCanvas::Rectangle& base_rect; /* we do not own this */ - ArdourCanvas::PolyLine* dragging_line; - int direction; - int edge_x; - Evoral::ControlList::OrderedPoints drawn_points; - bool did_snap; - bool line_break_pending; - - void maybe_add_point (GdkEvent*, Temporal::timepos_t const &); + void aborted (bool) {} }; +class VelocityLineDrag : public FreehandLineDrag +{ + public: + VelocityLineDrag (Editor*, ArdourCanvas::Rectangle&, Temporal::TimeDomain); + ~VelocityLineDrag (); + + void start_grab (GdkEvent *, Gdk::Cursor* c = 0); + void finished (GdkEvent*, bool); + void aborted (bool); + void point_added (ArdourCanvas::Duple const & d, ArdourCanvas::Rectangle const & r, double last_x); + + private: + VelocityGhostRegion* grv; + bool drag_did_change; +}; + + + #endif /* __gtk2_ardour_editor_drag_h_ */ diff --git a/gtk2_ardour/editor_items.h b/gtk2_ardour/editor_items.h index c8e934b99c..d8925741e8 100644 --- a/gtk2_ardour/editor_items.h +++ b/gtk2_ardour/editor_items.h @@ -69,6 +69,7 @@ enum ItemType { SelectionMarkerItem, DropZoneItem, VelocityItem, + VelocityBaseItem, /* don't remove this */ diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index 7ba0fa4e35..c83f770512 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -82,6 +82,7 @@ #include "mouse_cursors.h" #include "editor_cursors.h" #include "region_peak_cursor.h" +#include "velocity_ghost_region.h" #include "verbose_cursor.h" #include "note.h" @@ -902,6 +903,16 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT return true; break; + case VelocityBaseItem: + { + VelocityGhostRegion* grv = static_cast (item->get_data ("ghostregionview")); + if (grv) { + _drags->set (new VelocityLineDrag (this, grv->base_item(), Temporal::BeatTime), event); + } + } + return true; + break; + default: break; } @@ -1569,6 +1580,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT /* see if we're finishing a drag */ if (_drags->active ()) { + bool const r = _drags->end_grab (event); if (r) { /* grab dragged, so do nothing else */ diff --git a/gtk2_ardour/public_editor.h b/gtk2_ardour/public_editor.h index 2038b4316d..1563a9d124 100644 --- a/gtk2_ardour/public_editor.h +++ b/gtk2_ardour/public_editor.h @@ -451,6 +451,7 @@ public: virtual bool canvas_scroll_event (GdkEventScroll* event, bool from_canvas) = 0; virtual bool canvas_control_point_event (GdkEvent* event, ArdourCanvas::Item*, ControlPoint*) = 0; virtual bool canvas_velocity_event (GdkEvent* event, ArdourCanvas::Item*) = 0; + virtual bool canvas_velocity_base_event (GdkEvent* event, ArdourCanvas::Item*) = 0; virtual bool canvas_line_event (GdkEvent* event, ArdourCanvas::Item*, AutomationLine*) = 0; virtual bool canvas_selection_rect_event (GdkEvent* event, ArdourCanvas::Item*, SelectionRect*) = 0; virtual bool canvas_selection_start_trim_event (GdkEvent* event, ArdourCanvas::Item*, SelectionRect*) = 0; diff --git a/gtk2_ardour/velocity_ghost_region.cc b/gtk2_ardour/velocity_ghost_region.cc index 9cf6db7799..5328c3a2f8 100644 --- a/gtk2_ardour/velocity_ghost_region.cc +++ b/gtk2_ardour/velocity_ghost_region.cc @@ -58,6 +58,7 @@ VelocityGhostRegion::VelocityGhostRegion (MidiRegionView& mrv, TimeAxisView& tv, , drag_did_change (false) , selected (false) { + base_rect->set_data (X_("ghostregionview"), this); base_rect->Event.connect (sigc::mem_fun (*this, &VelocityGhostRegion::base_event)); base_rect->set_fill_color (UIConfiguration::instance().color_mod ("ghost track base", "ghost track midi fill")); base_rect->set_outline_color (UIConfiguration::instance().color ("automation track outline")); @@ -70,74 +71,36 @@ VelocityGhostRegion::~VelocityGhostRegion () } bool -VelocityGhostRegion::base_event (GdkEvent* ev) +VelocityGhostRegion::line_draw_motion (ArdourCanvas::Duple const & d, ArdourCanvas::Rectangle const & r, double last_x) { std::vector affected_lollis; - MidiRegionView* mrv = dynamic_cast (&parent_rv); - ArdourCanvas::Rect r = base_rect->item_to_canvas (base_rect->get()); - switch (ev->type) { - case GDK_MOTION_NOTIFY: - if (dragging) { - if (last_drag_x < 0) { - lollis_close_to_x (ev->motion.x, 20., affected_lollis); - } else if (last_drag_x < ev->motion.x) { - /* rightward, "later" motion */ - lollis_between (last_drag_x, ev->motion.x, affected_lollis); - } else { - /* leftward, "earlier" motion */ - lollis_between (ev->motion.x, last_drag_x, affected_lollis); - } - if (!affected_lollis.empty()) { - int velocity = y_position_to_velocity (r.height() - (r.y1 - ev->motion.y)); - drag_did_change |= mrv->set_velocity_for_notes (affected_lollis, velocity); - mrv->mid_drag_edit (); - } - if (dragging) { - dragging_line->add_point (ArdourCanvas::Duple (ev->motion.x - r.x0, ev->motion.y - r.y0)); - last_drag_x = ev->motion.x; - } - return true; - } - break; - case GDK_BUTTON_PRESS: - if (ev->button.button == 1) { - assert (!dragging); - desensitize_lollis (); - dragging = true; - drag_did_change = false; - last_drag_x = -1; - if (!dragging_line) { - dragging_line = new ArdourCanvas::PolyLine (_note_group); - dragging_line->set_ignore_events (true); - dragging_line->set_outline_color (UIConfiguration::instance().color ("midi note selected outline")); - } - dragging_line->set (ArdourCanvas::Points()); - dragging_line->show(); - dragging_line->raise_to_top(); - base_rect->grab(); - mrv->begin_drag_edit (_("draw velocities")); - return true; - } - break; - case GDK_BUTTON_RELEASE: - if (ev->button.button == 1 && dragging) { - mrv->end_drag_edit (drag_did_change); - base_rect->ungrab(); - dragging_line->hide (); - dragging = false; - sensitize_lollis (); - return true; - } - break; - default: - // std::cerr << "vgr event type " << Gtkmm2ext::event_type_string (ev->type) << std::endl; - break; + if (last_x < 0) { + lollis_close_to_x (d.x, 20., affected_lollis); + } else if (last_x < d.x) { + /* rightward, "later" motion */ + lollis_between (last_x, d.x, affected_lollis); + } else { + /* leftward, "earlier" motion */ + lollis_between (d.x, last_x, affected_lollis); } + bool ret = false; - return 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 (); + } + + return ret; +} + +bool +VelocityGhostRegion::base_event (GdkEvent* ev) +{ + return trackview.editor().canvas_velocity_base_event (ev, base_rect); } void @@ -234,7 +197,6 @@ VelocityGhostRegion::drag_lolli (ArdourCanvas::Lollipop* l, GdkEventMotion* ev) * (event coordinates use window coordinate space) */ - ev->y -= r.y0; /* clamp y to be within the range defined by the base_rect height minus @@ -357,6 +319,22 @@ VelocityGhostRegion::lollis_close_to_x (int x, double distance, std::vector (&parent_rv); + mrv->begin_drag_edit (_("draw velocities")); + desensitize_lollis (); +} + +void +VelocityGhostRegion::end_line_drag (bool did_change) +{ + MidiRegionView* mrv = dynamic_cast (&parent_rv); + mrv->end_drag_edit (did_change); + sensitize_lollis (); +} + void VelocityGhostRegion::desensitize_lollis () { @@ -381,5 +359,5 @@ VelocityGhostRegion::set_selected (bool yn) if (yn) { group->raise_to_top (); - } + } } diff --git a/gtk2_ardour/velocity_ghost_region.h b/gtk2_ardour/velocity_ghost_region.h index 152569eba8..638e3ccaf0 100644 --- a/gtk2_ardour/velocity_ghost_region.h +++ b/gtk2_ardour/velocity_ghost_region.h @@ -49,6 +49,12 @@ public: void set_selected (bool); + bool line_draw_motion (ArdourCanvas::Duple const & d, ArdourCanvas::Rectangle const & r, double last_x); + void start_line_drag (); + void end_line_drag (bool did_change); + + ArdourCanvas::Rectangle& base_item() { return *base_rect; } + private: bool dragging; ArdourCanvas::PolyLine* dragging_line;