diff --git a/gtk2_ardour/automation_line_base.cc b/gtk2_ardour/automation_line_base.cc index 4e4edb26c1..3ba06484bd 100644 --- a/gtk2_ardour/automation_line_base.cc +++ b/gtk2_ardour/automation_line_base.cc @@ -102,7 +102,7 @@ AutomationLineBase::AutomationLineBase (const string& name, , have_reset_timeout (false) , no_draw (false) , _is_boolean (false) - , editing_context (ec) + , _editing_context (ec) , _parent_group (parent) , _drag_base (drag_base) , _offset (0) @@ -122,7 +122,7 @@ AutomationLineBase::AutomationLineBase (const string& name, line->Event.connect (sigc::mem_fun (*this, &AutomationLineBase::event_handler)); - editing_context.session()->register_with_memento_command_factory(alist->id(), this); + _editing_context.session()->register_with_memento_command_factory(alist->id(), this); interpolation_changed (alist->interpolation ()); @@ -236,7 +236,7 @@ AutomationLineBase::control_point_box_size () } else if (_height > (guint32) TimeAxisView::preset_height (HeightNormal)) { return rint (6.0 * uiscale); } - return rint (4.0 * uiscale); + return rint (12.0 * uiscale); } void @@ -311,9 +311,8 @@ AutomationLineBase::modify_points_y (std::vector const& cps, doub y = min (1.0, y); y = _height - (y * _height); - editing_context.begin_reversible_command (_("automation event move")); - editing_context.session()->add_command ( - new MementoCommand (memento_command_binder(), &get_state(), 0)); + _editing_context.begin_reversible_command (_("automation event move")); + _editing_context.add_command (new MementoCommand (memento_command_binder(), &get_state(), 0)); alist->freeze (); for (auto const& cp : cps) { @@ -332,11 +331,10 @@ AutomationLineBase::modify_points_y (std::vector const& cps, doub update_pending = false; - editing_context.session()->add_command ( - new MementoCommand (memento_command_binder(), 0, &alist->get_state())); + _editing_context.add_command (new MementoCommand (memento_command_binder(), 0, &alist->get_state())); - editing_context.commit_reversible_command (); - editing_context.session()->set_dirty (); + _editing_context.commit_reversible_command (); + _editing_context.session()->set_dirty (); } void @@ -435,8 +433,7 @@ AutomationLineBase::string_to_fraction (string const & s) const void AutomationLineBase::start_drag_single (ControlPoint* cp, double x, float fraction) { - editing_context.session()->add_command ( - new MementoCommand (memento_command_binder(), &get_state(), 0)); + _editing_context.add_command (new MementoCommand (memento_command_binder(), &get_state(), 0)); _drag_points.clear (); _drag_points.push_back (cp); @@ -460,8 +457,7 @@ AutomationLineBase::start_drag_single (ControlPoint* cp, double x, float fractio void AutomationLineBase::start_drag_line (uint32_t i1, uint32_t i2, float fraction) { - editing_context.session()->add_command ( - new MementoCommand (memento_command_binder (), &get_state(), 0)); + _editing_context.add_command (new MementoCommand (memento_command_binder (), &get_state(), 0)); _drag_points.clear (); @@ -479,8 +475,7 @@ AutomationLineBase::start_drag_line (uint32_t i1, uint32_t i2, float fraction) void AutomationLineBase::start_drag_multiple (list cp, float fraction, XMLNode* state) { - editing_context.session()->add_command ( - new MementoCommand (memento_command_binder(), state, 0)); + _editing_context.add_command (new MementoCommand (memento_command_binder(), state, 0)); _drag_points = cp; start_drag_common (0, fraction); @@ -610,9 +605,9 @@ AutomationLineBase::dt_to_dx (timepos_t const & pos, timecnt_t const & dt) /* convert a shift of pos by dt into an absolute timepos */ timepos_t const new_pos ((pos + dt + get_origin()).shift_earlier (offset())); /* convert to pixels */ - double px = editing_context.time_to_pixel_unrounded (new_pos); + double px = _editing_context.time_to_pixel_unrounded (new_pos); /* convert back to pixels-relative-to-origin */ - px -= editing_context.time_to_pixel_unrounded (get_origin()); + px -= _editing_context.time_to_pixel_unrounded (get_origin()); return px; } @@ -792,10 +787,9 @@ AutomationLineBase::end_drag (bool with_push, uint32_t final_index) line->set_steps (line_points, is_stepped()); } - editing_context.session()->add_command ( - new MementoCommand(memento_command_binder (), 0, &alist->get_state())); + _editing_context.add_command (new MementoCommand(memento_command_binder (), 0, &alist->get_state())); - editing_context.session()->set_dirty (); + _editing_context.session()->set_dirty (); did_push = false; contiguous_points.clear (); @@ -827,7 +821,7 @@ AutomationLineBase::sync_model_with_view_point (ControlPoint& cp) const timepos_t absolute_time = model_time + origin; /* now convert to pixels relative to start of region, which matches view_x */ - const double model_x = editing_context.time_to_pixel_unrounded (absolute_time) - editing_context.time_to_pixel_unrounded (origin); + const double model_x = _editing_context.time_to_pixel_unrounded (absolute_time) - _editing_context.time_to_pixel_unrounded (origin); if (view_x != model_x) { @@ -840,7 +834,7 @@ AutomationLineBase::sync_model_with_view_point (ControlPoint& cp) * pixel_to_sample() islinear only depending on zoom level. */ - const timepos_t view_samples (editing_context.pixel_to_sample (view_x)); + const timepos_t view_samples (_editing_context.pixel_to_sample (view_x)); /* measure distance from RegionView origin (this preserves time domain) */ @@ -880,7 +874,7 @@ AutomationLineBase::control_points_adjacent (double xval, uint32_t & before, uin ControlPoint *acp = 0; double unit_xval; - unit_xval = editing_context.sample_to_pixel_unrounded (xval); + unit_xval = _editing_context.sample_to_pixel_unrounded (xval); for (vector::iterator i = control_points.begin(); i != control_points.end(); ++i) { @@ -936,17 +930,16 @@ AutomationLineBase::is_first_point (ControlPoint& cp) void AutomationLineBase::remove_point (ControlPoint& cp) { - editing_context.begin_reversible_command (_("remove control point")); + _editing_context.begin_reversible_command (_("remove control point")); XMLNode &before = alist->get_state(); - editing_context.get_selection ().clear_points (); + _editing_context.get_selection ().clear_points (); alist->erase (cp.model()); - editing_context.session()->add_command( - new MementoCommand (memento_command_binder (), &before, &alist->get_state())); + _editing_context.add_command (new MementoCommand (memento_command_binder (), &before, &alist->get_state())); - editing_context.commit_reversible_command (); - editing_context.session()->set_dirty (); + _editing_context.commit_reversible_command (); + _editing_context.session()->set_dirty (); } /** Get selectable points within an area. @@ -1109,7 +1102,7 @@ AutomationLineBase::reset_callback (const Evoral::ControlList& events) * zoom and scroll into account). */ - double px = editing_context.duration_to_pixels_unrounded (tx); + double px = _editing_context.duration_to_pixels_unrounded (tx); add_visible_control_point (vp, pi, px, ty, ai, np); vp++; } @@ -1167,7 +1160,7 @@ AutomationLineBase::reset_callback (const Evoral::ControlList& events) * from the last point to the very end */ - double px = editing_context.duration_to_pixels_unrounded (model_to_view_coord_x (_offset + _maximum_time)); + double px = _editing_context.duration_to_pixels_unrounded (model_to_view_coord_x (_offset + _maximum_time)); if (control_points[control_points.size() - 1]->get_x() != px && following != e.end()) { double ty = model_to_view_coord_y (e.unlocked_eval (_offset + _maximum_time)); @@ -1189,7 +1182,7 @@ AutomationLineBase::reset_callback (const Evoral::ControlList& events) update_visibility (); } - set_selected_points (editing_context.get_selection().points); + set_selected_points (_editing_context.get_selection().points); } void @@ -1219,7 +1212,7 @@ AutomationLineBase::queue_reset () { /* this must be called from the GUI thread */ - if (editing_context.session()->transport_rolling() && alist->automation_write()) { + if (_editing_context.session()->transport_rolling() && alist->automation_write()) { /* automation write pass ... defer to a timeout */ /* redraw in 1/4 second */ if (!have_reset_timeout) { @@ -1241,8 +1234,7 @@ AutomationLineBase::clear () XMLNode &before = alist->get_state(); alist->clear(); - editing_context.session()->add_command ( - new MementoCommand (memento_command_binder (), &before, &alist->get_state())); + _editing_context.add_command (new MementoCommand (memento_command_binder (), &before, &alist->get_state())); } void diff --git a/gtk2_ardour/automation_line_base.h b/gtk2_ardour/automation_line_base.h index 8f78f92dab..4bbd1671ca 100644 --- a/gtk2_ardour/automation_line_base.h +++ b/gtk2_ardour/automation_line_base.h @@ -174,6 +174,7 @@ public: double dt_to_dx (Temporal::timepos_t const &, Temporal::timecnt_t const &); ARDOUR::ParameterDescriptor const & param() const { return _desc; } + EditingContext& editing_context() const { return _editing_context; } protected: @@ -194,7 +195,7 @@ protected: /** true if we did a push at any point during the current drag */ bool did_push; - EditingContext& editing_context; + EditingContext& _editing_context; ArdourCanvas::Item& _parent_group; ArdourCanvas::Rectangle* _drag_base; ArdourCanvas::Container* group; diff --git a/gtk2_ardour/automation_region_view.cc b/gtk2_ardour/automation_region_view.cc index bc5d656066..c0223e4df6 100644 --- a/gtk2_ardour/automation_region_view.cc +++ b/gtk2_ardour/automation_region_view.cc @@ -330,7 +330,6 @@ AutomationRegionView::entered () } } - void AutomationRegionView::exited () { @@ -338,6 +337,7 @@ AutomationRegionView::exited () _line->track_exited(); } } + void AutomationRegionView::set_selected (bool yn) { diff --git a/gtk2_ardour/automation_streamview.cc b/gtk2_ardour/automation_streamview.cc index dcb80b4a4f..3232219a82 100644 --- a/gtk2_ardour/automation_streamview.cc +++ b/gtk2_ardour/automation_streamview.cc @@ -156,11 +156,9 @@ AutomationStreamView::set_automation_state (AutoState state) if (region_views.empty()) { _pending_automation_state = state; } else { - list > lines = get_lines (); - - for (list >::iterator i = lines.begin(); i != lines.end(); ++i) { - if ((*i)->the_list()) { - (*i)->the_list()->set_automation_state (state); + for (auto & line : get_lines()) { + if (line->the_list()) { + line->the_list()->set_automation_state (state); } } } @@ -222,10 +220,8 @@ AutomationStreamView::automation_state () const bool AutomationStreamView::has_automation () const { - list > lines = get_lines (); - - for (list >::iterator i = lines.begin(); i != lines.end(); ++i) { - if ((*i)->npoints() > 0) { + for (auto const & line : get_lines()) { + if (line->npoints() > 0) { return true; } } @@ -239,10 +235,8 @@ AutomationStreamView::has_automation () const void AutomationStreamView::set_interpolation (AutomationList::InterpolationStyle s) { - list > lines = get_lines (); - - for (list >::iterator i = lines.begin(); i != lines.end(); ++i) { - (*i)->the_list()->set_interpolation (s); + for (auto & line : get_lines()) { + line->the_list()->set_interpolation (s); } } @@ -264,10 +258,8 @@ AutomationStreamView::interpolation () const void AutomationStreamView::clear () { - list > lines = get_lines (); - - for (list >::iterator i = lines.begin(); i != lines.end(); ++i) { - (*i)->clear (); + for (auto & line : get_lines()) { + line->clear (); } } @@ -292,20 +284,18 @@ AutomationStreamView::get_selectables (timepos_t const & start, timepos_t const void AutomationStreamView::set_selected_points (PointSelection& ps) { - list > lines = get_lines (); - - for (list >::iterator i = lines.begin(); i != lines.end(); ++i) { - (*i)->set_selected_points (ps); + for (auto & line : get_lines()) { + line->set_selected_points (ps); } } -list > +list > AutomationStreamView::get_lines () const { - list > lines; + list > lines; - for (list::const_iterator i = region_views.begin(); i != region_views.end(); ++i) { - AutomationRegionView* arv = dynamic_cast (*i); + for (auto const & rv : region_views) { + AutomationRegionView* arv = dynamic_cast (rv); if (arv) { lines.push_back (arv->line()); } diff --git a/gtk2_ardour/automation_streamview.h b/gtk2_ardour/automation_streamview.h index e79b56aafe..45b5da42ab 100644 --- a/gtk2_ardour/automation_streamview.h +++ b/gtk2_ardour/automation_streamview.h @@ -66,7 +66,7 @@ public: void get_selectables (Temporal::timepos_t const &, Temporal::timepos_t const &, double, double, std::list &, bool within = false); void set_selected_points (PointSelection &); - std::list > get_lines () const; + std::list > get_lines () const; bool paste (Temporal::timepos_t const & pos, unsigned paste_count, diff --git a/gtk2_ardour/automation_time_axis.cc b/gtk2_ardour/automation_time_axis.cc index c00b29e98c..98246c5a70 100644 --- a/gtk2_ardour/automation_time_axis.cc +++ b/gtk2_ardour/automation_time_axis.cc @@ -1084,10 +1084,10 @@ AutomationTimeAxisView::has_automation () const return ( (_line && _line->npoints() > 0) || (_view && _view->has_automation()) ); } -list > +list > AutomationTimeAxisView::lines () const { - list > lines; + list > lines; if (_line) { lines.push_back (_line); @@ -1167,20 +1167,19 @@ AutomationTimeAxisView::parse_state_id ( void AutomationTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op) { - list > lines; - if (_line) { - lines.push_back (_line); - } else if (_view) { - lines = _view->get_lines (); - } + list > lines; - for (list >::iterator i = lines.begin(); i != lines.end(); ++i) { - cut_copy_clear_one (**i, selection, op); + if (_line) { + cut_copy_clear_one (*_line, selection, op); + } else if (_view) { + for (auto & line : _view->get_lines ()) { + cut_copy_clear_one (*line, selection, op); + } } } void -AutomationTimeAxisView::cut_copy_clear_one (AutomationLine& line, Selection& selection, CutCopyOp op) +AutomationTimeAxisView::cut_copy_clear_one (AutomationLineBase& line, Selection& selection, CutCopyOp op) { std::shared_ptr what_we_got; std::shared_ptr alist (line.the_list()); diff --git a/gtk2_ardour/automation_time_axis.h b/gtk2_ardour/automation_time_axis.h index 395c1797c6..077d10e4bf 100644 --- a/gtk2_ardour/automation_time_axis.h +++ b/gtk2_ardour/automation_time_axis.h @@ -54,6 +54,7 @@ class PublicEditor; class TimeSelection; class RegionSelection; class PointSelection; +class AutomationLineBase; class AutomationLine; class Selection; class Selectable; @@ -95,7 +96,7 @@ public: std::shared_ptr line() { return _line; } /** @return All AutomationLines associated with this view */ - std::list > lines () const; + std::list > lines () const; AutomationStreamView* automation_view() const { return _view; } @@ -202,7 +203,7 @@ protected: void build_display_menu (); - void cut_copy_clear_one (AutomationLine&, Selection&, Editing::CutCopyOp); + void cut_copy_clear_one (AutomationLineBase&, Selection&, Editing::CutCopyOp); bool paste_one (Temporal::timepos_t const &, unsigned, float times, const Selection&, ItemCounts& counts, bool greedy=false); void route_going_away (); diff --git a/gtk2_ardour/control_point.cc b/gtk2_ardour/control_point.cc index babb4c9f02..3c6a173779 100644 --- a/gtk2_ardour/control_point.cc +++ b/gtk2_ardour/control_point.cc @@ -88,7 +88,7 @@ ControlPoint::~ControlPoint () bool ControlPoint::event_handler (GdkEvent* event) { - return PublicEditor::instance().canvas_control_point_event (event, _item, this); + return _line.editing_context().canvas_control_point_event (event, _item, this); } void diff --git a/gtk2_ardour/editing_context.cc b/gtk2_ardour/editing_context.cc index 355a39490f..cccdd5af71 100644 --- a/gtk2_ardour/editing_context.cc +++ b/gtk2_ardour/editing_context.cc @@ -34,6 +34,8 @@ #include "actions.h" #include "ardour_ui.h" +#include "automation_line_base.h" +#include "control_point.h" #include "edit_note_dialog.h" #include "editing_context.h" #include "editing_convert.h" @@ -141,6 +143,11 @@ EditingContext::EditingContext (std::string const & name) , autoscroll_horizontal_allowed (false) , autoscroll_vertical_allowed (false) , autoscroll_cnt (0) + , _mouse_changed_selection (false) + , entered_marker (nullptr) + , entered_track (nullptr) + , entered_regionview (nullptr) + , clear_entered_track (false) { if (!button_bindings) { button_bindings = new Bindings ("editor-mouse"); @@ -2646,3 +2653,99 @@ EditingContext::get_draw_length_as_beats (bool& success, timepos_t const & posit return Temporal::Beats(); } +void +EditingContext::select_automation_line (GdkEventButton* event, ArdourCanvas::Item* item, ARDOUR::SelectionOperation op) +{ + AutomationLineBase* al = reinterpret_cast (item->get_data ("line")); + std::list selectables; + double mx = event->x; + double my = event->y; + bool press = (event->type == GDK_BUTTON_PRESS); + + al->grab_item().canvas_to_item (mx, my); + + uint32_t before, after; + samplecnt_t const where = (samplecnt_t) floor (canvas_to_timeline (mx) * samples_per_pixel); + + if (!al || !al->control_points_adjacent (where, before, after)) { + return; + } + + selectables.push_back (al->nth (before)); + selectables.push_back (al->nth (after)); + + switch (op) { + case SelectionSet: + if (press) { + selection->set (selectables); + _mouse_changed_selection = true; + } + break; + case SelectionAdd: + if (press) { + selection->add (selectables); + _mouse_changed_selection = true; + } + break; + case SelectionToggle: + if (press) { + selection->toggle (selectables); + _mouse_changed_selection = true; + } + break; + case SelectionExtend: + /* XXX */ + break; + case SelectionRemove: + /* not relevant */ + break; + } +} + +/** Reset all selected points to the relevant default value */ +void +EditingContext::reset_point_selection () +{ + for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) { + ARDOUR::AutomationList::iterator j = (*i)->model (); + (*j)->value = (*i)->line().the_list()->descriptor ().normal; + } +} + +EditingContext::EnterContext* +EditingContext::get_enter_context(ItemType type) +{ + for (ssize_t i = _enter_stack.size() - 1; i >= 0; --i) { + if (_enter_stack[i].item_type == type) { + return &_enter_stack[i]; + } + } + return NULL; +} + + +void +EditingContext::choose_canvas_cursor_on_entry (ItemType type) +{ + if (_drags->active()) { + return; + } + + Gdk::Cursor* cursor = which_canvas_cursor(type); + + if (!_cursors->is_invalid (cursor)) { + // Push a new enter context + const EnterContext ctx = { type, CursorContext::create(*this, cursor) }; + _enter_stack.push_back(ctx); + } +} + +void +EditingContext::update_all_enter_cursors () +{ + for (auto & ec : _enter_stack) { + ec.cursor_ctx->change(which_canvas_cursor (ec.item_type)); + } +} + + diff --git a/gtk2_ardour/editing_context.h b/gtk2_ardour/editing_context.h index cb92d3b055..d71917404d 100644 --- a/gtk2_ardour/editing_context.h +++ b/gtk2_ardour/editing_context.h @@ -59,6 +59,7 @@ namespace Temporal { class XMLNode; +class ControlPoint; class CursorContext; class DragManager; class EditorCursor; @@ -151,13 +152,6 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider virtual void instant_save() = 0; - /** Get the topmost enter context for the given item type. - * - * This is used to change the cursor associated with a given enter context, - * which may not be on the top of the stack. - */ - virtual EnterContext* get_enter_context(ItemType type) = 0; - virtual void begin_selection_op_history () = 0; virtual void begin_reversible_selection_op (std::string cmd_name) = 0; virtual void commit_reversible_selection_op () = 0; @@ -256,6 +250,7 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider virtual bool canvas_note_event (GdkEvent* event, ArdourCanvas::Item*) = 0; virtual bool canvas_velocity_base_event (GdkEvent* event, ArdourCanvas::Item*) = 0; virtual bool canvas_velocity_event (GdkEvent* event, ArdourCanvas::Item*) = 0; + virtual bool canvas_control_point_event (GdkEvent* event, ArdourCanvas::Item*, ControlPoint*) = 0; Temporal::Beats get_grid_type_as_beats (bool& success, Temporal::timepos_t const & position) const; Temporal::Beats get_draw_length_as_beats (bool& success, Temporal::timepos_t const & position) const; @@ -315,6 +310,8 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider virtual Selection& get_selection() const { return *selection; } virtual Selection& get_cut_buffer () const { return *cut_buffer; } + void reset_point_selection (); + /** Set the mouse mode (gain, object, range, timefx etc.) * @param m Mouse mode (defined in editing_syms.h) * @param force Perform the effects of the change even if no change is required @@ -329,9 +326,19 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider * (defined in editing_syms.h) */ Editing::MouseMode current_mouse_mode () const { return mouse_mode; } + virtual Editing::MouseMode effective_mouse_mode () const { return mouse_mode; } + /** @return Whether the current mouse mode is an "internal" editing mode. */ virtual bool internal_editing() const = 0; + virtual bool get_smart_mode() const { return false; } + + /** Push the appropriate enter/cursor context on item entry. */ + void choose_canvas_cursor_on_entry (ItemType); + + /** Update all enter cursors based on current settings. */ + void update_all_enter_cursors (); + virtual Gdk::Cursor* get_canvas_cursor () const; static MouseCursors const* cursors () { return _cursors; @@ -388,6 +395,20 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider bool on_velocity_scroll_event (GdkEventScroll*); void pre_render (); + void select_automation_line (GdkEventButton*, ArdourCanvas::Item*, ARDOUR::SelectionOperation); + + /** Get the topmost enter context for the given item type. + * + * This is used to change the cursor associated with a given enter context, + * which may not be on the top of the stack. + */ + virtual EnterContext* get_enter_context(ItemType type); + + virtual Gdk::Cursor* which_track_cursor () const = 0; + virtual Gdk::Cursor* which_mode_cursor () const = 0; + virtual Gdk::Cursor* which_trim_cursor (bool left_side) const = 0; + virtual Gdk::Cursor* which_canvas_cursor (ItemType type) const = 0; + /** Undo some transactions. * @param n Number of transactions to undo. */ @@ -652,6 +673,20 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider uint32_t autoscroll_cnt; ArdourCanvas::Rect autoscroll_boundary; + bool _mouse_changed_selection; + ArdourMarker* entered_marker; + TimeAxisView* entered_track; + /** If the mouse is over a RegionView or one of its child canvas items, this is set up + to point to the RegionView. Otherwise it is 0. + */ + RegionView* entered_regionview; + + bool clear_entered_track; + + virtual void set_entered_track (TimeAxisView*) {}; + + std::vector _enter_stack; + PBD::ScopedConnection escape_connection; virtual void escape () {} @@ -675,4 +710,3 @@ class EditingContext : public ARDOUR::SessionHandlePtr, public AxisViewProvider #endif /* __ardour_midi_editing_context_h__ */ - diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 8cc564c80e..71735af2f9 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -238,7 +238,6 @@ Editor::Editor () , marker_click_behavior (MarkerClickSelectOnly) , _join_object_range_state (JOIN_OBJECT_RANGE_NONE) , _notebook_shrunk (false) - , entered_marker (0) , _show_marker_lines (false) , clicked_axisview (0) , clicked_routeview (0) @@ -246,7 +245,6 @@ Editor::Editor () , clicked_selection (0) , clicked_control_point (0) , button_release_can_deselect (true) - , _mouse_changed_selection (false) , _popup_region_menu_item (0) , _track_canvas (0) , _track_canvas_viewport (0) @@ -377,9 +375,6 @@ Editor::Editor () , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true)) , current_stepping_trackview (0) , last_track_height_step_timestamp (0) - , entered_track (0) - , entered_regionview (0) - , clear_entered_track (false) , _edit_point (EditAtMouse) , meters_running (false) , rhythm_ferret (0) diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 3c0503a5c2..cf0b56e978 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -449,13 +449,6 @@ public: void get_pointer_position (double &, double &) const; - /** Get the topmost enter context for the given item type. - * - * This is used to change the cursor associated with a given enter context, - * which may not be on the top of the stack. - */ - EnterContext* get_enter_context(ItemType type); - TimeAxisView* stepping_axis_view () { return _stepping_axis_view; } @@ -656,7 +649,6 @@ private: ArdourMarker* find_marker_from_location_id (PBD::ID const&, bool) const; TempoMarker* find_marker_for_tempo (Temporal::TempoPoint const &); MeterMarker* find_marker_for_meter (Temporal::MeterPoint const &); - ArdourMarker* entered_marker; bool _show_marker_lines; typedef std::map LocationMarkerMap; @@ -724,7 +716,6 @@ private: void button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type); bool button_release_can_deselect; - bool _mouse_changed_selection; void catch_vanishing_regionview (RegionView*); @@ -778,12 +769,6 @@ private: Gdk::Cursor* which_trim_cursor (bool left_side) const; Gdk::Cursor* which_canvas_cursor (ItemType type) const; - /** Push the appropriate enter/cursor context on item entry. */ - void choose_canvas_cursor_on_entry (ItemType); - - /** Update all enter cursors based on current settings. */ - void update_all_enter_cursors (); - ArdourCanvas::GtkCanvas* _track_canvas; ArdourCanvas::GtkCanvasViewport* _track_canvas_viewport; @@ -1137,7 +1122,6 @@ private: /* EDITING OPERATIONS */ - void reset_point_selection (); void region_lock (); void region_unlock (); void toggle_region_lock (); @@ -2070,15 +2054,6 @@ private: gint track_height_step_timeout(); sigc::connection step_timeout; - TimeAxisView* entered_track; - /** If the mouse is over a RegionView or one of its child canvas items, this is set up - to point to the RegionView. Otherwise it is 0. - */ - RegionView* entered_regionview; - - std::vector _enter_stack; - - bool clear_entered_track; bool left_track_canvas (GdkEventCrossing*); bool entered_track_canvas (GdkEventCrossing*); void set_entered_track (TimeAxisView*); diff --git a/gtk2_ardour/editor_canvas.cc b/gtk2_ardour/editor_canvas.cc index b72392e978..dad5267474 100644 --- a/gtk2_ardour/editor_canvas.cc +++ b/gtk2_ardour/editor_canvas.cc @@ -45,6 +45,7 @@ #include "ardour_ui.h" #include "automation_time_axis.h" +#include "control_point.h" #include "editor.h" #include "editing.h" #include "rgb_macros.h" @@ -882,17 +883,6 @@ Editor::stop_canvas_autoscroll () autoscroll_cnt = 0; } -EditingContext::EnterContext* -Editor::get_enter_context(ItemType type) -{ - for (ssize_t i = _enter_stack.size() - 1; i >= 0; --i) { - if (_enter_stack[i].item_type == type) { - return &_enter_stack[i]; - } - } - return NULL; -} - bool Editor::left_track_canvas (GdkEventCrossing* ev) { @@ -1217,6 +1207,16 @@ Editor::which_track_cursor () const return cursor; } +double +Editor::trackviews_height() const +{ + if (!_trackview_group) { + return 0; + } + + return _visible_canvas_height - _trackview_group->canvas_origin().y; +} + Gdk::Cursor* Editor::which_canvas_cursor(ItemType type) const { @@ -1387,36 +1387,242 @@ Editor::which_canvas_cursor(ItemType type) const return cursor; } -void -Editor::choose_canvas_cursor_on_entry (ItemType type) +bool +Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type) { - if (_drags->active()) { - return; + ControlPoint* cp; + ArdourMarker * marker; + MeterMarker* m_marker = 0; + TempoMarker* t_marker = 0; + double fraction; + bool ret = true; + + /* by the time we reach here, entered_regionview and entered trackview + * will have already been set as appropriate. Things are done this + * way because this method isn't passed a pointer to a variable type of + * thing that is entered (which may or may not be canvas item). + * (e.g. the actual entered regionview) + */ + + choose_canvas_cursor_on_entry (item_type); + + switch (item_type) { + case GridZoneItem: + break; + + case ControlPointItem: + if (mouse_mode == MouseDraw || mouse_mode == MouseObject || mouse_mode == MouseContent) { + cp = static_cast(item->get_data ("control_point")); + cp->show (); + + fraction = 1.0 - (cp->get_y() / cp->line().height()); + + _verbose_cursor->set (cp->line().get_verbose_cursor_string (fraction)); + _verbose_cursor->show (); + } + break; + + case GainLineItem: + if (mouse_mode == MouseDraw) { + ArdourCanvas::Line *line = dynamic_cast (item); + if (line) { + line->set_outline_color (UIConfiguration::instance().color ("entered gain line")); + } + } + break; + + case AutomationLineItem: + if (mouse_mode == MouseDraw || mouse_mode == MouseObject) { + ArdourCanvas::Line *line = dynamic_cast (item); + if (line) { + line->set_outline_color (UIConfiguration::instance().color ("entered automation line")); + } + } + break; + + case AutomationTrackItem: + AutomationTimeAxisView* atv; + if ((atv = static_cast(item->get_data ("trackview"))) != 0) { + clear_entered_track = false; + set_entered_track (atv); + } + break; + + case MarkerItem: + if ((marker = static_cast (item->get_data ("marker"))) == 0) { + break; + } + entered_marker = marker; + marker->set_entered (true); + break; + + case MeterMarkerItem: + if ((m_marker = static_cast (item->get_data ("marker"))) == 0) { + break; + } + entered_marker = m_marker; + /* "music" currently serves as a stand-in for "entered". */ + m_marker->set_color ("meter marker music"); + break; + + case TempoMarkerItem: + if ((t_marker = static_cast (item->get_data ("marker"))) == 0) { + break; + } + entered_marker = t_marker; + /* "music" currently serves as a stand-in for "entered". */ + t_marker->set_color ("tempo marker music"); + break; + + case FadeInHandleItem: + case FadeInTrimHandleItem: + if (mouse_mode == MouseObject) { + ArdourCanvas::Rectangle *rect = dynamic_cast (item); + if (rect) { + RegionView* rv = static_cast(item->get_data ("regionview")); + rect->set_fill_color (rv->get_fill_color()); + } + } + break; + + case FadeOutHandleItem: + case FadeOutTrimHandleItem: + if (mouse_mode == MouseObject) { + ArdourCanvas::Rectangle *rect = dynamic_cast (item); + if (rect) { + RegionView* rv = static_cast(item->get_data ("regionview")); + rect->set_fill_color (rv->get_fill_color ()); + } + } + break; + + case FeatureLineItem: + { + ArdourCanvas::Line *line = dynamic_cast (item); + line->set_outline_color (0xFF0000FF); + } + break; + + case SelectionItem: + break; + + case WaveItem: + { + if (entered_regionview) { + entered_regionview->entered(); + } + } + break; + + default: + break; } - Gdk::Cursor* cursor = which_canvas_cursor(type); + /* third pass to handle entered track status in a comprehensible way. + */ - if (!_cursors->is_invalid (cursor)) { - // Push a new enter context - const EnterContext ctx = { type, CursorContext::create(*this, cursor) }; - _enter_stack.push_back(ctx); + switch (item_type) { + case GainLineItem: + case AutomationLineItem: + case ControlPointItem: + /* these do not affect the current entered track state */ + clear_entered_track = false; + break; + + case AutomationTrackItem: + /* handled above already */ + break; + + default: + + break; } + + return ret; } -void -Editor::update_all_enter_cursors () +bool +Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type) { - for (auto & ec : _enter_stack) { - ec.cursor_ctx->change(which_canvas_cursor (ec.item_type)); - } -} + AutomationLine* al; + ArdourMarker *marker; + TempoMarker *t_marker; + MeterMarker *m_marker; + bool ret = true; -double -Editor::trackviews_height() const -{ - if (!_trackview_group) { - return 0; + if (!_enter_stack.empty()) { + _enter_stack.pop_back(); } - return _visible_canvas_height - _trackview_group->canvas_origin().y; + switch (item_type) { + case GridZoneItem: + break; + + case ControlPointItem: + _verbose_cursor->hide (); + break; + + case GainLineItem: + case AutomationLineItem: + al = reinterpret_cast (item->get_data ("line")); + { + ArdourCanvas::Line *line = dynamic_cast (item); + if (line) { + line->set_outline_color (al->get_line_color()); + } + } + break; + + case MarkerItem: + if ((marker = static_cast (item->get_data ("marker"))) == 0) { + break; + } + entered_marker = 0; + marker->set_entered (false); + break; + + case MeterMarkerItem: + if ((m_marker = static_cast (item->get_data ("marker"))) == 0) { + break; + } + m_marker->set_color ("meter marker"); + entered_marker = 0; + break; + + case TempoMarkerItem: + if ((t_marker = static_cast (item->get_data ("marker"))) == 0) { + break; + } + t_marker->set_color ("tempo marker"); + entered_marker = 0; + break; + + case FadeInTrimHandleItem: + case FadeOutTrimHandleItem: + case FadeInHandleItem: + case FadeOutHandleItem: + { + ArdourCanvas::Rectangle *rect = dynamic_cast (item); + if (rect) { + rect->set_fill_color (UIConfiguration::instance().color ("inactive fade handle")); + } + } + break; + + case AutomationTrackItem: + break; + + case FeatureLineItem: + { + ArdourCanvas::Line *line = dynamic_cast (item); + line->set_outline_color (UIConfiguration::instance().color ("zero line")); + } + break; + + default: + _region_peak_cursor->hide (); + break; + } + + return ret; } diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index 20a4b93381..741486f600 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -4775,8 +4775,8 @@ MarkerDrag::update_item (Location*) /* noop */ } -ControlPointDrag::ControlPointDrag (Editor& e, ArdourCanvas::Item* i) - : EditorDrag (e, i, e.time_domain (), e.get_trackview_group(), false) +ControlPointDrag::ControlPointDrag (EditingContext& e, ArdourCanvas::Item* i) + : Drag (e, i, e.time_domain (), e.get_trackview_group(), false) , _fixed_grab_x (0.0) , _fixed_grab_y (0.0) , _cumulative_y_drag (0.0) @@ -4787,7 +4787,7 @@ ControlPointDrag::ControlPointDrag (Editor& e, ArdourCanvas::Item* i) _zero_gain_fraction = gain_to_slider_position_with_max (dB_to_coefficient (0.0), Config->get_max_gain ()); } - DEBUG_TRACE (DEBUG::Drags, "New ControlPointDrag\n"); + DEBUG_TRACE (DEBUG::Drags, string_compose ("New ControlPointDrag @ %1\n", this)); _point = reinterpret_cast (_item->get_data ("control_point")); assert (_point); @@ -4911,7 +4911,7 @@ ControlPointDrag::finished (GdkEvent* event, bool movement_occurred) if (!movement_occurred) { /* just a click */ if (Keyboard::modifier_state_equals (event->button.state, Keyboard::ModifierMask (Keyboard::TertiaryModifier))) { - _editor.reset_point_selection (); + editing_context.reset_point_selection (); } } else { @@ -4935,7 +4935,7 @@ ControlPointDrag::active (Editing::MouseMode m) } /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */ - return dynamic_cast (&(_point->line ())) != 0; + return dynamic_cast (&(_point->line ())) != 0; } LineDrag::LineDrag (Editor& e, ArdourCanvas::Item* i) @@ -4962,7 +4962,7 @@ LineDrag::~LineDrag () void LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/) { - _line = reinterpret_cast (_item->get_data ("line")); + _line = reinterpret_cast (_item->get_data ("line")); assert (_line); _item = &_line->grab_item (); @@ -6399,7 +6399,7 @@ AutomationRangeDrag::AutomationRangeDrag (EditingContext& ec, list { DEBUG_TRACE (DEBUG::Drags, "New AutomationRangeDrag\n"); - list> lines; + list> lines; for (list::const_iterator i = v.begin (); i != v.end (); ++i) { if (AudioRegionView* audio_view = dynamic_cast (*i)) { @@ -6418,12 +6418,12 @@ AutomationRangeDrag::AutomationRangeDrag (EditingContext& ec, list * @param offset Offset from the session start to the points in the AutomationLines. */ void -AutomationRangeDrag::setup (list> const& lines) +AutomationRangeDrag::setup (list> const& lines) { /* find the lines that overlap the ranges being dragged */ - list>::const_iterator i = lines.begin (); + list>::const_iterator i = lines.begin (); while (i != lines.end ()) { - list>::const_iterator j = i; + list>::const_iterator j = i; ++j; pair r = (*i)->get_point_x_range (); diff --git a/gtk2_ardour/editor_drag.h b/gtk2_ardour/editor_drag.h index 0c7740834a..d5dac0dd4e 100644 --- a/gtk2_ardour/editor_drag.h +++ b/gtk2_ardour/editor_drag.h @@ -84,7 +84,7 @@ class TempoMarker; class TempoCurve; class ControlPoint; class AudioRegionView; -class AutomationLine; +class AutomationLineBase; class AutomationTimeAxisView; class VelocityDisplay; @@ -1202,10 +1202,10 @@ private: }; /** Control point drag */ -class ControlPointDrag : public EditorDrag +class ControlPointDrag : public Drag { public: - ControlPointDrag (Editor&, ArdourCanvas::Item *); + ControlPointDrag (EditingContext&, ArdourCanvas::Item *); void start_grab (GdkEvent *, Gdk::Cursor* c = 0); void motion (GdkEvent *, bool); @@ -1250,7 +1250,7 @@ public: private: - AutomationLine* _line; + AutomationLineBase* _line; double _fixed_grab_x; double _fixed_grab_y; double _cumulative_y_drag; @@ -1487,7 +1487,7 @@ public: } private: - void setup (std::list > const &); + void setup (std::list > const &); double y_fraction (double global_y_position) const; double value (std::shared_ptr list, Temporal::timepos_t const & x) const; @@ -1495,7 +1495,7 @@ private: /** A line that is part of the drag */ struct Line { - std::shared_ptr line; ///< the line + std::shared_ptr line; ///< the line std::list points; ///< points to drag on the line std::pair range; ///< the range of all points on the line, in session time XMLNode* state; ///< the XML state node before the drag diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index e580a52bdd..fad1463cc4 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -561,49 +561,7 @@ Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType it case AutomationLineItem: if (eff_mouse_mode != MouseRange && eff_mouse_mode != MouseDraw) { - AutomationLine* al = reinterpret_cast (item->get_data ("line")); - std::list selectables; - double mx = event->button.x; - double my = event->button.y; - - al->grab_item().canvas_to_item (mx, my); - - uint32_t before, after; - samplecnt_t const where = (samplecnt_t) floor (mx * samples_per_pixel); - - if (!al || !al->control_points_adjacent (where, before, after)) { - break; - } - - selectables.push_back (al->nth (before)); - selectables.push_back (al->nth (after)); - - switch (op) { - case SelectionSet: - if (press) { - selection->set (selectables); - _mouse_changed_selection = true; - } - break; - case SelectionAdd: - if (press) { - selection->add (selectables); - _mouse_changed_selection = true; - } - break; - case SelectionToggle: - if (press) { - selection->toggle (selectables); - _mouse_changed_selection = true; - } - break; - case SelectionExtend: - /* XXX */ - break; - case SelectionRemove: - /* not relevant */ - break; - } + select_automation_line (&event->button, item, op); } break; @@ -1845,245 +1803,6 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT return false; } -bool -Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type) -{ - ControlPoint* cp; - ArdourMarker * marker; - MeterMarker* m_marker = 0; - TempoMarker* t_marker = 0; - double fraction; - bool ret = true; - - /* by the time we reach here, entered_regionview and entered trackview - * will have already been set as appropriate. Things are done this - * way because this method isn't passed a pointer to a variable type of - * thing that is entered (which may or may not be canvas item). - * (e.g. the actual entered regionview) - */ - - choose_canvas_cursor_on_entry (item_type); - - switch (item_type) { - case GridZoneItem: - break; - - case ControlPointItem: - if (mouse_mode == MouseDraw || mouse_mode == MouseObject || mouse_mode == MouseContent) { - cp = static_cast(item->get_data ("control_point")); - cp->show (); - - fraction = 1.0 - (cp->get_y() / cp->line().height()); - - _verbose_cursor->set (cp->line().get_verbose_cursor_string (fraction)); - _verbose_cursor->show (); - } - break; - - case GainLineItem: - if (mouse_mode == MouseDraw) { - ArdourCanvas::Line *line = dynamic_cast (item); - if (line) { - line->set_outline_color (UIConfiguration::instance().color ("entered gain line")); - } - } - break; - - case AutomationLineItem: - if (mouse_mode == MouseDraw || mouse_mode == MouseObject) { - ArdourCanvas::Line *line = dynamic_cast (item); - if (line) { - line->set_outline_color (UIConfiguration::instance().color ("entered automation line")); - } - } - break; - - case AutomationTrackItem: - AutomationTimeAxisView* atv; - if ((atv = static_cast(item->get_data ("trackview"))) != 0) { - clear_entered_track = false; - set_entered_track (atv); - } - break; - - case MarkerItem: - if ((marker = static_cast (item->get_data ("marker"))) == 0) { - break; - } - entered_marker = marker; - marker->set_entered (true); - break; - - case MeterMarkerItem: - if ((m_marker = static_cast (item->get_data ("marker"))) == 0) { - break; - } - entered_marker = m_marker; - /* "music" currently serves as a stand-in for "entered". */ - m_marker->set_color ("meter marker music"); - break; - - case TempoMarkerItem: - if ((t_marker = static_cast (item->get_data ("marker"))) == 0) { - break; - } - entered_marker = t_marker; - /* "music" currently serves as a stand-in for "entered". */ - t_marker->set_color ("tempo marker music"); - break; - - case FadeInHandleItem: - case FadeInTrimHandleItem: - if (mouse_mode == MouseObject) { - ArdourCanvas::Rectangle *rect = dynamic_cast (item); - if (rect) { - RegionView* rv = static_cast(item->get_data ("regionview")); - rect->set_fill_color (rv->get_fill_color()); - } - } - break; - - case FadeOutHandleItem: - case FadeOutTrimHandleItem: - if (mouse_mode == MouseObject) { - ArdourCanvas::Rectangle *rect = dynamic_cast (item); - if (rect) { - RegionView* rv = static_cast(item->get_data ("regionview")); - rect->set_fill_color (rv->get_fill_color ()); - } - } - break; - - case FeatureLineItem: - { - ArdourCanvas::Line *line = dynamic_cast (item); - line->set_outline_color (0xFF0000FF); - } - break; - - case SelectionItem: - break; - - case WaveItem: - { - if (entered_regionview) { - entered_regionview->entered(); - } - } - break; - - default: - break; - } - - /* third pass to handle entered track status in a comprehensible way. - */ - - switch (item_type) { - case GainLineItem: - case AutomationLineItem: - case ControlPointItem: - /* these do not affect the current entered track state */ - clear_entered_track = false; - break; - - case AutomationTrackItem: - /* handled above already */ - break; - - default: - - break; - } - - return ret; -} - -bool -Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type) -{ - AutomationLine* al; - ArdourMarker *marker; - TempoMarker *t_marker; - MeterMarker *m_marker; - bool ret = true; - - if (!_enter_stack.empty()) { - _enter_stack.pop_back(); - } - - switch (item_type) { - case GridZoneItem: - break; - - case ControlPointItem: - _verbose_cursor->hide (); - break; - - case GainLineItem: - case AutomationLineItem: - al = reinterpret_cast (item->get_data ("line")); - { - ArdourCanvas::Line *line = dynamic_cast (item); - if (line) { - line->set_outline_color (al->get_line_color()); - } - } - break; - - case MarkerItem: - if ((marker = static_cast (item->get_data ("marker"))) == 0) { - break; - } - entered_marker = 0; - marker->set_entered (false); - break; - - case MeterMarkerItem: - if ((m_marker = static_cast (item->get_data ("marker"))) == 0) { - break; - } - m_marker->set_color ("meter marker"); - entered_marker = 0; - break; - - case TempoMarkerItem: - if ((t_marker = static_cast (item->get_data ("marker"))) == 0) { - break; - } - t_marker->set_color ("tempo marker"); - entered_marker = 0; - break; - - case FadeInTrimHandleItem: - case FadeOutTrimHandleItem: - case FadeInHandleItem: - case FadeOutHandleItem: - { - ArdourCanvas::Rectangle *rect = dynamic_cast (item); - if (rect) { - rect->set_fill_color (UIConfiguration::instance().color ("inactive fade handle")); - } - } - break; - - case AutomationTrackItem: - break; - - case FeatureLineItem: - { - ArdourCanvas::Line *line = dynamic_cast (item); - line->set_outline_color (UIConfiguration::instance().color ("zero line")); - } - break; - - default: - _region_peak_cursor->hide (); - break; - } - - return ret; -} GridType Editor::determine_mapping_grid_snap(timepos_t t) diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index f7ee58dfe4..53fb4fade5 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -5708,16 +5708,6 @@ Editor::duplicate_selection (float times) } } -/** Reset all selected points to the relevant default value */ -void -Editor::reset_point_selection () -{ - for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) { - ARDOUR::AutomationList::iterator j = (*i)->model (); - (*j)->value = (*i)->line().the_list()->descriptor ().normal; - } -} - void Editor::center_playhead () { diff --git a/gtk2_ardour/midi_cue_automation_line.cc b/gtk2_ardour/midi_cue_automation_line.cc index 73a2239b88..1f9b0fc909 100644 --- a/gtk2_ardour/midi_cue_automation_line.cc +++ b/gtk2_ardour/midi_cue_automation_line.cc @@ -16,6 +16,11 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "canvas/rectangle.h" + +#include "editing_context.h" +#include "editor_drag.h" +#include "keyboard.h" #include "midi_cue_automation_line.h" MidiCueAutomationLine::MidiCueAutomationLine (const std::string& name, @@ -26,10 +31,18 @@ MidiCueAutomationLine::MidiCueAutomationLine (const std::string& const ARDOUR::ParameterDescriptor& desc) : AutomationLineBase (name, ec, parent, drag_base, al, desc) { + _drag_base->set_data ("line", this); + _drag_base->Event.connect (sigc::mem_fun (*this, &MidiCueAutomationLine::base_event_handler)); } bool -MidiCueAutomationLine::event_handler (GdkEvent*) +MidiCueAutomationLine::base_event_handler (GdkEvent* ev) { - return true; + return _editing_context.typed_event (_drag_base, ev, AutomationTrackItem); +} + +bool +MidiCueAutomationLine::event_handler (GdkEvent* ev) +{ + return _editing_context.typed_event (line, ev, AutomationLineItem); } diff --git a/gtk2_ardour/midi_cue_automation_line.h b/gtk2_ardour/midi_cue_automation_line.h index 0b9895e60d..4b8902d4cf 100644 --- a/gtk2_ardour/midi_cue_automation_line.h +++ b/gtk2_ardour/midi_cue_automation_line.h @@ -31,6 +31,7 @@ class MidiCueAutomationLine : public AutomationLineBase std::shared_ptr al, const ARDOUR::ParameterDescriptor& desc); + bool base_event_handler (GdkEvent*); bool event_handler (GdkEvent*); }; diff --git a/gtk2_ardour/midi_cue_editor.cc b/gtk2_ardour/midi_cue_editor.cc index 02fce3e0b0..b0d371a77c 100644 --- a/gtk2_ardour/midi_cue_editor.cc +++ b/gtk2_ardour/midi_cue_editor.cc @@ -393,6 +393,12 @@ MidiCueEditor::current_page_samples() const return (samplecnt_t) _visible_canvas_width* samples_per_pixel; } +bool +MidiCueEditor::canvas_control_point_event (GdkEvent* event, ArdourCanvas::Item* item, ControlPoint* cp) +{ + return typed_event (item, event, ControlPointItem); +} + bool MidiCueEditor::canvas_note_event (GdkEvent* event, ArdourCanvas::Item* item) { @@ -518,6 +524,11 @@ MidiCueEditor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event } return true; + case ControlPointItem: + _drags->set (new ControlPointDrag (*this, item), event); + return true; + break; + case VelocityItem: _drags->set (new LollipopDrag (*this, item), event); return true; @@ -528,6 +539,17 @@ MidiCueEditor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event return true; break; + case AutomationTrackItem: + _drags->set (new AutomationDrawDrag (*this, nullptr, *static_cast(item), false, Temporal::BeatTime), event); + return true; + break; + + case AutomationLineItem: { + ARDOUR::SelectionOperation op = ArdourKeyboard::selection_type (event->button.state); + select_automation_line (&event->button, item, op); + return true; + } + default: break; } @@ -604,18 +626,6 @@ MidiCueEditor::motion_handler (ArdourCanvas::Item*, GdkEvent* event, bool from_a return true; } -bool -MidiCueEditor::enter_handler (ArdourCanvas::Item*, GdkEvent*, ItemType) -{ - return true; -} - -bool -MidiCueEditor::leave_handler (ArdourCanvas::Item*, GdkEvent*, ItemType) -{ - return true; -} - bool MidiCueEditor::key_press_handler (ArdourCanvas::Item*, GdkEvent* ev, ItemType) { @@ -1455,3 +1465,165 @@ MidiCueEditor::escape () view->clear_note_selection (); } +Gdk::Cursor* +MidiCueEditor::which_track_cursor () const +{ + return _cursors->grabber; +} + +Gdk::Cursor* +MidiCueEditor::which_mode_cursor () const +{ + Gdk::Cursor* mode_cursor = MouseCursors::invalid_cursor (); + + switch (mouse_mode) { + case Editing::MouseContent: + /* don't use mode cursor, pick a grabber cursor based on the item */ + break; + + case Editing::MouseDraw: + mode_cursor = _cursors->midi_pencil; + break; + + default: + break; + } + + return mode_cursor; +} + +Gdk::Cursor* +MidiCueEditor::which_trim_cursor (bool left_side) const +{ + abort (); + /*NOTREACHED*/ + return nullptr; +} + + +Gdk::Cursor* +MidiCueEditor::which_canvas_cursor (ItemType type) const +{ + Gdk::Cursor* cursor = which_mode_cursor (); + + if (mouse_mode == Editing::MouseContent) { + + /* find correct cursor to use in object/smart mode */ + switch (type) { + case AutomationTrackItem: + cursor = which_track_cursor (); + break; + case PlayheadCursorItem: + cursor = _cursors->grabber; + break; + case SelectionItem: + cursor = _cursors->selector; + break; + case ControlPointItem: + cursor = _cursors->fader; + break; + case GainLineItem: + cursor = _cursors->cross_hair; + break; + case AutomationLineItem: + cursor = _cursors->cross_hair; + break; + case StartSelectionTrimItem: + cursor = _cursors->left_side_trim; + break; + case EndSelectionTrimItem: + cursor = _cursors->right_side_trim; + break; + case NoteItem: + cursor = _cursors->grabber_note; + default: + break; + } + + } else if (mouse_mode == Editing::MouseDraw) { + + /* ControlPointItem is not really specific to region gain mode + but it is the same cursor so don't worry about this for now. + The result is that we'll see the fader cursor if we enter + non-region-gain-line control points while in MouseDraw + mode, even though we can't edit them in this mode. + */ + + switch (type) { + case ControlPointItem: + cursor = _cursors->fader; + break; + case NoteItem: + cursor = _cursors->grabber_note; + default: + break; + } + } + + return cursor; +} + +bool +MidiCueEditor::enter_handler (ArdourCanvas::Item* item, GdkEvent* ev, ItemType item_type) +{ + AutomationLine* al; + + choose_canvas_cursor_on_entry (item_type); + + switch (item_type) { + case AutomationTrackItem: + /* item is the base rectangle */ + al = reinterpret_cast (item->get_data ("line")); + al->track_entered (); + break; + + case AutomationLineItem: + { + ArdourCanvas::Line *line = dynamic_cast (item); + + if (line) { + line->set_outline_color (UIConfiguration::instance().color ("entered automation line")); + } + } + break; + default: + break; + } + + return true; +} + +bool +MidiCueEditor::leave_handler (ArdourCanvas::Item* item, GdkEvent* ev, ItemType item_type) +{ + AutomationLine* al; + + if (!_enter_stack.empty()) { + _enter_stack.pop_back(); + } + + switch (item_type) { + case ControlPointItem: + _verbose_cursor->hide (); + break; + + case AutomationLineItem: + al = reinterpret_cast (item->get_data ("line")); + { + ArdourCanvas::Line *line = dynamic_cast (item); + if (line) { + line->set_outline_color (al->get_line_color()); + } + } + if (ev->crossing.detail != GDK_NOTIFY_INFERIOR) { + al->track_exited (); + } + break; + + default: + break; + } + + + return true; +} diff --git a/gtk2_ardour/midi_cue_editor.h b/gtk2_ardour/midi_cue_editor.h index 134f43c992..1d5e6a536b 100644 --- a/gtk2_ardour/midi_cue_editor.h +++ b/gtk2_ardour/midi_cue_editor.h @@ -68,6 +68,7 @@ class MidiCueEditor : public CueEditor bool canvas_note_event (GdkEvent* event, ArdourCanvas::Item*); bool canvas_velocity_base_event (GdkEvent* event, ArdourCanvas::Item*); bool canvas_velocity_event (GdkEvent* event, ArdourCanvas::Item*); + bool canvas_control_point_event (GdkEvent* event, ArdourCanvas::Item*, ControlPoint*); int32_t get_grid_beat_divisions (Editing::GridType gt) const { return 1; } int32_t get_grid_music_divisions (Editing::GridType gt, uint32_t event_state) const { return 1; } @@ -98,6 +99,11 @@ class MidiCueEditor : public CueEditor void midi_action (void (MidiView::*method)()); + Gdk::Cursor* which_track_cursor () const; + Gdk::Cursor* which_mode_cursor () const; + Gdk::Cursor* which_trim_cursor (bool left_side) const; + Gdk::Cursor* which_canvas_cursor (ItemType type) const; + protected: void register_actions (); diff --git a/gtk2_ardour/midi_cue_view.cc b/gtk2_ardour/midi_cue_view.cc index d4a037aff0..8af28c08e1 100644 --- a/gtk2_ardour/midi_cue_view.cc +++ b/gtk2_ardour/midi_cue_view.cc @@ -33,6 +33,7 @@ #include "midi_cue_view.h" #include "midi_cue_velocity.h" #include "note.h" +#include "ui_config.h" #include "velocity_display.h" #include "pbd/i18n.h" @@ -70,6 +71,7 @@ MidiCueView::MidiCueView (std::shared_ptr mt, automation_group = new ArdourCanvas::Rectangle (&parent); CANVAS_DEBUG_NAME (automation_group, "cue automation group"); + automation_group->set_fill_color (UIConfiguration::instance().color ("midi automation track fill")); velocity_base = new ArdourCanvas::Rectangle (&parent); CANVAS_DEBUG_NAME (velocity_base, "cue velocity base"); @@ -275,7 +277,6 @@ MidiCueView::show_automation (Evoral::Parameter const & param) std::shared_ptr ac = std::dynamic_pointer_cast (control); if (ac) { - std::cerr << "found control, list contains " << ac->alist()->size() << std::endl; automation_line = new MidiCueAutomationLine ("whatevs", _editing_context, *automation_group, diff --git a/gtk2_ardour/midi_view.cc b/gtk2_ardour/midi_view.cc index a43c645227..d37ee1bad1 100644 --- a/gtk2_ardour/midi_view.cc +++ b/gtk2_ardour/midi_view.cc @@ -1753,8 +1753,6 @@ MidiView::add_note(const std::shared_ptr note, bool visible) event = 0; } - std::cerr << "add note, event " << event << std::endl; - if (event) { ghost_add_note (event); diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc index 48d4ebb201..7f9fa9d273 100644 --- a/gtk2_ardour/route_time_axis.cc +++ b/gtk2_ardour/route_time_axis.cc @@ -2606,7 +2606,7 @@ RouteTimeAxisView::automation_child(Evoral::Parameter param, PBD::ID ctrl_id) return std::shared_ptr(); } -std::shared_ptr +std::shared_ptr RouteTimeAxisView::automation_child_by_alist_id (PBD::ID alist_id) { for (list::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) { @@ -2615,10 +2615,9 @@ RouteTimeAxisView::automation_child_by_alist_id (PBD::ID alist_id) if (!atv) { continue; } - list > lines = atv->lines(); - for (list >::const_iterator li = lines.begin(); li != lines.end(); ++li) { - if ((*li)->the_list()->id() == alist_id) { - return *li; + for (auto & line : atv->lines()) { + if (line->the_list()->id() == alist_id) { + return line; } } } diff --git a/gtk2_ardour/route_time_axis.h b/gtk2_ardour/route_time_axis.h index 4147eba0d3..549de78252 100644 --- a/gtk2_ardour/route_time_axis.h +++ b/gtk2_ardour/route_time_axis.h @@ -207,7 +207,7 @@ protected: void add_processor_automation_curve (std::shared_ptr r, Evoral::Parameter); void add_existing_processor_automation_curves (std::weak_ptr); - std::shared_ptr automation_child_by_alist_id (PBD::ID); + std::shared_ptr automation_child_by_alist_id (PBD::ID); void reset_processor_automation_curves (); diff --git a/gtk2_ardour/selection.cc b/gtk2_ardour/selection.cc index 3c5d3decf8..5ddd08bbaf 100644 --- a/gtk2_ardour/selection.cc +++ b/gtk2_ardour/selection.cc @@ -1315,7 +1315,7 @@ Selection::set_state (XMLNode const & node, int) vector cps; if (stv) { - std::shared_ptr li = stv->automation_child_by_alist_id (alist_id); + std::shared_ptr li = stv->automation_child_by_alist_id (alist_id); if (li) { ControlPoint* cp = li->nth(view_index); if (cp) { diff --git a/gtk2_ardour/stripable_time_axis.cc b/gtk2_ardour/stripable_time_axis.cc index db83aa0e33..92cb4053ff 100644 --- a/gtk2_ardour/stripable_time_axis.cc +++ b/gtk2_ardour/stripable_time_axis.cc @@ -192,15 +192,14 @@ StripableTimeAxisView::automation_child(Evoral::Parameter param, PBD::ID) } } -std::shared_ptr +std::shared_ptr StripableTimeAxisView::automation_child_by_alist_id (PBD::ID alist_id) { for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) { std::shared_ptr atv (i->second); - std::list > lines = atv->lines(); - for (std::list >::const_iterator li = lines.begin(); li != lines.end(); ++li) { - if ((*li)->the_list()->id() == alist_id) { - return *li; + for (auto & line : atv->lines()) { + if (line->the_list()->id() == alist_id) { + return line;; } } } diff --git a/gtk2_ardour/stripable_time_axis.h b/gtk2_ardour/stripable_time_axis.h index ddd78f26ba..8844bcb6b7 100644 --- a/gtk2_ardour/stripable_time_axis.h +++ b/gtk2_ardour/stripable_time_axis.h @@ -38,7 +38,7 @@ public: virtual void create_automation_child (const Evoral::Parameter& param, bool show) = 0; virtual std::shared_ptr automation_child (Evoral::Parameter param, PBD::ID ctrl_id = PBD::ID(0)); - virtual std::shared_ptr automation_child_by_alist_id (PBD::ID); + virtual std::shared_ptr automation_child_by_alist_id (PBD::ID); void request_redraw ();