After dragging from multiple tracks to the dropzone, create the right number of new...
[ardour.git] / gtk2_ardour / editor_drag.cc
index ba7964f5e0cb56fc0029c872d5c9417da1276039..519c7d9f329e9b32e39d32e1ed3c6e022bd00384 100644 (file)
@@ -108,6 +108,7 @@ DragManager::abort ()
        }
 
        _drags.clear ();
+       _editor->abort_reversible_command();
 
        _ending = false;
 }
@@ -219,6 +220,7 @@ Drag::Drag (Editor* e, ArdourCanvas::Item* i, bool trackview_only)
        , _pointer_frame_offset (0)
        , _trackview_only (trackview_only)
        , _move_threshold_passed (false)
+    , _starting_point_passed (false)
        , _was_double_click (false)
        , _raw_grab_frame (0)
        , _grab_frame (0)
@@ -233,11 +235,13 @@ Drag::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t /*t
        _item->ungrab ();
        _item = new_item;
 
-       if (cursor == 0) {
-               _item->grab ();
+       if (!_cursor_ctx) {
+               _cursor_ctx = CursorContext::create (*_editor, cursor);
        } else {
-               _item->grab ();
+               _cursor_ctx->change (cursor);
        }
+
+       _item->grab ();
 }
 
 void
@@ -270,12 +274,11 @@ Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
 
        _last_pointer_y = _grab_y;
 
-       if (cursor == 0) {
-               _item->grab ();
-       } else {
+       _item->grab ();
+
+       if (!_editor->cursors()->is_invalid (cursor)) {
                /* CAIROCANVAS need a variant here that passes *cursor */
