summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2014-12-06 12:20:52 -0500
committerDavid Robillard <d@drobilla.net>2014-12-06 12:20:52 -0500
commit63082821d87a8be61982adc551a35fd399f346a2 (patch)
tree68fdf3115c3ba8fe87ed99a076aad5ff8a1b3792
parentdb1fc6c3fa5129f0ac20c6668339c477c8ee9447 (diff)
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.
-rw-r--r--gtk2_ardour/automation_time_axis.cc24
-rw-r--r--gtk2_ardour/automation_time_axis.h4
-rw-r--r--gtk2_ardour/editor_ops.cc22
-rw-r--r--gtk2_ardour/midi_region_view.cc11
-rw-r--r--gtk2_ardour/midi_region_view.h2
-rw-r--r--gtk2_ardour/paste_context.h41
-rw-r--r--gtk2_ardour/route_time_axis.cc13
-rw-r--r--gtk2_ardour/route_time_axis.h2
-rw-r--r--gtk2_ardour/time_axis_view.h10
9 files changed, 96 insertions, 33 deletions
diff --git a/gtk2_ardour/automation_time_axis.cc b/gtk2_ardour/automation_time_axis.cc
index 67e7c06421..e2a0effb39 100644
--- a/gtk2_ardour/automation_time_axis.cc
+++ b/gtk2_ardour/automation_time_axis.cc
@@ -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);
diff --git a/gtk2_ardour/automation_time_axis.h b/gtk2_ardour/automation_time_axis.h
index 156a5701e3..b726de6440 100644
--- a/gtk2_ardour/automation_time_axis.h
+++ b/gtk2_ardour/automation_time_axis.h
@@ -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);
diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc
index 00703dfc94..c84bae6ad4 100644
--- a/gtk2_ardour/editor_ops.cc
+++ b/gtk2_ardour/editor_ops.cc
@@ -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 ();
diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc
index 54c37267a7..bad479bc26 100644
--- a/gtk2_ardour/midi_region_view.cc
+++ b/gtk2_ardour/midi_region_view.cc
@@ -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 ();
diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h
index 08005497df..e846fc2764 100644
--- a/gtk2_ardour/midi_region_view.h
+++ b/gtk2_ardour/midi_region_view.h
@@ -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);
diff --git a/gtk2_ardour/paste_context.h b/gtk2_ardour/paste_context.h
new file mode 100644
index 0000000000..418ee98acf
--- /dev/null
+++ b/gtk2_ardour/paste_context.h
@@ -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__ */
diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc
index d741b70501..0e71f858a4 100644
--- a/gtk2_ardour/route_time_axis.cc
+++ b/gtk2_ardour/route_time_axis.cc
@@ -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);
diff --git a/gtk2_ardour/route_time_axis.h b/gtk2_ardour/route_time_axis.h
index 008ed932de..7ea86e9b1b 100644
--- a/gtk2_ardour/route_time_axis.h
+++ b/gtk2_ardour/route_time_axis.h
@@ -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*);
diff --git a/gtk2_ardour/time_axis_view.h b/gtk2_ardour/time_axis_view.h
index c46d23ae58..6dc02110c2 100644
--- a/gtk2_ardour/time_axis_view.h
+++ b/gtk2_ardour/time_axis_view.h
@@ -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&) {}