first pass at the big rethink of managing sort order keys for editor and mixer. this...
authorPaul Davis <paul@linuxaudiosystems.com>
Wed, 27 Jun 2012 22:57:06 +0000 (22:57 +0000)
committerPaul Davis <paul@linuxaudiosystems.com>
Wed, 27 Jun 2012 22:57:06 +0000 (22:57 +0000)
git-svn-id: svn://localhost/ardour2/branches/3.0@12953 d708f5d6-7413-0410-9779-e7cbd77b26cf

22 files changed:
gtk2_ardour/ardour_ui.cc
gtk2_ardour/au_pluginui.mm
gtk2_ardour/editor.cc
gtk2_ardour/editor.h
gtk2_ardour/editor_group_tabs.cc
gtk2_ardour/editor_routes.cc
gtk2_ardour/editor_routes.h
gtk2_ardour/mixer_group_tabs.cc
gtk2_ardour/mixer_ui.cc
gtk2_ardour/mixer_ui.h
gtk2_ardour/port_matrix.cc
gtk2_ardour/port_matrix.h
gtk2_ardour/route_ui.cc
libs/ardour/ardour/debug.h
libs/ardour/ardour/route.h
libs/ardour/ardour/session.h
libs/ardour/ardour/types.h
libs/ardour/debug.cc
libs/ardour/enums.cc
libs/ardour/route.cc
libs/ardour/session.cc
libs/ardour/session_state.cc

index 8b90b2d5b87f5099b33b1d4ea29bb071357453bb..96e309ed014c3661b2661fcd7b3eead536e33aa2 100644 (file)
@@ -3142,8 +3142,6 @@ ARDOUR_UI::add_route (Gtk::Window* float_window)
                output_chan = input_chan;
        }
 
-       cerr << "ARD said " << input_chan << " and " << output_chan << endl;
-
        /* XXX do something with name template */
 
        switch (add_route_dialog->type_wanted()) {
index 359b32478aef7ab14fcc509ff74dc2acfc0892f6..0433d2502d6c9ae991d36daea9f3bbe3f6769b21 100644 (file)
@@ -568,12 +568,13 @@ AUPluginUI::parent_carbon_window ()
 
        int packing_extra = 6; // this is the total vertical packing in our top level window
 
-       MoveWindow (carbon_window, x, y + titlebar_height + top_box.get_height() + packing_extra, false);
-       ShowWindow (carbon_window);
-
        // create the cocoa window for the carbon one and make it visible
        cocoa_parent = [[NSWindow alloc] initWithWindowRef: carbon_window];
 
+        PositionWindow (carbon_window, [cocoa_parent windowRef], kWindowCascadeStartAtParentWindowScreen);
+       MoveWindow (carbon_window, x, y + titlebar_height + top_box.get_height() + packing_extra, false);
+       ShowWindow (carbon_window);
+
        SetWindowActivationScope (carbon_window, kWindowActivationScopeNone);
 
        _notify = [ [NotificationObject alloc] initWithPluginUI:this andCocoaParent:cocoa_parent andTopLevelParent:win ]; 
index 9daf72c589c873090475592eca8abfb0450e34fc..f33dda2dac7a79c52e66cb7777983eced2ac5464 100644 (file)
@@ -1271,7 +1271,7 @@ Editor::set_session (Session *t)
        _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
        _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
        _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
-       _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::handle_new_route, this, _1), gui_context());
+       _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
        _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
        _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
        _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
@@ -4785,9 +4785,8 @@ Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
        return t;
 }
 
-
 void
-Editor::handle_new_route (RouteList& routes)
+Editor::add_routes (RouteList& routes)
 {
        ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
 
@@ -4797,7 +4796,7 @@ Editor::handle_new_route (RouteList& routes)
        for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
                boost::shared_ptr<Route> route = (*x);
 
-               if (route->is_hidden() || route->is_monitor()) {
+               if (route->is_hidden()) {
                        continue;
                }
 
index 23da8d7c6d051bf230e113b92f7cb6c198096bd4..9408b27f8f5eda578ebeb73c86dd9ae0dac01566 100644 (file)
@@ -704,7 +704,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
        void popup_control_point_context_menu (ArdourCanvas::Item *, GdkEvent *);
        Gtk::Menu _control_point_context_menu;
 
-       void handle_new_route (ARDOUR::RouteList&);
+       void add_routes (ARDOUR::RouteList&);
        void timeaxisview_deleted (TimeAxisView *);
 
        Gtk::HBox           global_hpacker;
index 5a1e9c8aaa2cb3bc4fde327ca114e4f24cb4255b..cb855446698fdbc61af441377de44c8125b481cc 100644 (file)
@@ -201,5 +201,5 @@ EditorGroupTabs::selected_routes () const
 void
 EditorGroupTabs::sync_order_keys ()
 {
-       _editor->_routes->sync_order_keys (UndefinedSort);
+       _editor->_routes->sync_order_keys_from_model ();
 }
index 3faeba183f3fbf332bb27dc98b73aa964e9024ab..d8aec330070ac9092e8f7d2cddbe6749a5dc9415 100644 (file)
 #include <cmath>
 #include <cassert>
 
+#include "pbd/unknown_type.h"
+#include "pbd/unwind.h"
+
+#include "gtkmm2ext/cell_renderer_pixbuf_multi.h"
+#include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
+#include "gtkmm2ext/treeutils.h"
+
+#include "ardour/debug.h"
+#include "ardour/route.h"
+#include "ardour/midi_track.h"
 #include "ardour/session.h"
 
 #include "editor.h"
 #include "editor_group_tabs.h"
 #include "editor_routes.h"
 
-#include "pbd/unknown_type.h"
-
-#include "ardour/route.h"
-#include "ardour/midi_track.h"
-
-#include "gtkmm2ext/cell_renderer_pixbuf_multi.h"
-#include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
-#include "gtkmm2ext/treeutils.h"
-
 #include "i18n.h"
 
 using namespace std;
@@ -67,9 +68,7 @@ EditorRoutes::EditorRoutes (Editor* e)
        : EditorComponent (e)
         , _ignore_reorder (false)
         , _no_redisplay (false)
-        , _redisplay_does_not_sync_order_keys (false)
-        , _redisplay_does_not_reset_order_keys (false)
-        ,_menu (0)
+        , _menu (0)
         , old_focus (0)
         , selection_countdown (0)
         , name_editable (0)
@@ -282,7 +281,7 @@ EditorRoutes::EditorRoutes (Editor* e)
 
         _display.set_enable_search (false);
 
-       Route::SyncOrderKeys.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::sync_order_keys, this, _1), gui_context());
+       Route::SyncOrderKeys.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::sync_model_from_order_keys, this, _1), gui_context());
 }
 
 bool
@@ -502,12 +501,7 @@ EditorRoutes::redisplay ()
        */
        int n;
 
-       /* Order keys must not take children into account, so use a separate counter
-          for that.
-       */
-       int order_key;
-
-       for (n = 0, order_key = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
+       for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
                TimeAxisView *tv = (*i)[_columns.tv];
                boost::shared_ptr<Route> route = (*i)[_columns.route];
 
@@ -516,20 +510,6 @@ EditorRoutes::redisplay ()
                        continue;
                }
 
-               if (!_redisplay_does_not_reset_order_keys) {
-                       /* this reorder is caused by user action, so reassign sort order keys
-                          to tracks.
-                       */
-                       
-                       if (route->is_master()) {
-                               route->set_order_key (EditorSort, Route::MasterBusRemoteControlID);
-                       } else if (route->is_monitor()) {
-                               route->set_order_key (EditorSort, Route::MonitorBusRemoteControlID);
-                       } else {
-                               route->set_order_key (EditorSort, order_key++);
-                       }
-               }
-
                bool visible = tv->marked_for_display ();
 
                /* show or hide the TimeAxisView */
@@ -561,23 +541,23 @@ EditorRoutes::redisplay ()
                */
                _editor->vertical_adjustment.set_value (_editor->full_canvas_height - _editor->_canvas_height);
        }
