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
This commit is contained in:
Paul Davis 2012-06-27 22:57:06 +00:00
parent 5ba1996fd7
commit 11415b49be
22 changed files with 555 additions and 509 deletions

View file

@ -3142,8 +3142,6 @@ ARDOUR_UI::add_route (Gtk::Window* float_window)
output_chan = input_chan; output_chan = input_chan;
} }
cerr << "ARD said " << input_chan << " and " << output_chan << endl;
/* XXX do something with name template */ /* XXX do something with name template */
switch (add_route_dialog->type_wanted()) { switch (add_route_dialog->type_wanted()) {

View file

@ -568,12 +568,13 @@ AUPluginUI::parent_carbon_window ()
int packing_extra = 6; // this is the total vertical packing in our top level 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 // create the cocoa window for the carbon one and make it visible
cocoa_parent = [[NSWindow alloc] initWithWindowRef: carbon_window]; 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); SetWindowActivationScope (carbon_window, kWindowActivationScopeNone);
_notify = [ [NotificationObject alloc] initWithPluginUI:this andCocoaParent:cocoa_parent andTopLevelParent:win ]; _notify = [ [NotificationObject alloc] initWithPluginUI:this andCocoaParent:cocoa_parent andTopLevelParent:win ];

View file

@ -1271,7 +1271,7 @@ Editor::set_session (Session *t)
_session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context()); _session->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->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->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->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->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()); _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; return t;
} }
void void
Editor::handle_new_route (RouteList& routes) Editor::add_routes (RouteList& routes)
{ {
ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, 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) { for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
boost::shared_ptr<Route> route = (*x); boost::shared_ptr<Route> route = (*x);
if (route->is_hidden() || route->is_monitor()) { if (route->is_hidden()) {
continue; continue;
} }

View file

@ -704,7 +704,7 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
void popup_control_point_context_menu (ArdourCanvas::Item *, GdkEvent *); void popup_control_point_context_menu (ArdourCanvas::Item *, GdkEvent *);
Gtk::Menu _control_point_context_menu; Gtk::Menu _control_point_context_menu;
void handle_new_route (ARDOUR::RouteList&); void add_routes (ARDOUR::RouteList&);
void timeaxisview_deleted (TimeAxisView *); void timeaxisview_deleted (TimeAxisView *);
Gtk::HBox global_hpacker; Gtk::HBox global_hpacker;

View file

@ -201,5 +201,5 @@ EditorGroupTabs::selected_routes () const
void void
EditorGroupTabs::sync_order_keys () EditorGroupTabs::sync_order_keys ()
{ {
_editor->_routes->sync_order_keys (UndefinedSort); _editor->_routes->sync_order_keys_from_model ();
} }

View file

@ -24,6 +24,16 @@
#include <cmath> #include <cmath>
#include <cassert> #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 "ardour/session.h"
#include "editor.h" #include "editor.h"
@ -38,15 +48,6 @@
#include "editor_group_tabs.h" #include "editor_group_tabs.h"
#include "editor_routes.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" #include "i18n.h"
using namespace std; using namespace std;
@ -67,9 +68,7 @@ EditorRoutes::EditorRoutes (Editor* e)
: EditorComponent (e) : EditorComponent (e)
, _ignore_reorder (false) , _ignore_reorder (false)
, _no_redisplay (false) , _no_redisplay (false)
, _redisplay_does_not_sync_order_keys (false) , _menu (0)
, _redisplay_does_not_reset_order_keys (false)
,_menu (0)
, old_focus (0) , old_focus (0)
, selection_countdown (0) , selection_countdown (0)
, name_editable (0) , name_editable (0)
@ -282,7 +281,7 @@ EditorRoutes::EditorRoutes (Editor* e)
_display.set_enable_search (false); _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 bool
@ -502,12 +501,7 @@ EditorRoutes::redisplay ()
*/ */
int n; int n;
/* Order keys must not take children into account, so use a separate counter for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
for that.
*/
int order_key;
for (n = 0, order_key = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
TimeAxisView *tv = (*i)[_columns.tv]; TimeAxisView *tv = (*i)[_columns.tv];
boost::shared_ptr<Route> route = (*i)[_columns.route]; boost::shared_ptr<Route> route = (*i)[_columns.route];
@ -516,20 +510,6 @@ EditorRoutes::redisplay ()
continue; 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 (); bool visible = tv->marked_for_display ();
/* show or hide the TimeAxisView */ /* show or hide the TimeAxisView */
@ -561,23 +541,23 @@ EditorRoutes::redisplay ()
*/ */
_editor->vertical_adjustment.set_value (_editor->full_canvas_height - _editor->_canvas_height); _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 void
EditorRoutes::route_deleted (Gtk::TreeModel::Path const &) EditorRoutes::route_deleted (Gtk::TreeModel::Path const &)
{ {
if (!_session || _session->deletion_in_progress()) { /* this happens as the second step of a DnD within the treeview as well
return; 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 */ void
_ignore_reorder = true; EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
redisplay (); {
_ignore_reorder = false; DEBUG_TRACE (DEBUG::OrderKeys, "editor routes treeview reordered\n");
sync_order_keys_from_model ();
} }
void void
@ -595,10 +575,7 @@ EditorRoutes::visible_changed (std::string const & path)
bool visible = (*iter)[_columns.visible]; bool visible = (*iter)[_columns.visible];
if (tv->set_marked_for_display (!visible)) { if (tv->set_marked_for_display (!visible)) {
_redisplay_does_not_reset_order_keys = true;
update_visibility (); update_visibility ();
redisplay ();
_redisplay_does_not_reset_order_keys = false;
} }
} }
} }
@ -622,7 +599,6 @@ EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
{ {
TreeModel::Row row; TreeModel::Row row;
_redisplay_does_not_sync_order_keys = true;
suspend_redisplay (); suspend_redisplay ();
for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) { 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_input_active_display ();
update_active_display (); update_active_display ();
resume_redisplay (); 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 void
@ -714,12 +693,6 @@ EditorRoutes::route_removed (TimeAxisView *tv)
TreeModel::Children rows = _model->children(); TreeModel::Children rows = _model->children();
TreeModel::Children::iterator ri; 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) { for (ri = rows.begin(); ri != rows.end(); ++ri) {
if ((*ri)[_columns.tv] == tv) { if ((*ri)[_columns.tv] == tv) {
_model->erase (ri); _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 void
@ -782,6 +757,11 @@ EditorRoutes::update_visibility ()
(*i)[_columns.visible] = tv->marked_for_display (); (*i)[_columns.visible] = tv->marked_for_display ();
} }
/* force route order keys catch up with visibility changes
*/
sync_order_keys_from_model ();
resume_redisplay (); resume_redisplay ();
} }
@ -819,57 +799,109 @@ EditorRoutes::show_track_in_display (TimeAxisView& tv)
} }
void 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()) {
}
/** 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()) {
return; return;
} }
TreeModel::Children rows = _model->children();
if (rows.empty()) {
return;
}
DEBUG_TRACE (DEBUG::OrderKeys, "editor sync order keys from model\n");
TreeModel::Children::iterator ri;
bool changed = false; 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]; boost::shared_ptr<Route> route = (*ri)[_columns.route];
bool visible = (*ri)[_columns.visible];
int const old_key = order; uint32_t old_key = route->order_key (EditorSort);
int const new_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; changed = true;
} }
order++;
} }
if (changed) { if (changed) {
_redisplay_does_not_reset_order_keys = true; /* tell the world that we changed the editor sort keys */
_session->sync_order_keys (EditorSort);
/* `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);
}
assert (co.size() == _model->children().size ());
_model->reorder (co);
_redisplay_does_not_reset_order_keys = false;
} }
} }
void
EditorRoutes::sync_model_from_order_keys (RouteSortOrderKey src)
{
if (!_session || _session->deletion_in_progress()) {
return;
}
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;
}
DEBUG_TRACE (DEBUG::OrderKeys, "reset editor order key to match mixer\n");
/* 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 void
EditorRoutes::hide_all_tracks (bool /*with_select*/) EditorRoutes::hide_all_tracks (bool /*with_select*/)
@ -920,6 +952,11 @@ EditorRoutes::set_all_tracks_visibility (bool yn)
(*i)[_columns.visible] = yn; (*i)[_columns.visible] = yn;
} }
/* force route order keys catch up with visibility changes
*/
sync_order_keys_from_model ();
resume_redisplay (); 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 (); resume_redisplay ();
} }
@ -1187,7 +1229,13 @@ EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path
struct EditorOrderRouteSorter { struct EditorOrderRouteSorter {
bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) { 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); return a->order_key (EditorSort) < b->order_key (EditorSort);
} }
}; };
@ -1204,48 +1252,32 @@ EditorRoutes::initial_display ()
} }
boost::shared_ptr<RouteList> routes = _session->get_routes(); 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 ()) { if (ARDOUR_UI::instance()->session_is_new ()) {
TreeModel::Children rows = _model->children(); /* new session: stamp all routes with the right editor order
TreeModel::Children::iterator i; * key
*/
_no_redisplay = true; _editor->add_routes (*(routes.get()));
for (i = rows.begin(); i != rows.end(); ++i) { } else {
TimeAxisView *tv = (*i)[_columns.tv]; /* existing session: sort a copy of the route list by
RouteTimeAxisView *rtv; * editor-order and add its contents to the display.
*/
if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) { RouteList r (*routes);
if (rtv->route()->is_master()) { EditorOrderRouteSorter sorter;
_display.get_selection()->unselect (i);
} r.sort (sorter);
} _editor->add_routes (r);
}
_no_redisplay = false;
redisplay ();
} }
resume_redisplay (); 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 void
EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context, EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
int x, int y, int x, int y,
@ -1364,18 +1396,26 @@ EditorRoutes::move_selected_tracks (bool up)
} }
for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) { 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 #ifndef NDEBUG
DEBUG_TRACE (DEBUG::OrderKeys, "New order after moving tracks:\n");
for (vector<int>::iterator i = neworder.begin(); i != neworder.end(); ++i) { 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 ()); assert (*i < (int) neworder.size ());
} }
#endif #endif
_model->reorder (neworder); _model->reorder (neworder);
_session->sync_order_keys (EditorSort);
} }
void void
@ -1554,3 +1594,27 @@ EditorRoutes::show_tracks_with_regions_at_playhead ()
resume_redisplay (); 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;
}

