Fix copy paste of MIDI and track automation.
This commit is contained in:
parent
026f7bf5b7
commit
a12a065457
|
@ -319,13 +319,6 @@ AutomationStreamView::get_lines () const
|
||||||
return lines;
|
return lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RegionPositionSorter {
|
|
||||||
bool operator() (RegionView* a, RegionView* b) {
|
|
||||||
return a->region()->position() < b->region()->position();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
AutomationStreamView::paste (framepos_t pos,
|
AutomationStreamView::paste (framepos_t pos,
|
||||||
unsigned paste_count,
|
unsigned paste_count,
|
||||||
|
@ -338,7 +331,7 @@ AutomationStreamView::paste (framepos_t pos,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
region_views.sort (RegionPositionSorter ());
|
region_views.sort (RegionView::PositionOrder());
|
||||||
|
|
||||||
list<RegionView*>::const_iterator prev = region_views.begin ();
|
list<RegionView*>::const_iterator prev = region_views.begin ();
|
||||||
|
|
||||||
|
|
|
@ -4478,46 +4478,27 @@ Editor::paste_internal (framepos_t position, float times)
|
||||||
R1.A1, R1.A2, R2, R2.A1, ... */
|
R1.A1, R1.A2, R2, R2.A1, ... */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
begin_reversible_command (Operations::paste);
|
||||||
|
|
||||||
if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
|
if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
|
||||||
dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
|
dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
|
||||||
/* Only one line copied, and one automation track selected. Do a
|
/* Only one line copied, and one automation track selected. Do a
|
||||||
"greedy" paste from one automation type to another. */
|
"greedy" paste from one automation type to another. */
|
||||||
|
|
||||||
begin_reversible_command (Operations::paste);
|
|
||||||
|
|
||||||
PasteContext ctx(paste_count, times, ItemCounts(), true);
|
PasteContext ctx(paste_count, times, ItemCounts(), true);
|
||||||
ts.front()->paste (position, *cut_buffer, ctx);
|
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 {
|
} else {
|
||||||
|
|
||||||
/* we do redo (do you do voodoo?) */
|
/* Paste into tracks */
|
||||||
|
|
||||||
begin_reversible_command (Operations::paste);
|
|
||||||
|
|
||||||
PasteContext ctx(paste_count, times, ItemCounts(), false);
|
PasteContext ctx(paste_count, times, ItemCounts(), false);
|
||||||
for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
|
for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
|
||||||
(*i)->paste (position, *cut_buffer, ctx);
|
(*i)->paste (position, *cut_buffer, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
commit_reversible_command ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
commit_reversible_command ();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -3365,8 +3365,6 @@ MidiRegionView::selection_as_cut_buffer () const
|
||||||
bool
|
bool
|
||||||
MidiRegionView::paste (framepos_t pos, const ::Selection& selection, PasteContext& ctx)
|
MidiRegionView::paste (framepos_t pos, const ::Selection& selection, PasteContext& ctx)
|
||||||
{
|
{
|
||||||
trackview.editor().begin_reversible_command (Operations::paste);
|
|
||||||
|
|
||||||
// Paste notes, if available
|
// Paste notes, if available
|
||||||
MidiNoteSelection::const_iterator m = selection.midi_notes.get_nth(ctx.counts.n_notes());
|
MidiNoteSelection::const_iterator m = selection.midi_notes.get_nth(ctx.counts.n_notes());
|
||||||
if (m != selection.midi_notes.end()) {
|
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);
|
a->second->paste(pos, selection, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
trackview.editor().commit_reversible_command ();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -654,3 +654,41 @@ MidiStreamView::resume_updates ()
|
||||||
|
|
||||||
_canvas_group->redraw ();
|
_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;
|
||||||
|
}
|
||||||
|
|
|
@ -98,6 +98,8 @@ class MidiStreamView : public StreamView
|
||||||
|
|
||||||
RegionView* create_region_view (boost::shared_ptr<ARDOUR::Region>, bool, bool);
|
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 apply_note_range(uint8_t lowest, uint8_t highest, bool to_region_views);
|
||||||
|
|
||||||
void suspend_updates ();
|
void suspend_updates ();
|
||||||
|
|
|
@ -1583,3 +1583,14 @@ MidiTimeAxisView::capture_channel_mode_changed ()
|
||||||
break;
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -81,6 +81,8 @@ class MidiTimeAxisView : public RouteTimeAxisView
|
||||||
void show_existing_automation (bool apply_to_selection = false);
|
void show_existing_automation (bool apply_to_selection = false);
|
||||||
void create_automation_child (const Evoral::Parameter& param, bool show);
|
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::NoteMode note_mode() const { return _note_mode; }
|
||||||
ARDOUR::ColorMode color_mode() const { return _color_mode; }
|
ARDOUR::ColorMode color_mode() const { return _color_mode; }
|
||||||
|
|
||||||
|
|
|
@ -113,6 +113,12 @@ class RegionView : public TimeAxisViewItem
|
||||||
void drop_silent_frames ();
|
void drop_silent_frames ();
|
||||||
void hide_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;
|
ARDOUR::frameoffset_t snap_frame_to_frame (ARDOUR::frameoffset_t) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -42,8 +42,6 @@ using namespace std;
|
||||||
using namespace ARDOUR;
|
using namespace ARDOUR;
|
||||||
using namespace PBD;
|
using namespace PBD;
|
||||||
|
|
||||||
PBD::Signal0<void> Selection::ClearMidiNoteSelection;
|
|
||||||
|
|
||||||
struct AudioRangeComparator {
|
struct AudioRangeComparator {
|
||||||
bool operator()(AudioRange a, AudioRange b) {
|
bool operator()(AudioRange a, AudioRange b) {
|
||||||
return a.start < b.start;
|
return a.start < b.start;
|
||||||
|
|
|
@ -221,7 +221,7 @@ class Selection : public sigc::trackable, public PBD::ScopedConnectionList
|
||||||
XMLNode& get_state () const;
|
XMLNode& get_state () const;
|
||||||
int set_state (XMLNode const &, int);
|
int set_state (XMLNode const &, int);
|
||||||
|
|
||||||
static PBD::Signal0<void> ClearMidiNoteSelection;
|
PBD::Signal0<void> ClearMidiNoteSelection;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PublicEditor const * editor;
|
PublicEditor const * editor;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user