X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor_drag.cc;h=0c309d723458ddb727de2def826b36fc0421d27d;hb=2b8fc2a43b155d9a22d68554508181dd0894b69d;hp=cda4a264406b60508929f2326d9283313e72af6e;hpb=bdb15f942250ad3e8a42c6bef927374eedb0299f;p=ardour.git diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index cda4a26440..0c309d7234 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -29,6 +29,7 @@ #include "gtkmm2ext/utils.h" +#include "ardour/audioengine.h" #include "ardour/audioregion.h" #include "ardour/dB.h" #include "ardour/midi_region.h" @@ -205,19 +206,15 @@ Drag::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t tim _item = new_item; if (cursor == 0) { - cursor = _editor->which_grabber_cursor (); + _item->grab (Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK, time); + } else { + _item->grab (Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK, *cursor, time); } - - _item->grab (Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK, *cursor, time); } void Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor) { - if (cursor == 0) { - cursor = _editor->which_grabber_cursor (); - } - // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained if (Keyboard::is_button2_event (&event->button)) { @@ -240,9 +237,14 @@ Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor) _last_pointer_x = _grab_x; _last_pointer_y = _grab_y; - _item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK, - *cursor, - event->button.time); + if (cursor == 0) { + _item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK, + event->button.time); + } else { + _item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK, + *cursor, + event->button.time); + } if (_editor->session() && _editor->session()->transport_rolling()) { _was_rolling = true; @@ -330,7 +332,9 @@ Drag::motion_handler (GdkEvent* event, bool from_autoscroll) if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) { if (!from_autoscroll) { - _editor->maybe_autoscroll (true, allow_vertical_autoscroll ()); + bool const moving_left = _drags->current_pointer_x() < _last_pointer_x; + bool const moving_up = _drags->current_pointer_y() < _last_pointer_y; + _editor->maybe_autoscroll (true, allow_vertical_autoscroll (), moving_left, moving_up); } motion (event, _move_threshold_passed != old_move_threshold_passed); @@ -395,13 +399,29 @@ Drag::show_verbose_cursor_text (string const & text) ); } +boost::shared_ptr +Drag::add_midi_region (MidiTimeAxisView* view) +{ + if (_editor->session()) { + const TempoMap& map (_editor->session()->tempo_map()); + framecnt_t pos = grab_frame(); + const Meter& m = map.meter_at (pos); + /* not that the frame rate used here can be affected by pull up/down which + might be wrong. + */ + framecnt_t len = m.frames_per_bar (map.tempo_at (pos), _editor->session()->frame_rate()); + return view->add_region (grab_frame(), len, true); + } + + return boost::shared_ptr(); +} struct EditorOrderTimeAxisViewSorter { bool operator() (TimeAxisView* a, TimeAxisView* b) { RouteTimeAxisView* ra = dynamic_cast (a); RouteTimeAxisView* rb = dynamic_cast (b); assert (ra && rb); - return ra->route()->order_key (N_ ("editor")) < rb->route()->order_key (N_ ("editor")); + return ra->route()->order_key (EditorSort) < rb->route()->order_key (EditorSort); } }; @@ -434,7 +454,7 @@ RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, listget_time_axis_view().hide_dependent_views (*rv); + rv->drag_start (); /* Absolutely no idea why this is necessary, but it is; without it, the region view disappears after the reparent. @@ -679,15 +699,15 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move) if (tv->view()->layer_display() == Stacked) { tv->view()->set_layer_display (Expanded); } - + /* We're only allowed to go -ve in layer on Expanded views */ if (tv->view()->layer_display() != Expanded && (i->layer + this_delta_layer) < 0) { this_delta_layer = - i->layer; } - + /* Set height */ rv->set_height (tv->view()->child_height ()); - + /* Update show/hidden status as the region view may have come from a hidden track, or have moved to one. */ @@ -878,6 +898,8 @@ RegionMoveDrag::finished (GdkEvent* ev, bool movement_occurred) ); } + + _editor->maybe_locate_with_edit_preroll (_editor->get_selection().regions.start()); } void @@ -1040,7 +1062,7 @@ RegionMoveDrag::finished_no_copy ( rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item()); rv->get_canvas_group()->property_y() = i->initial_y; - rv->get_time_axis_view().reveal_dependent_views (*rv); + rv->drag_end (); /* just change the model */ @@ -1254,7 +1276,7 @@ RegionMotionDrag::aborted (bool) assert (rtv); rv->get_canvas_group()->reparent (*rtv->view()->canvas_item()); rv->get_canvas_group()->property_y() = 0; - rv->get_time_axis_view().reveal_dependent_views (*rv); + rv->drag_end (); rv->fake_set_opaque (false); rv->move (-_total_x_delta, 0); rv->set_height (rtv->view()->child_height ()); @@ -1442,7 +1464,7 @@ void RegionCreateDrag::motion (GdkEvent* event, bool first_move) { if (first_move) { - add_region(); + _region = add_midi_region (_view); _view->playlist()->freeze (); } else { if (_region) { @@ -1468,29 +1490,10 @@ void RegionCreateDrag::finished (GdkEvent*, bool movement_occurred) { if (!movement_occurred) { - add_region (); + add_midi_region (_view); } else { _view->playlist()->thaw (); } - - if (_region) { - _editor->commit_reversible_command (); - } -} - -void -RegionCreateDrag::add_region () -{ - if (_editor->session()) { - const TempoMap& map (_editor->session()->tempo_map()); - framecnt_t pos = grab_frame(); - const Meter& m = map.meter_at (pos); - /* not that the frame rate used here can be affected by pull up/down which - might be wrong. - */ - framecnt_t len = m.frames_per_bar (map.tempo_at (pos), _editor->session()->frame_rate()); - _region = _view->add_region (grab_frame(), len, false); - } } void @@ -1594,34 +1597,11 @@ NoteResizeDrag::aborted (bool) } } -RegionGainDrag::RegionGainDrag (Editor* e, ArdourCanvas::Item* i) - : Drag (e, i) -{ - DEBUG_TRACE (DEBUG::Drags, "New RegionGainDrag\n"); -} - -void -RegionGainDrag::motion (GdkEvent* /*event*/, bool) -{ - -} - -void -RegionGainDrag::finished (GdkEvent *, bool) -{ - -} - -void -RegionGainDrag::aborted (bool) -{ - /* XXX: TODO */ -} - -TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list const & v) +TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list const & v, bool preserve_fade_anchor) : RegionDrag (e, i, p, v) { DEBUG_TRACE (DEBUG::Drags, "New TrimDrag\n"); + _preserve_fade_anchor = preserve_fade_anchor; } void @@ -1722,6 +1702,7 @@ TrimDrag::motion (GdkEvent* event, bool first_move) if (arv) { arv->temporarily_hide_envelope (); + arv->drag_start (); } boost::shared_ptr pl = rv->region()->playlist(); @@ -1742,13 +1723,41 @@ TrimDrag::motion (GdkEvent* event, bool first_move) switch (_operation) { case StartTrim: for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { - i->view->trim_front (i->initial_position + dt, non_overlap_trim); + bool changed = i->view->trim_front (i->initial_position + dt, non_overlap_trim); + if (changed && _preserve_fade_anchor) { + AudioRegionView* arv = dynamic_cast (i->view); + if (arv) { + double distance; + double new_length; + framecnt_t len; + boost::shared_ptr ar (arv->audio_region()); + distance = _drags->current_pointer_x() - grab_x(); + len = ar->fade_in()->back()->when; + new_length = len - _editor->unit_to_frame (distance); + new_length = ar->verify_xfade_bounds (new_length, true /*START*/ ); + arv->reset_fade_in_shape_width (ar, new_length); //the grey shape + } + } } break; case EndTrim: for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { - i->view->trim_end (i->initial_end + dt, non_overlap_trim); + bool changed = i->view->trim_end (i->initial_end + dt, non_overlap_trim); + if (changed && _preserve_fade_anchor) { + AudioRegionView* arv = dynamic_cast (i->view); + if (arv) { + double distance; + double new_length; + framecnt_t len; + boost::shared_ptr ar (arv->audio_region()); + distance = grab_x() - _drags->current_pointer_x(); + len = ar->fade_out()->back()->when; + new_length = len - _editor->unit_to_frame (distance); + new_length = ar->verify_xfade_bounds (new_length, false /*END*/ ); + arv->reset_fade_out_shape_width (ar, new_length); //the grey shape + } + } } break; @@ -1800,16 +1809,56 @@ TrimDrag::finished (GdkEvent* event, bool movement_occurred) if (movement_occurred) { motion (event, false); - /* This must happen before the region's StatefulDiffCommand is created, as it may - `correct' (ahem) the region's _start from being negative to being zero. It - needs to be zero in the undo record. - */ if (_operation == StartTrim) { for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { - i->view->trim_front_ending (); + { + /* This must happen before the region's StatefulDiffCommand is created, as it may + `correct' (ahem) the region's _start from being negative to being zero. It + needs to be zero in the undo record. + */ + i->view->trim_front_ending (); + } + if (_preserve_fade_anchor) { + AudioRegionView* arv = dynamic_cast (i->view); + if (arv) { + double distance; + double new_length; + framecnt_t len; + boost::shared_ptr ar (arv->audio_region()); + distance = _drags->current_pointer_x() - grab_x(); + len = ar->fade_in()->back()->when; + new_length = len - _editor->unit_to_frame (distance); + new_length = ar->verify_xfade_bounds (new_length, true /*START*/ ); + ar->set_fade_in_length(new_length); + } + } + } + } else if (_operation == EndTrim) { + for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { + if (_preserve_fade_anchor) { + AudioRegionView* arv = dynamic_cast (i->view); + if (arv) { + double distance; + double new_length; + framecnt_t len; + boost::shared_ptr ar (arv->audio_region()); + distance = _drags->current_pointer_x() - grab_x(); + len = ar->fade_out()->back()->when; + new_length = len - _editor->unit_to_frame (distance); + new_length = ar->verify_xfade_bounds (new_length, false /*END*/ ); + ar->set_fade_out_length(new_length); + } + } } } - + + if (_operation == StartTrim) { + _editor->maybe_locate_with_edit_preroll ( _views.begin()->view->region()->position() ); + } + if (_operation == EndTrim) { + _editor->maybe_locate_with_edit_preroll ( _views.begin()->view->region()->position() + _views.begin()->view->region()->length() ); + } + if (!_editor->selection->selected (_primary)) { _primary->thaw_after_trim (); } else { @@ -1835,6 +1884,7 @@ TrimDrag::finished (GdkEvent* event, bool movement_occurred) } } } + for (set >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) { (*p)->thaw (); } @@ -2093,10 +2143,11 @@ TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred) motion (event, false); + TempoMap& map (_editor->session()->tempo_map()); + framepos_t beat_time = map.round_to_beat (last_pointer_frame(), 0); Timecode::BBT_Time when; - TempoMap& map (_editor->session()->tempo_map()); - map.bbt_time (last_pointer_frame(), when); + map.bbt_time (beat_time, when); if (_copy == true) { _editor->begin_reversible_command (_("copy tempo mark")); @@ -2184,9 +2235,20 @@ CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c) s->cancel_audition (); } - s->request_suspend_timecode_transmission (); - while (!s->timecode_transmission_suspended ()) { - /* twiddle our thumbs */ + + if (AudioEngine::instance()->connected()) { + + /* do this only if we're the engine is connected + * because otherwise this request will never be + * serviced and we'll busy wait forever. likewise, + * notice if we are disconnected while waiting for the + * request to be serviced. + */ + + s->request_suspend_timecode_transmission (); + while (AudioEngine::instance()->connected() && !s->timecode_transmission_suspended ()) { + /* twiddle our thumbs */ + } } } @@ -2250,8 +2312,6 @@ FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) boost::shared_ptr const r = arv->audio_region (); show_verbose_cursor_duration (r->position(), r->position() + r->fade_in()->back()->when, 32); - - arv->show_fade_line((framepos_t) r->fade_in()->back()->when); } void @@ -2287,8 +2347,7 @@ FadeInDrag::motion (GdkEvent* event, bool) continue; } - tmp->reset_fade_in_shape_width (fade_length); - tmp->show_fade_line((framecnt_t) fade_length); + tmp->reset_fade_in_shape_width (tmp->audio_region(), fade_length); } show_verbose_cursor_duration (region->position(), region->position() + fade_length, 32); @@ -2330,7 +2389,6 @@ FadeInDrag::finished (GdkEvent* event, bool movement_occurred) tmp->audio_region()->set_fade_in_length (fade_length); tmp->audio_region()->set_fade_in_active (true); - tmp->hide_fade_line(); XMLNode &after = alist->get_state(); _editor->session()->add_command(new MementoCommand(*alist.get(), &before, &after)); @@ -2349,8 +2407,7 @@ FadeInDrag::aborted (bool) continue; } - tmp->reset_fade_in_shape_width (tmp->audio_region()->fade_in()->back()->when); - tmp->hide_fade_line(); + tmp->reset_fade_in_shape_width (tmp->audio_region(), tmp->audio_region()->fade_in()->back()->when); } } @@ -2369,8 +2426,6 @@ FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) boost::shared_ptr r = arv->audio_region (); show_verbose_cursor_duration (r->last_frame() - r->fade_out()->back()->when, r->last_frame()); - - arv->show_fade_line(r->length() - r->fade_out()->back()->when); } void @@ -2408,8 +2463,7 @@ FadeOutDrag::motion (GdkEvent* event, bool) continue; } - tmp->reset_fade_out_shape_width (fade_length); - tmp->show_fade_line(region->length() - fade_length); + tmp->reset_fade_out_shape_width (tmp->audio_region(), fade_length); } show_verbose_cursor_duration (region->last_frame() - fade_length, region->last_frame()); @@ -2453,7 +2507,6 @@ FadeOutDrag::finished (GdkEvent* event, bool movement_occurred) tmp->audio_region()->set_fade_out_length (fade_length); tmp->audio_region()->set_fade_out_active (true); - tmp->hide_fade_line(); XMLNode &after = alist->get_state(); _editor->session()->add_command(new MementoCommand(*alist.get(), &before, &after)); @@ -2472,8 +2525,7 @@ FadeOutDrag::aborted (bool) continue; } - tmp->reset_fade_out_shape_width (tmp->audio_region()->fade_out()->back()->when); - tmp->hide_fade_line(); + tmp->reset_fade_out_shape_width (tmp->audio_region(), tmp->audio_region()->fade_out()->back()->when); } } @@ -2832,6 +2884,12 @@ ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/) event->button.x + 10, event->button.y + 10); _editor->verbose_cursor()->show (); + + _pushing = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier); + + if (!_point->can_slide ()) { + _x_constrained = true; + } } void @@ -2883,9 +2941,7 @@ ControlPointDrag::motion (GdkEvent* event, bool) float const fraction = 1.0 - (cy / _point->line().height()); - bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier); - - _point->line().drag_motion (_editor->frame_to_unit (cx_frames), fraction, false, push); + _point->line().drag_motion (_editor->frame_to_unit_unrounded (cx_frames), fraction, false, _pushing, _final_index); _editor->verbose_cursor()->set_text (_point->line().get_verbose_cursor_string (fraction)); } @@ -2905,7 +2961,7 @@ ControlPointDrag::finished (GdkEvent* event, bool movement_occurred) motion (event, false); } - _point->line().end_drag (); + _point->line().end_drag (_pushing, _final_index); _editor->session()->commit_reversible_command (); } @@ -2996,17 +3052,10 @@ LineDrag::motion (GdkEvent* event, bool) cy = min ((double) _line->height(), cy); double const fraction = 1.0 - (cy / _line->height()); - - bool push; - - if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) { - push = false; - } else { - push = true; - } + uint32_t ignored; /* we are ignoring x position for this drag, so we can just pass in anything */ - _line->drag_motion (0, fraction, true, push); + _line->drag_motion (0, fraction, true, false, ignored); _editor->verbose_cursor()->set_text (_line->get_verbose_cursor_string (fraction)); } @@ -3015,7 +3064,7 @@ void LineDrag::finished (GdkEvent* event, bool) { motion (event, false); - _line->end_drag (); + _line->end_drag (false, 0); _editor->session()->commit_reversible_command (); } @@ -3110,6 +3159,7 @@ FeatureLineDrag::aborted (bool) RubberbandSelectDrag::RubberbandSelectDrag (Editor* e, ArdourCanvas::Item* i) : Drag (e, i) + , _vertical_only (false) { DEBUG_TRACE (DEBUG::Drags, "New RubberbandSelectDrag\n"); } @@ -3161,8 +3211,14 @@ RubberbandSelectDrag::motion (GdkEvent* event, bool) double x2 = _editor->frame_to_pixel (end); _editor->rubberband_rect->property_x1() = x1; + if (_vertical_only) { + /* fixed 10 pixel width */ + _editor->rubberband_rect->property_x2() = x1 + 10; + } else { + _editor->rubberband_rect->property_x2() = x2; + } + _editor->rubberband_rect->property_y1() = y1; - _editor->rubberband_rect->property_x2() = x2; _editor->rubberband_rect->property_y2() = y2; _editor->rubberband_rect->show(); @@ -3212,7 +3268,29 @@ RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred) } else { - deselect_things (); + /* just a click */ + + bool do_deselect = true; + MidiTimeAxisView* mtv; + + if ((mtv = dynamic_cast(_editor->clicked_axisview)) != 0) { + /* MIDI track */ + if (_editor->selection->empty()) { + /* nothing selected */ + add_midi_region (mtv); + do_deselect = false; + } + } + + /* do not deselect if Primary or Tertiary (toggle-select or + * extend-select are pressed. + */ + + if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier) && + !Keyboard::modifier_state_contains (event->button.state, Keyboard::TertiaryModifier) && + do_deselect) { + deselect_things (); + } } @@ -3243,11 +3321,16 @@ void TimeFXDrag::motion (GdkEvent* event, bool) { RegionView* rv = _primary; + StreamView* cv = rv->get_time_axis_view().view (); + + pair const tv = _editor->trackview_by_y_position (grab_y()); + int layer = tv.first->layer_display() == Overlaid ? 0 : tv.second; + int layers = tv.first->layer_display() == Overlaid ? 1 : cv->layers(); framepos_t const pf = adjusted_current_frame (event); if (pf > rv->region()->position()) { - rv->get_time_axis_view().show_timestretch (rv->region()->position(), pf); + rv->get_time_axis_view().show_timestretch (rv->region()->position(), pf, layers, layer); } show_verbose_cursor_time (pf); @@ -3278,13 +3361,16 @@ TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred) } #endif - // XXX how do timeFX on multiple regions ? - - RegionSelection rs; - rs.add (_primary); + if (!_editor->get_selection().regions.empty()) { + /* primary will already be included in the selection, and edit + group shared editing will propagate selection across + equivalent regions, so just use the current region + selection. + */ - if (_editor->time_stretch (rs, percentage) == -1) { - error << _("An error occurred while executing time stretch operation") << endmsg; + if (_editor->time_stretch (_editor->get_selection().regions, percentage) == -1) { + error << _("An error occurred while executing time stretch operation") << endmsg; + } } } @@ -3330,11 +3416,18 @@ ScrubDrag::aborted (bool) SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o) : Drag (e, i) , _operation (o) - , _copy (false) + , _add (false) + , _extend (false) , _original_pointer_time_axis (-1) , _last_pointer_time_axis (-1) + , _time_selection_at_start (!_editor->get_selection().time.empty()) { DEBUG_TRACE (DEBUG::Drags, "New SelectionDrag\n"); + + if (_time_selection_at_start) { + start_at_start = _editor->get_selection().time.start(); + end_at_start = _editor->get_selection().time.end_frame(); + } } void @@ -3348,10 +3441,10 @@ SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*) switch (_operation) { case CreateSelection: - if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) { - _copy = true; + if (Keyboard::modifier_state_equals (event->button.state, Keyboard::CopyModifier)) { + _add = true; } else { - _copy = false; + _add = false; } cursor = _editor->cursors()->selector; Drag::start_grab (event, cursor); @@ -3374,6 +3467,10 @@ SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*) case SelectionMove: Drag::start_grab (event, cursor); break; + + case SelectionExtend: + Drag::start_grab (event, cursor); + break; } if (_operation == SelectionMove) { @@ -3401,6 +3498,9 @@ SelectionDrag::setup_pointer_frame_offset () case SelectionEndTrim: _pointer_frame_offset = raw_grab_frame() - _editor->selection->time[_editor->clicked_selection].end; break; + + case SelectionExtend: + break; } } @@ -3409,7 +3509,8 @@ SelectionDrag::motion (GdkEvent* event, bool first_move) { framepos_t start = 0; framepos_t end = 0; - framecnt_t length; + framecnt_t length = 0; + framecnt_t distance = 0; pair const pending_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ()); if (pending_time_axis.first == 0) { @@ -3430,10 +3531,15 @@ SelectionDrag::motion (GdkEvent* event, bool first_move) framepos_t grab = grab_frame (); if (first_move) { - _editor->snap_to (grab); + grab = adjusted_current_frame (event, false); + if (grab < pending_position) { + _editor->snap_to (grab, -1); + } else { + _editor->snap_to (grab, 1); + } } - if (pending_position < grab_frame()) { + if (pending_position < grab) { start = pending_position; end = grab; } else { @@ -3447,12 +3553,12 @@ SelectionDrag::motion (GdkEvent* event, bool first_move) if (first_move) { - if (_copy) { + if (_add) { /* adding to the selection */ _editor->set_selected_track_as_side_effect (Selection::Add); //_editor->selection->add (_editor->clicked_axisview); _editor->clicked_selection = _editor->selection->add (start, end); - _copy = false; + _add = false; } else { /* new selection */ @@ -3520,20 +3626,23 @@ SelectionDrag::motion (GdkEvent* event, bool first_move) } break; - + case SelectionMove: start = _editor->selection->time[_editor->clicked_selection].start; end = _editor->selection->time[_editor->clicked_selection].end; length = end - start; - + distance = pending_position - start; start = pending_position; _editor->snap_to (start); end = start + length; break; + + case SelectionExtend: + break; } if (event->button.x >= _editor->horizontal_position() + _editor->_canvas_width) { @@ -3541,7 +3650,15 @@ SelectionDrag::motion (GdkEvent* event, bool first_move) } if (start != end) { - _editor->selection->replace (_editor->clicked_selection, start, end); + switch (_operation) { + case SelectionMove: + if (_time_selection_at_start) { + _editor->selection->move_time (distance); + } + break; + default: + _editor->selection->replace (_editor->clicked_selection, start, end); + } } if (_operation == SelectionMove) { @@ -3564,22 +3681,43 @@ SelectionDrag::finished (GdkEvent* event, bool movement_occurred) } /* XXX what if its a music time selection? */ - if (s && (s->config.get_auto_play() || (s->get_play_range() && s->transport_rolling()))) { - s->request_play_range (&_editor->selection->time, true); + if (s) { + if ( s->get_play_range() && s->transport_rolling() ) { + s->request_play_range (&_editor->selection->time, true); + } else { + if (Config->get_always_play_range() && !s->transport_rolling()) { + s->request_locate (_editor->get_selection().time.start()); + } + } } - } else { - /* just a click, no pointer movement.*/ + /* just a click, no pointer movement. + */ - if (Keyboard::no_modifier_keys_pressed (&event->button)) { - _editor->selection->clear_time(); + if (_operation == SelectionExtend) { + if (_time_selection_at_start) { + framepos_t pos = adjusted_current_frame (event, false); + framepos_t start = min (pos, start_at_start); + framepos_t end = max (pos, end_at_start); + _editor->selection->set (start, end); + } + } else { + if (Keyboard::modifier_state_equals (event->button.state, Keyboard::CopyModifier)) { + if (_editor->clicked_selection) { + _editor->selection->remove (_editor->clicked_selection); + } + } else { + if (!_editor->clicked_selection) { + _editor->selection->clear_time(); + } + } } if (_editor->clicked_axisview && !_editor->selection->selected (_editor->clicked_axisview)) { _editor->selection->set (_editor->clicked_axisview); } - + if (s && s->get_play_range () && s->transport_rolling()) { s->request_stop (false, false); } @@ -3587,6 +3725,7 @@ SelectionDrag::finished (GdkEvent* event, bool movement_occurred) } _editor->stop_canvas_autoscroll (); + _editor->clicked_selection = 0; } void @@ -3660,7 +3799,7 @@ RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move) crect = _editor->cd_marker_bar_drag_rect; break; default: - cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl; + error << string_compose (_("programming_error: %1"), "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()") << endmsg; return; break; } @@ -3872,9 +4011,9 @@ MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred) motion (event, false); if (grab_frame() < last_pointer_frame()) { - _editor->temporal_zoom_by_frame (grab_frame(), last_pointer_frame(), "mouse zoom"); + _editor->temporal_zoom_by_frame (grab_frame(), last_pointer_frame()); } else { - _editor->temporal_zoom_by_frame (last_pointer_frame(), grab_frame(), "mouse zoom"); + _editor->temporal_zoom_by_frame (last_pointer_frame(), grab_frame()); } } else { if (Keyboard::the_keyboard().key_is_down (GDK_Shift_L)) { @@ -3957,7 +4096,15 @@ NoteDrag::total_dx () const int8_t NoteDrag::total_dy () const { - return ((int8_t) (grab_y() / _note_height)) - ((int8_t) (_drags->current_pointer_y() / _note_height)); + MidiStreamView* msv = _region->midi_stream_view (); + double const y = _region->midi_view()->y_position (); + /* new current note */ + uint8_t n = msv->y_to_note (_drags->current_pointer_y () - y); + /* clamp */ + n = max (msv->lowest_note(), n); + n = min (msv->highest_note(), n); + /* and work out delta */ + return n - msv->y_to_note (grab_y() - y); } void @@ -3999,8 +4146,11 @@ void NoteDrag::finished (GdkEvent* ev, bool moved) { if (!moved) { - if (_editor->current_mouse_mode() == Editing::MouseObject) { - + /* no motion - select note */ + + if (_editor->current_mouse_mode() == Editing::MouseObject || + _editor->current_mouse_mode() == Editing::MouseDraw) { + if (_was_selected) { bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier); if (add) { @@ -4030,31 +4180,49 @@ NoteDrag::aborted (bool) /* XXX: TODO */ } -AutomationRangeDrag::AutomationRangeDrag (Editor* editor, ArdourCanvas::Item* item, list const & r) - : Drag (editor, item) +/** Make an AutomationRangeDrag for lines in an AutomationTimeAxisView */ +AutomationRangeDrag::AutomationRangeDrag (Editor* editor, AutomationTimeAxisView* atv, list const & r) + : Drag (editor, atv->base_item ()) , _ranges (r) , _nothing_to_drag (false) { DEBUG_TRACE (DEBUG::Drags, "New AutomationRangeDrag\n"); + y_origin = atv->y_position(); + setup (atv->lines ()); +} - _atav = reinterpret_cast (_item->get_data ("trackview")); - assert (_atav); +/** Make an AutomationRangeDrag for region gain lines */ +AutomationRangeDrag::AutomationRangeDrag (Editor* editor, AudioRegionView* rv, list const & r) + : Drag (editor, rv->get_canvas_group ()) + , _ranges (r) + , _nothing_to_drag (false) +{ + DEBUG_TRACE (DEBUG::Drags, "New AutomationRangeDrag\n"); - /* get all lines in the automation view */ - list > lines = _atav->lines (); + list > lines; + lines.push_back (rv->get_gain_line ()); + y_origin = rv->get_time_axis_view().y_position(); + setup (lines); +} - /* find those that overlap the ranges being dragged */ - list >::iterator i = lines.begin (); +/** @param lines AutomationLines to drag. + * @param offset Offset from the session start to the points in the AutomationLines. + */ +void +AutomationRangeDrag::setup (list > const & lines) +{ + /* find the lines that overlap the ranges being dragged */ + list >::const_iterator i = lines.begin (); while (i != lines.end ()) { - list >::iterator j = i; + list >::const_iterator j = i; ++j; - pair const r = (*i)->get_point_x_range (); + pair r = (*i)->get_point_x_range (); /* check this range against all the AudioRanges that we are using */ list::const_iterator k = _ranges.begin (); while (k != _ranges.end()) { - if (k->coverage (r.first, r.second) != OverlapNone) { + if (k->coverage (r.first, r.second) != Evoral::OverlapNone) { break; } ++k; @@ -4075,6 +4243,12 @@ AutomationRangeDrag::AutomationRangeDrag (Editor* editor, ArdourCanvas::Item* it /* Now ::lines contains the AutomationLines that somehow overlap our drag */ } +double +AutomationRangeDrag::y_fraction (boost::shared_ptr line, double global_y) const +{ + return 1.0 - ((global_y - y_origin) / line->height()); +} + void AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) { @@ -4083,6 +4257,7 @@ AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) /* Get line states before we start changing things */ for (list::iterator i = _lines.begin(); i != _lines.end(); ++i) { i->state = &i->line->get_state (); + i->original_fraction = y_fraction (i->line, _drags->current_pointer_y()); } if (_ranges.empty()) { @@ -4123,9 +4298,7 @@ AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) double const q = j->line->time_converter().from (a - j->line->time_converter().origin_b ()); the_list->add (p, the_list->eval (p)); - j->line->add_always_in_view (p); the_list->add (q, the_list->eval (q)); - j->line->add_always_in_view (q); } /* same thing for the end */ @@ -4151,9 +4324,7 @@ AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) double const q = j->line->time_converter().from (i->end - j->line->time_converter().origin_b ()); the_list->add (p, the_list->eval (p)); - j->line->add_always_in_view (p); the_list->add (q, the_list->eval (q)); - j->line->add_always_in_view (q); } } @@ -4192,7 +4363,7 @@ AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) } for (list::iterator i = _lines.begin(); i != _lines.end(); ++i) { - i->line->start_drag_multiple (i->points, 1 - (_drags->current_pointer_y() / i->line->height ()), i->state); + i->line->start_drag_multiple (i->points, y_fraction (i->line, _drags->current_pointer_y()), i->state); } } @@ -4203,11 +4374,12 @@ AutomationRangeDrag::motion (GdkEvent*, bool /*first_move*/) return; } - for (list::iterator i = _lines.begin(); i != _lines.end(); ++i) { - float const f = 1 - (_drags->current_pointer_y() / i->line->height()); - + for (list::iterator l = _lines.begin(); l != _lines.end(); ++l) { + float const f = y_fraction (l->line, _drags->current_pointer_y()); /* we are ignoring x position for this drag, so we can just pass in anything */ - i->line->drag_motion (0, f, true, false); + uint32_t ignored; + l->line->drag_motion (0, f, true, false, ignored); + show_verbose_cursor_text (l->line->get_verbose_cursor_relative_string (l->original_fraction, f)); } } @@ -4220,8 +4392,7 @@ AutomationRangeDrag::finished (GdkEvent* event, bool) motion (event, false); for (list::iterator i = _lines.begin(); i != _lines.end(); ++i) { - i->line->end_drag (); - i->line->clear_always_in_view (); + i->line->end_drag (false, 0); } _editor->session()->commit_reversible_command (); @@ -4231,7 +4402,6 @@ void AutomationRangeDrag::aborted (bool) { for (list::iterator i = _lines.begin(); i != _lines.end(); ++i) { - i->line->clear_always_in_view (); i->line->reset (); } } @@ -4253,7 +4423,9 @@ PatchChangeDrag::PatchChangeDrag (Editor* e, CanvasPatchChange* i, MidiRegionVie , _patch_change (i) , _cumulative_dx (0) { - DEBUG_TRACE (DEBUG::Drags, "New PatchChangeDrag\n"); + DEBUG_TRACE (DEBUG::Drags, string_compose ("New PatchChangeDrag, patch @ %1, grab @ %2\n", + _region_view->source_beats_to_absolute_frames (_patch_change->patch()->time()), + grab_frame())); } void @@ -4264,8 +4436,8 @@ PatchChangeDrag::motion (GdkEvent* ev, bool) f = max (f, r->position ()); f = min (f, r->last_frame ()); - framecnt_t const dxf = f - grab_frame(); - double const dxu = _editor->frame_to_unit (dxf); + framecnt_t const dxf = f - grab_frame(); // permitted dx in frames + double const dxu = _editor->frame_to_unit (dxf); // permitted fx in units _patch_change->move (dxu - _cumulative_dx, 0); _cumulative_dx = dxu; } @@ -4278,14 +4450,13 @@ PatchChangeDrag::finished (GdkEvent* ev, bool movement_occurred) } boost::shared_ptr r (_region_view->region ()); - framepos_t f = adjusted_current_frame (ev); f = max (f, r->position ()); f = min (f, r->last_frame ()); _region_view->move_patch_change ( *_patch_change, - _region_view->region_frames_to_region_beats (f - r->position() - r->start()) + _region_view->region_frames_to_region_beats (f - (r->position() - r->start())) ); } @@ -4310,7 +4481,7 @@ MidiRubberbandSelectDrag::MidiRubberbandSelectDrag (Editor* e, MidiRegionView* r } void -MidiRubberbandSelectDrag::select_things (int button_state, framepos_t x1, framepos_t x2, double y1, double y2, bool drag_in_progress) +MidiRubberbandSelectDrag::select_things (int button_state, framepos_t x1, framepos_t x2, double y1, double y2, bool /*drag_in_progress*/) { framepos_t const p = _region_view->region()->position (); double const y = _region_view->midi_view()->y_position (); @@ -4335,6 +4506,34 @@ MidiRubberbandSelectDrag::deselect_things () /* XXX */ } +MidiVerticalSelectDrag::MidiVerticalSelectDrag (Editor* e, MidiRegionView* rv) + : RubberbandSelectDrag (e, rv->get_canvas_frame ()) + , _region_view (rv) +{ + _vertical_only = true; +} + +void +MidiVerticalSelectDrag::select_things (int button_state, framepos_t /*x1*/, framepos_t /*x2*/, double y1, double y2, bool /*drag_in_progress*/) +{ + double const y = _region_view->midi_view()->y_position (); + + y1 = max (0.0, y1 - y); + y2 = max (0.0, y2 - y); + + _region_view->update_vertical_drag_selection ( + y1, + y2, + Keyboard::modifier_state_contains (button_state, Keyboard::TertiaryModifier) + ); +} + +void +MidiVerticalSelectDrag::deselect_things () +{ + /* XXX */ +} + EditorRubberbandSelectDrag::EditorRubberbandSelectDrag (Editor* e, ArdourCanvas::Item* i) : RubberbandSelectDrag (e, i) { @@ -4428,7 +4627,7 @@ NoteCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) void NoteCreateDrag::motion (GdkEvent* event, bool) { - _note[1] = adjusted_current_frame (event) - _region_view->region()->position (); + _note[1] = max ((framepos_t)0, adjusted_current_frame (event) - _region_view->region()->position ()); double const x = _editor->frame_to_pixel (_note[1]); if (_note[1] > _note[0]) { _drag_rect->property_x2() = x; @@ -4438,7 +4637,7 @@ NoteCreateDrag::motion (GdkEvent* event, bool) } void -NoteCreateDrag::finished (GdkEvent* event, bool had_movement) +NoteCreateDrag::finished (GdkEvent*, bool had_movement) { if (!had_movement) { return; @@ -4448,7 +4647,7 @@ NoteCreateDrag::finished (GdkEvent* event, bool had_movement) framecnt_t length = abs (_note[0] - _note[1]); framecnt_t const g = grid_frames (start); - double const one_tick = 1 / Timecode::BBT_Time::ticks_per_bar_division; + double const one_tick = 1 / Timecode::BBT_Time::ticks_per_beat; if (_editor->snap_mode() == SnapNormal && length < g) { length = g - one_tick; @@ -4472,3 +4671,100 @@ NoteCreateDrag::aborted (bool) { } + +CrossfadeEdgeDrag::CrossfadeEdgeDrag (Editor* e, AudioRegionView* rv, ArdourCanvas::Item* i, bool start_yn) + : Drag (e, i) + , arv (rv) + , start (start_yn) +{ + std::cout << ("CrossfadeEdgeDrag is DEPRECATED. See TrimDrag::preserve_fade_anchor") << endl; +} + +void +CrossfadeEdgeDrag::start_grab (GdkEvent* event, Gdk::Cursor *cursor) +{ + Drag::start_grab (event, cursor); +} + +void +CrossfadeEdgeDrag::motion (GdkEvent*, bool) +{ + double distance; + double new_length; + framecnt_t len; + + boost::shared_ptr ar (arv->audio_region()); + + if (start) { + distance = _drags->current_pointer_x() - grab_x(); + len = ar->fade_in()->back()->when; + } else { + distance = grab_x() - _drags->current_pointer_x(); + len = ar->fade_out()->back()->when; + } + + /* how long should it be ? */ + + new_length = len + _editor->unit_to_frame (distance); + + /* now check with the region that this is legal */ + + new_length = ar->verify_xfade_bounds (new_length, start); + + if (start) { + arv->redraw_start_xfade_to (ar, new_length); + } else { + arv->redraw_end_xfade_to (ar, new_length); + } +} + +void +CrossfadeEdgeDrag::finished (GdkEvent*, bool) +{ + double distance; + double new_length; + framecnt_t len; + + boost::shared_ptr ar (arv->audio_region()); + + if (start) { + distance = _drags->current_pointer_x() - grab_x(); + len = ar->fade_in()->back()->when; + } else { + distance = grab_x() - _drags->current_pointer_x(); + len = ar->fade_out()->back()->when; + } + + new_length = ar->verify_xfade_bounds (len + _editor->unit_to_frame (distance), start); + + _editor->begin_reversible_command ("xfade trim"); + ar->playlist()->clear_owned_changes (); + + if (start) { + ar->set_fade_in_length (new_length); + } else { + ar->set_fade_out_length (new_length); + } + + /* Adjusting the xfade may affect other regions in the playlist, so we need + to get undo Commands from the whole playlist rather than just the + region. + */ + + vector cmds; + ar->playlist()->rdiff (cmds); + _editor->session()->add_commands (cmds); + _editor->commit_reversible_command (); + +} + +void +CrossfadeEdgeDrag::aborted (bool) +{ + if (start) { + arv->redraw_start_xfade (); + } else { + arv->redraw_end_xfade (); + } +} +