View file

@ -42,6 +42,10 @@ public:
_no_redisplay = true; _no_redisplay = true;
} }
void allow_redisplay () {
_no_redisplay = false;
}
void resume_redisplay () { void resume_redisplay () {
_no_redisplay = false; _no_redisplay = false;
redisplay (); redisplay ();
@ -55,8 +59,8 @@ public:
std::list<TimeAxisView*> views () const; std::list<TimeAxisView*> views () const;
void hide_all_tracks (bool); void hide_all_tracks (bool);
void clear (); void clear ();
void sync_order_keys (ARDOUR::RouteSortOrderKey); uint32_t count_displayed_non_special_routes () const;
void sync_order_keys_from_model ();
private: private:
void initial_display (); void initial_display ();
@ -68,6 +72,7 @@ private:
void on_tv_solo_safe_toggled (std::string const &); void on_tv_solo_safe_toggled (std::string const &);
void build_menu (); void build_menu ();
void show_menu (); void show_menu ();
void sync_model_from_order_keys (ARDOUR::RouteSortOrderKey);
void route_deleted (Gtk::TreeModel::Path const &); void route_deleted (Gtk::TreeModel::Path const &);
void visible_changed (std::string const &); void visible_changed (std::string const &);
void active_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 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); bool selection_filter (Glib::RefPtr<Gtk::TreeModel> const &, Gtk::TreeModel::Path const &, bool);
void name_edit (std::string const &, std::string const &); void name_edit (std::string const &, std::string const &);
void solo_changed_so_update_mute (); void solo_changed_so_update_mute ();
@ -150,8 +154,6 @@ private:
bool _ignore_reorder; bool _ignore_reorder;
bool _no_redisplay; bool _no_redisplay;
bool _redisplay_does_not_sync_order_keys;
bool _redisplay_does_not_reset_order_keys;
Gtk::Menu* _menu; Gtk::Menu* _menu;
Gtk::Widget* old_focus; Gtk::Widget* old_focus;

View file

@ -192,5 +192,5 @@ MixerGroupTabs::selected_routes () const
void void
MixerGroupTabs::sync_order_keys () MixerGroupTabs::sync_order_keys ()
{ {
_mixer->sync_order_keys (UndefinedSort); _mixer->sync_order_keys_from_model ();
} }

View file

@ -29,6 +29,8 @@
#include "pbd/convert.h" #include "pbd/convert.h"
#include "pbd/stacktrace.h" #include "pbd/stacktrace.h"
#include "pbd/unwind.h"
#include <glibmm/thread.h> #include <glibmm/thread.h>
#include <gtkmm2ext/gtk_ui.h> #include <gtkmm2ext/gtk_ui.h>
@ -36,6 +38,7 @@
#include <gtkmm2ext/tearoff.h> #include <gtkmm2ext/tearoff.h>
#include <gtkmm2ext/window_title.h> #include <gtkmm2ext/window_title.h>
#include "ardour/debug.h"
#include "ardour/plugin_manager.h" #include "ardour/plugin_manager.h"
#include "ardour/route_group.h" #include "ardour/route_group.h"
#include "ardour/session.h" #include "ardour/session.h"
@ -63,6 +66,7 @@ using namespace Gtkmm2ext;
using namespace std; using namespace std;
using PBD::atoi; using PBD::atoi;
using PBD::Unwinder;
Mixer_UI* Mixer_UI::_instance = 0; Mixer_UI* Mixer_UI::_instance = 0;
@ -78,22 +82,19 @@ Mixer_UI::instance ()
Mixer_UI::Mixer_UI () Mixer_UI::Mixer_UI ()
: Window (Gtk::WINDOW_TOPLEVEL) : 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) , _following_editor_selection (false)
{ {
/* allow this window to become the key focus window */ /* allow this window to become the key focus window */
set_flags (CAN_FOCUS); set_flags (CAN_FOCUS);
_strip_width = Config->get_default_narrow_ms() ? Narrow : Wide; Route::SyncOrderKeys.connect (*this, invalidator (*this), boost::bind (&Mixer_UI::sync_model_from_order_keys, this, _1), gui_context());
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());
scroller_base.set_flags (Gtk::CAN_FOCUS); scroller_base.set_flags (Gtk::CAN_FOCUS);
scroller_base.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK); scroller_base.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
@ -305,70 +306,68 @@ Mixer_UI::hide_window (GdkEventAny *ev)
void void
Mixer_UI::add_strip (RouteList& routes) Mixer_UI::add_strips (RouteList& routes)
{ {
MixerStrip* strip; MixerStrip* strip;
no_track_list_redisplay = true; {
strip_redisplay_does_not_sync_order_keys = true; Unwinder<bool> uw (no_track_list_redisplay, true);
for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) { for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
boost::shared_ptr<Route> route = (*x); boost::shared_ptr<Route> route = (*x);
if (route->is_hidden()) { if (route->is_hidden()) {
continue; continue;
} }
if (route->is_monitor()) { if (route->is_monitor()) {
if (!_monitor_section) { if (!_monitor_section) {
_monitor_section = new MonitorSection (_session); _monitor_section = new MonitorSection (_session);
XMLNode* mnode = ARDOUR_UI::instance()->tearoff_settings (X_("monitor-section")); XMLNode* mnode = ARDOUR_UI::instance()->tearoff_settings (X_("monitor-section"));
if (mnode) { if (mnode) {
_monitor_section->tearoff().set_state (*mnode); _monitor_section->tearoff().set_state (*mnode);
}
} }
}
out_packer.pack_end (_monitor_section->tearoff(), false, false); out_packer.pack_end (_monitor_section->tearoff(), false, false);
_monitor_section->set_session (_session); _monitor_section->set_session (_session);
_monitor_section->tearoff().show_all (); _monitor_section->tearoff().show_all ();
route->DropReferences.connect (*this, invalidator(*this), boost::bind (&Mixer_UI::monitor_section_going_away, this), gui_context()); route->DropReferences.connect (*this, invalidator(*this), boost::bind (&Mixer_UI::monitor_section_going_away, this), gui_context());
/* no regular strip shown for control out */ /* no regular strip shown for control out */
continue; continue;
} }
strip = new MixerStrip (*this, _session, route); strip = new MixerStrip (*this, _session, route);
strips.push_back (strip); strips.push_back (strip);
Config->get_default_narrow_ms() ? _strip_width = Narrow : _strip_width = Wide; Config->get_default_narrow_ms() ? _strip_width = Narrow : _strip_width = Wide;
if (strip->width_owner() != strip) { if (strip->width_owner() != strip) {
strip->set_width_enum (_strip_width, this); 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 (); redisplay_track_list ();
strip_redisplay_does_not_sync_order_keys = false;
} }
void void
@ -387,62 +386,117 @@ Mixer_UI::remove_strip (MixerStrip* strip)
strips.erase (i); strips.erase (i);
} }
strip_redisplay_does_not_sync_order_keys = true;
for (ri = rows.begin(); ri != rows.end(); ++ri) { for (ri = rows.begin(); ri != rows.end(); ++ri) {
if ((*ri)[track_columns.strip] == strip) { if ((*ri)[track_columns.strip] == strip) {
track_model->erase (ri); track_model->erase (ri);
break; break;
} }
} }
strip_redisplay_does_not_sync_order_keys = false;
} }
void void
Mixer_UI::sync_order_keys (RouteSortOrderKey src) Mixer_UI::sync_order_keys_from_model ()
{ {
TreeModel::Children rows = track_model->children(); if (ignore_reorder || !_session || _session->deletion_in_progress()) {
TreeModel::Children::iterator ri;
if (src == MixerSort || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
return; return;
} }
std::map<int,int> keys; TreeModel::Children rows = track_model->children();
if (rows.empty()) {
return;
}
DEBUG_TRACE (DEBUG::OrderKeys, "mixer sync order keys from model\n");
TreeModel::Children::iterator ri;
bool changed = false; bool changed = false;
uint32_t order = 0;
unsigned order = 0; for (ri = rows.begin(); ri != rows.end(); ++ri) {
for (ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
boost::shared_ptr<Route> route = (*ri)[track_columns.route]; boost::shared_ptr<Route> route = (*ri)[track_columns.route];
unsigned int old_key = order; bool visible = (*ri)[track_columns.visible];
unsigned int new_key = route->order_key (MixerSort);
keys[new_key] = old_key; uint32_t old_key = route->order_key (MixerSort);
uint32_t new_key;
if (new_key != old_key) { if (!visible) {
new_key = UINT_MAX;
} else {
new_key = order;
}
if (old_key != new_key) {
route->set_order_key (MixerSort, new_key);
changed = true; changed = true;
} }
order++;
}
if (changed) {
/* tell everyone that we changed the mixer sort keys */
_session->sync_order_keys (MixerSort);
}
}
void
Mixer_UI::sync_model_from_order_keys (RouteSortOrderKey src)
{
if (!_session || _session->deletion_in_progress()) {
return;
}
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);
}
} }
if (keys.size() != rows.size()) { /* we could get here after either a change in the Mixer or Editor sort
PBD::stacktrace (cerr, 20); * order, but either way, the mixer order keys reflect the intended
} * order for the GUI, so reorder the treeview model to match it.
assert(keys.size() == rows.size()); */
// Remove any gaps in keys caused by automation children tracks
vector<int> neworder; vector<int> neworder;
for (std::map<int,int>::const_iterator i = keys.begin(); i != keys.end(); ++i) { TreeModel::Children rows = track_model->children();
neworder.push_back(i->second); uint32_t n = 0;
}
assert(neworder.size() == rows.size());
if (changed) { if (rows.empty()) {
strip_redisplay_does_not_reset_order_keys = true; return;
track_model->reorder (neworder);
strip_redisplay_does_not_reset_order_keys = false;
} }
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);
}
redisplay_track_list ();
} }
void void
@ -573,7 +627,7 @@ Mixer_UI::set_session (Session* sess)
initial_track_display (); 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_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_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()); _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 rows = track_model->children();
TreeModel::Children::iterator i; TreeModel::Children::iterator i;
no_track_list_redisplay = true; {
Unwinder<bool> uw (no_track_list_redisplay, true);
for (i = rows.begin(); i != rows.end(); ++i) { for (i = rows.begin(); i != rows.end(); ++i) {
TreeModel::Row row = (*i); TreeModel::Row row = (*i);
MixerStrip* strip = row[track_columns.strip]; MixerStrip* strip = row[track_columns.strip];
if (strip == 0) { if (strip == 0) {
continue; continue;
}
if (strip->route()->is_master() || strip->route()->is_monitor()) {
continue;
}
(*i)[track_columns.visible] = yn;
} }
if (strip->route()->is_master() || strip->route()->is_monitor()) {
continue;
}
(*i)[track_columns.visible] = yn;
} }
no_track_list_redisplay = false;
redisplay_track_list (); 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 rows = track_model->children();
TreeModel::Children::iterator i; TreeModel::Children::iterator i;
no_track_list_redisplay = true; {
Unwinder<bool> uw (no_track_list_redisplay, true);
for (i = rows.begin(); i != rows.end(); ++i) { for (i = rows.begin(); i != rows.end(); ++i) {
TreeModel::Row row = (*i); TreeModel::Row row = (*i);
MixerStrip* strip = row[track_columns.strip]; MixerStrip* strip = row[track_columns.strip];
if (strip == 0) { if (strip == 0) {
continue; 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;
} }
break;
case 2: if (strip->route()->is_master() || strip->route()->is_monitor()) {
if (!at) { /* bus */ continue;
(*i)[track_columns.visible] = yn; }
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 (); redisplay_track_list ();
} }
@ -795,27 +851,18 @@ Mixer_UI::hide_all_audiotracks ()
void void
Mixer_UI::track_list_reorder (const TreeModel::Path&, const TreeModel::iterator&, int* /*new_order*/) Mixer_UI::track_list_reorder (const TreeModel::Path&, const TreeModel::iterator&, int* /*new_order*/)
{ {
strip_redisplay_does_not_sync_order_keys = true; DEBUG_TRACE (DEBUG::OrderKeys, "mixer UI treeview reordered\n");
redisplay_track_list (); sync_order_keys_from_model ();
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;
} }
void void
Mixer_UI::track_list_delete (const Gtk::TreeModel::Path&) Mixer_UI::track_list_delete (const Gtk::TreeModel::Path&)
{ {
/* this could require an order sync */ /* this happens as the second step of a DnD within the treeview as well
if (_session && !_session->deletion_in_progress()) { as when a row/route is actually deleted.
redisplay_track_list (); */
} DEBUG_TRACE (DEBUG::OrderKeys, "mixer UI treeview row deleted\n");
sync_order_keys_from_model ();
} }
void void
@ -823,8 +870,6 @@ Mixer_UI::redisplay_track_list ()
{ {
TreeModel::Children rows = track_model->children(); TreeModel::Children rows = track_model->children();
TreeModel::Children::iterator i; TreeModel::Children::iterator i;
long regular_order = 0;
long hidden_order = 999999; // arbitary high number
if (no_track_list_redisplay) { if (no_track_list_redisplay) {
return; return;
@ -849,40 +894,16 @@ Mixer_UI::redisplay_track_list ()
if (strip->route()->is_master() || strip->route()->is_monitor()) { if (strip->route()->is_master() || strip->route()->is_monitor()) {
out_packer.reorder_child (*strip, -1); 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 { } else {
strip_packer.reorder_child (*strip, -1); /* put at end */ 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 { } else {
if (strip->route()->is_master() || strip->route()->is_monitor()) { if (strip->route()->is_master() || strip->route()->is_monitor()) {
out_packer.pack_start (*strip, false, false); 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 { } else {
strip_packer.pack_start (*strip, false, false); 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); strip->set_packed (true);
} }
@ -898,18 +919,10 @@ Mixer_UI::redisplay_track_list ()
strip_packer.remove (*strip); strip_packer.remove (*strip);
strip->set_packed (false); 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 (); _group_tabs->set_dirty ();
} }
@ -942,7 +955,17 @@ Mixer_UI::strip_width_changed ()
struct SignalOrderRouteSorter { struct SignalOrderRouteSorter {
bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) { 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); return a->order_key (MixerSort) < b->order_key (MixerSort);
} }
}; };
@ -955,13 +978,13 @@ Mixer_UI::initial_track_display ()
copy.sort (sorter); copy.sort (sorter);
no_track_list_redisplay = true; {
Unwinder<bool> uw1 (no_track_list_redisplay, true);
Unwinder<bool> uw2 (ignore_reorder, true);
track_model->clear (); track_model->clear ();
add_strips (copy);
add_strip (copy); }
no_track_list_redisplay = false;
redisplay_track_list (); redisplay_track_list ();
} }
@ -1675,7 +1698,6 @@ Mixer_UI::setup_track_display ()
track_display.set_headers_visible (true); 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_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)); 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)); CellRendererToggle* track_list_visible_cell = dynamic_cast<CellRendererToggle*>(track_display.get_column_cell_renderer (1));

