Fix AutomationTrackItem rubberband click thinking it was unhandled.
authornick_m <mainsbridge@gmail.com>
Sat, 10 Jan 2015 17:07:31 +0000 (04:07 +1100)
committernick_m <mainsbridge@gmail.com>
Sat, 10 Jan 2015 17:07:31 +0000 (04:07 +1100)
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.

14 files changed:
gtk2_ardour/automation_line.cc
gtk2_ardour/editor.cc
gtk2_ardour/editor.h
gtk2_ardour/editor_canvas_events.cc
gtk2_ardour/editor_drag.cc
gtk2_ardour/editor_mouse.cc
gtk2_ardour/editor_selection.cc
gtk2_ardour/midi_region_view.cc
gtk2_ardour/midi_region_view.h
gtk2_ardour/midi_time_axis.cc
gtk2_ardour/midi_time_axis.h
gtk2_ardour/public_editor.h
gtk2_ardour/selection.cc
gtk2_ardour/selection.h

index c0ed14f7f955b01dac5044d8bb69452c4d203763..d5ed529ad882adca59efd0bfd8fb0746b0ea46e9 100644 (file)
@@ -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).
                */
index da1c25f374b53e84df84c04972483fc6a3b1a6ee..b18d6d6fb81fd17396a53f8c7eb112aff6e9c1f6 100644 (file)
@@ -80,7 +80,6 @@
 
 #include "control_protocol/control_protocol.h"
 
-#include "actions.h"
 #include "actions.h"
 #include "analysis_window.h"
 #include "audio_clock.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);
                                        }
                                }
                        }
@@ -4927,6 +4927,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)
 {
@@ -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 ();
 }
 
index 77d28f4e12bbea862c55644e5c5217ab8a901416..7e1d1702f0b26161d0b59eca9d3a7c97604df20f 100644 (file)
@@ -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 *);
 
index 93c0abea356bf2be94e2ae58f9525151e8b067f9..c1696c9f6cdada71cc2f0ec9814401e36ef48b23 100644 (file)
@@ -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;
 
index 9cf0f05b60e1b0c39fa1e3efa5fd5f18d94e6a23..aef59ed19ead573684c8e41cd53139688f735669 100644 (file)
@@ -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)
index e093eb5426ad54fda5a0f91bfa917d41c9ea7f93..b7818326185d5c240dbc2d1f244f30611b3c3acd 100644 (file)
@@ -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;
index 60f8b0433b9a21c03eecb12156b712ed201965bb..c46ef04a64331d47879d7cf40013158075c5067e 100644 (file)
@@ -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 ();
 }
index 97cb11529e64938aac281cf94fef012417efe963..6e257cc0ee24c6686a9860906334c277ad5700ec 100644 (file)
@@ -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)
 {
index 4f64e4410f2b3c0cfaaa41c5ca7e9ea97f361969..6ffdf98c25a464a49ea095dab4da29fd4df3b9d9 100644 (file)
@@ -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;
index 5d8dc83bc18db41a7516c0d79996e7ea3534313b..33d192aa1cc96105b38a3ba900cda3d34c046810 100644 (file)
@@ -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
@@ -1391,6 +1414,24 @@ MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t not
        dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
 }
 
+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)
 {
index 1897174e11512cb8315f3b8b3f8a4ea503170e55..9963ac420ced292a42b1c8023b2d22f6a1f363c3 100644 (file)
@@ -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 ();
 
index 69a3b13fcd3b86f6824a4b041eab87ce04fbce50..b7263756a6f44c40be8b240e2eff6920f67aa573 100644 (file)
@@ -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()
 
index 4a619e1b039e46904c7b4bfb70b459e0e9ab03dd..39ade0fadf69379243dc97b3385873b3c5e3859e 100644 (file)
@@ -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"));
index fe2be2e6e4fe0025c3698a5fa377cbfbe56e4f96..7585c0ae5685eb9b20a63191e09cbfd5a8d1227f 100644 (file)
@@ -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;