-               _item->grab ();
-               _cursor_ctx = CursorContext::create(*_editor, cursor);
+               _cursor_ctx = CursorContext::create (*_editor, cursor);
        }
 
        if (_editor->session() && _editor->session()->transport_rolling()) {
@@ -369,7 +372,7 @@ Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
 
        bool const old_move_threshold_passed = _move_threshold_passed;
 
-       if (!from_autoscroll && !_move_threshold_passed) {
+       if (!_move_threshold_passed) {
 
                bool const xp = (::llabs (_drags->current_pointer_frame () - _raw_grab_frame) >= threshold.first);
                bool const yp = (::fabs ((current_pointer_y () - _grab_y)) >= threshold.second);
@@ -385,7 +388,14 @@ Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
                        }
 
                        if (!_editor->autoscroll_active() || from_autoscroll) {
-                               motion (event, _move_threshold_passed != old_move_threshold_passed);
+                
+                               bool first_move = (_move_threshold_passed != old_move_threshold_passed) ||
+                                       from_autoscroll;
+                               motion (event, first_move && !_starting_point_passed);
+                               
+                               if (first_move && !_starting_point_passed) {
+                                       _starting_point_passed = true;
+                               }
                                
                                _last_pointer_x = _drags->current_pointer_x ();
                                _last_pointer_y = current_pointer_y ();
@@ -698,6 +708,9 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
        for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
 
                RegionView* rv = i->view;
+               double y_delta;
+
+               y_delta = 0;
 
                if (rv->region()->locked() || rv->region()->video_locked()) {
                        continue;
@@ -717,7 +730,7 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
                        /* move the item so that it continues to appear at the
                           same location now that its parent has changed.
                        */
-                       rvg->move (rv_canvas_offset - dmg_canvas_offset);
+                        rvg->move (rv_canvas_offset - dmg_canvas_offset);
                }
 
                /* If we have moved tracks, we'll fudge the layer delta so that the
@@ -739,7 +752,7 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
                        } else {
                                track_index = _time_axis_views.size() - 1 + delta_time_axis_view;
                        }
-                        
+                       
                        if (track_index < 0 || track_index >= (int) _time_axis_views.size()) {
                                continue;
                        }
@@ -799,10 +812,12 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
                                 * equivalent coordinate space as the trackview
                                 * we are now dragging over.
                                 */
+
+                               y_delta = track_origin.y - rv->get_canvas_group()->canvas_origin().y;
                                
-                               /* Now move the region view */
-                               rv->move (x_delta, track_origin.y - rv->get_canvas_group()->canvas_origin().y);
                        }
+
+
                } else {
 
                        /* Only move the region into the empty dropzone at the bottom if the pointer
@@ -819,11 +834,14 @@ RegionMotionDrag::motion (GdkEvent* event, bool first_move)
                                        last_track_bottom_edge = 0;
                                }
 
-                               rv->move (x_delta, last_track_bottom_edge - rv->get_canvas_group()->canvas_origin().y);
+                               y_delta = last_track_bottom_edge - rv->get_canvas_group()->canvas_origin().y;
                                i->time_axis_view = -1;
                        }
                }
                
+               /* Now move the region view */
+               rv->move (x_delta, y_delta);
+               
        } /* foreach region */
 
        _total_x_delta += x_delta;
@@ -1035,6 +1053,12 @@ RegionMoveDrag::finished_copy (bool const changed_position, bool const /*changed
                return;
        }
 
+       typedef map<boost::shared_ptr<Playlist>, RouteTimeAxisView*> PlaylistMapping;
+       PlaylistMapping playlist_mapping;
+
+       typedef map<boost::shared_ptr<Playlist>, RouteTimeAxisView*> PlaylistMapping;
+       PlaylistMapping playlist_mapping;
+
        /* insert the regions into their new playlists */
        for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end();) {
 
@@ -1051,13 +1075,23 @@ RegionMoveDrag::finished_copy (bool const changed_position, bool const /*changed
                } else {
                        where = i->view->region()->position();
                }
-               
+
                if (i->time_axis_view < 0) {
-                       if (!new_time_axis_view) {
+                       /* dragged to drop zone */
+
+                       PlaylistMapping::iterator pm;
+                       
+                       if ((pm = playlist_mapping.find (i->view->region()->playlist())) == playlist_mapping.end()) {
+                               /* first region from this original playlist: create a new track */
                                new_time_axis_view = create_destination_time_axis (i->view->region(), i->initial_time_axis_view);
+                               playlist_mapping.insert (make_pair (i->view->region()->playlist(), new_time_axis_view));
+                               dest_rtv = new_time_axis_view;
+                       } else {
+                               /* we already created a new track for regions from this playlist, use it */
+                               dest_rtv = pm->second;
                        }
-                       dest_rtv = new_time_axis_view;
                } else {
+                       /* destination time axis view is the one we dragged to */
                        dest_rtv = dynamic_cast<RouteTimeAxisView*> (_time_axis_views[i->time_axis_view]);
                }               
                
@@ -1111,6 +1145,12 @@ RegionMoveDrag::finished_no_copy (
                return;
        }
 
+       typedef map<boost::shared_ptr<Playlist>, RouteTimeAxisView*> PlaylistMapping;
+       PlaylistMapping playlist_mapping;
+
+       typedef map<boost::shared_ptr<Playlist>, RouteTimeAxisView*> PlaylistMapping;
+       PlaylistMapping playlist_mapping;
+
        for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ) {
 
                RegionView* rv = i->view;
@@ -1122,14 +1162,25 @@ RegionMoveDrag::finished_no_copy (
                }
                
                if (i->time_axis_view < 0) {
-                       if (!new_time_axis_view) {
-                               new_time_axis_view = create_destination_time_axis (rv->region(), i->initial_time_axis_view);
+                       /* dragged to drop zone */
+
+                       PlaylistMapping::iterator pm;
+                       
+                       if ((pm = playlist_mapping.find (i->view->region()->playlist())) == playlist_mapping.end()) {
+                               /* first region from this original playlist: create a new track */
+                               new_time_axis_view = create_destination_time_axis (i->view->region(), i->initial_time_axis_view);
+                               playlist_mapping.insert (make_pair (i->view->region()->playlist(), new_time_axis_view));
+                               dest_rtv = new_time_axis_view;
+                       } else {
+                               /* we already created a new track for regions from this playlist, use it */
+                               dest_rtv = pm->second;
                        }
-                       dest_rtv = new_time_axis_view;
+                       
                } else {
+                       /* destination time axis view is the one we dragged to */
                        dest_rtv = dynamic_cast<RouteTimeAxisView*> (_time_axis_views[i->time_axis_view]);
-               }
-                       
+               }               
+
                assert (dest_rtv);
 
                double const dest_layer = i->layer;
@@ -1369,8 +1420,11 @@ RegionMoveDrag::aborted (bool movement_occurred)
 {
        if (_copy) {
 
-               for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+               for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end();) {
+                       list<DraggingView>::const_iterator next = i;
+                       ++next;
                        delete i->view;
+                       i = next;
                }
 
                _views.clear ();
@@ -1963,6 +2017,8 @@ NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*ignored*/)
        */
        region->note_selected (cnote, cnote->selected ());
 
+       _editor->begin_reversible_command (_("resize notes"));
+
        for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ) {
                MidiRegionSelection::iterator next;
                next = r;
@@ -2001,6 +2057,8 @@ NoteResizeDrag::finished (GdkEvent*, bool /*movement_occurred*/)
                        mrv->commit_resizing (nb, at_front, _drags->current_pointer_x() - grab_x(), relative);
                }
        }