View file

@ -130,7 +130,7 @@ class Mixer_UI : public Gtk::Window, public PBD::ScopedConnectionList, public AR
void scroll_left (); void scroll_left ();
void scroll_right (); void scroll_right ();
void add_strip (ARDOUR::RouteList&); void add_strips (ARDOUR::RouteList&);
void remove_strip (MixerStrip *); void remove_strip (MixerStrip *);
MixerStrip* strip_by_route (boost::shared_ptr<ARDOUR::Route>); 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*); bool track_display_button_press (GdkEventButton*);
void strip_width_changed (); 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_delete (const Gtk::TreeModel::Path&);
void track_list_reorder (const Gtk::TreeModel::Path& path, const Gtk::TreeModel::iterator& iter, int* new_order); 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; Width _strip_width;
void sync_order_keys (ARDOUR::RouteSortOrderKey); void sync_order_keys_from_model ();
bool strip_redisplay_does_not_reset_order_keys; void sync_model_from_order_keys (ARDOUR::RouteSortOrderKey);
bool strip_redisplay_does_not_sync_order_keys; bool ignore_reorder;
bool ignore_sync;
void parameter_changed (std::string const &); void parameter_changed (std::string const &);
void set_route_group_activation (ARDOUR::RouteGroup *, bool); void set_route_group_activation (ARDOUR::RouteGroup *, bool);