-
-       if (!_redisplay_does_not_reset_order_keys && !_redisplay_does_not_sync_order_keys) {
-               _session->sync_order_keys (EditorSort);
-       }
 }
 
 void
 EditorRoutes::route_deleted (Gtk::TreeModel::Path const &)
 {
-       if (!_session || _session->deletion_in_progress()) {
-               return;
-       }
+       /* this happens as the second step of a DnD within the treeview as well
+          as when a row/route is actually deleted.
+       */
+       DEBUG_TRACE (DEBUG::OrderKeys, "editor routes treeview row deleted\n");
+       sync_order_keys_from_model ();
+}
 
-        /* this could require an order reset & sync */
-       _ignore_reorder = true;
-       redisplay ();
-       _ignore_reorder = false;
+void
+EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
+{
+       DEBUG_TRACE (DEBUG::OrderKeys, "editor routes treeview reordered\n");
+       sync_order_keys_from_model ();
 }
 
 void
@@ -595,10 +575,7 @@ EditorRoutes::visible_changed (std::string const & path)
                        bool visible = (*iter)[_columns.visible];
 
                        if (tv->set_marked_for_display (!visible)) {
-                               _redisplay_does_not_reset_order_keys = true;
                                update_visibility ();
-                               redisplay ();
-                               _redisplay_does_not_reset_order_keys = false;
                        }
                }
        }
@@ -622,7 +599,6 @@ EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
 {
        TreeModel::Row row;
 
-       _redisplay_does_not_sync_order_keys = true;
        suspend_redisplay ();
 
        for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) {
@@ -685,7 +661,10 @@ EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
        update_input_active_display ();
        update_active_display ();
        resume_redisplay ();
-       _redisplay_does_not_sync_order_keys = false;
+
+       /* now update route order keys from the treeview/track display order */
+
+       sync_order_keys_from_model ();
 }
 
 void
@@ -714,12 +693,6 @@ EditorRoutes::route_removed (TimeAxisView *tv)
        TreeModel::Children rows = _model->children();
        TreeModel::Children::iterator ri;
 
-       /* the core model has changed, there is no need to sync
-          view orders.
-       */
-
-       _redisplay_does_not_sync_order_keys = true;
-
        for (ri = rows.begin(); ri != rows.end(); ++ri) {
                if ((*ri)[_columns.tv] == tv) {
                        _model->erase (ri);
@@ -727,7 +700,9 @@ EditorRoutes::route_removed (TimeAxisView *tv)
                }
        }
 
-       _redisplay_does_not_sync_order_keys = false;
+       /* the deleted signal for the treeview/model will take 
+          care of any updates.
+       */
 }
 
 void
@@ -782,6 +757,11 @@ EditorRoutes::update_visibility ()
                (*i)[_columns.visible] = tv->marked_for_display ();
        }
 
+       /* force route order keys catch up with visibility changes
+        */
+
+       sync_order_keys_from_model ();
+
        resume_redisplay ();
 }
 
@@ -819,57 +799,109 @@ EditorRoutes::show_track_in_display (TimeAxisView& tv)
 }
 
 void
-EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
+EditorRoutes::sync_order_keys_from_model ()
 {
-       redisplay ();
-}
+       if (_ignore_reorder || !_session || _session->deletion_in_progress()) {
+               return;
+       }
 
-/** If src != "editor", take editor order keys from each route and use them to rearrange the
- *  route list so that the visual arrangement of routes matches the order keys from the routes.
- */
-void
-EditorRoutes::sync_order_keys (RouteSortOrderKey src)
-{
-       map<int, int> new_order;
        TreeModel::Children rows = _model->children();
-       TreeModel::Children::iterator ri;
-
-       if (src == EditorSort || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
+       
+       if (rows.empty()) {
                return;
        }
 
+       DEBUG_TRACE (DEBUG::OrderKeys, "editor sync order keys from model\n");
+
+       TreeModel::Children::iterator ri;
        bool changed = false;
-       int order;
+       uint32_t order = 0;
 
-       for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
+       for (ri = rows.begin(); ri != rows.end(); ++ri) {
                boost::shared_ptr<Route> route = (*ri)[_columns.route];
+               bool visible = (*ri)[_columns.visible];
 
-               int const old_key = order;
-               int const new_key = route->order_key (EditorSort);
+               uint32_t old_key = route->order_key (EditorSort);
+               uint32_t new_key;
 
-               new_order[new_key] = old_key;
+               if (!visible) {
+                       new_key = UINT_MAX;
+               } else {
+                       new_key = order;
+               }
 
-               if (new_key != old_key) {
+               if (old_key != new_key) {
+                       route->set_order_key (EditorSort, new_key);
                        changed = true;
                }
-       }
 
+               order++;
+       }
+       
        if (changed) {
-               _redisplay_does_not_reset_order_keys = true;
+               /* tell the world that we changed the editor sort keys */
+               _session->sync_order_keys (EditorSort);
+       }
+}
+
+void
+EditorRoutes::sync_model_from_order_keys (RouteSortOrderKey src)
+{
+       if (!_session || _session->deletion_in_progress()) {
+               return;
+       }
 
-               /* `compact' new_order into a vector */
-               vector<int> co;
-               for (map<int, int>::const_iterator i = new_order.begin(); i != new_order.end(); ++i) {
-                       co.push_back (i->second);
+       DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("editor sync model from order keys, src = %1\n", enum_2_string (src)));
+
+       if (src == MixerSort) {
+
+               if (!Config->get_sync_all_route_ordering()) {
+                       /* mixer sort keys changed - we don't care */
+                       return;
                }
 
-               assert (co.size() == _model->children().size ());
+               DEBUG_TRACE (DEBUG::OrderKeys, "reset editor order key to match mixer\n");
 
-               _model->reorder (co);
-               _redisplay_does_not_reset_order_keys = false;
+               /* mixer sort keys were changed, update the editor sort
+                * keys since "sync mixer+editor order" is enabled.
+                */
+
+               boost::shared_ptr<RouteList> r = _session->get_routes ();
+               
+               for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+                       (*i)->sync_order_keys (src);
+               }
        }
-}
 
+       /* we could get here after either a change in the Mixer or Editor sort
+        * order, but either way, the mixer order keys reflect the intended
+        * order for the GUI, so reorder the treeview model to match it.
+        */
+
+       vector<int> neworder;
+       TreeModel::Children rows = _model->children();
+       uint32_t n = 0;
+
+       if (rows.empty()) {
+               return;
+       }
+
+       neworder.assign (rows.size(), 0);
+
+       for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++n) {
+               boost::shared_ptr<Route> route = (*ri)[_columns.route];
+               neworder[route->order_key (EditorSort)] = n;
+               DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("editor change order for %1 to %2\n",
+                                                              route->name(), route->order_key (MixerSort)));
+       }
+
+       {
+               Unwinder<bool> uw (_ignore_reorder, true);
+               _model->reorder (neworder);
+       }
+
+       redisplay ();
+}
 
 void
 EditorRoutes::hide_all_tracks (bool /*with_select*/)
@@ -920,6 +952,11 @@ EditorRoutes::set_all_tracks_visibility (bool yn)
                (*i)[_columns.visible] = yn;
        }
 
+       /* force route order keys catch up with visibility changes
+        */
+
+       sync_order_keys_from_model ();
+
        resume_redisplay ();
 }
 
@@ -977,6 +1014,11 @@ EditorRoutes::set_all_audio_midi_visibility (int tracks, bool yn)
                }
        }
 
+       /* force route order keys catch up with visibility changes
+        */
+
+       sync_order_keys_from_model ();
+
        resume_redisplay ();
 }
 
@@ -1187,7 +1229,13 @@ EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path
 
 struct EditorOrderRouteSorter {
     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
-           /* use of ">" forces the correct sort order */
+           if (a->is_master()) {
+                   /* master before everything else */
+                   return true;
+           } else if (b->is_master()) {
+                   /* everything else before master */
+                   return false;
+           }
            return a->order_key (EditorSort) < b->order_key (EditorSort);
     }
 };
