diff options
Diffstat (limited to 'gtk2_ardour/editor_mouse.cc')
-rw-r--r-- | gtk2_ardour/editor_mouse.cc | 572 |
1 files changed, 312 insertions, 260 deletions
diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index e20bd86384..928801d0b2 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -24,6 +24,7 @@ #include <set> #include <string> #include <algorithm> +#include <bitset> #include "pbd/error.h" #include "pbd/enumwriter.h" @@ -35,9 +36,19 @@ #include "gtkmm2ext/utils.h" #include "gtkmm2ext/tearoff.h" +#include "canvas/canvas.h" + +#include "ardour/audioregion.h" +#include "ardour/operations.h" +#include "ardour/playlist.h" +#include "ardour/profile.h" +#include "ardour/region_factory.h" +#include "ardour/route.h" +#include "ardour/session.h" +#include "ardour/types.h" + #include "ardour_ui.h" #include "actions.h" -#include "canvas-note.h" #include "editor.h" #include "time_axis_view.h" #include "audio_time_axis.h" @@ -61,17 +72,7 @@ #include "mouse_cursors.h" #include "editor_cursors.h" #include "verbose_cursor.h" - -#include "ardour/audioregion.h" -#include "ardour/operations.h" -#include "ardour/playlist.h" -#include "ardour/profile.h" -#include "ardour/region_factory.h" -#include "ardour/route.h" -#include "ardour/session.h" -#include "ardour/types.h" - -#include <bitset> +#include "note.h" #include "i18n.h" @@ -101,84 +102,89 @@ Editor::mouse_frame (framepos_t& where, bool& in_track_canvas) const } int x, y; - double wx, wy; - Gdk::ModifierType mask; - Glib::RefPtr<Gdk::Window> canvas_window = const_cast<Editor*>(this)->track_canvas->get_window(); - Glib::RefPtr<const Gdk::Window> pointer_window; + Glib::RefPtr<Gdk::Window> canvas_window = const_cast<Editor*>(this)->_track_canvas->get_window(); if (!canvas_window) { return false; } - pointer_window = canvas_window->get_pointer (x, y, mask); + Glib::RefPtr<const Gdk::Window> pointer_window = Gdk::Display::get_default()->get_window_at_pointer (x, y); - if (pointer_window == track_canvas->get_bin_window()) { - wx = x; - wy = y; - in_track_canvas = true; + if (!pointer_window) { + return false; + } - } else { + if (pointer_window != canvas_window && pointer_window != _time_bars_canvas->get_window()) { in_track_canvas = false; - return false; + return false; } + in_track_canvas = true; + GdkEvent event; event.type = GDK_BUTTON_RELEASE; - event.button.x = wx; - event.button.y = wy; + event.button.x = x; + event.button.y = y; + + where = window_event_sample (&event, 0, 0); - where = event_frame (&event, 0, 0); return true; } framepos_t -Editor::event_frame (GdkEvent const * event, double* pcx, double* pcy) const +Editor::window_event_sample (GdkEvent const * event, double* pcx, double* pcy) const { - double cx, cy; + double x; + double y; - if (pcx == 0) { - pcx = &cx; + if (!gdk_event_get_coords (event, &x, &y)) { + return 0; } - if (pcy == 0) { - pcy = &cy; + + /* event coordinates are in window units, so convert to canvas + * (i.e. account for scrolling) + */ + + ArdourCanvas::Duple d = _track_canvas->window_to_canvas (ArdourCanvas::Duple (x, y)); + + if (pcx) { + *pcx = d.x; } - *pcx = 0; - *pcy = 0; + if (pcy) { + *pcy = d.y; + } - switch (event->type) { - case GDK_BUTTON_RELEASE: - case GDK_BUTTON_PRESS: - case GDK_2BUTTON_PRESS: - case GDK_3BUTTON_PRESS: - *pcx = event->button.x; - *pcy = event->button.y; - _trackview_group->w2i(*pcx, *pcy); - break; - case GDK_MOTION_NOTIFY: - *pcx = event->motion.x; - *pcy = event->motion.y; - _trackview_group->w2i(*pcx, *pcy); - break; - case GDK_ENTER_NOTIFY: - case GDK_LEAVE_NOTIFY: - track_canvas->w2c(event->crossing.x, event->crossing.y, *pcx, *pcy); - break; - case GDK_KEY_PRESS: - case GDK_KEY_RELEASE: - // track_canvas->w2c(event->key.x, event->key.y, *pcx, *pcy); - break; - default: - warning << string_compose (_("Editor::event_frame() used on unhandled event type %1"), event->type) << endmsg; - break; + return pixel_to_sample (d.x); +} + +framepos_t +Editor::canvas_event_sample (GdkEvent const * event, double* pcx, double* pcy) const +{ + double x; + double y; + + /* event coordinates are already in canvas units */ + + if (!gdk_event_get_coords (event, &x, &y)) { + cerr << "!NO c COORDS for event type " << event->type << endl; + return 0; + } + + if (pcx) { + *pcx = x; } - /* note that pixel_to_frame() never returns less than zero, so even if the pixel + if (pcy) { + *pcy = y; + } + + /* note that pixel_to_sample_from_event() never returns less than zero, so even if the pixel position is negative (as can be the case with motion events in particular), the frame location is always positive. */ - return pixel_to_frame (*pcx); + return pixel_to_sample_from_event (x); } Gdk::Cursor* @@ -303,13 +309,27 @@ Editor::set_canvas_cursor () /* 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); - ArdourCanvas::Item* i = track_canvas->get_item_at (x, y); - if (i && i->property_parent() && (*i->property_parent()).get_data (X_("timeselection"))) { - pair<TimeAxisView*, int> tvp = trackview_by_y_position (_last_motion_y + vertical_adjustment.get_value() - canvas_timebars_vsize); - if (dynamic_cast<AutomationTimeAxisView*> (tvp.first)) { - current_canvas_cursor = _cursors->up_down; + + if (x >= 0 && y >= 0) { + + vector<ArdourCanvas::Item const *> items; + + _track_canvas->root()->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<TimeAxisView*, int> tvp = trackview_by_y_position (_last_motion_y); + if (dynamic_cast<AutomationTimeAxisView*> (tvp.first)) { + current_canvas_cursor = _cursors->up_down; + } + } } } } @@ -326,9 +346,11 @@ Editor::mouse_mode_object_range_toggled() assert (act); Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act); assert (tact); - if (tact->get_active()) + + if (tact->get_active()) { m = MouseObject; //Smart mode turned to ON, force editing to Object mode - + } + set_mouse_mode(m, true); //call this so the button styles can get updated } @@ -477,11 +499,33 @@ Editor::mouse_mode_toggled (MouseMode m) set_canvas_cursor (); set_gain_envelope_visibility (); + + update_time_selection_display (); MouseModeChanged (); /* EMIT SIGNAL */ } void +Editor::update_time_selection_display () +{ + if (smart_mode_action->get_active()) { + /* not sure what to do here */ + if (mouse_mode == MouseObject) { + } else { + } + } else { + switch (mouse_mode) { + case MouseRange: + selection->clear_objects (); + break; + default: + selection->clear_time (); + break; + } + } +} + +void Editor::step_mouse_mode (bool next) { switch (current_mouse_mode()) { @@ -579,6 +623,15 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp to cut notes or regions. */ + MouseMode eff_mouse_mode = mouse_mode; + + if (get_smart_mode() && eff_mouse_mode == MouseRange && event->button.button == 3 && item_type == RegionItem) { + /* context clicks are always about object properties, even if + we're in range mode within smart mode. + */ + eff_mouse_mode = MouseObject; + } + if (((mouse_mode != MouseObject) && (mouse_mode != MouseAudition || item_type != RegionItem) && (mouse_mode != MouseTimeFX || item_type != RegionItem) && @@ -607,25 +660,23 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp switch (item_type) { case RegionItem: - if (!get_smart_mode() || (_join_object_range_state != JOIN_OBJECT_RANGE_RANGE)) { - if (press) { - if (mouse_mode != MouseRange) { - set_selected_regionview_from_click (press, op); - } else { - /* don't change the selection unless the - clicked track is not currently selected. if - so, "collapse" the selection to just this - track - */ - if (!selection->selected (clicked_axisview)) { - set_selected_track_as_side_effect (Selection::Set); - } - } + if (press) { + if (eff_mouse_mode != MouseRange) { + set_selected_regionview_from_click (press, op); } else { - if (mouse_mode != MouseRange) { - set_selected_regionview_from_click (press, op); + /* don't change the selection unless the + clicked track is not currently selected. if + so, "collapse" the selection to just this + track + */ + if (!selection->selected (clicked_axisview)) { + set_selected_track_as_side_effect (Selection::Set); } } + } else { + if (eff_mouse_mode != MouseRange) { + set_selected_regionview_from_click (press, op); + } } break; @@ -633,7 +684,7 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp case RegionViewName: case LeftFrameHandle: case RightFrameHandle: - if ( mouse_mode != MouseRange ) { + if (eff_mouse_mode != MouseRange) { set_selected_regionview_from_click (press, op); } else if (event->type == GDK_BUTTON_PRESS) { set_selected_track_as_side_effect (op); @@ -646,7 +697,8 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp case FadeOutItem: case StartCrossFadeItem: case EndCrossFadeItem: - if ( mouse_mode != MouseRange ) { + if (eff_mouse_mode != MouseRange) { + cerr << "Should be setting selected regionview\n"; set_selected_regionview_from_click (press, op); } else if (event->type == GDK_BUTTON_PRESS) { set_selected_track_as_side_effect (op); @@ -655,7 +707,7 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp case ControlPointItem: set_selected_track_as_side_effect (op); - if ( mouse_mode != MouseRange ) { + if (eff_mouse_mode != MouseRange) { set_selected_control_point_from_click (press, op); } break; @@ -688,7 +740,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT switch (item_type) { case PlayheadCursorItem: - _drags->set (new CursorDrag (this, item, true), event); + _drags->set (new CursorDrag (this, *playhead_cursor, true), event); return true; case MarkerItem: @@ -703,38 +755,30 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT { TempoMarker* m = reinterpret_cast<TempoMarker*> (item->get_data ("marker")); assert (m); - if (m->tempo().movable ()) { - _drags->set ( - new TempoMarkerDrag ( - this, - item, - Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier) - ), - event - ); - return true; - } else { - return false; - } + _drags->set ( + new TempoMarkerDrag ( + this, + item, + Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier) + ), + event + ); + return true; } case MeterMarkerItem: { MeterMarker* m = reinterpret_cast<MeterMarker*> (item->get_data ("marker")); assert (m); - if (m->meter().movable ()) { - _drags->set ( - new MeterMarkerDrag ( - this, - item, - Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier) - ), - event - ); - return true; - } else { - return false; - } + _drags->set ( + new MeterMarkerDrag ( + this, + item, + Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier) + ), + event + ); + return true; } case VideoBarItem: @@ -746,7 +790,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT case TempoBarItem: case MeterBarItem: if (!Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) { - _drags->set (new CursorDrag (this, &playhead_cursor->canvas_item, false), event); + _drags->set (new CursorDrag (this, *playhead_cursor, false), event); } return true; break; @@ -754,7 +798,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT case RangeMarkerBarItem: if (!Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) { - _drags->set (new CursorDrag (this, &playhead_cursor->canvas_item, false), event); + _drags->set (new CursorDrag (this, *playhead_cursor, false), event); } else { _drags->set (new RangeMarkerBarDrag (this, item, RangeMarkerBarDrag::CreateRangeMarker), event); } @@ -763,7 +807,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT case CdMarkerBarItem: if (!Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) { - _drags->set (new CursorDrag (this, &playhead_cursor->canvas_item, false), event); + _drags->set (new CursorDrag (this, *playhead_cursor, false), event); } else { _drags->set (new RangeMarkerBarDrag (this, item, RangeMarkerBarDrag::CreateCDMarker), event); } @@ -772,7 +816,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT case TransportMarkerBarItem: if (!Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) { - _drags->set (new CursorDrag (this, &playhead_cursor->canvas_item, false), event); + _drags->set (new CursorDrag (this, *playhead_cursor, false), event); } else { _drags->set (new RangeMarkerBarDrag (this, item, RangeMarkerBarDrag::CreateTransportMarker), event); } @@ -823,11 +867,12 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT case SelectionItem: if (Keyboard::modifier_state_contains (event->button.state, Keyboard::ModifierMask(Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) { start_selection_grab (item, event); + return true; } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::SecondaryModifier)) { /* grab selection for moving */ _drags->set (new SelectionDrag (this, item, SelectionDrag::SelectionMove), event); } else { - double const y = event->button.y + vertical_adjustment.get_value() - canvas_timebars_vsize; + double const y = event->button.y; pair<TimeAxisView*, int> tvp = trackview_by_y_position (y); if (tvp.first) { AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*> (tvp.first); @@ -881,16 +926,18 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT case MouseDraw: switch (item_type) { case NoteItem: + /* Existing note: allow trimming/motion */ if (internal_editing()) { /* trim notes if we're in internal edit mode and near the ends of the note */ - ArdourCanvas::CanvasNote* cn = dynamic_cast<ArdourCanvas::CanvasNote*> (item); - if (cn && cn->big_enough_to_trim() && cn->mouse_near_ends()) { + NoteBase* cn = reinterpret_cast<NoteBase*>(item->get_data ("notebase")); + assert (cn); + if (cn->big_enough_to_trim() && cn->mouse_near_ends()) { _drags->set (new NoteResizeDrag (this, item), event, current_canvas_cursor); } else { _drags->set (new NoteDrag (this, item), event); } return true; - } + } break; case StreamItem: if (internal_editing()) { @@ -909,9 +956,11 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT case MouseObject: switch (item_type) { case NoteItem: + /* Existing note: allow trimming/motion */ if (internal_editing()) { - ArdourCanvas::CanvasNoteEvent* cn = dynamic_cast<ArdourCanvas::CanvasNoteEvent*> (item); - if (cn->mouse_near_ends()) { + NoteBase* cn = reinterpret_cast<NoteBase*> (item->get_data ("notebase")); + assert (cn); + if (cn->big_enough_to_trim() && cn->mouse_near_ends()) { _drags->set (new NoteResizeDrag (this, item), event, current_canvas_cursor); } else { _drags->set (new NoteDrag (this, item), event); @@ -992,6 +1041,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT // } _drags->start_grab (event); + return true; break; case RegionViewNameHighlight: @@ -1047,7 +1097,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT _drags->set (new RegionCreateDrag (this, item, parent), event); } else { /* See if there's a region before the click that we can extend, and extend it if so */ - framepos_t const t = event_frame (event); + framepos_t const t = canvas_event_sample (event); boost::shared_ptr<Region> prev = pl->find_next_region (t, End, -1); if (!prev) { _drags->set (new RegionCreateDrag (this, item, parent), event); @@ -1066,7 +1116,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT { if ( get_smart_mode() ) { /* we're in "smart" joined mode, and we've clicked on a Selection */ - double const y = event->button.y + vertical_adjustment.get_value() - canvas_timebars_vsize; + double const y = event->button.y; pair<TimeAxisView*, int> tvp = trackview_by_y_position (y); if (tvp.first) { /* if we're over an automation track, start a drag of its data */ @@ -1085,7 +1135,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT boost::shared_ptr<Playlist> pl = t->playlist (); if (pl) { - boost::shared_ptr<Region> r = pl->top_region_at (event_frame (event)); + boost::shared_ptr<Region> r = pl->top_region_at (canvas_event_sample (event)); if (r) { RegionView* rv = rtv->view()->find_view (r); clicked_selection = select_range (rv->region()->position(), @@ -1095,6 +1145,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT rvs.push_back (rv); _drags->add (new RegionMoveDrag (this, item, rv, rvs, false, false)); _drags->start_grab (event); + return true; } } } @@ -1157,9 +1208,13 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT break; case MouseTimeFX: - if (internal_editing() && item_type == NoteItem) { + if (internal_editing() && item_type == NoteItem ) { /* drag notes if we're in internal edit mode */ - _drags->set (new NoteResizeDrag (this, item), event, current_canvas_cursor); + NoteBase* cn = reinterpret_cast<NoteBase*>(item->get_data ("notebase")); + assert (cn); + if (cn->big_enough_to_trim()) { + _drags->set (new NoteResizeDrag (this, item), event, current_canvas_cursor); + } return true; } else if (clicked_regionview) { /* do time-FX */ @@ -1251,9 +1306,9 @@ Editor::button_press_handler_2 (ArdourCanvas::Item* item, GdkEvent* event, ItemT case MouseZoom: if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) { - temporal_zoom_to_frame (false, event_frame (event)); + temporal_zoom_to_frame (false, canvas_event_sample (event)); } else { - temporal_zoom_to_frame (true, event_frame(event)); + temporal_zoom_to_frame (true, canvas_event_sample(event)); } return true; break; @@ -1268,15 +1323,17 @@ Editor::button_press_handler_2 (ArdourCanvas::Item* item, GdkEvent* event, ItemT bool Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type) { + if (event->type == GDK_2BUTTON_PRESS) { + _drags->mark_double_click (); + gdk_pointer_ungrab (GDK_CURRENT_TIME); + return true; + } + if (event->type != GDK_BUTTON_PRESS) { - if (event->type == GDK_2BUTTON_PRESS) { - gdk_pointer_ungrab (GDK_CURRENT_TIME); - return button_double_click_handler (item, event, item_type); - } return false; } - Glib::RefPtr<Gdk::Window> canvas_window = const_cast<Editor*>(this)->track_canvas->get_window(); + Glib::RefPtr<Gdk::Window> canvas_window = const_cast<Editor*>(this)->_track_canvas_viewport->get_window(); if (canvas_window) { Glib::RefPtr<const Gdk::Window> pointer_window; @@ -1286,14 +1343,14 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp pointer_window = canvas_window->get_pointer (x, y, mask); - if (pointer_window == track_canvas->get_bin_window()) { - track_canvas->window_to_world (x, y, wx, wy); + if (pointer_window == _track_canvas->get_window()) { + _track_canvas->window_to_canvas (x, y, wx, wy); } } pre_press_cursor = current_canvas_cursor; - - track_canvas->grab_focus(); + + _track_canvas->grab_focus(); if (_session && _session->actively_recording()) { return true; @@ -1350,7 +1407,7 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp //not rolling, range mode click + join_play_range : locate the PH here if ( !_drags->active () && !_session->transport_rolling() && ( effective_mouse_mode() == MouseRange ) && Config->get_always_play_range() ) { - framepos_t where = event_frame (event, 0, 0); + framepos_t where = canvas_event_sample (event); snap_to(where); _session->request_locate (where, false); } @@ -1397,55 +1454,9 @@ Editor::button_release_dispatch (GdkEventButton* ev) } bool -Editor::button_double_click_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type) { - - if (event->button.button != 1) { - return false; - } - - switch (item_type) { - case RegionItem: - RegionView *rv; - rv = clicked_regionview; - rv->show_region_editor (); - return true; - case NoteItem: - case PlayheadCursorItem: - break; - case MarkerItem: - case RangeMarkerBarItem: - case CdMarkerBarItem: - Marker* marker; - if ((marker = static_cast<Marker *> (item->get_data ("marker"))) == 0) { - break; - } - rename_marker (marker); - return true; - case TempoMarkerItem: - edit_tempo_marker (item); - return true; - case MeterMarkerItem: - edit_meter_marker (item); - return true; - case MarkerBarItem: - case TempoBarItem: - case MeterBarItem: - case TransportMarkerBarItem: - case StreamItem: - break; - - default: - break; - } - return false; -} - - - -bool Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type) { - framepos_t where = event_frame (event, 0, 0); + framepos_t where = canvas_event_sample (event); AutomationTimeAxisView* atv = 0; if (pre_press_cursor) { @@ -1472,7 +1483,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT were_dragging = true; } - update_region_layering_order_editor (); + update_region_layering_order_editor (); /* edit events get handled here */ @@ -1482,13 +1493,40 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT show_region_properties (); break; - case TempoMarkerItem: - edit_tempo_marker (item); + case TempoMarkerItem: { + Marker* marker; + TempoMarker* tempo_marker; + + if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) { + fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg; + /*NOTREACHED*/ + } + + if ((tempo_marker = dynamic_cast<TempoMarker*> (marker)) == 0) { + fatal << _("programming error: marker for tempo is not a tempo marker!") << endmsg; + /*NOTREACHED*/ + } + + edit_tempo_marker (*tempo_marker); break; + } - case MeterMarkerItem: - edit_meter_marker (item); + case MeterMarkerItem: { + Marker* marker; + MeterMarker* meter_marker; + + if ((marker = reinterpret_cast<Marker *> (item->get_data ("marker"))) == 0) { + fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg; + /*NOTREACHED*/ + } + + if ((meter_marker = dynamic_cast<MeterMarker*> (marker)) == 0) { + fatal << _("programming error: marker for meter is not a meter marker!") << endmsg; + /*NOTREACHED*/ + } + edit_meter_marker (*meter_marker); break; + } case RegionViewName: if (clicked_regionview->name_active()) { @@ -1667,7 +1705,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT case MeterBarItem: if (!_dragging_playhead) { - mouse_add_new_meter_event (pixel_to_frame (event->button.x)); + mouse_add_new_meter_event (pixel_to_sample (event->button.x)); } return true; break; @@ -1807,7 +1845,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ case ControlPointItem: if (mouse_mode == MouseGain || mouse_mode == MouseObject) { cp = static_cast<ControlPoint*>(item->get_data ("control_point")); - cp->set_visible (true); + cp->show (); double at_x, at_y; at_x = cp->get_x(); @@ -1830,8 +1868,9 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ case GainLineItem: if (mouse_mode == MouseGain) { ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item); - if (line) - line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_EnteredGainLine.get(); + if (line) { + line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_EnteredGainLine()); + } if (is_drawable()) { set_canvas_cursor (_cursors->fader); } @@ -1842,7 +1881,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ if (mouse_mode == MouseGain || mouse_mode == MouseObject) { ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item); if (line) { - line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_EnteredAutomationLine.get(); + line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_EnteredAutomationLine()); } if (is_drawable()) { set_canvas_cursor (_cursors->fader); @@ -1864,6 +1903,17 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ } 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); @@ -1888,6 +1938,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ } break; + case RegionViewName: /* when the name is not an active item, the entire name highlight is for trimming */ @@ -1942,7 +1993,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ break; } entered_marker = marker; - marker->set_color_rgba (ARDOUR_UI::config()->canvasvar_EnteredMarker.get()); + marker->set_color_rgba (ARDOUR_UI::config()->get_canvasvar_EnteredMarker()); // fall through case MeterMarkerItem: case TempoMarkerItem: @@ -1953,29 +2004,32 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ case FadeInHandleItem: if (mouse_mode == MouseObject && !internal_editing()) { - ArdourCanvas::SimpleRect *rect = dynamic_cast<ArdourCanvas::SimpleRect *> (item); + ArdourCanvas::Rectangle *rect = dynamic_cast<ArdourCanvas::Rectangle *> (item); if (rect) { - rect->property_fill_color_rgba() = 0xBBBBBBAA; + RegionView* rv = static_cast<RegionView*>(item->get_data ("regionview")); + rect->set_fill_color (rv->get_fill_color()); + set_canvas_cursor (_cursors->fade_in); } - set_canvas_cursor (_cursors->fade_in); } break; case FadeOutHandleItem: if (mouse_mode == MouseObject && !internal_editing()) { - ArdourCanvas::SimpleRect *rect = dynamic_cast<ArdourCanvas::SimpleRect *> (item); + ArdourCanvas::Rectangle *rect = dynamic_cast<ArdourCanvas::Rectangle *> (item); if (rect) { - rect->property_fill_color_rgba() = 0xBBBBBBAA; + RegionView* rv = static_cast<RegionView*>(item->get_data ("regionview")); + rect->set_fill_color (rv->get_fill_color ()); + set_canvas_cursor (_cursors->fade_out); } - set_canvas_cursor (_cursors->fade_out); } break; case FeatureLineItem: - { - ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item); - line->property_fill_color_rgba() = 0xFF0000FF; - } - break; + { + ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item); + line->set_outline_color (0xFF0000FF); + } + break; + case SelectionItem: if ( get_smart_mode() ) { set_canvas_cursor (); @@ -2013,7 +2067,6 @@ bool Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type) { AutomationLine* al; - ControlPoint* cp; Marker *marker; Location *loc; RegionView* rv; @@ -2022,13 +2075,6 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type) switch (item_type) { case ControlPointItem: - cp = reinterpret_cast<ControlPoint*>(item->get_data ("control_point")); - if (cp->line().the_list()->interpolation() != AutomationList::Discrete) { - if (cp->line().npoints() > 1 && !cp->get_selected()) { - cp->set_visible (false); - } - } - if (is_drawable()) { set_canvas_cursor (current_canvas_cursor); } @@ -2055,8 +2101,9 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type) al = reinterpret_cast<AutomationLine*> (item->get_data ("line")); { ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item); - if (line) - line->property_fill_color_rgba() = al->get_line_color(); + if (line) { + line->set_outline_color (al->get_line_color()); + } } if (is_drawable()) { set_canvas_cursor (current_canvas_cursor); @@ -2107,9 +2154,9 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type) case FadeOutHandleItem: rv = static_cast<RegionView*>(item->get_data ("regionview")); { - ArdourCanvas::SimpleRect *rect = dynamic_cast<ArdourCanvas::SimpleRect *> (item); + ArdourCanvas::Rectangle *rect = dynamic_cast<ArdourCanvas::Rectangle *> (item); if (rect) { - rect->property_fill_color_rgba() = rv->get_fill_color(); + rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_InactiveFadeHandle()); } } set_canvas_cursor (current_canvas_cursor); @@ -2125,7 +2172,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type) case FeatureLineItem: { ArdourCanvas::Line *line = dynamic_cast<ArdourCanvas::Line *> (item); - line->property_fill_color_rgba() = (guint) ARDOUR_UI::config()->canvasvar_ZeroLine.get();; + line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_ZeroLine()); } break; @@ -2242,7 +2289,7 @@ Editor::motion_handler (ArdourCanvas::Item* /*item*/, GdkEvent* event, bool from event might do, its a good tradeoff. */ - track_canvas->get_pointer (x, y); + _track_canvas->get_pointer (x, y); } if (current_stepping_trackview) { @@ -2541,14 +2588,11 @@ Editor::hide_marker (ArdourCanvas::Item* item, GdkEvent* /*event*/) void Editor::reposition_zoom_rect (framepos_t start, framepos_t end) { - double x1 = frame_to_pixel (start); - double x2 = frame_to_pixel (end); - double y2 = full_canvas_height - 1.0; - - zoom_rect->property_x1() = x1; - zoom_rect->property_y1() = 1.0; - zoom_rect->property_x2() = x2; - zoom_rect->property_y2() = y2; + double x1 = sample_to_pixel (start); + double x2 = sample_to_pixel (end); + double y2 = _full_canvas_height - 1.0; + + zoom_rect->set (ArdourCanvas::Rect (x1, 1.0, x2, y2)); } @@ -2648,9 +2692,6 @@ Editor::add_region_drag (ArdourCanvas::Item* item, GdkEvent*, RegionView* region } else { _drags->add (new RegionMoveDrag (this, item, region_view, selection->regions.by_layer(), false, false)); } - - /* sync the canvas to what we think is its current state */ - update_canvas_now(); } void @@ -2826,7 +2867,7 @@ Editor::update_join_object_range_location (double /*x*/, double y) } /* XXX: maybe we should make entered_track work in all cases, rather than resorting to this */ - pair<TimeAxisView*, int> tvp = trackview_by_y_position (y + vertical_adjustment.get_value() - canvas_timebars_vsize); + pair<TimeAxisView*, int> tvp = trackview_by_y_position (y); if (tvp.first) { @@ -2835,7 +2876,7 @@ Editor::update_join_object_range_location (double /*x*/, double y) double cx = 0; double cy = y; - rtv->canvas_display()->w2i (cx, cy); + rtv->canvas_display()->canvas_to_item (cx, cy); double const c = cy / (rtv->view()->child_height() - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE); @@ -2859,7 +2900,7 @@ Editor::effective_mouse_mode () const void Editor::remove_midi_note (ArdourCanvas::Item* item, GdkEvent *) { - ArdourCanvas::CanvasNoteEvent* e = dynamic_cast<ArdourCanvas::CanvasNoteEvent*> (item); + NoteBase* e = reinterpret_cast<NoteBase*> (item->get_data ("notebase")); assert (e); e->region_view().delete_note (e->note ()); @@ -2868,42 +2909,53 @@ Editor::remove_midi_note (ArdourCanvas::Item* item, GdkEvent *) void Editor::set_canvas_cursor_for_region_view (double x, RegionView* rv) { - assert (rv); + /* XXX: this check should not be necessary */ + if (rv == 0) { + return; + } ArdourCanvas::Group* g = rv->get_canvas_group (); - ArdourCanvas::Group* p = g->get_parent_group (); + ArdourCanvas::Group* p = g->parent (); /* Compute x in region view parent coordinates */ double dy = 0; - p->w2i (x, dy); + p->canvas_to_item (x, dy); - double x1, x2, y1, y2; - g->get_bounds (x1, y1, x2, y2); + boost::optional<ArdourCanvas::Rect> item_bbox = g->bounding_box (); + assert (item_bbox); + ArdourCanvas::Rect parent_bbox = g->item_to_parent (item_bbox.get ()); - /* Halfway across the region */ - double const h = (x1 + x2) / 2; + /* First or last 10% of region is used for trimming, if the whole + region is wider than 20 pixels at the current zoom level. + */ - Trimmable::CanTrim ct = rv->region()->can_trim (); - if (x <= h) { - if (ct & Trimmable::FrontTrimEarlier) { - set_canvas_cursor (_cursors->left_side_trim); - } else { - set_canvas_cursor (_cursors->left_side_trim_right_only); - } - } else { - if (ct & Trimmable::EndTrimLater) { - set_canvas_cursor (_cursors->right_side_trim); - } else { - set_canvas_cursor (_cursors->right_side_trim_left_only); + 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 world coordinates */ +/** Obtain the pointer position in canvas coordinates */ void Editor::get_pointer_position (double& x, double& y) const { int px, py; - track_canvas->get_pointer (px, py); - track_canvas->window_to_world (px, py, x, y); + _track_canvas->get_pointer (px, py); + _track_canvas->window_to_canvas (px, py, x, y); } |