View file

@ -157,7 +157,7 @@ PortMatrix::init ()
_session->engine().PortRegisteredOrUnregistered.connect (_session_connections, invalidator (*this), boost::bind (&PortMatrix::setup_global_ports, this), gui_context()); _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) */ /* 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 */ /* Part 3: other stuff */
@ -598,13 +598,15 @@ PortMatrix::setup_global_ports ()
} }
void 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 if (sk == EditorSort) {
for a discussion. /* 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)); Glib::signal_idle().connect_once (sigc::mem_fun (*this, &PortMatrix::setup_global_ports));
}
} }
void void

View file

@ -188,7 +188,7 @@ private:
void disassociate_all_on_channel (boost::weak_ptr<ARDOUR::Bundle>, uint32_t, int); 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 disassociate_all_on_bundle (boost::weak_ptr<ARDOUR::Bundle>, int);
void setup_global_ports (); void setup_global_ports ();
void setup_global_ports_proxy (); void setup_global_ports_proxy (ARDOUR::RouteSortOrderKey);
void toggle_show_only_bundles (); void toggle_show_only_bundles ();
bool on_scroll_event (GdkEventScroll *); bool on_scroll_event (GdkEventScroll *);
boost::shared_ptr<ARDOUR::IO> io_from_bundle (boost::shared_ptr<ARDOUR::Bundle>) const; boost::shared_ptr<ARDOUR::IO> io_from_bundle (boost::shared_ptr<ARDOUR::Bundle>) const;

View file

@ -1738,9 +1738,12 @@ RouteUI::open_remote_control_id_dialog ()
dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT); dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
} else { } else {
Label* l = manage (new Label()); 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>"), "<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.get_vbox()->pack_start (*l);
dialog.add_button (Stock::OK, RESPONSE_CANCEL); dialog.add_button (Stock::OK, RESPONSE_CANCEL);
} }

View file

@ -59,6 +59,7 @@ namespace PBD {
extern uint64_t Layering; extern uint64_t Layering;
extern uint64_t TempoMath; extern uint64_t TempoMath;
extern uint64_t TempoMap; extern uint64_t TempoMap;
extern uint64_t OrderKeys;
} }
} }

View file

@ -101,8 +101,10 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
bool set_name (const std::string& str); bool set_name (const std::string& str);
static void set_name_in_state (XMLNode &, const std::string &); static void set_name_in_state (XMLNode &, const std::string &);
int32_t order_key (RouteSortOrderKey) const; uint32_t order_key (RouteSortOrderKey) const;
void set_order_key (RouteSortOrderKey, int32_t); 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_hidden() const { return _flags & Hidden; }
bool is_master() const { return _flags & MasterOut; } 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> meter_change;
PBD::Signal0<void> signal_latency_changed; PBD::Signal0<void> signal_latency_changed;
PBD::Signal0<void> initial_delay_changed; PBD::Signal0<void> initial_delay_changed;
PBD::Signal0<void> order_key_changed;
/** Emitted with the process lock held */ /** Emitted with the process lock held */
PBD::Signal0<void> io_changed; 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 */ /* for things concerned about *any* route's RID changes */
static PBD::Signal0<void> RemoteControlIDChange; static PBD::Signal0<void> RemoteControlIDChange;
void sync_order_keys (RouteSortOrderKey);
static PBD::Signal1<void,RouteSortOrderKey> SyncOrderKeys; static PBD::Signal1<void,RouteSortOrderKey> SyncOrderKeys;
bool has_external_redirects() const; bool has_external_redirects() const;
@ -533,7 +532,7 @@ class Route : public SessionObject, public Automatable, public RouteGroupMember,
static uint32_t order_key_cnt; static uint32_t order_key_cnt;
typedef std::map<RouteSortOrderKey,int32_t> OrderKeys; typedef std::map<RouteSortOrderKey,uint32_t> OrderKeys;
OrderKeys order_keys; OrderKeys order_keys;
uint32_t* _remote_control_id; uint32_t* _remote_control_id;

View file

@ -806,8 +806,6 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
void send_mmc_locate (framepos_t); void send_mmc_locate (framepos_t);
int send_full_time_code (framepos_t); int send_full_time_code (framepos_t);
PBD::Signal0<void> RouteOrderKeyChanged;
bool step_editing() const { return (_step_editors > 0); } bool step_editing() const { return (_step_editors > 0); }
void request_suspend_timecode_transmission (); void request_suspend_timecode_transmission ();
@ -1503,8 +1501,6 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi
void setup_midi_machine_control (); void setup_midi_machine_control ();
void route_order_key_changed ();
void step_edit_status_change (bool); void step_edit_status_change (bool);
uint32_t _step_editors; uint32_t _step_editors;

View file

@ -352,7 +352,6 @@ namespace ARDOUR {
}; };
enum RouteSortOrderKey { enum RouteSortOrderKey {
UndefinedSort,
EditorSort, EditorSort,
MixerSort MixerSort
}; };