@@ -1204,48 +1252,32 @@ EditorRoutes::initial_display ()
        }
 
        boost::shared_ptr<RouteList> routes = _session->get_routes();
-       RouteList r (*routes);
-       EditorOrderRouteSorter sorter;
-
-       r.sort (sorter);
-       _editor->handle_new_route (r);
-
-       /* don't show master bus in a new session */
 
        if (ARDOUR_UI::instance()->session_is_new ()) {
 
-               TreeModel::Children rows = _model->children();
-               TreeModel::Children::iterator i;
-
-               _no_redisplay = true;
-
-               for (i = rows.begin(); i != rows.end(); ++i) {
+               /* new session: stamp all routes with the right editor order
+                * key
+                */
 
-                       TimeAxisView *tv =  (*i)[_columns.tv];
-                       RouteTimeAxisView *rtv;
+               _editor->add_routes (*(routes.get()));
+               
+       } else {
 
-                       if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
-                               if (rtv->route()->is_master()) {
-                                       _display.get_selection()->unselect (i);
-                               }
-                       }
-               }
+               /* existing session: sort a copy of the route list by
+                * editor-order and add its contents to the display.
+                */
 
-               _no_redisplay = false;
-               redisplay ();
+               RouteList r (*routes);
+               EditorOrderRouteSorter sorter;
+               
+               r.sort (sorter);
+               _editor->add_routes (r);
+               
        }
 
        resume_redisplay ();
 }
 
-void
-EditorRoutes::track_list_reorder (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &, int* /*new_order*/)
-{
-       _redisplay_does_not_sync_order_keys = true;
-       redisplay ();
-       _redisplay_does_not_sync_order_keys = false;
-}
-
 void
 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
                                             int x, int y,
@@ -1364,18 +1396,26 @@ EditorRoutes::move_selected_tracks (bool up)
        }
 
        for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
-               neworder.push_back (leading->second->order_key (EditorSort));
+               uint32_t order = leading->second->order_key (EditorSort);
+               neworder.push_back (order);
        }
 
 #ifndef NDEBUG
+       DEBUG_TRACE (DEBUG::OrderKeys, "New order after moving tracks:\n");
        for (vector<int>::iterator i = neworder.begin(); i != neworder.end(); ++i) {
+               DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("\t%1\n", *i));
+       }
+       DEBUG_TRACE (DEBUG::OrderKeys, "-------\n");
+
+       for (vector<int>::iterator i = neworder.begin(); i != neworder.end(); ++i) {
+               if (*i >= (int) neworder.size()) {
+                       cerr << "Trying to move something to " << *i << " of " << neworder.size() << endl;
+               }
                assert (*i < (int) neworder.size ());
        }
 #endif 
 
        _model->reorder (neworder);
-
-       _session->sync_order_keys (EditorSort);
 }
 
 void
@@ -1554,3 +1594,27 @@ EditorRoutes::show_tracks_with_regions_at_playhead ()
 
        resume_redisplay ();
 }
+
+uint32_t
+EditorRoutes::count_displayed_non_special_routes () const
+{
+       if (!_model) {
+               return 0;
+       }
+       uint32_t cnt = 0;
+       TreeModel::Children rows = _model->children ();
+       for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
+               bool visible = (*i)[_columns.visible];
+               if (visible) {
+                       boost::shared_ptr<Route> route = (*i)[_columns.route];
+                       if (route) {
+                               if (route->is_master() || route->is_monitor()) {
+                                       continue;
+                               }
+                               cnt++;
+                       }
+               }
+       }
+
+       return cnt;
+}
index 00631d914af524879409e03029e2feeac4b3bdf6..cbe9825cb56369be2e6083c659d515b0ae5f5a70 100644 (file)
@@ -42,6 +42,10 @@ public:
                _no_redisplay = true;
        }
 
+        void allow_redisplay () { 
+               _no_redisplay = false;
+       }
+
        void resume_redisplay () {
                _no_redisplay = false;
                redisplay ();
@@ -55,8 +59,8 @@ public:
        std::list<TimeAxisView*> views () const;
        void hide_all_tracks (bool);
        void clear ();
-        void sync_order_keys (ARDOUR::RouteSortOrderKey);
-
+        uint32_t count_displayed_non_special_routes () const;
+        void sync_order_keys_from_model ();
 private:
 
        void initial_display ();
@@ -68,6 +72,7 @@ private:
        void on_tv_solo_safe_toggled (std::string const &);
        void build_menu ();
        void show_menu ();
+        void sync_model_from_order_keys (ARDOUR::RouteSortOrderKey);
        void route_deleted (Gtk::TreeModel::Path const &);
        void visible_changed (std::string const &);
        void active_changed (std::string const &);
@@ -98,7 +103,6 @@ private:
                Glib::RefPtr<Gdk::DragContext> const &, gint, gint, Gtk::SelectionData const &, guint, guint
                );
 
-       void track_list_reorder (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const & iter, int* new_order);
        bool selection_filter (Glib::RefPtr<Gtk::TreeModel> const &, Gtk::TreeModel::Path const &, bool);
        void name_edit (std::string const &, std::string const &);
        void solo_changed_so_update_mute ();
@@ -150,8 +154,6 @@ private:
 
        bool _ignore_reorder;
        bool _no_redisplay;
-       bool _redisplay_does_not_sync_order_keys;
-       bool _redisplay_does_not_reset_order_keys;
 
        Gtk::Menu* _menu;
         Gtk::Widget* old_focus;
index 60a625c96db505867946bb17459115901e857620..f3121a5ca99518a5c64b0eecd784c248c00b5dd4 100644 (file)
@@ -192,5 +192,5 @@ MixerGroupTabs::selected_routes () const
 void
 MixerGroupTabs::sync_order_keys ()
 {
-       _mixer->sync_order_keys (UndefinedSort);
+       _mixer->sync_order_keys_from_model ();
 }
index 503424368088e2d7b9db54b95f6b9ef5e77c7e51..17d37fa5fbcf4de7df439eefa5d427a4716a952d 100644 (file)
@@ -29,6 +29,8 @@
 
 #include "pbd/convert.h"
 #include "pbd/stacktrace.h"
+#include "pbd/unwind.h"
+
 #include <glibmm/thread.h>
 
 #include <gtkmm2ext/gtk_ui.h>
@@ -36,6 +38,7 @@
 #include <gtkmm2ext/tearoff.h>
 #include <gtkmm2ext/window_title.h>
 
+#include "ardour/debug.h"
 #include "ardour/plugin_manager.h"
 #include "ardour/route_group.h"
 #include "ardour/session.h"
@@ -63,6 +66,7 @@ using namespace Gtkmm2ext;
 using namespace std;
 
 using PBD::atoi;
+using PBD::Unwinder;
 
 Mixer_UI* Mixer_UI::_instance = 0;
 
@@ -78,22 +82,19 @@ Mixer_UI::instance ()
 
 Mixer_UI::Mixer_UI ()
        : Window (Gtk::WINDOW_TOPLEVEL)
+       , _visible (false)
+       , no_track_list_redisplay (false)
+       , in_group_row_change (false)
+       , track_menu (0)
+       , _monitor_section (0)
+       , _strip_width (Config->get_default_narrow_ms() ? Narrow : Wide)
+       , ignore_reorder (false)
        , _following_editor_selection (false)
 {
        /* allow this window to become the key focus window */
        set_flags (CAN_FOCUS);
 
-       _strip_width = Config->get_default_narrow_ms() ? Narrow : Wide;
-       track_menu = 0;
-        _monitor_section = 0;
-       no_track_list_redisplay = false;
-       in_group_row_change = false;
-       _visible = false;
-       strip_redisplay_does_not_reset_order_keys = false;
-       strip_redisplay_does_not_sync_order_keys = false;
-       ignore_sync = false;
-
-       Route::SyncOrderKeys.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::sync_order_keys, this, _1), gui_context());
+       Route::SyncOrderKeys.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::sync_model_from_order_keys, this, _1), gui_context());
 
        scroller_base.set_flags (Gtk::CAN_FOCUS);
        scroller_base.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
@@ -305,70 +306,68 @@ Mixer_UI::hide_window (GdkEventAny *ev)
 
 
 void
-Mixer_UI::add_strip (RouteList& routes)
+Mixer_UI::add_strips (RouteList& routes)
 {
        MixerStrip* strip;
 
-       no_track_list_redisplay = true;
-       strip_redisplay_does_not_sync_order_keys = true;
-       
-       for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
-               boost::shared_ptr<Route> route = (*x);
-
-               if (route->is_hidden()) {
-                       continue;
-               }
-
-                if (route->is_monitor()) {
-
-                        if (!_monitor_section) {
-                                _monitor_section = new MonitorSection (_session);
+       {
+               Unwinder<bool> uw (no_track_list_redisplay, true);
+               
+               for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
+                       boost::shared_ptr<Route> route = (*x);
+                       
+                       if (route->is_hidden()) {
+                               continue;
+                       }
+                       
+                       if (route->is_monitor()) {
                                
-                               XMLNode* mnode = ARDOUR_UI::instance()->tearoff_settings (X_("monitor-section"));
-                               if (mnode) {
-                                       _monitor_section->tearoff().set_state (*mnode);
-                               }
-                        } 
-
-                       out_packer.pack_end (_monitor_section->tearoff(), false, false);
-                       _monitor_section->set_session (_session);
-                        _monitor_section->tearoff().show_all ();
-
-                       route->DropReferences.connect (*this, invalidator(*this), boost::bind (&Mixer_UI::monitor_section_going_away, this), gui_context());
-
-                        /* no regular strip shown for control out */
-
-                        continue;
-                }
-
-               strip = new MixerStrip (*this, _session, route);
-               strips.push_back (strip);
-
-               Config->get_default_narrow_ms() ? _strip_width = Narrow : _strip_width = Wide;
-
-               if (strip->width_owner() != strip) {
-                       strip->set_width_enum (_strip_width, this);
+                               if (!_monitor_section) {
+                                       _monitor_section = new MonitorSection (_session);
+                                       
+                                       XMLNode* mnode = ARDOUR_UI::instance()->tearoff_settings (X_("monitor-section"));
+                                       if (mnode) {
+                                               _monitor_section->tearoff().set_state (*mnode);
+                                       }
+                               } 
+                               
+                               out_packer.pack_end (_monitor_section->tearoff(), false, false);
+                               _monitor_section->set_session (_session);
+                               _monitor_section->tearoff().show_all ();
+                               
+                               route->DropReferences.connect (*this, invalidator(*this), boost::bind (&Mixer_UI::monitor_section_going_away, this), gui_context());
+                               
+                               /* no regular strip shown for control out */
+                               
+                               continue;
+                       }
+                       
+                       strip = new MixerStrip (*this, _session, route);
+                       strips.push_back (strip);
+                       
+                       Config->get_default_narrow_ms() ? _strip_width = Narrow : _strip_width = Wide;
+                       
+                       if (strip->width_owner() != strip) {
+                               strip->set_width_enum (_strip_width, this);
+                       }
+                       
+                       show_strip (strip);
+                       
+                       TreeModel::Row row = *(track_model->append());
+                       row[track_columns.text] = route->name();
+                       row[track_columns.visible] = strip->route()->is_master() ? true : strip->marked_for_display();
+                       row[track_columns.route] = route;
+                       row[track_columns.strip] = strip;
+                       
+                       route->PropertyChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::strip_property_changed, this, _1, strip), gui_context());
+                       
+                       strip->WidthChanged.connect (sigc::mem_fun(*this, &Mixer_UI::strip_width_changed));
+                       strip->signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::strip_button_release_event), strip));
                }
-
-               show_strip (strip);
-
-               TreeModel::Row row = *(track_model->append());
-               row[track_columns.text] = route->name();
-               row[track_columns.visible] = strip->route()->is_master() ? true : strip->marked_for_display();
-               row[track_columns.route] = route;
-               row[track_columns.strip] = strip;
-
-               route->PropertyChanged.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::strip_property_changed, this, _1, strip), gui_context());
-
-               strip->WidthChanged.connect (sigc::mem_fun(*this, &Mixer_UI::strip_width_changed));
-               strip->signal_button_release_event().connect (sigc::bind (sigc::mem_fun(*this, &Mixer_UI::strip_button_release_event), strip));
        }
 
-       no_track_list_redisplay = false;
-
+       sync_order_keys_from_model ();
        redisplay_track_list ();
-
-       strip_redisplay_does_not_sync_order_keys = false;
 }
 
 void
@@ -387,62 +386,117 @@ Mixer_UI::remove_strip (MixerStrip* strip)
                strips.erase (i);
        }
        
-       strip_redisplay_does_not_sync_order_keys = true;
-       
        for (ri = rows.begin(); ri != rows.end(); ++ri) {
                if ((*ri)[track_columns.strip] == strip) {
                        track_model->erase (ri);
                        break;
                }
        }
-       
-       strip_redisplay_does_not_sync_order_keys = false;
 }
 
 void
-Mixer_UI::sync_order_keys (RouteSortOrderKey src)
+Mixer_UI::sync_order_keys_from_model ()
 {
-       TreeModel::Children rows = track_model->children();
-       TreeModel::Children::iterator ri;
+       if (ignore_reorder || !_session || _session->deletion_in_progress()) {
+               return;
+       }
 
-       if (src == MixerSort || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
+       TreeModel::Children rows = track_model->children();
+       
+       if (rows.empty()) {
                return;
        }
 
-       std::map<int,int> keys;
+       DEBUG_TRACE (DEBUG::OrderKeys, "mixer sync order keys from model\n");
 
+       TreeModel::Children::iterator ri;
        bool changed = false;
+       uint32_t order = 0;
 
-       unsigned order = 0;
-       for (ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
+       for (ri = rows.begin(); ri != rows.end(); ++ri) {
                boost::shared_ptr<Route> route = (*ri)[track_columns.route];
-               unsigned int old_key = order;
-               unsigned int new_key = route->order_key (MixerSort);
+               bool visible = (*ri)[track_columns.visible];
+
+               uint32_t old_key = route->order_key (MixerSort);
+               uint32_t new_key;
 
-               keys[new_key] = old_key;
+               if (!visible) {
+                       new_key = UINT_MAX;
+               } else {
+                       new_key = order;
+               }
 
-               if (new_key != old_key) {
+               if (old_key != new_key) {
+                       route->set_order_key (MixerSort, new_key);
                        changed = true;
                }
+
+               order++;
+       }
+       
+       if (changed) {
+               /* tell everyone that we changed the mixer sort keys */
+               _session->sync_order_keys (MixerSort);
        }
+}
 
-       if (keys.size() != rows.size()) {
-               PBD::stacktrace (cerr, 20);
+void
+Mixer_UI::sync_model_from_order_keys (RouteSortOrderKey src)
+{
+       if (!_session || _session->deletion_in_progress()) {
+               return;
        }
-       assert(keys.size() == rows.size());
 
-       // Remove any gaps in keys caused by automation children tracks
+       DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("mixer sync model from order keys, src = %1\n", enum_2_string (src)));
+
+       if (src == EditorSort) {
+
+               if (!Config->get_sync_all_route_ordering()) {
+                       /* editor sort keys changed - we don't care */
+                       return;
+               }
+
+               DEBUG_TRACE (DEBUG::OrderKeys, "reset mixer order key to match editor\n");
+
+               /* editor sort keys were changed, update the mixer sort
+                * keys since "sync mixer+editor order" is enabled.
+                */
+
+               boost::shared_ptr<RouteList> r = _session->get_routes ();
+               
+               for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+                       (*i)->sync_order_keys (src);
+               }
+       }
+
+       /* we could get here after either a change in the Mixer or Editor sort
+        * order, but either way, the mixer order keys reflect the intended
+        * order for the GUI, so reorder the treeview model to match it.
+        */
+
        vector<int> neworder;
-       for (std::map<int,int>::const_iterator i = keys.begin(); i != keys.end(); ++i) {
-               neworder.push_back(i->second);
+       TreeModel::Children rows = track_model->children();
+       uint32_t n = 0;
+
+       if (rows.empty()) {
+               return;
        }
-       assert(neworder.size() == rows.size());
 
-       if (changed) {
-               strip_redisplay_does_not_reset_order_keys = true;
+       neworder.assign (rows.size(), 0);
+       
+       for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++n) {
+               boost::shared_ptr<Route> route = (*ri)[track_columns.route];
+               neworder[route->order_key (MixerSort)] = n;
+               DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("mixer change order for %1 to %2\n",
+                                                              route->name(), route->order_key (MixerSort)));
+       }
+
+       {
+               Unwinder<bool> uw (ignore_reorder, true);
                track_model->reorder (neworder);
-               strip_redisplay_does_not_reset_order_keys = false;
        }
+
+       redisplay_track_list ();
 }
 
 void
@@ -573,7 +627,7 @@ Mixer_UI::set_session (Session* sess)
 
        initial_track_display ();
 
-       _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::add_strip, this, _1), gui_context());
+       _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::add_strips, this, _1), gui_context());
        _session->route_group_added.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::add_route_group, this, _1), gui_context());
        _session->route_group_removed.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::route_groups_changed, this), gui_context());
        _session->route_groups_reordered.connect (_session_connections, invalidator (*this), boost::bind (&Mixer_UI::route_groups_changed, this), gui_context());
