X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor_drag.cc;h=7004f9b4192990dc39f973837cbdc5b5583658e3;hb=ac33bb425641bd4377f68f8a6a3eabc6c58286a9;hp=d9580c1eeb017f2b3689f0b4181ebabf75c13939;hpb=e5888d398350b26ba2cdc634cc9791e90b4fc6b6;p=ardour.git diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index d9580c1eeb..7004f9b419 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -32,12 +32,16 @@ #include "ardour/audioengine.h" #include "ardour/audioregion.h" +#include "ardour/audio_track.h" #include "ardour/dB.h" #include "ardour/midi_region.h" +#include "ardour/midi_track.h" #include "ardour/operations.h" #include "ardour/region_factory.h" #include "ardour/session.h" +#include "canvas/scroll_group.h" + #include "editor.h" #include "i18n.h" #include "keyboard.h" @@ -127,7 +131,7 @@ DragManager::start_grab (GdkEvent* e, Gdk::Cursor* c) _old_follow_playhead = _editor->follow_playhead (); _editor->set_follow_playhead (false); - _current_pointer_frame = _editor->canvas_event_frame (e, &_current_pointer_x, &_current_pointer_y); + _current_pointer_frame = _editor->canvas_event_sample (e, &_current_pointer_x, &_current_pointer_y); for (list::const_iterator i = _drags.begin(); i != _drags.end(); ++i) { (*i)->start_grab (e, c); @@ -173,7 +177,7 @@ DragManager::motion_handler (GdkEvent* e, bool from_autoscroll) { bool r = false; - _current_pointer_frame = _editor->canvas_event_frame (e, &_current_pointer_x, &_current_pointer_y); + _current_pointer_frame = _editor->canvas_event_sample (e, &_current_pointer_x, &_current_pointer_y); for (list::iterator i = _drags.begin(); i != _drags.end(); ++i) { bool const t = (*i)->motion_handler (e, from_autoscroll); @@ -191,7 +195,7 @@ DragManager::window_motion_handler (GdkEvent* e, bool from_autoscroll) { bool r = false; - _current_pointer_frame = _editor->window_event_frame (e, &_current_pointer_x, &_current_pointer_y); + _current_pointer_frame = _editor->canvas_event_sample (e, &_current_pointer_x, &_current_pointer_y); for (list::iterator i = _drags.begin(); i != _drags.end(); ++i) { bool const t = (*i)->motion_handler (e, from_autoscroll); @@ -259,7 +263,7 @@ Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor) _y_constrained = false; } - _raw_grab_frame = _editor->canvas_event_frame (event, &_grab_x, &_grab_y); + _raw_grab_frame = _editor->canvas_event_sample (event, &_grab_x, &_grab_y); setup_pointer_frame_offset (); _grab_frame = adjusted_frame (_raw_grab_frame, event); _last_pointer_frame = _grab_frame; @@ -361,16 +365,16 @@ Drag::motion_handler (GdkEvent* event, bool from_autoscroll) if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) { if (!from_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); + _editor->maybe_autoscroll (true, allow_vertical_autoscroll (), false); } - motion (event, _move_threshold_passed != old_move_threshold_passed); - - _last_pointer_x = _drags->current_pointer_x (); - _last_pointer_y = _drags->current_pointer_y (); - _last_pointer_frame = adjusted_current_frame (event); + if (!_editor->autoscroll_active() || from_autoscroll) { + motion (event, _move_threshold_passed != old_move_threshold_passed); + + _last_pointer_x = _drags->current_pointer_x (); + _last_pointer_y = _drags->current_pointer_y (); + _last_pointer_frame = adjusted_current_frame (event); + } return true; } @@ -450,7 +454,7 @@ struct EditorOrderTimeAxisViewSorter { RouteTimeAxisView* ra = dynamic_cast (a); RouteTimeAxisView* rb = dynamic_cast (b); assert (ra && rb); - return ra->route()->order_key (EditorSort) < rb->route()->order_key (EditorSort); + return ra->route()->order_key () < rb->route()->order_key (); } }; @@ -641,38 +645,39 @@ RegionMotionDrag::y_movement_allowed (int delta_track, double delta_layer) const void RegionMotionDrag::motion (GdkEvent* event, bool first_move) { + double delta_layer = 0; + int delta_time_axis_view = 0; + assert (!_views.empty ()); + /* Note: time axis views in this method are often expressed as an index into the _time_axis_views vector */ + /* Find the TimeAxisView that the pointer is now over */ - pair const tv = _editor->trackview_by_y_position (_drags->current_pointer_y ()); + pair const r = _editor->trackview_by_y_position (_drags->current_pointer_y ()); + TimeAxisView* tv = r.first; - /* Bail early if we're not over a track */ - RouteTimeAxisView* rtv = dynamic_cast (tv.first); + if (tv && tv->view()) { + double layer = r.second; + + if (first_move && tv->view()->layer_display() == Stacked) { + tv->view()->set_layer_display (Expanded); + } - if (!rtv || !rtv->is_track()) { - _editor->verbose_cursor()->hide (); - return; - } + /* Here's the current pointer position in terms of time axis view and layer */ + int const current_pointer_time_axis_view = find_time_axis_view (tv); + double const current_pointer_layer = tv->layer_display() == Overlaid ? 0 : layer; + + /* Work out the change in y */ - if (first_move && tv.first->view()->layer_display() == Stacked) { - tv.first->view()->set_layer_display (Expanded); + delta_time_axis_view = current_pointer_time_axis_view - _last_pointer_time_axis_view; + delta_layer = current_pointer_layer - _last_pointer_layer; } - - /* Note: time axis views in this method are often expressed as an index into the _time_axis_views vector */ - - /* Here's the current pointer position in terms of time axis view and layer */ - int const current_pointer_time_axis_view = find_time_axis_view (tv.first); - double const current_pointer_layer = tv.first->layer_display() == Overlaid ? 0 : tv.second; - + /* Work out the change in x */ framepos_t pending_region_position; double const x_delta = compute_x_delta (event, &pending_region_position); - /* Work out the change in y */ - - int delta_time_axis_view = current_pointer_time_axis_view - _last_pointer_time_axis_view; - double delta_layer = current_pointer_layer - _last_pointer_layer; - + /* Verify change in y */ if (!y_movement_allowed (delta_time_axis_view, delta_layer)) { /* this y movement is not allowed, so do no y movement this time */ delta_time_axis_view = 0; @@ -697,22 +702,9 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move) } if (first_move) { - rv->drag_start (); - - /* Reparent to a non scrolling group so that we can keep the - region selection above all time axis views. - Reparenting means that we will have to move the region view - within its new parent, as the two parent groups have different coordinates. - */ - - ArdourCanvas::Group* rvg = rv->get_canvas_group(); - Duple rv_canvas_offset = rvg->item_to_canvas (Duple (0,0)); - - rv->get_canvas_group()->reparent (_editor->_region_motion_group); - rv->fake_set_opaque (true); - rvg->set_position (rv_canvas_offset); + rv->raise_to_top (); } /* If we have moved tracks, we'll fudge the layer delta so that the @@ -725,61 +717,90 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move) this_delta_layer = - i->layer; } - /* The TimeAxisView that this region is now on */ - TimeAxisView* tv = _time_axis_views[i->time_axis_view + delta_time_axis_view]; + if (tv) { - /* Ensure it is moved from stacked -> expanded if appropriate */ - if (tv->view()->layer_display() == Stacked) { - tv->view()->set_layer_display (Expanded); - } + int track_index = i->time_axis_view + delta_time_axis_view; + + if (track_index < 0 || track_index >= (int) _time_axis_views.size()) { + continue; + } + + /* The TimeAxisView that this region is now over */ + TimeAxisView* current_tv = _time_axis_views[i->time_axis_view + delta_time_axis_view]; + + /* Ensure it is moved from stacked -> expanded if appropriate */ + if (current_tv->view()->layer_display() == Stacked) { + current_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; - } + /* We're only allowed to go -ve in layer on Expanded views */ + if (current_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 ()); + /* Set height */ + rv->set_height (current_tv->view()->child_height ()); - /* Update show/hidden status as the region view may have come from a hidden track, - or have moved to one. - */ - if (tv->hidden ()) { - rv->get_canvas_group()->hide (); - } else { - rv->get_canvas_group()->show (); - } + /* Update show/hidden status as the region view may have come from a hidden track, + or have moved to one. + */ + if (current_tv->hidden ()) { + rv->get_canvas_group()->hide (); + } else { + rv->get_canvas_group()->show (); + } - /* Update the DraggingView */ - i->time_axis_view += delta_time_axis_view; - i->layer += this_delta_layer; + /* Update the DraggingView */ + i->time_axis_view += delta_time_axis_view; + i->layer += this_delta_layer; - if (_brushing) { - _editor->mouse_brush_insert_region (rv, pending_region_position); - } else { - double x = 0; - double y = 0; + if (_brushing) { + _editor->mouse_brush_insert_region (rv, pending_region_position); + } else { + Duple track_origin; - /* Get the y coordinate of the top of the track that this region is now on */ - tv->canvas_display()->item_to_canvas (x, y); + /* Get the y coordinate of the top of the track that this region is now over */ + track_origin = current_tv->canvas_display()->item_to_canvas (track_origin); + + /* And adjust for the layer that it should be on */ + StreamView* cv = current_tv->view (); + switch (cv->layer_display ()) { + case Overlaid: + break; + case Stacked: + track_origin.y += (cv->layers() - i->layer - 1) * cv->child_height (); + break; + case Expanded: + track_origin.y += (cv->layers() - i->layer - 0.5) * 2 * cv->child_height (); + break; + } - /* And adjust for the layer that it should be on */ - StreamView* cv = tv->view (); - switch (cv->layer_display ()) { - case Overlaid: - break; - case Stacked: - y += (cv->layers() - i->layer - 1) * cv->child_height (); - break; - case Expanded: - y += (cv->layers() - i->layer - 0.5) * 2 * cv->child_height (); - break; + /* need to get the parent of the regionview + * canvas group and get its position in + * equivalent coordinate space as the trackview + * we are now dragging over. + */ + + /* Now move the region view */ + rv->move (x_delta, track_origin.y - rv->get_canvas_group()->item_to_canvas (Duple (0, 0)).y); } + } else { - /* Now move the region view */ - rv->move (x_delta, y - rv->get_canvas_group()->position().y); - } + /* Only move the region into the empty dropzone at the bottom if the pointer + * is down there. + */ + if (_drags->current_pointer_y() >= _editor->get_trackview_group()->item_to_canvas (Duple (0,0)).y) { + Duple track_origin; + + TimeAxisView* last = _time_axis_views.back(); + track_origin = last->canvas_display()->item_to_canvas (track_origin); + track_origin.y += last->effective_height(); + rv->move (x_delta, track_origin.y - rv->get_canvas_group()->item_to_canvas (Duple (0,0)).y); + i->time_axis_view = -1; + } + } + } /* foreach region */ _total_x_delta += x_delta; @@ -872,7 +893,15 @@ RegionMoveDrag::finished (GdkEvent* ev, bool movement_occurred) RegionMotionDrag::finished (ev, movement_occurred); if (!movement_occurred) { + /* just a click */ + + if (was_double_click() && !_views.empty()) { + DraggingView dv = _views.front(); + dv.view->show_region_editor (); + + } + return; } @@ -919,12 +948,36 @@ RegionMoveDrag::finished (GdkEvent* ev, bool movement_occurred) _editor->maybe_locate_with_edit_preroll (_editor->get_selection().regions.start()); } +RouteTimeAxisView* +RegionMoveDrag::create_destination_time_axis (boost::shared_ptr region) +{ + /* Add a new track of the correct type, and return the RouteTimeAxisView that is created to display the + new track. + */ + + try { + if (boost::dynamic_pointer_cast (region)) { + list > audio_tracks; + audio_tracks = _editor->session()->new_audio_track (region->n_channels(), region->n_channels(), ARDOUR::Normal, 0, 1, region->name()); + return _editor->axis_view_from_route (audio_tracks.front()); + } else { + ChanCount one_midi_port (DataType::MIDI, 1); + list > midi_tracks; + midi_tracks = _editor->session()->new_midi_track (one_midi_port, one_midi_port, boost::shared_ptr(), ARDOUR::Normal, 0, 1, region->name()); + return _editor->axis_view_from_route (midi_tracks.front()); + } + } catch (...) { + error << _("Could not create new track after region placed in the drop zone") << endmsg; + return 0; + } +} + void RegionMoveDrag::finished_copy (bool const changed_position, bool const /*changed_tracks*/, framecnt_t const drag_delta) { RegionSelection new_views; PlaylistSet modified_playlists; - list views_to_delete; + RouteTimeAxisView* new_time_axis_view = 0; if (_brushing) { /* all changes were made during motion event handlers */ @@ -944,7 +997,9 @@ RegionMoveDrag::finished_copy (bool const changed_position, bool const /*changed } /* insert the regions into their new playlists */ - for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { + for (list::const_iterator i = _views.begin(); i != _views.end();) { + + RouteTimeAxisView* dest_rtv = 0; if (i->view->region()->locked() || i->view->region()->video_locked()) { continue; @@ -957,27 +1012,31 @@ RegionMoveDrag::finished_copy (bool const changed_position, bool const /*changed } else { where = i->view->region()->position(); } - - RegionView* new_view = insert_region_into_playlist ( - i->view->region(), dynamic_cast (_time_axis_views[i->time_axis_view]), i->layer, where, modified_playlists - ); - - if (new_view == 0) { - continue; + + if (i->time_axis_view < 0) { + if (!new_time_axis_view) { + new_time_axis_view = create_destination_time_axis (i->view->region()); + } + dest_rtv = new_time_axis_view; + } else { + dest_rtv = dynamic_cast (_time_axis_views[i->time_axis_view]); + } + + if (dest_rtv != 0) { + RegionView* new_view = insert_region_into_playlist (i->view->region(), dest_rtv, i->layer, where, modified_playlists); + if (new_view != 0) { + new_views.push_back (new_view); + } } + + /* Delete the copy of the view that was used for dragging. Need to play safe with the iterator + since deletion will automagically remove it from _views, thus invalidating i as an iterator. + */ - new_views.push_back (new_view); - - /* we don't need the copied RegionView any more */ - views_to_delete.push_back (i->view); - } - - /* Delete views that are no longer needed; we can't do this directly in the iteration over _views - because when views are deleted they are automagically removed from _views, which messes - up the iteration. - */ - for (list::iterator i = views_to_delete.begin(); i != views_to_delete.end(); ++i) { - delete *i; + list::const_iterator next = i; + ++next; + delete i->view; + i = next; } /* If we've created new regions either by copying or moving @@ -1005,6 +1064,7 @@ RegionMoveDrag::finished_no_copy ( PlaylistSet modified_playlists; PlaylistSet frozen_playlists; set views_to_update; + RouteTimeAxisView* new_time_axis_view = 0; if (_brushing) { /* all changes were made during motion event handlers */ @@ -1021,15 +1081,26 @@ RegionMoveDrag::finished_no_copy ( for (list::const_iterator i = _views.begin(); i != _views.end(); ) { RegionView* rv = i->view; - - RouteTimeAxisView* const dest_rtv = dynamic_cast (_time_axis_views[i->time_axis_view]); - double const dest_layer = i->layer; + RouteTimeAxisView* dest_rtv = 0; if (rv->region()->locked() || rv->region()->video_locked()) { ++i; continue; } + + if (i->time_axis_view < 0) { + if (!new_time_axis_view) { + new_time_axis_view = create_destination_time_axis (rv->region()); + } + dest_rtv = new_time_axis_view; + } else { + dest_rtv = dynamic_cast (_time_axis_views[i->time_axis_view]); + } + + assert (dest_rtv); + double const dest_layer = i->layer; + views_to_update.insert (dest_rtv); framepos_t where; @@ -1069,6 +1140,17 @@ RegionMoveDrag::finished_no_copy ( } else { + boost::shared_ptr playlist = dest_rtv->playlist(); + + /* this movement may result in a crossfade being modified, or a layering change, + so we need to get undo data from the playlist as well as the region. + */ + + pair r = modified_playlists.insert (playlist); + if (r.second) { + playlist->clear_changes (); + } + rv->region()->clear_changes (); /* @@ -1082,30 +1164,18 @@ RegionMoveDrag::finished_no_copy ( rv->drag_end (); /* just change the model */ - - boost::shared_ptr playlist = dest_rtv->playlist(); - if (dest_rtv->view()->layer_display() == Stacked || dest_rtv->view()->layer_display() == Expanded) { playlist->set_layer (rv->region(), dest_layer); } /* freeze playlist to avoid lots of relayering in the case of a multi-region drag */ - pair r = frozen_playlists.insert (playlist); + r = frozen_playlists.insert (playlist); if (r.second) { playlist->freeze (); } - /* this movement may result in a crossfade being modified, so we need to get undo - data from the playlist as well as the region. - */ - - r = modified_playlists.insert (playlist); - if (r.second) { - playlist->clear_changes (); - } - rv->region()->set_position (where); _editor->session()->add_command (new StatefulDiffCommand (rv->region())); @@ -1498,7 +1568,7 @@ RegionCreateDrag::motion (GdkEvent* event, bool first_move) place snapped notes at the start of the region. */ - framecnt_t const len = (framecnt_t) fabs (f - grab_frame () - 1); + framecnt_t const len = (framecnt_t) fabs ((double)(f - grab_frame () - 1)); _region->set_length (len < 1 ? 1 : len); } } @@ -1781,9 +1851,10 @@ VideoTimeLineDrag::aborted (bool) TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list const & v, bool preserve_fade_anchor) : RegionDrag (e, i, p, v) + , _preserve_fade_anchor (preserve_fade_anchor) + , _jump_position_when_done (false) { DEBUG_TRACE (DEBUG::Drags, "New TrimDrag\n"); - _preserve_fade_anchor = preserve_fade_anchor; } void @@ -1820,6 +1891,10 @@ TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor*) } } + if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) { + _jump_position_when_done = true; + } + switch (_operation) { case StartTrim: show_verbose_cursor_time (region_start); @@ -1855,7 +1930,7 @@ TrimDrag::motion (GdkEvent* event, bool first_move) speed = tv->track()->speed(); } - framecnt_t const dt = adjusted_current_frame (event) - raw_grab_frame () + _pointer_frame_offset; + framecnt_t dt = adjusted_current_frame (event) - raw_grab_frame () + _pointer_frame_offset; if (first_move) { @@ -1871,6 +1946,9 @@ TrimDrag::motion (GdkEvent* event, bool first_move) case ContentsTrim: trim_type = "Region content trim"; break; + default: + assert(0); + break; } _editor->begin_reversible_command (trim_type); @@ -1903,42 +1981,67 @@ TrimDrag::motion (GdkEvent* event, bool first_move) non_overlap_trim = true; } + /* contstrain trim to fade length */ + if (_preserve_fade_anchor) { + switch (_operation) { + case StartTrim: + for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { + AudioRegionView* arv = dynamic_cast (i->view); + if (!arv) continue; + boost::shared_ptr ar (arv->audio_region()); + if (ar->locked()) continue; + framecnt_t len = ar->fade_in()->back()->when; + if (len < dt) dt = min(dt, len); + } + break; + case EndTrim: + for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { + AudioRegionView* arv = dynamic_cast (i->view); + if (!arv) continue; + boost::shared_ptr ar (arv->audio_region()); + if (ar->locked()) continue; + framecnt_t len = ar->fade_out()->back()->when; + if (len < -dt) dt = max(dt, -len); + } + break; + case ContentsTrim: + break; + } + } + + switch (_operation) { case StartTrim: - for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { + for (list::iterator i = _views.begin(); i != _views.end(); ++i) { 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->pixel_to_sample (distance); - new_length = ar->verify_xfade_bounds (new_length, true /*START*/ ); - arv->reset_fade_in_shape_width (ar, new_length); //the grey shape + framecnt_t len = ar->fade_in()->back()->when; + framecnt_t diff = ar->first_frame() - i->initial_position; + framepos_t new_length = len - diff; + i->anchored_fade_length = min (ar->length(), new_length); + //i->anchored_fade_length = ar->verify_xfade_bounds (new_length, true /*START*/ ); + arv->reset_fade_in_shape_width (ar, i->anchored_fade_length, true); } } } break; case EndTrim: - for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { + for (list::iterator i = _views.begin(); i != _views.end(); ++i) { 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->pixel_to_sample (distance); - new_length = ar->verify_xfade_bounds (new_length, false /*END*/ ); - arv->reset_fade_out_shape_width (ar, new_length); //the grey shape + framecnt_t len = ar->fade_out()->back()->when; + framecnt_t diff = 1 + ar->last_frame() - i->initial_end; + framepos_t new_length = len + diff; + i->anchored_fade_length = min (ar->length(), new_length); + //i->anchored_fade_length = ar->verify_xfade_bounds (new_length, false /*END*/ ); + arv->reset_fade_out_shape_width (ar, i->anchored_fade_length, true); } } } @@ -1946,8 +2049,7 @@ TrimDrag::motion (GdkEvent* event, bool first_move) case ContentsTrim: { - frame_delta = (adjusted_current_frame(event) - last_pointer_frame()); - // frame_delta = (last_pointer_frame() - adjusted_current_frame(event)); + frame_delta = (last_pointer_frame() - adjusted_current_frame(event)); for (list::const_iterator i = _views.begin(); i != _views.end(); ++i) { i->view->move_contents (frame_delta); @@ -1988,34 +2090,30 @@ TrimDrag::finished (GdkEvent* event, bool movement_occurred) 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->pixel_to_sample (distance); - new_length = ar->verify_xfade_bounds (new_length, true /*START*/ ); - ar->set_fade_in_length(new_length); + arv->reset_fade_in_shape_width (ar, i->anchored_fade_length); + ar->set_fade_in_length(i->anchored_fade_length); + ar->set_fade_in_active(true); } } + if (_jump_position_when_done) { + i->view->region()->set_position (i->initial_position); + } } } 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->pixel_to_sample (distance); - new_length = ar->verify_xfade_bounds (new_length, false /*END*/ ); - ar->set_fade_out_length(new_length); + arv->reset_fade_out_shape_width (ar, i->anchored_fade_length); + ar->set_fade_out_length(i->anchored_fade_length); + ar->set_fade_out_active(true); } } + if (_jump_position_when_done) { + i->view->region()->set_position (i->initial_end - i->view->region()->length()); + } } } @@ -2146,6 +2244,10 @@ MeterMarkerDrag::setup_pointer_frame_offset () void MeterMarkerDrag::motion (GdkEvent* event, bool first_move) { + if (!_marker->meter().movable()) { + return; + } + if (first_move) { // create a dummy marker for visual representation of moving the @@ -2191,6 +2293,13 @@ void MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred) { if (!movement_occurred) { + if (was_double_click()) { + _editor->edit_meter_marker (*_marker); + } + return; + } + + if (!_marker->meter().movable()) { return; } @@ -2266,6 +2375,10 @@ TempoMarkerDrag::setup_pointer_frame_offset () void TempoMarkerDrag::motion (GdkEvent* event, bool first_move) { + if (!_marker->tempo().movable()) { + return; + } + if (first_move) { // create a dummy marker for visual representation of moving the @@ -2310,6 +2423,13 @@ void TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred) { if (!movement_occurred) { + if (was_double_click()) { + _editor->edit_tempo_marker (*_marker); + } + return; + } + + if (!_marker->tempo().movable()) { return; } @@ -2358,7 +2478,7 @@ TempoMarkerDrag::aborted (bool moved) } CursorDrag::CursorDrag (Editor* e, EditorCursor& c, bool s) - : Drag (e, &c.time_bar_canvas_item()) + : Drag (e, &c.track_canvas_item()) , _cursor (c) , _stop (s) { @@ -2398,7 +2518,7 @@ CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c) _grab_zoom = _editor->samples_per_pixel; - framepos_t where = _editor->canvas_event_frame (event); + framepos_t where = _editor->canvas_event_sample (event); _editor->snap_to_with_modifier (where, event); @@ -3001,7 +3121,8 @@ MarkerDrag::finished (GdkEvent* event, bool movement_occurred) if (!movement_occurred) { if (was_double_click()) { - cerr << "End of marker double click\n"; + _editor->rename_marker (_marker); + return; } /* just a click, do nothing but finish @@ -3287,10 +3408,24 @@ LineDrag::motion (GdkEvent* event, bool) } void -LineDrag::finished (GdkEvent* event, bool) +LineDrag::finished (GdkEvent* event, bool movement_occured) { - motion (event, false); - _line->end_drag (false, 0); + if (movement_occured) { + motion (event, false); + _line->end_drag (false, 0); + } else { + /* add a new control point on the line */ + + AutomationTimeAxisView* atv; + + _line->end_drag (false, 0); + + if ((atv = dynamic_cast(_editor->clicked_axisview)) != 0) { + framepos_t where = _editor->window_event_sample (event, 0, 0); + atv->add_automation_event (event, where, event->button.y, false); + } + } + _editor->session()->commit_reversible_command (); } @@ -3428,16 +3563,28 @@ RubberbandSelectDrag::motion (GdkEvent* event, bool) double x1 = _editor->sample_to_pixel (start); double x2 = _editor->sample_to_pixel (end); + const double min_dimension = 2.0; _editor->rubberband_rect->set_x0 (x1); if (_vertical_only) { /* fixed 10 pixel width */ _editor->rubberband_rect->set_x1 (x1 + 10); } else { + if (x2 < x1) { + x2 = min (x1 - min_dimension, x2); + } else { + x2 = max (x1 + min_dimension, x2); + } _editor->rubberband_rect->set_x1 (x2); } _editor->rubberband_rect->set_y0 (y1); + if (y2 < y1) { + y2 = min (y1 - min_dimension, y2); + } else { + y2 = max (y1 + min_dimension, y2); + } + _editor->rubberband_rect->set_y1 (y2); _editor->rubberband_rect->show(); @@ -3731,16 +3878,9 @@ SelectionDrag::motion (GdkEvent* event, bool first_move) 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) { - return; - } - framepos_t const pending_position = adjusted_current_frame (event); - /* only alter selection if things have changed */ - - if (pending_time_axis.first->order() == _last_pointer_time_axis && pending_position == last_pointer_frame()) { + if (_operation != CreateSelection && pending_position == last_pointer_frame()) { return; } @@ -3773,51 +3913,49 @@ SelectionDrag::motion (GdkEvent* event, bool first_move) if (first_move) { 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); _add = false; + } else { + /* new selection */ if (_editor->clicked_axisview && !_editor->selection->selected (_editor->clicked_axisview)) { - //_editor->selection->set (_editor->clicked_axisview); _editor->set_selected_track_as_side_effect (Selection::Set); } _editor->clicked_selection = _editor->selection->set (start, end); } } + + /* select all tracks within the rectangle that we've marked out so far */ + TrackViewList to_be_added_to_selection; + TrackViewList to_be_removed_from_selection; + TrackViewList& all_tracks (_editor->track_views); - /* select the track that we're in */ - if (find (_added_time_axes.begin(), _added_time_axes.end(), pending_time_axis.first) == _added_time_axes.end()) { - // _editor->set_selected_track_as_side_effect (Selection::Add); - _editor->selection->add (pending_time_axis.first); - _added_time_axes.push_back (pending_time_axis.first); - } - - /* deselect any tracks that this drag no longer includes, being careful to only deselect - tracks that we selected in the first place. - */ - - int min_order = min (_original_pointer_time_axis, pending_time_axis.first->order()); - int max_order = max (_original_pointer_time_axis, pending_time_axis.first->order()); - - list::iterator i = _added_time_axes.begin(); - while (i != _added_time_axes.end()) { - - list::iterator tmp = i; - ++tmp; - - if ((*i)->order() < min_order || (*i)->order() > max_order) { - _editor->selection->remove (*i); - _added_time_axes.remove (*i); + for (TrackViewList::const_iterator i = all_tracks.begin(); i != all_tracks.end(); ++i) { + + if ((*i)->covered_by_y_range (grab_y(), _drags->current_pointer_y())) { + if (!(*i)->get_selected()) { + to_be_added_to_selection.push_back (*i); + } + } else { + if ((*i)->get_selected()) { + to_be_removed_from_selection.push_back (*i); + } } + } - i = tmp; + if (!to_be_added_to_selection.empty()) { + _editor->selection->add (to_be_added_to_selection); } + if (!to_be_removed_from_selection.empty()) { + _editor->selection->remove (to_be_removed_from_selection); + } } break; @@ -3864,10 +4002,6 @@ SelectionDrag::motion (GdkEvent* event, bool first_move) break; } - if (event->button.x >= _editor->horizontal_position() + _editor->_visible_canvas_width) { - _editor->start_canvas_autoscroll (1, 0); - } - if (start != end) { switch (_operation) { case SelectionMove: @@ -4055,10 +4189,6 @@ RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move) } } - if (event->button.x >= _editor->horizontal_position() + _editor->_visible_canvas_width) { - _editor->start_canvas_autoscroll (1, 0); - } - if (start != end) { _editor->temp_location->set (start, end); @@ -4116,10 +4246,24 @@ RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred) _editor->new_transport_marker_context_menu (&event->button, _item); break; } + } else { + /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */ - if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) { + if (_operation == CreateTransportMarker) { + + /* didn't drag, so just locate */ + + _editor->session()->request_locate (grab_frame(), _editor->session()->transport_rolling()); + + } else if (_operation == CreateCDMarker) { + + /* didn't drag, but mark is already created so do + * nothing */ + + } else { /* operation == CreateRangeMarker */ + framepos_t start; framepos_t end; @@ -4357,7 +4501,7 @@ NoteDrag::motion (GdkEvent *, bool) uint8_t new_note = min (max (_primary->note()->note() + note_delta, 0), 127); snprintf (buf, sizeof (buf), "%s (%d)", Evoral::midi_note_name (new_note).c_str(), - (int) floor (new_note)); + (int) floor ((double)new_note)); show_verbose_cursor_text (buf); } @@ -4836,7 +4980,7 @@ NoteCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor) double const y = sv->note_to_y (sv->y_to_note (y_to_region (event->button.y))); _drag_rect->set (ArdourCanvas::Rect (x, y, x, y + floor (_region_view->midi_stream_view()->note_height ()))); - _drag_rect->set_outline_what (0xff); + _drag_rect->set_outline_all (); _drag_rect->set_outline_color (0xffffff99); _drag_rect->set_fill_color (0xffffff66); } @@ -4861,7 +5005,7 @@ NoteCreateDrag::finished (GdkEvent*, bool had_movement) } framepos_t const start = min (_note[0], _note[1]); - framecnt_t length = (framecnt_t) fabs (_note[0] - _note[1]); + framecnt_t length = (framecnt_t) fabs ((double)(_note[0] - _note[1])); framecnt_t const g = grid_frames (start); double const one_tick = 1 / Timecode::BBT_Time::ticks_per_beat;