View file

@ -56,5 +56,6 @@ uint64_t PBD::DEBUG::MidiTrackers = PBD::new_debug_bit ("miditrackers");
uint64_t PBD::DEBUG::Layering = PBD::new_debug_bit ("layering"); uint64_t PBD::DEBUG::Layering = PBD::new_debug_bit ("layering");
uint64_t PBD::DEBUG::TempoMath = PBD::new_debug_bit ("tempomath"); uint64_t PBD::DEBUG::TempoMath = PBD::new_debug_bit ("tempomath");
uint64_t PBD::DEBUG::TempoMap = PBD::new_debug_bit ("tempomap"); uint64_t PBD::DEBUG::TempoMap = PBD::new_debug_bit ("tempomap");
uint64_t PBD::DEBUG::OrderKeys = PBD::new_debug_bit ("orderkeys");

View file

@ -400,7 +400,7 @@ setup_enum_writer ()
REGISTER_ENUM (MixerSort); REGISTER_ENUM (MixerSort);
REGISTER_ENUM (EditorSort); REGISTER_ENUM (EditorSort);
REGISTER_BITS (_RouteSortOrderKey); REGISTER (_RouteSortOrderKey);
REGISTER_CLASS_ENUM (Source, Writable); REGISTER_CLASS_ENUM (Source, Writable);
REGISTER_CLASS_ENUM (Source, CanRename); REGISTER_CLASS_ENUM (Source, CanRename);

