MIDI: ctrl-d now duplicates selected notes

This commit also fixes selection-after-paste, so that the selection is always
the newly pasted notes.
This commit is contained in:
Paul Davis 2022-04-27 08:13:04 -06:00
parent 8d4516228a
commit 9e77d8923a
4 changed files with 55 additions and 2 deletions

View File

@ -487,6 +487,7 @@ This mode provides many different operations on both regions and control points,
@notes|Notes/alt-add-select-previous|<@PRIMARY@><@TERTIARY@>ISO_Left_Tab|Add previous note to selection
@notes|Notes/extend-selection|<@PRIMARY@>e|Extend selection to end of region
@notes|Notes/invert-selection|<@PRIMARY@>i|Invert note selection
@notes|Notes/duplicate-selection|<@PRIMARY@>d|Duplicate note selection
@rec|Recorder/arm-all|<@PRIMARY@>r|record arm all tracks
@rec|Recorder/arm-none|<@PRIMARY@><@TERTIARY@>r|disable record arm of all tracks

View File

@ -798,6 +798,7 @@ Editor::register_midi_actions (Bindings* midi_bindings)
ActionManager::register_action (_midi_actions, X_("clear-selection"), _("Clear Note Selection"), sigc::bind (sigc::mem_fun (*this, &Editor::midi_action), &MidiRegionView::clear_note_selection));
ActionManager::register_action (_midi_actions, X_("invert-selection"), _("Invert Note Selection"), sigc::bind (sigc::mem_fun (*this, &Editor::midi_action), &MidiRegionView::invert_selection));
ActionManager::register_action (_midi_actions, X_("extend-selection"), _("Extend Note Selection"), sigc::bind (sigc::mem_fun (*this, &Editor::midi_action), &MidiRegionView::extend_selection));
ActionManager::register_action (_midi_actions, X_("duplicate-selection"), _("Duplicate Note Selection"), sigc::bind (sigc::mem_fun (*this, &Editor::midi_action), &MidiRegionView::duplicate_selection));
/* Lengthen */

View File

@ -171,6 +171,7 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Container* parent,
, _last_event_y (0)
, _entered (false)
, _entered_note (0)
, _pasting (false)
, _mouse_changed_selection (false)
{
CANVAS_DEBUG_NAME (_note_group, string_compose ("note group for %1", get_item_name()));
@ -1935,7 +1936,9 @@ MidiRegionView::add_note(const boost::shared_ptr<NoteType> note, bool visible)
}
}
if (_marked_for_selection.find(note) != _marked_for_selection.end()) {
if (_pasting) {
note_selected (event, true);
} else if (_marked_for_selection.find(note) != _marked_for_selection.end()) {
note_selected (event, false);
}
@ -3800,20 +3803,61 @@ MidiRegionView::selection_as_cut_buffer () const
return cb;
}
void
MidiRegionView::duplicate_selection ()
{
std::cerr << "dup selection\n";
if (_selection.empty()) {
return;
}
/* find last selection position */
timepos_t dup_pos = timepos_t (Temporal::BeatTime);
for (Selection::const_iterator s = _selection.begin(); s != _selection.end(); ++s) {
dup_pos = std::max (dup_pos, _region->source_beats_to_absolute_time ((*s)->note()->end_time()));
}
PublicEditor& editor (trackview.editor());
/* Use a local Selection object that will not affect the global
* selection. Possible ::paste() should accept a different kind of
* object but that would conflict with the Editor API.
*/
::Selection local_selection (&editor, false);
MidiNoteSelection note_selection;
note_selection.push_back (selection_as_cut_buffer());
local_selection.set (note_selection);
PasteContext ctxt (0, 1, ItemCounts(), false);
paste (dup_pos, local_selection, ctxt);
}
/** This method handles undo */
bool
MidiRegionView::paste (timepos_t const & pos, const ::Selection& selection, PasteContext& ctx)
{
bool commit = false;
// Paste notes, if available
MidiNoteSelection::const_iterator m = selection.midi_notes.get_nth(ctx.counts.n_notes());
if (m != selection.midi_notes.end()) {
ctx.counts.increase_n_notes();
if (!(*m)->empty()) {
commit = true;
}
paste_internal(pos, ctx.count, ctx.times, **m);
/* clear any current selection because we're going to select the duplicated ones */
clear_note_selection ();
paste_internal (pos, ctx.count, ctx.times, **m);
}
// Paste control points to automation children, if available
@ -3842,6 +3886,8 @@ MidiRegionView::paste_internal (timepos_t const & pos, unsigned paste_count, flo
return;
}
PBD::Unwinder<bool> puw (_pasting, true);
start_note_diff_command (_("paste"));
const Temporal::Beats snap_beats = get_grid_beats(pos);
@ -3889,6 +3935,9 @@ MidiRegionView::paste_internal (timepos_t const & pos, unsigned paste_count, flo
trackview.session()->add_command (new StatefulDiffCommand (_region));
}
_marked_for_selection.clear ();
_pending_note_selection.clear ();
apply_diff (true);
}

View File

@ -208,6 +208,7 @@ public:
void select_range(Temporal::timepos_t const & start, Temporal::timepos_t const & end);
void invert_selection ();
void extend_selection ();
void duplicate_selection ();
Temporal::Beats earliest_in_selection ();
void move_selection(Temporal::timecnt_t const & dx, double dy, double cumulative_dy);
@ -545,6 +546,7 @@ public:
double _last_event_y;
bool _entered;
NoteBase* _entered_note;
bool _pasting;
bool _mouse_changed_selection;