From 11415b49be02f16495c95d6286c485ac8afc5189 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Wed, 27 Jun 2012 22:57:06 +0000 Subject: first pass at the big rethink of managing sort order keys for editor and mixer. this appears to work, but remote control IDs are not yet correct (frequently off by one because of the presence of the master bus in the editor) git-svn-id: svn://localhost/ardour2/branches/3.0@12953 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/ardour_ui.cc | 2 - gtk2_ardour/au_pluginui.mm | 7 +- gtk2_ardour/editor.cc | 7 +- gtk2_ardour/editor.h | 2 +- gtk2_ardour/editor_group_tabs.cc | 2 +- gtk2_ardour/editor_routes.cc | 304 ++++++++++++++++------------ gtk2_ardour/editor_routes.h | 12 +- gtk2_ardour/mixer_group_tabs.cc | 2 +- gtk2_ardour/mixer_ui.cc | 414 +++++++++++++++++++++------------------ gtk2_ardour/mixer_ui.h | 10 +- gtk2_ardour/port_matrix.cc | 16 +- gtk2_ardour/port_matrix.h | 2 +- gtk2_ardour/route_ui.cc | 7 +- 13 files changed, 438 insertions(+), 349 deletions(-) (limited to 'gtk2_ardour') 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 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 = (*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 #include +#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 = (*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 routes) { TreeModel::Row row; - _redisplay_does_not_sync_order_keys = true; suspend_redisplay (); for (list::iterator x = routes.begin(); x != routes.end(); ++x) { @@ -685,7 +661,10 @@ EditorRoutes::routes_added (list 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 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 = (*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 co; - for (map::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 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 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 = (*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 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 const &, TreeModel::Path struct EditorOrderRouteSorter { bool operator() (boost::shared_ptr a, boost::shared_ptr 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 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(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& 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::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::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 = (*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 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 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 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 #include @@ -36,6 +38,7 @@ #include #include +#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 = (*x); - - if (route->is_hidden()) { - continue; - } - - if (route->is_monitor()) { - - if (!_monitor_section) { - _monitor_section = new MonitorSection (_session); + { + Unwinder uw (no_track_list_redisplay, true); + + for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) { + boost::shared_ptr 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 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 = (*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 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 neworder; - for (std::map::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 = (*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 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 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 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 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 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 a, boost::shared_ptr 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 uw1 (no_track_list_redisplay, true); + Unwinder 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(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); @@ -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, uint32_t, int); void disassociate_all_on_bundle (boost::weak_ptr, 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 io_from_bundle (boost::shared_ptr) 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" "Use the User Interaction tab of the Preferences window if you want to change this"), - (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); } -- cgit v1.2.3