#include <cmath>
#include <cassert>
+#include "pbd/unknown_type.h"
+#include "pbd/unwind.h"
+
+#include "ardour/debug.h"
+#include "ardour/route.h"
+#include "ardour/midi_track.h"
#include "ardour/session.h"
+#include "gtkmm2ext/cell_renderer_pixbuf_multi.h"
+#include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
+#include "gtkmm2ext/treeutils.h"
+
#include "editor.h"
#include "keyboard.h"
#include "ardour_ui.h"
#include "gui_thread.h"
#include "actions.h"
#include "utils.h"
+#include "route_sorter.h"
#include "editor_group_tabs.h"
#include "editor_routes.h"
-#include "pbd/unknown_type.h"
-
-#include "ardour/route.h"
-#include "ardour/midi_track.h"
-
-#include "gtkmm2ext/cell_renderer_pixbuf_multi.h"
-#include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
-#include "gtkmm2ext/treeutils.h"
-
#include "i18n.h"
using namespace std;
using namespace Glib;
using Gtkmm2ext::Keyboard;
+struct ColumnInfo {
+ int index;
+ const char* label;
+ const char* tooltip;
+};
+
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)
+ , _adding_routes (false)
+ , _menu (0)
, old_focus (0)
, selection_countdown (0)
, name_editable (0)
{
+ static const int column_width = 22;
+
_scroller.add (_display);
_scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
// Record enable toggle
CellRendererPixbufMulti* rec_col_renderer = manage (new CellRendererPixbufMulti());
- rec_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
- rec_col_renderer->set_pixbuf (1, ::get_icon("rec-in-progress"));
- rec_col_renderer->set_pixbuf (2, ::get_icon("rec-enabled"));
- rec_col_renderer->set_pixbuf (3, ::get_icon("step-editing"));
+ rec_col_renderer->set_pixbuf (0, ::get_icon("record-normal-disabled"));
+ rec_col_renderer->set_pixbuf (1, ::get_icon("record-normal-in-progress"));
+ rec_col_renderer->set_pixbuf (2, ::get_icon("record-normal-enabled"));
+ rec_col_renderer->set_pixbuf (3, ::get_icon("record-step"));
rec_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_rec_enable_changed));
TreeViewColumn* rec_state_column = manage (new TreeViewColumn("R", *rec_col_renderer));
rec_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
rec_state_column->set_alignment(ALIGN_CENTER);
rec_state_column->set_expand(false);
- rec_state_column->set_fixed_width(15);
+ rec_state_column->set_fixed_width(column_width);
// MIDI Input Active
CellRendererPixbufMulti* input_active_col_renderer = manage (new CellRendererPixbufMulti());
- input_active_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
+ input_active_col_renderer->set_pixbuf (0, ::get_icon("midi-input-inactive"));
input_active_col_renderer->set_pixbuf (1, ::get_icon("midi-input-active"));
input_active_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_input_active_changed));
input_active_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
input_active_column->set_alignment(ALIGN_CENTER);
input_active_column->set_expand(false);
- input_active_column->set_fixed_width(20);
+ input_active_column->set_fixed_width(column_width);
// Mute enable toggle
CellRendererPixbufMulti* mute_col_renderer = manage (new CellRendererPixbufMulti());
- mute_col_renderer->set_pixbuf (0, ::get_icon("mute-disabled"));
- mute_col_renderer->set_pixbuf (1, ::get_icon("muted-by-others"));
- mute_col_renderer->set_pixbuf (2, ::get_icon("mute-enabled"));
+ mute_col_renderer->set_pixbuf (Gtkmm2ext::Off, ::get_icon("mute-disabled"));
+ mute_col_renderer->set_pixbuf (Gtkmm2ext::ImplicitActive, ::get_icon("muted-by-others"));
+ mute_col_renderer->set_pixbuf (Gtkmm2ext::ExplicitActive, ::get_icon("mute-enabled"));
mute_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_mute_enable_toggled));
TreeViewColumn* mute_state_column = manage (new TreeViewColumn("M", *mute_col_renderer));
// Solo enable toggle
CellRendererPixbufMulti* solo_col_renderer = manage (new CellRendererPixbufMulti());
- solo_col_renderer->set_pixbuf (0, ::get_icon("solo-disabled"));
- solo_col_renderer->set_pixbuf (1, ::get_icon("solo-enabled"));
- solo_col_renderer->set_pixbuf (3, ::get_icon("soloed-by-others"));
+ solo_col_renderer->set_pixbuf (Gtkmm2ext::Off, ::get_icon("solo-disabled"));
+ solo_col_renderer->set_pixbuf (Gtkmm2ext::ExplicitActive, ::get_icon("solo-enabled"));
+ solo_col_renderer->set_pixbuf (Gtkmm2ext::ImplicitActive, ::get_icon("soloed-by-others"));
solo_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_enable_toggled));
TreeViewColumn* solo_state_column = manage (new TreeViewColumn("S", *solo_col_renderer));
solo_state_column->add_attribute(solo_col_renderer->property_state(), _columns.solo_state);
+ solo_state_column->add_attribute(solo_col_renderer->property_visible(), _columns.solo_visible);
solo_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
solo_state_column->set_alignment(ALIGN_CENTER);
solo_state_column->set_expand(false);
- solo_state_column->set_fixed_width(15);
+ solo_state_column->set_fixed_width(column_width);
// Solo isolate toggle
CellRendererPixbufMulti* solo_iso_renderer = manage (new CellRendererPixbufMulti());
TreeViewColumn* solo_isolate_state_column = manage (new TreeViewColumn("SI", *solo_iso_renderer));
solo_isolate_state_column->add_attribute(solo_iso_renderer->property_state(), _columns.solo_isolate_state);
+ solo_isolate_state_column->add_attribute(solo_iso_renderer->property_visible(), _columns.solo_visible);
solo_isolate_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
solo_isolate_state_column->set_alignment(ALIGN_CENTER);
solo_isolate_state_column->set_expand(false);
- solo_isolate_state_column->set_fixed_width(22);
+ solo_isolate_state_column->set_fixed_width(column_width);
// Solo safe toggle
CellRendererPixbufMulti* solo_safe_renderer = manage (new CellRendererPixbufMulti ());
TreeViewColumn* solo_safe_state_column = manage (new TreeViewColumn(_("SS"), *solo_safe_renderer));
solo_safe_state_column->add_attribute(solo_safe_renderer->property_state(), _columns.solo_safe_state);
+ solo_safe_state_column->add_attribute(solo_safe_renderer->property_visible(), _columns.solo_visible);
solo_safe_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
solo_safe_state_column->set_alignment(ALIGN_CENTER);
solo_safe_state_column->set_expand(false);
- solo_safe_state_column->set_fixed_width(22);
+ solo_safe_state_column->set_fixed_width(column_width);
+
+ _name_column = _display.append_column ("", _columns.text) - 1;
+ _visible_column = _display.append_column ("", _columns.visible) - 1;
+ _active_column = _display.append_column ("", _columns.active) - 1;
_display.append_column (*input_active_column);
_display.append_column (*rec_state_column);
_display.append_column (*solo_isolate_state_column);
_display.append_column (*solo_safe_state_column);
- _name_column = _display.append_column (_("Name"), _columns.text) - 1;
- _visible_column = _display.append_column (_("V"), _columns.visible) - 1;
+
+ TreeViewColumn* col;
+ Gtk::Label* l;
+
+ ColumnInfo ci[] = {
+ { 0, _("Name"), _("Track/Bus Name") },
+ { 1, _("V"), _("Track/Bus visible ?") },
+ { 2, _("A"), _("Track/Bus active ?") },
+ { 3, _("I"), _("MIDI input enabled") },
+ { 4, _("R"), _("Record enabled") },
+ { 5, _("M"), _("Muted") },
+ { 6, _("S"), _("Soloed") },
+ { 7, _("SI"), _("Solo Isolated") },
+ { 8, _("SS"), _("Solo Safe (Locked)") },
+ { -1, 0, 0 }
+ };
+
+ for (int i = 0; ci[i].index >= 0; ++i) {
+ col = _display.get_column (ci[i].index);
+ l = manage (new Label (ci[i].label));
+ ARDOUR_UI::instance()->set_tip (*l, ci[i].tooltip);
+ col->set_widget (*l);
+ l->show ();
+ }
_display.set_headers_visible (true);
- _display.set_name ("TrackListDisplay");
_display.get_selection()->set_mode (SELECTION_SINGLE);
_display.get_selection()->set_select_function (sigc::mem_fun (*this, &EditorRoutes::selection_filter));
_display.set_reorderable (true);
+ _display.set_name (X_("EditGroupList"));
_display.set_rules_hint (true);
_display.set_size_request (100, -1);
_display.add_object_drag (_columns.route.index(), "routes");
visible_col->set_fixed_width(30);
visible_col->set_alignment(ALIGN_CENTER);
+ CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (_active_column));
+
+ active_cell->property_activatable() = true;
+ active_cell->property_radio() = false;
+ active_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::active_changed));
+
+ TreeViewColumn* active_col = dynamic_cast<TreeViewColumn*> (_display.get_column (_active_column));
+ active_col->set_expand (false);
+ active_col->set_sizing (TREE_VIEW_COLUMN_FIXED);
+ active_col->set_fixed_width (30);
+ active_col->set_alignment (ALIGN_CENTER);
+
_model->signal_row_deleted().connect (sigc::mem_fun (*this, &EditorRoutes::route_deleted));
_model->signal_rows_reordered().connect (sigc::mem_fun (*this, &EditorRoutes::reordered));
_display.set_enable_search (false);
- Route::SyncOrderKeys.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::sync_order_keys, this, _1), gui_context());
+ Route::SyncOrderKeys.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::sync_treeview_from_order_keys, this, _1), gui_context());
}
bool
void
EditorRoutes::redisplay ()
{
- if (_no_redisplay || !_session) {
+ if (_no_redisplay || !_session || _session->deletion_in_progress()) {
return;
}
TreeModel::Children rows = _model->children();
TreeModel::Children::iterator i;
uint32_t position;
+
+ /* n will be the count of tracks plus children (updated by TimeAxisView::show_at),
+ so we will use that to know where to put things.
+ */
int n;
for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
continue;
}
- if (!_redisplay_does_not_reset_order_keys) {
- /* this reorder is caused by user action, so reassign sort order keys
- to tracks.
- */
- route->set_order_key (N_ ("editor"), n);
- }
-
- bool visible = (*i)[_columns.visible];
+ bool visible = tv->marked_for_display ();
/* show or hide the TimeAxisView */
if (visible) {
- tv->set_marked_for_display (true);
position += tv->show_at (position, n, &_editor->edit_controls_vbox);
tv->clip_to_viewport ();
} else {
- tv->set_visibility (false);
+ tv->hide ();
}
n++;
}
-
/* whenever we go idle, update the track view list to reflect the new order.
we can't do this here, because we could mess up something that is traversing
the track order and has caused a redisplay of the list.
_editor->reset_controls_layout_height (position);
_editor->reset_controls_layout_width ();
- _editor->full_canvas_height = position + _editor->canvas_timebars_vsize;
- _editor->vertical_adjustment.set_upper (_editor->full_canvas_height);
+ _editor->_full_canvas_height = position;
+ _editor->vertical_adjustment.set_upper (_editor->_full_canvas_height);
- if ((_editor->vertical_adjustment.get_value() + _editor->_canvas_height) > _editor->vertical_adjustment.get_upper()) {
+ if ((_editor->vertical_adjustment.get_value() + _editor->_visible_canvas_height) > _editor->vertical_adjustment.get_upper()) {
/*
We're increasing the size of the canvas while the bottom is visible.
We scroll down to keep in step with the controls layout.
*/
- _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 (N_ ("editor"));
+ _editor->vertical_adjustment.set_value (_editor->_full_canvas_height - _editor->_visible_canvas_height);
}
}
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_treeview ();
+}
- /* this could require an order reset & sync */
- _session->set_remote_control_ids();
- _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_treeview ();
}
void
TimeAxisView* tv = (*iter)[_columns.tv];
if (tv) {
bool visible = (*iter)[_columns.visible];
- (*iter)[_columns.visible] = !visible;
+
+ if (tv->set_marked_for_display (!visible)) {
+ update_visibility ();
+ }
}
}
+}
- _redisplay_does_not_reset_order_keys = true;
- _session->set_remote_control_ids();
- redisplay ();
- _redisplay_does_not_reset_order_keys = false;
+void
+EditorRoutes::active_changed (std::string const & path)
+{
+ if (_session && _session->deletion_in_progress ()) {
+ return;
+ }
+
+ Gtk::TreeModel::Row row = *_model->get_iter (path);
+ boost::shared_ptr<Route> route = row[_columns.route];
+ bool const active = row[_columns.active];
+ route->set_active (!active, this);
}
void
EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
{
TreeModel::Row row;
+ PBD::Unwinder<bool> at (_adding_routes, true);
- _redisplay_does_not_sync_order_keys = true;
suspend_redisplay ();
+ _display.set_model (Glib::RefPtr<ListStore>());
+
for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) {
boost::shared_ptr<MidiTrack> midi_trk = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
row[_columns.text] = (*x)->route()->name();
row[_columns.visible] = (*x)->marked_for_display();
+ row[_columns.active] = (*x)->route()->active ();
row[_columns.tv] = *x;
row[_columns.route] = (*x)->route ();
row[_columns.is_track] = (boost::dynamic_pointer_cast<Track> ((*x)->route()) != 0);
row[_columns.is_midi] = false;
}
- row[_columns.mute_state] = (*x)->route()->muted();
- row[_columns.solo_state] = RouteUI::solo_visual_state ((*x)->route());
+ row[_columns.mute_state] = (*x)->route()->muted() ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off;
+ row[_columns.solo_state] = RouteUI::solo_active_state ((*x)->route());
+ row[_columns.solo_visible] = !(*x)->route()->is_master ();
row[_columns.solo_isolate_state] = (*x)->route()->solo_isolated();
row[_columns.solo_safe_state] = (*x)->route()->solo_safe();
row[_columns.name_editable] = true;
- _ignore_reorder = true;
-
- /* added a new fresh one at the end */
- if ((*x)->route()->order_key (N_ ("editor")) == -1) {
- (*x)->route()->set_order_key (N_ ("editor"), _model->children().size()-1);
- }
-
- _ignore_reorder = false;
-
boost::weak_ptr<Route> wr ((*x)->route());
- (*x)->route()->gui_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
- (*x)->route()->PropertyChanged.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::route_property_changed, this, _1, wr), gui_context());
+ (*x)->route()->gui_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
+ (*x)->route()->PropertyChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::route_property_changed, this, _1, wr), gui_context());
if ((*x)->is_track()) {
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
}
(*x)->route()->mute_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
- (*x)->route()->solo_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
- (*x)->route()->listen_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
+ (*x)->route()->solo_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
+ (*x)->route()->listen_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
(*x)->route()->solo_isolated_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_isolate_display, this), gui_context());
(*x)->route()->solo_safe_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_safe_display, this), gui_context());
+ (*x)->route()->active_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_active_display, this), gui_context ());
+
}
update_rec_display ();
update_solo_isolate_display ();
update_solo_safe_display ();
update_input_active_display ();
+ update_active_display ();
+
resume_redisplay ();
- _redisplay_does_not_sync_order_keys = false;
+ _display.set_model (_model);
+
+ /* now update route order keys from the treeview/track display order */
+
+ sync_order_keys_from_treeview ();
}
void
EditorRoutes::handle_gui_changes (string const & what, void*)
{
- ENSURE_GUI_THREAD (*this, &EditorRoutes::handle_gui_changes, what, src)
+ if (_adding_routes) {
+ return;
+ }
if (what == "track_height") {
/* Optional :make tracks change height while it happens, instead
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);
}
}
- _redisplay_does_not_sync_order_keys = false;
+ /* the deleted signal for the treeview/model will take
+ care of any updates.
+ */
}
void
}
}
+void
+EditorRoutes::update_active_display ()
+{
+ TreeModel::Children rows = _model->children();
+ TreeModel::Children::iterator i;
+
+ for (i = rows.begin(); i != rows.end(); ++i) {
+ boost::shared_ptr<Route> route = (*i)[_columns.route];
+ (*i)[_columns.active] = route->active ();
+ }
+}
+
void
EditorRoutes::update_visibility ()
{
for (i = rows.begin(); i != rows.end(); ++i) {
TimeAxisView *tv = (*i)[_columns.tv];
(*i)[_columns.visible] = tv->marked_for_display ();
- cerr << "marked " << tv->name() << " for display = " << tv->marked_for_display() << endl;
}
+ /* force route order keys catch up with visibility changes
+ */
+
+ sync_order_keys_from_treeview ();
+
resume_redisplay ();
}
for (i = rows.begin(); i != rows.end(); ++i) {
if ((*i)[_columns.tv] == &tv) {
+ tv.set_marked_for_display (false);
(*i)[_columns.visible] = false;
+ redisplay ();
break;
}
}
-
- redisplay ();
}
void
TreeModel::Children rows = _model->children();
TreeModel::Children::iterator i;
+
for (i = rows.begin(); i != rows.end(); ++i) {
if ((*i)[_columns.tv] == &tv) {
+ tv.set_marked_for_display (true);
(*i)[_columns.visible] = true;
+ redisplay ();
break;
}
}
-
- redisplay ();
}
void
-EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
+EditorRoutes::reset_remote_control_ids ()
{
- redisplay ();
+ if (Config->get_remote_model() != EditorOrdered || !_session || _session->deletion_in_progress()) {
+ return;
+ }
+
+ TreeModel::Children rows = _model->children();
+
+ if (rows.empty()) {
+ return;
+ }
+
+
+ DEBUG_TRACE (DEBUG::OrderKeys, "editor reset remote control ids\n");
+
+ TreeModel::Children::iterator ri;
+ bool rid_change = false;
+ uint32_t rid = 1;
+ uint32_t invisible_key = UINT32_MAX;
+
+ for (ri = rows.begin(); ri != rows.end(); ++ri) {
+
+ boost::shared_ptr<Route> route = (*ri)[_columns.route];
+ bool visible = (*ri)[_columns.visible];
+
+
+ if (!route->is_master() && !route->is_monitor()) {
+
+ uint32_t new_rid = (visible ? rid : invisible_key--);
+
+ if (new_rid != route->remote_control_id()) {
+ route->set_remote_control_id_from_order_key (EditorSort, new_rid);
+ rid_change = true;
+ }
+
+ if (visible) {
+ rid++;
+ }
+
+ }
+ }
+
+ if (rid_change) {
+ /* tell the world that we changed the remote control IDs */
+ _session->notify_remote_id_change ();
+ }
}
-/** 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 (string const & src)
+EditorRoutes::sync_order_keys_from_treeview ()
{
- map<int, int> new_order;
- TreeModel::Children rows = _model->children();
- TreeModel::Children::iterator ri;
+ if (_ignore_reorder || !_session || _session->deletion_in_progress()) {
+ return;
+ }
- if (src == N_ ("editor") || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
+ TreeModel::Children rows = _model->children();
+
+ if (rows.empty()) {
return;
}
+
+ DEBUG_TRACE (DEBUG::OrderKeys, "editor sync order keys from treeview\n");
+
+ TreeModel::Children::iterator ri;
bool changed = false;
- int order;
+ bool rid_change = false;
+ uint32_t order = 0;
+ uint32_t rid = 1;
+ uint32_t invisible_key = UINT32_MAX;
+
+ for (ri = rows.begin(); ri != rows.end(); ++ri) {
- for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
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 (N_ ("editor"));
+ uint32_t old_key = route->order_key (EditorSort);
- new_order[new_key] = old_key;
+ if (order != old_key) {
+ route->set_order_key (EditorSort, order);
- if (new_key != old_key) {
changed = true;
}
- }
- if (changed) {
- _redisplay_does_not_reset_order_keys = true;
+ if ((Config->get_remote_model() == EditorOrdered) && !route->is_master() && !route->is_monitor()) {
+
+ uint32_t new_rid = (visible ? rid : invisible_key--);
+
+ if (new_rid != route->remote_control_id()) {
+ route->set_remote_control_id_from_order_key (EditorSort, new_rid);
+ rid_change = true;
+ }
+
+ if (visible) {
+ rid++;
+ }
- /* `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);
}
- _model->reorder (co);
- _redisplay_does_not_reset_order_keys = false;
+ ++order;
+ }
+
+ if (changed) {
+ /* tell the world that we changed the editor sort keys */
+ _session->sync_order_keys (EditorSort);
+ }
+
+ if (rid_change) {
+ /* tell the world that we changed the remote control IDs */
+ _session->notify_remote_id_change ();
}
}
+void
+EditorRoutes::sync_treeview_from_order_keys (RouteSortOrderKey src)
+{
+ /* Some route order key(s) for `src' has been changed, make sure that
+ we update out tree/list model and GUI to reflect the change.
+ */
+
+ 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 old_order = 0;
+ bool changed = false;
+
+ if (rows.empty()) {
+ return;
+ }
+
+ OrderKeySortedRoutes sorted_routes;
+
+ for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++old_order) {
+ boost::shared_ptr<Route> route = (*ri)[_columns.route];
+ sorted_routes.push_back (RoutePlusOrderKey (route, old_order, route->order_key (EditorSort)));
+ }
+
+ SortByNewDisplayOrder cmp;
+
+ sort (sorted_routes.begin(), sorted_routes.end(), cmp);
+ neworder.assign (sorted_routes.size(), 0);
+
+ uint32_t n = 0;
+
+ for (OrderKeySortedRoutes::iterator sr = sorted_routes.begin(); sr != sorted_routes.end(); ++sr, ++n) {
+
+ neworder[n] = sr->old_display_order;
+
+ if (sr->old_display_order != n) {
+ changed = true;
+ }
+
+ DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("EDITOR change order for %1 from %2 to %3\n",
+ sr->route->name(), sr->old_display_order, n));
+ }
+
+ if (changed) {
+ Unwinder<bool> uw (_ignore_reorder, true);
+ _model->reorder (neworder);
+ }
+
+ redisplay ();
+}
void
EditorRoutes::hide_all_tracks (bool /*with_select*/)
continue;
}
+ tv->set_marked_for_display (yn);
(*i)[_columns.visible] = yn;
}
+ /* force route order keys catch up with visibility changes
+ */
+
+ sync_order_keys_from_treeview ();
+
resume_redisplay ();
}
}
}
+ /* force route order keys catch up with visibility changes
+ */
+
+ sync_order_keys_from_treeview ();
+
resume_redisplay ();
}
break;
case 's':
- if (Config->get_solo_control_is_listen_control()) {
- _session->set_listen (rl, !rl->front()->listening_via_monitor(), Session::rt_cleanup);
- } else {
- _session->set_solo (rl, !rl->front()->self_soloed(), Session::rt_cleanup);
+ if (get_relevant_routes (rl)) {
+ if (Config->get_solo_control_is_listen_control()) {
+ _session->set_listen (rl, !rl->front()->listening_via_monitor(), Session::rt_cleanup);
+ } else {
+ _session->set_solo (rl, !rl->front()->self_soloed(), Session::rt_cleanup);
+ }
}
return true;
break;
return true;
}
- //Scroll editor canvas to selected track
- if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
+ TreeModel::Path path;
+ TreeViewColumn *tvc;
+ int cell_x;
+ int cell_y;
- TreeModel::Path path;
- TreeViewColumn *tvc;
- int cell_x;
- int cell_y;
+ if (!_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y)) {
+ /* cancel selection */
+ _display.get_selection()->unselect_all ();
+ /* end any editing by grabbing focus */
+ _display.grab_focus ();
+ return true;
+ }
- _display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y);
+ //Scroll editor canvas to selected track
+ if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
// Get the model row.
Gtk::TreeModel::Row row = *_model->get_iter (path);
int y_pos = tv->y_position();
//Clamp the y pos so that we do not extend beyond the canvas full height.
- if (_editor->full_canvas_height - y_pos < _editor->_canvas_height){
- y_pos = _editor->full_canvas_height - _editor->_canvas_height;
+ if (_editor->_full_canvas_height - y_pos < _editor->_visible_canvas_height){
+ y_pos = _editor->_full_canvas_height - _editor->_visible_canvas_height;
}
//Only scroll to if the track is visible
struct EditorOrderRouteSorter {
bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
- /* use of ">" forces the correct sort order */
- return a->order_key (N_ ("editor")) < b->order_key (N_ ("editor"));
+ 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);
}
};
}
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;
+ /* new session: stamp all routes with the right editor order
+ * key
+ */
- _no_redisplay = true;
-
- for (i = rows.begin(); i != rows.end(); ++i) {
-
- 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;
- _session->set_remote_control_ids();
- redisplay ();
- _redisplay_does_not_sync_order_keys = false;
-}
-
void
EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
int x, int y,
}
for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
- neworder.push_back (leading->second->order_key (N_ ("editor")));
+ uint32_t order = leading->second->order_key (EditorSort);
+ neworder.push_back (order);
}
- _model->reorder (neworder);
+#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
- _session->sync_order_keys (N_ ("editor"));
+ _model->reorder (neworder);
}
void
for (i = rows.begin(); i != rows.end(); ++i) {
boost::shared_ptr<Route> route = (*i)[_columns.route];
- (*i)[_columns.mute_state] = RouteUI::mute_visual_state (_session, route);
+ (*i)[_columns.mute_state] = RouteUI::mute_active_state (_session, route);
}
}
for (i = rows.begin(); i != rows.end(); ++i) {
boost::shared_ptr<Route> route = (*i)[_columns.route];
- (*i)[_columns.solo_state] = RouteUI::solo_visual_state (route);
+ (*i)[_columns.solo_state] = RouteUI::solo_active_state (route);
}
}
for (i = rows.begin(); i != rows.end(); ++i) {
boost::shared_ptr<Route> route = (*i)[_columns.route];
- (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_visual_state (route) > 0 ? 1 : 0;
+ (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_active_state (route) ? 1 : 0;
}
}
for (i = rows.begin(); i != rows.end(); ++i) {
boost::shared_ptr<Route> route = (*i)[_columns.route];
- (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_visual_state (route) > 0 ? 1 : 0;
+ (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_active_state (route) ? 1 : 0;
}
}
resume_redisplay ();
}
+