X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor_mouse.cc;h=8e1ef327ab745ea310b1f4dcbf5dc5cc28b52dff;hb=71003b02353ea090902bdd5623d42da141fa25ad;hp=b2ee2777cfea9845f34853fa41a7eef478f76f88;hpb=75b933eadbe8f90a73a29bb207ff26eebcd4121a;p=ardour.git diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index b2ee2777cf..8e1ef327ab 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -34,7 +34,6 @@ #include "gtkmm2ext/bindings.h" #include "gtkmm2ext/utils.h" -#include "gtkmm2ext/tearoff.h" #include "canvas/canvas.h" @@ -47,8 +46,8 @@ #include "ardour/session.h" #include "ardour/types.h" -#include "ardour_ui.h" #include "actions.h" +#include "ardour_ui.h" #include "editor.h" #include "time_axis_view.h" #include "audio_time_axis.h" @@ -60,7 +59,6 @@ #include "automation_time_axis.h" #include "control_point.h" #include "prompter.h" -#include "utils.h" #include "selection.h" #include "keyboard.h" #include "editing.h" @@ -74,7 +72,7 @@ #include "verbose_cursor.h" #include "note.h" -#include "i18n.h" +#include "pbd/i18n.h" using namespace std; using namespace ARDOUR; @@ -87,7 +85,7 @@ bool Editor::mouse_frame (framepos_t& where, bool& in_track_canvas) const { /* gdk_window_get_pointer() has X11's XQueryPointer semantics in that it only - pays attentions to subwindows. this means that menu windows are ignored, and + pays attentions to subwindows. this means that menu windows are ignored, and if the pointer is in a menu, the return window from the call will be the the regular subwindow *under* the menu. @@ -114,7 +112,7 @@ Editor::mouse_frame (framepos_t& where, bool& in_track_canvas) const return false; } - if (pointer_window != canvas_window && pointer_window != _time_bars_canvas->get_window()) { + if (pointer_window != canvas_window) { in_track_canvas = false; return false; } @@ -126,26 +124,24 @@ Editor::mouse_frame (framepos_t& where, bool& in_track_canvas) const event.button.x = x; event.button.y = y; - where = window_event_frame (&event, 0, 0); + where = window_event_sample (&event, 0, 0); return true; } framepos_t -Editor::window_event_frame (GdkEvent const * event, double* pcx, double* pcy) const +Editor::window_event_sample (GdkEvent const * event, double* pcx, double* pcy) const { - double x; - double y; + ArdourCanvas::Duple d; - if (!gdk_event_get_coords (event, &x, &y)) { + if (!gdk_event_get_coords (event, &d.x, &d.y)) { return 0; } /* 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)); + d = _track_canvas->window_to_canvas (d); if (pcx) { *pcx = d.x; @@ -159,7 +155,7 @@ Editor::window_event_frame (GdkEvent const * event, double* pcx, double* pcy) co } framepos_t -Editor::canvas_event_frame (GdkEvent const * event, double* pcx, double* pcy) const +Editor::canvas_event_sample (GdkEvent const * event, double* pcx, double* pcy) const { double x; double y; @@ -179,57 +175,12 @@ Editor::canvas_event_frame (GdkEvent const * event, double* pcx, double* pcy) co *pcy = y; } - /* note that pixel_to_sample() never returns less than zero, so even if the pixel + /* 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_sample (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; + return pixel_to_sample_from_event (x); } void @@ -239,7 +190,6 @@ Editor::set_current_trimmable (boost::shared_ptr t) if (!st || st == t) { _trimmable = t; - set_canvas_cursor (); } } @@ -250,108 +200,44 @@ 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; - - _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 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() { MouseMode m = mouse_mode; - + Glib::RefPtr act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-range")); assert (act); Glib::RefPtr tact = Glib::RefPtr::cast_dynamic (act); assert (tact); - 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 } +static Glib::RefPtr +get_mouse_mode_action(MouseMode m) +{ + switch (m) { + case MouseRange: + return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-range")); + case MouseObject: + return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object")); + case MouseCut: + return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-cut")); + case MouseDraw: + return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-draw")); + case MouseTimeFX: + return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-timefx")); + case MouseContent: + return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-content")); + case MouseAudition: + return ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-audition")); + } + return Glib::RefPtr(); +} + void Editor::set_mouse_mode (MouseMode m, bool force) { @@ -363,42 +249,12 @@ Editor::set_mouse_mode (MouseMode m, bool force) return; } - Glib::RefPtr act; - - switch (m) { - case MouseRange: - act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-range")); - break; - - case MouseObject: - act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object")); - break; - - case MouseDraw: - act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-draw")); - break; - - case MouseGain: - act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-gain")); - break; - - case MouseZoom: - act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-zoom")); - break; - - case MouseTimeFX: - act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-timefx")); - break; - - case MouseAudition: - act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-audition")); - break; + if (ARDOUR::Profile->get_mixbus()) { + if ( m == MouseCut) m = MouseObject; } - assert (act); - - Glib::RefPtr tact = Glib::RefPtr::cast_dynamic (act); - assert (tact); + Glib::RefPtr act = get_mouse_mode_action(m); + Glib::RefPtr tact = Glib::RefPtr::cast_dynamic(act); /* go there and back to ensure that the toggled handler is called to set up mouse_mode */ tact->set_active (false); @@ -410,43 +266,12 @@ Editor::set_mouse_mode (MouseMode m, bool force) void Editor::mouse_mode_toggled (MouseMode m) { - Glib::RefPtr act; - Glib::RefPtr tact; - - switch (m) { - case MouseRange: - act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-range")); - break; - - case MouseObject: - act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object")); - break; - - case MouseDraw: - act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-draw")); - break; - - case MouseGain: - act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-gain")); - break; - - case MouseZoom: - act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-zoom")); - break; - - case MouseTimeFX: - act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-timefx")); - break; - - case MouseAudition: - act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-audition")); - break; + if (ARDOUR::Profile->get_mixbus()) { + if ( m == MouseCut) m = MouseObject; } - assert (act); - - tact = Glib::RefPtr::cast_dynamic (act); - assert (tact); + Glib::RefPtr act = get_mouse_mode_action(m); + Glib::RefPtr tact = Glib::RefPtr::cast_dynamic(act); if (!tact->get_active()) { /* this was just the notification that the old mode has been @@ -456,136 +281,127 @@ Editor::mouse_mode_toggled (MouseMode m) return; } - switch (m) { - case MouseDraw: - act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit")); - tact = Glib::RefPtr::cast_dynamic(act); - tact->set_active (true); - break; - default: - break; - } - if (_session && mouse_mode == MouseAudition) { /* stop transport and reset default speed to avoid oddness with auditioning */ _session->request_transport_speed (0.0, true); } + const bool was_internal = internal_editing(); + mouse_mode = m; + /* Switch snap type/mode if we're moving to/from an internal tool. Note + this must toggle the actions and not call set_snap_*() directly, + otherwise things get out of sync and the combo box stops working. */ + if (!was_internal && internal_editing()) { + snap_type_action(internal_snap_type)->set_active(true); + snap_mode_action(internal_snap_mode)->set_active(true); + } else if (was_internal && !internal_editing()) { + snap_type_action(pre_internal_snap_type)->set_active(true); + snap_mode_action(pre_internal_snap_mode)->set_active(true); + } + instant_save (); - //TODO: set button styles for smart buttons -/* - if ( smart_mode_action->get_active() ) { - if( mouse_mode == MouseObject ) { //smart active and object active - smart_mode_button.set_active(1); - smart_mode_button.set_name("smart mode button"); - mouse_move_button.set_name("smart mode button"); - } else { //smart active but object inactive - smart_mode_button.set_active(0); - smart_mode_button.set_name("smart mode button"); - mouse_move_button.set_name("mouse mode button"); - } - } else { - smart_mode_button.set_active(0); - smart_mode_button.set_name("mouse mode button"); - mouse_move_button.set_name("mouse mode button"); + /* this should generate a new enter event which will + trigger the appropiate cursor. + */ + + if (_track_canvas) { + _track_canvas->re_enter (); } -*/ - - set_canvas_cursor (); + set_gain_envelope_visibility (); + update_time_selection_display (); + + update_all_enter_cursors (); + MouseModeChanged (); /* EMIT SIGNAL */ } -void -Editor::step_mouse_mode (bool next) +bool +Editor::internal_editing() const { - switch (current_mouse_mode()) { - case MouseObject: - if (next) { - if (Profile->get_sae()) { - set_mouse_mode (MouseZoom); - } else { - set_mouse_mode (MouseRange); - } - } else { - set_mouse_mode (MouseTimeFX); - } - break; + return mouse_mode == Editing::MouseContent || mouse_mode == Editing::MouseDraw; +} +void +Editor::update_time_selection_display () +{ + switch (mouse_mode) { case MouseRange: - if (next) set_mouse_mode (MouseDraw); - else set_mouse_mode (MouseObject); + selection->clear_objects (); + selection->clear_midi_notes (); break; - - case MouseDraw: - if (next) set_mouse_mode (MouseZoom); - else set_mouse_mode (MouseRange); - break; - - case MouseZoom: - if (next) { - if (Profile->get_sae()) { - set_mouse_mode (MouseTimeFX); - } else { - set_mouse_mode (MouseGain); - } - } else { - if (Profile->get_sae()) { - set_mouse_mode (MouseObject); - } else { - set_mouse_mode (MouseDraw); - } - } + case MouseObject: + selection->clear_time (); + selection->clear_tracks (); + selection->clear_midi_notes (); break; + case MouseDraw: + /* Clear regions, but not time or tracks, since that + would destroy the range selection rectangle, which we need to stick + around for AutomationRangeDrag. */ + selection->clear_regions (); + selection->clear_playlists (); + break; + case MouseContent: + /* This handles internal edit. + Clear everything except points and notes. + */ + selection->clear_regions(); + selection->clear_lines(); + selection->clear_playlists (); - case MouseGain: - if (next) set_mouse_mode (MouseTimeFX); - else set_mouse_mode (MouseZoom); + selection->clear_time (); + selection->clear_tracks (); break; case MouseTimeFX: - if (next) { - set_mouse_mode (MouseAudition); - } else { - if (Profile->get_sae()) { - set_mouse_mode (MouseZoom); - } else { - set_mouse_mode (MouseGain); - } - } + /* We probably want to keep region selection */ + selection->clear_points (); + selection->clear_lines(); + selection->clear_playlists (); + + selection->clear_time (); + selection->clear_tracks (); break; case MouseAudition: - if (next) set_mouse_mode (MouseObject); - else set_mouse_mode (MouseTimeFX); + /*Don't lose lines or points if no action in this mode */ + selection->clear_regions (); + selection->clear_playlists (); + selection->clear_time (); + selection->clear_tracks (); + break; + + default: + /*Clear everything */ + selection->clear_objects(); + selection->clear_time (); + selection->clear_tracks (); break; } } -bool -Editor::toggle_internal_editing_from_double_click (GdkEvent* event) +void +Editor::step_mouse_mode (bool next) { - if (_drags->active()) { - _drags->end_grab (event); - } - - ActionManager::do_action ("MouseMode", "toggle-internal-edit"); - - /* prevent reversion of edit cursor on button release */ - - pre_press_cursor = 0; - - return true; + const int n_mouse_modes = (int)MouseContent + 1; + int current = (int)current_mouse_mode(); + if (next) { + set_mouse_mode((MouseMode)((current + 1) % n_mouse_modes)); + } else { + set_mouse_mode((MouseMode)((current + n_mouse_modes - 1) % n_mouse_modes)); + } } void -Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemType item_type) +Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type) { + /* in object/audition/timefx/gain-automation mode, any button press sets the selection if the object can be selected. this is a bit of hack, because @@ -599,14 +415,40 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp to cut notes or regions. */ + MouseMode eff_mouse_mode = effective_mouse_mode (); + + if (eff_mouse_mode == MouseCut) { + /* never change selection in cut mode */ + return; + } + + 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; + } + + /* special case: allow drag of region fade in/out in object mode with join object/range enabled */ + if (get_smart_mode()) { + switch (item_type) { + case FadeInHandleItem: + case FadeInTrimHandleItem: + case FadeOutHandleItem: + case FadeOutTrimHandleItem: + eff_mouse_mode = MouseObject; + break; + default: + break; + } + } + if (((mouse_mode != MouseObject) && (mouse_mode != MouseAudition || item_type != RegionItem) && (mouse_mode != MouseTimeFX || item_type != RegionItem) && - (mouse_mode != MouseGain) && - (mouse_mode != MouseDraw)) || - ((event->type != GDK_BUTTON_PRESS && event->type != GDK_BUTTON_RELEASE) || event->button.button > 3) || - (internal_editing() && mouse_mode != MouseTimeFX)) { - + (mouse_mode != MouseDraw) && + (mouse_mode != MouseContent || item_type == RegionItem)) || + ((event->type != GDK_BUTTON_PRESS && event->type != GDK_BUTTON_RELEASE) || event->button.button > 3)) { return; } @@ -616,7 +458,9 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp /* almost no selection action on modified button-2 or button-3 events */ - if (item_type != RegionItem && event->button.button != 2) { + if ((item_type != RegionItem && event->button.button != 2) + /* for selection of control points prior to delete (shift-right click) */ + && !(item_type == ControlPointItem && event->button.button == 3 && event->type == GDK_BUTTON_PRESS)) { return; } } @@ -625,27 +469,32 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp Selection::Operation op = ArdourKeyboard::selection_type (event->button.state); bool press = (event->type == GDK_BUTTON_PRESS); + if (press) { + _mouse_changed_selection = false; + } + 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 (eff_mouse_mode == MouseDraw) { + break; + } + if (press) { + if (eff_mouse_mode != MouseRange) { + _mouse_changed_selection = 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) { + _mouse_changed_selection |= set_selected_regionview_from_click (press, op); + } } break; @@ -653,30 +502,118 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp case RegionViewName: case LeftFrameHandle: case RightFrameHandle: - if ( mouse_mode != MouseRange ) { - set_selected_regionview_from_click (press, op); - } else if (event->type == GDK_BUTTON_PRESS) { - set_selected_track_as_side_effect (op); - } - break; - case FadeInHandleItem: + case FadeInTrimHandleItem: case FadeInItem: case FadeOutHandleItem: + case FadeOutTrimHandleItem: case FadeOutItem: case StartCrossFadeItem: case EndCrossFadeItem: - if ( mouse_mode != MouseRange ) { - set_selected_regionview_from_click (press, op); + if (get_smart_mode() || eff_mouse_mode != MouseRange) { + _mouse_changed_selection |= set_selected_regionview_from_click (press, op); } else if (event->type == GDK_BUTTON_PRESS) { set_selected_track_as_side_effect (op); } break; case ControlPointItem: - set_selected_track_as_side_effect (op); - if ( mouse_mode != MouseRange ) { - set_selected_control_point_from_click (press, op); + /* for object/track exclusivity, we don't call set_selected_track_as_side_effect (op); */ + + if (eff_mouse_mode != MouseRange) { + if (event->button.button != 3) { + _mouse_changed_selection |= set_selected_control_point_from_click (press, op); + } else { + _mouse_changed_selection |= set_selected_control_point_from_click (press, Selection::Set); + } + } + break; + + case GainLineItem: + if (eff_mouse_mode != MouseRange) { + AutomationLine* argl = reinterpret_cast (item->get_data ("line")); + + std::list selectables; + uint32_t before, after; + framecnt_t const where = (framecnt_t) floor (event->button.x * samples_per_pixel) - clicked_regionview->region ()->position (); + + if (!argl || !argl->control_points_adjacent (where, before, after)) { + break; + } + + selectables.push_back (argl->nth (before)); + selectables.push_back (argl->nth (after)); + + switch (op) { + case Selection::Set: + if (press) { + selection->set (selectables); + _mouse_changed_selection = true; + } + break; + case Selection::Add: + if (press) { + selection->add (selectables); + _mouse_changed_selection = true; + } + break; + case Selection::Toggle: + if (press) { + selection->toggle (selectables); + _mouse_changed_selection = true; + } + break; + + case Selection::Extend: + /* XXX */ + break; + } + } + break; + + case AutomationLineItem: + if (eff_mouse_mode != MouseRange) { + 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; + framecnt_t const where = (framecnt_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 Selection::Set: + if (press) { + selection->set (selectables); + _mouse_changed_selection = true; + } + break; + case Selection::Add: + if (press) { + selection->add (selectables); + _mouse_changed_selection = true; + } + break; + case Selection::Toggle: + if (press) { + selection->toggle (selectables); + _mouse_changed_selection = true; + } + break; + + case Selection::Extend: + /* XXX */ + break; + } } break; @@ -685,16 +622,42 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp if (event->button.button == 3) { selection->clear_tracks (); set_selected_track_as_side_effect (op); + + /* We won't get a release.*/ + begin_reversible_selection_op (X_("Button 3 Menu Select")); + commit_reversible_selection_op (); + } + break; + + case AutomationTrackItem: + if (eff_mouse_mode != MouseDraw && op == Selection::Set) { + set_selected_track_as_side_effect (op); } break; - case AutomationTrackItem: - set_selected_track_as_side_effect (op); + case NoteItem: + if (press && event->button.button == 3) { + NoteBase* cnote = reinterpret_cast (item->get_data ("notebase")); + assert (cnote); + if (cnote->region_view().selection_size() == 0 || !cnote->selected()) { + selection->clear_points(); + cnote->region_view().unique_select (cnote); + /* we won't get the release, so store the selection change now */ + begin_reversible_selection_op (X_("Button 3 Note Selection")); + commit_reversible_selection_op (); + } + } break; default: break; } + + if ((!press) && _mouse_changed_selection) { + begin_reversible_selection_op (X_("Button Selection")); + commit_reversible_selection_op (); + _mouse_changed_selection = false; + } } bool @@ -706,6 +669,8 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT them to be modeless. */ + NoteBase* note = NULL; + switch (item_type) { case PlayheadCursorItem: _drags->set (new CursorDrag (this, *playhead_cursor, true), event); @@ -721,40 +686,28 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT case TempoMarkerItem: { - TempoMarker* m = reinterpret_cast (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, + ArdourKeyboard::indicates_copy (event->button.state) + ), + event + ); + return true; } case MeterMarkerItem: { - MeterMarker* m = reinterpret_cast (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, + ArdourKeyboard::indicates_copy (event->button.state) + ), + event + ); + return true; } case VideoBarItem: @@ -764,19 +717,29 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT case MarkerBarItem: case TempoBarItem: + case TempoCurveItem: case MeterBarItem: - if (!Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) { + case TimecodeRulerItem: + case SamplesRulerItem: + case MinsecRulerItem: + case BBTRulerItem: + if (!Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier) + && !ArdourKeyboard::indicates_constraint (event->button.state)) { _drags->set (new CursorDrag (this, *playhead_cursor, false), event); + } else if (ArdourKeyboard::indicates_constraint (event->button.state)) { + _drags->set (new BBTRulerDrag (this, item), event); } return true; break; case RangeMarkerBarItem: - if (!Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) { - _drags->set (new CursorDrag (this, *playhead_cursor, false), event); - } else { + if (Keyboard::modifier_state_contains (event->button.state, Keyboard::TertiaryModifier)) { + _drags->set (new RangeMarkerBarDrag (this, item, RangeMarkerBarDrag::CreateSkipMarker), event); + } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) { _drags->set (new RangeMarkerBarDrag (this, item, RangeMarkerBarDrag::CreateRangeMarker), event); + } else { + _drags->set (new CursorDrag (this, *playhead_cursor, false), event); } return true; break; @@ -820,13 +783,17 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT Editing::MouseMode eff = effective_mouse_mode (); /* special case: allow drag of region fade in/out in object mode with join object/range enabled */ - if (item_type == FadeInHandleItem || item_type == FadeOutHandleItem) { - eff = MouseObject; - } - - /* there is no Range mode when in internal edit mode */ - if (eff == MouseRange && internal_editing()) { - eff = MouseObject; + if (get_smart_mode()) { + switch (item_type) { + case FadeInHandleItem: + case FadeInTrimHandleItem: + case FadeOutHandleItem: + case FadeOutTrimHandleItem: + eff = MouseObject; + break; + default: + break; + } } switch (eff) { @@ -848,36 +815,19 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT /* grab selection for moving */ _drags->set (new SelectionDrag (this, item, SelectionDrag::SelectionMove), event); } else { - double const y = event->button.y; - pair tvp = trackview_by_y_position (y); - if (tvp.first) { - AutomationTimeAxisView* atv = dynamic_cast (tvp.first); - if ( get_smart_mode() && atv) { - /* smart "join" mode: drag automation */ - _drags->set (new AutomationRangeDrag (this, atv, selection->time), event, _cursors->up_down); - } else { - /* this was debated, but decided the more common action was to - make a new selection */ - _drags->set (new SelectionDrag (this, item, SelectionDrag::CreateSelection), event); - } - } + /* this was debated, but decided the more common action was to + make a new selection */ + _drags->set (new SelectionDrag (this, item, SelectionDrag::CreateSelection), event); } break; case StreamItem: - if (internal_editing()) { - if (dynamic_cast (clicked_axisview)) { - _drags->set (new RegionCreateDrag (this, item, clicked_axisview), event); - return true; - } + if (Keyboard::modifier_state_equals (event->button.state, Keyboard::RangeSelectModifier)) { + _drags->set (new SelectionDrag (this, item, SelectionDrag::SelectionExtend), event); } else { - if (Keyboard::modifier_state_equals (event->button.state, Keyboard::RangeSelectModifier)) { - _drags->set (new SelectionDrag (this, item, SelectionDrag::SelectionExtend), event); - } else { - _drags->set (new SelectionDrag (this, item, SelectionDrag::CreateSelection), event); - } - return true; + _drags->set (new SelectionDrag (this, item, SelectionDrag::CreateSelection), event); } + return true; break; case RegionViewNameHighlight: @@ -888,57 +838,77 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT break; default: - if (!internal_editing()) { - if (Keyboard::modifier_state_equals (event->button.state, Keyboard::RangeSelectModifier)) { - _drags->set (new SelectionDrag (this, item, SelectionDrag::SelectionExtend), event); - } else { - _drags->set (new SelectionDrag (this, item, SelectionDrag::CreateSelection), event); - } + if (Keyboard::modifier_state_equals (event->button.state, Keyboard::RangeSelectModifier)) { + _drags->set (new SelectionDrag (this, item, SelectionDrag::SelectionExtend), event); + } else { + _drags->set (new SelectionDrag (this, item, SelectionDrag::CreateSelection), event); } } return true; break; - case MouseDraw: + case MouseCut: switch (item_type) { - case NoteItem: - if (internal_editing()) { - /* trim notes if we're in internal edit mode and near the ends of the note */ - NoteBase* cn = reinterpret_cast(item->get_data ("notebase")); - assert (cn); - if (cn && 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 RegionItem: + case FadeInHandleItem: + case FadeOutHandleItem: + case LeftFrameHandle: + case RightFrameHandle: + case FeatureLineItem: + case RegionViewNameHighlight: + case RegionViewName: case StreamItem: - if (internal_editing()) { - if (dynamic_cast (clicked_axisview)) { - _drags->set (new RegionCreateDrag (this, item, clicked_axisview), event); - } - return true; - } + case AutomationTrackItem: + _drags->set (new RegionCutDrag (this, item, canvas_event_sample (event)), event, get_canvas_cursor()); + return true; break; - default: break; } break; - case MouseObject: + case MouseContent: switch (item_type) { case NoteItem: - if (internal_editing()) { - NoteBase* cn = reinterpret_cast (item->get_data ("notebase")); - assert (cn); - if (cn->mouse_near_ends()) { - _drags->set (new NoteResizeDrag (this, item), event, current_canvas_cursor); + /* Existing note: allow trimming/motion */ + if ((note = reinterpret_cast (item->get_data ("notebase")))) { + if (note->big_enough_to_trim() && note->mouse_near_ends()) { + _drags->set (new NoteResizeDrag (this, item), event, get_canvas_cursor()); } else { _drags->set (new NoteDrag (this, item), event); } + } + return true; + + case GainLineItem: + _drags->set (new LineDrag (this, item), event); + return true; + break; + + case ControlPointItem: + _drags->set (new ControlPointDrag (this, item), event); + return true; + break; + + case AutomationLineItem: + _drags->set (new LineDrag (this, item), event); + return true; + break; + + case StreamItem: + //in the past, we created a new midi region here, but perhaps that is best left to the Draw mode + break; + + case AutomationTrackItem: + /* rubberband drag to select automation points */ + _drags->set (new EditorRubberbandSelectDrag (this, item), event); + return true; + break; + + case RegionItem: + if (dynamic_cast(clicked_regionview)) { + /* rubberband drag to select automation points */ + _drags->set (new EditorRubberbandSelectDrag (this, item), event); return true; } break; @@ -946,7 +916,9 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT default: break; } + break; + case MouseObject: if (Keyboard::modifier_state_contains (event->button.state, Keyboard::ModifierMask(Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)) && event->type == GDK_BUTTON_PRESS) { @@ -969,7 +941,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT case StartCrossFadeItem: case EndCrossFadeItem: - /* we might allow user to grab inside the fade to trim a region with preserve_fade_anchor. for not this is not fully implemented */ + /* we might allow user to grab inside the fade to trim a region with preserve_fade_anchor. for not this is not fully implemented */ // if (!clicked_regionview->region()->locked()) { // _drags->set (new TrimDrag (this, item, clicked_regionview, selection->regions.by_layer(), true), event); // return true; @@ -996,12 +968,8 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT break; } - if (internal_editing ()) { - break; - } - /* click on a normal region view */ - if (Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier)) { + if (ArdourKeyboard::indicates_copy (event->button.state)) { add_region_copy_drag (item, event, clicked_regionview); } else if (Keyboard::the_keyboard().key_is_down (GDK_b)) { add_region_brush_drag (item, event, clicked_regionview); @@ -1010,28 +978,34 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT } -// if (!internal_editing() && (_join_object_range_state == JOIN_OBJECT_RANGE_RANGE && !selection->regions.empty())) { -// _drags->add (new SelectionDrag (this, clicked_axisview->get_selection_rect (clicked_selection)->rect, SelectionDrag::SelectionMove)); -// } - _drags->start_grab (event); return true; break; case RegionViewNameHighlight: case LeftFrameHandle: - case RightFrameHandle: + case RightFrameHandle: if (!clicked_regionview->region()->locked()) { _drags->set (new TrimDrag (this, item, clicked_regionview, selection->regions.by_layer()), event); return true; } break; + case FadeInTrimHandleItem: + case FadeOutTrimHandleItem: + if (!clicked_regionview->region()->locked()) { + _drags->set (new TrimDrag (this, item, clicked_regionview, selection->regions.by_layer(), true), event); + return true; + } + break; + case RegionViewName: { /* rename happens on edit clicks */ - _drags->set (new TrimDrag (this, clicked_regionview->get_name_highlight(), clicked_regionview, selection->regions.by_layer()), event); - return true; + if (clicked_regionview->get_name_highlight()) { + _drags->set (new TrimDrag (this, clicked_regionview->get_name_highlight(), clicked_regionview, selection->regions.by_layer()), event); + return true; + } break; } @@ -1046,15 +1020,8 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT break; case StreamItem: - if (internal_editing()) { - if (dynamic_cast (clicked_axisview)) { - _drags->set (new RegionCreateDrag (this, item, clicked_axisview), event); - } - return true; - } else { - _drags->set (new EditorRubberbandSelectDrag (this, item), event); - } - break; + _drags->set (new EditorRubberbandSelectDrag (this, item), event); + return true; case AutomationTrackItem: { @@ -1071,12 +1038,12 @@ 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 = canvas_event_frame (event); + framepos_t const t = canvas_event_sample (event); boost::shared_ptr prev = pl->find_next_region (t, End, -1); if (!prev) { _drags->set (new RegionCreateDrag (this, item, parent), event); } else { - prev->set_length (t - prev->position ()); + prev->set_length (t - prev->position (), get_grid_music_divisions (event->button.state)); } } } else { @@ -1088,45 +1055,6 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT case SelectionItem: { - if ( get_smart_mode() ) { - /* we're in "smart" joined mode, and we've clicked on a Selection */ - double const y = event->button.y; - pair tvp = trackview_by_y_position (y); - if (tvp.first) { - /* if we're over an automation track, start a drag of its data */ - AutomationTimeAxisView* atv = dynamic_cast (tvp.first); - if (atv) { - _drags->set (new AutomationRangeDrag (this, atv, selection->time), event, _cursors->up_down); - } - - /* if we're over a track and a region, and in the `object' part of a region, - put a selection around the region and drag both - */ -/* RouteTimeAxisView* rtv = dynamic_cast (tvp.first); - if (rtv && _join_object_range_state == JOIN_OBJECT_RANGE_OBJECT) { - boost::shared_ptr t = boost::dynamic_pointer_cast (rtv->route ()); - if (t) { - boost::shared_ptr pl = t->playlist (); - if (pl) { - - boost::shared_ptr r = pl->top_region_at (canvas_event_frame (event)); - if (r) { - RegionView* rv = rtv->view()->find_view (r); - clicked_selection = select_range (rv->region()->position(), - rv->region()->last_frame()+1); - _drags->add (new SelectionDrag (this, item, SelectionDrag::SelectionMove)); - list rvs; - rvs.push_back (rv); - _drags->add (new RegionMoveDrag (this, item, rv, rvs, false, false)); - _drags->start_grab (event); - return true; - } - } - } - } -*/ - } - } break; } @@ -1141,7 +1069,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT return true; break; - case MouseGain: + case MouseDraw: switch (item_type) { case GainLineItem: _drags->set (new LineDrag (this, item), event); @@ -1154,10 +1082,20 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT case SelectionItem: { - AudioRegionView* arv = dynamic_cast (clicked_regionview); - if (arv) { - _drags->set (new AutomationRangeDrag (this, arv, selection->time), event, _cursors->up_down); - _drags->start_grab (event); + if (dynamic_cast(clicked_regionview) || + dynamic_cast(clicked_regionview)) { + _drags->set (new AutomationRangeDrag (this, clicked_regionview, selection->time), + event, _cursors->up_down); + } else { + double const y = event->button.y; + pair tvp = trackview_by_y_position (y, false); + if (tvp.first) { + AutomationTimeAxisView* atv = dynamic_cast (tvp.first); + if ( atv) { + /* smart "join" mode: drag automation */ + _drags->set (new AutomationRangeDrag (this, atv, selection->time), event, _cursors->up_down); + } + } } return true; break; @@ -1166,25 +1104,40 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT case AutomationLineItem: _drags->set (new LineDrag (this, item), event); break; - + + case NoteItem: + if ((note = reinterpret_cast(item->get_data ("notebase")))) { + if (note->big_enough_to_trim() && note->mouse_near_ends()) { + /* Note is big and pointer is near the end, trim */ + _drags->set (new NoteResizeDrag (this, item), event, get_canvas_cursor()); + } else { + /* Drag note */ + _drags->set (new NoteDrag (this, item), event); + } + return true; + } + return true; + + case StreamItem: + if (dynamic_cast (clicked_axisview)) { + _drags->set (new RegionCreateDrag (this, item, clicked_axisview), event); + } + return true; + default: break; } return true; break; - case MouseZoom: - if (event->type == GDK_BUTTON_PRESS) { - _drags->set (new MouseZoomDrag (this, item), event); - } - - return true; - break; - case MouseTimeFX: - 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); + if (item_type == NoteItem) { + /* resize-drag notes */ + if ((note = reinterpret_cast(item->get_data ("notebase")))) { + if (note->big_enough_to_trim()) { + _drags->set (new NoteResizeDrag (this, item), event, get_canvas_cursor()); + } + } return true; } else if (clicked_regionview) { /* do time-FX */ @@ -1194,12 +1147,11 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT break; case MouseAudition: - _drags->set (new ScrubDrag (this, item), event); + _drags->set (new ScrubDrag (this, item), event, _cursors->transparent); scrub_reversals = 0; scrub_reverse_distance = 0; last_scrub_x = event->button.x; scrubbing_direction = 0; - set_canvas_cursor (_cursors->transparent); return true; break; @@ -1218,12 +1170,7 @@ Editor::button_press_handler_2 (ArdourCanvas::Item* item, GdkEvent* event, ItemT case MouseObject: switch (item_type) { case RegionItem: - if (internal_editing ()) { - /* no region drags in internal edit mode */ - return false; - } - - if (Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier)) { + if (ArdourKeyboard::indicates_copy (event->button.state)) { add_region_copy_drag (item, event, clicked_regionview); } else { add_region_drag (item, event, clicked_regionview); @@ -1242,15 +1189,13 @@ Editor::button_press_handler_2 (ArdourCanvas::Item* item, GdkEvent* event, ItemT switch (item_type) { case RegionViewNameHighlight: - _drags->set (new TrimDrag (this, item, clicked_regionview, selection->regions.by_layer()), event); - return true; - break; + _drags->set (new TrimDrag (this, item, clicked_regionview, selection->regions.by_layer()), event); + return true; + break; - case LeftFrameHandle: - case RightFrameHandle: - if (!internal_editing ()) { - _drags->set (new TrimDrag (this, item, clicked_regionview, selection->regions.by_layer()), event); - } + case LeftFrameHandle: + case RightFrameHandle: + _drags->set (new TrimDrag (this, item, clicked_regionview, selection->regions.by_layer()), event); return true; break; @@ -1273,96 +1218,32 @@ Editor::button_press_handler_2 (ArdourCanvas::Item* item, GdkEvent* event, ItemT return true; break; - - case MouseZoom: - if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) { - temporal_zoom_to_frame (false, canvas_event_frame (event)); - } else { - temporal_zoom_to_frame (true, canvas_event_frame(event)); - } - return true; - break; - default: break; } return false; } - + bool Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type) { if (event->type == GDK_2BUTTON_PRESS) { _drags->mark_double_click (); - return false; + gdk_pointer_ungrab (GDK_CURRENT_TIME); + return true; } if (event->type != GDK_BUTTON_PRESS) { return false; } - Glib::RefPtr canvas_window = const_cast(this)->_track_canvas_viewport->get_window(); - - if (canvas_window) { - Glib::RefPtr pointer_window; - int x, y; - double wx, wy; - Gdk::ModifierType mask; - - pointer_window = canvas_window->get_pointer (x, y, mask); - - 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(); if (_session && _session->actively_recording()) { return true; } - if (internal_editing()) { - bool leave_internal_edit_mode = false; - - switch (item_type) { - case NoteItem: - break; - - case RegionItem: - if (!dynamic_cast (clicked_regionview) && !dynamic_cast (clicked_regionview)) { - leave_internal_edit_mode = true; - } - break; - - case PlayheadCursorItem: - case MarkerItem: - case TempoMarkerItem: - case MeterMarkerItem: - case MarkerBarItem: - case TempoBarItem: - case MeterBarItem: - case RangeMarkerBarItem: - case CdMarkerBarItem: - case TransportMarkerBarItem: - case StreamItem: - /* button press on these events never does anything to - change the editing mode. - */ - break; - - default: - break; - } - - if (leave_internal_edit_mode) { - ActionManager::do_action ("MouseMode", "toggle-internal-edit"); - } - } - button_selection (item, event, item_type); if (!_drags->active () && @@ -1374,9 +1255,21 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp return true; } - //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 = canvas_event_frame (event); + /* not rolling, effectively in range mode, follow edits enabled (likely + * to start range drag), not in a fade handle (since that means we are + * not starting a range drag): locate the PH here + */ + + if ((item_type != FadeInHandleItem) && + (item_type != FadeOutHandleItem) && + !_drags->active () && + _session && + !_session->transport_rolling() && + (effective_mouse_mode() == MouseRange) && + UIConfiguration::instance().get_follow_edits() && + !_session->config.get_external_sync()) { + + framepos_t where = canvas_event_sample (event); snap_to(where); _session->request_locate (where, false); } @@ -1425,13 +1318,10 @@ Editor::button_release_dispatch (GdkEventButton* ev) bool Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type) { - framepos_t where = canvas_event_frame (event); + framepos_t where = canvas_event_sample (event); AutomationTimeAxisView* atv = 0; - if (pre_press_cursor) { - set_canvas_cursor (pre_press_cursor); - pre_press_cursor = 0; - } + _press_cursor_ctx.reset(); /* no action if we're recording */ @@ -1439,20 +1329,24 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT return true; } - /* see if we're finishing a drag */ + bool were_dragging = false; - bool were_dragging = false; - if (_drags->active ()) { - bool const r = _drags->end_grab (event); - if (r) { - /* grab dragged, so do nothing else */ - return true; - } + if (!Keyboard::is_context_menu_event (&event->button)) { - were_dragging = true; - } + /* see if we're finishing a drag */ + + if (_drags->active ()) { + bool const r = _drags->end_grab (event); + if (r) { + /* grab dragged, so do nothing else */ + return true; + } + + were_dragging = true; + } - update_region_layering_order_editor (); + update_region_layering_order_editor (); + } /* edit events get handled here */ @@ -1461,14 +1355,40 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT case RegionItem: show_region_properties (); break; + case TempoMarkerItem: { + ArdourMarker* marker; + TempoMarker* tempo_marker; - case TempoMarkerItem: - edit_tempo_marker (item); + if ((marker = reinterpret_cast (item->get_data ("marker"))) == 0) { + fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg; + abort(); /*NOTREACHED*/ + } + + if ((tempo_marker = dynamic_cast (marker)) == 0) { + fatal << _("programming error: marker for tempo is not a tempo marker!") << endmsg; + abort(); /*NOTREACHED*/ + } + + edit_tempo_marker (*tempo_marker); break; + } - case MeterMarkerItem: - edit_meter_marker (item); + case MeterMarkerItem: { + ArdourMarker* marker; + MeterMarker* meter_marker; + + if ((marker = reinterpret_cast (item->get_data ("marker"))) == 0) { + fatal << _("programming error: tempo marker canvas item has no marker object pointer!") << endmsg; + abort(); /*NOTREACHED*/ + } + + if ((meter_marker = dynamic_cast (marker)) == 0) { + fatal << _("programming error: marker for meter is not a meter marker!") << endmsg; + abort(); /*NOTREACHED*/ + } + edit_meter_marker (*meter_marker); break; + } case RegionViewName: if (clicked_regionview->name_active()) { @@ -1500,27 +1420,28 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT switch (item_type) { case FadeInItem: case FadeInHandleItem: - case FadeOutItem: - case FadeOutHandleItem: - popup_fade_context_menu (1, event->button.time, item, item_type); - break; - + case FadeInTrimHandleItem: case StartCrossFadeItem: popup_xfade_in_context_menu (1, event->button.time, item, item_type); break; + case FadeOutItem: + case FadeOutHandleItem: + case FadeOutTrimHandleItem: case EndCrossFadeItem: popup_xfade_out_context_menu (1, event->button.time, item, item_type); break; + case LeftFrameHandle: + case RightFrameHandle: + break; + case StreamItem: popup_track_context_menu (1, event->button.time, item_type, false); break; case RegionItem: case RegionViewNameHighlight: - case LeftFrameHandle: - case RightFrameHandle: case RegionViewName: popup_track_context_menu (1, event->button.time, item_type, false); break; @@ -1528,7 +1449,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT case SelectionItem: popup_track_context_menu (1, event->button.time, item_type, true); break; - + case AutomationTrackItem: popup_track_context_menu (1, event->button.time, item_type, false); break; @@ -1538,8 +1459,13 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT case TransportMarkerBarItem: case CdMarkerBarItem: case TempoBarItem: + case TempoCurveItem: case MeterBarItem: case VideoBarItem: + case TimecodeRulerItem: + case SamplesRulerItem: + case MinsecRulerItem: + case BBTRulerItem: popup_ruler_menu (where, item_type); break; @@ -1563,6 +1489,12 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT popup_control_point_context_menu (item, event); break; + case NoteItem: + if (internal_editing()) { + popup_note_context_menu (item, event); + } + break; + default: break; } @@ -1625,7 +1557,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT case MarkerBarItem: if (!_dragging_playhead) { - snap_to_with_modifier (where, event, 0, true); + snap_to_with_modifier (where, event, RoundNearest, true); mouse_add_new_marker (where); } return true; @@ -1633,12 +1565,12 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT case CdMarkerBarItem: if (!_dragging_playhead) { // if we get here then a dragged range wasn't done - snap_to_with_modifier (where, event, 0, true); + snap_to_with_modifier (where, event, RoundNearest, true); mouse_add_new_marker (where, true); } return true; - case TempoBarItem: + case TempoCurveItem: if (!_dragging_playhead) { snap_to_with_modifier (where, event); mouse_add_new_tempo_event (where); @@ -1651,27 +1583,20 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT } return true; break; - - default: - break; - } - - switch (eff) { - case MouseObject: - switch (item_type) { - case AutomationTrackItem: - atv = dynamic_cast(clicked_axisview); - if (atv) { - atv->add_automation_event (event, where, event->button.y); - } - return true; - break; - default: - break; - } + + case TimecodeRulerItem: + case SamplesRulerItem: + case MinsecRulerItem: + case BBTRulerItem: + return true; + break; + + default: break; + } - case MouseGain: + switch (eff) { + case MouseDraw: switch (item_type) { case RegionItem: { @@ -1681,24 +1606,28 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT */ AudioRegionView* arv = dynamic_cast (clicked_regionview); if (!were_dragging && arv) { - arv->add_gain_point_event (item, event); + bool with_guard_points = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier); + arv->add_gain_point_event (item, event, with_guard_points); } return true; break; } - case AutomationTrackItem: - dynamic_cast(clicked_axisview)-> - add_automation_event (event, where, event->button.y); + case AutomationTrackItem: { + bool with_guard_points = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier); + atv = dynamic_cast(clicked_axisview); + if (atv) { + atv->add_automation_event (event, where, event->button.y, with_guard_points); + } return true; break; + } default: break; } break; case MouseAudition: - set_canvas_cursor (current_canvas_cursor); if (scrubbing_direction == 0) { /* no drag, just a click */ switch (item_type) { @@ -1708,7 +1637,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT default: break; } - } else { + } else if (_session) { /* make sure we stop */ _session->request_transport_speed (0.0); } @@ -1720,7 +1649,8 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT } /* do any (de)selection operations that should occur on button release */ - button_selection (item, event, item_type); + button_selection (item, event, item_type); + return true; break; @@ -1749,7 +1679,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT case MouseDraw: return true; - + case MouseRange: // x_style_paste (where, 1.0); return true; @@ -1775,196 +1705,137 @@ bool Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type) { ControlPoint* cp; - Marker * marker; + 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 ControlPointItem: - if (mouse_mode == MouseGain || mouse_mode == MouseObject) { + if (mouse_mode == MouseDraw || mouse_mode == MouseObject || mouse_mode == MouseContent) { cp = static_cast(item->get_data ("control_point")); - cp->set_visible (true); - - double at_x, at_y; - at_x = cp->get_x(); - at_y = cp->get_y (); - cp->i2w (at_x, at_y); - at_x += 10.0; - at_y += 10.0; + cp->show (); 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->set (cp->line().get_verbose_cursor_string (fraction)); _verbose_cursor->show (); } break; case GainLineItem: - if (mouse_mode == MouseGain) { + if (mouse_mode == MouseDraw) { ArdourCanvas::Line *line = dynamic_cast (item); if (line) { - line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_EnteredGainLine()); - } - if (is_drawable()) { - set_canvas_cursor (_cursors->fader); + line->set_outline_color (UIConfiguration::instance().color ("entered gain line")); } } break; case AutomationLineItem: - if (mouse_mode == MouseGain || mouse_mode == MouseObject) { + if (mouse_mode == MouseDraw || mouse_mode == MouseObject) { ArdourCanvas::Line *line = dynamic_cast (item); if (line) { - line->set_outline_color (ARDOUR_UI::config()->get_canvasvar_EnteredAutomationLine()); - } - if (is_drawable()) { - set_canvas_cursor (_cursors->fader); + line->set_outline_color (UIConfiguration::instance().color ("entered automation line")); } } 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 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; - } + case AutomationTrackItem: + AutomationTimeAxisView* atv; + if ((atv = static_cast(item->get_data ("trackview"))) != 0) { + clear_entered_track = false; + set_entered_track (atv); } 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; - } + case MarkerItem: + if ((marker = static_cast (item->get_data ("marker"))) == 0) { + break; } + entered_marker = marker; + marker->set_color_rgba (UIConfiguration::instance().color ("entered marker")); 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); - } + case MeterMarkerItem: + if ((m_marker = static_cast (item->get_data ("marker"))) == 0) { + break; } - break; - - case MarkerBarItem: - case RangeMarkerBarItem: - case TransportMarkerBarItem: - case CdMarkerBarItem: - case MeterBarItem: - case TempoBarItem: - if (is_drawable()) { - set_canvas_cursor (_cursors->timebar); + entered_marker = m_marker; + if (m_marker->meter().position_lock_style() == MusicTime) { + m_marker->set_color_rgba (UIConfiguration::instance().color ("meter marker")); + } else { + m_marker->set_color_rgba (UIConfiguration::instance().color ("meter marker music")); } break; - case MarkerItem: - if ((marker = static_cast (item->get_data ("marker"))) == 0) { + case TempoMarkerItem: + if ((t_marker = static_cast (item->get_data ("marker"))) == 0) { break; } - entered_marker = marker; - marker->set_color_rgba (ARDOUR_UI::config()->get_canvasvar_EnteredMarker()); - // fall through - case MeterMarkerItem: - case TempoMarkerItem: - if (is_drawable()) { - set_canvas_cursor (_cursors->timebar); + entered_marker = t_marker; + if (t_marker->tempo().position_lock_style() == MusicTime) { + t_marker->set_color_rgba (UIConfiguration::instance().color ("tempo marker")); + } else { + t_marker->set_color_rgba (UIConfiguration::instance().color ("tempo marker music")); } break; case FadeInHandleItem: - if (mouse_mode == MouseObject && !internal_editing()) { + case FadeInTrimHandleItem: + if (mouse_mode == MouseObject) { ArdourCanvas::Rectangle *rect = dynamic_cast (item); if (rect) { - rect->set_fill_color (0xBBBBBBAA); + RegionView* rv = static_cast(item->get_data ("regionview")); + rect->set_fill_color (rv->get_fill_color()); } - set_canvas_cursor (_cursors->fade_in); } break; case FadeOutHandleItem: - if (mouse_mode == MouseObject && !internal_editing()) { + case FadeOutTrimHandleItem: + if (mouse_mode == MouseObject) { ArdourCanvas::Rectangle *rect = dynamic_cast (item); if (rect) { - rect->set_fill_color (0xBBBBBBAA); + RegionView* rv = static_cast(item->get_data ("regionview")); + rect->set_fill_color (rv->get_fill_color ()); } - set_canvas_cursor (_cursors->fade_out); } break; + case FeatureLineItem: { ArdourCanvas::Line *line = dynamic_cast (item); line->set_outline_color (0xFF0000FF); } break; - + case SelectionItem: - if ( get_smart_mode() ) { - set_canvas_cursor (); - } break; + case WaveItem: + { + if (entered_regionview) { + entered_regionview->entered(); + } + } + 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) { @@ -1980,7 +1851,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ break; default: - set_entered_track (0); + break; } @@ -1991,43 +1862,22 @@ bool Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent*, ItemType item_type) { AutomationLine* al; - ControlPoint* cp; - Marker *marker; + ArdourMarker *marker; + TempoMarker *t_marker; + MeterMarker *m_marker; Location *loc; - RegionView* rv; bool is_start; bool ret = true; + if (!_enter_stack.empty()) { + _enter_stack.pop_back(); + } + switch (item_type) { case ControlPointItem: - cp = reinterpret_cast(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); - } - _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")); @@ -2037,76 +1887,63 @@ 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); - } + case MarkerItem: + if ((marker = static_cast (item->get_data ("marker"))) == 0) { + break; } - break; - - case RangeMarkerBarItem: - case TransportMarkerBarItem: - case CdMarkerBarItem: - case MeterBarItem: - case TempoBarItem: - case MarkerBarItem: - if (is_drawable()) { - set_canvas_cursor (current_canvas_cursor); + entered_marker = 0; + if ((loc = find_location_from_marker (marker, is_start)) != 0) { + location_flags_changed (loc); } break; - case MarkerItem: - if ((marker = static_cast (item->get_data ("marker"))) == 0) { + case MeterMarkerItem: + if ((m_marker = static_cast (item->get_data ("marker"))) == 0) { break; } entered_marker = 0; - if ((loc = find_location_from_marker (marker, is_start)) != 0) { - location_flags_changed (loc, this); + if (m_marker->meter().position_lock_style() == MusicTime) { + m_marker->set_color_rgba (UIConfiguration::instance().color ("meter marker music")); + } else { + m_marker->set_color_rgba (UIConfiguration::instance().color ("meter marker")); } - // fall through - case MeterMarkerItem: - case TempoMarkerItem: + break; - if (is_drawable()) { - set_canvas_cursor (current_canvas_cursor); + case TempoMarkerItem: + if ((t_marker = static_cast (item->get_data ("marker"))) == 0) { + break; + } + entered_marker = 0; + if (t_marker->tempo().position_lock_style() == MusicTime) { + t_marker->set_color_rgba (UIConfiguration::instance().color ("tempo marker music")); + } else { + t_marker->set_color_rgba (UIConfiguration::instance().color ("tempo marker")); } - break; + case FadeInTrimHandleItem: + case FadeOutTrimHandleItem: case FadeInHandleItem: case FadeOutHandleItem: - rv = static_cast(item->get_data ("regionview")); - { - ArdourCanvas::Rectangle *rect = dynamic_cast (item); - if (rect) { - rect->set_fill_color (rv->get_fill_color()); - } + { + ArdourCanvas::Rectangle *rect = dynamic_cast (item); + if (rect) { + rect->set_fill_color (UIConfiguration::instance().color ("inactive fade handle")); } - 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 (UIConfiguration::instance().color ("zero line")); + } + break; default: break; @@ -2115,16 +1952,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) { @@ -2235,28 +2062,13 @@ 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 ()) { - handled = _drags->motion_handler (event, from_autoscroll); + return _drags->motion_handler (event, from_autoscroll); } - if (!handled) { - return false; - } - - track_canvas_motion (event); - return true; + return false; } bool @@ -2266,7 +2078,7 @@ Editor::can_remove_control_point (ArdourCanvas::Item* item) if ((control_point = reinterpret_cast (item->get_data ("control_point"))) == 0) { fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg; - /*NOTREACHED*/ + abort(); /*NOTREACHED*/ } AutomationLine& line = control_point->line (); @@ -2291,7 +2103,7 @@ Editor::remove_control_point (ArdourCanvas::Item* item) if ((control_point = reinterpret_cast (item->get_data ("control_point"))) == 0) { fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg; - /*NOTREACHED*/ + abort(); /*NOTREACHED*/ } control_point->line().remove_point (*control_point); @@ -2304,11 +2116,10 @@ Editor::edit_control_point (ArdourCanvas::Item* item) if (p == 0) { fatal << _("programming error: control point canvas item has no control point object pointer!") << endmsg; - /*NOTREACHED*/ + abort(); /*NOTREACHED*/ } ControlPointDialog d (p); - ensure_float (d); if (d.run () != RESPONSE_ACCEPT) { return; @@ -2318,32 +2129,39 @@ Editor::edit_control_point (ArdourCanvas::Item* item) } void -Editor::edit_notes (TimeAxisViewItem& tavi) +Editor::edit_notes (MidiRegionView* mrv) { - MidiRegionView* mrv = dynamic_cast(&tavi); - - if (!mrv) { - return; - } - MidiRegionView::Selection const & s = mrv->selection(); if (s.empty ()) { return; } - - EditNoteDialog* d = new EditNoteDialog (&(*s.begin())->region_view(), s); - d->show_all (); - ensure_float (*d); - d->signal_response().connect (sigc::bind (sigc::mem_fun (*this, &Editor::note_edit_done), d)); + EditNoteDialog* d = new EditNoteDialog (mrv, s); + d->show_all (); + + 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; + begin_reversible_command (_("edit note(s)")); + + d->done (r); + delete d; + + commit_reversible_command(); +} + +void +Editor::edit_region (RegionView* rv) +{ + if (UIConfiguration::instance().get_use_double_click_to_zoom_to_selection()) { + temporal_zoom_selection (Both); + } else { + rv->show_region_editor (); + } } void @@ -2356,7 +2174,7 @@ Editor::visible_order_range (int* low, int* high) const RouteTimeAxisView* rtv = dynamic_cast (*i); - if (!rtv->hidden()) { + if (rtv && !rtv->hidden()) { if (*high < rtv->order()) { *high = rtv->order (); @@ -2413,7 +2231,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); } @@ -2431,12 +2249,12 @@ 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 (); clicked_selection = 0; -} +} void Editor::point_trim (GdkEvent* event, framepos_t new_bound) @@ -2471,7 +2289,7 @@ Editor::point_trim (GdkEvent* event, framepos_t new_bound) break; case 2: - begin_reversible_command (_("End point trim")); + begin_reversible_command (_("end point trim")); if (selection->selected (rv)) { @@ -2504,30 +2322,18 @@ Editor::point_trim (GdkEvent* event, framepos_t new_bound) void Editor::hide_marker (ArdourCanvas::Item* item, GdkEvent* /*event*/) { - Marker* marker; + ArdourMarker* marker; bool is_start; - if ((marker = static_cast (item->get_data ("marker"))) == 0) { + if ((marker = static_cast (item->get_data ("marker"))) == 0) { fatal << _("programming error: marker canvas item has no marker object pointer!") << endmsg; - /*NOTREACHED*/ + abort(); /*NOTREACHED*/ } Location* location = find_location_from_marker (marker, is_start); location->set_hidden (true, this); } - -void -Editor::reposition_zoom_rect (framepos_t start, framepos_t end) -{ - 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)); -} - - gint Editor::mouse_rename_region (ArdourCanvas::Item* /*item*/, GdkEvent* /*event*/) { @@ -2581,7 +2387,7 @@ Editor::mouse_brush_insert_region (RegionView* rv, framepos_t pos) RouteTimeAxisView* rtv = dynamic_cast(&rv->get_time_axis_view()); - if (rtv == 0 || !rtv->is_track()) { + if (!rtv || !rtv->is_track()) { return; } @@ -2595,7 +2401,7 @@ Editor::mouse_brush_insert_region (RegionView* rv, framepos_t pos) // playlist is frozen, so we have to update manually XXX this is disgusting - playlist->RegionAdded (new_region); /* EMIT SIGNAL */ + //playlist->RegionAdded (new_region); /* EMIT SIGNAL */ } gint @@ -2617,12 +2423,17 @@ Editor::add_region_drag (ArdourCanvas::Item* item, GdkEvent*, RegionView* region return; } - _region_motion_group->raise_to_top (); + switch (Config->get_edit_mode()) { + case Splice: + _drags->add (new RegionSpliceDrag (this, item, region_view, selection->regions.by_layer())); + break; + case Ripple: + _drags->add (new RegionRippleDrag (this, item, region_view, selection->regions.by_layer())); + break; + default: + _drags->add (new RegionMoveDrag (this, item, region_view, selection->regions.by_layer(), false, false)); + break; - if (Config->get_edit_mode() == Splice) { - _drags->add (new RegionSpliceDrag (this, item, region_view, selection->regions.by_layer())); - } else { - _drags->add (new RegionMoveDrag (this, item, region_view, selection->regions.by_layer(), false, false)); } } @@ -2635,8 +2446,6 @@ Editor::add_region_copy_drag (ArdourCanvas::Item* item, GdkEvent*, RegionView* r return; } - _region_motion_group->raise_to_top (); - _drags->add (new RegionMoveDrag (this, item, region_view, selection->regions.by_layer(), false, true)); } @@ -2649,13 +2458,11 @@ Editor::add_region_brush_drag (ArdourCanvas::Item* item, GdkEvent*, RegionView* return; } - if (Config->get_edit_mode() == Splice) { + if (Config->get_edit_mode() == Splice || Config->get_edit_mode() == Ripple) { return; } _drags->add (new RegionMoveDrag (this, item, region_view, selection->regions.by_layer(), true, false)); - - begin_reversible_command (Operations::drag_region_brush); } /** Start a grab where a time range is selected, track(s) are selected, and the @@ -2695,7 +2502,6 @@ Editor::start_selection_grab (ArdourCanvas::Item* /*item*/, GdkEvent* event) /* A selection grab currently creates two undo/redo operations, one for creating the new region and another for moving it. */ - begin_reversible_command (Operations::selection_grab); boost::shared_ptr playlist = clicked_axisview->playlist(); @@ -2704,20 +2510,22 @@ Editor::start_selection_grab (ArdourCanvas::Item* /*item*/, GdkEvent* event) clicked_routeview->playlist()->add_region (region, selection->time[clicked_selection].start); _session->add_command(new StatefulDiffCommand (playlist)); - commit_reversible_command (); - c.disconnect (); if (latest_regionviews.empty()) { /* something went wrong */ + abort_reversible_command (); return; } /* we need to deselect all other regionviews, and select this one i'm ignoring undo stuff, because the region creation will take care of it */ + selection->set (latest_regionviews); + commit_reversible_command (); + _drags->set (new RegionMoveDrag (this, latest_regionviews.front()->get_canvas_group(), latest_regionviews.front(), latest_regionviews, false, false), event); } @@ -2729,90 +2537,78 @@ Editor::escape () } else { selection->clear (); } -} - -void -Editor::set_internal_edit (bool yn) -{ - if (_internal_editing == yn) { - return; - } - - _internal_editing = yn; - - if (yn) { - 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 (); - } - - set_snap_to (internal_snap_type); - set_snap_mode (internal_snap_mode); - - } else { - - 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 (); - } - - 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 (); + ARDOUR_UI::instance()->reset_focus (&contents()); } -/** 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. +/** 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 (!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); + if (entered_regionview) { + + //ToDo: there is currently a bug here(?) + //when we are inside a region fade handle, it acts as though we are in range mode because it is in the top half of the region + //can it be fixed here? - if (tvp.first) { + 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(); - RouteTimeAxisView* rtv = dynamic_cast (tvp.first); - if (rtv) { + _join_object_range_state = c <= 0.5 ? JOIN_OBJECT_RANGE_RANGE : JOIN_OBJECT_RANGE_OBJECT; + + Editor::EnterContext* ctx = get_enter_context(RegionItem); + if (_join_object_range_state != old && ctx) { + ctx->cursor_ctx->change(which_track_cursor()); + } + + } else if (entered_track) { + + RouteTimeAxisView* entered_route_view = dynamic_cast (entered_track); + + if (entered_route_view) { double cx = 0; double cy = y; - rtv->canvas_display()->canvas_to_item (cx, cy); - double const c = cy / (rtv->view()->child_height() - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE); + entered_route_view->canvas_display()->canvas_to_item (cx, cy); + + double track_height = entered_route_view->view()->child_height(); + if (UIConfiguration::instance().get_show_name_highlight()) { + track_height -= TimeAxisViewItem::NAME_HIGHLIGHT_SIZE; + } + double const c = cy / track_height; + - _join_object_range_state = c <= 0.5 ? JOIN_OBJECT_RANGE_RANGE : JOIN_OBJECT_RANGE_OBJECT; + if (c <= 0.5) { + _join_object_range_state = JOIN_OBJECT_RANGE_RANGE; + } else { + _join_object_range_state = JOIN_OBJECT_RANGE_OBJECT; + } + + } else { + /* Other kinds of tracks use object mode */ + _join_object_range_state = JOIN_OBJECT_RANGE_OBJECT; + } + + Editor::EnterContext* ctx = get_enter_context(StreamItem); + if (_join_object_range_state != old && ctx) { + ctx->cursor_ctx->change(which_track_cursor()); } } } @@ -2838,46 +2634,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; - } - - assert (rv); - - 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 ()); - - /* Halfway across the region */ - double const h = (parent_bbox.x0 + parent_bbox.x1) / 2; - - 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); - } - } -} - /** Obtain the pointer position in canvas coordinates */ void Editor::get_pointer_position (double& x, double& y) const