View file

@ -247,116 +247,84 @@ uint32_t
Route::remote_control_id() const Route::remote_control_id() const
{ {
switch (Config->get_remote_model()) { switch (Config->get_remote_model()) {
case MixerOrdered:
return order_key (MixerSort) + 1;
case EditorOrdered:
return order_key (EditorSort) + 1;
case UserOrdered: case UserOrdered:
if (_remote_control_id) { if (_remote_control_id) {
return *_remote_control_id; return *_remote_control_id;
} }
break;
default:
break;
} }
/* fall back to MixerSort as the default */ if (is_master()) {
return MasterBusRemoteControlID;
}
return order_key (MixerSort) + 1; if (is_monitor()) {
return MonitorBusRemoteControlID;
}
/* 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;
}
} }
int32_t bool
Route::has_order_key (RouteSortOrderKey key) const
{
return (order_keys.find (key) != order_keys.end());
}
uint32_t
Route::order_key (RouteSortOrderKey key) const Route::order_key (RouteSortOrderKey key) const
{ {
OrderKeys::const_iterator i = order_keys.find (key); OrderKeys::const_iterator i = order_keys.find (key);
if (i == order_keys.end()) { if (i == order_keys.end()) {
return -1; return 0;
} }
return i->second; return i->second;
} }
void
Route::set_order_key (RouteSortOrderKey key, int32_t n)
{
bool changed = false;
/* 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 (Config->get_sync_all_route_ordering()) {
for (OrderKeys::iterator x = order_keys.begin(); x != order_keys.end(); ++x) {
/* 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()) || x->first != MixerSort) {
if (x->second != n) {
x->second = n;
changed = true;
}
}
}
}
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 void
Route::sync_order_keys (RouteSortOrderKey base) Route::sync_order_keys (RouteSortOrderKey base)
{ {
if (order_keys.empty()) { OrderKeys::iterator i = order_keys.find (base);
if (i == order_keys.end()) {
return; return;
} }
OrderKeys::iterator i; for (OrderKeys::iterator k = order_keys.begin(); k != order_keys.end(); ++k) {
int32_t key;
if ((i = order_keys.find (base)) == order_keys.end()) { if (k->first == MixerSort && (is_master() || is_monitor())) {
/* key doesn't exist, use the first existing key (during session initialization) */ /* don't sync the mixer sort keys for master/monitor,
i = order_keys.begin(); * since they are not part of the normal ordering.
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; continue;
}
for (; i != order_keys.end(); ++i) { if (k->first != base) {
k->second = i->second;
/* 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) { void
order_key_changed (); /* EMIT SIGNAL */ Route::set_order_key (RouteSortOrderKey key, uint32_t n)
{
if (order_keys.find (key) == order_keys.end() || order_keys[key] != n) {
order_keys[key] = n;
_session.set_dirty ();
} }
} }

