X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor_mouse.cc;h=b3343c42c33fd8dc79dd312aac96b9b3d04c0309;hb=3a3780249ad4c4e98da317fd18a40890c0cf78b9;hp=ebc17e41f75c95397eb9b3431a1c675a8bc28424;hpb=1c060502b5b7623fe30edbcf9a21609a69202ce0;p=ardour.git diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index ebc17e41f7..b3343c42c3 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -75,21 +75,21 @@ Editor::mouse_frame (nframes64_t& where, bool& in_track_canvas) const int x, y; double wx, wy; Gdk::ModifierType mask; - Glib::RefPtr canvas_window = const_cast(this)->track_canvas.get_window(); + Glib::RefPtr canvas_window = const_cast(this)->track_canvas->get_window(); Glib::RefPtr pointer_window; pointer_window = canvas_window->get_pointer (x, y, mask); - if (pointer_window == track_canvas.get_bin_window()) { + if (pointer_window == track_canvas->get_bin_window()) { - track_canvas.window_to_world (x, y, wx, wy); + track_canvas->window_to_world (x, y, wx, wy); in_track_canvas = true; } else { in_track_canvas = false; - if (pointer_window == time_canvas.get_bin_window()) { - time_canvas.window_to_world (x, y, wx, wy); + if (pointer_window == time_canvas->get_bin_window()) { + time_canvas->window_to_world (x, y, wx, wy); } else { return false; } @@ -127,18 +127,18 @@ Editor::event_frame (GdkEvent* event, double* pcx, double* pcy) const case GDK_BUTTON_PRESS: case GDK_2BUTTON_PRESS: case GDK_3BUTTON_PRESS: - track_canvas.w2c(event->button.x, event->button.y, *pcx, *pcy); + track_canvas->w2c(event->button.x, event->button.y, *pcx, *pcy); break; case GDK_MOTION_NOTIFY: - track_canvas.w2c(event->motion.x, event->motion.y, *pcx, *pcy); + track_canvas->w2c(event->motion.x, event->motion.y, *pcx, *pcy); break; case GDK_ENTER_NOTIFY: case GDK_LEAVE_NOTIFY: - track_canvas.w2c(event->crossing.x, event->crossing.y, *pcx, *pcy); + 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); + // 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; @@ -202,6 +202,53 @@ Editor::mouse_mode_toggled (MouseMode m) } } +Gdk::Cursor* +Editor::which_grabber_cursor () +{ + switch (_edit_point) { + case EditAtMouse: + return grabber_edit_point_cursor; + break; + default: + return grabber_cursor; + break; + } +} + +void +Editor::set_canvas_cursor () +{ + switch (mouse_mode) { + case MouseRange: + current_canvas_cursor = selector_cursor; + break; + + case MouseObject: + current_canvas_cursor = which_grabber_cursor(); + break; + + case MouseGain: + current_canvas_cursor = cross_hair_cursor; + break; + + case MouseZoom: + current_canvas_cursor = zoom_cursor; + break; + + case MouseTimeFX: + current_canvas_cursor = time_fx_cursor; // just use playhead + break; + + case MouseAudition: + current_canvas_cursor = speaker_cursor; + break; + } + + if (is_drawable()) { + track_canvas->get_window()->set_cursor(*current_canvas_cursor); + } +} + void Editor::set_mouse_mode (MouseMode m, bool force) { @@ -243,7 +290,7 @@ Editor::set_mouse_mode (MouseMode m, bool force) } } - /* XXX the hack of unsetting all other buttongs should go + /* XXX the hack of unsetting all other buttons should go away once GTK2 allows us to use regular radio buttons drawn like normal buttons, rather than my silly GroupedButton hack. */ @@ -253,40 +300,32 @@ Editor::set_mouse_mode (MouseMode m, bool force) switch (mouse_mode) { case MouseRange: mouse_select_button.set_active (true); - current_canvas_cursor = selector_cursor; break; case MouseObject: mouse_move_button.set_active (true); - current_canvas_cursor = grabber_cursor; break; case MouseGain: mouse_gain_button.set_active (true); - current_canvas_cursor = cross_hair_cursor; break; case MouseZoom: mouse_zoom_button.set_active (true); - current_canvas_cursor = zoom_cursor; break; case MouseTimeFX: mouse_timefx_button.set_active (true); - current_canvas_cursor = time_fx_cursor; // just use playhead break; case MouseAudition: mouse_audition_button.set_active (true); - current_canvas_cursor = speaker_cursor; break; } ignore_mouse_mode_toggle = false; - - if (is_drawable()) { - track_canvas.get_window()->set_cursor(*current_canvas_cursor); - } + + set_canvas_cursor (); } void @@ -328,8 +367,6 @@ Editor::step_mouse_mode (bool next) void Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type) { - bool commit = false; - /* in object/audition/timefx mode, any button press sets the selection if the object can be selected. this is a bit of hack, because we want to avoid this if the @@ -368,18 +405,18 @@ Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType it switch (item_type) { case RegionItem: if (mouse_mode != MouseRange) { - commit = set_selected_regionview_from_click (press, op, true); + set_selected_regionview_from_click (press, op, true); } else if (event->type == GDK_BUTTON_PRESS) { - commit = set_selected_track_from_click (press, op, false); + set_selected_track_as_side_effect (); } break; case RegionViewNameHighlight: case RegionViewName: if (mouse_mode != MouseRange) { - commit = set_selected_regionview_from_click (press, op, true); + set_selected_regionview_from_click (press, op, true); } else if (event->type == GDK_BUTTON_PRESS) { - commit = set_selected_track_from_click (press, op, false); + set_selected_track_as_side_effect (); } break; @@ -388,41 +425,37 @@ Editor::button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType it case FadeOutHandleItem: case FadeOutItem: if (mouse_mode != MouseRange) { - commit = set_selected_regionview_from_click (press, op, true); + set_selected_regionview_from_click (press, op, true); } else if (event->type == GDK_BUTTON_PRESS) { - commit = set_selected_track_from_click (press, op, false); + set_selected_track_as_side_effect (); } break; case GainAutomationControlPointItem: case PanAutomationControlPointItem: case RedirectAutomationControlPointItem: - commit = set_selected_track_from_click (press, op, true); + set_selected_track_as_side_effect (); if (mouse_mode != MouseRange) { - commit |= set_selected_control_point_from_click (op, false); + set_selected_control_point_from_click (op, false); } break; case StreamItem: /* for context click or range selection, select track */ if (event->button.button == 3) { - commit = set_selected_track_from_click (press, op, true); + set_selected_track_as_side_effect (); } else if (event->type == GDK_BUTTON_PRESS && mouse_mode == MouseRange) { - commit = set_selected_track_from_click (press, op, false); + set_selected_track_as_side_effect (); } break; case AutomationTrackItem: - commit = set_selected_track_from_click (press, op, true); + set_selected_track_as_side_effect (true); break; default: break; } - -// if (commit) { -// commit_reversible_command (); -// } } const static double ZERO_GAIN_FRACTION = gain_to_slider_position(dB_to_coefficient(0.0)); @@ -430,7 +463,7 @@ const static double ZERO_GAIN_FRACTION = gain_to_slider_position(dB_to_coefficie bool Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type) { - track_canvas.grab_focus(); + track_canvas->grab_focus(); if (session && session->actively_recording()) { return true; @@ -468,7 +501,7 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp return true; case MarkerItem: - if (Keyboard::modifier_state_equals (event->button.state, Keyboard::ModifierMask(Keyboard::Control|Keyboard::Shift))) { + if (Keyboard::modifier_state_equals (event->button.state, Keyboard::ModifierMask(Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) { hide_marker (item, event); } else { start_marker_grab (item, event); @@ -476,7 +509,7 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp return true; case TempoMarkerItem: - if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) { + if (Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier)) { start_tempo_marker_copy_grab (item, event); } else { start_tempo_marker_grab (item, event); @@ -484,7 +517,7 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp return true; case MeterMarkerItem: - if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) { + if (Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier)) { start_meter_marker_copy_grab (item, event); } else { start_meter_marker_grab (item, event); @@ -502,6 +535,11 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp return true; break; + case CdMarkerBarItem: + start_range_markerbar_op (item, event, CreateCDMarker); + return true; + break; + case TransportMarkerBarItem: start_range_markerbar_op (item, event, CreateTransportMarker); return true; @@ -525,14 +563,13 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp case SelectionItem: if (Keyboard::modifier_state_contains - (event->button.state, Keyboard::ModifierMask(Keyboard::Alt))) { + (event->button.state, Keyboard::ModifierMask(Keyboard::SecondaryModifier))) { // contains and not equals because I can't use alt as a modifier alone. start_selection_grab (item, event); - } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) { + } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) { /* grab selection for moving */ start_selection_op (item, event, SelectionMove); - } - else { + } else { /* this was debated, but decided the more common action was to make a new selection */ start_selection_op (item, event, CreateSelection); @@ -546,7 +583,7 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp break; case MouseObject: - if (Keyboard::modifier_state_contains (event->button.state, Keyboard::ModifierMask(Keyboard::Control|Keyboard::Alt)) && + if (Keyboard::modifier_state_contains (event->button.state, Keyboard::ModifierMask(Keyboard::PrimaryModifier|Keyboard::SecondaryModifier)) && event->type == GDK_BUTTON_PRESS) { start_rubberband_select (item, event); @@ -563,7 +600,7 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp return true; case RegionItem: - if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) { + if (Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier)) { start_region_copy_grab (item, event); } else if (Keyboard::the_keyboard().key_is_down (GDK_b)) { start_region_brush_grab (item, event); @@ -709,8 +746,11 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp case MouseAudition: _scrubbing = true; + scrub_reversals = 0; + scrub_reverse_distance = 0; last_scrub_x = event->button.x; scrubbing_direction = 0; + track_canvas->get_window()->set_cursor (*transparent_cursor); /* rest handled in motion & release */ break; @@ -725,13 +765,14 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp if (event->type == GDK_BUTTON_PRESS) { switch (item_type) { case RegionItem: - if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) { + if (Keyboard::modifier_state_contains (event->button.state, Keyboard::CopyModifier)) { start_region_copy_grab (item, event); } else { start_region_grab (item, event); } - + return true; break; + case GainAutomationControlPointItem: case PanAutomationControlPointItem: case RedirectAutomationControlPointItem: @@ -771,7 +812,7 @@ Editor::button_press_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemTyp case MouseZoom: - if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) { + if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) { temporal_zoom_session(); } else { temporal_zoom_to_frame (true, event_frame(event)); @@ -800,6 +841,7 @@ bool Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type) { nframes_t where = event_frame (event, 0, 0); + AutomationTimeAxisView* atv = 0; /* no action if we're recording */ @@ -884,7 +926,8 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT case MarkerBarItem: case RangeMarkerBarItem: - case TransportMarkerBarItem: + case TransportMarkerBarItem: + case CdMarkerBarItem: case TempoBarItem: case MeterBarItem: popup_ruler_menu (pixel_to_frame(event->button.x), item_type); @@ -993,6 +1036,14 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT mouse_add_new_marker (where); return true; + case CdMarkerBarItem: + // if we get here then a dragged range wasn't done + if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) { + snap_to (where, 0, true); + } + mouse_add_new_marker (where, true); + return true; + case TempoBarItem: if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) { snap_to (where); @@ -1013,14 +1064,14 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT case MouseObject: switch (item_type) { case AutomationTrackItem: - dynamic_cast(clicked_trackview)->add_automation_event - (item, - event, - where, - event->button.y); + atv = dynamic_cast(clicked_trackview); + if (atv) { + atv->add_automation_event (item, event, where, event->button.y); + } return true; + break; - + default: break; } @@ -1051,11 +1102,12 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT case MouseAudition: _scrubbing = false; + track_canvas->get_window()->set_cursor (*current_canvas_cursor); if (scrubbing_direction == 0) { /* no drag, just a click */ switch (item_type) { case RegionItem: - audition_selected_region (); + play_selected_region (); break; default: break; @@ -1081,9 +1133,9 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT case MouseObject: switch (item_type) { case RegionItem: - if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) { + if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) { raise_region (); - } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::ModifierMask (Keyboard::Shift|Keyboard::Alt))) { + } else if (Keyboard::modifier_state_equals (event->button.state, Keyboard::ModifierMask (Keyboard::TertiaryModifier|Keyboard::SecondaryModifier))) { lower_region (); } else { // Button2 click is unused @@ -1125,6 +1177,11 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ Marker * marker; double fraction; + if (last_item_entered != item) { + last_item_entered = item; + last_item_entered_n = 0; + } + switch (item_type) { case GainControlPointItem: if (mouse_mode == MouseGain) { @@ -1140,11 +1197,14 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ fraction = 1.0 - (cp->get_y() / cp->line.height()); - set_verbose_canvas_cursor (cp->line.get_verbose_cursor_string (fraction), at_x, at_y); - show_verbose_canvas_cursor (); + if (is_drawable() && !_scrubbing) { + track_canvas->get_window()->set_cursor (*fader_cursor); + } - if (is_drawable()) { - track_canvas.get_window()->set_cursor (*fader_cursor); + last_item_entered_n++; + set_verbose_canvas_cursor (cp->line.get_verbose_cursor_string (fraction), at_x, at_y); + if (last_item_entered_n < 10) { + show_verbose_canvas_cursor (); } } break; @@ -1169,7 +1229,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ show_verbose_canvas_cursor (); if (is_drawable()) { - track_canvas.get_window()->set_cursor (*fader_cursor); + track_canvas->get_window()->set_cursor (*fader_cursor); } } break; @@ -1180,7 +1240,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ if (line) line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_EnteredGainLine.get(); if (is_drawable()) { - track_canvas.get_window()->set_cursor (*fader_cursor); + track_canvas->get_window()->set_cursor (*fader_cursor); } } break; @@ -1195,14 +1255,14 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_EnteredAutomationLine.get(); } if (is_drawable()) { - track_canvas.get_window()->set_cursor (*fader_cursor); + track_canvas->get_window()->set_cursor (*fader_cursor); } } break; case RegionViewNameHighlight: if (is_drawable() && mouse_mode == MouseObject) { - track_canvas.get_window()->set_cursor (*trimmer_cursor); + track_canvas->get_window()->set_cursor (*trimmer_cursor); } break; @@ -1216,13 +1276,20 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ /* */ if (is_drawable()) { - track_canvas.get_window()->set_cursor (*trimmer_cursor); + track_canvas->get_window()->set_cursor (*trimmer_cursor); } break; case PlayheadCursorItem: if (is_drawable()) { - track_canvas.get_window()->set_cursor (*grabber_cursor); + switch (_edit_point) { + case EditAtMouse: + track_canvas->get_window()->set_cursor (*grabber_edit_point_cursor); + break; + default: + track_canvas->get_window()->set_cursor (*grabber_cursor); + break; + } } break; @@ -1232,7 +1299,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ if (!reinterpret_cast (item->get_data ("regionview"))->name_active()) { if (mouse_mode == MouseObject && is_drawable()) { - track_canvas.get_window()->set_cursor (*trimmer_cursor); + track_canvas->get_window()->set_cursor (*trimmer_cursor); } } break; @@ -1253,7 +1320,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ break; } - track_canvas.get_window()->set_cursor (*cursor); + track_canvas->get_window()->set_cursor (*cursor); AutomationTimeAxisView* atv; if ((atv = static_cast(item->get_data ("trackview"))) != 0) { @@ -1266,10 +1333,11 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ case MarkerBarItem: case RangeMarkerBarItem: case TransportMarkerBarItem: + case CdMarkerBarItem: case MeterBarItem: case TempoBarItem: if (is_drawable()) { - time_canvas.get_window()->set_cursor (*timebar_cursor); + time_canvas->get_window()->set_cursor (*timebar_cursor); } break; @@ -1283,7 +1351,7 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ case MeterMarkerItem: case TempoMarkerItem: if (is_drawable()) { - time_canvas.get_window()->set_cursor (*timebar_cursor); + time_canvas->get_window()->set_cursor (*timebar_cursor); } break; case FadeInHandleItem: @@ -1352,7 +1420,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ } if (is_drawable()) { - track_canvas.get_window()->set_cursor (*current_canvas_cursor); + track_canvas->get_window()->set_cursor (*current_canvas_cursor); } hide_verbose_canvas_cursor (); @@ -1369,7 +1437,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ case MarkerViewHandleEndItem: /* */ if (is_drawable()) { - track_canvas.get_window()->set_cursor (*current_canvas_cursor); + track_canvas->get_window()->set_cursor (*current_canvas_cursor); } break; @@ -1384,7 +1452,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ line->property_fill_color_rgba() = al->get_line_color(); } if (is_drawable()) { - track_canvas.get_window()->set_cursor (*current_canvas_cursor); + track_canvas->get_window()->set_cursor (*current_canvas_cursor); } break; @@ -1392,18 +1460,19 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ /* see enter_handler() for notes */ if (!reinterpret_cast (item->get_data ("regionview"))->name_active()) { if (is_drawable() && mouse_mode == MouseObject) { - track_canvas.get_window()->set_cursor (*current_canvas_cursor); + track_canvas->get_window()->set_cursor (*current_canvas_cursor); } } break; case RangeMarkerBarItem: case TransportMarkerBarItem: + case CdMarkerBarItem: case MeterBarItem: case TempoBarItem: case MarkerBarItem: if (is_drawable()) { - time_canvas.get_window()->set_cursor (*timebar_cursor); + time_canvas->get_window()->set_cursor (*timebar_cursor); } break; @@ -1420,7 +1489,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ case TempoMarkerItem: if (is_drawable()) { - time_canvas.get_window()->set_cursor (*timebar_cursor); + time_canvas->get_window()->set_cursor (*timebar_cursor); } break; @@ -1439,7 +1508,7 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ case AutomationTrackItem: if (is_drawable()) { - track_canvas.get_window()->set_cursor (*current_canvas_cursor); + track_canvas->get_window()->set_cursor (*current_canvas_cursor); clear_entered_track = true; Glib::signal_idle().connect (mem_fun(*this, &Editor::left_automation_track)); } @@ -1462,21 +1531,102 @@ Editor::left_automation_track () return false; } +void +Editor::scrub () +{ + double delta; + + if (scrubbing_direction == 0) { + /* first move */ + session->request_locate (drag_info.current_pointer_frame, false); + session->request_transport_speed (0.1); + scrubbing_direction = 1; + + } else { + + if (last_scrub_x > drag_info.current_pointer_x) { + + /* pointer moved to the left */ + + if (scrubbing_direction > 0) { + + /* we reversed direction to go backwards */ + + scrub_reversals++; + scrub_reverse_distance += (int) (last_scrub_x - drag_info.current_pointer_x); + + } else { + + /* still moving to the left (backwards) */ + + scrub_reversals = 0; + scrub_reverse_distance = 0; + + delta = 0.01 * (last_scrub_x - drag_info.current_pointer_x); + session->request_transport_speed (session->transport_speed() - delta); + } + + } else { + /* pointer moved to the right */ + + if (scrubbing_direction < 0) { + /* we reversed direction to go forward */ + + scrub_reversals++; + scrub_reverse_distance += (int) (drag_info.current_pointer_x - last_scrub_x); + + } else { + /* still moving to the right */ + + scrub_reversals = 0; + scrub_reverse_distance = 0; + + delta = 0.01 * (drag_info.current_pointer_x - last_scrub_x); + session->request_transport_speed (session->transport_speed() + delta); + } + } + + /* if there have been more than 2 opposite motion moves detected, or one that moves + back more than 10 pixels, reverse direction + */ + + if (scrub_reversals >= 2 || scrub_reverse_distance > 10) { + + if (scrubbing_direction > 0) { + /* was forwards, go backwards */ + session->request_transport_speed (-0.1); + scrubbing_direction = -1; + } else { + /* was backwards, go forwards */ + session->request_transport_speed (0.1); + scrubbing_direction = 1; + } + + scrub_reverse_distance = 0; + scrub_reversals = 0; + } + } + + last_scrub_x = drag_info.current_pointer_x; +} + bool Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type, bool from_autoscroll) { - gint x, y; - - /* We call this so that MOTION_NOTIFY events continue to be - delivered to the canvas. We need to do this because we set - Gdk::POINTER_MOTION_HINT_MASK on the canvas. This reduces - the density of the events, at the expense of a round-trip - to the server. Given that this will mostly occur on cases - where DISPLAY = :0.0, and given the cost of what the motion - event might do, its a good tradeoff. - */ - - track_canvas.get_pointer (x, y); + if (event->motion.is_hint) { + gint x, y; + + /* We call this so that MOTION_NOTIFY events continue to be + delivered to the canvas. We need to do this because we set + Gdk::POINTER_MOTION_HINT_MASK on the canvas. This reduces + the density of the events, at the expense of a round-trip + to the server. Given that this will mostly occur on cases + where DISPLAY = :0.0, and given the cost of what the motion + event might do, its a good tradeoff. + */ + + track_canvas->get_pointer (x, y); + } if (current_stepping_trackview) { /* don't keep the persistent stepped trackview if the mouse moves */ @@ -1495,57 +1645,13 @@ Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item drag_info.current_pointer_frame = event_frame (event, &drag_info.current_pointer_x, &drag_info.current_pointer_y); + switch (mouse_mode) { case MouseAudition: if (_scrubbing) { - - double delta; - - if (scrubbing_direction == 0) { - /* first move */ - session->request_locate (drag_info.current_pointer_frame, false); - session->request_transport_speed (0.1); - scrubbing_direction = 1; - - } else { - - - if (last_scrub_x > drag_info.current_pointer_x) { - /* move to the left */ - - if (scrubbing_direction > 0) { - /* we reversed direction to go backwards */ - - session->request_transport_speed (-0.1); - - } else { - /* still moving to the left (backwards) */ - - delta = 0.005 * (last_scrub_x - drag_info.current_pointer_x); - session->request_transport_speed (session->transport_speed() - delta); - } - - scrubbing_direction = -1; - - } else { - /* move to the right */ - if (scrubbing_direction < 0) { - /* we reversed direction to go forward */ - - session->request_transport_speed (0.1); - } else { - /* still moving to the right */ - - delta = 0.005 * (drag_info.current_pointer_x - last_scrub_x); - session->request_transport_speed (session->transport_speed() + delta); - } - - scrubbing_direction = 1; - } - } - - last_scrub_x = drag_info.current_pointer_x; + scrub (); } + break; default: break; @@ -1601,7 +1707,7 @@ Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item if (drag_info.item && (event->motion.state & Gdk::BUTTON1_MASK || (event->motion.state & Gdk::BUTTON2_MASK))) { if (!from_autoscroll) { - maybe_autoscroll (event); + maybe_autoscroll (&event->motion); } (this->*(drag_info.motion_callback)) (item, event); goto handled; @@ -1620,7 +1726,7 @@ Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item if (drag_info.item && (event->motion.state & GDK_BUTTON1_MASK || (event->motion.state & GDK_BUTTON2_MASK))) { if (!from_autoscroll) { - maybe_autoscroll (event); + maybe_autoscroll (&event->motion); } (this->*(drag_info.motion_callback)) (item, event); goto handled; @@ -1641,6 +1747,48 @@ Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item return false; } +void +Editor::break_drag () +{ + stop_canvas_autoscroll (); + hide_verbose_canvas_cursor (); + + if (drag_info.item) { + drag_info.item->ungrab (0); + + /* put it back where it came from */ + + double cxw, cyw; + cxw = 0; + cyw = 0; + drag_info.item->i2w (cxw, cyw); + drag_info.item->move (drag_info.original_x - cxw, drag_info.original_y - cyw); + } + + finalize_drag (); +} + +void +Editor::finalize_drag () +{ + drag_info.item = 0; + drag_info.copy = false; + drag_info.motion_callback = 0; + drag_info.finished_callback = 0; + drag_info.dest_trackview = 0; + drag_info.source_trackview = 0; + drag_info.last_frame_position = 0; + drag_info.grab_frame = 0; + drag_info.last_pointer_frame = 0; + drag_info.current_pointer_frame = 0; + drag_info.brushing = false; + + if (drag_info.copied_location) { + delete drag_info.copied_location; + drag_info.copied_location = 0; + } +} + void Editor::start_grab (GdkEvent* event, Gdk::Cursor *cursor) { @@ -1651,13 +1799,13 @@ Editor::start_grab (GdkEvent* event, Gdk::Cursor *cursor) } if (cursor == 0) { - cursor = grabber_cursor; + cursor = which_grabber_cursor (); } // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained if (event->button.button == 2) { - if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Alt)) { + if (Keyboard::modifier_state_equals (event->button.state, Keyboard::SecondaryModifier)) { drag_info.y_constrained = true; drag_info.x_constrained = false; } else { @@ -1685,6 +1833,10 @@ Editor::start_grab (GdkEvent* event, Gdk::Cursor *cursor) drag_info.brushing = false; drag_info.copied_location = 0; + drag_info.original_x = 0; + drag_info.original_y = 0; + drag_info.item->i2w (drag_info.original_x, drag_info.original_y); + drag_info.item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK, *cursor, event->button.time); @@ -1714,7 +1866,7 @@ Editor::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t t drag_info.item = new_item; if (cursor == 0) { - cursor = grabber_cursor; + cursor = which_grabber_cursor (); } drag_info.item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK, *cursor, time); @@ -1743,21 +1895,7 @@ Editor::end_grab (ArdourCanvas::Item* item, GdkEvent* event) hide_verbose_canvas_cursor(); - drag_info.item = 0; - drag_info.copy = false; - drag_info.motion_callback = 0; - drag_info.finished_callback = 0; - drag_info.last_trackview = 0; - drag_info.last_frame_position = 0; - drag_info.grab_frame = 0; - drag_info.last_pointer_frame = 0; - drag_info.current_pointer_frame = 0; - drag_info.brushing = false; - - if (drag_info.copied_location) { - delete drag_info.copied_location; - drag_info.copied_location = 0; - } + finalize_drag (); return did_drag; } @@ -1861,6 +1999,7 @@ Editor::fade_in_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* even XMLNode &before = alist.get_state(); tmp->audio_region()->set_fade_in_length (fade_length); + tmp->audio_region()->set_fade_in_active (true); XMLNode &after = alist.get_state(); session->add_command(new MementoCommand(alist, &before, &after)); @@ -1977,6 +2116,7 @@ Editor::fade_out_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* eve XMLNode &before = alist.get_state(); tmp->audio_region()->set_fade_out_length (fade_length); + tmp->audio_region()->set_fade_out_active (true); XMLNode &after = alist.get_state(); session->add_command(new MementoCommand(alist, &before, &after)); @@ -2032,7 +2172,7 @@ Editor::cursor_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) } if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) { - if (cursor == playhead_cursor && snap_type != SnapToEditPoint) { + if (cursor == playhead_cursor) { snap_to (adjusted_frame); } } @@ -2103,6 +2243,8 @@ Editor::start_marker_grab (ArdourCanvas::Item* item, GdkEvent* event) start_grab (event); + _dragging_edit_point = true; + drag_info.copied_location = new Location (*location); drag_info.pointer_frame_offset = drag_info.grab_frame - (is_start ? location->start() : location->end()); @@ -2150,7 +2292,6 @@ Editor::marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) bool is_start; bool move_both = false; - nframes_t newframe; if (drag_info.pointer_frame_offset <= drag_info.current_pointer_frame) { newframe = drag_info.current_pointer_frame - drag_info.pointer_frame_offset; @@ -2184,7 +2325,7 @@ Editor::marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) f_delta = copy_location->end() - copy_location->start(); - if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) { + if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) { move_both = true; } @@ -2231,7 +2372,8 @@ Editor::marker_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) LocationMarkers* lm = find_location_markers (real_location); lm->set_position (copy_location->start(), copy_location->end()); - + edit_point_clock.set (copy_location->start()); + show_verbose_time_cursor (newframe, 10); } @@ -2239,9 +2381,11 @@ void Editor::marker_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event) { if (drag_info.first_move) { - marker_drag_motion_callback (item, event); - + /* just a click, do nothing but whatever selection occured */ + return; } + + _dragging_edit_point = false; Marker* marker = (Marker *) drag_info.data; bool is_start; @@ -2292,6 +2436,7 @@ Editor::start_meter_marker_grab (ArdourCanvas::Item* item, GdkEvent* event) } drag_info.item = item; + drag_info.copy = false; drag_info.data = marker; drag_info.motion_callback = &Editor::meter_marker_drag_motion_callback; drag_info.finished_callback = &Editor::meter_marker_drag_finished_callback; @@ -2421,6 +2566,7 @@ Editor::start_tempo_marker_grab (ArdourCanvas::Item* item, GdkEvent* event) } drag_info.item = item; + drag_info.copy = false; drag_info.data = marker; drag_info.motion_callback = &Editor::tempo_marker_drag_motion_callback; drag_info.finished_callback = &Editor::tempo_marker_drag_finished_callback; @@ -2584,7 +2730,7 @@ Editor::start_control_point_grab (ArdourCanvas::Item* item, GdkEvent* event) drag_info.grab_x = control_point->get_x(); drag_info.grab_y = control_point->get_y(); control_point->line.parent_group().i2w(drag_info.grab_x, drag_info.grab_y); - track_canvas.w2c(drag_info.grab_x, drag_info.grab_y, + track_canvas->w2c(drag_info.grab_x, drag_info.grab_y, drag_info.grab_x, drag_info.grab_y); drag_info.grab_frame = pixel_to_frame(drag_info.grab_x); @@ -2606,7 +2752,7 @@ Editor::control_point_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* double dx = drag_info.current_pointer_x - drag_info.last_pointer_x; double dy = drag_info.current_pointer_y - drag_info.last_pointer_y; - if (event->button.state & Keyboard::Alt) { + if (event->button.state & Keyboard::SecondaryModifier) { dx *= 0.1; dy *= 0.1; } @@ -2653,7 +2799,7 @@ Editor::control_point_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* bool push; - if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) { + if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) { push = true; } else { push = false; @@ -2675,7 +2821,7 @@ Editor::control_point_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent /* just a click */ - if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) { + if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) { reset_point_selection (); } @@ -2756,7 +2902,7 @@ Editor::line_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) double dy = drag_info.current_pointer_y - drag_info.last_pointer_y; - if (event->button.state & Keyboard::Alt) { + if (event->button.state & Keyboard::SecondaryModifier) { dy *= 0.1; } @@ -2787,7 +2933,7 @@ Editor::line_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) bool push; - if (Keyboard::modifier_state_contains (event->button.state, Keyboard::Control)) { + if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) { push = false; } else { push = true; @@ -2816,8 +2962,14 @@ Editor::start_region_grab (ArdourCanvas::Item* item, GdkEvent* event) drag_info.copy = false; drag_info.item = item; drag_info.data = clicked_regionview; - drag_info.motion_callback = &Editor::region_drag_motion_callback; - drag_info.finished_callback = &Editor::region_drag_finished_callback; + + if (Config->get_edit_mode() == Splice) { + drag_info.motion_callback = &Editor::region_drag_splice_motion_callback; + drag_info.finished_callback = &Editor::region_drag_splice_finished_callback; + } else { + drag_info.motion_callback = &Editor::region_drag_motion_callback; + drag_info.finished_callback = &Editor::region_drag_finished_callback; + } start_grab (event); @@ -2831,7 +2983,8 @@ Editor::start_region_grab (ArdourCanvas::Item* item, GdkEvent* event) drag_info.last_frame_position = (nframes_t) (clicked_regionview->region()->position() / speed); drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position; - drag_info.last_trackview = &clicked_regionview->get_time_axis_view(); + drag_info.source_trackview = &clicked_regionview->get_time_axis_view(); + drag_info.dest_trackview = drag_info.source_trackview; // we want a move threshold drag_info.want_move_threshold = true; @@ -2861,7 +3014,8 @@ Editor::start_region_copy_grab (ArdourCanvas::Item* item, GdkEvent* event) speed = atv->get_diskstream()->speed(); } - drag_info.last_trackview = &clicked_regionview->get_time_axis_view(); + drag_info.source_trackview = &clicked_regionview->get_time_axis_view(); + drag_info.dest_trackview = drag_info.source_trackview; drag_info.last_frame_position = (nframes_t) (clicked_regionview->region()->position() / speed); drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position; // we want a move threshold @@ -2874,7 +3028,7 @@ Editor::start_region_copy_grab (ArdourCanvas::Item* item, GdkEvent* event) void Editor::start_region_brush_grab (ArdourCanvas::Item* item, GdkEvent* event) { - if (selection->regions.empty() || clicked_regionview == 0) { + if (selection->regions.empty() || clicked_regionview == 0 || Config->get_edit_mode() == Splice) { return; } @@ -2896,7 +3050,8 @@ Editor::start_region_brush_grab (ArdourCanvas::Item* item, GdkEvent* event) drag_info.last_frame_position = (nframes_t) (clicked_regionview->region()->position() / speed); drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position; - drag_info.last_trackview = &clicked_regionview->get_time_axis_view(); + drag_info.source_trackview = &clicked_regionview->get_time_axis_view(); + drag_info.dest_trackview = drag_info.source_trackview; // we want a move threshold drag_info.want_move_threshold = true; drag_info.brushing = true; @@ -2905,23 +3060,13 @@ Editor::start_region_brush_grab (ArdourCanvas::Item* item, GdkEvent* event) } void -Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) +Editor::possibly_copy_regions_during_grab (GdkEvent* event) { - double x_delta; - double y_delta = 0; - RegionView* rv = reinterpret_cast (drag_info.data); - nframes_t pending_region_position = 0; - int32_t pointer_y_span = 0, canvas_pointer_y_span = 0, original_pointer_order; - int32_t visible_y_high = 0, visible_y_low = 512; //high meaning higher numbered.. not the height on the screen - bool clamp_y_axis = false; - vector height_list(512) ; - vector::iterator j; - if (drag_info.copy && drag_info.move_threshold_passed && drag_info.want_move_threshold) { drag_info.want_move_threshold = false; // don't copy again - /* duplicate the region(s) */ + /* duplicate the regionview(s) and region(s) */ vector new_regionviews; @@ -2929,7 +3074,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) RegionView* rv; RegionView* nrv; AudioRegionView* arv; - + rv = (*i); @@ -2937,8 +3082,12 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) /* XXX handle MIDI here */ continue; } + + const boost::shared_ptr original = arv->region(); + boost::shared_ptr region_copy = RegionFactory::create (original); + boost::shared_ptr ar = boost::dynamic_pointer_cast (region_copy); - nrv = new AudioRegionView (*arv); + nrv = new AudioRegionView (*arv, ar); nrv->get_canvas_group()->show (); new_regionviews.push_back (nrv); @@ -2948,35 +3097,140 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) return; } - /* reset selection to new regionviews */ + /* reset selection to new regionviews. This will not set selection visual status for + these regionviews since they don't belong to a track, so do that by hand too. + */ selection->set (new_regionviews); - + + for (vector::iterator i = new_regionviews.begin(); i != new_regionviews.end(); ++i) { + (*i)->set_selected (true); + } + /* reset drag_info data to reflect the fact that we are dragging the copies */ drag_info.data = new_regionviews.front(); swap_grab (new_regionviews.front()->get_canvas_group (), 0, event->motion.time); } +} +bool +Editor::check_region_drag_possible (AudioTimeAxisView** tv) +{ /* Which trackview is this ? */ TimeAxisView* tvp = trackview_by_y_position (drag_info.current_pointer_y); - AudioTimeAxisView* tv = dynamic_cast(tvp); + (*tv) = dynamic_cast(tvp); /* The region motion is only processed if the pointer is over an audio track. */ - if (!tv || !tv->is_audio_track()) { + if (!(*tv) || !(*tv)->is_audio_track()) { /* To make sure we hide the verbose canvas cursor when the mouse is not held over and audiotrack. */ hide_verbose_canvas_cursor (); - return; + return false; } - original_pointer_order = drag_info.last_trackview->order; + return true; +} + +struct RegionSelectionByPosition { + bool operator() (RegionView*a, RegionView* b) { + return a->region()->position () < b->region()->position(); + } +}; + +void +Editor::region_drag_splice_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) +{ + AudioTimeAxisView* tv; + + if (!check_region_drag_possible (&tv)) { + return; + } + + if (!drag_info.move_threshold_passed) { + return; + } + + int dir; + + if (drag_info.current_pointer_x - drag_info.grab_x > 0) { + dir = 1; + } else { + dir = -1; + } + + RegionSelection copy (selection->regions); + + RegionSelectionByPosition cmp; + copy.sort (cmp); + + for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) { + + AudioTimeAxisView* atv = dynamic_cast (&(*i)->get_time_axis_view()); + + if (!atv) { + continue; + } + + boost::shared_ptr playlist; + + if ((playlist = atv->playlist()) == 0) { + continue; + } + + if (!playlist->region_is_shuffle_constrained ((*i)->region())) { + continue; + } + + if (dir > 0) { + if (drag_info.current_pointer_frame < (*i)->region()->last_frame() + 1) { + continue; + } + } else { + if (drag_info.current_pointer_frame > (*i)->region()->first_frame()) { + continue; + } + } + + + playlist->shuffle ((*i)->region(), dir); + + drag_info.grab_x = drag_info.current_pointer_x; + } +} + +void +Editor::region_drag_splice_finished_callback (ArdourCanvas::Item* item, GdkEvent* event) +{ +} + +void +Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) +{ + double x_delta; + double y_delta = 0; + RegionView* rv = reinterpret_cast (drag_info.data); + nframes_t pending_region_position = 0; + int32_t pointer_y_span = 0, canvas_pointer_y_span = 0, original_pointer_order; + int32_t visible_y_high = 0, visible_y_low = 512; //high meaning higher numbered.. not the height on the screen + bool clamp_y_axis = false; + vector height_list(512) ; + vector::iterator j; + AudioTimeAxisView* tv; + + possibly_copy_regions_during_grab (event); + + if (!check_region_drag_possible (&tv)) { + return; + } + + original_pointer_order = drag_info.dest_trackview->order; /************************************************************ Y-Delta Computation @@ -2987,8 +3241,8 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) pointer_y_span = 0; goto y_axis_done; } - - if ((pointer_y_span = (drag_info.last_trackview->order - tv->order)) != 0) { + + if ((pointer_y_span = (drag_info.dest_trackview->order - tv->order)) != 0) { int32_t children = 0, numtracks = 0; // XXX hard coding track limit, oh my, so very very bad @@ -3032,16 +3286,16 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) /* find the actual span according to the canvas */ canvas_pointer_y_span = pointer_y_span; - if (drag_info.last_trackview->order >= tv->order) { + if (drag_info.dest_trackview->order >= tv->order) { int32_t y; - for (y = tv->order; y < drag_info.last_trackview->order; y++) { + for (y = tv->order; y < drag_info.dest_trackview->order; y++) { if (height_list[y] == 0 ) { canvas_pointer_y_span--; } } } else { int32_t y; - for (y = drag_info.last_trackview->order;y <= tv->order; y++) { + for (y = drag_info.dest_trackview->order;y <= tv->order; y++) { if ( height_list[y] == 0 ) { canvas_pointer_y_span++; } @@ -3053,6 +3307,10 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) double ix1, ix2, iy1, iy2; int32_t n = 0; + if (rv2->region()->locked()) { + continue; + } + rv2->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2); rv2->get_canvas_group()->i2w (ix1, iy1); TimeAxisView* tvp2 = trackview_by_y_position (iy1); @@ -3124,13 +3382,13 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) } } - } else if (drag_info.last_trackview == tv) { + } else if (drag_info.dest_trackview == tv) { clamp_y_axis = true; } y_axis_done: if (!clamp_y_axis) { - drag_info.last_trackview = tv; + drag_info.dest_trackview = tv; } /************************************************************ @@ -3141,30 +3399,34 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) the region would be if we moved it by that much. */ - if (drag_info.move_threshold_passed) { + if ( drag_info.move_threshold_passed ) { if (drag_info.current_pointer_frame > drag_info.pointer_frame_offset) { nframes_t sync_frame; nframes_t sync_offset; int32_t sync_dir; - + pending_region_position = drag_info.current_pointer_frame - drag_info.pointer_frame_offset; sync_offset = rv->region()->sync_offset (sync_dir); - sync_frame = rv->region()->adjust_to_sync (pending_region_position); - /* we snap if the snap modifier is not enabled. + /* we don't handle a sync point that lies before zero. */ + if (sync_dir >= 0 || (sync_dir < 0 && pending_region_position >= sync_offset)) { + sync_frame = pending_region_position + (sync_dir*sync_offset); + + /* we snap if the snap modifier is not enabled. + */ - if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) { - snap_to (sync_frame); - } + if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) { + snap_to (sync_frame); + } - if (sync_frame - sync_offset <= sync_frame) { - pending_region_position = sync_frame - (sync_dir*sync_offset); + pending_region_position = rv->region()->adjust_to_sync (sync_frame); + } else { - pending_region_position = 0; + pending_region_position = drag_info.last_frame_position; } } else { @@ -3176,10 +3438,23 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) } // printf ("3: pending_region_position= %lu %lu\n", pending_region_position, drag_info.last_frame_position ); - - if (pending_region_position != drag_info.last_frame_position && !drag_info.x_constrained) { - /* now compute the canvas unit distance we need to move the regiondrag_info.last_trackview->order + bool x_move_allowed; + + if (Config->get_edit_mode() == Lock) { + if (drag_info.copy) { + x_move_allowed = !drag_info.x_constrained; + } else { + /* in locked edit mode, reverse the usual meaning of x_constrained */ + x_move_allowed = drag_info.x_constrained; + } + } else { + x_move_allowed = !drag_info.x_constrained; + } + + if ( pending_region_position != drag_info.last_frame_position && x_move_allowed ) { + + /* now compute the canvas unit distance we need to move the regionview to make it appear at the new location. */ @@ -3200,7 +3475,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) x_delta = 0; } - + /************************************************************* PREPARE TO MOVE ************************************************************/ @@ -3251,13 +3526,17 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) pair >::iterator,bool> insert_result; const list& layered_regions = selection->regions.by_layer(); - + for (list::const_iterator i = layered_regions.begin(); i != layered_regions.end(); ++i) { RegionView* rv = (*i); double ix1, ix2, iy1, iy2; int32_t temp_pointer_y_span = pointer_y_span; + if (rv->region()->locked()) { + continue; + } + /* get item BBox, which will be relative to parent. so we have to query on a child, then convert to world coordinates using the parent. @@ -3295,6 +3574,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) y_delta -= (*j); temp_pointer_y_span--; } + while (temp_pointer_y_span < 0) { y_delta += (*j); if (x != original_pointer_order) { @@ -3325,7 +3605,8 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) x++; } } - + + /* prevent the regionview from being moved to before the zero position on the canvas. */ @@ -3357,7 +3638,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) cursor_group->raise_to_top(); rv->fake_set_opaque (true); } - + if (drag_info.brushing) { mouse_brush_insert_region (rv, pending_region_position); } else { @@ -3381,15 +3662,12 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) void Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event) { - nframes_t where; - RegionView* rv = reinterpret_cast (drag_info.data); - pair >::iterator,bool> insert_result; bool nocommit = true; - double speed; - RouteTimeAxisView* atv; - bool regionview_y_movement; - bool regionview_x_movement; vector copies; + RouteTimeAxisView* source_tv; + boost::shared_ptr ds; + boost::shared_ptr from_playlist; + vector new_selection; /* first_move is set to false if the regionview has been moved in the motion handler. @@ -3408,6 +3686,11 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event region_drag_motion_callback (item, event); + if (Config->get_edit_mode() == Splice && !pre_drag_region_selection.empty()) { + selection->set (pre_drag_region_selection); + pre_drag_region_selection.clear (); + } + if (drag_info.brushing) { /* all changes were made during motion event handlers */ @@ -3420,20 +3703,6 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event goto out; } - /* adjust for track speed */ - speed = 1.0; - - atv = dynamic_cast (drag_info.last_trackview); - if (atv && atv->get_diskstream()) { - speed = atv->get_diskstream()->speed(); - } - - regionview_x_movement = (drag_info.last_frame_position != (nframes_t) (rv->region()->position()/speed)); - regionview_y_movement = (drag_info.last_trackview != &rv->get_time_axis_view()); - - //printf ("last_frame: %s position is %lu %g\n", rv->get_time_axis_view().name().c_str(), drag_info.last_frame_position, speed); - //printf ("last_rackview: %s \n", drag_info.last_trackview->name().c_str()); - char* op_string; if (drag_info.copy) { @@ -3452,71 +3721,110 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event begin_reversible_command (op_string); - if (regionview_y_movement) { - - /* moved to a different audio track. */ - - vector new_selection; - - for (list::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ) { + for (list::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ) { - RegionView* rv = (*i); + RegionView* rv = (*i); + double ix1, ix2, iy1, iy2; + rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2); + rv->get_canvas_group()->i2w (ix1, iy1); + TimeAxisView* dest_tv = trackview_by_y_position (iy1); + AudioTimeAxisView* dest_atv = dynamic_cast(dest_tv); + double speed; + bool changed_tracks; + bool changed_position; + nframes_t where; + + if (rv->region()->locked()) { + ++i; + continue; + } - double ix1, ix2, iy1, iy2; - - rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2); - rv->get_canvas_group()->i2w (ix1, iy1); - TimeAxisView* tvp2 = trackview_by_y_position (iy1); - AudioTimeAxisView* atv2 = dynamic_cast(tvp2); + /* adjust for track speed */ - boost::shared_ptr from_playlist = rv->region()->playlist(); - boost::shared_ptr to_playlist = atv2->playlist(); + speed = 1.0; + + if (dest_atv && dest_atv->get_diskstream()) { + speed = dest_atv->get_diskstream()->speed(); + } + + changed_position = (drag_info.last_frame_position != (nframes_t) (rv->region()->position()/speed)); + changed_tracks = (dest_tv != &rv->get_time_axis_view()); + if (changed_position && !drag_info.x_constrained) { where = (nframes_t) (unit_to_frame (ix1) * speed); - boost::shared_ptr new_region (RegionFactory::create (rv->region())); - - /* undo the previous hide_dependent_views so that xfades don't - disappear on copying regions - */ + } else { + where = rv->region()->position(); + } + + /* undo the previous hide_dependent_views so that xfades don't + disappear on copying regions + */ + + rv->get_time_axis_view().reveal_dependent_views (*rv); + + boost::shared_ptr new_region; - rv->get_time_axis_view().reveal_dependent_views (*rv); + if (drag_info.copy) { + /* we already made a copy */ + new_region = rv->region(); + } else { + new_region = RegionFactory::create (rv->region()); + } - if (!drag_info.copy) { - - /* the region that used to be in the old playlist is not - moved to the new one - we make a copy of it. as a result, - any existing editor for the region should no longer be - visible. - */ - - rv->hide_region_editor(); - rv->fake_set_opaque (false); + if (changed_tracks || drag_info.copy) { - session->add_command (new MementoCommand(*from_playlist, &from_playlist->get_state(), 0)); - from_playlist->remove_region ((rv->region())); - session->add_command (new MementoCommand(*from_playlist, 0, &from_playlist->get_state())); + boost::shared_ptr to_playlist = dest_atv->playlist(); - } else { + latest_regionviews.clear (); - /* the regionview we dragged around is a temporary copy, queue it for deletion */ - - copies.push_back (rv); - } - - latest_regionview = 0; - - sigc::connection c = atv2->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view)); + sigc::connection c = dest_atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view)); session->add_command (new MementoCommand(*to_playlist, &to_playlist->get_state(), 0)); to_playlist->add_region (new_region, where); session->add_command (new MementoCommand(*to_playlist, 0, &to_playlist->get_state())); c.disconnect (); - if (latest_regionview) { - new_selection.push_back (latest_regionview); + if (!latest_regionviews.empty()) { + // XXX why just the first one ? we only expect one + dest_atv->reveal_dependent_views (*latest_regionviews.front()); + new_selection.push_back (latest_regionviews.front()); } + } else { + + /* just change the model */ + + rv->region()->set_position (where, (void*) this); + } + + if (changed_tracks && !drag_info.copy) { + + /* get the playlist where this drag started. we can't use rv->region()->playlist() + because we may have copied the region and it has not been attached to a playlist. + */ + + assert ((source_tv = dynamic_cast (&rv->get_time_axis_view()))); + assert ((ds = source_tv->get_diskstream())); + assert ((from_playlist = ds->playlist())); + + /* moved to a different audio track, without copying */ + + /* the region that used to be in the old playlist is not + moved to the new one - we use a copy of it. as a result, + any existing editor for the region should no longer be + visible. + */ + + rv->hide_region_editor(); + rv->fake_set_opaque (false); + + /* remove the region from the old playlist */ + + session->add_command (new MementoCommand(*from_playlist, &from_playlist->get_state(), 0)); + from_playlist->remove_region ((rv->region())); + session->add_command (new MementoCommand(*from_playlist, 0, &from_playlist->get_state())); + /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region - was selected in all of them, then removing it from the playlist will have removed all + was selected in all of them, then removing it from a playlist will have removed all trace of it from the selection (i.e. there were N regions selected, we removed 1, but since its the same playlist for N tracks, all N tracks updated themselves, removed the corresponding regionview, and the selection is now empty). @@ -3532,115 +3840,37 @@ Editor::region_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent* event we can just iterate. */ - if (drag_info.copy) { - ++i; - } else { - if (selection->regions.empty()) { - break; - } else { - i = selection->regions.by_layer().begin(); - } + if (selection->regions.empty()) { + break; + } else { + i = selection->regions.by_layer().begin(); } - } - selection->set (new_selection); - - } else { - - /* motion within a single track */ - - list regions = selection->regions.by_layer(); - - if (drag_info.copy) { - selection->clear_regions(); + } else { + ++i; } - for (list::iterator i = regions.begin(); i != regions.end(); ++i) { - - rv = (*i); - - if (rv->region()->locked()) { - continue; - } - - - if (regionview_x_movement) { - double ownspeed = 1.0; - atv = dynamic_cast (&(rv->get_time_axis_view())); - - if (atv && atv->get_diskstream()) { - ownspeed = atv->get_diskstream()->speed(); - } - - /* base the new region position on the current position of the regionview.*/ - - double ix1, ix2, iy1, iy2; - - rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2); - rv->get_canvas_group()->i2w (ix1, iy1); - where = (nframes_t) (unit_to_frame (ix1) * ownspeed); - - } else { - - where = rv->region()->position(); - } - - boost::shared_ptr to_playlist = rv->region()->playlist(); - - assert (to_playlist); - - /* add the undo */ - - session->add_command (new MementoCommand(*to_playlist, &to_playlist->get_state(), 0)); - - if (drag_info.copy) { - - boost::shared_ptr newregion; - boost::shared_ptr ar; - - if ((ar = boost::dynamic_pointer_cast(rv->region())) != 0) { - newregion = RegionFactory::create (ar); - } else { - /* XXX MIDI HERE drobilla */ - continue; - } - - /* add it */ - - latest_regionview = 0; - sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view)); - to_playlist->add_region (newregion, (nframes_t) (where * atv->get_diskstream()->speed())); - c.disconnect (); - - if (latest_regionview) { - atv->reveal_dependent_views (*latest_regionview); - selection->add (latest_regionview); - } - - /* if the original region was locked, we don't care for the new one */ - - newregion->set_locked (false); - - } else { - - /* just change the model */ - - rv->region()->set_position (where, (void*) this); - - } - - /* add the redo */ - - session->add_command (new MementoCommand(*to_playlist, 0, &to_playlist->get_state())); - - if (drag_info.copy) { - copies.push_back (rv); - } + if (drag_info.copy) { + copies.push_back (rv); } } - - out: + if (new_selection.empty()) { + if (drag_info.copy) { + /* the region(view)s that are selected and being dragged around + are copies and do not belong to any track. remove them + from the selection right here. + */ + selection->clear_regions(); + } + } else { + /* this will clear any existing selection that would have been + cleared in the other clause above + */ + selection->set (new_selection); + } + + out: if (!nocommit) { commit_reversible_command (); } @@ -3657,7 +3887,7 @@ Editor::region_view_item_click (AudioRegionView& rv, GdkEventButton* event) this is an alignment click (control used) */ - if (Keyboard::modifier_state_contains (event->state, Keyboard::Control)) { + if (Keyboard::modifier_state_contains (event->state, Keyboard::PrimaryModifier)) { TimeAxisView* tv = &rv.get_time_axis_view(); AudioTimeAxisView* atv = dynamic_cast(tv); double speed = 1.0; @@ -3669,11 +3899,11 @@ Editor::region_view_item_click (AudioRegionView& rv, GdkEventButton* event) if (where >= 0) { - if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Alt))) { + if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) { align_region (rv.region(), SyncPoint, (nframes_t) (where * speed)); - } else if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::Control|Keyboard::Shift))) { + } else if (Keyboard::modifier_state_equals (event->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) { align_region (rv.region(), End, (nframes_t) (where * speed)); @@ -3699,7 +3929,15 @@ Editor::show_verbose_time_cursor (nframes_t frame, double offset, double xpos, d return; } - switch (Profile->get_small_screen() ? ARDOUR_UI::instance()->primary_clock.mode () : ARDOUR_UI::instance()->secondary_clock.mode ()) { + AudioClock::Mode m; + + if (Profile->get_sae() || Profile->get_small_screen()) { + m = ARDOUR_UI::instance()->primary_clock.mode(); + } else { + m = ARDOUR_UI::instance()->secondary_clock.mode(); + } + + switch (m) { case AudioClock::BBT: session->bbt_time (frame, bbt); snprintf (buf, sizeof (buf), "%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32, bbt.bars, bbt.beats, bbt.ticks); @@ -3751,7 +3989,15 @@ Editor::show_verbose_duration_cursor (nframes_t start, nframes_t end, double off return; } - switch (ARDOUR_UI::instance()->secondary_clock.mode ()) { + AudioClock::Mode m; + + if (Profile->get_sae() || Profile->get_small_screen()) { + m = ARDOUR_UI::instance()->primary_clock.mode (); + } else { + m = ARDOUR_UI::instance()->secondary_clock.mode (); + } + + switch (m) { case AudioClock::BBT: session->bbt_time (start, sbbt); session->bbt_time (end, ebbt); @@ -3806,13 +4052,14 @@ Editor::show_verbose_duration_cursor (nframes_t start, nframes_t end, double off else { set_verbose_canvas_cursor (buf, drag_info.current_pointer_x + offset, drag_info.current_pointer_y + offset); } + show_verbose_canvas_cursor (); } void Editor::collect_new_region_view (RegionView* rv) { - latest_regionview = rv; + latest_regionviews.push_back (rv); } void @@ -3842,7 +4089,7 @@ Editor::start_selection_grab (ArdourCanvas::Item* item, GdkEvent* event) set the regionview we want to then drag. */ - latest_regionview = 0; + latest_regionviews.clear(); sigc::connection c = clicked_audio_trackview->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view)); /* A selection grab currently creates two undo/redo operations, one for @@ -3862,24 +4109,26 @@ Editor::start_selection_grab (ArdourCanvas::Item* item, GdkEvent* event) c.disconnect (); - if (latest_regionview == 0) { + if (latest_regionviews.empty()) { /* something went wrong */ 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_regionview); + i'm ignoring undo stuff, because the region creation will take care of it + */ + selection->set (latest_regionviews); - drag_info.item = latest_regionview->get_canvas_group(); - drag_info.data = latest_regionview; + drag_info.item = latest_regionviews.front()->get_canvas_group(); + drag_info.data = latest_regionviews.front(); drag_info.motion_callback = &Editor::region_drag_motion_callback; drag_info.finished_callback = &Editor::region_drag_finished_callback; start_grab (event); - drag_info.last_trackview = clicked_trackview; - drag_info.last_frame_position = latest_regionview->region()->position(); + drag_info.source_trackview = clicked_trackview; + drag_info.dest_trackview = drag_info.source_trackview; + drag_info.last_frame_position = latest_regionviews.front()->region()->position(); drag_info.pointer_frame_offset = drag_info.grab_frame - drag_info.last_frame_position; show_verbose_time_cursor (drag_info.last_frame_position, 10); @@ -3891,10 +4140,8 @@ Editor::cancel_selection () for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { (*i)->hide_selection (); } - begin_reversible_command (_("cancel selection")); selection->clear (); clicked_selection = 0; - commit_reversible_command (); } void @@ -3915,7 +4162,7 @@ Editor::start_selection_op (ArdourCanvas::Item* item, GdkEvent* event, Selection switch (op) { case CreateSelection: - if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) { + if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) { drag_info.copy = true; } else { drag_info.copy = false; @@ -4066,7 +4313,7 @@ Editor::drag_selection (ArdourCanvas::Item* item, GdkEvent* event) } if (event->button.x >= horizontal_adjustment.get_value() + canvas_width) { - start_canvas_autoscroll (1); + start_canvas_autoscroll (1, 0); } if (start != end) { @@ -4130,7 +4377,7 @@ Editor::start_trim (ArdourCanvas::Item* item, GdkEvent* event) start_grab (event, trimmer_cursor); - if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) { + if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) { trim_op = ContentsTrim; } else { /* These will get overridden for a point trim.*/ @@ -4257,7 +4504,7 @@ Editor::trim_motion_callback (ArdourCanvas::Item* item, GdkEvent* event) { bool swap_direction = false; - if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Control)) { + if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) { swap_direction = true; } @@ -4398,7 +4645,7 @@ Editor::trim_finished_callback (ArdourCanvas::Item* item, GdkEvent* event) if (!drag_info.first_move) { trim_motion_callback (item, event); - if (!clicked_regionview->get_selected()) { + if (!selection->selected (clicked_regionview)) { thaw_region_after_trim (*clicked_regionview); } else { @@ -4440,7 +4687,7 @@ Editor::point_trim (GdkEvent* event) trim_op = StartTrim; begin_reversible_command (_("Start point trim")); - if (rv->get_selected()) { + if (selection->selected (rv)) { for (list::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) @@ -4472,7 +4719,7 @@ Editor::point_trim (GdkEvent* event) trim_op = EndTrim; begin_reversible_command (_("End point trim")); - if (rv->get_selected()) { + if (selection->selected (rv)) { for (list::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) { @@ -4558,8 +4805,9 @@ Editor::start_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event, Ran switch (op) { case CreateRangeMarker: case CreateTransportMarker: - - if (Keyboard::modifier_state_equals (event->button.state, Keyboard::Shift)) { + case CreateCDMarker: + + if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) { drag_info.copy = true; } else { drag_info.copy = false; @@ -4577,7 +4825,23 @@ Editor::drag_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event) { nframes_t start = 0; nframes_t end = 0; - ArdourCanvas::SimpleRect *crect = (range_marker_op == CreateRangeMarker) ? range_bar_drag_rect: transport_bar_drag_rect; + ArdourCanvas::SimpleRect *crect; + + switch (range_marker_op) { + case CreateRangeMarker: + crect = range_bar_drag_rect; + break; + case CreateTransportMarker: + crect = transport_bar_drag_rect; + break; + case CreateCDMarker: + crect = cd_marker_bar_drag_rect; + break; + default: + cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl; + return; + break; + } if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) { snap_to (drag_info.current_pointer_frame); @@ -4592,6 +4856,7 @@ Editor::drag_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event) switch (range_marker_op) { case CreateRangeMarker: case CreateTransportMarker: + case CreateCDMarker: if (drag_info.first_move) { snap_to (drag_info.grab_frame); } @@ -4623,7 +4888,7 @@ Editor::drag_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event) } if (event->button.x >= horizontal_adjustment.get_value() + canvas_width) { - start_canvas_autoscroll (1); + start_canvas_autoscroll (1, 0); } if (start != end) { @@ -4649,23 +4914,32 @@ Editor::end_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event) { Location * newloc = 0; string rangename; + int flags; if (!drag_info.first_move) { drag_range_markerbar_op (item, event); switch (range_marker_op) { case CreateRangeMarker: + case CreateCDMarker: { begin_reversible_command (_("new range marker")); XMLNode &before = session->locations()->get_state(); session->locations()->next_available_name(rangename,"unnamed"); - newloc = new Location(temp_location->start(), temp_location->end(), rangename, Location::IsRangeMarker); + if (range_marker_op == CreateCDMarker) { + flags = Location::IsRangeMarker|Location::IsCDMarker; + cd_marker_bar_drag_rect->hide(); + } + else { + flags = Location::IsRangeMarker; + range_bar_drag_rect->hide(); + } + newloc = new Location(temp_location->start(), temp_location->end(), rangename, (Location::Flags) flags); session->locations()->add (newloc, true); XMLNode &after = session->locations()->get_state(); session->add_command(new MementoCommand(*(session->locations()), &before, &after)); commit_reversible_command (); - range_bar_drag_rect->hide(); range_marker_drag_rect->hide(); break; } @@ -4679,7 +4953,7 @@ Editor::end_range_markerbar_op (ArdourCanvas::Item* item, GdkEvent* event) } else { /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */ - if (Keyboard::no_modifier_keys_pressed (&event->button)) { + if (Keyboard::no_modifier_keys_pressed (&event->button) && range_marker_op != CreateCDMarker) { nframes_t start; nframes_t end; @@ -4831,7 +5105,7 @@ Editor::drag_rubberband_select (ArdourCanvas::Item* item, GdkEvent* event) return; } - if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) { + if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) && Config->get_rubberbanding_snaps_to_grid()) { if (drag_info.first_move) { snap_to (drag_info.grab_frame); } @@ -4995,11 +5269,20 @@ Editor::end_time_fx (ArdourCanvas::Item* item, GdkEvent* event) } nframes_t newlen = drag_info.last_pointer_frame - clicked_regionview->region()->position(); +#ifdef USE_RUBBERBAND + float percentage = (float) ((double) newlen / (double) clicked_regionview->region()->length()); +#else float percentage = (float) ((double) newlen - (double) clicked_regionview->region()->length()) / ((double) newlen) * 100.0f; - +#endif + begin_reversible_command (_("timestretch")); - if (run_timestretch (selection->regions, percentage) == 0) { + // XXX how do timeFX on multiple regions ? + + RegionSelection rs; + rs.add (clicked_regionview); + + if (time_stretch (rs, percentage) == 0) { session->commit_reversible_command (); } } @@ -5021,9 +5304,7 @@ Editor::mouse_brush_insert_region (RegionView* rv, nframes_t pos) } switch (snap_type) { - case SnapToFrame: case SnapToMark: - case SnapToEditPoint: return; default: