diff options
-rw-r--r-- | gtk2_ardour/ardour_ui.cc | 2 | ||||
-rw-r--r-- | gtk2_ardour/au_pluginui.mm | 7 | ||||
-rw-r--r-- | gtk2_ardour/editor.cc | 7 | ||||
-rw-r--r-- | gtk2_ardour/editor.h | 2 | ||||
-rw-r--r-- | gtk2_ardour/editor_group_tabs.cc | 2 | ||||
-rw-r--r-- | gtk2_ardour/editor_routes.cc | 304 | ||||
-rw-r--r-- | gtk2_ardour/editor_routes.h | 12 | ||||
-rw-r--r-- | gtk2_ardour/mixer_group_tabs.cc | 2 | ||||
-rw-r--r-- | gtk2_ardour/mixer_ui.cc | 414 | ||||
-rw-r--r-- | gtk2_ardour/mixer_ui.h | 10 | ||||
-rw-r--r-- | gtk2_ardour/port_matrix.cc | 16 | ||||
-rw-r--r-- | gtk2_ardour/port_matrix.h | 2 | ||||
-rw-r--r-- | gtk2_ardour/route_ui.cc | 7 | ||||
-rw-r--r-- | libs/ardour/ardour/debug.h | 1 | ||||
-rw-r--r-- | libs/ardour/ardour/route.h | 11 | ||||
-rw-r--r-- | libs/ardour/ardour/session.h | 4 | ||||
-rw-r--r-- | libs/ardour/ardour/types.h | 1 | ||||
-rw-r--r-- | libs/ardour/debug.cc | 1 | ||||
-rw-r--r-- | libs/ardour/enums.cc | 2 | ||||
-rw-r--r-- | libs/ardour/route.cc | 124 | ||||
-rw-r--r-- | libs/ardour/session.cc | 89 | ||||
-rw-r--r-- | libs/ardour/session_state.cc | 8 |
22 files changed, 537 insertions, 491 deletions
diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 8b90b2d5b8..96e309ed01 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -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()) { diff --git a/gtk2_ardour/au_pluginui.mm b/gtk2_ardour/au_pluginui.mm index 359b32478a..0433d2502d 100644 --- a/gtk2_ardour/au_pluginui.mm +++ b/gtk2_ardour/au_pluginui.mm @@ -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 ]; diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 9daf72c589..f33dda2dac 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -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; } diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 23da8d7c6d..9408b27f8f 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -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; diff --git a/gtk2_ardour/editor_group_tabs.cc b/gtk2_ardour/editor_group_tabs.cc index 5a1e9c8aaa..cb85544669 100644 --- a/gtk2_ardour/editor_group_tabs.cc +++ b/gtk2_ardour/editor_group_tabs.cc @@ -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 (); } diff --git a/gtk2_ardour/editor_routes.cc b/gtk2_ardour/editor_routes.cc index 3faeba183f..d8aec33007 100644 --- a/gtk2_ardour/editor_routes.cc +++ b/gtk2_ardour/editor_routes.cc @@ -24,6 +24,16 @@ #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" @@ -38,15 +48,6 @@ #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,49 +1252,33 @@ 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, const SelectionData& data, @@ -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; +} diff --git a/gtk2_ardour/editor_routes.h b/gtk2_ardour/editor_routes.h index 00631d914a..cbe9825cb5 100644 --- a/gtk2_ardour/editor_routes.h +++ b/gtk2_ardour/editor_routes.h @@ -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; diff --git a/gtk2_ardour/mixer_group_tabs.cc b/gtk2_ardour/mixer_group_tabs.cc index 60a625c96d..f3121a5ca9 100644 --- a/gtk2_ardour/mixer_group_tabs.cc +++ b/gtk2_ardour/mixer_group_tabs.cc @@ -192,5 +192,5 @@ MixerGroupTabs::selected_routes () const void MixerGroupTabs::sync_order_keys () { - _mixer->sync_order_keys (UndefinedSort); + _mixer->sync_order_keys_from_model (); } diff --git a/gtk2_ardour/mixer_ui.cc b/gtk2_ardour/mixer_ui.cc index 5034243680..17d37fa5fb 100644 --- a/gtk2_ardour/mixer_ui.cc +++ b/gtk2_ardour/mixer_ui.cc @@ -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)); diff --git a/gtk2_ardour/mixer_ui.h b/gtk2_ardour/mixer_ui.h index f3d7845461..ab0223aa4d 100644 --- a/gtk2_ardour/mixer_ui.h +++ b/gtk2_ardour/mixer_ui.h @@ -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); diff --git a/gtk2_ardour/port_matrix.cc b/gtk2_ardour/port_matrix.cc index 40c48b2345..8db2dad475 100644 --- a/gtk2_ardour/port_matrix.cc +++ b/gtk2_ardour/port_matrix.cc @@ -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 diff --git a/gtk2_ardour/port_matrix.h b/gtk2_ardour/port_matrix.h index 76ead4bee9..2b5e9ce31d 100644 --- a/gtk2_ardour/port_matrix.h +++ b/gtk2_ardour/port_matrix.h @@ -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; diff --git a/gtk2_ardour/route_ui.cc b/gtk2_ardour/route_ui.cc index b6c81717a2..536b4f110b 100644 --- a/gtk2_ardour/route_ui.cc +++ b/gtk2_ardour/route_ui.cc @@ -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); } diff --git a/libs/ardour/ardour/debug.h b/libs/ardour/ardour/debug.h index b9ecabd309..5c72c9236f 100644 --- a/libs/ardour/ardour/debug.h +++ b/libs/ardour/ardour/debug.h @@ -59,6 +59,7 @@ namespace PBD { extern uint64_t Layering; extern uint64_t TempoMath; extern uint64_t TempoMap; + extern uint64_t OrderKeys; } } diff --git a/libs/ardour/ardour/route.h b/libs/ardour/ardour/route.h index a15937377e..695e151dbb 100644 --- a/libs/ardour/ardour/route.h +++ b/libs/ardour/ardour/route.h @@ -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; diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 518a99d961..a132a4a5e8 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -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; diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index 713e35ebab..595ee38369 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -352,7 +352,6 @@ namespace ARDOUR { }; enum RouteSortOrderKey { - UndefinedSort, EditorSort, MixerSort }; diff --git a/libs/ardour/debug.cc b/libs/ardour/debug.cc index a0fc09a2ad..db0f409d11 100644 --- a/libs/ardour/debug.cc +++ b/libs/ardour/debug.cc @@ -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"); diff --git a/libs/ardour/enums.cc b/libs/ardour/enums.cc index 1ef9047f57..042b10adb5 100644 --- a/libs/ardour/enums.cc +++ b/libs/ardour/enums.cc @@ -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); diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index 62bb2d0933..2112336d8b 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -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 (); } } diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 9dacdc34cb..062d07ec26 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -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 diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 40cb364d73..da6f618c11 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -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) { |