@@ -690,25 +744,26 @@ Mixer_UI::set_all_strips_visibility (bool yn)
        TreeModel::Children rows = track_model->children();
        TreeModel::Children::iterator i;
 
-       no_track_list_redisplay = true;
-
-       for (i = rows.begin(); i != rows.end(); ++i) {
-
-               TreeModel::Row row = (*i);
-               MixerStrip* strip = row[track_columns.strip];
-
-               if (strip == 0) {
-                       continue;
-               }
-
-               if (strip->route()->is_master() || strip->route()->is_monitor()) {
-                       continue;
+       {
+               Unwinder<bool> uw (no_track_list_redisplay, true);
+               
+               for (i = rows.begin(); i != rows.end(); ++i) {
+                       
+                       TreeModel::Row row = (*i);
+                       MixerStrip* strip = row[track_columns.strip];
+                       
+                       if (strip == 0) {
+                               continue;
+                       }
+                       
+                       if (strip->route()->is_master() || strip->route()->is_monitor()) {
+                               continue;
+                       }
+                       
+                       (*i)[track_columns.visible] = yn;
                }
-
-               (*i)[track_columns.visible] = yn;
        }
 
-       no_track_list_redisplay = false;
        redisplay_track_list ();
 }
 
@@ -719,42 +774,43 @@ Mixer_UI::set_all_audio_visibility (int tracks, bool yn)
        TreeModel::Children rows = track_model->children();
        TreeModel::Children::iterator i;
 
-       no_track_list_redisplay = true;
-
-       for (i = rows.begin(); i != rows.end(); ++i) {
-               TreeModel::Row row = (*i);
-               MixerStrip* strip = row[track_columns.strip];
-
-               if (strip == 0) {
-                       continue;
-               }
-
-               if (strip->route()->is_master() || strip->route()->is_monitor()) {
-                       continue;
-               }
-
-               boost::shared_ptr<AudioTrack> at = strip->audio_track();
-
-               switch (tracks) {
-               case 0:
-                       (*i)[track_columns.visible] = yn;
-                       break;
-
-               case 1:
-                       if (at) { /* track */
-                               (*i)[track_columns.visible] = yn;
+       {
+               Unwinder<bool> uw (no_track_list_redisplay, true);
+               
+               for (i = rows.begin(); i != rows.end(); ++i) {
+                       TreeModel::Row row = (*i);
+                       MixerStrip* strip = row[track_columns.strip];
+                       
+                       if (strip == 0) {
+                               continue;
                        }
-                       break;
-
-               case 2:
-                       if (!at) { /* bus */
+                       
+                       if (strip->route()->is_master() || strip->route()->is_monitor()) {
+                               continue;
+                       }
+                       
+                       boost::shared_ptr<AudioTrack> at = strip->audio_track();
+                       
+                       switch (tracks) {
+                       case 0:
                                (*i)[track_columns.visible] = yn;
+                               break;
+                               
+                       case 1:
+                               if (at) { /* track */
+                                       (*i)[track_columns.visible] = yn;
+                               }
+                               break;
+                               
+                       case 2:
+                               if (!at) { /* bus */
+                                       (*i)[track_columns.visible] = yn;
+                               }
+                               break;
                        }
-                       break;
                }
        }
 
-       no_track_list_redisplay = false;
        redisplay_track_list ();
 }
 
@@ -795,27 +851,18 @@ Mixer_UI::hide_all_audiotracks ()
 void
 Mixer_UI::track_list_reorder (const TreeModel::Path&, const TreeModel::iterator&, int* /*new_order*/)
 {
-       strip_redisplay_does_not_sync_order_keys = true;
-       redisplay_track_list ();
-       strip_redisplay_does_not_sync_order_keys = false;
-}
-
-void
-Mixer_UI::track_list_change (const Gtk::TreeModel::Path&, const Gtk::TreeModel::iterator&)
-{
-       // never reset order keys because of a property change
-       strip_redisplay_does_not_reset_order_keys = true;
-       redisplay_track_list ();
-       strip_redisplay_does_not_reset_order_keys = false;
+       DEBUG_TRACE (DEBUG::OrderKeys, "mixer UI treeview reordered\n");
+       sync_order_keys_from_model ();
 }
 
 void
 Mixer_UI::track_list_delete (const Gtk::TreeModel::Path&)
 {
-       /* this could require an order sync */
-       if (_session && !_session->deletion_in_progress()) {
-               redisplay_track_list ();
-       }
+       /* this happens as the second step of a DnD within the treeview as well
+          as when a row/route is actually deleted.
+       */
+       DEBUG_TRACE (DEBUG::OrderKeys, "mixer UI treeview row deleted\n");
+       sync_order_keys_from_model ();
 }
 
 void
@@ -823,8 +870,6 @@ Mixer_UI::redisplay_track_list ()
 {
        TreeModel::Children rows = track_model->children();
        TreeModel::Children::iterator i;
-       long regular_order = 0;
-       long hidden_order = 999999; // arbitary high number
        
        if (no_track_list_redisplay) {
                return;
@@ -848,41 +893,17 @@ Mixer_UI::redisplay_track_list ()
 
                                if (strip->route()->is_master() || strip->route()->is_monitor()) {
                                        out_packer.reorder_child (*strip, -1);
-                                       
-                                       if (!strip_redisplay_does_not_reset_order_keys) {
-                                               if (strip->route()->is_master()) {
-                                                       strip->route()->set_order_key (MixerSort, Route::MasterBusRemoteControlID);
-                                               } else {
-                                                       strip->route()->set_order_key (MixerSort, Route::MonitorBusRemoteControlID);
-                                               }
-                                       }
 
                                } else {
                                        strip_packer.reorder_child (*strip, -1); /* put at end */
-
-                                       if (!strip_redisplay_does_not_reset_order_keys) {
-                                               strip->route()->set_order_key (MixerSort, regular_order++);
-                                       }
-
                                }
 
                        } else {
 
                                if (strip->route()->is_master() || strip->route()->is_monitor()) {
                                        out_packer.pack_start (*strip, false, false);
-                                       if (!strip_redisplay_does_not_reset_order_keys) {
-                                               if (strip->route()->is_master()) {
-                                                       strip->route()->set_order_key (MixerSort, Route::MasterBusRemoteControlID);
-                                               } else {
-                                                       strip->route()->set_order_key (MixerSort, Route::MonitorBusRemoteControlID);
-                                               }
-                                       }
                                } else {
                                        strip_packer.pack_start (*strip, false, false);
-
-                                       if (!strip_redisplay_does_not_reset_order_keys) {
-                                               strip->route()->set_order_key (MixerSort, regular_order++);
-                                       }
                                }
                                strip->set_packed (true);
                        }
@@ -898,18 +919,10 @@ Mixer_UI::redisplay_track_list ()
                                        strip_packer.remove (*strip);
                                        strip->set_packed (false);
                                }
-
-                               if (!strip_redisplay_does_not_reset_order_keys) {
-                                       strip->route()->set_order_key (MixerSort, hidden_order++);
-                               }
                        }
                }
        }
 
-       if (!strip_redisplay_does_not_reset_order_keys && !strip_redisplay_does_not_sync_order_keys) {
-               _session->sync_order_keys (MixerSort);
-       }
-
        _group_tabs->set_dirty ();
 }
 
