Fix copy paste of MIDI and track automation.
authorDavid Robillard <d@drobilla.net>
Tue, 16 Dec 2014 19:37:40 +0000 (14:37 -0500)
committerDavid Robillard <d@drobilla.net>
Fri, 19 Dec 2014 01:23:34 +0000 (20:23 -0500)
gtk2_ardour/automation_streamview.cc
gtk2_ardour/editor_ops.cc
gtk2_ardour/midi_region_view.cc
gtk2_ardour/midi_streamview.cc
gtk2_ardour/midi_streamview.h
gtk2_ardour/midi_time_axis.cc
gtk2_ardour/midi_time_axis.h
gtk2_ardour/region_view.h
gtk2_ardour/selection.cc
gtk2_ardour/selection.h

index 16dab909c7c9bb0c92a09919f40090db80db153e..9b68c55d2356164cc645eebaec9cc8d566edba77 100644 (file)
@@ -319,13 +319,6 @@ AutomationStreamView::get_lines () const
        return lines;
 }
 
-struct RegionPositionSorter {
-       bool operator() (RegionView* a, RegionView* b) {
-               return a->region()->position() < b->region()->position();
-       }
-};
-
-
 bool
 AutomationStreamView::paste (framepos_t                                pos,
                              unsigned                                  paste_count,
@@ -338,7 +331,7 @@ AutomationStreamView::paste (framepos_t                                pos,
                return false;
        }
 
-       region_views.sort (RegionPositionSorter ());
+       region_views.sort (RegionView::PositionOrder());
 
        list<RegionView*>::const_iterator prev = region_views.begin ();
 
index 77dad5bf29de7806cd6caf7f6f2cd0f1aeefeefc..c09bbcceb8dd3e31f8557795bdb0b496865361ec 100644 (file)
@@ -4478,46 +4478,27 @@ Editor::paste_internal (framepos_t position, float times)
                   R1.A1, R1.A2, R2, R2.A1, ... */
        }
 
+       begin_reversible_command (Operations::paste);
+
        if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
            dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
            /* Only one line copied, and one automation track selected.  Do a
               "greedy" paste from one automation type to another. */
 
-           begin_reversible_command (Operations::paste);
-
            PasteContext ctx(paste_count, times, ItemCounts(), true);
            ts.front()->paste (position, *cut_buffer, ctx);
 
-           commit_reversible_command ();
-
-       } else if (internal_editing ()) {
-
-               /* undo/redo is handled by individual tracks/regions */
-
-               RegionSelection rs;
-               get_regions_at (rs, position, ts);
-
-               PasteContext ctx(paste_count, times, ItemCounts(), false);
-               for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
-                       MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
-                       if (mrv) {
-                               mrv->paste (position, *cut_buffer, ctx);
-                       }
-               }
-
        } else {
 
-               /* we do redo (do you do voodoo?) */
-
-               begin_reversible_command (Operations::paste);
+               /* Paste into tracks */
 
                PasteContext ctx(paste_count, times, ItemCounts(), false);
                for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
                        (*i)->paste (position, *cut_buffer, ctx);
                }
-
-               commit_reversible_command ();
        }
+
+       commit_reversible_command ();
 }
 
 void
index 18ea905ce447bca4006e4b68a208ef700088ff92..787a997e7e44912ab135318116627622915c6d1d 100644 (file)
@@ -3365,8 +3365,6 @@ MidiRegionView::selection_as_cut_buffer () const
 bool
 MidiRegionView::paste (framepos_t pos, const ::Selection& selection, PasteContext& ctx)
 {
-       trackview.editor().begin_reversible_command (Operations::paste);
-
        // Paste notes, if available
        MidiNoteSelection::const_iterator m = selection.midi_notes.get_nth(ctx.counts.n_notes());
        if (m != selection.midi_notes.end()) {
@@ -3381,8 +3379,6 @@ MidiRegionView::paste (framepos_t pos, const ::Selection& selection, PasteContex
                a->second->paste(pos, selection, ctx);
        }
 
-       trackview.editor().commit_reversible_command ();
-
        return true;
 }
 
index f47091b3a6e7727dea27d197f34043b903c633da..5207b7354d7a0ba3edeb966a9e4b4ee17e397a28 100644 (file)
@@ -654,3 +654,41 @@ MidiStreamView::resume_updates ()
 
        _canvas_group->redraw ();
 }
