summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornick_m <mainsbridge@gmail.com>2015-01-11 04:07:31 +1100
committernick_m <mainsbridge@gmail.com>2015-01-11 04:07:31 +1100
commit44203ce955f33135065456f55f1f685131174ba6 (patch)
tree623864e0e94e7d1fb59c5ee24bdbd16f551aee4b
parent9e873acedb35ee0077f128a2da1648b65c78eeeb (diff)
Fix AutomationTrackItem rubberband click thinking it was unhandled.
Fix several other cases where a single mouse click could cause several (not nested) selection ops. Fix missing selection memento for midi notes and midi commands. Rename some variables. Fix random style issues.
-rw-r--r--gtk2_ardour/automation_line.cc2
-rw-r--r--gtk2_ardour/editor.cc56
-rw-r--r--gtk2_ardour/editor.h4
-rw-r--r--gtk2_ardour/editor_canvas_events.cc4
-rw-r--r--gtk2_ardour/editor_drag.cc26
-rw-r--r--gtk2_ardour/editor_mouse.cc25
-rw-r--r--gtk2_ardour/editor_selection.cc14
-rw-r--r--gtk2_ardour/midi_region_view.cc102
-rw-r--r--gtk2_ardour/midi_region_view.h7
-rw-r--r--gtk2_ardour/midi_time_axis.cc41
-rw-r--r--gtk2_ardour/midi_time_axis.h11
-rw-r--r--gtk2_ardour/public_editor.h6
-rw-r--r--gtk2_ardour/selection.cc141
-rw-r--r--gtk2_ardour/selection.h2
14 files changed, 375 insertions, 66 deletions
diff --git a/gtk2_ardour/automation_line.cc b/gtk2_ardour/automation_line.cc
index c0ed14f7f9..d5ed529ad8 100644
--- a/gtk2_ardour/automation_line.cc
+++ b/gtk2_ardour/automation_line.cc
@@ -156,7 +156,7 @@ void
AutomationLine::update_visibility ()
{
if (_visible & Line) {
- /* Only show the line there are some points, otherwise we may show an out-of-date line
+ /* Only show the line when there are some points, otherwise we may show an out-of-date line
when automation points have been removed (the line will still follow the shape of the
old points).
*/
diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc
index da1c25f374..b18d6d6fb8 100644
--- a/gtk2_ardour/editor.cc
+++ b/gtk2_ardour/editor.cc
@@ -81,7 +81,6 @@
#include "control_protocol/control_protocol.h"
#include "actions.h"
-#include "actions.h"
#include "analysis_window.h"
#include "audio_clock.h"
#include "audio_region_view.h"
@@ -251,6 +250,7 @@ pane_size_watcher (Paned* pane)
Editor::Editor ()
: _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
+ , _mouse_changed_selection (false)
/* time display buttons */
, minsec_label (_("Mins:Secs"))
, bbt_label (_("Bars:Beats"))
@@ -3336,7 +3336,7 @@ void
Editor::begin_reversible_selection_op (string name)
{
if (_session) {
- //cerr << name << endl;
+ cerr << name << endl;
/* begin/commit pairs can be nested */
selection_op_cmd_depth++;
}
@@ -3349,20 +3349,22 @@ Editor::commit_reversible_selection_op ()
if (selection_op_cmd_depth == 1) {
if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
+ /* the user has undone some selection ops and then made a new one */
list<XMLNode *>::iterator it = selection_op_history.begin();
advance (it, selection_op_history_it);
selection_op_history.erase (selection_op_history.begin(), it);
}
+
selection_op_history.push_front (&_selection_memento->get_state ());
selection_op_history_it = 0;
+
+ selection_undo_action->set_sensitive (true);
+ selection_redo_action->set_sensitive (false);
}
if (selection_op_cmd_depth > 0) {
selection_op_cmd_depth--;
}
-
- selection_undo_action->set_sensitive (true);
- selection_redo_action->set_sensitive (false);
}
}
@@ -3378,7 +3380,6 @@ Editor::undo_selection_op ()
selection_redo_action->set_sensitive (true);
}
++n;
-
}
/* is there an earlier entry? */
if ((selection_op_history_it + 1) >= selection_op_history.size()) {
@@ -3401,7 +3402,6 @@ Editor::redo_selection_op ()
selection_undo_action->set_sensitive (true);
}
++n;
-
}
if (selection_op_history_it == 0) {
@@ -4899,17 +4899,17 @@ Editor::get_regions_from_selection_and_entered ()
}
void
-Editor::get_regionviews_by_id (PBD::ID const & id, RegionSelection & regions) const
+Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
{
for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
- RouteTimeAxisView* tatv;
+ RouteTimeAxisView* rtav;
- if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
+ if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
boost::shared_ptr<Playlist> pl;
std::vector<boost::shared_ptr<Region> > results;
boost::shared_ptr<Track> tr;
- if ((tr = tatv->track()) == 0) {
+ if ((tr = rtav->track()) == 0) {
/* bus */
continue;
}
@@ -4917,9 +4917,9 @@ Editor::get_regionviews_by_id (PBD::ID const & id, RegionSelection & regions) co
if ((pl = (tr->playlist())) != 0) {
boost::shared_ptr<Region> r = pl->region_by_id (id);
if (r) {
- RegionView* marv = tatv->view()->find_view (r);
- if (marv) {
- regions.push_back (marv);
+ RegionView* rv = rtav->view()->find_view (r);
+ if (rv) {
+ regions.push_back (rv);
}
}
}
@@ -4928,6 +4928,21 @@ Editor::get_regionviews_by_id (PBD::ID const & id, RegionSelection & regions) co
}
void
+Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
+{
+
+ for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
+ MidiTimeAxisView* mtav;
+
+ if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
+
+ mtav->get_per_region_note_selection (selection);
+ }
+ }
+
+}
+
+void
Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
{
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
@@ -5102,6 +5117,19 @@ Editor::region_view_added (RegionView * rv)
break;
}
}
+
+ MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
+ if (mrv) {
+ list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
+ for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
+ if (rv->region()->id () == (*rnote).first) {
+ mrv->select_notes ((*rnote).second);
+ selection->pending_midi_note_selection.erase(rnote);
+ break;
+ }
+ }
+ }
+
_summary->set_background_dirty ();
}
diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h
index 77d28f4e12..7e1d1702f0 100644
--- a/gtk2_ardour/editor.h
+++ b/gtk2_ardour/editor.h
@@ -421,7 +421,8 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
void get_regions_corresponding_to (boost::shared_ptr<ARDOUR::Region> region, std::vector<RegionView*>& regions, bool src_comparison);
- void get_regionviews_by_id (PBD::ID const & id, RegionSelection & regions) const;
+ void get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const;
+ void get_per_region_note_selection (std::list<std::pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >&) const;
void center_screen (framepos_t);
@@ -706,6 +707,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
void button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type);
bool button_release_can_deselect;
+ bool _mouse_changed_selection;
void catch_vanishing_regionview (RegionView *);
diff --git a/gtk2_ardour/editor_canvas_events.cc b/gtk2_ardour/editor_canvas_events.cc
index 93c0abea35..c1696c9f6c 100644
--- a/gtk2_ardour/editor_canvas_events.cc
+++ b/gtk2_ardour/editor_canvas_events.cc
@@ -178,7 +178,9 @@ Editor::canvas_scroll_event (GdkEventScroll *event, bool from_canvas)
bool
Editor::track_canvas_button_press_event (GdkEventButton */*event*/)
{
+ begin_reversible_selection_op (_("Clear Selection Click (track canvas)"));
selection->clear ();
+ commit_reversible_selection_op();
_track_canvas->grab_focus();
return false;
}
@@ -1105,8 +1107,10 @@ Editor::canvas_drop_zone_event (GdkEvent* event)
switch (event->type) {
case GDK_BUTTON_RELEASE:
if (event->button.button == 1) {
+ begin_reversible_selection_op (_("Nowhere Click"));
selection->clear_objects ();
selection->clear_tracks ();
+ commit_reversible_selection_op ();
}
break;
diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc
index 9cf0f05b60..aef59ed19e 100644
--- a/gtk2_ardour/editor_drag.cc
+++ b/gtk2_ardour/editor_drag.cc
@@ -4718,6 +4718,9 @@ NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
} else {
_region->unique_select (_primary);
}
+
+ _editor->begin_reversible_selection_op(_("Select Note Press"));
+ _editor->commit_reversible_selection_op();
}
}
}
@@ -4799,14 +4802,17 @@ NoteDrag::finished (GdkEvent* ev, bool moved)
{
if (!moved) {
/* no motion - select note */
-
+
if (_editor->current_mouse_mode() == Editing::MouseObject ||
_editor->current_mouse_mode() == Editing::MouseDraw) {
-
+
+ bool changed = false;
+
if (_was_selected) {
bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
if (add) {
_region->note_deselected (_primary);
+ changed = true;
}
} else {
bool extend = Keyboard::modifier_state_equals (ev->button.state, Keyboard::TertiaryModifier);
@@ -4814,12 +4820,19 @@ NoteDrag::finished (GdkEvent* ev, bool moved)
if (!extend && !add && _region->selection_size() > 1) {
_region->unique_select (_primary);
+ changed = true;
} else if (extend) {
_region->note_selected (_primary, true, true);
+ changed = true;
} else {
/* it was added during button press */
}
}
+
+ if (changed) {
+ _editor->begin_reversible_selection_op(_("Select Note Release"));
+ _editor->commit_reversible_selection_op();
+ }
}
} else {
_region->note_dropped (_primary, total_dx(), total_dy());
@@ -5204,12 +5217,15 @@ EditorRubberbandSelectDrag::select_things (int button_state, framepos_t x1, fram
void
EditorRubberbandSelectDrag::deselect_things ()
{
- if (!getenv("ARDOUR_SAE")) {
- _editor->selection->clear_tracks();
- }
+ _editor->begin_reversible_selection_op (_("Clear Selection (rubberband)"));
+
+ _editor->selection->clear_tracks();
_editor->selection->clear_regions();
_editor->selection->clear_points ();
_editor->selection->clear_lines ();
+ _editor->selection->clear_midi_notes ();
+
+ _editor->commit_reversible_selection_op();
}
NoteCreateDrag::NoteCreateDrag (Editor* e, ArdourCanvas::Item* i, MidiRegionView* rv)
diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc
index e093eb5426..b781832618 100644
--- a/gtk2_ardour/editor_mouse.cc
+++ b/gtk2_ardour/editor_mouse.cc
@@ -448,11 +448,15 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp
Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
bool press = (event->type == GDK_BUTTON_PRESS);
+ if (press) {
+ _mouse_changed_selection = false;
+ }
+
switch (item_type) {
case RegionItem:
if (press) {
if (eff_mouse_mode != MouseRange) {
- set_selected_regionview_from_click (press, op);
+ _mouse_changed_selection = set_selected_regionview_from_click (press, op);
} else {
/* don't change the selection unless the
clicked track is not currently selected. if
@@ -465,7 +469,7 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp
}
} else {
if (eff_mouse_mode != MouseRange) {
- set_selected_regionview_from_click (press, op);
+ _mouse_changed_selection = set_selected_regionview_from_click (press, op);
}
}
break;
@@ -483,7 +487,7 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp
case StartCrossFadeItem:
case EndCrossFadeItem:
if (get_smart_mode() || eff_mouse_mode != MouseRange) {
- set_selected_regionview_from_click (press, op);
+ _mouse_changed_selection = set_selected_regionview_from_click (press, op);
} else if (event->type == GDK_BUTTON_PRESS) {
set_selected_track_as_side_effect (op);
}
@@ -492,7 +496,7 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp
case ControlPointItem:
set_selected_track_as_side_effect (op);
if (eff_mouse_mode != MouseRange) {
- set_selected_control_point_from_click (press, op);
+ _mouse_changed_selection = set_selected_control_point_from_click (press, op);
}
break;
@@ -501,6 +505,7 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp
if (event->button.button == 3) {
selection->clear_tracks ();
set_selected_track_as_side_effect (op);
+ _mouse_changed_selection = true;
}
break;
@@ -511,6 +516,12 @@ Editor::button_selection (ArdourCanvas::Item* /*item*/, GdkEvent* event, ItemTyp
default:
break;
}
+
+ if ((!press) && _mouse_changed_selection) {
+ begin_reversible_selection_op (_("Button Selection"));
+ commit_reversible_selection_op ();
+ _mouse_changed_selection = false;
+ }
}
bool
@@ -744,6 +755,7 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
case AutomationTrackItem:
/* rubberband drag to select automation points */
_drags->set (new EditorRubberbandSelectDrag (this, item), event);
+ return true;
break;
default:
@@ -1465,10 +1477,7 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
}
/* do any (de)selection operations that should occur on button release */
-
- begin_reversible_selection_op (_("Button Select"));
- button_selection (item, event, item_type);
- commit_reversible_selection_op ();
+ button_selection (item, event, item_type);
return true;
break;
diff --git a/gtk2_ardour/editor_selection.cc b/gtk2_ardour/editor_selection.cc
index 60f8b0433b..c46ef04a64 100644
--- a/gtk2_ardour/editor_selection.cc
+++ b/gtk2_ardour/editor_selection.cc
@@ -202,8 +202,9 @@ Editor::set_selected_track_as_side_effect (Selection::Operation op)
}
} else if (group && group->is_active()) {
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
- if ((*i)->route_group() == group)
+ if ((*i)->route_group() == group) {
selection->remove(*i);
+ }
}
} else {
selection->remove (clicked_axisview);
@@ -215,8 +216,9 @@ Editor::set_selected_track_as_side_effect (Selection::Operation op)
}
} else if (group && group->is_active()) {
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
- if ( (*i)->route_group() == group)
+ if ((*i)->route_group() == group) {
selection->add(*i);
+ }
}
} else {
selection->add (clicked_axisview);
@@ -234,8 +236,9 @@ Editor::set_selected_track_as_side_effect (Selection::Operation op)
}
} else if (group && group->is_active()) {
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
- if ((*i)->route_group() == group)
+ if ((*i)->route_group() == group) {
selection->add(*i);
+ }
}
} else {
selection->add (clicked_axisview);
@@ -253,8 +256,9 @@ Editor::set_selected_track_as_side_effect (Selection::Operation op)
}
} else if (group && group->is_active()) {
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end (); ++i) {
- if ((*i)->route_group() == group)
+ if ((*i)->route_group() == group) {
selection->add(*i);
+ }
}
} else {
selection->set (clicked_axisview);
@@ -1953,7 +1957,7 @@ Editor::get_edit_op_range (framepos_t& start, framepos_t& end) const
void
Editor::deselect_all ()
{
- begin_reversible_selection_op(_("Clear Selection"));
+ begin_reversible_selection_op(_("Deselect All"));
selection->clear ();
commit_reversible_selection_op ();
}
diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc
index 97cb11529e..6e257cc0ee 100644
--- a/gtk2_ardour/midi_region_view.cc
+++ b/gtk2_ardour/midi_region_view.cc
@@ -123,6 +123,7 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Container* parent,
, _last_event_y (0)
, _grabbed_keyboard (false)
, _entered (false)
+ , _mouse_changed_selection (false)
{
CANVAS_DEBUG_NAME (_note_group, string_compose ("note group for %1", get_item_name()));
_note_group->raise_to_top();
@@ -169,6 +170,7 @@ MidiRegionView::MidiRegionView (ArdourCanvas::Container* parent,
, _last_event_y (0)
, _grabbed_keyboard (false)
, _entered (false)
+ , _mouse_changed_selection (false)
{
CANVAS_DEBUG_NAME (_note_group, string_compose ("note group for %1", get_item_name()));
_note_group->raise_to_top();
@@ -220,6 +222,7 @@ MidiRegionView::MidiRegionView (const MidiRegionView& other)
, _last_event_y (0)
, _grabbed_keyboard (false)
, _entered (false)
+ , _mouse_changed_selection (false)
{
init (false);
}
@@ -250,6 +253,7 @@ MidiRegionView::MidiRegionView (const MidiRegionView& other, boost::shared_ptr<M
, _last_event_y (0)
, _grabbed_keyboard (false)
, _entered (false)
+ , _mouse_changed_selection (false)
{
init (true);
}
@@ -502,6 +506,7 @@ MidiRegionView::button_press (GdkEventButton* ev)
}
_pressed_button = ev->button;
+ _mouse_changed_selection = false;
return true;
}
@@ -532,12 +537,14 @@ MidiRegionView::button_release (GdkEventButton* ev)
case MouseRange:
/* no motion occured - simple click */
clear_selection ();
+ _mouse_changed_selection = true;
break;
case MouseContent:
case MouseTimeFX:
{
clear_selection();
+ _mouse_changed_selection = true;
if (Keyboard::is_insert_note_event(ev)) {
@@ -591,6 +598,11 @@ MidiRegionView::button_release (GdkEventButton* ev)
break;
}
+ if(_mouse_changed_selection) {
+ trackview.editor().begin_reversible_selection_op (_("Mouse Selection Change"));
+ trackview.editor().commit_reversible_selection_op ();
+ }
+
return false;
}
@@ -643,6 +655,7 @@ MidiRegionView::motion (GdkEventMotion* ev)
editor.drags()->set (new MidiRubberbandSelectDrag (dynamic_cast<Editor *> (&editor), this), (GdkEvent *) ev);
if (!Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
clear_selection ();
+ _mouse_changed_selection = true;
}
_mouse_state = SelectRectDragging;
return true;
@@ -747,22 +760,32 @@ MidiRegionView::key_press (GdkEventKey* ev)
} else if (ev->keyval == GDK_Tab) {
+ trackview.editor().begin_reversible_selection_op (_("Select Adjacent Note"));
+
if (Keyboard::modifier_state_contains (ev->state, Keyboard::PrimaryModifier)) {
goto_previous_note (Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier));
} else {
goto_next_note (Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier));
}
+
+ trackview.editor().commit_reversible_selection_op();
+
return true;
} else if (ev->keyval == GDK_ISO_Left_Tab) {
/* Shift-TAB generates ISO Left Tab, for some reason */
+ trackview.editor().begin_reversible_selection_op (_("Select Adjacent Note"));
+
if (Keyboard::modifier_state_contains (ev->state, Keyboard::PrimaryModifier)) {
goto_previous_note (Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier));
} else {
goto_next_note (Keyboard::modifier_state_contains (ev->state, Keyboard::TertiaryModifier));
}
+
+ trackview.editor().commit_reversible_selection_op();
+
return true;
@@ -946,9 +969,11 @@ MidiRegionView::create_note_at (framepos_t t, double y, Evoral::Beats length, bo
view->update_note_range(new_note->note());
+ trackview.editor().begin_reversible_command(_("add note"));
MidiModel::NoteDiffCommand* cmd = _model->new_note_diff_command(_("add note"));
cmd->add (new_note);
_model->apply_command(*trackview.session(), cmd);
+ trackview.editor().commit_reversible_command();
play_midi_note (new_note);
}
@@ -982,8 +1007,8 @@ MidiRegionView::display_model(boost::shared_ptr<MidiModel> model)
content_connection.disconnect ();
_model->ContentsChanged.connect (content_connection, invalidator (*this), boost::bind (&MidiRegionView::redisplay_model, this), gui_context());
-
- clear_events ();
+ /* Don't signal as nobody else needs to know until selection has been altered.*/
+ clear_events (false);
if (_enable_display) {
redisplay_model();
@@ -994,6 +1019,7 @@ void
MidiRegionView::start_note_diff_command (string name)
{
if (!_note_diff_command) {
+ trackview.editor().begin_reversible_command (name);
_note_diff_command = _model->new_note_diff_command (name);
}
}
@@ -1044,6 +1070,7 @@ void
MidiRegionView::apply_diff (bool as_subcommand)
{
bool add_or_remove;
+ bool commit = false;
if (!_note_diff_command) {
return;
@@ -1060,6 +1087,7 @@ MidiRegionView::apply_diff (bool as_subcommand)
_model->apply_command_as_subcommand (*trackview.session(), _note_diff_command);
} else {
_model->apply_command (*trackview.session(), _note_diff_command);
+ commit = true;
}
_note_diff_command = 0;
@@ -1070,6 +1098,9 @@ MidiRegionView::apply_diff (bool as_subcommand)
}
_marked_for_velocity.clear();
+ if (commit) {
+ trackview.editor().commit_reversible_command ();
+ }
}
void
@@ -1100,6 +1131,27 @@ MidiRegionView::find_canvas_note (boost::shared_ptr<NoteType> note)
return 0;
}
+/** This version finds any canvas note matching the supplied note.*/
+NoteBase*
+MidiRegionView::find_canvas_note (NoteType note)
+{
+ if (_optimization_iterator != _events.end()) {
+ ++_optimization_iterator;
+ }
+
+ if (_optimization_iterator != _events.end() && (*(*_optimization_iterator)->note()) == note) {
+ return *_optimization_iterator;
+ }
+
+ for (_optimization_iterator = _events.begin(); _optimization_iterator != _events.end(); ++_optimization_iterator) {
+ if (*((*_optimization_iterator)->note()) == note) {
+ return *_optimization_iterator;
+ }
+ }
+
+ return 0;
+}
+
void
MidiRegionView::get_events (Events& e, Evoral::Sequence<Evoral::Beats>::NoteOperator op, uint8_t val, int chan_mask)
{
@@ -1173,6 +1225,13 @@ MidiRegionView::redisplay_model()
add_note (note, visible);
}
+ set<boost::shared_ptr<NoteType> >::iterator it;
+ for (it = _pending_note_selection.begin(); it != _pending_note_selection.end(); ++it) {
+ if (*(*it) == *note) {
+ add_to_selection (cne);
+ }
+ }
+
} else {
if (!empty_when_starting && (cne = find_canvas_note (note)) != 0) {
@@ -1182,7 +1241,6 @@ MidiRegionView::redisplay_model()
}
}
-
/* remove note items that are no longer valid */
if (!empty_when_starting) {
@@ -1213,6 +1271,7 @@ MidiRegionView::redisplay_model()
_marked_for_selection.clear ();
_marked_for_velocity.clear ();
+ _pending_note_selection.clear ();
/* we may have caused _events to contain things out of order (e.g. if a note
moved earlier or later). we don't generally need them in time order, but
@@ -1909,7 +1968,9 @@ MidiRegionView::get_patch_key_at (Evoral::Beats time, uint8_t channel, MIDI::Nam
void
MidiRegionView::change_patch_change (PatchChange& pc, const MIDI::Name::PatchPrimaryKey& new_patch)
{
- MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (_("alter patch change"));
+ string name = _("alter patch change");
+ trackview.editor().begin_reversible_command (name);
+ MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (name);
if (pc.patch()->program() != new_patch.program()) {
c->change_program (pc.patch (), new_patch.program());
@@ -1921,6 +1982,7 @@ MidiRegionView::change_patch_change (PatchChange& pc, const MIDI::Name::PatchPri
}
_model->apply_command (*trackview.session(), c);
+ trackview.editor().commit_reversible_command ();
_patch_changes.clear ();
display_patch_changes ();
@@ -1929,7 +1991,9 @@ MidiRegionView::change_patch_change (PatchChange& pc, const MIDI::Name::PatchPri
void
MidiRegionView::change_patch_change (MidiModel::PatchChangePtr old_change, const Evoral::PatchChange<Evoral::Beats> & new_change)
{
- MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (_("alter patch change"));
+ string name = _("alter patch change");
+ trackview.editor().begin_reversible_command (name);
+ MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (name);
if (old_change->time() != new_change.time()) {
c->change_time (old_change, new_change.time());
@@ -1948,6 +2012,7 @@ MidiRegionView::change_patch_change (MidiModel::PatchChangePtr old_change, const
}
_model->apply_command (*trackview.session(), c);
+ trackview.editor().commit_reversible_command ();
_patch_changes.clear ();
display_patch_changes ();
@@ -1962,8 +2027,10 @@ void
MidiRegionView::add_patch_change (framecnt_t t, Evoral::PatchChange<Evoral::Beats> const & patch)
{
MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
+ string name = _("add patch change");
- MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (_("add patch change"));
+ trackview.editor().begin_reversible_command (name);
+ MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (name);
c->add (MidiModel::PatchChangePtr (
new Evoral::PatchChange<Evoral::Beats> (
absolute_frames_to_source_beats (_region->position() + t),
@@ -1973,6 +2040,7 @@ MidiRegionView::add_patch_change (framecnt_t t, Evoral::PatchChange<Evoral::Beat
);
_model->apply_command (*trackview.session(), c);
+ trackview.editor().commit_reversible_command ();
_patch_changes.clear ();
display_patch_changes ();
@@ -1981,9 +2049,11 @@ MidiRegionView::add_patch_change (framecnt_t t, Evoral::PatchChange<Evoral::Beat
void
MidiRegionView::move_patch_change (PatchChange& pc, Evoral::Beats t)
{
+ trackview.editor().begin_reversible_command (_("move patch change"));
MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (_("move patch change"));
c->change_time (pc.patch (), t);
_model->apply_command (*trackview.session(), c);
+ trackview.editor().commit_reversible_command ();
_patch_changes.clear ();
display_patch_changes ();
@@ -1992,9 +2062,11 @@ MidiRegionView::move_patch_change (PatchChange& pc, Evoral::Beats t)
void
MidiRegionView::delete_patch_change (PatchChange* pc)
{
+ trackview.editor().begin_reversible_command (_("delete patch change"));
MidiModel::PatchChangeDiffCommand* c = _model->new_patch_change_diff_command (_("delete patch change"));
c->remove (pc->patch ());
_model->apply_command (*trackview.session(), c);
+ trackview.editor().commit_reversible_command ();
_patch_changes.clear ();
display_patch_changes ();
@@ -2143,6 +2215,24 @@ MidiRegionView::invert_selection ()
}
}
+/** Used for selection undo/redo.
+ The requested notes most likely won't exist in the view until the next model redisplay.
+*/
+void
+MidiRegionView::select_notes (list<boost::shared_ptr<NoteType> > notes)
+{
+ NoteBase* cne;
+ list<boost::shared_ptr<NoteType> >::iterator n;
+
+ for (n = notes.begin(); n != notes.end(); ++n) {
+ if ((cne = find_canvas_note(*(*n))) != 0) {
+ add_to_selection (cne);
+ } else {
+ _pending_note_selection.insert(*n);
+ }
+ }
+}
+
void
MidiRegionView::select_matching_notes (uint8_t notenum, uint16_t channel_mask, bool add, bool extend)
{
diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h
index 4f64e4410f..6ffdf98c25 100644
--- a/gtk2_ardour/midi_region_view.h
+++ b/gtk2_ardour/midi_region_view.h
@@ -203,6 +203,7 @@ public:
void move_selection(double dx, double dy, double cumulative_dy);
void note_dropped (NoteBase* ev, ARDOUR::frameoffset_t, int8_t d_note);
+ void select_notes (std::list<boost::shared_ptr<NoteType> >);
void select_matching_notes (uint8_t notenum, uint16_t channel_mask, bool add, bool extend);
void toggle_matching_notes (uint8_t notenum, uint16_t channel_mask);
@@ -438,6 +439,9 @@ private:
* when they appear after the command is applied. */
std::set< boost::shared_ptr<NoteType> > _marked_for_selection;
+ /** Notes that should be selected when the model is redisplayed. */
+ std::set< boost::shared_ptr<NoteType> > _pending_note_selection;
+
/** New notes (created in the current command) which should have visible velocity
* when they appear after the command is applied. */
std::set< boost::shared_ptr<NoteType> > _marked_for_velocity;
@@ -448,6 +452,7 @@ private:
PBD::ScopedConnection content_connection;
NoteBase* find_canvas_note (boost::shared_ptr<NoteType>);
+ NoteBase* find_canvas_note (NoteType);
Events::iterator _optimization_iterator;
void update_note (NoteBase*, bool update_ghost_regions = true);
@@ -499,6 +504,8 @@ private:
bool _grabbed_keyboard;
bool _entered;
+ bool _mouse_changed_selection;
+
framepos_t snap_frame_to_grid_underneath (framepos_t p, framecnt_t &) const;
PBD::ScopedConnection _mouse_mode_connection;
diff --git a/gtk2_ardour/midi_time_axis.cc b/gtk2_ardour/midi_time_axis.cc
index 5d8dc83bc1..33d192aa1c 100644
--- a/gtk2_ardour/midi_time_axis.cc
+++ b/gtk2_ardour/midi_time_axis.cc
@@ -1308,6 +1308,8 @@ MidiTimeAxisView::set_note_selection (uint8_t note)
{
uint16_t chn_mask = midi_track()->get_playback_channel_mask();
+ _editor.begin_reversible_selection_op(_("Set Note Selection"));
+
if (_view->num_selected_regionviews() == 0) {
_view->foreach_regionview (
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
@@ -1317,6 +1319,8 @@ MidiTimeAxisView::set_note_selection (uint8_t note)
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
note, chn_mask));
}
+
+ _editor.commit_reversible_selection_op();
}
void
@@ -1324,6 +1328,8 @@ MidiTimeAxisView::add_note_selection (uint8_t note)
{
const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
+ _editor.begin_reversible_selection_op(_("Add Note Selection"));
+
if (_view->num_selected_regionviews() == 0) {
_view->foreach_regionview (
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
@@ -1333,6 +1339,8 @@ MidiTimeAxisView::add_note_selection (uint8_t note)
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
note, chn_mask));
}
+
+ _editor.commit_reversible_selection_op();
}
void
@@ -1340,6 +1348,8 @@ MidiTimeAxisView::extend_note_selection (uint8_t note)
{
const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
+ _editor.begin_reversible_selection_op(_("Extend Note Selection"));
+
if (_view->num_selected_regionviews() == 0) {
_view->foreach_regionview (
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
@@ -1349,6 +1359,8 @@ MidiTimeAxisView::extend_note_selection (uint8_t note)
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
note, chn_mask));
}
+
+ _editor.commit_reversible_selection_op();
}
void
@@ -1356,6 +1368,8 @@ MidiTimeAxisView::toggle_note_selection (uint8_t note)
{
const uint16_t chn_mask = midi_track()->get_playback_channel_mask();
+ _editor.begin_reversible_selection_op(_("Toggle Note Selection"));
+
if (_view->num_selected_regionviews() == 0) {
_view->foreach_regionview (
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
@@ -1365,6 +1379,15 @@ MidiTimeAxisView::toggle_note_selection (uint8_t note)
sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
note, chn_mask));
}
+
+ _editor.commit_reversible_selection_op();
+}
+
+void
+MidiTimeAxisView::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >& selection)
+{
+ _view->foreach_regionview (
+ sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::get_per_region_note_selection_region_view), sigc::ref(selection)));
}
void
@@ -1392,6 +1415,24 @@ MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t not
}
void
+MidiTimeAxisView::get_per_region_note_selection_region_view (RegionView* rv, list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection)
+{
+ Evoral::Sequence<Evoral::Beats>::Notes selected;
+ dynamic_cast<MidiRegionView*>(rv)->selection_as_notelist (selected, false);
+
+ std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > notes;
+
+ Evoral::Sequence<Evoral::Beats>::Notes::iterator sel_it;
+ for (sel_it = selected.begin(); sel_it != selected.end(); ++sel_it) {
+ notes.insert (*sel_it);
+ }
+
+ if (!notes.empty()) {
+ selection.push_back (make_pair ((rv)->region()->id(), notes));
+ }
+}
+
+void
MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
{
/* hide all automation tracks that use the wrong channel(s) and show all those that use
diff --git a/gtk2_ardour/midi_time_axis.h b/gtk2_ardour/midi_time_axis.h
index 1897174e11..9963ac420c 100644
--- a/gtk2_ardour/midi_time_axis.h
+++ b/gtk2_ardour/midi_time_axis.h
@@ -30,6 +30,8 @@
#include <gtkmm2ext/selector.h>
#include <list>
+#include "evoral/Note.hpp"
+
#include "ardour/types.h"
#include "ardour/region.h"
@@ -65,7 +67,7 @@ class MidiChannelSelectorWindow;
class MidiTimeAxisView : public RouteTimeAxisView
{
- public:
+public:
MidiTimeAxisView (PublicEditor&, ARDOUR::Session*, ArdourCanvas::Canvas& canvas);
virtual ~MidiTimeAxisView ();
@@ -100,11 +102,13 @@ class MidiTimeAxisView : public RouteTimeAxisView
uint8_t get_channel_for_add () const;
- protected:
+ void get_per_region_note_selection (std::list<std::pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >&);
+
+protected:
void start_step_editing ();
void stop_step_editing ();
- private:
+private:
sigc::signal<void, std::string, std::string> _midi_patch_settings_changed;
void model_changed(const std::string& model);
@@ -165,6 +169,7 @@ class MidiTimeAxisView : public RouteTimeAxisView
void add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask);
void extend_note_selection_region_view (RegionView*, uint8_t note, uint16_t chn_mask);
void toggle_note_selection_region_view (RegionView*, uint8_t note, uint16_t chn_mask);
+ void get_per_region_note_selection_region_view (RegionView*, std::list<std::pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >&);
void ensure_step_editor ();
diff --git a/gtk2_ardour/public_editor.h b/gtk2_ardour/public_editor.h
index 69a3b13fcd..b7263756a6 100644
--- a/gtk2_ardour/public_editor.h
+++ b/gtk2_ardour/public_editor.h
@@ -34,6 +34,7 @@
#include <gtkmm/actiongroup.h>
#include <sigc++/signal.h>
+#include "evoral/Note.hpp"
#include "evoral/types.hpp"
#include "pbd/statefuldestructible.h"
@@ -391,6 +392,8 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulDestructible, publi
virtual void stop_canvas_autoscroll () = 0;
virtual bool autoscroll_active() const = 0;
+ virtual void begin_reversible_selection_op (std::string cmd_name) = 0;
+ virtual void commit_reversible_selection_op () = 0;
virtual void begin_reversible_command (std::string cmd_name) = 0;
virtual void begin_reversible_command (GQuark) = 0;
virtual void commit_reversible_command () = 0;
@@ -412,7 +415,8 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulDestructible, publi
virtual void get_regions_at (RegionSelection &, framepos_t where, TrackViewList const &) const = 0;
virtual RegionSelection get_regions_from_selection_and_mouse (framepos_t) = 0;
- virtual void get_regionviews_by_id (PBD::ID const & id, RegionSelection & regions) const = 0;
+ virtual void get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const = 0;
+ virtual void get_per_region_note_selection (std::list<std::pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >&) const = 0;
/// Singleton instance, set up by Editor::Editor()
diff --git a/gtk2_ardour/selection.cc b/gtk2_ardour/selection.cc
index 4a619e1b03..39ade0fadf 100644
--- a/gtk2_ardour/selection.cc
+++ b/gtk2_ardour/selection.cc
@@ -109,6 +109,7 @@ Selection::clear ()
clear_midi_notes ();
clear_midi_regions ();
clear_markers ();
+ pending_midi_note_selection.clear();
}
void
@@ -506,9 +507,9 @@ Selection::add (RegionView* r)
if (find (regions.begin(), regions.end(), r) == regions.end()) {
bool changed = regions.add (r);
- if (changed) {
- RegionsChanged ();
- }
+ if (changed) {
+ RegionsChanged ();
+ }
}
}
@@ -1229,12 +1230,45 @@ Selection::get_state () const
for (RegionSelection::const_iterator i = regions.begin(); i != regions.end(); ++i) {
XMLNode* r = node->add_child (X_("Region"));
r->add_property (X_("id"), atoi ((*i)->region ()->id ().to_s ().c_str()));
-
+ }
+
+ /* midi region views have thir own internal selection. */
+ XMLNode* n;
+ list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > rid_notes;
+ editor->get_per_region_note_selection (rid_notes);
+ if (!rid_notes.empty()) {
+ n = node->add_child (X_("MIDINote"));
+ }
+ list<pair<PBD::ID, std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rn_it;
+ for (rn_it = rid_notes.begin(); rn_it != rid_notes.end(); ++rn_it) {
+ n->add_property (X_("region_id"), atoi((*rn_it).first.to_s().c_str()));
+
+ for (std::set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > >::iterator i = (*rn_it).second.begin(); i != (*rn_it).second.end(); ++i) {
+ XMLNode* nc = n->add_child(X_("note"));
+ snprintf(buf, sizeof(buf), "%d", (*i)->channel());
+ nc->add_property(X_("channel"), string(buf));
+
+ snprintf(buf, sizeof(buf), "%f", (*i)->time().to_double());
+ nc->add_property(X_("time"), string(buf));
+
+ snprintf(buf, sizeof(buf), "%d", (*i)->note());
+ nc->add_property(X_("note"), string(buf));
+
+ snprintf(buf, sizeof(buf), "%f", (*i)->length().to_double());
+ nc->add_property(X_("length"), string(buf));
+
+ snprintf(buf, sizeof(buf), "%d", (*i)->velocity());
+ nc->add_property(X_("velocity"), string(buf));
+
+ snprintf(buf, sizeof(buf), "%d", (*i)->off_velocity());
+ nc->add_property(X_("off-velocity"), string(buf));
+ }
}
for (PointSelection::const_iterator i = points.begin(); i != points.end(); ++i) {
AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*> (&(*i)->line().trackview);
if (atv) {
+
XMLNode* r = node->add_child (X_("ControlPoint"));
r->add_property (X_("type"), "track");
r->add_property (X_("route-id"), atoi (atv->parent_route()->id ().to_s ().c_str()));
@@ -1243,6 +1277,7 @@ Selection::get_state () const
snprintf(buf, sizeof(buf), "%d", (*i)->view_index());
r->add_property (X_("view-index"), string(buf));
+
}
}
@@ -1304,44 +1339,106 @@ Selection::set_state (XMLNode const & node, int)
add (rs);
} else {
/*
- regionviews are being constructed - stash the region IDs
+ regionviews haven't been constructed - stash the region IDs
so we can identify them in Editor::region_view_added ()
*/
regions.pending.push_back (id);
}
+ } else if ((*i)->name() == X_("MIDINote")) {
+ XMLProperty* prop_region_id = (*i)->property (X_("region-id"));
+
+ assert (prop_region_id);
+
+ PBD::ID const id (prop_region_id->value ());
+ RegionSelection rs;
+
+ editor->get_regionviews_by_id (id, rs); // there could be more than one
+
+ std::list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > notes;
+ XMLNodeList children = (*i)->children ();
+
+ for (XMLNodeList::const_iterator ci = children.begin(); ci != children.end(); ++ci) {
+ XMLProperty* prop_channel = (*ci)->property (X_("channel"));
+ XMLProperty* prop_time = (*ci)->property (X_("time"));
+ XMLProperty* prop_note = (*ci)->property (X_("note"));
+ XMLProperty* prop_length = (*ci)->property (X_("length"));
+ XMLProperty* prop_velocity = (*ci)->property (X_("velocity"));
+ XMLProperty* prop_off_velocity = (*ci)->property (X_("off-velocity"));
+
+ assert (prop_channel);
+ assert (prop_time);
+ assert (prop_note);
+ assert (prop_length);
+ assert (prop_velocity);
+ assert (prop_off_velocity);
+
+ uint8_t channel = atoi(prop_channel->value());
+ Evoral::Beats time (atof(prop_time->value()));
+ Evoral::Beats length (atof(prop_length->value()));
+ uint8_t note = atoi(prop_note->value());
+ uint8_t velocity = atoi(prop_velocity->value());
+ uint8_t off_velocity = atoi(prop_off_velocity->value());
+ boost::shared_ptr<Evoral::Note<Evoral::Beats> > the_note
+ (new Evoral::Note<Evoral::Beats> (channel, time, length, note, velocity));
+ the_note->set_off_velocity (off_velocity);
+
+ notes.push_back (the_note);
+ }
+
+ for (RegionSelection::iterator rsi = rs.begin(); rsi != rs.end(); ++rsi) {
+ MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*rsi);
+ if (mrv) {
+ mrv->select_notes(notes);
+ }
+ }
+
+ if (rs.empty()) {
+ /* regionviews containing these notes don't yet exist on the canvas.*/
+ pending_midi_note_selection.push_back (make_pair (id, notes));
+ }
+
} else if ((*i)->name() == X_("ControlPoint")) {
XMLProperty* prop_type = (*i)->property (X_("type"));
- XMLProperty* prop_route_id = (*i)->property (X_("route-id"));
- XMLProperty* prop_alist_id = (*i)->property (X_("automation-list-id"));
- XMLProperty* prop_parameter = (*i)->property (X_("parameter"));
- XMLProperty* prop_view_index = (*i)->property (X_("view-index"));
-
- assert (prop_type);
- assert (prop_route_id);
- assert (prop_alist_id);
- assert (prop_parameter);
- assert (prop_view_index);
+
+ assert(prop_type);
if (prop_type->value () == "track") {
- PBD::ID id (prop_route_id->value ());
- RouteTimeAxisView* rtv = editor->get_route_view_by_route_id (id);
+
+ XMLProperty* prop_route_id = (*i)->property (X_("route-id"));
+ XMLProperty* prop_alist_id = (*i)->property (X_("automation-list-id"));
+ XMLProperty* prop_parameter = (*i)->property (X_("parameter"));
+ XMLProperty* prop_view_index = (*i)->property (X_("view-index"));
+
+ assert (prop_type);
+ assert (prop_route_id);
+ assert (prop_alist_id);
+ assert (prop_parameter);
+ assert (prop_view_index);
+
+ PBD::ID route_id (prop_route_id->value ());
+ RouteTimeAxisView* rtv = editor->get_route_view_by_route_id (route_id);
+ vector <ControlPoint *> cps;
if (rtv) {
boost::shared_ptr<AutomationTimeAxisView> atv = rtv->automation_child (EventTypeMap::instance().from_symbol (prop_parameter->value ()));
if (atv) {
list<boost::shared_ptr<AutomationLine> > lines = atv->lines();
- for (list<boost::shared_ptr<AutomationLine> > ::iterator i = lines.begin(); i != lines.end(); ++i) {
- if ((*i)->the_list()->id() == prop_alist_id->value()) {
- ControlPoint* cp = (*i)->nth(atol(prop_view_index->value().c_str()));
+ for (list<boost::shared_ptr<AutomationLine> > ::iterator li = lines.begin(); li != lines.end(); ++li) {
+ if ((*li)->the_list()->id() == prop_alist_id->value()) {
+ ControlPoint* cp = (*li)->nth(atol(prop_view_index->value().c_str()));
if (cp) {
- add (cp);
+ cps.push_back (cp);
+ cp->show();
}
}
}
}
}
- }
+ if (!cps.empty()) {
+ add (cps);
+ }
+ }
} else if ((*i)->name() == X_("AudioRange")) {
XMLProperty* prop_start = (*i)->property (X_("start"));
diff --git a/gtk2_ardour/selection.h b/gtk2_ardour/selection.h
index fe2be2e6e4..7585c0ae56 100644
--- a/gtk2_ardour/selection.h
+++ b/gtk2_ardour/selection.h
@@ -223,6 +223,8 @@ class Selection : public sigc::trackable, public PBD::ScopedConnectionList
PBD::Signal0<void> ClearMidiNoteSelection;
+ std::list<std::pair<PBD::ID const, std::list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > pending_midi_note_selection;
+
private:
PublicEditor const * editor;
uint32_t next_time_id;