@@ -942,7 +955,17 @@ Mixer_UI::strip_width_changed ()
 
 struct SignalOrderRouteSorter {
     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
+           if (a->is_master() || a->is_monitor()) {
+                   /* "a" is a special route (master, monitor, etc), and comes
+                    * last in the mixer ordering
+                    */
+                   return false;
+           } else if (b->is_master() || b->is_monitor()) {
+                   /* everything comes before b */
+                   return true;
+           }
            return a->order_key (MixerSort) < b->order_key (MixerSort);
+
     }
 };
 
@@ -955,13 +978,13 @@ Mixer_UI::initial_track_display ()
 
        copy.sort (sorter);
 
-       no_track_list_redisplay = true;
-
-       track_model->clear ();
-
-       add_strip (copy);
+       {
+               Unwinder<bool> uw1 (no_track_list_redisplay, true);
+               Unwinder<bool> uw2 (ignore_reorder, true);
 
-       no_track_list_redisplay = false;
+               track_model->clear ();
+               add_strips (copy);
+       }
 
        redisplay_track_list ();
 }
@@ -1675,7 +1698,6 @@ Mixer_UI::setup_track_display ()
        track_display.set_headers_visible (true);
 
        track_model->signal_row_deleted().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_delete));
-       track_model->signal_row_changed().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_change));
        track_model->signal_rows_reordered().connect (sigc::mem_fun (*this, &Mixer_UI::track_list_reorder));
 
        CellRendererToggle* track_list_visible_cell = dynamic_cast<CellRendererToggle*>(track_display.get_column_cell_renderer (1));
index f3d7845461cfa0bf3d6bbf1ad094fbf96fc7bac8..ab0223aa4db7d7740e2b5655110f37285e1bf453 100644 (file)
@@ -130,7 +130,7 @@ class Mixer_UI : public Gtk::Window, public PBD::ScopedConnectionList, public AR
        void scroll_left ();
        void scroll_right ();
 
-       void add_strip (ARDOUR::RouteList&);
+       void add_strips (ARDOUR::RouteList&);
        void remove_strip (MixerStrip *);
 
        MixerStrip* strip_by_route (boost::shared_ptr<ARDOUR::Route>);
@@ -161,7 +161,6 @@ class Mixer_UI : public Gtk::Window, public PBD::ScopedConnectionList, public AR
        bool track_display_button_press (GdkEventButton*);
        void strip_width_changed ();
 
-       void track_list_change (const Gtk::TreeModel::Path&,const Gtk::TreeModel::iterator&);
        void track_list_delete (const Gtk::TreeModel::Path&);
        void track_list_reorder (const Gtk::TreeModel::Path& path, const Gtk::TreeModel::iterator& iter, int* new_order);
 
@@ -245,10 +244,9 @@ class Mixer_UI : public Gtk::Window, public PBD::ScopedConnectionList, public AR
 
        Width _strip_width;
 
-        void sync_order_keys (ARDOUR::RouteSortOrderKey);
-       bool strip_redisplay_does_not_reset_order_keys;
-       bool strip_redisplay_does_not_sync_order_keys;
-       bool ignore_sync;
+        void sync_order_keys_from_model ();
+        void sync_model_from_order_keys (ARDOUR::RouteSortOrderKey);
+        bool ignore_reorder;
 
        void parameter_changed (std::string const &);
        void set_route_group_activation (ARDOUR::RouteGroup *, bool);
index 40c48b23453478ac1a24250134e251f33a599627..8db2dad475e8da8ec1e234ee20a32b0dc5510482 100644 (file)
@@ -157,7 +157,7 @@ PortMatrix::init ()
        _session->engine().PortRegisteredOrUnregistered.connect (_session_connections, invalidator (*this), boost::bind (&PortMatrix::setup_global_ports, this), gui_context());
 
        /* watch for route order keys changing, which changes the order of things in our global ports list(s) */
-       _session->RouteOrderKeyChanged.connect (_session_connections, invalidator (*this), boost::bind (&PortMatrix::setup_global_ports_proxy, this), gui_context());
+       Route::SyncOrderKeys.connect (_session_connections, invalidator (*this), boost::bind (&PortMatrix::setup_global_ports_proxy, this, _1), gui_context());
 
        /* Part 3: other stuff */
 
@@ -598,13 +598,15 @@ PortMatrix::setup_global_ports ()
 }
 
 void
-PortMatrix::setup_global_ports_proxy ()
+PortMatrix::setup_global_ports_proxy (RouteSortOrderKey sk)
 {
-       /* Avoid a deadlock by calling this in an idle handler: see IOSelector::io_changed_proxy
-          for a discussion.
-       */
-
-       Glib::signal_idle().connect_once (sigc::mem_fun (*this, &PortMatrix::setup_global_ports));
+       if (sk == EditorSort) {
+               /* Avoid a deadlock by calling this in an idle handler: see IOSelector::io_changed_proxy
+                  for a discussion.
+               */
+               
+               Glib::signal_idle().connect_once (sigc::mem_fun (*this, &PortMatrix::setup_global_ports));
+       }
 }
 
 void
index 76ead4bee94dd861d81583b8a395e2a63b137cab..2b5e9ce31d1c3a874b015f20e6955f52f1f355ca 100644 (file)
@@ -188,7 +188,7 @@ private:
        void disassociate_all_on_channel (boost::weak_ptr<ARDOUR::Bundle>, uint32_t, int);
        void disassociate_all_on_bundle (boost::weak_ptr<ARDOUR::Bundle>, int);
        void setup_global_ports ();
-       void setup_global_ports_proxy ();
+        void setup_global_ports_proxy (ARDOUR::RouteSortOrderKey);
        void toggle_show_only_bundles ();
        bool on_scroll_event (GdkEventScroll *);
        boost::shared_ptr<ARDOUR::IO> io_from_bundle (boost::shared_ptr<ARDOUR::Bundle>) const;
index b6c81717a23caa82115a159da83e9d03a9407505..536b4f110b9e5f7482511e9f9c64320a40a7d626 100644 (file)
@@ -1738,9 +1738,12 @@ RouteUI::open_remote_control_id_dialog ()
                dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
        } else {
                Label* l = manage (new Label());
-               l->set_markup (string_compose (_("Remote Control IDs are currently determined by track/bus ordering in %1\n\n\n"
+               l->set_markup (string_compose (_("Remote Control IDs are currently determined by track/bus ordering in %1\n\n"
+                                                "This %2 has remote control ID %3\n\n\n"
                                                 "<span size=\"small\" style=\"italic\">Use the User Interaction tab of the Preferences window if you want to change this</span>"),
-                                              (Config->get_remote_model() == MixerOrdered ? _("the mixer") : ("the editor"))));
+                                              (Config->get_remote_model() == MixerOrdered ? _("the mixer") : ("the editor")),
+                                              (is_track() ? _("track") : _("bus")),
+                                              _route->remote_control_id()));
                dialog.get_vbox()->pack_start (*l);
                dialog.add_button (Stock::OK, RESPONSE_CANCEL);
        }
index b9ecabd309cc6b60de80025c9c2de78e10ab0e3d..5c72c9236f8c104e313a5c018dc491d4caf4012d 100644 (file)
@@ -59,6 +59,7 @@ namespace PBD {
                extern uint64_t Layering;
                extern uint64_t TempoMath;
                extern uint64_t TempoMap;
+               extern uint64_t OrderKeys;
        }
 }
 
