use CoreSelection for track selection
authorPaul Davis <paul@linuxaudiosystems.com>
Fri, 5 May 2017 11:31:49 +0000 (12:31 +0100)
committerPaul Davis <paul@linuxaudiosystems.com>
Fri, 5 May 2017 17:56:25 +0000 (18:56 +0100)
33 files changed:
gtk2_ardour/automation_time_axis.cc
gtk2_ardour/automation_time_axis.h
gtk2_ardour/axis_view.cc
gtk2_ardour/axis_view.h
gtk2_ardour/editor.cc
gtk2_ardour/editor.h
gtk2_ardour/editor_canvas_events.cc
gtk2_ardour/editor_drag.cc
gtk2_ardour/editor_mixer.cc
gtk2_ardour/editor_mouse.cc
gtk2_ardour/editor_routes.cc
gtk2_ardour/editor_routes.h
gtk2_ardour/editor_selection.cc
gtk2_ardour/mixer_ui.cc
gtk2_ardour/mixer_ui.h
gtk2_ardour/monitor_section.cc
gtk2_ardour/monitor_section.h
gtk2_ardour/monitor_selector.h
gtk2_ardour/port_group.cc
gtk2_ardour/processor_box.cc
gtk2_ardour/processor_box.h
gtk2_ardour/processor_selection.h
gtk2_ardour/public_editor.h
gtk2_ardour/route_params_ui.cc
gtk2_ardour/route_params_ui.h
gtk2_ardour/route_processor_selection.cc
gtk2_ardour/route_processor_selection.h
gtk2_ardour/selection.cc
gtk2_ardour/selection.h
gtk2_ardour/time_axis_view.cc
gtk2_ardour/track_selection.cc
gtk2_ardour/track_selection.h
gtk2_ardour/wscript

index 0b71e423cd98d8e2e95d736a9db9e4902557865d..3028fdaefd1b8bb55c3a75074a0ec1f1e5601cba 100644 (file)
@@ -1062,3 +1062,4 @@ AutomationTimeAxisView::color () const
 {
        return gdk_color_from_rgb (_route->presentation_info().color());
 }
+
index 4be1a4c4d21a6a0d3d23835ed016daabd2480871..c298ac325b9dadc7282bfb0bb7ecf3aeb406d2fc 100644 (file)
@@ -105,8 +105,8 @@ class AutomationTimeAxisView : public TimeAxisView {
        std::string state_id() const;
        static bool parse_state_id (std::string const &, PBD::ID &, bool &, Evoral::Parameter &);
 
-       boost::shared_ptr<ARDOUR::AutomationControl> control()    { return _control; }
-       boost::shared_ptr<AutomationController>      controller() { return _controller; }
+       boost::shared_ptr<ARDOUR::AutomationControl> control() const   { return _control; }
+       boost::shared_ptr<AutomationController>      controller() const { return _controller; }
        Evoral::Parameter parameter () const {
                return _parameter;
        }
index 3d25b35e173146a2f2668fd823544a332cef6a5c..632289bddffe68254493669c1f10e02b1dfeff2a 100644 (file)
 
 #include "pbd/error.h"
 #include "pbd/convert.h"
+#include "pbd/i18n.h"
 
 #include <gtkmm2ext/utils.h>
 #include <gtkmm2ext/selector.h>
 #include <gtkmm2ext/gtk_ui.h>
 
+#include "ardour/selection.h"
+
 #include "public_editor.h"
 #include "ardour_ui.h"
 #include "gui_object.h"
 #include "axis_view.h"
 #include "utils.h"
-#include "pbd/i18n.h"
 
 using namespace std;
 using namespace Gtk;
@@ -131,10 +133,4 @@ AxisView::set_selected (bool yn)
        }
 
        Selectable::set_selected (yn);
-
-       boost::shared_ptr<Stripable> s = stripable ();
-
-       if (s) {
-               s->presentation_info().set_selected (yn);
-       }
 }
index 81fe489252acfe788fda0ac554bfce772ee26eae..77518116a3b19a90285fb7e9c63a3c96544806ff 100644 (file)
 #include "prompter.h"
 #include "selectable.h"
 
+namespace PBD {
+       class Controllable;
+}
+
 namespace ARDOUR {
        class Session;
        class Stripable;
@@ -49,14 +53,13 @@ namespace ARDOUR {
 class AxisView : public virtual PBD::ScopedConnectionList, public virtual ARDOUR::SessionHandlePtr, public virtual Selectable
 {
   public:
-       ARDOUR::Session* session() const { return _session; }
-
        virtual std::string name() const = 0;
        virtual Gdk::Color color() const = 0;
 
        sigc::signal<void> Hiding;
 
        virtual boost::shared_ptr<ARDOUR::Stripable> stripable() const = 0;
+       virtual boost::shared_ptr<ARDOUR::AutomationControl> control() const { return boost::shared_ptr<ARDOUR::AutomationControl>(); }
 
        virtual std::string state_id() const = 0;
        /* for now, we always return properties in string form.
index 0d6eb334161e55a65deb3c0ab38c04e5569ec03a..7fe49de57b37ca864e7109eacf1f5f5612bcde98 100644 (file)
@@ -642,6 +642,8 @@ Editor::Editor ()
        bottom_hbox.set_border_width (2);
        bottom_hbox.set_spacing (3);
 
+       PresentationInfo::Change.connect (*this, MISSING_INVALIDATOR, boost::bind (&Editor::presentation_info_changed, this, _1), gui_context());
+
        _route_groups = new EditorRouteGroups (this);
        _routes = new EditorRoutes (this);
        _regions = new EditorRegions (this);
@@ -1038,7 +1040,7 @@ Editor::control_unselect ()
 void
 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
 {
-       TimeAxisView* tav = axis_view_from_stripable (s);
+       TimeAxisView* tav = time_axis_view_from_stripable (s);
 
        if (tav) {
                switch (op) {
@@ -1371,6 +1373,12 @@ Editor::set_session (Session *t)
        XMLNode* node = ARDOUR_UI::instance()->editor_settings();
        set_state (*node, Stateful::loading_state_version);
 
+       /* catch up on selection state, etc. */
+
+       PropertyChange sc;
+       sc.add (Properties::selected);
+       presentation_info_changed (sc);
+
        /* catch up with the playhead */
 
        _session->request_locate (playhead_cursor->current_frame ());
@@ -1431,25 +1439,6 @@ Editor::set_session (Session *t)
                break;
        }
 
-       /* catch up on selection of stripables (other selection state is lost
-        * when a session is closed
-        */
-
-       StripableList sl;
-       TrackViewList tl;
-       _session->get_stripables (sl);
-       for (StripableList::const_iterator s = sl.begin(); s != sl.end(); ++s) {
-               if ((*s)->presentation_info().selected()) {
-                       RouteTimeAxisView* rtav = get_route_view_by_route_id ((*s)->id());
-                       if (rtav) {
-                               tl.push_back (rtav);
-                       }
-               }
-       }
-       if (!tl.empty()) {
-               selection->set (tl);
-       }
-
        /* register for undo history */
        _session->register_with_memento_command_factory(id(), this);
        _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
@@ -5246,8 +5235,8 @@ Editor::region_view_removed ()
        _summary->set_background_dirty ();
 }
 
-TimeAxisView*
-Editor::axis_view_from_stripable (boost::shared_ptr<Stripable> s) const
+AxisView*
+Editor::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
 {
        for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
                if ((*j)->stripable() == s) {
@@ -5258,6 +5247,17 @@ Editor::axis_view_from_stripable (boost::shared_ptr<Stripable> s) const
        return 0;
 }
 
+AxisView*
+Editor::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
+{
+       for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
+               if ((*j)->control() == c) {
+                       return *j;
+               }
+       }
+
+       return 0;
+}
 
 TrackViewList
 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
@@ -5265,7 +5265,7 @@ Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
        TrackViewList t;
 
        for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
-               TimeAxisView* tv = axis_view_from_stripable (*i);
+               TimeAxisView* tv = time_axis_view_from_stripable (*i);
                if (tv) {
                        t.push_back (tv);
                }
index 868817bddd9f759eded73ca8770c7d83a6b38156..60bf93494d83e5f5d7f3e2f47ef737b78f9f7e8f 100644 (file)
@@ -140,14 +140,13 @@ class TimeSelection;
 class RegionLayeringOrderEditor;
 class VerboseCursor;
 
-class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARDOUR::SessionHandlePtr
+class Editor : public PublicEditor, public PBD::ScopedConnectionList
 {
 public:
        Editor ();
        ~Editor ();
 
        void             set_session (ARDOUR::Session *);
-       ARDOUR::Session* session() const { return _session; }
 
        Gtk::Window* use_own_window (bool and_fill_it);
 
@@ -427,7 +426,7 @@ public:
        void start_resize_line_ops ();
        void end_resize_line_ops ();
 
-       TrackViewList const & get_track_views () {
+       TrackViewList const & get_track_views () const {
                return track_views;
        }
 
@@ -1158,7 +1157,13 @@ private:
        /* track views */
        TrackViewList track_views;
        std::pair<TimeAxisView*, double> trackview_by_y_position (double, bool trackview_relative_offset = true) const;
-       TimeAxisView* axis_view_from_stripable (boost::shared_ptr<ARDOUR::Stripable>) const;
+
+       AxisView* axis_view_by_stripable (boost::shared_ptr<ARDOUR::Stripable>) const;
+       AxisView* axis_view_by_control (boost::shared_ptr<ARDOUR::AutomationControl>) const;
+
+       TimeAxisView* time_axis_view_from_stripable (boost::shared_ptr<ARDOUR::Stripable> s) const {
+               return dynamic_cast<TimeAxisView*> (axis_view_by_stripable (s));
+       }
 
        TrackViewList get_tracks_for_range_action () const;
 
@@ -1857,7 +1862,7 @@ private:
 
        void time_selection_changed ();
        void update_time_selection_display ();
-       void track_selection_changed ();
+       void presentation_info_changed (PBD::PropertyChange const &);
        void region_selection_changed ();
        sigc::connection editor_regions_selection_changed_connection;
        void sensitize_all_region_actions (bool);
index 132f6f870b931f0644a3b6644763c84a36d01e18..ad1cb8def85cc9fb41a3848ce01c778f4ae01ac1 100644 (file)
@@ -1295,7 +1295,7 @@ Editor::drop_regions (const Glib::RefPtr<Gdk::DragContext>& /*context*/,
                                }
                                list<boost::shared_ptr<AudioTrack> > audio_tracks;
                                audio_tracks = session()->new_audio_track (region->n_channels(), output_chan, 0, 1, region->name(), PresentationInfo::max_order);
-                               rtav = dynamic_cast<RouteTimeAxisView*> (axis_view_from_stripable (audio_tracks.front()));
+                               rtav = dynamic_cast<RouteTimeAxisView*> (time_axis_view_from_stripable (audio_tracks.front()));
                        } else if (boost::dynamic_pointer_cast<MidiRegion> (region)) {
                                ChanCount one_midi_port (DataType::MIDI, 1);
                                list<boost::shared_ptr<MidiTrack> > midi_tracks;
@@ -1304,7 +1304,7 @@ Editor::drop_regions (const Glib::RefPtr<Gdk::DragContext>& /*context*/,
                                                                         boost::shared_ptr<ARDOUR::PluginInfo>(),
                                                                         (ARDOUR::Plugin::PresetRecord*) 0,
                                                                         (ARDOUR::RouteGroup*) 0, 1, region->name(), PresentationInfo::max_order);
-                               rtav = dynamic_cast<RouteTimeAxisView*> (axis_view_from_stripable (midi_tracks.front()));
+                               rtav = dynamic_cast<RouteTimeAxisView*> (time_axis_view_from_stripable (midi_tracks.front()));
                        } else {
                                return;
                        }
index 35e9d395c54bade152c75fa91c3e08dbabc76197..90ef18f5b7b798ef9f7e052fee2b3ab2ff108a16 100644 (file)
@@ -1443,7 +1443,7 @@ RegionMoveDrag::create_destination_time_axis (boost::shared_ptr<Region> region,
                                output_chan =  _editor->session()->master_out()->n_inputs().n_audio();
                        }
                        audio_tracks = _editor->session()->new_audio_track (region->n_channels(), output_chan, 0, 1, region->name(), PresentationInfo::max_order);
-                       tav =_editor->axis_view_from_stripable (audio_tracks.front());
+                       tav =_editor->time_axis_view_from_stripable (audio_tracks.front());
                } else {
                        ChanCount one_midi_port (DataType::MIDI, 1);
                        list<boost::shared_ptr<MidiTrack> > midi_tracks;
@@ -1452,7 +1452,7 @@ RegionMoveDrag::create_destination_time_axis (boost::shared_ptr<Region> region,
                                                                          boost::shared_ptr<ARDOUR::PluginInfo>(),
                                                                          (ARDOUR::Plugin::PresetRecord*) 0,
                                                                          (ARDOUR::RouteGroup*) 0, 1, region->name(), PresentationInfo::max_order);
-                       tav = _editor->axis_view_from_stripable (midi_tracks.front());
+                       tav = _editor->time_axis_view_from_stripable (midi_tracks.front());
                }
 
                if (tav) {
index 840b2293cfc9863c2ea0144e7a99f6e32899bd33..00635367351ab262f54358d80ca87d5ef4e1d267 100644 (file)
@@ -146,7 +146,7 @@ Editor::show_editor_mixer (bool yn)
 
                if (current_mixer_strip && current_mixer_strip->get_parent() == 0) {
                        global_hpacker.pack_start (*current_mixer_strip, Gtk::PACK_SHRINK );
-                       global_hpacker.reorder_child (*current_mixer_strip, 0);
+                       global_hpacker.reorder_child (*current_mixer_strip, 0);
                        current_mixer_strip->show ();
                }
 
@@ -285,4 +285,3 @@ Editor::mixer_strip_width_changed ()
 
        editor_mixer_strip_width = current_mixer_strip->get_width_enum ();
 }
-
index 008f6094744607c0557fa448b028c1392307767d..2348ef7ba57dd40318b5ebbdbfff2ab920d0f0fa 100644 (file)
@@ -337,7 +337,6 @@ Editor::update_time_selection_display ()
                break;
        case MouseObject:
                selection->clear_time ();
-               selection->clear_tracks ();
                selection->clear_midi_notes ();
                break;
        case MouseDraw:
index 0d08c6ea87ae441e77d15ec6ec8cbb8f0b1e2184..059439befee7fe7ed120f14db530c06c7f5eb658 100644 (file)
@@ -31,6 +31,7 @@
 #include "ardour/audio_track.h"
 #include "ardour/midi_track.h"
 #include "ardour/route.h"
+#include "ardour/selection.h"
 #include "ardour/session.h"
 #include "ardour/solo_isolate_control.h"
 #include "ardour/utils.h"
@@ -319,7 +320,6 @@ EditorRoutes::EditorRoutes (Editor* e)
        _display.set_enable_search (false);
 
        Route::PluginSetup.connect_same_thread (*this, boost::bind (&EditorRoutes::plugin_setup, this, _1, _2, _3));
-       PresentationInfo::Change.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::presentation_info_changed, this, _1), gui_context());
 }
 
 bool
