Further refactoring of drag code. Changes so that drags from the region list display...
authorCarl Hetherington <carl@carlh.net>
Mon, 8 Jun 2009 19:28:51 +0000 (19:28 +0000)
committerCarl Hetherington <carl@carlh.net>
Mon, 8 Jun 2009 19:28:51 +0000 (19:28 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@5127 d708f5d6-7413-0410-9779-e7cbd77b26cf

26 files changed:
gtk2_ardour/audio_region_view.cc
gtk2_ardour/audio_region_view.h
gtk2_ardour/audio_streamview.cc
gtk2_ardour/audio_streamview.h
gtk2_ardour/automation_region_view.cc
gtk2_ardour/automation_region_view.h
gtk2_ardour/automation_streamview.cc
gtk2_ardour/editor.h
gtk2_ardour/editor_canvas.cc
gtk2_ardour/editor_canvas_events.cc
gtk2_ardour/editor_drag.cc
gtk2_ardour/editor_drag.h
gtk2_ardour/editor_mouse.cc
gtk2_ardour/midi_region_view.cc
gtk2_ardour/midi_region_view.h
gtk2_ardour/midi_streamview.cc
gtk2_ardour/midi_streamview.h
gtk2_ardour/region_view.cc
gtk2_ardour/region_view.h
gtk2_ardour/streamview.cc
gtk2_ardour/streamview.h
gtk2_ardour/tape_region_view.cc
gtk2_ardour/tape_region_view.h
gtk2_ardour/time_axis_view_item.cc
gtk2_ardour/time_axis_view_item.h
libs/gtkmm2ext/gtkmm2ext/dndtreeview.h

index ca8090dcc4d2de702db3574997d9a79dbc19c5ff..30f97ba523854ac9303060b5c01019278e0495db 100644 (file)
@@ -66,7 +66,7 @@ using namespace ArdourCanvas;
 static const int32_t sync_mark_width = 9;
 
 AudioRegionView::AudioRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, boost::shared_ptr<AudioRegion> r, double spu,
-                                 Gdk::Color& basic_color)
+                                 Gdk::Color const & basic_color)
        : RegionView (parent, tv, r, spu, basic_color)
        , sync_mark(0)
        , zero_line(0)
@@ -83,7 +83,7 @@ AudioRegionView::AudioRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView
 
 
 AudioRegionView::AudioRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, boost::shared_ptr<AudioRegion> r, double spu, 
-                                 Gdk::Color& basic_color, bool recording, TimeAxisViewItem::Visibility visibility)
+                                 Gdk::Color const & basic_color, bool recording, TimeAxisViewItem::Visibility visibility)
        : RegionView (parent, tv, r, spu, basic_color, recording, visibility)
        , sync_mark(0)
        , zero_line(0)
@@ -145,7 +145,7 @@ AudioRegionView::AudioRegionView (const AudioRegionView& other, boost::shared_pt
 }
 
 void
-AudioRegionView::init (Gdk::Color& basic_color, bool wfd)
+AudioRegionView::init (Gdk::Color const & basic_color, bool wfd)
 {
        // FIXME: Some redundancy here with RegionView::init.  Need to figure out
        // where order is important and where it isn't...
@@ -731,9 +731,9 @@ AudioRegionView::set_amplitude_above_axis (gdouble spp)
 }
 
 void
-AudioRegionView::compute_colors (Gdk::Color& basic_color)
+AudioRegionView::compute_colors (Gdk::Color const & basic_color)
 {
-       RegionView::compute_colors(basic_color);
+       RegionView::compute_colors (basic_color);
        
        uint32_t r, g, b, a;
 
index 35e93b985f889a2a6b20b1978e7b05dfe30effc7..6d74b7a1ed32ed4775a3eb1316fea74d163c45ae 100644 (file)
@@ -53,22 +53,22 @@ class AudioRegionView : public RegionView
                         RouteTimeAxisView&,
                         boost::shared_ptr<ARDOUR::AudioRegion>,
                         double initial_samples_per_unit,
-                        Gdk::Color& basic_color);
+                        Gdk::Color const & basic_color);
 
        AudioRegionView (ArdourCanvas::Group *, 
-                    RouteTimeAxisView&,
-                    boost::shared_ptr<ARDOUR::AudioRegion>,
-                    double      samples_per_unit,
-                    Gdk::Color& basic_color,
+                        RouteTimeAxisView&,
+                        boost::shared_ptr<ARDOUR::AudioRegion>,
+                        double samples_per_unit,
+                        Gdk::Color const & basic_color,
                         bool recording,
-                    TimeAxisViewItem::Visibility);
+                        TimeAxisViewItem::Visibility);
 
        AudioRegionView (const AudioRegionView& other);
        AudioRegionView (const AudioRegionView& other, boost::shared_ptr<ARDOUR::AudioRegion>);
 
        ~AudioRegionView ();
        
-       virtual void init (Gdk::Color& base_color, bool wait_for_data);
+       virtual void init (Gdk::Color const & base_color, bool wait_for_data);
        
        boost::shared_ptr<ARDOUR::AudioRegion> audio_region() const;
        
@@ -162,7 +162,7 @@ class AudioRegionView : public RegionView
     void store_flags ();
 
     void set_colors ();
-    void compute_colors (Gdk::Color&);
+    void compute_colors (Gdk::Color const &);
     void reset_width_dependent_items (double pixel_width);
     void set_waveview_data_src();
     void set_frame_color ();
index 03f3d3d8bde6b100f81a0098dc6dff9382c655de..e2aa080b645a3a90d19b7dd2cd7ca5a2b598b97c 100644 (file)
@@ -104,36 +104,15 @@ AudioStreamView::set_amplitude_above_axis (gdouble app)
 }
 
 RegionView*