+
+struct RegionPositionSorter {
+       bool operator() (RegionView* a, RegionView* b) {
+               return a->region()->position() < b->region()->position();
+       }
+};
+
+bool
+MidiStreamView::paste (ARDOUR::framepos_t pos, const Selection& selection, PasteContext& ctx)
+{
+       /* Paste into the first region which starts on or before pos.  Only called when
+          using an internal editing tool. */
+
+       if (region_views.empty()) {
+               return false;
+       }
+
+       region_views.sort (RegionView::PositionOrder());
+
+       list<RegionView*>::const_iterator prev = region_views.begin ();
+
+       for (list<RegionView*>::const_iterator i = region_views.begin(); i != region_views.end(); ++i) {
+               if ((*i)->region()->position() > pos) {
+                       break;
+               }
+               prev = i;
+       }
+
+       boost::shared_ptr<Region> r = (*prev)->region ();
+
+       /* If *prev doesn't cover pos, it's no good */
+       if (r->position() > pos || ((r->position() + r->length()) < pos)) {
+               return false;
+       }
+
+       MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*prev);
+       return mrv ? mrv->paste(pos, selection, ctx) : false;
+}
index 7733f87074a41b6ac3c60bf64f653251eebd1c75..9be3b34d9ce1b779e7d034630e4852217f047768 100644 (file)
@@ -98,6 +98,8 @@ class MidiStreamView : public StreamView
 
        RegionView* create_region_view (boost::shared_ptr<ARDOUR::Region>, bool, bool);
 
+       bool paste (ARDOUR::framepos_t pos, const Selection& selection, PasteContext& ctx);
+
        void apply_note_range(uint8_t lowest, uint8_t highest, bool to_region_views);
 
        void suspend_updates ();
index b23d86194a93806ac17ecd8afb5bb4bbc1063fef..f15cf231f0e21f9ddbd0956f7af038f1e9c9096a 100644 (file)
@@ -1583,3 +1583,14 @@ MidiTimeAxisView::capture_channel_mode_changed ()
                break;
        }
 }
+
+bool
+MidiTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx)
+{
+       if (!_editor.internal_editing()) {
+               // Non-internal paste, paste regions like any other route
+               return RouteTimeAxisView::paste(pos, selection, ctx);
+       }
+
+       return midi_view()->paste(pos, selection, ctx);
+}
index ebc51b14278a53bcd83c918be5161b7ae7502c96..1897174e11512cb8315f3b8b3f8a4ea503170e55 100644 (file)
@@ -81,6 +81,8 @@ class MidiTimeAxisView : public RouteTimeAxisView
        void show_existing_automation (bool apply_to_selection = false);
        void create_automation_child (const Evoral::Parameter& param, bool show);
 
+       bool paste (ARDOUR::framepos_t, const Selection&, PasteContext& ctx);
+
        ARDOUR::NoteMode  note_mode() const { return _note_mode; }
        ARDOUR::ColorMode color_mode() const { return _color_mode; }
 
index 389faf89210adda3c95ca2d4dece9a11585d52d5..d39e75b759de7215dada75cf2b4696f7b174e1fe 100644 (file)
@@ -113,6 +113,12 @@ class RegionView : public TimeAxisViewItem
         void drop_silent_frames ();
         void hide_silent_frames ();
 
+       struct PositionOrder {
+               bool operator()(const RegionView* a, const RegionView* b) {
+                       return a->region()->position() < b->region()->position();
+               }
+       };
+
        ARDOUR::frameoffset_t snap_frame_to_frame (ARDOUR::frameoffset_t) const;
        
   protected:
index 9f69666497c314a869e02cb17aa07eb3d1bac174..b00f59ce83f558f36a6e47ff41ad750f5a69f93c 100644 (file)
@@ -42,8 +42,6 @@ using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
-PBD::Signal0<void> Selection::ClearMidiNoteSelection;
-
 struct AudioRangeComparator {
     bool operator()(AudioRange a, AudioRange b) {
            return a.start < b.start;
index 1701d693991791d049c66735274d4a622fcbbf7e..fe2be2e6e4fe0025c3698a5fa377cbfbe56e4f96 100644 (file)
@@ -221,7 +221,7 @@ class Selection : public sigc::trackable, public PBD::ScopedConnectionList
        XMLNode& get_state () const;
        int set_state (XMLNode const &, int);
 
-       static PBD::Signal0<void> ClearMidiNoteSelection;
+       PBD::Signal0<void> ClearMidiNoteSelection;
 
   private:
        PublicEditor const * editor;