@@ -727,7 +727,10 @@ EditorRoutes::time_axis_views_added (list<TimeAxisView*> tavs)
                }
        }
 
-       _display.set_model (Glib::RefPtr<ListStore>());
+       {
+               PBD::Unwinder<bool> uw (_ignore_selection_change, true);
+               _display.set_model (Glib::RefPtr<ListStore>());
+       }
 
        for (list<TimeAxisView*>::iterator x = tavs.begin(); x != tavs.end(); ++x) {
 
@@ -754,7 +757,6 @@ EditorRoutes::time_axis_views_added (list<TimeAxisView*> tavs)
 
                        row[_columns.is_track] = (boost::dynamic_pointer_cast<Track> (stripable) != 0);
 
-
                        if (midi_trk) {
                                row[_columns.is_input_active] = midi_trk->input_active ();
                                row[_columns.is_midi] = true;
@@ -832,7 +834,11 @@ EditorRoutes::time_axis_views_added (list<TimeAxisView*> tavs)
        update_input_active_display ();
        update_active_display ();
 
-       _display.set_model (_model);
+       {
+               PBD::Unwinder<bool> uw (_ignore_selection_change, true);
+               cerr << "Should ignore model/selection change\n";
+               _display.set_model (_model);
+       }
 
        /* now update route order keys from the treeview/track display order */
 
@@ -1082,19 +1088,6 @@ EditorRoutes::sync_presentation_info_from_treeview ()
        }
 }
 