-AudioStreamView::add_region_view_internal (boost::shared_ptr<Region> r, bool wait_for_waves, bool recording)
+AudioStreamView::create_region_view (boost::shared_ptr<Region> r, bool wait_for_waves, bool recording)
 {
        AudioRegionView *region_view = 0;
        boost::shared_ptr<AudioRegion> region = boost::dynamic_pointer_cast<AudioRegion> (r);
 
        if (region == 0) {
-               return NULL;
+               return 0;
        }
 
-//     if(!recording){
-//             for (list<RegionView *>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
-//                     if ((*i)->region() == r) {
-//                             cerr << "audio_streamview in add_region_view_internal region found" << endl;
-                               /* great. we already have a AudioRegionView for this Region. use it again. */
-                               
-//                             (*i)->set_valid (true);
-
-                               // this might not be necessary
-//                             AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
-
-//                             if (arv) {
-//                                     arv->set_waveform_scale (_waveform_scale);
-//                                     arv->set_waveform_shape (_waveform_shape);
-//                             }
-                                       
-//                             return NULL;
-//                     }
-//             }
-//     }
-
        switch (_trackview.audio_track()->mode()) {
        
        case NonLayered:
@@ -160,7 +139,6 @@ AudioStreamView::add_region_view_internal (boost::shared_ptr<Region> r, bool wai
        region_view->init (region_color, wait_for_waves);
        region_view->set_amplitude_above_axis(_amplitude_above_axis);
        region_view->set_height (child_height ());
-       region_views.push_front (region_view);
 
        /* if its the special single-sample length that we use for rec-regions, make it 
           insensitive to events 
@@ -195,8 +173,42 @@ AudioStreamView::add_region_view_internal (boost::shared_ptr<Region> r, bool wai
        /* follow global waveform setting */
        region_view->set_waveform_visible(_trackview.editor().show_waveforms());
 
+       return region_view;     
+}
+
+RegionView*
+AudioStreamView::add_region_view_internal (boost::shared_ptr<Region> r, bool wait_for_waves, bool recording)
+{
+       RegionView *region_view = create_region_view (r, wait_for_waves, recording);
+       if (region_view == 0) {
+               return 0;
+       }
+
+//     if(!recording){
+//             for (list<RegionView *>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
+//                     if ((*i)->region() == r) {
+//                             cerr << "audio_streamview in add_region_view_internal region found" << endl;
+                               /* great. we already have a AudioRegionView for this Region. use it again. */
+                               
+//                             (*i)->set_valid (true);
+
+                               // this might not be necessary
+//                             AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
+
+//                             if (arv) {
+//                                     arv->set_waveform_scale (_waveform_scale);
+//                                     arv->set_waveform_shape (_waveform_shape);
+//                             }
+                                       
+//                             return NULL;
+//                     }
+//             }
+//     }
+
+       region_views.push_front (region_view);
+
        /* catch regionview going away */
-       region->GoingAway.connect (bind (mem_fun (*this, &AudioStreamView::remove_region_view), boost::weak_ptr<Region> (r)));
+       r->GoingAway.connect (bind (mem_fun (*this, &AudioStreamView::remove_region_view), boost::weak_ptr<Region> (r)));
 
        RegionViewAdded (region_view);
 
@@ -400,7 +412,7 @@ AudioStreamView::redisplay_diskstream ()
 
        if (_trackview.is_audio_track()) {
                _trackview.get_diskstream()->playlist()->foreach_region(
-                       sigc::mem_fun (*this, &StreamView::add_region_view)
+                       sigc::hide_return (sigc::mem_fun (*this, &StreamView::add_region_view))
                        );
 
                boost::shared_ptr<AudioPlaylist> apl = boost::dynamic_pointer_cast<AudioPlaylist>(
index 9c1335042b19d232dc346915c8f9e1849c1f6059..728e9b39f239710d62270983c6d07a6a2f514b53 100644 (file)
@@ -80,6 +80,8 @@ class AudioStreamView : public StreamView
        void hide_xfades_involving (AudioRegionView&);
        void reveal_xfades_involving (AudioRegionView&);
 
+       RegionView* create_region_view (boost::shared_ptr<ARDOUR::Region>, bool, bool);
+
   private:
        void setup_rec_box ();
        void rec_peak_range_ready (nframes_t start, nframes_t cnt, boost::weak_ptr<ARDOUR::Source> src); 
index dc0a5b07cdeaf5a4b23eb75d95dd5e9954221e1a..80dbd669ca1ccd5d768668f59d36d28f12ef77b9 100644 (file)
@@ -33,7 +33,7 @@ AutomationRegionView::AutomationRegionView(ArdourCanvas::Group*
                                            const Evoral::Parameter&                  param,
                                            boost::shared_ptr<ARDOUR::AutomationList> list,
                                            double                                    spu,
-                                           Gdk::Color&                               basic_color)
+                                           Gdk::Color const &                        basic_color)
        : RegionView(parent, time_axis, region, spu, basic_color)
        , _parameter(param)
 { 
@@ -46,7 +46,7 @@ AutomationRegionView::AutomationRegionView(ArdourCanvas::Group*
 }
 
 void
-AutomationRegionView::init (Gdk::Color& basic_color, bool wfd)
+AutomationRegionView::init (Gdk::Color const & basic_color, bool wfd)
 {
        _enable_display = false;
        
index 99a344d681adabbf55b55f5ceba56f55930a5985..e6531821d3959dc593f4a1db6a4377bc5514a8d3 100644 (file)
@@ -45,11 +45,11 @@ public:
                             const Evoral::Parameter& parameter,
                             boost::shared_ptr<ARDOUR::AutomationList>,
                             double initial_samples_per_unit,
-                            Gdk::Color& basic_color);
+                            Gdk::Color const & basic_color);
 
        ~AutomationRegionView() {}
        
-       void init (Gdk::Color& basic_color, bool wfd);
+       void init (Gdk::Color const & basic_color, bool wfd);
        
        inline AutomationTimeAxisView* automation_view() const
                { return dynamic_cast<AutomationTimeAxisView*>(&trackview); }
index 0ba49fd2d9c801391da861d54278cfe0af303e6f..1654e7e5a9ceac2240a11d18d2542a532a5d3feb 100644 (file)
@@ -167,7 +167,7 @@ AutomationStreamView::redisplay_diskstream ()
        // Add and display region views, and flag them as valid
        if (_trackview.is_track()) {
                _trackview.get_diskstream()->playlist()->foreach_region (
-                       sigc::mem_fun (*this, &StreamView::add_region_view)
+                       sigc::hide_return (sigc::mem_fun (*this, &StreamView::add_region_view))
                        );
        }
        
index c8fc118efaec69f0225cdf47f16d2518a9f6002a..2a28d0fe1b2d09b8e3be7184c31ac89eb4b27f11 100644 (file)
@@ -1495,6 +1495,7 @@ public:
        Gtk::Allocation canvas_allocation;
        void track_canvas_allocate (Gtk::Allocation alloc);
        bool track_canvas_size_allocated ();
+       bool track_canvas_drag_motion (Glib::RefPtr<Gdk::DragContext> const &, int, int, guint);
 
        void set_playhead_cursor ();
 
@@ -2014,7 +2015,7 @@ public:
 
        void duplicate_dialog (bool with_dialog);
        
-       nframes64_t event_frame (GdkEvent*, double* px = 0, double* py = 0) const;
+       nframes64_t event_frame (GdkEvent const *, double* px = 0, double* py = 0) const;
 
        /* returns false if mouse pointer is not in track or marker canvas
         */
@@ -2244,6 +2245,8 @@ public:
        friend class RangeMarkerBarDrag;
        friend class MouseZoomDrag;
        friend class RegionCreateDrag;
+       friend class RegionMotionDrag;
+       friend class RegionInsertDrag;
 };
 
 #endif /* __ardour_editor_h__ */
index 10878ce712c2bd17373460b560e83684b932674c..0c10ebf8c334a4d4ab3da2148c29584b2f033a34 100644 (file)
@@ -22,7 +22,6 @@
 #include <jack/types.h>
 #include <gtkmm2ext/utils.h>
 
-#include "ardour/audioregion.h"
 #include "ardour/profile.h"
 
 #include "ardour_ui.h"
@@ -39,9 +38,9 @@
 #include "editing.h"
 #include "rgb_macros.h"
 #include "utils.h"
-#include "time_axis_view.h"
 #include "audio_time_axis.h"
 #include "editor_drag.h"
+#include "region_view.h"
 
 #include "i18n.h"
 
@@ -283,6 +282,7 @@ Editor::initialize_canvas ()
        track_canvas->signal_motion_notify_event().connect (mem_fun (*this, &Editor::track_canvas_motion_notify_event));
        track_canvas->signal_button_press_event().connect (mem_fun (*this, &Editor::track_canvas_button_press_event));
        track_canvas->signal_button_release_event().connect (mem_fun (*this, &Editor::track_canvas_button_release_event));
+       track_canvas->signal_drag_motion().connect (mem_fun (*this, &Editor::track_canvas_drag_motion));
 
        track_canvas->set_name ("EditorMainCanvas");
        track_canvas->add_events (Gdk::POINTER_MOTION_HINT_MASK|Gdk::SCROLL_MASK);
@@ -532,20 +532,10 @@ Editor::drop_regions (const RefPtr<Gdk::DragContext>& context,
                      const SelectionData& data,
                      guint info, guint time)
 {
-       std::list<boost::shared_ptr<Region> > regions;
-       Gtk::TreeView* source;
-       region_list_display.get_object_drag_data (regions, &source);
-
-       for (list<boost::shared_ptr<Region> >::iterator r = regions.begin(); r != regions.end(); ++r) {
-
-               boost::shared_ptr<AudioRegion> ar;
-
-               if ((ar = boost::dynamic_pointer_cast<AudioRegion>(*r)) != 0) {
-                       insert_region_list_drag (ar, x, y);
-               }
-       }
-
-       context->drag_finish (true, false, time);
+       assert (_drag);
+       _drag->end_grab (0);
+       delete _drag;
+       _drag = 0;
 }
 
 void
index 73c02d75d68a35eb2bb5c3ea4d88340033762686..99868367f05160995640a675c262bf8b0411880d 100644 (file)
@@ -26,6 +26,9 @@
 
 #include "ardour/audio_diskstream.h"
 #include "ardour/audioplaylist.h"
+#include "ardour/midi_region.h"
+#include "ardour/audioregion.h"
+#include "ardour/region_factory.h"
 
 #include "editor.h"
 #include "keyboard.h"
@@ -43,6 +46,7 @@
 #include "simplerect.h"
 #include "interactive-item.h"
 #include "editor_drag.h"
+#include "midi_time_axis.h"
 
 #include "i18n.h"
 
@@ -896,3 +900,63 @@ Editor::canvas_zoom_rect_event (GdkEvent *event, ArdourCanvas::Item* item)
        return typed_event (item, event, NoItem);
 }
 
+bool
+Editor::track_canvas_drag_motion (Glib::RefPtr<Gdk::DragContext> const & c, int x, int y, guint time)
+{
+       double wx;
+       double wy;
+       track_canvas->window_to_world (x, y, wx, wy);
+
+       GdkEvent event;
+       event.type = GDK_MOTION_NOTIFY;
+       event.button.x = wx;
+       event.button.y = wy;
+       /* assume we're dragging with button 1 */
+       event.motion.state = Gdk::BUTTON1_MASK;
+
+       if (_drag == 0) {
+
+               double px;
+               double py;
+               nframes64_t const pos = event_frame (&event, &px, &py);
+       
+               std::pair<TimeAxisView*, int> const tv = trackview_by_y_position (py);
+               if (tv.first == 0) {
+                       return true;
+               }
+
+               RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv.first);
+               if (rtav == 0 || !rtav->is_track ()) {
+                       return true;
+               }
+
+               list<boost::shared_ptr<Region> > regions;
+               TreeView* source;
+               region_list_display.get_object_drag_data (regions, &source);
+               assert (regions.size() == 1);
+               boost::shared_ptr<Region> region = regions.front ();
+
+               boost::shared_ptr<Region> region_copy = RegionFactory::create (region);
+
+               if (boost::dynamic_pointer_cast<AudioRegion> (region_copy) != 0 && 
+                   dynamic_cast<AudioTimeAxisView*> (tv.first) == 0) {
+
+                       /* audio -> non-audio */
+                       return true;
+               }
+
+               if (boost::dynamic_pointer_cast<MidiRegion> (region_copy) == 0 && 
+                   dynamic_cast<MidiTimeAxisView*> (tv.first) != 0) {
+
+                       /* MIDI -> non-MIDI */
+                       return true;
+               }
+               
+               _drag = new RegionInsertDrag (this, region_copy, rtav, pos);
+               _drag->start_grab (&event);
+       }
+
+       _drag->motion_handler (&event, false);
+
+       return true;
+}
index dd4c8c1b32d14bb291fab43b82d01645cd611bad..d41a91aadd8c95ed63ae1d9ae49177a1114305c5 100644 (file)
@@ -33,6 +33,8 @@
 #include "utils.h"
 #include "region_gain_line.h"
 #include "editor_drag.h"
+#include "audio_time_axis.h"
+#include "midi_time_axis.h"
 
 using namespace std;
 using namespace ARDOUR;
@@ -50,7 +52,6 @@ Drag::Drag (Editor* e, ArdourCanvas::Item* i) :
        _grab_frame (0),
        _last_pointer_frame (0),
        _current_pointer_frame (0),
-       _copy (false),
        _had_movement (false),
        _move_threshold_passed (false)
 {
@@ -138,11 +139,9 @@ Drag::end_grab (GdkEvent* event)
 
        _item->ungrab (event ? event->button.time : 0);
 
-       if (event) {
-               _last_pointer_x = _current_pointer_x;
-               _last_pointer_y = _current_pointer_y;
-               finished (event, _had_movement);
-       }
+       _last_pointer_x = _current_pointer_x;
+       _last_pointer_y = _current_pointer_y;
+       finished (event, _had_movement);
 
        _editor->hide_verbose_canvas_cursor();
 
@@ -256,147 +255,108 @@ RegionDrag::update_selection ()
        _editor->selection->set (s);
 }
 
-RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
+RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
        : RegionDrag (e, i, p, v),
+         _dest_trackview (0),
+         _dest_layer (0),
          _brushing (b)
 {
-       _copy = c;
        
-       TimeAxisView* const tv = &_primary->get_time_axis_view ();
-       
-       _dest_trackview = tv;
-       _dest_layer = _primary->region()->layer ();
-
-       double speed = 1;
-       RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
-       if (rtv && rtv->is_track()) {
-               speed = rtv->get_diskstream()->speed ();
-       }
-
-       _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
 }
 
+
 void
-RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
+RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
 {
        Drag::start_grab (event);
        
-       _pointer_frame_offset = _grab_frame - _last_frame_position;
        _editor->show_verbose_time_cursor (_last_frame_position, 10);
 }
 
-void
-RegionMoveDrag::motion (GdkEvent* event, bool first_move)
+RegionMotionDrag::TimeAxisViewSummary
+RegionMotionDrag::get_time_axis_view_summary ()
 {
-       double x_delta = 0;
-       double y_delta = 0;
-       nframes64_t pending_region_position = 0;
-       int32_t pointer_order_span = 0, canvas_pointer_order_span = 0;
-       int32_t pointer_layer_span = 0;
-       
-       bool clamp_y_axis = false;
-       vector<int32_t>::iterator j;
+       int32_t children = 0;
+       TimeAxisViewSummary sum;
 
-       if (_copy && first_move) {
-               copy_regions (event);
-       }
-       
-       /* *pointer* variables reflect things about the pointer; as we may be moving
-          multiple regions, much detail must be computed per-region */
+       _editor->visible_order_range (&sum.visible_y_low, &sum.visible_y_high);
+               
+       /* get a bitmask representing the visible tracks */
 
-       /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
-          current_pointer_layer the current layer on that TimeAxisView */
-       RouteTimeAxisView* current_pointer_view;
-       layer_t current_pointer_layer;
-       if (!check_possible (&current_pointer_view, &current_pointer_layer)) {
-               return;
+       for (Editor::TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
+               RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
+               TimeAxisView::Children children_list;
+               
+               /* zeroes are audio/MIDI tracks. ones are other types. */
+               
+               if (!rtv->hidden()) {
+                       
+                       if (!rtv->is_track()) {
+                               /* not an audio nor MIDI track */
+                               sum.tracks = sum.tracks |= (0x01 << rtv->order());
+                       }
+                       
+                       sum.height_list[rtv->order()] = (*i)->current_height();
+                       children = 1;
+
+                       if ((children_list = rtv->get_child_list()).size() > 0) {
+                               for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) { 
+                                       sum.tracks = sum.tracks |= (0x01 << (rtv->order() + children));
+                                       sum.height_list[rtv->order() + children] = (*j)->current_height();
+                                       children++;     
+                               }
+                       }
+               }
        }
 
-       /* TimeAxisView that we were pointing at last time we entered this method */
-       TimeAxisView const * const last_pointer_view = _dest_trackview;
-       /* the order of the track that we were pointing at last time we entered this method */
-       int32_t const last_pointer_order = last_pointer_view->order ();
-       /* the layer that we were pointing at last time we entered this method */
-       layer_t const last_pointer_layer = _dest_layer;
-
-       /************************************************************
-            Y DELTA COMPUTATION
-       ************************************************************/   
+       return sum;
+}
 
-       /* Height of TimeAxisViews, indexed by order */
-       /* XXX: hard-coded limit of TimeAxisViews */
-       vector<int32_t> height_list (512);
-       
+bool
+RegionMotionDrag::compute_y_delta (
+       TimeAxisView const * last_pointer_view, TimeAxisView* current_pointer_view,
+       int32_t last_pointer_layer, int32_t current_pointer_layer,
+       TimeAxisViewSummary const & tavs,
+       int32_t* pointer_order_span, int32_t* pointer_layer_span,
+       int32_t* canvas_pointer_order_span
+       )
+{
        if (_brushing) {
-               clamp_y_axis = true;
-               pointer_order_span = 0;
-               goto y_axis_done;
+               *pointer_order_span = 0;
+               *pointer_layer_span = 0;
+               return true;
        }
 
+       bool clamp_y_axis = false;
+               
        /* the change in track order between this callback and the last */
-       pointer_order_span = last_pointer_view->order() - current_pointer_view->order();
+       *pointer_order_span = last_pointer_view->order() - current_pointer_view->order();
        /* the change in layer between this callback and the last;
           only meaningful if pointer_order_span == 0 (ie we've not moved tracks) */
-       pointer_layer_span = last_pointer_layer - current_pointer_layer;
-
-       if (pointer_order_span != 0) {
-
-               int32_t children = 0;
-               /* XXX: hard-coded limit of tracks */
-               bitset <512> tracks (0x00);
-
-               int visible_y_high;
-               int visible_y_low;
-               _editor->visible_order_range (&visible_y_low, &visible_y_high);
-               
-               /* get a bitmask representing the visible tracks */
+       *pointer_layer_span = last_pointer_layer - current_pointer_layer;
 
-               for (Editor::TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
-                       RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
-                       TimeAxisView::Children children_list;
-             
-                       /* zeroes are audio/MIDI tracks. ones are other types. */
-             
-                       if (!rtv->hidden()) {
-                               
-                               if (!rtv->is_track()) {
-                                       /* not an audio nor MIDI track */
-                                       tracks = tracks |= (0x01 << rtv->order());
-                               }
-       
-                               height_list[rtv->order()] = (*i)->current_height();
-                               children = 1;
+       if (*pointer_order_span != 0) {
 
-                               if ((children_list = rtv->get_child_list()).size() > 0) {
-                                       for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) { 
-                                               tracks = tracks |= (0x01 << (rtv->order() + children));
-                                               height_list[rtv->order() + children] = (*j)->current_height();
-                                               children++;     
-                                       }
-                               }
-                       }
-               }
-               
                /* find the actual pointer span, in terms of the number of visible tracks;
                   to do this, we reduce |pointer_order_span| by the number of hidden tracks
                   over the span */
 
-               canvas_pointer_order_span = pointer_order_span;
+               *canvas_pointer_order_span = *pointer_order_span;
                if (last_pointer_view->order() >= current_pointer_view->order()) {
                        for (int32_t y = current_pointer_view->order(); y < last_pointer_view->order(); y++) {
-                               if (height_list[y] == 0) {
-                                       canvas_pointer_order_span--;
+                               if (tavs.height_list[y] == 0) {
+                                       *canvas_pointer_order_span--;
                                }
                        }
                } else {
                        for (int32_t y = last_pointer_view->order(); y <= current_pointer_view->order(); y++) {
-                               if (height_list[y] == 0) {
-                                       canvas_pointer_order_span++;
+                               if (tavs.height_list[y] == 0) {
+                                       *canvas_pointer_order_span++;
                                }
                        }
                }
 
-               for (list<RegionView*>::const_iterator i = _editor->selection->regions.by_layer().begin(); i != _editor->selection->regions.by_layer().end(); ++i) {
+               for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
                        
                        RegionView* rv = (*i);
 
@@ -414,18 +374,11 @@ RegionMoveDrag::motion (GdkEvent* event, bool first_move)
                        assert (tvp.first);
                        RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
 
-                       /* I know this method has a slightly excessive argument list, but I think
-                          it's nice to separate the code out all the same, since it has such a
-                          simple result, and it makes it clear that there are no other
-                          side-effects.
-                       */
-
                        /* XXX: not sure that we should be passing canvas_pointer_order_span in here,
                           as surely this is a per-region thing... */
                        
                        clamp_y_axis = y_movement_disallowed (
-                               rtv->order(), last_pointer_order, canvas_pointer_order_span, visible_y_low, visible_y_high,
-                               tracks, height_list
+                               rtv->order(), last_pointer_view->order(), *canvas_pointer_order_span, tavs
                                );
 
                        if (clamp_y_axis) {
@@ -441,16 +394,20 @@ RegionMoveDrag::motion (GdkEvent* event, bool first_move)
                } 
        }
 
-  y_axis_done:
        if (!clamp_y_axis) {
                _dest_trackview = current_pointer_view;
                _dest_layer = current_pointer_layer;
        }
-         
-       /************************************************************
-           X DELTA COMPUTATION
-       ************************************************************/
 
+       return clamp_y_axis;
+}
+
+
+double
+RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_region_position)
+{
+       *pending_region_position = 0;
+       
        /* compute the amount of pointer motion in frames, and where
           the region would be if we moved it by that much.
        */
@@ -460,14 +417,15 @@ RegionMoveDrag::motion (GdkEvent* event, bool first_move)
                nframes64_t sync_offset;
                int32_t sync_dir;
                
-               pending_region_position = _current_pointer_frame - _pointer_frame_offset;
+               *pending_region_position = _current_pointer_frame - _pointer_frame_offset;
                
                sync_offset = _primary->region()->sync_offset (sync_dir);
                
                /* 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);
+               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.
                         */
@@ -476,43 +434,30 @@ RegionMoveDrag::motion (GdkEvent* event, bool first_move)
                                _editor->snap_to (sync_frame);  
                        }
                        
-                       pending_region_position = _primary->region()->adjust_to_sync (sync_frame);
+                       *pending_region_position = _primary->region()->adjust_to_sync (sync_frame);
                        
                } else {
-                       pending_region_position = _last_frame_position;
+                       *pending_region_position = _last_frame_position;
                }
                
-       } else {
-               pending_region_position = 0;
-       }
-       
-       if (pending_region_position > max_frames - _primary->region()->length()) {
-               pending_region_position = _last_frame_position;
        }
        
-       bool x_move_allowed;
-               
-       if (Config->get_edit_mode() == Lock) {
-               if (_copy) {
-                       x_move_allowed = !_x_constrained;
-               } else {
-                       /* in locked edit mode, reverse the usual meaning of _x_constrained */
-                       x_move_allowed = _x_constrained;
-               }
-       } else {
-               x_move_allowed = !_x_constrained;
+       if (*pending_region_position > max_frames - _primary->region()->length()) {
+               *pending_region_position = _last_frame_position;
        }
+
+       double x_delta = 0;
        
-       if (( pending_region_position != _last_frame_position) && x_move_allowed ) {
+       if ((*pending_region_position != _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.
                */
+
+               x_delta = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit;
                
-               if (pending_region_position > _last_frame_position) {
-                       x_delta = ((double) (pending_region_position - _last_frame_position) / _editor->frames_per_unit);
-               } else {
-                       x_delta = -((double) (_last_frame_position - pending_region_position) / _editor->frames_per_unit);
+               if (*pending_region_position <= _last_frame_position) {
+                       
                        for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
                                
                                RegionView* rv = (*i);
@@ -525,20 +470,60 @@ RegionMoveDrag::motion (GdkEvent* event, bool first_move)
                                
                                if (-x_delta > ix1 + _editor->horizontal_adjustment.get_value()) {
                                        x_delta = 0;
-                                       pending_region_position = _last_frame_position;
+                                       *pending_region_position = _last_frame_position;
                                        break;
                                }
                        }
                        
                }
                
-               _last_frame_position = pending_region_position;
-               
-       } else {
-               x_delta = 0;
+               _last_frame_position = *pending_region_position;
        }
 
+       return x_delta;
+}
+
+void
+RegionMotionDrag::motion (GdkEvent* event, bool first_move)
+{
+       double y_delta = 0;
+
+       TimeAxisViewSummary tavs = get_time_axis_view_summary ();
+
+       vector<int32_t>::iterator j;
+
+       /* *pointer* variables reflect things about the pointer; as we may be moving
+          multiple regions, much detail must be computed per-region */
+
+       /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
+          current_pointer_layer the current layer on that TimeAxisView */
+       RouteTimeAxisView* current_pointer_view;
+       layer_t current_pointer_layer;
+       if (!check_possible (&current_pointer_view, &current_pointer_layer)) {
+               return;
+       }
+
+       /* TimeAxisView that we were pointing at last time we entered this method */
+       TimeAxisView const * const last_pointer_view = _dest_trackview;
+       /* the order of the track that we were pointing at last time we entered this method */
+       int32_t const last_pointer_order = last_pointer_view->order ();
+       /* the layer that we were pointing at last time we entered this method */
+       layer_t const last_pointer_layer = _dest_layer;
+
+       int32_t pointer_order_span;
+       int32_t pointer_layer_span;
+       int32_t canvas_pointer_order_span;
        
+       bool const clamp_y_axis = compute_y_delta (
+               last_pointer_view, current_pointer_view,
+               last_pointer_layer, current_pointer_layer, tavs,
+               &pointer_order_span, &pointer_layer_span,
+               &canvas_pointer_order_span
+               );
+
+       nframes64_t pending_region_position;
+       double const x_delta = compute_x_delta (event, &pending_region_position);
+
        /*************************************************************
            PREPARE TO MOVE
        ************************************************************/
@@ -614,9 +599,9 @@ RegionMoveDrag::motion (GdkEvent* event, bool first_move)
                        /* INTER-TRACK MOVEMENT */
                        
                        /* move through the height list to the track that the region is currently on */
-                       vector<int32_t>::iterator j = height_list.begin ();
+                       vector<int32_t>::iterator j = tavs.height_list.begin ();
                        int32_t x = 0;
-                       while (j != height_list.end () && x != rtv->order ()) {
+                       while (j != tavs.height_list.end () && x != rtv->order ()) {
                                ++x;
                                ++j;
                        }
@@ -624,7 +609,7 @@ RegionMoveDrag::motion (GdkEvent* event, bool first_move)
                        y_delta = 0;
                        int32_t temp_pointer_order_span = canvas_pointer_order_span;
                        
-                       if (j != height_list.end ()) {
+                       if (j != tavs.height_list.end ()) {
                                
                                /* Account for layers in the original and
                                   destination tracks.  If we're moving around in layers we assume
@@ -654,7 +639,7 @@ RegionMoveDrag::motion (GdkEvent* event, bool first_move)
                                        /* we're moving up canvas-wise,
                                           so we need to find the next track height
                                        */
-                                       if (j != height_list.begin()) {           
+                                       if (j != tavs.height_list.begin()) {              
                                                j--;
                                        }
                                        
@@ -678,7 +663,7 @@ RegionMoveDrag::motion (GdkEvent* event, bool first_move)
                                                }
                                        }
                                        
-                                       if (j != height_list.end()) {                 
+                                       if (j != tavs.height_list.end()) {                    
                                                j++;
                                        }
                                        
@@ -724,7 +709,17 @@ RegionMoveDrag::motion (GdkEvent* event, bool first_move)
        if (x_delta != 0 && !_brushing) {
                _editor->show_verbose_time_cursor (_last_frame_position, 10);
        }
-} 
+}
+
+void
+RegionMoveDrag::motion (GdkEvent* event, bool first_move)
+{
+       if (_copy && first_move) {
+               copy_regions (event);
+       }
+
+       RegionMotionDrag::motion (event, first_move);
+}
 
 void
 RegionMoveDrag::finished (GdkEvent* event, bool movement_occurred)
@@ -769,8 +764,6 @@ RegionMoveDrag::finished (GdkEvent* event, bool movement_occurred)
                goto out;
        }
 
-       char* op_string;
-
        /* reverse this here so that we have the correct logic to finalize
           the drag.
        */
@@ -781,19 +774,18 @@ RegionMoveDrag::finished (GdkEvent* event, bool movement_occurred)
 
        if (_copy) {
                if (_x_constrained) {
-                       op_string = _("fixed time region copy");
+                       _editor->begin_reversible_command (_("fixed time region copy"));
                } else {
-                       op_string = _("region copy");
+                       _editor->begin_reversible_command (_("region copy"));
                } 
        } else {
                if (_x_constrained) {
-                       op_string = _("fixed time region drag");
+                       _editor->begin_reversible_command (_("fixed time region drag"));
                } else {
-                       op_string = _("region drag");
+                       _editor->begin_reversible_command (_("region drag"));
                }
        }
 
-       _editor->begin_reversible_command (op_string);
        changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
        tvp = _editor->trackview_by_y_position (_current_pointer_y);
        changed_tracks = (tvp.first != &_primary->get_time_axis_view());
@@ -803,16 +795,7 @@ RegionMoveDrag::finished (GdkEvent* event, bool movement_occurred)
        _editor->track_canvas->update_now ();
 
        /* make a list of where each region ended up */
-       for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
-
-               double ix1, ix2, iy1, iy2;
-               (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
-               (*i)->get_canvas_frame()->i2w (ix1, iy1);
-               iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
-
-               pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
-               final[*i] = dynamic_cast<RouteTimeAxisView*> (tv.first);
-       }
+       final = find_time_axis_views ();
 
        for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ) {
 
@@ -999,10 +982,35 @@ RegionMoveDrag::finished (GdkEvent* event, bool movement_occurred)
                delete *x;
        }
 }
+
+
+bool
+RegionMoveDrag::x_move_allowed () const
+{
+       if (Config->get_edit_mode() == Lock) {
+               if (_copy) {
+                       return !_x_constrained;
+               } else {
+                       /* in locked edit mode, reverse the usual meaning of _x_constrained */
+                       return _x_constrained;
+               }
+       }
        
+       return !_x_constrained;
+}
+
+bool
+RegionInsertDrag::x_move_allowed () const
+{
+       if (Config->get_edit_mode() == Lock) {
+               return _x_constrained;
+       }
+
+       return !_x_constrained;
+}
 
 void
-RegionMoveDrag::copy_regions (GdkEvent* event)
+RegionMotionDrag::copy_regions (GdkEvent* event)
 {
        /* duplicate the regionview(s) and region(s) */
 
@@ -1043,7 +1051,8 @@ RegionMoveDrag::copy_regions (GdkEvent* event)
        _primary = new_regionviews.front();
        _views = new_regionviews;
                
-       swap_grab (new_regionviews.front()->get_canvas_group (), 0, event->motion.time);
+       swap_grab (new_regionviews.front()->get_canvas_group (), 0, event ? event->motion.time : 0);
+       
        /* 
           sync the canvas to what we think is its current state 
           without it, the canvas seems to 
@@ -1055,7 +1064,7 @@ RegionMoveDrag::copy_regions (GdkEvent* event)
 }
 
 bool
-RegionMoveDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
+RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
 {
        /* Which trackview is this ? */
 
@@ -1081,16 +1090,10 @@ RegionMoveDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
 /** @param new_order New track order.
  *  @param old_order Old track order.
  *  @param visible_y_low Lowest visible order.
- *  @param visible_y_high Highest visible order.
- *  @param tracks Bitset of tracks indexed by order; 0 means a audio/MIDI track, 1 means something else.
- *  @param heigh_list Heights of tracks indexed by order.
  *  @return true if y movement should not happen, otherwise false.
  */
 bool
-RegionMoveDrag::y_movement_disallowed (
-       int new_order, int old_order, int y_span, int visible_y_low, int visible_y_high,
-       bitset<512> const & tracks, vector<int32_t> const & height_list
-       ) const
+RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
 {
        if (new_order != old_order) {
 
@@ -1099,7 +1102,7 @@ RegionMoveDrag::y_movement_disallowed (
                if (y_span > 0) {
 
                        /* moving up the canvas */
-                       if ( (new_order - y_span) >= visible_y_low) {
+                       if ( (new_order - y_span) >= tavs.visible_y_low) {
 
                                int32_t n = 0;
 
@@ -1107,13 +1110,13 @@ RegionMoveDrag::y_movement_disallowed (
                                int32_t visible_tracks = 0;
                                while (visible_tracks < y_span ) {
                                        visible_tracks++;
-                                       while (height_list[new_order - (visible_tracks - n)] == 0) {
+                                       while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
                                                /* passing through a hidden track */
                                                n--;
                                        }                 
                                }
                 
-                               if (tracks[new_order - (y_span - n)] != 0x00) {
+                               if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
                                        /* moving to a non-track; disallow */
                                        return true;
                                }
@@ -1127,20 +1130,20 @@ RegionMoveDrag::y_movement_disallowed (
                } else if (y_span < 0) {
 
                        /* moving down the canvas */
-                       if ((new_order - y_span) <= visible_y_high) {
+                       if ((new_order - y_span) <= tavs.visible_y_high) {
 
                                int32_t visible_tracks = 0;
                                int32_t n = 0;
                                while (visible_tracks > y_span ) {
                                        visible_tracks--;
                      
-                                       while (height_list[new_order - (visible_tracks - n)] == 0) {
+                                       while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
                                                /* passing through a hidden track */
                                                n++;
                                        }                
                                }
                                                
-                               if (tracks[new_order - (y_span - n)] != 0x00) {
+                               if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
                                        /* moving to a non-track; disallow */
                                        return true;
                                }
@@ -1157,10 +1160,10 @@ RegionMoveDrag::y_movement_disallowed (
                
                /* this is the pointer's track */
                
-               if ((new_order - y_span) > visible_y_high) {
+               if ((new_order - y_span) > tavs.visible_y_high) {
                        /* we will overflow */
                        return true;
-               } else if ((new_order - y_span) < visible_y_low) {
+               } else if ((new_order - y_span) < tavs.visible_y_low) {
                        /* we will overflow */
                        return true;
                }
@@ -1169,6 +1172,97 @@ RegionMoveDrag::y_movement_disallowed (
        return false;
 }
 
+
+RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
+       : RegionMotionDrag (e, i, p, v, b),
+         _copy (c)
+{
+       TimeAxisView* const tv = &_primary->get_time_axis_view ();
+       
+       _dest_trackview = tv;
+       _dest_layer = _primary->region()->layer ();
+
+       double speed = 1;
+       RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
+       if (rtv && rtv->is_track()) {
+               speed = rtv->get_diskstream()->speed ();
+       }
+
+       _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
+}
+
+void
+RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
+{
+       RegionMotionDrag::start_grab (event, c);
+       
+       _pointer_frame_offset = _grab_frame - _last_frame_position;
+}
+
+RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, nframes64_t pos)
+       : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
+{
+       assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
+               (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
+
+       _primary = v->view()->create_region_view (r, false, false);
+       
+       _primary->get_canvas_group()->show ();
+       _primary->set_position (pos, 0);
+       _views.push_back (_primary);
+
+       _last_frame_position = pos;
+
+       _item = _primary->get_canvas_group ();
+       _dest_trackview = v;
+       _dest_layer = _primary->region()->layer ();
+}
+
+map<RegionView*, RouteTimeAxisView*>
+RegionMotionDrag::find_time_axis_views ()
+{
+       map<RegionView*, RouteTimeAxisView*> tav;
+       
+       for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
+
+               double ix1, ix2, iy1, iy2;
+               (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
+               (*i)->get_canvas_frame()->i2w (ix1, iy1);
+               iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
+
+               pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
+               tav[*i] = dynamic_cast<RouteTimeAxisView*> (tv.first);
+       }
+
+       return tav;
+}
+
+
+void
+RegionInsertDrag::finished (GdkEvent* event, bool movement_occurred)
+{
+       _editor->track_canvas->update_now ();
+
+       map<RegionView*, RouteTimeAxisView*> final = find_time_axis_views ();
+       
+       RouteTimeAxisView* dest_rtv = final[_primary];
+
+       _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
+       _primary->get_canvas_group()->property_y() = 0;
+
+       boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
+
+       _editor->begin_reversible_command (_("insert region"));
+       XMLNode& before = playlist->get_state ();
+       playlist->add_region (_primary->region (), _last_frame_position);
+       _editor->session->add_command (new MementoCommand<Playlist> (*playlist, &before, &playlist->get_state()));
+       _editor->commit_reversible_command ();
+
+       delete _primary;
+       _primary = 0;
+       _views.clear ();
+}
+
 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
        : RegionMoveDrag (e, i, p, v, false, false)
 {
@@ -1550,10 +1644,9 @@ TrimDrag::finished (GdkEvent* event, bool movement_occurred)
 }
 
 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
-       : Drag (e, i)
+       : Drag (e, i),
+         _copy (c)
 {
-       _copy = c;
-
        _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
        assert (_marker);
 }
@@ -1645,10 +1738,9 @@ MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
 }
 
 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
-       : Drag (e, i)
+       : Drag (e, i),
+         _copy (c)
 {
-       _copy = c;
-
        TempoMarker* _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
        assert (_marker);
 }
@@ -2731,7 +2823,8 @@ TimeFXDrag::finished (GdkEvent* event, bool movement_occurred)
 
 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
        : Drag (e, i),
-         _operation (o)
+         _operation (o),
+         _copy (false)
 {
 
 }
@@ -2944,7 +3037,8 @@ SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
 
 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
        : Drag (e, i),
-         _operation (o)
+         _operation (o),
+         _copy (false)
 {
        _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
        _drag_rect->hide ();
index 79e01154719f52519d1ad609c267ed6d1831c96a..370cc566436aef6ebd888114c8acf61f3f920079 100644 (file)
@@ -134,7 +134,6 @@ protected:
        double _last_pointer_y; ///< item y of the pointer last time a motion occurred
        bool _x_constrained; ///< true if x motion is constrained, otherwise false
        bool _y_constrained; ///< true if y motion is constrained, otherwise false
-       bool _copy; ///< true if we're copying the things that we're dragging
        bool _was_rolling; ///< true if the session was rolling before the drag started, otherwise false
 
 private:
@@ -164,33 +163,80 @@ private:
 };
 
 
-/** Drags to move regions */
-class RegionMoveDrag : public RegionDrag
+/** Drags involving region motion from somewhere */
+class RegionMotionDrag : public RegionDrag
+{
+public:
+       
+       RegionMotionDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &, bool);
+       virtual ~RegionMotionDrag () {}
+
+       virtual void start_grab (GdkEvent *, Gdk::Cursor *);
+       virtual void motion (GdkEvent *, bool);
+       virtual void finished (GdkEvent *, bool) = 0;
+
+protected:
+       struct TimeAxisViewSummary {
+               TimeAxisViewSummary () : height_list(512) {}
+               
+               std::bitset<512> tracks;
+               std::vector<int32_t> height_list;
+               int visible_y_low;
+               int visible_y_high;
+       };
+       
+       void copy_regions (GdkEvent *);
+       bool y_movement_disallowed (int, int, int, TimeAxisViewSummary const &) const;
+       std::map<RegionView*, RouteTimeAxisView*> find_time_axis_views ();
+       double compute_x_delta (GdkEvent const *, nframes64_t *);
+       bool compute_y_delta (
+               TimeAxisView const *, TimeAxisView*, int32_t, int32_t, TimeAxisViewSummary const &,
+               int32_t *, int32_t *, int32_t *
+               );
+
+       TimeAxisViewSummary get_time_axis_view_summary ();
+       virtual bool x_move_allowed () const = 0;
+       
+       TimeAxisView* _dest_trackview;
+       ARDOUR::layer_t _dest_layer;
+       bool check_possible (RouteTimeAxisView **, ARDOUR::layer_t *);
+       bool _brushing;
+};
+
+
+/** Drags to move (or copy) regions that are already shown in the GUI to
+ *  somewhere different.
+ */
+class RegionMoveDrag : public RegionMotionDrag
 {
 public:
        RegionMoveDrag (Editor *, ArdourCanvas::Item *, RegionView *, std::list<RegionView*> const &, bool, bool);
        virtual ~RegionMoveDrag () {}
 
        virtual void start_grab (GdkEvent *, Gdk::Cursor *);
-       virtual void motion (GdkEvent *, bool);
-       virtual void finished (GdkEvent *, bool);
+       void motion (GdkEvent *, bool);
+       void finished (GdkEvent *, bool);
+       
        bool apply_move_threshold () const {
                return true;
        }
 
-protected:
+private:
+       bool x_move_allowed () const;
 
-       bool check_possible (RouteTimeAxisView **, ARDOUR::layer_t *);
+       bool _copy;
+};
 
-       TimeAxisView* _dest_trackview;
-       ARDOUR::layer_t _dest_layer;
+/** Drag to insert a region from somewhere */
+class RegionInsertDrag : public RegionMotionDrag
+{
+public:
+       RegionInsertDrag (Editor *, boost::shared_ptr<ARDOUR::Region>, RouteTimeAxisView*, nframes64_t);
 
+       void finished (GdkEvent *, bool);
+       
 private:
-
-       void copy_regions (GdkEvent *);
-       bool y_movement_disallowed (int, int, int, int, int, std::bitset<512> const &, std::vector<int32_t> const &) const;
-
-       bool _brushing;
+       bool x_move_allowed () const;
 };
 
 /** Region drag in splice mode */
@@ -264,6 +310,7 @@ public:
 
 private:
        MeterMarker* _marker;
+       bool _copy;
 };
 
 /** Tempo marker drag */
@@ -278,6 +325,7 @@ public:
 
 private:
        TempoMarker* _marker;
+       bool _copy;
 };
 
 
@@ -416,6 +464,7 @@ public:
 
 private:
        Operation _operation;
+       bool _copy;
 };
 
 /** Range marker drag */
@@ -439,6 +488,7 @@ private:
 
        Operation _operation;
        ArdourCanvas::SimpleRect* _drag_rect;
+       bool _copy;
 };
 
 /* Drag of rectangle to set zoom */
index 32f01872fe7209263dfd5d5d0b2b72b4231411c3..c67ca5942d88a35c6d66edeaf79ad6c4c510952e 100644 (file)
@@ -112,7 +112,7 @@ Editor::mouse_frame (nframes64_t& where, bool& in_track_canvas) const
 }
 
 nframes64_t
-Editor::event_frame (GdkEvent* event, double* pcx, double* pcy) const
+Editor::event_frame (GdkEvent const * event, double* pcx, double* pcy) const
 {
        double cx, cy;
 
index 4e0b58da95d765d3cedf778c9f50c550adacce3d..4ec2698e67393972924333706867c80f363d4d6a 100644 (file)
@@ -66,7 +66,7 @@ using namespace Editing;
 using namespace ArdourCanvas;
 
 MidiRegionView::MidiRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv,
-               boost::shared_ptr<MidiRegion> r, double spu, Gdk::Color& basic_color)
+               boost::shared_ptr<MidiRegion> r, double spu, Gdk::Color const & basic_color)
        : RegionView (parent, tv, r, spu, basic_color)
        , _force_channel(-1)
        , _last_channel_selection(0xFFFF)
@@ -150,7 +150,7 @@ MidiRegionView::MidiRegionView (const MidiRegionView& other, boost::shared_ptr<M
 }
 
 void
-MidiRegionView::init (Gdk::Color& basic_color, bool wfd)
+MidiRegionView::init (Gdk::Color const & basic_color, bool wfd)
 {
        if (wfd) {
                midi_region()->midi_source(0)->load_model();
index b26edb5a47c81c459837e6b92eda70810331e6a9..3df4001ab41683b6ce723efa4f5f468bc45f8ab2 100644 (file)
@@ -66,14 +66,14 @@ class MidiRegionView : public RegionView
                        RouteTimeAxisView&,
                        boost::shared_ptr<ARDOUR::MidiRegion>,
                        double initial_samples_per_unit,
-                       Gdk::Color& basic_color);
+                       Gdk::Color const & basic_color);
        
        MidiRegionView (const MidiRegionView& other);
        MidiRegionView (const MidiRegionView& other, boost::shared_ptr<ARDOUR::MidiRegion>);
 
        ~MidiRegionView ();
 
-       virtual void init (Gdk::Color& basic_color, bool wfd);
+       virtual void init (Gdk::Color const & basic_color, bool wfd);
 
        inline const boost::shared_ptr<ARDOUR::MidiRegion> midi_region() const
                { return boost::dynamic_pointer_cast<ARDOUR::MidiRegion>(_region); }
index b7fa88404e6b3b1a07fb7e4815ae6f7c45340b76..ebc6b0d64254b31be804c12e58c8135acef6f9b1 100644 (file)
@@ -130,18 +130,32 @@ veto_note_range(uint8_t& min, uint8_t& max)
 }
 
 RegionView*
-MidiStreamView::add_region_view_internal (boost::shared_ptr<Region> r, bool wfd, bool recording)
+MidiStreamView::create_region_view (boost::shared_ptr<Region> r, bool wfd, bool)
 {
        boost::shared_ptr<MidiRegion> region = boost::dynamic_pointer_cast<MidiRegion> (r);
 
        if (region == 0) {
-               return NULL;
+               return 0;
        }
 
-       MidiRegionView *region_view;
-       list<RegionView *>::iterator i;
+       RegionView* region_view = new MidiRegionView (canvas_group, _trackview, region, 
+                                                     _samples_per_unit, region_color);
+               
+       region_view->init (region_color, false);
+                       
+       return region_view;
+}
 
-       for (i = region_views.begin(); i != region_views.end(); ++i) {
+RegionView*
+MidiStreamView::add_region_view_internal (boost::shared_ptr<Region> r, bool wfd, bool recording)
+{
+       boost::shared_ptr<MidiRegion> region = boost::dynamic_pointer_cast<MidiRegion> (r);
+
+       if (region == 0) {
+               return 0;
+       }
+
+       for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
                if ((*i)->region() == r) {
                        
                        /* great. we already have a MidiRegionView for this Region. use it again. */
@@ -150,18 +164,19 @@ MidiStreamView::add_region_view_internal (boost::shared_ptr<Region> r, bool wfd,
                        
                        display_region(dynamic_cast<MidiRegionView*>(*i), wfd);
 
-                       return NULL;
+                       return 0;
                }
        }
+
+       MidiRegionView* region_view = dynamic_cast<MidiRegionView*> (create_region_view (r, wfd, recording));
+       if (region_view == 0) {
+               return 0;
+       }
        
-       region_view = new MidiRegionView (canvas_group, _trackview, region, 
-                       _samples_per_unit, region_color);
-               
-       region_view->init (region_color, false);
        region_views.push_front (region_view);
                        
        /* display events and find note range */
-       display_region(region_view, wfd);
+       display_region (region_view, wfd);
 
        /* catch regionview going away */
        region->GoingAway.connect (bind (mem_fun (*this, &MidiStreamView::remove_region_view), region));
@@ -266,7 +281,7 @@ MidiStreamView::redisplay_diskstream ()
 
        // Add and display region views, and flag them as valid
        _trackview.get_diskstream()->playlist()->foreach_region(
-               sigc::mem_fun (*this, &StreamView::add_region_view)
+               sigc::hide_return (sigc::mem_fun (*this, &StreamView::add_region_view))
                );
 
        // Stack regions by layer, and remove invalid regions
index a844d8d5056442f0cd64c7136eae1971e8bae25b..2b7a7b02fa827eee6f092a050604c2ad6eff418b 100644 (file)
@@ -98,6 +98,8 @@ class MidiStreamView : public StreamView
        
        sigc::signal<void> NoteRangeChanged;
 
+       RegionView* create_region_view (boost::shared_ptr<ARDOUR::Region>, bool, bool);
+
   private:
        void setup_rec_box ();
 
index 3d59c0a0d54c811bde3af65c1f384264a1e0396f..85d59a93b1f41b294cebff2db41f789e3b10642c 100644 (file)
@@ -64,10 +64,10 @@ RegionView::RegionView (ArdourCanvas::Group*              parent,
                         TimeAxisView&                     tv,
                         boost::shared_ptr<ARDOUR::Region> r,
                         double                            spu,
-                        Gdk::Color&                       basic_color)
+                        Gdk::Color const &                basic_color)
        : TimeAxisViewItem (r->name(), *parent, tv, spu, basic_color, r->position(), r->length(), false,
-                       TimeAxisViewItem::Visibility (TimeAxisViewItem::ShowNameText|
-                               TimeAxisViewItem::ShowNameHighlight| TimeAxisViewItem::ShowFrame))
+                           TimeAxisViewItem::Visibility (TimeAxisViewItem::ShowNameText|
+                                                         TimeAxisViewItem::ShowNameHighlight| TimeAxisViewItem::ShowFrame))
        , _region (r)
        , sync_mark(0)
        , sync_line(0)
@@ -118,7 +118,7 @@ RegionView::RegionView (ArdourCanvas::Group*         parent,
                         TimeAxisView&                tv,
                         boost::shared_ptr<ARDOUR::Region> r,
                         double                       spu,
-                        Gdk::Color&                  basic_color,
+                        Gdk::Color const &           basic_color,
                                                bool recording,
                         TimeAxisViewItem::Visibility visibility)
        : TimeAxisViewItem (r->name(), *parent, tv, spu, basic_color, r->position(), r->length(), recording, visibility)
@@ -137,7 +137,7 @@ RegionView::RegionView (ArdourCanvas::Group*         parent,
 }
 
 void
-RegionView::init (Gdk::Color& basic_color, bool wfd)
+RegionView::init (Gdk::Color const & basic_color, bool wfd)
 {
        editor        = 0;
        valid         = true;
@@ -350,12 +350,6 @@ RegionView::set_duration (nframes_t frames, void *src)
        return true;
 }
 
-void
-RegionView::compute_colors (Gdk::Color& basic_color)
-{
-       TimeAxisViewItem::compute_colors (basic_color);
-}
-
 void
 RegionView::set_colors ()
 {
index 25c4eb871408f91ee518c68849af57915d16bb26..98329ee77bd74e03e72e2d3772d28651d9a71003 100644 (file)
@@ -45,14 +45,14 @@ class RegionView : public TimeAxisViewItem
                    TimeAxisView&        time_view,
                    boost::shared_ptr<ARDOUR::Region> region,
                    double               samples_per_unit,
-                   Gdk::Color&          basic_color);
+                   Gdk::Color const &   basic_color);
 
        RegionView (const RegionView& other);
        RegionView (const RegionView& other, boost::shared_ptr<ARDOUR::Region> other_region);
 
        ~RegionView ();
        
-       virtual void init (Gdk::Color& base_color, bool wait_for_data);
+       virtual void init (Gdk::Color const & base_color, bool wait_for_data);
     
        boost::shared_ptr<ARDOUR::Region> region() const { return _region; }
        
@@ -99,8 +99,8 @@ class RegionView : public TimeAxisViewItem
     RegionView (ArdourCanvas::Group *, 
                TimeAxisView&,
                boost::shared_ptr<ARDOUR::Region>,
-               double      samples_per_unit,
-               Gdk::Color& basic_color,
+               double samples_per_unit,
+               Gdk::Color const & basic_color,
                bool recording,
                TimeAxisViewItem::Visibility);
     
@@ -117,7 +117,6 @@ class RegionView : public TimeAxisViewItem
     void        lock_toggle ();
 
     virtual void set_colors ();
-    virtual void compute_colors (Gdk::Color&);
     virtual void set_frame_color ();
     virtual void reset_width_dependent_items (double pixel_width);
 
index 2127d1354c0848e83ba017a8975804eafa45c981..4e55720ac60897a7c742b1a79a4240db9563dde3 100644 (file)
@@ -178,12 +178,14 @@ StreamView::add_region_view_weak (boost::weak_ptr<Region> r)
        }
 }
 
+
 void
 StreamView::add_region_view (boost::shared_ptr<Region> r)
 {
        ENSURE_GUI_THREAD (bind (mem_fun (*this, &StreamView::add_region_view), r));
-
+       
        add_region_view_internal (r, true);
+       
        if (_layer_display == Stacked) {
                update_contents_height ();
        }
index bb6047df230e333f1274bcf8d7e68398a38afb86..557f605f59c6ff3e8a78d4d37a76a56c5fa5ee7f 100644 (file)
@@ -103,6 +103,10 @@ public:
        virtual void redisplay_diskstream () = 0;
        double child_height () const;
        ARDOUR::layer_t layers () const { return _layers; }
+
+       virtual RegionView* create_region_view (boost::shared_ptr<ARDOUR::Region>, bool, bool) {
+               return 0;
+       }
        
        sigc::signal<void,RegionView*> RegionViewAdded;
 
index c28d6c2f7f9963fa46bd27147326eacbe91795f8..a10541ffc6a1955bf8e441a28fee4f252d114b2b 100644 (file)
@@ -52,7 +52,7 @@ const TimeAxisViewItem::Visibility TapeAudioRegionView::default_tape_visibility
 TapeAudioRegionView::TapeAudioRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView &tv, 
                                          boost::shared_ptr<AudioRegion> r, 
                                          double spu, 
-                                         Gdk::Color& basic_color)
+                                         Gdk::Color const & basic_color)
 
        : AudioRegionView (parent, tv, r, spu, basic_color, false,
                           TimeAxisViewItem::Visibility ((r->position() != 0) ? default_tape_visibility : 
@@ -61,7 +61,7 @@ TapeAudioRegionView::TapeAudioRegionView (ArdourCanvas::Group *parent, RouteTime
 }
 
 void
-TapeAudioRegionView::init (Gdk::Color& basic_color, bool wfw)
+TapeAudioRegionView::init (Gdk::Color const & basic_color, bool wfw)
 {
        /* never wait for data: always just create the waves, connect once and then
           we'll update whenever we need to.
index 048c9bcc5bbc59fd7b54fce08c697bedf9d51e27..888728139393812c262520b53fb1b1322892607a 100644 (file)
@@ -31,11 +31,11 @@ class TapeAudioRegionView : public AudioRegionView
                             RouteTimeAxisView&,
                             boost::shared_ptr<ARDOUR::AudioRegion>,
                             double initial_samples_per_unit,
-                            Gdk::Color& base_color);
+                            Gdk::Color const & base_color);
        ~TapeAudioRegionView ();
 
   protected:
-       void init (Gdk::Color& base_color, bool wait_for_waves);
+       void init (Gdk::Color const & base_color, bool wait_for_waves);
 
        void set_frame_color ();
        void update (uint32_t n);
index 47790c717254805c9f55138f4388e2711d77ba64..ed311043765303000f4e0a164c67b2efcb6dfea8 100644 (file)
@@ -68,7 +68,7 @@ double TimeAxisViewItem::NAME_HIGHLIGHT_THRESH;
  * @param start the start point of this item
  * @param duration the duration of this item
  */
-TimeAxisViewItem::TimeAxisViewItem(const string & it_name, ArdourCanvas::Group& parent, TimeAxisView& tv, double spu, Gdk::Color& base_color, 
+TimeAxisViewItem::TimeAxisViewItem(const string & it_name, ArdourCanvas::Group& parent, TimeAxisView& tv, double spu, Gdk::Color const & base_color, 
                                   nframes_t start, nframes_t duration, bool recording,
                                   Visibility vis)
        : trackview (tv), _recregion(recording)
@@ -124,7 +124,7 @@ TimeAxisViewItem::TimeAxisViewItem (const TimeAxisViewItem& other)
 }
 
 void
-TimeAxisViewItem::init (const string& it_name, double spu, Gdk::Color& base_color, nframes_t start, nframes_t duration, Visibility vis)
+TimeAxisViewItem::init (const string& it_name, double spu, Gdk::Color const & base_color, nframes_t start, nframes_t duration, Visibility vis)
 {
        item_name = it_name ;
        samples_per_unit = spu ;
@@ -614,7 +614,7 @@ TimeAxisViewItem::set_height (double height)
  * 
  */
 void
-TimeAxisViewItem::set_color(Gdk::Color& base_color)
+TimeAxisViewItem::set_color (Gdk::Color const & base_color)
 {
        compute_colors (base_color);
        set_colors ();
@@ -662,7 +662,7 @@ TimeAxisViewItem::get_name_pixbuf()
  * @param color the base color of the item
  */
 void
-TimeAxisViewItem::compute_colors(Gdk::Color& base_color)
+TimeAxisViewItem::compute_colors (Gdk::Color const & base_color)
 {
        unsigned char radius ;
        char minor_shift ;
index 7cd1699caa7a4283a29803ca768310a5c19fee61..97e7a73745eb5b1dff8a0229b8f04a4223dcc27a 100644 (file)
@@ -213,7 +213,7 @@ class TimeAxisViewItem : public Selectable
     /**
      * 
      */
-    void set_color(Gdk::Color& color) ;
+    void set_color (Gdk::Color const &);
     
     /**
      * 
@@ -341,19 +341,19 @@ class TimeAxisViewItem : public Selectable
      * @param start the start point of this item
      * @param duration the duration of this item
      */
-    TimeAxisViewItem(const std::string & it_name, ArdourCanvas::Group& parent, TimeAxisView& tv, double spu, Gdk::Color& base_color, 
+    TimeAxisViewItem(const std::string & it_name, ArdourCanvas::Group& parent, TimeAxisView& tv, double spu, Gdk::Color const & base_color, 
                     nframes_t start, nframes_t duration, bool recording = false, Visibility v = Visibility (0));
 
     TimeAxisViewItem (const TimeAxisViewItem& other);
 
-    void init (const std::string& it_name, double spu, Gdk::Color& base_color, nframes_t start, nframes_t duration, Visibility vis);
+    void init (const std::string& it_name, double spu, Gdk::Color const & base_color, nframes_t start, nframes_t duration, Visibility vis);
     
     /**
      * Calculates some contrasting color for displaying various parts of this item, based upon the base color
      *
      * @param color the base color of the item
      */
-    virtual void compute_colors(Gdk::Color& color) ;
+    virtual void compute_colors (Gdk::Color const & color);
     
     /**
      * convenience method to set the various canvas item colors
index cc9d1c14635737e8073a244d3b9e9a16650284d7..5464920a59b89d6bea716d1f617d00af7cd492d7 100644 (file)
@@ -45,6 +45,11 @@ class DnDTreeViewBase : public Gtk::TreeView
 
        void add_drop_targets (std::list<Gtk::TargetEntry>&);
        void add_object_drag (int column, std::string type_name);
+
+       void on_drag_begin (Glib::RefPtr<Gdk::DragContext> const & context) {
+               Gtk::TreeView::on_drag_begin (context);
+               start_object_drag ();
+       }
        
        void on_drag_leave(const Glib::RefPtr<Gdk::DragContext>& context, guint time) {
                suggested_action = context->get_suggested_action();
@@ -95,8 +100,6 @@ class DnDTreeView : public DnDTreeViewBase
 
                } else if (selection_data.get_target() == object_type) {
 
-                       start_object_drag ();
-
                        /* we don't care about the data passed around by DnD, but
                           we have to provide something otherwise it will stop.
                         */