index a15937377eccf4902b1f99dbe52c06913a35a096..695e151dbbb1205fb35a3595c5cd95691691e568 100644 (file)
@@ -101,8 +101,10 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
        bool set_name (const std::string& str);
        static void set_name_in_state (XMLNode &, const std::string &);
 
-       int32_t order_key (RouteSortOrderKey) const;
-       void set_order_key (RouteSortOrderKey, int32_t);
+        uint32_t order_key (RouteSortOrderKey) const;
+        bool has_order_key (RouteSortOrderKey) const;
+       void set_order_key (RouteSortOrderKey, uint32_t);
+        void sync_order_keys (RouteSortOrderKey);
 
        bool is_hidden() const { return _flags & Hidden; }
        bool is_master() const { return _flags & MasterOut; }
@@ -286,7 +288,6 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
        PBD::Signal0<void>       meter_change;
        PBD::Signal0<void>       signal_latency_changed;
        PBD::Signal0<void>       initial_delay_changed;
-       PBD::Signal0<void>       order_key_changed;
 
        /** Emitted with the process lock held */
        PBD::Signal0<void>       io_changed;
@@ -430,8 +431,6 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
        /* for things concerned about *any* route's RID changes */
 
        static PBD::Signal0<void> RemoteControlIDChange;
-
-       void sync_order_keys (RouteSortOrderKey);
        static PBD::Signal1<void,RouteSortOrderKey> SyncOrderKeys;
 
        bool has_external_redirects() const;
@@ -533,7 +532,7 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
 
        static uint32_t order_key_cnt;
 
-       typedef std::map<RouteSortOrderKey,int32_t> OrderKeys;
+       typedef std::map<RouteSortOrderKey,uint32_t> OrderKeys;
        OrderKeys order_keys;
        uint32_t* _remote_control_id;
 
index 518a99d961bd00b48d988e1b0616465ad6617aa1..a132a4a5e8e83fc08c406cfc89a1bad6d9712b2e 100644 (file)
@@ -806,8 +806,6 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
        void send_mmc_locate (framepos_t);
        int send_full_time_code (framepos_t);
 
-       PBD::Signal0<void> RouteOrderKeyChanged;
-
        bool step_editing() const { return (_step_editors > 0); }
 
        void request_suspend_timecode_transmission ();
@@ -1503,8 +1501,6 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
 
        void setup_midi_machine_control ();
 
-       void route_order_key_changed ();
-
        void step_edit_status_change (bool);
        uint32_t _step_editors;
 
index 713e35ebab1a1f6b808808e94d21f4ef96c58e2f..595ee38369865a86495972dda1ac45d3b17620b6 100644 (file)
@@ -352,7 +352,6 @@ namespace ARDOUR {
        };
 
         enum RouteSortOrderKey { 
-               UndefinedSort,
                EditorSort,
                MixerSort
        };
index a0fc09a2ad48f97779c5b304b5901751f0709844..db0f409d119f471488429c71c25bc4e855c997e8 100644 (file)
@@ -56,5 +56,6 @@ uint64_t PBD::DEBUG::MidiTrackers = PBD::new_debug_bit ("miditrackers");
 uint64_t PBD::DEBUG::Layering = PBD::new_debug_bit ("layering");
 uint64_t PBD::DEBUG::TempoMath = PBD::new_debug_bit ("tempomath");
 uint64_t PBD::DEBUG::TempoMap = PBD::new_debug_bit ("tempomap");
+uint64_t PBD::DEBUG::OrderKeys = PBD::new_debug_bit ("orderkeys");
 
 
index 1ef9047f57711ec9b61312bcc34a0dc19c2b3eee..042b10adb5ea8d67a05236379c45659ce5fd8d96 100644 (file)
@@ -400,7 +400,7 @@ setup_enum_writer ()
 
        REGISTER_ENUM (MixerSort);
        REGISTER_ENUM (EditorSort);
-       REGISTER_BITS (_RouteSortOrderKey);
+       REGISTER (_RouteSortOrderKey);
 
        REGISTER_CLASS_ENUM (Source, Writable);
        REGISTER_CLASS_ENUM (Source, CanRename);
index 62bb2d0933ac37a230095d83e46d10d162f0fca5..2112336d8b040541b876cf5cbc4de2b7f5937d84 100644 (file)
@@ -247,116 +247,84 @@ uint32_t
 Route::remote_control_id() const
 {
        switch (Config->get_remote_model()) {
-       case MixerOrdered:
-               return order_key (MixerSort) + 1;
-       case EditorOrdered:
-               return order_key (EditorSort) + 1;
        case UserOrdered:
                if (_remote_control_id) {
                        return *_remote_control_id;
                }
+               break;
+       default:
+               break;
+       }
+
+       if (is_master()) {
+               return MasterBusRemoteControlID;
+       } 
+
+       if (is_monitor()) {
+               return MonitorBusRemoteControlID;
        }
 
-       /* fall back to MixerSort as the default */
+       /* order keys are zero-based, remote control ID's are one-based
+        */
+
+       switch (Config->get_remote_model()) {
+       case EditorOrdered:
+               return order_key (EditorSort) + 1;
+       case MixerOrdered:
+       default:
+               return order_key (MixerSort) + 1;
+       }
+}
 
-       return order_key (MixerSort) + 1;
+bool
+Route::has_order_key (RouteSortOrderKey key) const
+{
+       return (order_keys.find (key) != order_keys.end());
 }
 
-int32_t
+uint32_t
 Route::order_key (RouteSortOrderKey key) const
 {
        OrderKeys::const_iterator i = order_keys.find (key);
 
        if (i == order_keys.end()) {
-               return -1;
+               return 0;
        }
 
        return i->second;
 }
 
 void