-void
-EditorRoutes::presentation_info_changed (PropertyChange const & what_changed)
-{
-       PropertyChange soh;
-       soh.add (Properties::selected);
-       soh.add (Properties::order);
-       soh.add (Properties::hidden);
-
-       if (what_changed.contains (soh)) {
-               sync_treeview_from_presentation_info (what_changed);
-       }
-}
-
 void
 EditorRoutes::sync_treeview_from_presentation_info (PropertyChange const & what_changed)
 {
@@ -1169,13 +1162,18 @@ EditorRoutes::sync_treeview_from_presentation_info (PropertyChange const & what_
 
        if (what_changed.contains (Properties::selected)) {
 
+               /* by the time this is invoked, the GUI Selection model has
+                * already updated itself.
+                */
+
                TrackViewList tvl;
                PBD::Unwinder<bool> uw (_ignore_selection_change, true);
 
-               /* step one: set the treeview model selection state */
+               /* set the treeview model selection state */
+
                for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri) {
                        boost::shared_ptr<Stripable> stripable = (*ri)[_columns.stripable];
-                       if (stripable && stripable->presentation_info().selected()) {
+                       if (stripable && stripable->is_selected()) {
                                TimeAxisView* tav = (*ri)[_columns.tv];
                                if (tav) {
                                        tvl.push_back (tav);
@@ -1185,12 +1183,6 @@ EditorRoutes::sync_treeview_from_presentation_info (PropertyChange const & what_
                                _display.get_selection()->unselect (*ri);
                        }
                }
-
-               /* step two: set the Selection (for stripables/routes) */
-               _editor->get_selection().set (tvl);
-
-               /* step three, tell the editor */
-               _editor->track_selection_changed ();
        }
 
        redisplay ();
@@ -1645,7 +1637,7 @@ EditorRoutes::move_selected_tracks (bool up)
        /* build a list that includes time axis view information */
 
        for (StripableList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
-               TimeAxisView* tv = _editor->axis_view_from_stripable (*sli);
+               TimeAxisView* tv = _editor->time_axis_view_from_stripable (*sli);
                view_stripables.push_back (ViewStripable (tv, *sli));
        }
 
@@ -1666,7 +1658,7 @@ EditorRoutes::move_selected_tracks (bool up)
 
                        while (vsi != view_stripables.end()) {
 
-                               if (vsi->stripable->presentation_info().selected()) {
+                               if (vsi->stripable->is_selected()) {
 
                                        if (unselected_neighbour != view_stripables.end()) {
 
@@ -1701,7 +1693,7 @@ EditorRoutes::move_selected_tracks (bool up)
 
                                --vsi;
 
-                               if (vsi->stripable->presentation_info().selected()) {
+                               if (vsi->stripable->is_selected()) {
 
                                        if (unselected_neighbour != view_stripables.end()) {
 
@@ -1852,6 +1844,7 @@ EditorRoutes::views () const
 void
 EditorRoutes::clear ()
 {
+       PBD::Unwinder<bool> uw (_ignore_selection_change, true);
        _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
        _model->clear ();
        _display.set_model (_model);
@@ -1902,7 +1895,7 @@ EditorRoutes::show_tracks_with_regions_at_playhead ()
 
        set<TimeAxisView*> show;
        for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
-               TimeAxisView* tav = _editor->axis_view_from_stripable (*i);
+               TimeAxisView* tav = _editor->time_axis_view_from_stripable (*i);
                if (tav) {
                        show.insert (tav);
                }
index a9d7115fdfa853727a35c6560c345d3be3b68dbe..2ceb6682b2e09e9ac94a033c0a66c4e8ad8be7b5 100644 (file)
@@ -65,6 +65,7 @@ public:
        void hide_all_tracks (bool);
        void clear ();
        void sync_presentation_info_from_treeview ();
+       void sync_treeview_from_presentation_info (PBD::PropertyChange const &);
 
 private:
        void initial_display ();
@@ -78,7 +79,6 @@ private:
        void on_tv_solo_safe_toggled (std::string const &);
        void build_menu ();
        void presentation_info_changed (PBD::PropertyChange const &);
-       void sync_treeview_from_presentation_info (PBD::PropertyChange const &);
        void row_deleted (Gtk::TreeModel::Path const &);
        void visible_changed (std::string const &);
        void active_changed (std::string const &);
index 770bfe9c1f220a0148e7fd60edcc6f337df21b31..c9e2ba49fdcc1f6f4d9c8aa3ac27aa043f6594e3 100644 (file)
 #include "ardour/playlist.h"
 #include "ardour/profile.h"
 #include "ardour/route_group.h"
+#include "ardour/selection.h"
 #include "ardour/session.h"
 
 #include "control_protocol/control_protocol.h"
 
-#include "editor_drag.h"
 #include "editor.h"
+#include "editor_drag.h"
+#include "editor_routes.h"
 #include "actions.h"
 #include "audio_time_axis.h"
 #include "audio_region_view.h"
@@ -267,9 +269,7 @@ Editor::set_selected_track (TimeAxisView& view, Selection::Operation op, bool no
                break;
 
        case Selection::Add:
-               if (!selection->selected (&view)) {
-                       selection->add (&view);
-               }
+               selection->add (&view);
                break;
 
        case Selection::Set:
@@ -999,84 +999,136 @@ struct SelectionOrderSorter {
 };
 
 void
-Editor::track_selection_changed ()
+Editor::presentation_info_changed (PropertyChange const & what_changed)
 {
-       SelectionOrderSorter cmp;
-       selection->tracks.sort (cmp);
+       /* We cannot ensure ordering of the handlers for
+        * PresentationInfo::Changed, so we have to do everything in order
+        * here, as a single handler.
+        */
 
-       switch (selection->tracks.size()) {
-       case 0:
-               break;
-       default:
-               set_selected_mixer_strip (*(selection->tracks.back()));
-               if (!_track_selection_change_without_scroll) {
-                       ensure_time_axis_view_is_visible (*(selection->tracks.back()), false);
-               }
-               break;
+       for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
+               (*i)->set_selected (false);
+               (*i)->hide_selection ();
        }
 
-       RouteNotificationListPtr routes (new RouteNotificationList);
-       StripableNotificationListPtr stripables (new StripableNotificationList);
+       /* STEP 1: set the GUI selection state (in which TimeAxisViews for the
+        * currently selected stripable/controllable duples are found and added
+        */
 
-       for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
+       selection->core_selection_changed (what_changed);
 
-               bool yn = (find (selection->tracks.begin(), selection->tracks.end(), *i) != selection->tracks.end());
+       /* STEP 2: update TimeAxisView's knowledge of their selected state
+        */
 
-               (*i)->set_selected (yn);
 
-               TimeAxisView::Children c = (*i)->get_child_list ();
-               for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
-                       (*j)->set_selected (find (selection->tracks.begin(), selection->tracks.end(), j->get()) != selection->tracks.end());
-               }
+       PropertyChange pc;
+       pc.add (Properties::selected);
 
-               if (yn) {
-                       (*i)->reshow_selection (selection->time);
-               } else {
-                       (*i)->hide_selection ();
-               }
+       if (what_changed.contains (Properties::selected)) {
 
+               StripableNotificationListPtr stripables (new StripableNotificationList);
 
-               if (yn) {
-                       RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*i);
-                       if (rtav) {
-                               routes->push_back (rtav->route());
-                               stripables->push_back (rtav->route());
+               switch (selection->tracks.size()) {
+               case 0:
+                       break;
+               default:
+                       set_selected_mixer_strip (*(selection->tracks.back()));
+                       if (!_track_selection_change_without_scroll) {
+                               ensure_time_axis_view_is_visible (*(selection->tracks.back()), false);
                        }
+                       break;
                }
-       }
 
-       ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, !selection->tracks.empty());
+               CoreSelection::StripableAutomationControls sc;
+               _session->selection().get_stripables (sc);
 
-       sensitize_the_right_region_actions (false);
+               for (CoreSelection::StripableAutomationControls::const_iterator i = sc.begin(); i != sc.end(); ++i) {
 
-       /* notify control protocols */
+                       AxisView* av = axis_view_by_stripable ((*i).stripable);
 
-       ControlProtocol::StripableSelectionChanged (stripables);
+                       if (!av) {
+                               continue;
+                       }
 
-       if (sfbrowser && _session && !_session->deletion_in_progress()) {
-               uint32_t audio_track_cnt = 0;
-               uint32_t midi_track_cnt = 0;
+                       TimeAxisView* tav = dynamic_cast<TimeAxisView*> (av);
 
-               for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
-                       AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*x);
+                       if (!tav) {
+                               continue; /* impossible */
+                       }
 
-                       if (atv) {
-                               if (atv->is_audio_track()) {
-                                       audio_track_cnt++;
-                               }
+                       if (!(*i).controllable) {
+
+                               /* "parent" track selected */
+                               tav->set_selected (true);
+                               tav->reshow_selection (selection->time);
 
                        } else {
-                               MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*>(*x);
 
-                               if (mtv) {
-                                       if (mtv->is_midi_track()) {
-                                               midi_track_cnt++;
+                               /* possibly a child */
+
+                               TimeAxisView::Children c = tav->get_child_list ();
+
+                               for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
+
+                                       boost::shared_ptr<AutomationControl> control = (*j)->control ();
+
+                                       if (control != (*i).controllable) {
+                                               continue;
                                        }
+
+                                       (*j)->set_selected (true);
+                                       (*j)->reshow_selection (selection->time);
                                }
                        }
+
+                       stripables->push_back ((*i).stripable);
+               }
+
+               ActionManager::set_sensitive (ActionManager::track_selection_sensitive_actions, !selection->tracks.empty());
+
+               sensitize_the_right_region_actions (false);
+
+               /* STEP 4: notify control protocols */
+
+               ControlProtocol::StripableSelectionChanged (stripables);
+
+               if (sfbrowser && _session && !_session->deletion_in_progress()) {
+                       uint32_t audio_track_cnt = 0;
+                       uint32_t midi_track_cnt = 0;
+
+                       for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
+                               AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*>(*x);
+
+                               if (atv) {
+                                       if (atv->is_audio_track()) {
+                                               audio_track_cnt++;
+                                       }
+
+                               } else {
+                                       MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*>(*x);
+
+                                       if (mtv) {
+                                               if (mtv->is_midi_track()) {
+                                                       midi_track_cnt++;
+                                               }
+                                       }
+                               }
+                       }
+
+                       sfbrowser->reset (audio_track_cnt, midi_track_cnt);
                }
+       }
 
-               sfbrowser->reset (audio_track_cnt, midi_track_cnt);
+       /* STEP 4: update EditorRoutes treeview */
+
+       PropertyChange soh;
+
+       soh.add (Properties::selected);
+       soh.add (Properties::order);
+       soh.add (Properties::hidden);
+
+       if (what_changed.contains (soh)) {
+               _routes->sync_treeview_from_presentation_info (what_changed);
        }
 }
 
@@ -1570,28 +1622,32 @@ Editor::select_all_objects (Selection::Operation op)
 {
        list<Selectable *> touched;
 
-       TrackViewList ts  = track_views;
-
        if (internal_editing() && select_all_internal_edit(op)) {
                return;  // Selected notes
        }
 
+       TrackViewList ts;
+
+       if (selection->tracks.empty()) {
+               ts = track_views;
+       } else {
+               ts = selection->tracks;
+       }
+
        for (TrackViewList::iterator iter = ts.begin(); iter != ts.end(); ++iter) {
                if ((*iter)->hidden()) {
                        continue;
                }
                (*iter)->get_selectables (0, max_framepos, 0, DBL_MAX, touched);
-               selection->add (*iter);
        }
 
-
        begin_reversible_selection_op (X_("select all"));
        switch (op) {
        case Selection::Add:
                selection->add (touched);
                break;
        case Selection::Toggle:
-               selection->add (touched);
+               selection->toggle (touched);
                break;
        case Selection::Set:
                selection->set (touched);
index 4c5d60d6c753c27479b2a7efe9df713f6c8ae532..b70ceef37db5e21be034c4e94717c9a6836c97a5 100644 (file)
@@ -48,6 +48,7 @@
 #include "ardour/midi_track.h"
 #include "ardour/plugin_manager.h"
 #include "ardour/route_group.h"
+#include "ardour/selection.h"
 #include "ardour/session.h"
 #include "ardour/vca.h"
 #include "ardour/vca_manager.h"
@@ -110,6 +111,7 @@ Mixer_UI::Mixer_UI ()
        , _maximised (false)
        , _show_mixer_list (true)
        , myactions (X_("mixer"))
+       , _selection (*this, *this)
 {
        register_actions ();
        load_bindings ();
@@ -683,6 +685,8 @@ Mixer_UI::remove_strip (MixerStrip* strip)
 void
 Mixer_UI::presentation_info_changed (PropertyChange const & what_changed)
 {
+       _selection.presentation_info_changed (what_changed);
+
        PropertyChange soh;
        soh.add (Properties::selected);
        soh.add (Properties::order);
@@ -850,7 +854,7 @@ Mixer_UI::sync_treeview_from_presentation_info (PropertyChange const & what_chan
 
                for (list<MixerStrip *>::const_iterator i = strips.begin(); i != strips.end(); ++i) {
                        boost::shared_ptr<Stripable> stripable = (*i)->stripable();
-                       if (stripable && stripable->presentation_info().selected()) {
+                       if (stripable && stripable->is_selected()) {
                                _selection.add (*i);
                        } else {
                                _selection.remove (*i);
@@ -891,7 +895,7 @@ Mixer_UI::strip_by_stripable (boost::shared_ptr<Stripable> s) const
 }
 
 AxisView*
-Mixer_UI::axis_by_stripable (boost::shared_ptr<Stripable> s) const
+Mixer_UI::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
 {
        for (list<MixerStrip *>::const_iterator i = strips.begin(); i != strips.end(); ++i) {
                if ((*i)->stripable() == s) {
@@ -902,6 +906,18 @@ Mixer_UI::axis_by_stripable (boost::shared_ptr<Stripable> s) const
        return 0;
 }
 
+AxisView*
+Mixer_UI::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
+{
+       for (list<MixerStrip *>::const_iterator i = strips.begin(); i != strips.end(); ++i) {
+               if ((*i)->control() == c) {
+                       return (*i);
+               }
+       }
+
+       return 0;
+}
+
 bool
 Mixer_UI::strip_button_release_event (GdkEventButton *ev, MixerStrip *strip)
 {
@@ -1000,6 +1016,7 @@ Mixer_UI::set_session (Session* sess)
        }
 
        if (!_session) {
+               _selection.clear ();
                return;
        }
 
@@ -1029,6 +1046,13 @@ Mixer_UI::set_session (Session* sess)
        if (_visible) {
                show_window();
        }
+
+       /* catch up on selection state, etc. */
+
+       PropertyChange sc;
+       sc.add (Properties::selected);
+       _selection.presentation_info_changed (sc);
+
        start_updating ();
 }
 
index 413c8be72702e45ae921d6eb5285f099a5393b93..4e2bda711b4fc82ef5c5b532322164d036fc366d 100644 (file)
@@ -47,6 +47,7 @@
 #include "gtkmm2ext/tabbable.h"
 #include "gtkmm2ext/treeutils.h"
 
+#include "axis_provider.h"
 #include "enums.h"
 #include "route_processor_selection.h"
 
@@ -76,7 +77,7 @@ protected:
        virtual bool row_drop_possible_vfunc (const Gtk::TreeModel::Path&, const Gtk::SelectionData&) const;
 };
 
-class Mixer_UI : public Gtkmm2ext::Tabbable, public PBD::ScopedConnectionList, public ARDOUR::SessionHandlePtr
+class Mixer_UI : public Gtkmm2ext::Tabbable, public PBD::ScopedConnectionList, public ARDOUR::SessionHandlePtr, public AxisViewProvider
 {
   public:
        static Mixer_UI* instance();
@@ -188,7 +189,9 @@ class Mixer_UI : public Gtkmm2ext::Tabbable, public PBD::ScopedConnectionList, p
 
        MixerStrip* strip_by_route (boost::shared_ptr<ARDOUR::Route>) const;
        MixerStrip* strip_by_stripable (boost::shared_ptr<ARDOUR::Stripable>) const;
-       AxisView* axis_by_stripable (boost::shared_ptr<ARDOUR::Stripable>) const;
+
+       AxisView* axis_view_by_stripable (boost::shared_ptr<ARDOUR::Stripable>) const;
+       AxisView* axis_view_by_control (boost::shared_ptr<ARDOUR::AutomationControl>) const;
 
        void hide_all_strips (bool with_select);
        void unselect_all_strips();
index de1d9504c02fec9c1089b033c0497a6d90769af7..2cd46c051a41a39e549eccb771790be68a7025b5 100644 (file)
@@ -88,6 +88,7 @@ MonitorSection::MonitorSection (Session* s)
        , solo_mute_override_button (ArdourButton::led_default_elements)
        , toggle_processorbox_button (ArdourButton::default_elements)
        , _inhibit_solo_model_update (false)
+       , _rr_selection ()
        , _ui_initialized (false)
 {
 
index b58203f52164148859183564d5ef8947be9ea443..61f4480c2fc799d12abe56ea61a8c244739e916e 100644 (file)
@@ -32,8 +32,8 @@
 #include "monitor_selector.h"
 
 #include "plugin_selector.h"
-#include "route_processor_selection.h"
 #include "processor_box.h"
+#include "processor_selection.h"
 
 namespace Gtkmm2ext {
        class TearOff;
@@ -192,7 +192,7 @@ class MonitorSection : public RouteUI, public Gtk::EventBox
 
        ProcessorBox* insert_box;
        PluginSelector* _plugin_selector;
-       RouteProcessorSelection _rr_selection;
+       ProcessorSelection _rr_selection;
        void help_count_processors (boost::weak_ptr<ARDOUR::Processor> p, uint32_t* cnt) const;
        uint32_t count_processors ();
 
index 8c642b5dfe26e5720c9903f63a13c7b2368c74e2..8e572e958c643195e50404ab31633fc92fc4292e 100644 (file)
@@ -34,8 +34,6 @@ class MonitorSelector : public PortMatrix
        std::string disassociation_verb () const;
        std::string channel_noun () const;
 
-        ARDOUR::Session* session() const { return _session; }
-
        uint32_t n_io_ports () const;
        boost::shared_ptr<ARDOUR::IO> const io () { return _io; }
        void setup_ports (int);
index 7439fe1b772509e954b916752f816595cab6a14f..5db8585a83bc76ba34dd71b66b7d33935b9d9a8a 100644 (file)
@@ -378,7 +378,7 @@ PortGroupList::gather (ARDOUR::Session* session, ARDOUR::DataType type, bool inp
        /* Now put the bundles that belong to these sorted RouteIOs into the PortGroup. */
 
        for (list<RouteIOs>::iterator i = route_ios.begin(); i != route_ios.end(); ++i) {
-               TimeAxisView* tv = PublicEditor::instance().axis_view_from_stripable (i->route);
+               TimeAxisView* tv = PublicEditor::instance().time_axis_view_from_stripable (i->route);
 
                /* Work out which group to put these IOs' bundles in */
                boost::shared_ptr<PortGroup> g;
index 37645f01852c2ec78beeee38997c5d067c8000ab..34bcbf28b5fe550b38f72da8e3d4c4d52b58e915 100644 (file)
@@ -76,9 +76,9 @@
 #include "plugin_ui.h"
 #include "port_insert_ui.h"
 #include "processor_box.h"
+#include "processor_selection.h"
 #include "public_editor.h"
 #include "return_ui.h"
-#include "route_processor_selection.h"
 #include "script_selector.h"
 #include "send_ui.h"
 #include "timers.h"
@@ -1807,14 +1807,14 @@ static std::list<Gtk::TargetEntry> drag_targets_noplugin()
 }
 
 ProcessorBox::ProcessorBox (ARDOUR::Session* sess, boost::function<PluginSelector*()> get_plugin_selector,
-                           RouteProcessorSelection& rsel, MixerStrip* parent, bool owner_is_mixer)
+                           ProcessorSelection& psel, MixerStrip* parent, bool owner_is_mixer)
        : _parent_strip (parent)
        , _owner_is_mixer (owner_is_mixer)
        , ab_direction (true)
        , _get_plugin_selector (get_plugin_selector)
        , _placement (-1)
        , _visible_prefader_processors (0)
-       , _rr_selection(rsel)
+       , _p_selection(psel)
        , processor_display (drop_targets())
        , _redisplay_pending (false)
 {
@@ -2200,7 +2200,7 @@ ProcessorBox::show_processor_menu (int arg)
 
        const bool sensitive = !processor_display.selection().empty() && ! stub_processor_selected ();
 
-       paste_action->set_sensitive (!_rr_selection.processors.empty());
+       paste_action->set_sensitive (!_p_selection.processors.empty());
        cut_action->set_sensitive (sensitive && can_cut ());
        copy_action->set_sensitive (sensitive);
        delete_action->set_sensitive (sensitive || stub_processor_selected ());
@@ -3165,7 +3165,7 @@ ProcessorBox::cut_processors (const ProcSelection& to_be_removed)
                return;
        }
 
-       _rr_selection.set (node);
+       _p_selection.set (node);
 
        no_processor_redisplay = false;
        redisplay_processors ();
@@ -3189,7 +3189,7 @@ ProcessorBox::copy_processors (const ProcSelection& to_be_copied)
                }
        }
 
-       _rr_selection.set (node);
+       _p_selection.set (node);
 }
 
 void
@@ -3304,22 +3304,22 @@ ProcessorBox::rename_processor (boost::shared_ptr<Processor> processor)
 void
 ProcessorBox::paste_processors ()
 {
-       if (_rr_selection.processors.empty()) {
+       if (_p_selection.processors.empty()) {
                return;
        }
 
-       paste_processor_state (_rr_selection.processors.get_node().children(), boost::shared_ptr<Processor>());
+       paste_processor_state (_p_selection.processors.get_node().children(), boost::shared_ptr<Processor>());
 }
 
 void
 ProcessorBox::paste_processors (boost::shared_ptr<Processor> before)
 {
 
-       if (_rr_selection.processors.empty()) {
+       if (_p_selection.processors.empty()) {
                return;
        }
 
-       paste_processor_state (_rr_selection.processors.get_node().children(), before);
+       paste_processor_state (_p_selection.processors.get_node().children(), before);
 }
 
 void
index 330a920e87bc4eec49a7dd6be134083ae555cd5a..5e73afa45cf3c1e3850237d16aac9771db4255ce 100644 (file)
@@ -62,7 +62,7 @@
 class MotionController;
 class PluginSelector;
 class PluginUIWindow;
-class RouteProcessorSelection;
+class ProcessorSelection;
 class MixerStrip;
 
 namespace ARDOUR {
@@ -414,7 +414,7 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject, public ARD
        };
 
        ProcessorBox (ARDOUR::Session*, boost::function<PluginSelector*()> get_plugin_selector,
-                     RouteProcessorSelection&, MixerStrip* parent, bool owner_is_mixer = false);
+                     ProcessorSelection&, MixerStrip* parent, bool owner_is_mixer = false);
        ~ProcessorBox ();
 
        void set_route (boost::shared_ptr<ARDOUR::Route>);
@@ -490,7 +490,7 @@ class ProcessorBox : public Gtk::HBox, public PluginInterestedObject, public ARD
        int _placement;
        uint32_t                  _visible_prefader_processors;
 
-       RouteProcessorSelection& _rr_selection;
+       ProcessorSelection& _p_selection;
        static Gtkmm2ext::ActionMap myactions;
 
        static void load_bindings ();
index d371493b416e0988fc9ac6b2885dd21c59f5fa4b..fc3a133ef1ff993dd03eef3067dfdedfca616402 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2000-2007 Paul Davis
+    Copyright (C) 2004 Paul Davis
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
 #ifndef __ardour_gtk_processor_selection_h__
 #define __ardour_gtk_processor_selection_h__
 
+#include <vector>
+
+#include "pbd/signals.h"
 #include "pbd/xml++.h"
 
-class ProcessorSelection {
+class XMLProcessorSelection {
   public:
-    ProcessorSelection() : node (0) {}
-    ~ProcessorSelection() { if (node) { delete node; } }
-
-    void set (XMLNode* n) {
-           if (node) {
-                   delete node;
-           }
-           node = n;
-    }
-
-    void add (XMLNode* newchild) {
-           if (!node) {
-                   node = new XMLNode ("add");
-           }
-           node->add_child_nocopy (*newchild);
-    }
-
-    void clear () {
-           if (node) {
-                   delete node;
-                   node = 0;
-           }
-    }
-
-    bool empty () const { return node == 0 || node->children().empty(); }
-
-    const XMLNode& get_node() const { return *node; }
+       XMLProcessorSelection() : node (0) {}
+       ~XMLProcessorSelection() { if (node) { delete node; } }
+
+       void set (XMLNode* n) {
+               if (node) {
+                       delete node;
+               }
+               node = n;
+       }
+
+       void add (XMLNode* newchild) {
+               if (!node) {
+                       node = new XMLNode ("add");
+               }
+               node->add_child_nocopy (*newchild);
+       }
+
+       void clear () {
+               if (node) {
+                       delete node;
+                       node = 0;
+               }
+       }
+
+       bool empty () const { return node == 0 || node->children().empty(); }
+
+       const XMLNode& get_node() const { return *node; }
 
   private:
-    XMLNode* node;
+       XMLNode* node;
 };
 
+class ProcessorSelection : public PBD::ScopedConnectionList, public sigc::trackable
+{
+  public:
+       ProcessorSelection () {}
+
+       XMLProcessorSelection processors;
+       sigc::signal<void> ProcessorsChanged;
+
+       ProcessorSelection& operator= (const ProcessorSelection& other);
+
+       void clear ();
+       bool empty();
+
+       void set (XMLNode* node);
+       void add (XMLNode* node);
+
+       void clear_processors ();
+};
+
+bool operator==(const ProcessorSelection& a, const ProcessorSelection& b);
+
 #endif /* __ardour_gtk_processor_selection_h__ */
index ea7980fb7b9d4d01d684906c3da80b996e77c6e9..f0ed177500a125075e10ffbdc4cb22ce02ccd388 100644 (file)
@@ -40,6 +40,8 @@
 
 #include "pbd/statefuldestructible.h"
 
+#include "ardour/session_handle.h"
+
 #include "canvas/fwd.h"
 
 #include "gtkmm2ext/actions.h"
@@ -47,6 +49,7 @@
 #include "gtkmm2ext/tabbable.h"
 #include "gtkmm2ext/visibility_tracker.h"
 
+#include "axis_provider.h"
 #include "editing.h"
 #include "selection.h"
 
@@ -105,8 +108,8 @@ using ARDOUR::framecnt_t;
  * of PublicEditor need not be recompiled if private methods or member variables
  * change.
  */
-class PublicEditor : public Gtkmm2ext::Tabbable {
-public:
+class PublicEditor : public Gtkmm2ext::Tabbable,  public ARDOUR::SessionHandlePtr, public AxisViewProvider {
+  public:
        PublicEditor (Gtk::Widget& content);
        virtual ~PublicEditor ();
 
@@ -123,9 +126,6 @@ public:
         */
        virtual void set_session (ARDOUR::Session* s) = 0;
 
-       /** @return The Session that we are editing, or 0 */
-       virtual ARDOUR::Session* session () const = 0;
-
        /** Set the snap type.
         * @param t Snap type (defined in editing_syms.h)
         */
@@ -353,6 +353,8 @@ public:
 
        virtual RouteTimeAxisView* get_route_view_by_route_id (const PBD::ID& id) const = 0;
 
+       virtual TimeAxisView* time_axis_view_from_stripable (boost::shared_ptr<ARDOUR::Stripable> s) const = 0;
+
        virtual void get_equivalent_regions (RegionView* rv, std::vector<RegionView*>&, PBD::PropertyID) const = 0;
        virtual RegionView* regionview_from_region (boost::shared_ptr<ARDOUR::Region>) const = 0;
        virtual RouteTimeAxisView* rtav_from_route (boost::shared_ptr<ARDOUR::Route>) const = 0;
@@ -422,15 +424,13 @@ public:
 
        virtual ArdourCanvas::GtkCanvasViewport* get_track_canvas() const = 0;
 
-       virtual TimeAxisView* axis_view_from_stripable (boost::shared_ptr<ARDOUR::Stripable>) const = 0;
-
        virtual void set_current_trimmable (boost::shared_ptr<ARDOUR::Trimmable>) = 0;
        virtual void set_current_movable (boost::shared_ptr<ARDOUR::Movable>) = 0;
 
        virtual void center_screen (framepos_t) = 0;
 
        virtual TrackViewList axis_views_from_routes (boost::shared_ptr<ARDOUR::RouteList>) const = 0;
-       virtual TrackViewList const & get_track_views () = 0;
+       virtual TrackViewList const & get_track_views () const = 0;
 
        virtual DragManager* drags () const = 0;
        virtual void maybe_autoscroll (bool, bool, bool from_headers) = 0;
index a8ddc02c1f9bef62c8560dae48620861d670f369..b377c838db618880ff298fda5b8a8da6a5d33cac 100644 (file)
@@ -56,9 +56,9 @@ using namespace Gtk;
 using namespace Gtkmm2ext;
 
 RouteParams_UI::RouteParams_UI ()
-       : ArdourWindow (_("Tracks and Busses")),
-         latency_apply_button (Stock::APPLY),
-         track_menu(0)
+       : ArdourWindow (_("Tracks and Busses"))
+       , latency_apply_button (Stock::APPLY)
+       , track_menu(0)
 {
        insert_box = 0;
        _input_iosel = 0;
@@ -235,7 +235,7 @@ RouteParams_UI::setup_processor_boxes()
                cleanup_processor_boxes();
 
                // construct new redirect boxes
-               insert_box = new ProcessorBox (_session, boost::bind (&RouteParams_UI::plugin_selector, this), _rr_selection, 0);
+               insert_box = new ProcessorBox (_session, boost::bind (&RouteParams_UI::plugin_selector, this), _p_selection, 0);
                insert_box->set_route (_route);
 
                boost::shared_ptr<AudioTrack> at = boost::dynamic_pointer_cast<AudioTrack>(_route);
index 83ddf27110f937275159bd926b57745233279c7b..2f04590c2b2e231e1a650c2c8287147ccd2f6774 100644 (file)
@@ -40,7 +40,7 @@
 
 #include "ardour_window.h"
 #include "processor_box.h"
-#include "route_processor_selection.h"
+#include "processor_selection.h"
 #include "latency_gui.h"
 
 namespace ARDOUR {
@@ -113,7 +113,7 @@ class RouteParams_UI : public ArdourWindow, public PBD::ScopedConnectionList
        IOSelector     * _output_iosel;
 
        PluginSelector    *_plugin_selector;
-       RouteProcessorSelection  _rr_selection;
+       ProcessorSelection  _p_selection;
 
        boost::shared_ptr<ARDOUR::Route> _route;
        PBD::ScopedConnection _route_processors_connection;
index 5b0b48c4ba04f1453d72bd3323eb5f072f868e40..0dc15e7f8a2b17a1d66013d4889d35ca10bc594a 100644 (file)
 
 #include <algorithm>
 #include <sigc++/bind.h>
+
 #include "pbd/error.h"
+#include "pbd/i18n.h"
 
+#include "ardour/selection.h"
+#include "ardour/session.h"
+#include "ardour/session_handle.h"
+
+#include "axis_provider.h"
 #include "gui_thread.h"
 #include "mixer_strip.h"
+#include "mixer_ui.h"
 #include "route_processor_selection.h"
 #include "route_ui.h"
 
-#include "pbd/i18n.h"
-
 using namespace std;
 using namespace ARDOUR;
 using namespace PBD;
 
-
-RouteProcessorSelection::RouteProcessorSelection()
+RouteProcessorSelection::RouteProcessorSelection (SessionHandlePtr& s, AxisViewProvider& ap)
+       : shp (s), avp (ap)
 {
 }
 
@@ -41,7 +47,7 @@ RouteProcessorSelection&
 RouteProcessorSelection::operator= (const RouteProcessorSelection& other)
 {
        if (&other != this) {
-               processors = other.processors;
+               (*((ProcessorSelection*) this)) = (*((ProcessorSelection const *) &other));
                axes = other.axes;
        }
        return *this;
@@ -62,46 +68,57 @@ RouteProcessorSelection::clear ()
 }
 
 void
-RouteProcessorSelection::clear_processors ()
+RouteProcessorSelection::clear_routes ()
 {
-       processors.clear ();
-       ProcessorsChanged ();
+       if (shp.session()) {
+               PresentationInfo::ChangeSuspender cs;
+               shp.session()->selection().clear_stripables ();
+       }
 }
 
 void
-RouteProcessorSelection::clear_routes ()
+RouteProcessorSelection::presentation_info_changed (PropertyChange const & what_changed)
 {
-       PresentationInfo::ChangeSuspender cs;
+       Session* s = shp.session();
 
-       for (AxisViewSelection::iterator i = axes.begin(); i != axes.end(); ++i) {
-               (*i)->set_selected (false);
+       if (!s) {
+               /* too early ... session handle provider doesn't know about the
+                  session yet.
+               */
+               return;
        }
-       axes.clear ();
-       drop_connections ();
-}
 
-void
-RouteProcessorSelection::add (XMLNode* node)
-{
-       // XXX check for duplicate
-       processors.add (node);
-       ProcessorsChanged();
-}
+       PropertyChange pc;
+       pc.add (Properties::selected);
 
-void
-RouteProcessorSelection::set (XMLNode* node)
-{
-       clear_processors ();
-       processors.set (node);
-       ProcessorsChanged ();
+       CoreSelection::StripableAutomationControls sc;
+       s->selection().get_stripables (sc);
+
+       for (AxisViewSelection::iterator a = axes.begin(); a != axes.end(); ++a) {
+               (*a)->set_selected (false);
+       }
+
+       axes.clear ();
+
+       for (CoreSelection::StripableAutomationControls::const_iterator i = sc.begin(); i != sc.end(); ++i) {
+               AxisView* av = avp.axis_view_by_stripable ((*i).stripable);
+               if (av) {
+                       axes.insert (av);
+                       av->set_selected (true);
+               }
+       }
 }
 
 void
 RouteProcessorSelection::add (AxisView* r)
 {
+       if (!shp.session()) {
+               return;
+       }
+
        if (axes.insert (r).second) {
 
-               r->set_selected (true);
+               shp.session()->selection().add (r->stripable(), boost::shared_ptr<AutomationControl>());
 
                MixerStrip* ms = dynamic_cast<MixerStrip*> (r);
 
@@ -114,23 +131,20 @@ RouteProcessorSelection::add (AxisView* r)
 void
 RouteProcessorSelection::remove (AxisView* r)
 {
-       ENSURE_GUI_THREAD (*this, &RouteProcessorSelection::remove, r);
-       PresentationInfo::ChangeSuspender cs;
-
-       AxisViewSelection::iterator i;
-       if ((i = find (axes.begin(), axes.end(), r)) != axes.end()) {
-               AxisView* av = *i;
-               axes.erase (i);
-               av->set_selected (false);
+       if (!shp.session()) {
+               return;
        }
+       ENSURE_GUI_THREAD (*this, &RouteProcessorSelection::remove, r);
+       shp.session()->selection().remove (r->stripable(), boost::shared_ptr<AutomationControl>());
 }
 
 void
 RouteProcessorSelection::set (AxisView* r)
 {
-       PresentationInfo::ChangeSuspender cs;
-       clear_routes ();
-       add (r);
+       if (!shp.session()) {
+               return;
+       }
+       shp.session()->selection().set (r->stripable(), boost::shared_ptr<AutomationControl>());
 }
 
 bool
index c708723e4dff87ef8640d5a123da4af02d266b55..b0e7c36fbd3ba107cafa3bdceec418f13ef72e5b 100644 (file)
 #include "processor_selection.h"
 #include "route_ui_selection.h"
 
-class RouteProcessorSelection : public PBD::ScopedConnectionList, public sigc::trackable
+namespace ARDOUR {
+       class SessionHandlePtr;
+}
+
+class AxisViewProvider;
+
+class RouteProcessorSelection : public ProcessorSelection
 {
   public:
-       ProcessorSelection processors;
        AxisViewSelection  axes;
 
-       RouteProcessorSelection();
+       RouteProcessorSelection (ARDOUR::SessionHandlePtr&, AxisViewProvider&);
 
        RouteProcessorSelection& operator= (const RouteProcessorSelection& other);
 
-       sigc::signal<void> ProcessorsChanged;
-
        void clear ();
        bool empty();
 
-       void set (XMLNode* node);
-       void add (XMLNode* node);
-
        void set (AxisView*);
        void add (AxisView*);
        void remove (AxisView*);
+       bool selected (AxisView*);
 
-       void clear_processors ();
        void clear_routes ();
 
-       bool selected (AxisView*);
+       void presentation_info_changed (PBD::PropertyChange const & what_changed);
 
   private:
+       ARDOUR::SessionHandlePtr& shp;
+       AxisViewProvider& avp;
        void removed (AxisView*);
 };
 
index 1114222248f1f008be12432d688abae27bde80aa..23d89d0786049eb721689ef27e96eee09f6f6213 100644 (file)
 #include "pbd/stacktrace.h"
 #include "pbd/types_convert.h"
 
+#include "ardour/evoral_types_convert.h"
 #include "ardour/playlist.h"
 #include "ardour/rc_configuration.h"
-#include "ardour/evoral_types_convert.h"
+#include "ardour/selection.h"
 
 #include "control_protocol/control_protocol.h"
 
@@ -65,9 +66,6 @@ Selection::Selection (const PublicEditor* e)
 
        /* we have disambiguate which remove() for the compiler */
 
-       void (Selection::*track_remove)(TimeAxisView*) = &Selection::remove;
-       TimeAxisView::CatchDeletion.connect (*this, MISSING_INVALIDATOR, boost::bind (track_remove, this, _1), gui_context());
-
        void (Selection::*marker_remove)(ArdourMarker*) = &Selection::remove;
        ArdourMarker::CatchDeletion.connect (*this, MISSING_INVALIDATOR, boost::bind (marker_remove, this, _1), gui_context());
 
@@ -130,20 +128,6 @@ Selection::clear_objects (bool with_signal)
        clear_midi_regions (with_signal);
 }
 
-void
-Selection::clear_tracks (bool with_signal)
-{
-       if (!tracks.empty()) {
-               PresentationInfo::ChangeSuspender cs;
-
-               for (TrackViewList::iterator x = tracks.begin(); x != tracks.end(); ++x) {
-                       (*x)->set_selected (false);
-               }
-
-               tracks.clear ();
-       }
-}
-
 void
 Selection::clear_time (bool with_signal)
 {
@@ -271,38 +255,6 @@ Selection::toggle (boost::shared_ptr<Playlist> pl)
        PlaylistsChanged ();
 }
 
-void
-Selection::toggle (const TrackViewList& track_list)
-{
-       PresentationInfo::ChangeSuspender cs;
-
-       for (TrackViewList::const_iterator i = track_list.begin(); i != track_list.end(); ++i) {
-               if (dynamic_cast<VCATimeAxisView*> (*i)) {
-                       continue;
-               }
-               toggle ((*i));
-       }
-}
-
-void
-Selection::toggle (TimeAxisView* track)
-{
-       if (dynamic_cast<VCATimeAxisView*> (track)) {
-               return;
-       }
-
-       TrackSelection::iterator i;
-
-       if ((i = find (tracks.begin(), tracks.end(), track)) == tracks.end()) {
-               tracks.push_back (track);
-               track->set_selected (true);
-       } else {
-               tracks.erase (i);
-               track->set_selected (false);
-       }
-
-}
-
 void
 Selection::toggle (const MidiNoteSelection& midi_note_list)
 {
@@ -405,10 +357,10 @@ Selection::toggle (framepos_t start, framepos_t end)
 void
 Selection::add (boost::shared_ptr<Playlist> pl)
 {
-       clear_time();  //enforce object/range exclusivity
-       clear_tracks();  //enforce object/track exclusivity
 
        if (find (playlists.begin(), playlists.end(), pl) == playlists.end()) {
+               clear_time();  //enforce object/range exclusivity
+               clear_tracks();  //enforce object/track exclusivity
                pl->use ();
                playlists.push_back(pl);
                PlaylistsChanged ();
@@ -418,9 +370,6 @@ Selection::add (boost::shared_ptr<Playlist> pl)
 void
 Selection::add (const list<boost::shared_ptr<Playlist> >& pllist)
 {
-       clear_time();  //enforce object/range exclusivity
-       clear_tracks();  //enforce object/track exclusivity
-
        bool changed = false;
 
        for (list<boost::shared_ptr<Playlist> >::const_iterator i = pllist.begin(); i != pllist.end(); ++i) {
@@ -432,51 +381,21 @@ Selection::add (const list<boost::shared_ptr<Playlist> >& pllist)
        }
 
        if (changed) {
+               clear_time();  //enforce object/range exclusivity
+               clear_tracks();  //enforce object/track exclusivity
                PlaylistsChanged ();
        }
 }
 
-void
-Selection::add (TrackViewList const & track_list)
-{
-       clear_objects();  //enforce object/range exclusivity
-
-       PresentationInfo::ChangeSuspender cs;
-
-       TrackViewList added = tracks.add (track_list);
-
-       if (!added.empty()) {
-               for (TrackViewList::iterator x = added.begin(); x != added.end(); ++x) {
-                       if (dynamic_cast<VCATimeAxisView*> (*x)) {
-                               continue;
-                       }
-                       (*x)->set_selected (true);
-               }
-       }
-}
-
-void
-Selection::add (TimeAxisView* track)
-{
-       if (dynamic_cast<VCATimeAxisView*> (track)) {
-               return;
-       }
-
-       TrackViewList tr;
-       tr.push_back (track);
-       add (tr);
-}
-
 void
 Selection::add (const MidiNoteSelection& midi_list)
 {
-       clear_time();  //enforce object/range exclusivity
-       clear_tracks();  //enforce object/track exclusivity
-
        const MidiNoteSelection::const_iterator b = midi_list.begin();
        const MidiNoteSelection::const_iterator e = midi_list.end();
 
        if (!midi_list.empty()) {
+               clear_time();  //enforce object/range exclusivity
+               clear_tracks();  //enforce object/track exclusivity
                midi_notes.insert (midi_notes.end(), b, e);
                MidiNotesChanged ();
        }
@@ -496,9 +415,6 @@ Selection::add (MidiCutBuffer* midi)
 void
 Selection::add (vector<RegionView*>& v)
 {
-       clear_time();  //enforce object/range exclusivity
-       clear_tracks();  //enforce object/track exclusivity
-
        /* XXX This method or the add (const RegionSelection&) needs to go
         */
 
@@ -511,6 +427,8 @@ Selection::add (vector<RegionView*>& v)
        }
 
        if (changed) {
+               clear_time();  //enforce object/range exclusivity
+               clear_tracks();  //enforce object/track exclusivity
                RegionsChanged ();
        }
 }
@@ -518,9 +436,6 @@ Selection::add (vector<RegionView*>& v)
 void
 Selection::add (const RegionSelection& rs)
 {
-       clear_time();  //enforce object/range exclusivity
-       clear_tracks();  //enforce object/track exclusivity
-
        /* XXX This method or the add (const vector<RegionView*>&) needs to go
         */
 
@@ -533,6 +448,8 @@ Selection::add (const RegionSelection& rs)
        }
 
        if (changed) {
+               clear_time();  //enforce object/range exclusivity
+               clear_tracks();  //enforce object/track exclusivity
                RegionsChanged ();
        }
 }
@@ -540,12 +457,11 @@ Selection::add (const RegionSelection& rs)
 void
 Selection::add (RegionView* r)
 {
-       clear_time();  //enforce object/range exclusivity
-       clear_tracks();  //enforce object/track exclusivity
-
        if (find (regions.begin(), regions.end(), r) == regions.end()) {
                bool changed = regions.add (r);
                if (changed) {
+                       clear_time();  //enforce object/range exclusivity
+                       clear_tracks();  //enforce object/track exclusivity
                        RegionsChanged ();
                }
        }
@@ -624,16 +540,18 @@ Selection::replace (uint32_t sid, framepos_t start, framepos_t end)
 void
 Selection::add (boost::shared_ptr<Evoral::ControlList> cl)
 {
-       clear_time();  //enforce object/range exclusivity
-       clear_tracks();  //enforce object/track exclusivity
+       boost::shared_ptr<ARDOUR::AutomationList> al = boost::dynamic_pointer_cast<ARDOUR::AutomationList>(cl);
 
-       boost::shared_ptr<ARDOUR::AutomationList> al
-               = boost::dynamic_pointer_cast<ARDOUR::AutomationList>(cl);
        if (!al) {
                warning << "Programming error: Selected list is not an ARDOUR::AutomationList" << endmsg;
                return;
        }
 
+       if (!cl->empty()) {
+               clear_time();  //enforce object/range exclusivity
+               clear_tracks();  //enforce object/track exclusivity
+       }
+
        /* The original may change so we must store a copy (not a pointer) here.
         * e.g AutomationLine rewrites the list with gain mapping.
         * the downside is that we can't perfom duplicate checks.
@@ -643,38 +561,6 @@ Selection::add (boost::shared_ptr<Evoral::ControlList> cl)
        LinesChanged();
 }
 
-void
-Selection::remove (TimeAxisView* track)
-{
-       list<TimeAxisView*>::iterator i;
-       if ((i = find (tracks.begin(), tracks.end(), track)) != tracks.end()) {
-               /* erase first, because set_selected() will remove the track
-                  from the selection, invalidating the iterator.
-
-                  In fact, we don't really even need to do the erase, but this is
-                  a hangover of axis view selection being in the GUI.
-               */
-               tracks.erase (i);
-               track->set_selected (false);
-       }
-}
-
-void
-Selection::remove (const TrackViewList& track_list)
-{
-       PresentationInfo::ChangeSuspender cs;
-
-       for (TrackViewList::const_iterator i = track_list.begin(); i != track_list.end(); ++i) {
-
-               TrackViewList::iterator x = find (tracks.begin(), tracks.end(), *i);
-
-               if (x != tracks.end()) {
-                       tracks.erase (x);
-                       (*i)->set_selected (false);
-               }
-       }
-}
-
 void
 Selection::remove (ControlPoint* p)
 {
@@ -800,68 +686,13 @@ Selection::remove (boost::shared_ptr<ARDOUR::AutomationList> ac)
        }
 }
 
-void
-Selection::set (TimeAxisView* track)
-{
-       if (dynamic_cast<VCATimeAxisView*> (track)) {
-               return;
-       }
-       clear_objects ();  //enforce object/range exclusivity
-
-       PresentationInfo::ChangeSuspender cs;
-
-       if (!tracks.empty()) {
-
-               if (tracks.size() == 1 && tracks.front() == track) {
-                       /* already single selection: nothing to do */
-                       return;
-               }
-
-               for (TrackViewList::iterator x = tracks.begin(); x != tracks.end(); ++x) {
-                       (*x)->set_selected (false);
-               }
-
-               tracks.clear ();
-       }
-
-       add (track);
-}
-
-void
-Selection::set (const TrackViewList& track_list)
-{
-       clear_objects();  //enforce object/range exclusivity
-
-
-       TrackViewList to_be_added;
-       TrackViewList to_be_removed;
-
-       for (TrackViewList::const_iterator x = tracks.begin(); x != tracks.end(); ++x) {
-               if (find (track_list.begin(), track_list.end(), *x) == track_list.end()) {
-                       to_be_removed.push_back (*x);
-               }
-       }
-
-       for (TrackViewList::const_iterator x = track_list.begin(); x != track_list.end(); ++x) {
-               if (dynamic_cast<VCATimeAxisView*> (*x)) {
-                       continue;
-               }
-               if (find (tracks.begin(), tracks.end(), *x) == tracks.end()) {
-                       to_be_added.push_back (*x);
-               }
-       }
-
-       PresentationInfo::ChangeSuspender cs;
-       remove (to_be_removed);
-       add (to_be_added);
-
-}
-
 void
 Selection::set (const MidiNoteSelection& midi_list)
 {
-       clear_time ();  //enforce region/object exclusivity
-       clear_tracks();  //enforce object/track exclusivity
+       if (!midi_list.empty()) {
+               clear_time ();  //enforce region/object exclusivity
+               clear_tracks();  //enforce object/track exclusivity
+       }
        clear_objects ();
        add (midi_list);
 }
@@ -869,8 +700,10 @@ Selection::set (const MidiNoteSelection& midi_list)
 void
 Selection::set (boost::shared_ptr<Playlist> playlist)
 {
-       clear_time ();  //enforce region/object exclusivity
-       clear_tracks();  //enforce object/track exclusivity
+       if (playlist) {
+               clear_time ();  //enforce region/object exclusivity
+               clear_tracks();  //enforce object/track exclusivity
+       }
        clear_objects ();
        add (playlist);
 }
@@ -878,7 +711,9 @@ Selection::set (boost::shared_ptr<Playlist> playlist)
 void
 Selection::set (const list<boost::shared_ptr<Playlist> >& pllist)
 {
-       clear_time();  //enforce region/object exclusivity
+       if (!pllist.empty()) {
+               clear_time();  //enforce region/object exclusivity
+       }
        clear_objects ();
        add (pllist);
 }
@@ -886,8 +721,10 @@ Selection::set (const list<boost::shared_ptr<Playlist> >& pllist)
 void
 Selection::set (const RegionSelection& rs)
 {
-       clear_time();  //enforce region/object exclusivity
-       clear_tracks();  //enforce object/track exclusivity
+       if (!rs.empty()) {
+               clear_time();  //enforce region/object exclusivity
+               clear_tracks();  //enforce object/track exclusivity
+       }
        clear_objects();
        regions = rs;
        RegionsChanged(); /* EMIT SIGNAL */
@@ -896,8 +733,10 @@ Selection::set (const RegionSelection& rs)
 void
 Selection::set (MidiRegionView* mrv)
 {
-       clear_time();  //enforce region/object exclusivity
-       clear_tracks();  //enforce object/track exclusivity
+       if (mrv) {
+               clear_time();  //enforce region/object exclusivity
+               clear_tracks();  //enforce object/track exclusivity
+       }
        clear_objects ();
        add (mrv);
 }
@@ -905,8 +744,10 @@ Selection::set (MidiRegionView* mrv)
 void
 Selection::set (RegionView* r, bool /*also_clear_tracks*/)
 {
-       clear_time();  //enforce region/object exclusivity
-       clear_tracks();  //enforce object/track exclusivity
+       if (r) {
+               clear_time();  //enforce region/object exclusivity
+               clear_tracks();  //enforce object/track exclusivity
+       }
        clear_objects ();
        add (r);
 }
@@ -914,8 +755,11 @@ Selection::set (RegionView* r, bool /*also_clear_tracks*/)
 void
 Selection::set (vector<RegionView*>& v)
 {
-       clear_time();  //enforce region/object exclusivity
-       clear_tracks();  //enforce object/track exclusivity
+       if (!v.empty()) {
+               clear_time();  //enforce region/object exclusivity
+               clear_tracks();  //enforce object/track exclusivity
+       }
+
        clear_objects();
 
        add (v);
@@ -999,12 +843,6 @@ Selection::selected (ArdourMarker* m) const
        return find (markers.begin(), markers.end(), m) != markers.end();
 }
 
-bool
-Selection::selected (TimeAxisView* tv) const
-{
-       return tv->selected ();
-}
-
 bool
 Selection::selected (RegionView* rv) const
 {
@@ -1384,26 +1222,19 @@ Selection::set_state (XMLNode const & node, int)
        clear_midi_notes ();
        clear_points ();
        clear_time ();
-       clear_tracks ();
        clear_markers ();
 
        RegionSelection selected_regions;
 
+       /* NOTE: stripable/time-axis-view selection is saved/restored by
+        * ARDOUR::CoreSelection, not this Selection object
+        */
+
        PBD::ID id;
        XMLNodeList children = node.children ();
-       for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
-               if ((*i)->name() == X_("RouteView")) {
-
-                       if (!(*i)->get_property (X_("id"), id)) {
-                               assert(false); // handle this more gracefully?
-                       }
 
-                       RouteTimeAxisView* rtv = editor->get_route_view_by_route_id (id);
-                       if (rtv) {
-                               add (rtv);
-                       }
-
-               } else if ((*i)->name() == X_("Region")) {
+       for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
+               if ((*i)->name() == X_("Region")) {
 
                        if (!(*i)->get_property (X_("id"), id)) {
                                assert(false);
@@ -1594,3 +1425,252 @@ Selection::remove_regions (TimeAxisView* t)
                i = tmp;
        }
 }
+
+/* TIME AXIS VIEW ... proxy for Stripable/Controllable
+ *
+ * public methods just modify the CoreSelection; PresentationInfo::Changed will
+ * trigger Selection::core_selection_changed() and we will update our own data
+ * structures there.
+ */
+
+void
+Selection::toggle (const TrackViewList& track_list)
+{
+       TrackViewList t = add_grouped_tracks (track_list);
+
+       CoreSelection& selection (editor->session()->selection());
+       PresentationInfo::ChangeSuspender cs;
+
+       for (TrackSelection::const_iterator i = t.begin(); i != t.end(); ++i) {
+               boost::shared_ptr<Stripable> s = (*i)->stripable ();
+               boost::shared_ptr<AutomationControl> c = (*i)->control ();
+               selection.toggle (s, c);
+       }
+}
+
+void
+Selection::toggle (TimeAxisView* track)
+{
+       if (dynamic_cast<VCATimeAxisView*> (track)) {
+               return;
+       }
+
+       TrackViewList tr;
+       tr.push_back (track);
+       toggle (tr);
+}
+
+void
+Selection::add (TrackViewList const & track_list)
+{
+       TrackViewList t = add_grouped_tracks (track_list);
+
+       CoreSelection& selection (editor->session()->selection());
+       PresentationInfo::ChangeSuspender cs;
+
+       for (TrackSelection::const_iterator i = t.begin(); i != t.end(); ++i) {
+               boost::shared_ptr<Stripable> s = (*i)->stripable ();
+               boost::shared_ptr<AutomationControl> c = (*i)->control ();
+               selection.add (s, c);
+       }
+}
+
+void
+Selection::add (TimeAxisView* track)
+{
+       if (dynamic_cast<VCATimeAxisView*> (track)) {
+               return;
+       }
+
+       TrackViewList tr;
+       tr.push_back (track);
+       add (tr);
+}
+
+void
+Selection::remove (TimeAxisView* track)
+{
+       if (dynamic_cast<VCATimeAxisView*> (track)) {
+               return;
+       }
+
+       TrackViewList tvl;
+       tvl.push_back (track);
+       remove (tvl);
+}
+
+void
+Selection::remove (const TrackViewList& t)
+{
+       CoreSelection& selection (editor->session()->selection());
+       PresentationInfo::ChangeSuspender cs;
+
+       for (TrackSelection::const_iterator i = t.begin(); i != t.end(); ++i) {
+               boost::shared_ptr<Stripable> s = (*i)->stripable ();
+               boost::shared_ptr<AutomationControl> c = (*i)->control ();
+               selection.remove (s, c);
+       }
+}
+
+void
+Selection::set (TimeAxisView* track)
+{
+       if (dynamic_cast<VCATimeAxisView*> (track)) {
+               return;
+       }
+
+       TrackViewList tvl;
+       tvl.push_back (track);
+       set (tvl);
+}
+
+void
+Selection::set (const TrackViewList& track_list)
+{
+       TrackViewList t = add_grouped_tracks (track_list);
+
+       CoreSelection& selection (editor->session()->selection());
+       PresentationInfo::ChangeSuspender cs;
+
+       selection.clear_stripables ();
+
+       for (TrackSelection::const_iterator i = t.begin(); i != t.end(); ++i) {
+               boost::shared_ptr<Stripable> s = (*i)->stripable ();
+               boost::shared_ptr<AutomationControl> c = (*i)->control ();
+               selection.add (s, c);
+       }
+}
+
+void
+Selection::clear_tracks (bool)
+{
+       Session* s = editor->session();
+       if (s) {
+               CoreSelection& selection (s->selection());
+               selection.clear_stripables ();
+       }
+}
+
+bool
+Selection::selected (TimeAxisView* tv) const
+{
+       Session* session = editor->session();
+
+       if (!session) {
+               return false;
+       }
+
+       CoreSelection& selection (session->selection());
+       boost::shared_ptr<Stripable> s = tv->stripable ();
+       boost::shared_ptr<AutomationControl> c = tv->control ();
+
+       if (c) {
+               return selection.selected (c);
+       }
+
+       return selection.selected (s);
+}
+
+TrackViewList
+Selection::add_grouped_tracks (TrackViewList const & t)
+{
+       TrackViewList added;
+
+       for (TrackSelection::const_iterator i = t.begin(); i != t.end(); ++i) {
+               if (dynamic_cast<VCATimeAxisView*> (*i)) {
+                       continue;
+               }
+
+               /* select anything in the same select-enabled route group */
+               ARDOUR::RouteGroup* rg = (*i)->route_group ();
+
+               if (rg && rg->is_active() && rg->is_select ()) {
+
+                       TrackViewList tr = editor->axis_views_from_routes (rg->route_list ());
+
+                       for (TrackViewList::iterator j = tr.begin(); j != tr.end(); ++j) {
+
+                               /* Do not add the trackview passed in as an
+                                * argument, because we want that to be on the
+                                * end of the list.
+                                */
+
+                               if (*j != *i) {
+                                       if (!added.contains (*j)) {
+                                               added.push_back (*j);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /* now add the the trackview's passed in as actual arguments */
+       added.insert (added.end(), t.begin(), t.end());
+
+       return added;
+}
+
+#if 0
+static void dump_tracks (Selection const & s)
+{
+       cerr << "--TRACKS [" << s.tracks.size() << ']' << ":\n";
+       for (TrackViewList::const_iterator x = s.tracks.begin(); x != s.tracks.end(); ++x) {
+               cerr << (*x)->name() << ' ' << (*x)->stripable() << " C = " << (*x)->control() << endl;
+       }
+       cerr << "///\n";
+}
+#endif
+
+void
+Selection::core_selection_changed (PropertyChange const & what_changed)
+{
+       PropertyChange pc;
+
+       pc.add (Properties::selected);
+
+       if (!what_changed.contains (pc)) {
+               return;
+       }
+
+       CoreSelection& selection (editor->session()->selection());
+
+       if (selection.selected()) {
+               clear_objects();  // enforce object/range exclusivity
+       }
+
+       tracks.clear (); // clear stage for whatever tracks are now selected (maybe none)
+
+       TrackViewList const & tvl (editor->get_track_views ());
+
+       for (TrackViewList::const_iterator x = tvl.begin(); x != tvl.end(); ++x) {
+
+               boost::shared_ptr<Stripable> s = (*x)->stripable ();
+               boost::shared_ptr<AutomationControl> c = (*x)->control ();
+
+               if (!s) {
+                       continue;
+               }
+
+               TimeAxisView* tav = editor->time_axis_view_from_stripable (s);
+
+               if (!tav) {
+                       continue;
+               }
+
+               if ((c && selection.selected (c)) || selection.selected (s)) {
+                       tracks.push_back (tav);
+               }
+
+               TimeAxisView::Children kids = tav->get_child_list ();
+
+               for (TimeAxisView::Children::iterator j = kids.begin(); j != kids.end(); ++j) {
+                       s = (*j)->stripable ();
+                       c = (*j)->control ();
+
+                       if ((c && selection.selected (c)) || selection.selected (s)) {
+                               tracks.push_back ((*j).get());
+                       }
+               }
+
+       }
+}
index 959690b95dc8e909d06bdf70da7d1bb606093a61..7e8ba19d7b34a3bd4ebcc90e3ca3222c748301fa 100644 (file)
@@ -225,9 +225,13 @@ class Selection : public sigc::trackable, public PBD::ScopedConnectionList
 
        std::list<std::pair<PBD::ID const, std::list<Evoral::event_id_t> > > pending_midi_note_selection;
 
+       void core_selection_changed (PBD::PropertyChange const & pc);
+
   private:
        PublicEditor const * editor;
        uint32_t next_time_id;
+
+       TrackViewList add_grouped_tracks (TrackViewList const & t);
 };
 
 bool operator==(const Selection& a, const Selection& b);
index 999734962822dce33ed9ccaa4a96f33caa085bcd..5bd26b193a987f56dfad6281dd636e8d6b91537b 100644 (file)
@@ -769,19 +769,9 @@ TimeAxisView::set_selected (bool yn)
                time_axis_vbox.set_name (controls_base_unselected_name);
 
                hide_selection ();
-
-               /* children will be set for the yn=true case. but when deselecting
-                  the editor only has a list of top-level trackviews, so we
-                  have to do this here.
-               */
-
-               for (Children::iterator i = children.begin(); i != children.end(); ++i) {
-                       (*i)->set_selected (false);
-               }
        }
 
        time_axis_frame.show();
-
 }
 
 void
index ac3d8b68e52b891e8833b86e9267a69915be891c..ad761ef4cd4dd9e56f6f4031bd8fe4898603804f 100644 (file)
@@ -39,47 +39,3 @@ TrackSelection::~TrackSelection ()
 {
 }
 
-TrackViewList
-TrackSelection::add (TrackViewList const & t)
-{
-       TrackViewList added;
-
-       for (TrackSelection::const_iterator i = t.begin(); i != t.end(); ++i) {
-               if (dynamic_cast<VCATimeAxisView*> (*i)) {
-                       continue;
-               }
-
-               /* select anything in the same select-enabled route group */
-               ARDOUR::RouteGroup* rg = (*i)->route_group ();
-
-               if (rg && rg->is_active() && rg->is_select ()) {
-
-                       TrackViewList tr = _editor->axis_views_from_routes (rg->route_list ());
-
-                       for (TrackViewList::iterator j = tr.begin(); j != tr.end(); ++j) {
-
-                               /* Do not add the trackview passed in as an
-                                * argument, because we want that to be on the
-                                * end of the list.
-                                */
-
-                               if (*j != *i) {
-                                       if (!contains (*j)) {
-                                               added.push_back (*j);
-                                               push_back (*j);
-                                       }
-                               }
-                       }
-               }
-
-               /* now add the the trackview's passed in as actual arguments */
-
-               if (!contains (*i)) {
-                       added.push_back (*i);
-                       push_back (*i);
-               }
-       }
-
-
-       return added;
-}
index 2e9927ab420ad89a82e535c7a3eaa0eeab4e2266..8c7aac45c4776b1c01bf5ba1167dacab8e082f55 100644 (file)
@@ -35,8 +35,6 @@ public:
 
        virtual ~TrackSelection ();
 
-       TrackViewList add (TrackViewList const &);
-
        template <typename Function>
        void foreach_time_axis (Function f) {
                for (iterator i = begin(); i != end(); ++i) {
index 646ae17d6bc59bfd762962e4a70cfb7920bbf107..b925e2657bb23f7f2eca9602702962dac524af60 100644 (file)
@@ -202,6 +202,7 @@ gtk2_ardour_sources = [
         'port_matrix_labels.cc',
         'port_matrix_row_labels.cc',
         'processor_box.cc',
+        'processor_selection.cc',
         'patch_change_dialog.cc',
         'progress_reporter.cc',
         'prompter.cc',