fix behaviour of select_(next|prev)_route() in editor, when VCAs are present.
[ardour.git] / gtk2_ardour / editor.cc
index 13f7c5bef5344e5bbfe643aa320a57036ae8d849..c0ab97d9a42472795cf33a4afbad85e916e313ef 100644 (file)
 #include "ardour/lmath.h"
 #include "ardour/location.h"
 #include "ardour/profile.h"
+#include "ardour/route.h"
 #include "ardour/route_group.h"
 #include "ardour/session_playlists.h"
 #include "ardour/tempo.h"
 #include "ardour/utils.h"
 #include "ardour/vca_manager.h"
+#include "ardour/vca.h"
 
 #include "canvas/debug.h"
 #include "canvas/text.h"
 #include "region_layering_order_editor.h"
 #include "rgb_macros.h"
 #include "rhythm_ferret.h"
+#include "route_sorter.h"
 #include "selection.h"
 #include "simple_progress_dialog.h"
 #include "sfdb_ui.h"
@@ -726,19 +729,23 @@ Editor::Editor ()
 
        float fract;
 
-       if (!settings || ((prop = settings->property ("edit-horizontal-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
-               /* initial allocation is 90% to canvas, 10% to notebook */
-               edit_pane.set_divider (0, 0.90);
-       } else {
-               edit_pane.set_divider (0, fract);
-       }
+       {
+               LocaleGuard lg;
 
-       if (!settings || ((prop = settings->property ("edit-vertical-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
-               /* initial allocation is 90% to canvas, 10% to summary */
-               editor_summary_pane.set_divider (0, 0.90);
-       } else {
+               if (!settings || ((prop = settings->property ("edit-horizontal-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
+                       /* initial allocation is 90% to canvas, 10% to notebook */
+                       edit_pane.set_divider (0, 0.90);
+               } else {
+                       edit_pane.set_divider (0, fract);
+               }
 
-               editor_summary_pane.set_divider (0, fract);
+               if (!settings || ((prop = settings->property ("edit-vertical-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
+                       /* initial allocation is 90% to canvas, 10% to summary */
+                       editor_summary_pane.set_divider (0, 0.90);
+               } else {
+
+                       editor_summary_pane.set_divider (0, fract);
+               }
        }
 
        top_hbox.pack_start (toolbar_frame);
@@ -796,11 +803,9 @@ Editor::Editor ()
        ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
        ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
 
-       ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
-       ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
-       ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
+       ControlProtocol::AddStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
        ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
-       ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
+       ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
 
        BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
 
@@ -1004,7 +1009,7 @@ Editor::control_unselect ()
 }
 
 void
-Editor::control_select (PresentationInfo::global_order_t global_order, Selection::Operation op)
+Editor::control_select (PresentationInfo::order_t order, Selection::Operation op)
 {
        /* handles the (static) signal from the ControlProtocol class that
         * requests setting the selected track to a given RID
@@ -1014,22 +1019,7 @@ Editor::control_select (PresentationInfo::global_order_t global_order, Selection
                return;
        }
 
-       PresentationInfo::Flag select_flags;
-
-       if (global_order & ~0xffffffff) {
-               /* some flags are set, so the PresentationInfo constructor
-                * will use them
-                */
-               select_flags = PresentationInfo::Flag (0);
-       } else {
-               /* no type flags set in the global order ID, so assume caller
-                * wants to select a Route
-                */
-               select_flags = PresentationInfo::Route;
-       }
-
-       PresentationInfo pi (global_order, select_flags);
-       boost::shared_ptr<Stripable> s = _session->get_remote_nth_stripable (pi.group_order(), pi.flags());
+       boost::shared_ptr<Stripable> s = _session->get_nth_stripable (order);
 
        /* selected object may not be a Route */
 
@@ -2345,6 +2335,7 @@ Editor::set_state (const XMLNode& node, int version)
        XMLProperty const * prop;
        set_id (node);
        PBD::Unwinder<bool> nsi (no_save_instant, true);
+       LocaleGuard lg;
 
        Tabbable::set_state (node, version);
 
@@ -2367,6 +2358,8 @@ Editor::set_state (const XMLNode& node, int version)
 
        if ((prop = node.property ("zoom-focus"))) {
                zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
+       } else {
+               zoom_focus_selection_done (zoom_focus);
        }
 
        if ((prop = node.property ("zoom"))) {
@@ -2384,6 +2377,8 @@ Editor::set_state (const XMLNode& node, int version)
        if ((prop = node.property ("snap-to"))) {
                snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
                set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
+       } else {
+               set_snap_to (_snap_type);
        }
 
        if ((prop = node.property ("snap-mode"))) {
@@ -2393,6 +2388,8 @@ Editor::set_state (const XMLNode& node, int version)
                 * which does not trigger set_text().
                 */
                set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
+       } else {
+               set_snap_mode (_snap_mode);
        }
 
        if ((prop = node.property ("internal-snap-to"))) {
@@ -2445,6 +2442,8 @@ Editor::set_state (const XMLNode& node, int version)
 
        if ((prop = node.property ("edit-point"))) {
                set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
+       } else {
+               set_edit_point_preference (_edit_point);
        }
 
        if ((prop = node.property ("show-measures"))) {
@@ -4247,7 +4246,7 @@ Editor::new_playlists (TimeAxisView* v)
        begin_reversible_command (_("new playlists"));
        vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
        _session->playlists->get (playlists);
-       mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
+       mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
        commit_reversible_command ();
 }
 
@@ -4263,7 +4262,7 @@ Editor::copy_playlists (TimeAxisView* v)
        begin_reversible_command (_("copy playlists"));
        vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
        _session->playlists->get (playlists);
-       mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
+       mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
        commit_reversible_command ();
 }
 
@@ -4278,7 +4277,7 @@ Editor::clear_playlists (TimeAxisView* v)
        begin_reversible_command (_("clear playlists"));
        vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
        _session->playlists->get (playlists);
-       mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
+       mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
        commit_reversible_command ();
 }
 
@@ -5189,73 +5188,94 @@ Editor::resume_route_redisplay ()
 }
 
 void
-Editor::add_vcas (VCAList& vcas)
+Editor::add_vcas (VCAList& vlist)
 {
-       VCATimeAxisView* vtv;
-       list<VCATimeAxisView*> new_views;
+       StripableList sl;
 
-       for (VCAList::iterator v = vcas.begin(); v != vcas.end(); ++v) {
-               vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
-               vtv->set_vca (*v);
-               new_views.push_back (vtv);
+       for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
+               sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
        }
 
-       if (new_views.size() > 0) {
-               _routes->vcas_added (new_views);
-       }
+       add_stripables (sl);
 }
 
 void
-Editor::add_routes (RouteList& routes)
+Editor::add_routes (RouteList& rlist)
 {
-       ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
+       StripableList sl;
+
+       for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
+               sl.push_back (*r);
+       }
 
-       RouteTimeAxisView *rtv;
-       list<RouteTimeAxisView*> new_views;
+       add_stripables (sl);
+}
+
+void
+Editor::add_stripables (StripableList& sl)
+{
+       list<TimeAxisView*> new_views;
+       boost::shared_ptr<VCA> v;
+       boost::shared_ptr<Route> r;
        TrackViewList new_selection;
        bool from_scratch = (track_views.size() == 0);
 
-       for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
-               boost::shared_ptr<Route> route = (*x);
+       sl.sort (StripablePresentationInfoSorter());
 
-               if (route->is_auditioner() || route->is_monitor()) {
-                       continue;
-               }
+       for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
 
-               DataType dt = route->input()->default_type();
+               if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
 
-               if (dt == ARDOUR::DataType::AUDIO) {
-                       rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
-                       rtv->set_route (route);
-               } else if (dt == ARDOUR::DataType::MIDI) {
-                       rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
-                       rtv->set_route (route);
-               } else {
-                       throw unknown_type();
-               }
+                       VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
+                       vtv->set_vca (v);
+                       new_views.push_back (vtv);
 
-               new_views.push_back (rtv);
-               track_views.push_back (rtv);
-               new_selection.push_back (rtv);
+               } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
 
-               rtv->effective_gain_display ();
+                       if (r->is_auditioner() || r->is_monitor()) {
+                               continue;
+                       }
+
+                       RouteTimeAxisView* rtv;
+                       DataType dt = r->input()->default_type();
+
+                       if (dt == ARDOUR::DataType::AUDIO) {
+                               rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
+                               rtv->set_route (r);
+                       } else if (dt == ARDOUR::DataType::MIDI) {
+                               rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
+                               rtv->set_route (r);
+                       } else {
+                               throw unknown_type();
+                       }
 
-               rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
-               rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
+                       new_views.push_back (rtv);
+                       track_views.push_back (rtv);
+                       new_selection.push_back (rtv);
+
+                       rtv->effective_gain_display ();
+
+                       rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
+                       rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
+               }
        }
 
        if (new_views.size() > 0) {
-               _routes->routes_added (new_views);
-               _summary->routes_added (new_views);
+               _routes->time_axis_views_added (new_views);
+               //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
        }
 
-       if (!from_scratch) {
+       /* note: !new_selection.empty() means that we got some routes rather
+        * than just VCAs
+        */
+
+       if (!from_scratch && !new_selection.empty()) {
                selection->tracks.clear();
                selection->add (new_selection);
                begin_selection_op_history();
        }
 
-       if (show_editor_mixer_when_tracks_arrive) {
+       if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
                show_editor_mixer (true);
        }