-Route::set_order_key (RouteSortOrderKey key, int32_t n)
+Route::sync_order_keys (RouteSortOrderKey base)
 {
-       bool changed = false;
+       OrderKeys::iterator i = order_keys.find (base);
 
-       /* This method looks more complicated than it should, but
-          it's important that we don't emit order_key_changed unless
-          it actually has, as expensive things happen on receipt of that
-          signal.
-       */
-
-       if (order_keys.find (key) == order_keys.end() || order_keys[key] != n) {
-               order_keys[key] = n;
-               changed = true;
+       if (i == order_keys.end()) {
+               return;
        }
 
-       if (Config->get_sync_all_route_ordering()) {
-               for (OrderKeys::iterator x = order_keys.begin(); x != order_keys.end(); ++x) {
+       for (OrderKeys::iterator k = order_keys.begin(); k != order_keys.end(); ++k) {
 
-                       /* we do not sync the signal order keys for mixer +
-                        * monitor because they are considered "external" to
-                        * the ordering of other routes.
+               if (k->first == MixerSort && (is_master() || is_monitor())) {
+                       /* don't sync the mixer sort keys for master/monitor,
+                        * since they are not part of the normal ordering.
                         */
-
-                       if ((!is_master() && !is_monitor()) || x->first != MixerSort) {
-                               if (x->second != n) {
-                                       x->second = n;
-                                       changed = true;
-                               }
-                       }
+                        
+                       continue;
+               }
+               
+               if (k->first != base) {
+                       k->second = i->second;
                }
-       }
-
-       if (changed) {
-               order_key_changed (); /* EMIT SIGNAL */
-               _session.set_dirty ();
        }
 }
 
-/** Set all order keys to be the same as that for `base', if such a key
- *  exists in this route.
- *  @param base Base key.
- */
 void
-Route::sync_order_keys (RouteSortOrderKey base)
+Route::set_order_key (RouteSortOrderKey key, uint32_t n)
 {
-       if (order_keys.empty()) {
-               return;
-       }
-
-       OrderKeys::iterator i;
-       int32_t key;
-
-       if ((i = order_keys.find (base)) == order_keys.end()) {
-               /* key doesn't exist, use the first existing key (during session initialization) */
-               i = order_keys.begin();
-               key = i->second;
-               ++i;
-       } else {
-               /* key exists - use it and reset all others (actually, itself included) */
-               key = i->second;
-               i = order_keys.begin();
-       }
-
-       bool changed = false;
-
-       for (; i != order_keys.end(); ++i) {
-
-               /* we do not sync the signal order keys for mixer +
-                * monitor because they are considered "external" to
-                * the ordering of other routes.
-                */
-
-               if ((!is_master() && !is_monitor()) || i->first != MixerSort) {
-                       if (i->second != key) {
-                               i->second = key;
-                               changed = true;
-                       }
-               }
-       }
-
-       if (changed) {
-               order_key_changed (); /* EMIT SIGNAL */
+       if (order_keys.find (key) == order_keys.end() || order_keys[key] != n) {
+               order_keys[key] = n;
+               _session.set_dirty ();
        }
 }
 
index 9dacdc34cb950fc859d4faea9ec8ac31450d3dad..062d07ec2609f6b5e08e777d63ee8778f0cfd8e7 100644 (file)
@@ -2103,6 +2103,7 @@ Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output
 {
         ChanCount existing_inputs;
         ChanCount existing_outputs;
+       uint32_t order = next_control_id();
 
         count_existing_track_channels (existing_inputs, existing_outputs);
 
@@ -2133,7 +2134,6 @@ Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output
                r->mute_changed.connect_same_thread (*this, boost::bind (&Session::route_mute_changed, this, _1));
                r->output()->changed.connect_same_thread (*this, boost::bind (&Session::set_worst_io_latencies_x, this, _1, _2));
                r->processors_changed.connect_same_thread (*this, boost::bind (&Session::route_processors_changed, this, _1));
-               r->order_key_changed.connect_same_thread (*this, boost::bind (&Session::route_order_key_changed, this));
 
                if (r->is_master()) {
                        _master_out = r;
@@ -2159,6 +2159,24 @@ Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output
                if (input_auto_connect || output_auto_connect) {
                        auto_connect_route (r, existing_inputs, existing_outputs, true, input_auto_connect);
                }
+
+               /* order keys are a GUI responsibility but we need to set up
+                  reasonable defaults because they also affect the remote control
+                  ID in most situations.
+               */
+               
+               if (!r->has_order_key (EditorSort)) {
+                       if (r->is_hidden()) {
+                               /* use an arbitrarily high value */
+                               r->set_order_key (EditorSort, UINT_MAX);
+                               r->set_order_key (MixerSort, UINT_MAX);
+                       } else {
+                               DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("while adding, set %1 to order key %2\n", r->name(), order));
+                               r->set_order_key (EditorSort, order);
+                               r->set_order_key (MixerSort, order);
+                               order++;
+                       }
+               }
        }
 
        if (_monitor_out && IO::connecting_legal) {
@@ -2355,8 +2373,6 @@ Session::remove_route (boost::shared_ptr<Route> route)
 
        route->drop_references ();
 
-       sync_order_keys (UndefinedSort);
-
        Route::RemoteControlIDChange(); /* EMIT SIGNAL */
 
        /* save the new state of the world */
@@ -4096,27 +4112,6 @@ Session::add_automation_list(AutomationList *al)
        automation_lists[al->id()] = al;
 }
 
-void
-Session::sync_order_keys (RouteSortOrderKey base)
-{
-       if (deletion_in_progress()) {
-               return;
-       }
-
-       if (!Config->get_sync_all_route_ordering()) {
-               /* leave order keys as they are */
-               return;
-       }
-
-       boost::shared_ptr<RouteList> r = routes.reader ();
-
-       for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-               (*i)->sync_order_keys (base);
-       }
-
-       Route::SyncOrderKeys (base); // EMIT SIGNAL
-}
-
 /** @return true if there is at least one record-enabled track, otherwise false */
 bool
 Session::have_rec_enabled_track () const
@@ -4268,13 +4263,6 @@ Session::add_session_range_location (framepos_t start, framepos_t end)
        _locations->add (_session_range_location);
 }
 
-/** Called when one of our routes' order keys has changed */
-void
-Session::route_order_key_changed ()
-{
-       RouteOrderKeyChanged (); /* EMIT SIGNAL */
-}
-
 void
 Session::step_edit_status_change (bool yn)
 {
@@ -4694,30 +4682,41 @@ Session::next_control_id () const
 {
        int subtract = 0;
 
-       /* the master and monitor bus remote ID's occupy a different
-        * "namespace" than regular routes. their existence doesn't
+       /* the monitor bus remote ID is in a different
+        * "namespace" than regular routes. its existence doesn't
         * affect normal (low) numbered routes.
         */
 
-       if (_master_out) {
+       if (_monitor_out) {
                subtract++;
        }
 
-       if (_monitor_out) {
-               subtract++;
+       return nroutes() - subtract;
+}
+
+void
+Session::sync_order_keys (RouteSortOrderKey sort_key_changed)
+{
+       if (deletion_in_progress()) {
+               return;
        }
 
-       /* remote control IDs are based either on this
-          value, or signal order, which is zero-based. so we have
-          to ensure consistency of zero-based-ness for both
-          sources of the number.
-          
-          we actually add 1 to the value to form an actual
-          remote control ID, which is 1-based.
+       switch (Config->get_remote_model()) {
+       case MixerSort:
+       case EditorSort:
+               Route::RemoteControlIDChange (); /* EMIT SIGNAL */
+               break;
+       default:
+               break;
+       }
+
+       /* tell everyone that something has happened to the sort keys
+          and let them sync up with the change(s)
        */
 
-       cerr << "Next control ID will be " << ntracks() + (nbusses() - subtract) << endl;
-       return ntracks() + (nbusses() - subtract);
+       DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("Sync Order Keys, based on %1\n", enum_2_string (sort_key_changed)));
+
+       Route::SyncOrderKeys (sort_key_changed); /* EMIT SIGNAL */
 }
 
 bool
index 40cb364d732e865a1bcb14e56cf8029458f4d14c..da6f618c117cce0d8ca5b050416b16b0211cc807 100644 (file)
@@ -3060,13 +3060,11 @@ Session::controllable_by_descriptor (const ControllableDescriptor& desc)
        }
 
        case ControllableDescriptor::RemoteControlID:
-               cerr << "RID " << desc.rid() << endl;
                r = route_by_remote_id (desc.rid());
                break;
        }
 
        if (!r) {
-               cerr << "no controllable with no route\n";
                return c;
        }
 
@@ -3149,16 +3147,12 @@ Session::controllable_by_descriptor (const ControllableDescriptor& desc)
                        --send;
                }
 
-               cerr << "Look for send " << send << endl;
-
                boost::shared_ptr<Processor> p = r->nth_send (send);
 
                if (p) {
                        boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
                        boost::shared_ptr<Amp> a = s->amp();
                        
-                       cerr << " looked for send " << send << " got " << s << " amp = " << a << endl;
-
                        if (a) {
                                c = s->amp()->gain_control();
                        }
@@ -3513,7 +3507,7 @@ Session::config_changed (std::string p, bool ours)
        } else if (p == "history-depth") {
                set_history_depth (Config->get_history_depth());
        } else if (p == "sync-all-route-ordering") {
-               sync_order_keys (UndefinedSort);
+               /* XXX sync_order_keys (UndefinedSort); */
        } else if (p == "initial-program-change") {
 
                if (MIDI::Manager::instance()->mmc()->output_port() && Config->get_initial_program_change() >= 0) {