+
+       _editor->commit_reversible_command ();
 }
 
 void
@@ -3515,9 +3573,27 @@ MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
 }
 
 void
-MarkerDrag::aborted (bool)
+MarkerDrag::aborted (bool movement_occured)
 {
-       /* XXX: TODO */
+       if (!movement_occured) {
+               return;
+       }
+
+       for (CopiedLocationInfo::iterator x = _copied_locations.begin(); x != _copied_locations.end(); ++x) {
+
+               /* move all markers to their original location */
+               
+
+               for (vector<Marker*>::iterator m = x->markers.begin(); m != x->markers.end(); ++m) {
+
+                       bool is_start;
+                       Location * location = _editor->find_location_from_marker (*m, is_start);
+
+                       if (location) {
+                               (*m)->set_position (is_start ? location->start() : location->end());
+                       }
+               }
+       }
 }
 
 void
@@ -3845,7 +3921,7 @@ void
 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
 {
        Drag::start_grab (event);
-       show_verbose_cursor_time (adjusted_current_frame (event));
+       show_verbose_cursor_time (adjusted_current_frame (event, ARDOUR_UI::config()->get_rubberbanding_snaps_to_grid()));
 }
 
 void
@@ -3856,11 +3932,13 @@ RubberbandSelectDrag::motion (GdkEvent* event, bool)
        double y1;
        double y2;
 
-       framepos_t const pf = adjusted_current_frame (event, ARDOUR_UI::config()->get_rubberbanding_snaps_to_grid ());
+       framepos_t const pf = adjusted_current_frame (event, ARDOUR_UI::config()->get_rubberbanding_snaps_to_grid());
 
        framepos_t grab = grab_frame ();
        if (ARDOUR_UI::config()->get_rubberbanding_snaps_to_grid ()) {
                _editor->snap_to_with_modifier (grab, event);
+       } else {
+               grab = raw_grab_frame ();
        }
 
        /* base start and end on initial click position */
@@ -3931,13 +4009,20 @@ RubberbandSelectDrag::do_select_things (GdkEvent* event, bool drag_in_progress)
 {
        framepos_t x1;
        framepos_t x2;
+       framepos_t grab = grab_frame ();
+       framepos_t lpf = last_pointer_frame ();
+
+       if (!ARDOUR_UI::config()->get_rubberbanding_snaps_to_grid ()) {
+               grab = raw_grab_frame ();
+               lpf = _editor->pixel_to_sample_from_event (last_pointer_x());
+       }
        
-       if (grab_frame() < last_pointer_frame()) {
-               x1 = grab_frame ();
-               x2 = last_pointer_frame ();
+       if (grab < lpf) {
+               x1 = grab;
+               x2 = lpf;
        } else {
-               x2 = grab_frame ();
-               x1 = last_pointer_frame ();
+               x2 = grab;
+               x1 = lpf;
        }
 
        double y1;
@@ -4131,7 +4216,7 @@ SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
                return;
        }
 
-       Gdk::Cursor* cursor = 0;
+       Gdk::Cursor* cursor = MouseCursors::invalid_cursor();
 
        switch (_operation) {
        case CreateSelection:
@@ -4462,6 +4547,15 @@ RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operat
        _drag_rect->set_outline_color (ARDOUR_UI::config()->color ("range drag rect"));
 }
 
+RangeMarkerBarDrag::~RangeMarkerBarDrag()
+{
+       /* normal canvas items will be cleaned up when their parent group is deleted. But 
+          this item is created as the child of a long-lived parent group, and so we
+          need to explicitly delete it.
+       */
+       delete _drag_rect;
+}
+
 void
 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
 {
@@ -4469,7 +4563,7 @@ RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
                return;
        }
 
-       Gdk::Cursor* cursor = 0;
+       Gdk::Cursor* cursor = MouseCursors::invalid_cursor();
 
        if (!_editor->temp_location) {
                _editor->temp_location = new Location (*_editor->session());
@@ -4669,9 +4763,11 @@ RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
 }
 
 void
-RangeMarkerBarDrag::aborted (bool)
+RangeMarkerBarDrag::aborted (bool movement_occured)
 {
-       /* XXX: TODO */
+       if (movement_occured) {
+               _drag_rect->hide ();
+       }
 }
 
 void
@@ -5440,9 +5536,9 @@ void
 CrossfadeEdgeDrag::aborted (bool)
 {
        if (start) {
-               arv->redraw_start_xfade ();
+               // arv->redraw_start_xfade ();
        } else {
-               arv->redraw_end_xfade ();
+               // arv->redraw_end_xfade ();
        }
 }