View file

@ -2103,6 +2103,7 @@ Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output
{ {
ChanCount existing_inputs; ChanCount existing_inputs;
ChanCount existing_outputs; ChanCount existing_outputs;
uint32_t order = next_control_id();
count_existing_track_channels (existing_inputs, existing_outputs); 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->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->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->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()) { if (r->is_master()) {
_master_out = r; _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) { if (input_auto_connect || output_auto_connect) {
auto_connect_route (r, existing_inputs, existing_outputs, true, input_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) { if (_monitor_out && IO::connecting_legal) {
@ -2355,8 +2373,6 @@ Session::remove_route (boost::shared_ptr<Route> route)
route->drop_references (); route->drop_references ();
sync_order_keys (UndefinedSort);
Route::RemoteControlIDChange(); /* EMIT SIGNAL */ Route::RemoteControlIDChange(); /* EMIT SIGNAL */
/* save the new state of the world */ /* save the new state of the world */
@ -4096,27 +4112,6 @@ Session::add_automation_list(AutomationList *al)
automation_lists[al->id()] = 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 */ /** @return true if there is at least one record-enabled track, otherwise false */
bool bool
Session::have_rec_enabled_track () const 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); _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 void
Session::step_edit_status_change (bool yn) Session::step_edit_status_change (bool yn)
{ {
@ -4694,30 +4682,41 @@ Session::next_control_id () const
{ {
int subtract = 0; int subtract = 0;
/* the master and monitor bus remote ID's occupy a different /* the monitor bus remote ID is in a different
* "namespace" than regular routes. their existence doesn't * "namespace" than regular routes. its existence doesn't
* affect normal (low) numbered routes. * affect normal (low) numbered routes.
*/ */
if (_master_out) {
subtract++;
}
if (_monitor_out) { if (_monitor_out) {
subtract++; subtract++;
} }
/* remote control IDs are based either on this return nroutes() - subtract;
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 void
remote control ID, which is 1-based. Session::sync_order_keys (RouteSortOrderKey sort_key_changed)
{
if (deletion_in_progress()) {
return;
}
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; DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("Sync Order Keys, based on %1\n", enum_2_string (sort_key_changed)));
return ntracks() + (nbusses() - subtract);
Route::SyncOrderKeys (sort_key_changed); /* EMIT SIGNAL */
} }
bool bool

View file

@ -3060,13 +3060,11 @@ Session::controllable_by_descriptor (const ControllableDescriptor& desc)
} }
case ControllableDescriptor::RemoteControlID: case ControllableDescriptor::RemoteControlID:
cerr << "RID " << desc.rid() << endl;
r = route_by_remote_id (desc.rid()); r = route_by_remote_id (desc.rid());
break; break;
} }
if (!r) { if (!r) {
cerr << "no controllable with no route\n";
return c; return c;
} }
@ -3149,16 +3147,12 @@ Session::controllable_by_descriptor (const ControllableDescriptor& desc)
--send; --send;
} }
cerr << "Look for send " << send << endl;
boost::shared_ptr<Processor> p = r->nth_send (send); boost::shared_ptr<Processor> p = r->nth_send (send);
if (p) { if (p) {
boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p); boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
boost::shared_ptr<Amp> a = s->amp(); boost::shared_ptr<Amp> a = s->amp();
cerr << " looked for send " << send << " got " << s << " amp = " << a << endl;
if (a) { if (a) {
c = s->amp()->gain_control(); c = s->amp()->gain_control();
} }
@ -3513,7 +3507,7 @@ Session::config_changed (std::string p, bool ours)
} else if (p == "history-depth") { } else if (p == "history-depth") {
set_history_depth (Config->get_history_depth()); set_history_depth (Config->get_history_depth());
} else if (p == "sync-all-route-ordering") { } else if (p == "sync-all-route-ordering") {
sync_order_keys (UndefinedSort); /* XXX sync_order_keys (UndefinedSort); */
} else if (p == "initial-program-change") { } else if (p == "initial-program-change") {
if (MIDI::Manager::instance()->mmc()->output_port() && Config->get_initial_program_change() >= 0) { if (MIDI::Manager::instance()->mmc()->output_port() && Config->get_initial_program_change() >= 0) {