13
0

Support paste between automation lanes.

Also push the increasingly unwieldly paste parameters into a context object.

As with othe things, currently it is only possible to do "cross-type paste" by
explicitly selecting the target track.  We will need to get automation region
view selection working to do better here, but at least for now it's possible to
get the data over.
This commit is contained in:
David Robillard 2014-12-06 12:20:52 -05:00
parent db1fc6c3fa
commit 63082821d8
9 changed files with 96 additions and 33 deletions

View File

@ -43,6 +43,7 @@
#include "gui_thread.h"
#include "route_time_axis.h"
#include "automation_line.h"
#include "paste_context.h"
#include "public_editor.h"
#include "selection.h"
#include "rgb_macros.h"
@ -633,14 +634,19 @@ AutomationTimeAxisView::add_automation_event (GdkEvent* event, framepos_t when,
}
bool
AutomationTimeAxisView::paste (framepos_t pos, unsigned paste_count, float times, const Selection& selection, ItemCounts& counts)
AutomationTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx)
{
if (_line) {
return paste_one (pos, paste_count, times, selection, counts);
return paste_one (pos, ctx.count, ctx.times, selection, ctx.counts, ctx.greedy);
} else if (_view) {
AutomationSelection::const_iterator l = selection.lines.get_nth(_parameter, counts.n_lines(_parameter));
if (l != selection.lines.end() && _view->paste (pos, paste_count, times, *l)) {
counts.increase_n_lines(_parameter);
AutomationSelection::const_iterator l = selection.lines.get_nth(_parameter, ctx.counts.n_lines(_parameter));
if (l == selection.lines.end()) {
if (ctx.greedy && selection.lines.size() == 1) {
l = selection.lines.begin();
}
}
if (l != selection.lines.end() && _view->paste (pos, ctx.count, ctx.times, *l)) {
ctx.counts.increase_n_lines(_parameter);
return true;
}
}
@ -649,7 +655,7 @@ AutomationTimeAxisView::paste (framepos_t pos, unsigned paste_count, float times
}
bool
AutomationTimeAxisView::paste_one (framepos_t pos, unsigned paste_count, float times, const Selection& selection, ItemCounts& counts)
AutomationTimeAxisView::paste_one (framepos_t pos, unsigned paste_count, float times, const Selection& selection, ItemCounts& counts, bool greedy)
{
boost::shared_ptr<AutomationList> alist(_line->the_list());
@ -661,7 +667,11 @@ AutomationTimeAxisView::paste_one (framepos_t pos, unsigned paste_count, float t
/* Get appropriate list from selection. */
AutomationSelection::const_iterator p = selection.lines.get_nth(_parameter, counts.n_lines(_parameter));
if (p == selection.lines.end()) {
return false;
if (greedy && selection.lines.size() == 1) {
p = selection.lines.begin();
} else {
return false;
}
}
counts.increase_n_lines(_parameter);

View File

@ -93,7 +93,7 @@ class AutomationTimeAxisView : public TimeAxisView {
/* editing operations */
void cut_copy_clear (Selection&, Editing::CutCopyOp);
bool paste (ARDOUR::framepos_t, unsigned paste_count, float times, const Selection&, ItemCounts&);
bool paste (ARDOUR::framepos_t, const Selection&, PasteContext&);
int set_state (const XMLNode&, int version);
@ -175,7 +175,7 @@ class AutomationTimeAxisView : public TimeAxisView {
void build_display_menu ();
void cut_copy_clear_one (AutomationLine&, Selection&, Editing::CutCopyOp);
bool paste_one (ARDOUR::framepos_t, unsigned, float times, const Selection&, ItemCounts& counts);
bool paste_one (ARDOUR::framepos_t, unsigned, float times, const Selection&, ItemCounts& counts, bool greedy=false);
void route_going_away ();
void set_automation_state (ARDOUR::AutoState);

View File

@ -83,6 +83,7 @@
#include "mixer_strip.h"
#include "mouse_cursors.h"
#include "normalize_dialog.h"
#include "paste_context.h"
#include "patch_change_dialog.h"
#include "quantize_dialog.h"
#include "region_gain_line.h"
@ -4446,11 +4447,24 @@ Editor::paste_internal (framepos_t position, float times)
RegionSelection rs;
get_regions_at (rs, position, ts);
ItemCounts counts;
if (ts.size() == 1 && cut_buffer->lines.size() == 1) {
AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(ts.front());
if (atv) {
/* Only one line, and one automation track selected. Do a
"greedy" paste from one automation type to another. */
PasteContext ctx(paste_count, times, ItemCounts(), true);
begin_reversible_command (Operations::paste);
atv->paste (position, *cut_buffer, ctx);
commit_reversible_command ();
return;
}
}
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, paste_count, times, *cut_buffer, counts);
mrv->paste (position, *cut_buffer, ctx);
}
}
@ -4460,9 +4474,9 @@ Editor::paste_internal (framepos_t position, float times)
begin_reversible_command (Operations::paste);
ItemCounts counts;
PasteContext ctx(paste_count, times, ItemCounts(), false);
for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
(*i)->paste (position, paste_count, times, *cut_buffer, counts);
(*i)->paste (position, *cut_buffer, ctx);
}
commit_reversible_command ();

View File

@ -66,6 +66,7 @@
#include "midi_velocity_dialog.h"
#include "mouse_cursors.h"
#include "note_player.h"
#include "paste_context.h"
#include "public_editor.h"
#include "route_time_axis.h"
#include "rgb_macros.h"
@ -3322,22 +3323,22 @@ MidiRegionView::selection_as_cut_buffer () const
/** This method handles undo */
bool
MidiRegionView::paste (framepos_t pos, unsigned paste_count, float times, const ::Selection& selection, ItemCounts& counts)
MidiRegionView::paste (framepos_t pos, const ::Selection& selection, PasteContext& ctx)
{
trackview.session()->begin_reversible_command (Operations::paste);
// Paste notes, if available
MidiNoteSelection::const_iterator m = selection.midi_notes.get_nth(counts.n_notes());
MidiNoteSelection::const_iterator m = selection.midi_notes.get_nth(ctx.counts.n_notes());
if (m != selection.midi_notes.end()) {
counts.increase_n_notes();
paste_internal(pos, paste_count, times, **m);
ctx.counts.increase_n_notes();
paste_internal(pos, ctx.count, ctx.times, **m);
}
// Paste control points to automation children, if available
typedef RouteTimeAxisView::AutomationTracks ATracks;
const ATracks& atracks = midi_view()->automation_tracks();
for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
a->second->paste(pos, paste_count, times, selection, counts);
a->second->paste(pos, selection, ctx);
}
trackview.session()->commit_reversible_command ();

View File

@ -113,7 +113,7 @@ public:
void resolve_note(uint8_t note_num, Evoral::MusicalTime end_time);
void cut_copy_clear (Editing::CutCopyOp);
bool paste (framepos_t pos, unsigned paste_count, float times, const ::Selection& selection, ItemCounts& counts);
bool paste (framepos_t pos, const ::Selection& selection, PasteContext& ctx);
void paste_internal (framepos_t pos, unsigned paste_count, float times, const MidiCutBuffer&);
void add_canvas_patch_change (ARDOUR::MidiModel::PatchChangePtr patch, const std::string& displaytext, bool);

View File

@ -0,0 +1,41 @@
/*
Copyright (C) 2014 Paul Davis
Author: David Robillard
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __ardour_paste_context_h__
#define __ardour_paste_context_h__
#include "item_counts.h"
class PasteContext
{
public:
PasteContext(unsigned count, float times, ItemCounts counts, bool greedy)
: count(count)
, times(times)
, counts(counts)
, greedy(greedy)
{}
unsigned count; ///< Number of previous pastes to the same position
float times; ///< Number of times to paste
ItemCounts counts; ///< Count of consumed selection items
bool greedy; ///< If true, greedily steal items that don't match
};
#endif /* __ardour_paste_context_h__ */

View File

@ -67,6 +67,7 @@
#include "gui_thread.h"
#include "item_counts.h"
#include "keyboard.h"
#include "paste_context.h"
#include "playlist_selector.h"
#include "point_selection.h"
#include "prompter.h"
@ -1572,7 +1573,7 @@ RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op)
}
bool
RouteTimeAxisView::paste (framepos_t pos, unsigned paste_count, float times, const Selection& selection, ItemCounts& counts)
RouteTimeAxisView::paste (framepos_t pos, const Selection& selection, PasteContext& ctx)
{
if (!is_track()) {
return false;
@ -1580,12 +1581,12 @@ RouteTimeAxisView::paste (framepos_t pos, unsigned paste_count, float times, con
boost::shared_ptr<Playlist> pl = playlist ();
const ARDOUR::DataType type = pl->data_type();
PlaylistSelection::const_iterator p = selection.playlists.get_nth(type, counts.n_playlists(type));
PlaylistSelection::const_iterator p = selection.playlists.get_nth(type, ctx.counts.n_playlists(type));
if (p == selection.playlists.end()) {
return false;
}
counts.increase_n_playlists(type);
ctx.counts.increase_n_playlists(type);
DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("paste to %1\n", pos));
@ -1597,15 +1598,15 @@ RouteTimeAxisView::paste (framepos_t pos, unsigned paste_count, float times, con
/* add multi-paste offset if applicable */
std::pair<framepos_t, framepos_t> extent = (*p)->get_extent();
const framecnt_t duration = extent.second - extent.first;
pos += _editor.get_paste_offset(pos, paste_count, duration);
pos += _editor.get_paste_offset(pos, ctx.count, duration);
pl->clear_changes ();
if (Config->get_edit_mode() == Ripple) {
std::pair<framepos_t, framepos_t> extent = (*p)->get_extent_with_endspace();
framecnt_t amount = extent.second - extent.first;
pl->ripple(pos, amount * times, boost::shared_ptr<Region>());
pl->ripple(pos, amount * ctx.times, boost::shared_ptr<Region>());
}
pl->paste (*p, pos, times);
pl->paste (*p, pos, ctx.times);
vector<Command*> cmds;
pl->rdiff (cmds);

View File

@ -100,7 +100,7 @@ public:
/* Editing operations */
void cut_copy_clear (Selection&, Editing::CutCopyOp);
bool paste (ARDOUR::framepos_t, unsigned paste_count, float times, const Selection&, ItemCounts&);
bool paste (ARDOUR::framepos_t, const Selection&, PasteContext& ctx);
RegionView* combine_regions ();
void uncombine_regions ();
void uncombine_region (RegionView*);

View File

@ -79,6 +79,7 @@ class GhostRegion;
class StreamView;
class ArdourDialog;
class ItemCounts;
class PasteContext;
/** Abstract base class for time-axis views (horizontal editor 'strips')
*
@ -169,17 +170,12 @@ class TimeAxisView : public virtual AxisView
/** Paste a selection.
* @param pos Position to paste to (session frames).
* @param paste_count Number of pastes to the same location previously (multi-paste).
* @param times Number of times to paste.
* @param selection Selection to paste.
* @param counts Count of consumed selection items (used to find the
* correct item to paste here, then updated for the next pastee).
* @param ctx Paste context.
*/
virtual bool paste (ARDOUR::framepos_t pos,
unsigned paste_count,
float times,
const Selection& selection,
ItemCounts& counts) { return false; }
PasteContext& ctx) { return false; }
virtual void set_selected_regionviews (RegionSelection&) {}
virtual void set_selected_points (PointSelection&) {}