diff --git a/gtk2_ardour/audio_region_view.cc b/gtk2_ardour/audio_region_view.cc index 9c21a9403d..38dcc5c386 100644 --- a/gtk2_ardour/audio_region_view.cc +++ b/gtk2_ardour/audio_region_view.cc @@ -407,7 +407,7 @@ AudioRegionView::reset_width_dependent_items (double pixel_width) RegionView::reset_width_dependent_items(pixel_width); assert(_pixel_width == pixel_width); - if (pixel_width <= 6.0 || _height < 5.0 || !trackview.session()->config.get_show_region_fades()) { + if (pixel_width <= 20.0 || _height < 5.0 || !trackview.session()->config.get_show_region_fades()) { if (fade_in_handle) { fade_in_handle->hide(); } if (fade_out_handle) { fade_out_handle->hide(); } if (fade_in_trim_handle) { fade_in_trim_handle->hide(); } @@ -1144,6 +1144,8 @@ AudioRegionView::create_one_wave (uint32_t which, bool /*direct*/) wave->set_samples_per_pixel (samples_per_pixel); wave->set_show_zero_line (true); wave->set_clip_level (Config->get_waveform_clip_level ()); + + wave->Event.connect (sigc::bind (sigc::mem_fun (PublicEditor::instance(), &PublicEditor::canvas_wave_view_event), wave, this)); switch (Config->get_waveform_shape()) { case Rectified: diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 638c000d2e..e0e11e3f49 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -743,7 +743,6 @@ Editor::Editor () _popup_region_menu_item = 0; _show_marker_lines = false; - _over_region_trim_target = false; /* Button bindings */ @@ -794,7 +793,7 @@ Editor::add_toplevel_controls (Container& cont) bool Editor::get_smart_mode () const { - return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() ); + return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active()); } void @@ -819,8 +818,6 @@ Editor::catch_vanishing_regionview (RegionView *rv) if (!_all_region_actions_sensitized) { sensitize_all_region_actions (true); } - - _over_region_trim_target = false; } void @@ -834,7 +831,9 @@ Editor::set_entered_regionview (RegionView* rv) entered_regionview->exited (); } - if ((entered_regionview = rv) != 0) { + entered_regionview = rv; + + if (entered_regionview != 0) { entered_regionview->entered (internal_editing ()); } @@ -853,7 +852,9 @@ Editor::set_entered_track (TimeAxisView* tav) entered_track->exited (); } - if ((entered_track = tav) != 0) { + entered_track = tav; + + if (entered_track) { entered_track->entered (); } } @@ -2010,7 +2011,7 @@ Editor::set_edit_point_preference (EditPoint ep, bool force) edit_point_selector.set_text (str); } - set_canvas_cursor (); + reset_canvas_cursor (); if (!force && !changed) { return; @@ -2416,7 +2417,7 @@ Editor::get_state () * in stacked or expanded region display mode, otherwise 0. */ std::pair -Editor::trackview_by_y_position (double y, bool trackview_relative_offset) +Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const { if (!trackview_relative_offset) { y -= _trackview_group->canvas_origin().y; @@ -2426,7 +2427,7 @@ Editor::trackview_by_y_position (double y, bool trackview_relative_offset) return std::make_pair ( (TimeAxisView *) 0, 0); } - for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) { + for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) { std::pair const r = (*iter)->covers_y_position (y); diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 9e78181dcf..6606f26b93 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -535,7 +535,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD JoinObjectRangeState _join_object_range_state; - void update_join_object_range_location (double, double); + void update_join_object_range_location (double); boost::optional pre_notebook_shrink_pane_width; @@ -703,8 +703,12 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD std::stack _cursor_stack; Gdk::Cursor* current_canvas_cursor; - Gdk::Cursor* which_grabber_cursor (); - void set_canvas_cursor (); + Gdk::Cursor* which_grabber_cursor () const; + Gdk::Cursor* which_region_cursor () const; + Gdk::Cursor* which_mode_cursor () const; + Gdk::Cursor* which_trim_cursor (bool left_side) const; + bool reset_canvas_cursor (); + void choose_canvas_cursor_on_entry (GdkEventCrossing*, ItemType); ArdourCanvas::GtkCanvas* _track_canvas; ArdourCanvas::GtkCanvasViewport* _track_canvas_viewport; @@ -1041,7 +1045,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD /* track views */ TrackViewList track_views; - std::pair trackview_by_y_position (double, bool trackview_relative_offset = true); + std::pair trackview_by_y_position (double, bool trackview_relative_offset = true) const; RouteTimeAxisView* axis_view_from_route (boost::shared_ptr) const; TrackViewList get_tracks_for_range_action () const; @@ -1402,6 +1406,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD bool canvas_fade_out_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*); bool canvas_fade_out_handle_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*, bool trim = false); bool canvas_region_view_event (GdkEvent* event,ArdourCanvas::Item*, RegionView*); + bool canvas_wave_view_event (GdkEvent* event,ArdourCanvas::Item*, RegionView*); bool canvas_frame_handle_event (GdkEvent* event,ArdourCanvas::Item*, RegionView*); bool canvas_region_view_name_highlight_event (GdkEvent* event,ArdourCanvas::Item*, RegionView*); bool canvas_region_view_name_event (GdkEvent* event,ArdourCanvas::Item*, RegionView*); @@ -1439,9 +1444,6 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD friend class EditorRouteGroups; friend class EditorRegions; - /** true if the mouse is over a place where region trim can happen */ - bool _over_region_trim_target; - /* non-public event handlers */ bool canvas_playhead_cursor_event (GdkEvent* event, ArdourCanvas::Item*); @@ -2059,8 +2061,6 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD Gtk::MenuItem& action_menu_item (std::string const &); void action_pre_activated (Glib::RefPtr const &); - void set_canvas_cursor_for_region_view (double, RegionView *); - MouseCursors* _cursors; void follow_mixer_selection (); diff --git a/gtk2_ardour/editor_canvas.cc b/gtk2_ardour/editor_canvas.cc index 8ad2abdfad..73bc7d1884 100644 --- a/gtk2_ardour/editor_canvas.cc +++ b/gtk2_ardour/editor_canvas.cc @@ -35,6 +35,7 @@ #include "canvas/debug.h" #include "ardour_ui.h" +#include "automation_time_axis.h" #include "editor.h" #include "global_signals.h" #include "editing.h" @@ -926,39 +927,6 @@ Editor::horizontal_position () const return sample_to_pixel (leftmost_frame); } -void -Editor::set_canvas_cursor (Gdk::Cursor* cursor, bool save) -{ - if (save) { - current_canvas_cursor = cursor; - } - - Glib::RefPtr win = _track_canvas->get_window(); - - if (win) { - _track_canvas->get_window()->set_cursor (*cursor); - } -} - -void -Editor::push_canvas_cursor (Gdk::Cursor* cursor) -{ - if (cursor) { - _cursor_stack.push (cursor); - set_canvas_cursor (cursor, false); - } -} - -void -Editor::pop_canvas_cursor () -{ - if (!_cursor_stack.empty()) { - Gdk::Cursor* cursor = _cursor_stack.top (); - _cursor_stack.pop (); - set_canvas_cursor (cursor, false); - } -} - bool Editor::track_canvas_key_press (GdkEventKey*) { @@ -1004,3 +972,352 @@ Editor::get_track_canvas() const { return _track_canvas_viewport; } + +void +Editor::set_canvas_cursor (Gdk::Cursor* cursor, bool save) +{ + if (save) { + current_canvas_cursor = cursor; + } + + Glib::RefPtr win = _track_canvas->get_window(); + + if (win) { + _track_canvas->get_window()->set_cursor (*cursor); + } +} + +void +Editor::push_canvas_cursor (Gdk::Cursor* cursor) +{ + if (cursor) { + _cursor_stack.push (cursor); + set_canvas_cursor (cursor, false); + } +} + +void +Editor::pop_canvas_cursor () +{ + if (!_cursor_stack.empty()) { + Gdk::Cursor* cursor = _cursor_stack.top (); + _cursor_stack.pop (); + set_canvas_cursor (cursor, false); + } +} + +Gdk::Cursor* +Editor::which_grabber_cursor () const +{ + Gdk::Cursor* c = _cursors->grabber; + + if (_internal_editing) { + switch (mouse_mode) { + case MouseDraw: + c = _cursors->midi_pencil; + break; + + case MouseObject: + c = _cursors->grabber_note; + break; + + case MouseTimeFX: + c = _cursors->midi_resize; + break; + + case MouseRange: + c = _cursors->grabber_note; + break; + + default: + break; + } + + } else { + + switch (_edit_point) { + case EditAtMouse: + c = _cursors->grabber_edit_point; + break; + default: + boost::shared_ptr m = _movable.lock(); + if (m && m->locked()) { + c = _cursors->speaker; + } + break; + } + } + + return c; +} + +Gdk::Cursor* +Editor::which_trim_cursor (bool left) const +{ + if (!entered_regionview) { + return 0; + } + + Trimmable::CanTrim ct = entered_regionview->region()->can_trim (); + + if (left) { + + if (ct & Trimmable::FrontTrimEarlier) { + return _cursors->left_side_trim; + } else { + return _cursors->left_side_trim_right_only; + } + } else { + if (ct & Trimmable::EndTrimLater) { + return _cursors->right_side_trim; + } else { + return _cursors->right_side_trim_left_only; + } + } +} + +Gdk::Cursor* +Editor::which_mode_cursor () const +{ + Gdk::Cursor* mode_cursor = 0; + + switch (mouse_mode) { + case MouseRange: + mode_cursor = _cursors->selector; + if (_internal_editing) { + mode_cursor = which_grabber_cursor(); + } + break; + + case MouseObject: + /* don't use mode cursor, pick a grabber cursor based on the item */ + break; + + case MouseDraw: + mode_cursor = _cursors->midi_pencil; + break; + + case MouseGain: + mode_cursor = _cursors->cross_hair; + break; + + case MouseZoom: + if (Keyboard::the_keyboard().key_is_down (GDK_Control_L)) { + mode_cursor = _cursors->zoom_out; + } else { + mode_cursor = _cursors->zoom_in; + } + break; + + case MouseTimeFX: + mode_cursor = _cursors->time_fx; // just use playhead + break; + + case MouseAudition: + mode_cursor = _cursors->speaker; + break; + } + + /* up-down cursor as a cue that automation can be dragged up and down when in join object/range mode */ + if (!_internal_editing && get_smart_mode() ) { + + double x, y; + get_pointer_position (x, y); + + if (x >= 0 && y >= 0) { + + vector items; + + /* Note how we choose a specific scroll group to get + * items from. This could be problematic. + */ + + hv_scroll_group->add_items_at_point (ArdourCanvas::Duple (x,y), items); + + // first item will be the upper most + + if (!items.empty()) { + const ArdourCanvas::Item* i = items.front(); + + if (i && i->parent() && i->parent()->get_data (X_("timeselection"))) { + pair tvp = trackview_by_y_position (_last_motion_y); + if (dynamic_cast (tvp.first)) { + mode_cursor = _cursors->up_down; + } + } + } + } + } + + return mode_cursor; +} + +Gdk::Cursor* +Editor::which_region_cursor () const +{ + Gdk::Cursor* cursor = 0; + + assert (mouse_mode == MouseObject || get_smart_mode()); + + if (!_internal_editing) { + switch (_join_object_range_state) { + case JOIN_OBJECT_RANGE_NONE: + case JOIN_OBJECT_RANGE_OBJECT: + cursor = which_grabber_cursor (); + cerr << "region use grabber\n"; + break; + case JOIN_OBJECT_RANGE_RANGE: + cursor = _cursors->selector; + cerr << "region use selector\n"; + break; + } + } + + return cursor; +} + +bool +Editor::reset_canvas_cursor () +{ + if (!is_drawable()) { + return false; + } + + Gdk::Cursor* cursor = which_mode_cursor (); + + if (cursor) { + set_canvas_cursor (cursor); + return true; + } + + return false; +} + +void +Editor::choose_canvas_cursor_on_entry (GdkEventCrossing* /*event*/, ItemType type) +{ + Gdk::Cursor* cursor = 0; + + cerr << "entered new item type " << enum_2_string (type) << endl; + + if (_drags->active()) { + return; + } + + cursor = which_mode_cursor (); + + if (mouse_mode == MouseObject || get_smart_mode ()) { + + /* find correct cursor to use in object/smart mode */ + + switch (type) { + case RegionItem: + case RegionViewNameHighlight: + case RegionViewName: + case WaveItem: + cursor = which_region_cursor (); + break; + case PlayheadCursorItem: + switch (_edit_point) { + case EditAtMouse: + cursor = _cursors->grabber_edit_point; + break; + default: + cursor = _cursors->grabber; + break; + } + break; + case SelectionItem: + cursor = _cursors->selector; + break; + case ControlPointItem: + cursor = _cursors->fader; + break; + case GainLineItem: + cursor = _cursors->fader; + break; + case AutomationLineItem: + cursor = _cursors->cross_hair; + break; + case StartSelectionTrimItem: + break; + case EndSelectionTrimItem: + break; + case AutomationTrackItem: + cursor = _cursors->cross_hair; + break; + case FadeInItem: + cursor = _cursors->fade_in; + break; + case FadeInHandleItem: + cursor = _cursors->fade_in; + break; + case FadeInTrimHandleItem: + cursor = _cursors->fade_in; + break; + case FadeOutItem: + cursor = _cursors->fade_out; + break; + case FadeOutHandleItem: + cursor = _cursors->fade_out; + break; + case FadeOutTrimHandleItem: + cursor = _cursors->fade_out; + break; + case NoteItem: + cursor = which_grabber_cursor(); + break; + case FeatureLineItem: + cursor = _cursors->cross_hair; + break; + case LeftFrameHandle: + cursor = which_trim_cursor (true); + break; + case RightFrameHandle: + cursor = which_trim_cursor (false); + break; + case StartCrossFadeItem: + cursor = _cursors->fade_in; + break; + case EndCrossFadeItem: + cursor = _cursors->fade_out; + break; + case CrossfadeViewItem: + cursor = _cursors->cross_hair; + break; + default: + break; + } + } + + switch (type) { + /* These items use the timebar cursor at all times */ + case TimecodeRulerItem: + case MinsecRulerItem: + case BBTRulerItem: + case SamplesRulerItem: + cursor = _cursors->timebar; + break; + + /* These items use the grabber cursor at all times */ + case MeterMarkerItem: + case TempoMarkerItem: + case MeterBarItem: + case TempoBarItem: + case MarkerItem: + case MarkerBarItem: + case RangeMarkerBarItem: + case CdMarkerBarItem: + case VideoBarItem: + case TransportMarkerBarItem: + cursor = which_grabber_cursor(); + break; + + default: + break; + } + + if (cursor) { + set_canvas_cursor (cursor, false); + } +} diff --git a/gtk2_ardour/editor_canvas_events.cc b/gtk2_ardour/editor_canvas_events.cc index 2f4fe40bcd..4eeb323e9e 100644 --- a/gtk2_ardour/editor_canvas_events.cc +++ b/gtk2_ardour/editor_canvas_events.cc @@ -278,16 +278,14 @@ Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, Reg break; case GDK_ENTER_NOTIFY: - if (event->crossing.detail != GDK_NOTIFY_INFERIOR) { - set_entered_regionview (rv); - ret = true; - } + set_entered_regionview (rv); + ret = enter_handler (item, event, RegionItem); break; case GDK_LEAVE_NOTIFY: if (event->crossing.detail != GDK_NOTIFY_INFERIOR) { set_entered_regionview (0); - ret = true; + ret = leave_handler (item, event, RegionItem); } break; @@ -298,6 +296,42 @@ Editor::canvas_region_view_event (GdkEvent *event, ArdourCanvas::Item* item, Reg return ret; } +bool +Editor::canvas_wave_view_event (GdkEvent *event, ArdourCanvas::Item* item, RegionView* rv) +{ + /* we only care about enter events here, required for mouse/cursor + * tracking. there is a non-linear (non-child/non-parent) relationship + * between various components of a regionview and so when we leave one + * of them (e.g. a trim handle) and enter another (e.g. the waveview) + * no other items get notified. enter/leave handling does not propagate + * in the same way as other events, so we need to catch this because + * entering (and leaving) the waveview is equivalent to + * entering/leaving the regionview (which is why it is passed in as a + * third argument). + * + * And in fact, we really only care about enter events. + */ + + bool ret = false; + + if (!rv->sensitive ()) { + return false; + } + + switch (event->type) { + case GDK_ENTER_NOTIFY: + set_entered_regionview (rv); + ret = enter_handler (item, event, WaveItem); + break; + + default: + break; + } + + return ret; +} + + bool Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, RouteTimeAxisView *tv) { @@ -324,11 +358,14 @@ Editor::canvas_stream_view_event (GdkEvent *event, ArdourCanvas::Item* item, Rou case GDK_ENTER_NOTIFY: set_entered_track (tv); - ret = true; + ret = enter_handler (item, event, StreamItem); break; case GDK_LEAVE_NOTIFY: - set_entered_track (0); + if (event->crossing.detail != GDK_NOTIFY_INFERIOR) { + set_entered_track (0); + } + ret = leave_handler (item, event, StreamItem); break; default: diff --git a/gtk2_ardour/editor_items.h b/gtk2_ardour/editor_items.h index 211b0d0212..ce9de4bc12 100644 --- a/gtk2_ardour/editor_items.h +++ b/gtk2_ardour/editor_items.h @@ -23,6 +23,7 @@ enum ItemType { RegionItem, StreamItem, + WaveItem, PlayheadCursorItem, MarkerItem, MarkerBarItem, diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index 8f84d5f602..6eedcf5bb7 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -185,51 +185,6 @@ Editor::canvas_event_sample (GdkEvent const * event, double* pcx, double* pcy) c return pixel_to_sample_from_event (x); } -Gdk::Cursor* -Editor::which_grabber_cursor () -{ - Gdk::Cursor* c = _cursors->grabber; - - if (_internal_editing) { - switch (mouse_mode) { - case MouseDraw: - c = _cursors->midi_pencil; - break; - - case MouseObject: - c = _cursors->grabber_note; - break; - - case MouseTimeFX: - c = _cursors->midi_resize; - break; - - case MouseRange: - c = _cursors->grabber_note; - break; - - default: - break; - } - - } else { - - switch (_edit_point) { - case EditAtMouse: - c = _cursors->grabber_edit_point; - break; - default: - boost::shared_ptr m = _movable.lock(); - if (m && m->locked()) { - c = _cursors->speaker; - } - break; - } - } - - return c; -} - void Editor::set_current_trimmable (boost::shared_ptr t) { @@ -237,7 +192,6 @@ Editor::set_current_trimmable (boost::shared_ptr t) if (!st || st == t) { _trimmable = t; - set_canvas_cursor (); } } @@ -248,97 +202,9 @@ Editor::set_current_movable (boost::shared_ptr m) if (!sm || sm != m) { _movable = m; - set_canvas_cursor (); } } -void -Editor::set_canvas_cursor () -{ - switch (mouse_mode) { - case MouseRange: - current_canvas_cursor = _cursors->selector; - if (_internal_editing) { - current_canvas_cursor = which_grabber_cursor(); - } - break; - - case MouseObject: - current_canvas_cursor = which_grabber_cursor(); - break; - - case MouseDraw: - current_canvas_cursor = _cursors->midi_pencil; - break; - - case MouseGain: - current_canvas_cursor = _cursors->cross_hair; - break; - - case MouseZoom: - if (Keyboard::the_keyboard().key_is_down (GDK_Control_L)) { - current_canvas_cursor = _cursors->zoom_out; - } else { - current_canvas_cursor = _cursors->zoom_in; - } - break; - - case MouseTimeFX: - current_canvas_cursor = _cursors->time_fx; // just use playhead - break; - - case MouseAudition: - current_canvas_cursor = _cursors->speaker; - break; - } - - if (!_internal_editing) { - switch (_join_object_range_state) { - case JOIN_OBJECT_RANGE_NONE: - break; - case JOIN_OBJECT_RANGE_OBJECT: - current_canvas_cursor = which_grabber_cursor (); - break; - case JOIN_OBJECT_RANGE_RANGE: - current_canvas_cursor = _cursors->selector; - break; - } - } - - /* up-down cursor as a cue that automation can be dragged up and down when in join object/range mode */ - if (!_internal_editing && get_smart_mode() ) { - - double x, y; - get_pointer_position (x, y); - - if (x >= 0 && y >= 0) { - - vector items; - - /* Note how we choose a specific scroll group to get - * items from. This could be problematic. - */ - - hv_scroll_group->add_items_at_point (ArdourCanvas::Duple (x,y), items); - - // first item will be the upper most - - if (!items.empty()) { - const ArdourCanvas::Item* i = items.front(); - - if (i && i->parent() && i->parent()->get_data (X_("timeselection"))) { - pair tvp = trackview_by_y_position (_last_motion_y); - if (dynamic_cast (tvp.first)) { - current_canvas_cursor = _cursors->up_down; - } - } - } - } - } - - set_canvas_cursor (current_canvas_cursor, true); -} - void Editor::mouse_mode_object_range_toggled() { @@ -499,7 +365,7 @@ Editor::mouse_mode_toggled (MouseMode m) } */ - set_canvas_cursor (); + reset_canvas_cursor (); set_gain_envelope_visibility (); update_time_selection_display (); @@ -1247,7 +1113,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT scrub_reverse_distance = 0; last_scrub_x = event->button.x; scrubbing_direction = 0; - set_canvas_cursor (_cursors->transparent); + push_canvas_cursor (_cursors->transparent); return true; break; @@ -1777,7 +1643,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT break; case MouseAudition: - set_canvas_cursor (current_canvas_cursor); + pop_canvas_cursor (); if (scrubbing_direction == 0) { /* no drag, just a click */ switch (item_type) { @@ -1858,6 +1724,15 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ 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 (&event->crossing, item_type); + switch (item_type) { case ControlPointItem: if (mouse_mode == MouseGain || mouse_mode == MouseObject) { @@ -1873,10 +1748,6 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ fraction = 1.0 - (cp->get_y() / cp->line().height()); - if (is_drawable() && !_drags->active ()) { - set_canvas_cursor (_cursors->fader); - } - _verbose_cursor->set (cp->line().get_verbose_cursor_string (fraction), at_x, at_y); _verbose_cursor->show (); } @@ -1888,9 +1759,6 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ if (line) { line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_EnteredGainLine()); } - if (is_drawable()) { - set_canvas_cursor (_cursors->fader); - } } break; @@ -1900,112 +1768,14 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ if (line) { line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_EnteredAutomationLine()); } - if (is_drawable()) { - set_canvas_cursor (_cursors->fader); - } } break; - case RegionViewNameHighlight: - if (is_drawable() && effective_mouse_mode() == MouseObject && entered_regionview) { - set_canvas_cursor_for_region_view (event->crossing.x, entered_regionview); - _over_region_trim_target = true; - } - break; - - case LeftFrameHandle: - case RightFrameHandle: - if (is_drawable() && effective_mouse_mode() == MouseObject && !internal_editing() && entered_regionview) { - set_canvas_cursor_for_region_view (event->crossing.x, entered_regionview); - } - break; - - case RegionItem: - switch (effective_mouse_mode()) { - case MouseRange: - set_canvas_cursor (_cursors->selector); - break; - default: - set_canvas_cursor (which_grabber_cursor()); - break; - } - break; - - case StartSelectionTrimItem: - if (is_drawable()) { - set_canvas_cursor (_cursors->left_side_trim); - } - break; - case EndSelectionTrimItem: - if (is_drawable()) { - set_canvas_cursor (_cursors->right_side_trim); - } - break; - - case PlayheadCursorItem: - if (is_drawable()) { - switch (_edit_point) { - case EditAtMouse: - set_canvas_cursor (_cursors->grabber_edit_point); - break; - default: - set_canvas_cursor (_cursors->grabber); - break; - } - } - break; - - - case RegionViewName: - - /* when the name is not an active item, the entire name highlight is for trimming */ - - if (!reinterpret_cast (item->get_data ("regionview"))->name_active()) { - if (mouse_mode == MouseObject && is_drawable()) { - set_canvas_cursor_for_region_view (event->crossing.x, entered_regionview); - _over_region_trim_target = true; - } - } - break; - - case AutomationTrackItem: - if (is_drawable()) { - Gdk::Cursor *cursor; - switch (mouse_mode) { - case MouseRange: - cursor = _cursors->selector; - break; - case MouseZoom: - cursor = _cursors->zoom_in; - break; - default: - cursor = _cursors->cross_hair; - break; - } - - set_canvas_cursor (cursor); - - AutomationTimeAxisView* atv; - if ((atv = static_cast(item->get_data ("trackview"))) != 0) { - clear_entered_track = false; - set_entered_track (atv); - } - } - break; - - case MarkerBarItem: - case RangeMarkerBarItem: - case TransportMarkerBarItem: - case CdMarkerBarItem: - case MeterBarItem: - case TempoBarItem: - case TimecodeRulerItem: - case SamplesRulerItem: - case MinsecRulerItem: - case BBTRulerItem: - if (is_drawable()) { - set_canvas_cursor (_cursors->timebar); + AutomationTimeAxisView* atv; + if ((atv = static_cast(item->get_data ("trackview"))) != 0) { + clear_entered_track = false; + set_entered_track (atv); } break; @@ -2018,9 +1788,6 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ // fall through case MeterMarkerItem: case TempoMarkerItem: - if (is_drawable()) { - set_canvas_cursor (_cursors->timebar); - } break; case FadeInHandleItem: @@ -2030,7 +1797,6 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ if (rect) { RegionView* rv = static_cast(item->get_data ("regionview")); rect->set_fill_color (rv->get_fill_color()); - set_canvas_cursor (_cursors->fade_in); } } break; @@ -2042,7 +1808,6 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ if (rect) { RegionView* rv = static_cast(item->get_data ("regionview")); rect->set_fill_color (rv->get_fill_color ()); - set_canvas_cursor (_cursors->fade_out); } } break; @@ -2055,16 +1820,13 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ break; case SelectionItem: - if ( get_smart_mode() ) { - set_canvas_cursor (); - } break; default: break; } - /* second pass to handle entered track status in a comprehensible way. + /* third pass to handle entered track status in a comprehensible way. */ switch (item_type) { @@ -2080,7 +1842,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ break; default: - set_entered_track (0); + break; } @@ -2098,27 +1860,9 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type) switch (item_type) { case ControlPointItem: - if (is_drawable()) { - set_canvas_cursor (current_canvas_cursor); - } - _verbose_cursor->hide (); break; - case RegionViewNameHighlight: - case LeftFrameHandle: - case RightFrameHandle: - case StartSelectionTrimItem: - case EndSelectionTrimItem: - case PlayheadCursorItem: - - _over_region_trim_target = false; - - if (is_drawable()) { - set_canvas_cursor (current_canvas_cursor); - } - break; - case GainLineItem: case AutomationLineItem: al = reinterpret_cast (item->get_data ("line")); @@ -2128,35 +1872,6 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type) line->set_outline_color (al->get_line_color()); } } - if (is_drawable()) { - set_canvas_cursor (current_canvas_cursor); - } - break; - - case RegionViewName: - /* see enter_handler() for notes */ - _over_region_trim_target = false; - - if (!reinterpret_cast (item->get_data ("regionview"))->name_active()) { - if (is_drawable() && mouse_mode == MouseObject) { - set_canvas_cursor (current_canvas_cursor); - } - } - break; - - case RangeMarkerBarItem: - case TransportMarkerBarItem: - case CdMarkerBarItem: - case MeterBarItem: - case TempoBarItem: - case MarkerBarItem: - case TimecodeRulerItem: - case SamplesRulerItem: - case MinsecRulerItem: - case BBTRulerItem: - if (is_drawable()) { - set_canvas_cursor (current_canvas_cursor); - } break; case MarkerItem: @@ -2170,39 +1885,29 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type) // fall through case MeterMarkerItem: case TempoMarkerItem: - - if (is_drawable()) { - set_canvas_cursor (current_canvas_cursor); - } - break; case FadeInTrimHandleItem: case FadeOutTrimHandleItem: case FadeInHandleItem: case FadeOutHandleItem: - { - ArdourCanvas::Rectangle *rect = dynamic_cast (item); - if (rect) { - rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_InactiveFadeHandle()); - } + { + ArdourCanvas::Rectangle *rect = dynamic_cast (item); + if (rect) { + rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_InactiveFadeHandle()); } - set_canvas_cursor (current_canvas_cursor); - break; + } + break; case AutomationTrackItem: - if (is_drawable()) { - set_canvas_cursor (current_canvas_cursor); - clear_entered_track = true; - Glib::signal_idle().connect (sigc::mem_fun(*this, &Editor::left_automation_track)); - } break; + case FeatureLineItem: - { - ArdourCanvas::Line *line = dynamic_cast (item); - line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_ZeroLine()); - } - break; + { + ArdourCanvas::Line *line = dynamic_cast (item); + line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_ZeroLine()); + } + break; default: break; @@ -2211,16 +1916,6 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type) return ret; } -gint -Editor::left_automation_track () -{ - if (clear_entered_track) { - set_entered_track (0); - clear_entered_track = false; - } - return false; -} - void Editor::scrub (framepos_t frame, double current_x) { @@ -2331,16 +2026,7 @@ Editor::motion_handler (ArdourCanvas::Item* /*item*/, GdkEvent* event, bool from return true; } - JoinObjectRangeState const old = _join_object_range_state; - update_join_object_range_location (event->motion.x, event->motion.y); - - if (!_internal_editing && _join_object_range_state != old) { - set_canvas_cursor (); - } - - if (!_internal_editing && _over_region_trim_target) { - set_canvas_cursor_for_region_view (event->motion.x, entered_regionview); - } + update_join_object_range_location (event->motion.y); bool handled = false; if (_drags->active ()) { @@ -2427,19 +2113,19 @@ Editor::edit_notes (TimeAxisViewItem& tavi) if (s.empty ()) { return; } - + EditNoteDialog* d = new EditNoteDialog (&(*s.begin())->region_view(), s); - d->show_all (); + d->show_all (); ensure_float (*d); - d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &Editor::note_edit_done), d)); + d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &Editor::note_edit_done), d)); } void Editor::note_edit_done (int r, EditNoteDialog* d) { - d->done (r); - delete d; + d->done (r); + delete d; } void @@ -2509,7 +2195,7 @@ Editor::collect_new_region_view (RegionView* rv) void Editor::collect_and_select_new_region_view (RegionView* rv) { - selection->add(rv); + selection->add(rv); latest_regionviews.push_back (rv); } @@ -2527,7 +2213,7 @@ Editor::cancel_selection () void Editor::cancel_time_selection () { - for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { + for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { (*i)->hide_selection (); } selection->time.clear (); @@ -2831,15 +2517,15 @@ Editor::set_internal_edit (bool yn) } _internal_editing = yn; - + if (yn) { - pre_internal_mouse_mode = mouse_mode; + pre_internal_mouse_mode = mouse_mode; pre_internal_snap_type = _snap_type; pre_internal_snap_mode = _snap_mode; - for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { - (*i)->enter_internal_edit_mode (); - } + for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { + (*i)->enter_internal_edit_mode (); + } set_snap_to (internal_snap_type); set_snap_mode (internal_snap_mode); @@ -2849,62 +2535,71 @@ Editor::set_internal_edit (bool yn) internal_snap_mode = _snap_mode; internal_snap_type = _snap_type; - for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { - (*i)->leave_internal_edit_mode (); - } + for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { + (*i)->leave_internal_edit_mode (); + } - if (mouse_mode == MouseDraw && pre_internal_mouse_mode != MouseDraw) { - /* we were drawing .. flip back to something sensible */ - set_mouse_mode (pre_internal_mouse_mode); - } + if (mouse_mode == MouseDraw && pre_internal_mouse_mode != MouseDraw) { + /* we were drawing .. flip back to something sensible */ + set_mouse_mode (pre_internal_mouse_mode); + } set_snap_to (pre_internal_snap_type); set_snap_mode (pre_internal_snap_mode); } - - set_canvas_cursor (); + + reset_canvas_cursor (); } -/** Update _join_object_range_state which indicate whether we are over the top or bottom half of a region view, - * used by the `join object/range' tool mode. Coordinates in canvas space. +/** Update _join_object_range_state which indicate whether we are over the top + * or bottom half of a route view, used by the `join object/range' tool + * mode. Coordinates in canvas space. */ void -Editor::update_join_object_range_location (double /*x*/, double y) +Editor::update_join_object_range_location (double y) { - /* XXX: actually, this decides based on whether the mouse is in the top - or bottom half of a the waveform part RouteTimeAxisView; - - Note that entered_{track,regionview} is not always setup (e.g. if - the mouse is over a TimeSelection), and to get a Region - that we're over requires searching the playlist. - */ - - if ( !get_smart_mode() ) { + if (_internal_editing || !get_smart_mode()) { _join_object_range_state = JOIN_OBJECT_RANGE_NONE; return; } + JoinObjectRangeState const old = _join_object_range_state; + if (mouse_mode == MouseObject) { _join_object_range_state = JOIN_OBJECT_RANGE_OBJECT; } else if (mouse_mode == MouseRange) { _join_object_range_state = JOIN_OBJECT_RANGE_RANGE; } - /* XXX: maybe we should make entered_track work in all cases, rather than resorting to this */ - pair tvp = trackview_by_y_position (y, false); + cerr << "Entered RV = " << entered_regionview << " track = " << entered_track << endl; - if (tvp.first) { + if (entered_regionview) { - RouteTimeAxisView* rtv = dynamic_cast (tvp.first); - if (rtv) { + ArdourCanvas::Duple const item_space = entered_regionview->get_canvas_group()->canvas_to_item (ArdourCanvas::Duple (0, y)); + double const c = item_space.y / entered_regionview->height(); + + _join_object_range_state = c <= 0.5 ? JOIN_OBJECT_RANGE_RANGE : JOIN_OBJECT_RANGE_OBJECT; + + if (_join_object_range_state != old) { + set_canvas_cursor (which_region_cursor ()); + } - double cx = 0; - double cy = y; - rtv->canvas_display()->canvas_to_item (cx, cy); + } else if (entered_track) { - double const c = cy / (rtv->view()->child_height() - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE); - - _join_object_range_state = c <= 0.5 ? JOIN_OBJECT_RANGE_RANGE : JOIN_OBJECT_RANGE_OBJECT; + RouteTimeAxisView* entered_route_view = dynamic_cast (entered_track); + + if (entered_route_view) { + /* track/bus ... but not in a region ... use range mode */ + _join_object_range_state = JOIN_OBJECT_RANGE_RANGE; + if (_join_object_range_state != old) { + set_canvas_cursor (which_region_cursor ()); + } + } else { + /* Other kinds of tracks use object mode */ + _join_object_range_state = JOIN_OBJECT_RANGE_OBJECT; + if (_join_object_range_state != old) { + set_canvas_cursor (which_region_cursor ()); + } } } } @@ -2930,51 +2625,6 @@ Editor::remove_midi_note (ArdourCanvas::Item* item, GdkEvent *) e->region_view().delete_note (e->note ()); } -void -Editor::set_canvas_cursor_for_region_view (double x, RegionView* rv) -{ - /* XXX: this check should not be necessary */ - if (rv == 0) { - return; - } - - ArdourCanvas::Group* g = rv->get_canvas_group (); - ArdourCanvas::Group* p = g->parent (); - - /* Compute x in region view parent coordinates */ - double dy = 0; - p->canvas_to_item (x, dy); - - boost::optional item_bbox = g->bounding_box (); - assert (item_bbox); - ArdourCanvas::Rect parent_bbox = g->item_to_parent (item_bbox.get ()); - - /* First or last 10% of region is used for trimming, if the whole - region is wider than 20 pixels at the current zoom level. - */ - - double const w = parent_bbox.width(); - - if (w > 20.0 && x >= parent_bbox.x0 && x < parent_bbox.x1) { - - Trimmable::CanTrim ct = rv->region()->can_trim (); - - if (((x - parent_bbox.x0) / w) < 0.10) { - if (ct & Trimmable::FrontTrimEarlier) { - set_canvas_cursor (_cursors->left_side_trim, true); - } else { - set_canvas_cursor (_cursors->left_side_trim_right_only, true); - } - } else if (((parent_bbox.x1 - x) / w) < 0.10) { - if (ct & Trimmable::EndTrimLater) { - set_canvas_cursor (_cursors->right_side_trim, true); - } else { - set_canvas_cursor (_cursors->right_side_trim_left_only, true); - } - } - } -} - /** Obtain the pointer position in canvas coordinates */ void Editor::get_pointer_position (double& x, double& y) const diff --git a/gtk2_ardour/enums.cc b/gtk2_ardour/enums.cc index 867a21dde2..d2f0f23284 100644 --- a/gtk2_ardour/enums.cc +++ b/gtk2_ardour/enums.cc @@ -135,6 +135,7 @@ setup_gtk_ardour_enums () REGISTER (zoom_focus); REGISTER_ENUM (RegionItem); + REGISTER_ENUM (WaveItem); REGISTER_ENUM (StreamItem); REGISTER_ENUM (PlayheadCursorItem); REGISTER_ENUM (MarkerItem); diff --git a/gtk2_ardour/public_editor.h b/gtk2_ardour/public_editor.h index af66415a65..a0f5e74ef9 100644 --- a/gtk2_ardour/public_editor.h +++ b/gtk2_ardour/public_editor.h @@ -331,6 +331,7 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulDestructible, publi virtual bool canvas_fade_out_event (GdkEvent* event, ArdourCanvas::Item*, AudioRegionView*) = 0; virtual bool canvas_fade_out_handle_event (GdkEvent* event, ArdourCanvas::Item*, AudioRegionView*, bool) = 0; virtual bool canvas_region_view_event (GdkEvent* event, ArdourCanvas::Item*, RegionView*) = 0; + virtual bool canvas_wave_view_event (GdkEvent* event, ArdourCanvas::Item*, RegionView*) = 0; virtual bool canvas_frame_handle_event (GdkEvent* event, ArdourCanvas::Item*, RegionView*) = 0; virtual bool canvas_region_view_name_highlight_event (GdkEvent* event, ArdourCanvas::Item*, RegionView*) = 0; virtual bool canvas_region_view_name_event (GdkEvent* event, ArdourCanvas::Item*, RegionView*) = 0; diff --git a/gtk2_ardour/time_axis_view_item.h b/gtk2_ardour/time_axis_view_item.h index 3536baa222..04072d1a8e 100644 --- a/gtk2_ardour/time_axis_view_item.h +++ b/gtk2_ardour/time_axis_view_item.h @@ -71,6 +71,7 @@ class TimeAxisViewItem : public Selectable, public PBD::ScopedConnectionList TimeAxisView& get_time_axis_view () const; void set_name_text(const std::string&); virtual void set_height(double h); + virtual double height() const { return _height; } void set_y (double); void set_color (uint32_t); void set_name_text_color (); diff --git a/libs/canvas/canvas.cc b/libs/canvas/canvas.cc index 3d4f9e0c5d..574304e7dd 100644 --- a/libs/canvas/canvas.cc +++ b/libs/canvas/canvas.cc @@ -487,7 +487,6 @@ GtkCanvas::deliver_enter_leave (Duple const & point, int state) enter_detail = GDK_NOTIFY_INFERIOR; leave_detail = GDK_NOTIFY_ANCESTOR; - } else if (_new_current_item->is_descendant_of (*_current_item)) { /* move from ancestor to descendant (X: "_new_current_item is * an inferior ("child") of _current_item")