summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gtk2_ardour/ardour_ui.cc2
-rw-r--r--gtk2_ardour/au_pluginui.mm7
-rw-r--r--gtk2_ardour/editor.cc7
-rw-r--r--gtk2_ardour/editor.h2
-rw-r--r--gtk2_ardour/editor_group_tabs.cc2
-rw-r--r--gtk2_ardour/editor_routes.cc304
-rw-r--r--gtk2_ardour/editor_routes.h12
-rw-r--r--gtk2_ardour/mixer_group_tabs.cc2
-rw-r--r--gtk2_ardour/mixer_ui.cc414
-rw-r--r--gtk2_ardour/mixer_ui.h10
-rw-r--r--gtk2_ardour/port_matrix.cc16
-rw-r--r--gtk2_ardour/port_matrix.h2
-rw-r--r--gtk2_ardour/route_ui.cc7
-rw-r--r--libs/ardour/ardour/debug.h1
-rw-r--r--libs/ardour/ardour/route.h11
-rw-r--r--libs/ardour/ardour/session.h4
-rw-r--r--libs/ardour/ardour/types.h1
-rw-r--r--libs/ardour/debug.cc1
-rw-r--r--libs/ardour/enums.cc2
-rw-r--r--libs/ardour/route.cc124
-rw-r--r--libs/ardour/session.cc89
-rw-r--r--libs/ardour/session_state.cc8
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) {