2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #include "pbd/unknown_type.h"
28 #include "pbd/unwind.h"
30 #include "ardour/debug.h"
31 #include "ardour/route.h"
32 #include "ardour/midi_track.h"
33 #include "ardour/session.h"
35 #include "gtkmm2ext/cell_renderer_pixbuf_multi.h"
36 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
37 #include "gtkmm2ext/treeutils.h"
41 #include "ardour_ui.h"
42 #include "audio_time_axis.h"
43 #include "midi_time_axis.h"
44 #include "mixer_strip.h"
45 #include "gui_thread.h"
48 #include "route_sorter.h"
49 #include "editor_group_tabs.h"
50 #include "editor_routes.h"
55 using namespace ARDOUR;
56 using namespace ARDOUR_UI_UTILS;
59 using namespace Gtkmm2ext;
61 using Gtkmm2ext::Keyboard;
69 EditorRoutes::EditorRoutes (Editor* e)
71 , _ignore_reorder (false)
72 , _no_redisplay (false)
73 , _adding_routes (false)
74 , _route_deletion_in_progress (false)
77 , selection_countdown (0)
80 static const int column_width = 22;
82 _scroller.add (_display);
83 _scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
85 _model = ListStore::create (_columns);
86 _display.set_model (_model);
88 // Record enable toggle
89 CellRendererPixbufMulti* rec_col_renderer = manage (new CellRendererPixbufMulti());
91 rec_col_renderer->set_pixbuf (0, ::get_icon("record-normal-disabled"));
92 rec_col_renderer->set_pixbuf (1, ::get_icon("record-normal-in-progress"));
93 rec_col_renderer->set_pixbuf (2, ::get_icon("record-normal-enabled"));
94 rec_col_renderer->set_pixbuf (3, ::get_icon("record-step"));
95 rec_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_rec_enable_changed));
97 TreeViewColumn* rec_state_column = manage (new TreeViewColumn("R", *rec_col_renderer));
99 rec_state_column->add_attribute(rec_col_renderer->property_state(), _columns.rec_state);
100 rec_state_column->add_attribute(rec_col_renderer->property_visible(), _columns.is_track);
102 rec_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
103 rec_state_column->set_alignment(ALIGN_CENTER);
104 rec_state_column->set_expand(false);
105 rec_state_column->set_fixed_width(column_width);
109 CellRendererPixbufMulti* input_active_col_renderer = manage (new CellRendererPixbufMulti());
110 input_active_col_renderer->set_pixbuf (0, ::get_icon("midi-input-inactive"));
111 input_active_col_renderer->set_pixbuf (1, ::get_icon("midi-input-active"));
112 input_active_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_input_active_changed));
114 TreeViewColumn* input_active_column = manage (new TreeViewColumn ("I", *input_active_col_renderer));
116 input_active_column->add_attribute(input_active_col_renderer->property_state(), _columns.is_input_active);
117 input_active_column->add_attribute (input_active_col_renderer->property_visible(), _columns.is_midi);
119 input_active_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
120 input_active_column->set_alignment(ALIGN_CENTER);
121 input_active_column->set_expand(false);
122 input_active_column->set_fixed_width(column_width);
124 // Mute enable toggle
125 CellRendererPixbufMulti* mute_col_renderer = manage (new CellRendererPixbufMulti());
127 mute_col_renderer->set_pixbuf (Gtkmm2ext::Off, ::get_icon("mute-disabled"));
128 mute_col_renderer->set_pixbuf (Gtkmm2ext::ImplicitActive, ::get_icon("muted-by-others"));
129 mute_col_renderer->set_pixbuf (Gtkmm2ext::ExplicitActive, ::get_icon("mute-enabled"));
130 mute_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_mute_enable_toggled));
132 TreeViewColumn* mute_state_column = manage (new TreeViewColumn("M", *mute_col_renderer));
134 mute_state_column->add_attribute(mute_col_renderer->property_state(), _columns.mute_state);
135 mute_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
136 mute_state_column->set_alignment(ALIGN_CENTER);
137 mute_state_column->set_expand(false);
138 mute_state_column->set_fixed_width(15);
140 // Solo enable toggle
141 CellRendererPixbufMulti* solo_col_renderer = manage (new CellRendererPixbufMulti());
143 solo_col_renderer->set_pixbuf (Gtkmm2ext::Off, ::get_icon("solo-disabled"));
144 solo_col_renderer->set_pixbuf (Gtkmm2ext::ExplicitActive, ::get_icon("solo-enabled"));
145 solo_col_renderer->set_pixbuf (Gtkmm2ext::ImplicitActive, ::get_icon("soloed-by-others"));
146 solo_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_enable_toggled));
148 TreeViewColumn* solo_state_column = manage (new TreeViewColumn("S", *solo_col_renderer));
150 solo_state_column->add_attribute(solo_col_renderer->property_state(), _columns.solo_state);
151 solo_state_column->add_attribute(solo_col_renderer->property_visible(), _columns.solo_visible);
152 solo_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
153 solo_state_column->set_alignment(ALIGN_CENTER);
154 solo_state_column->set_expand(false);
155 solo_state_column->set_fixed_width(column_width);
157 // Solo isolate toggle
158 CellRendererPixbufMulti* solo_iso_renderer = manage (new CellRendererPixbufMulti());
160 solo_iso_renderer->set_pixbuf (0, ::get_icon("solo-isolate-disabled"));
161 solo_iso_renderer->set_pixbuf (1, ::get_icon("solo-isolate-enabled"));
162 solo_iso_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_isolate_toggled));
164 TreeViewColumn* solo_isolate_state_column = manage (new TreeViewColumn("SI", *solo_iso_renderer));
166 solo_isolate_state_column->add_attribute(solo_iso_renderer->property_state(), _columns.solo_isolate_state);
167 solo_isolate_state_column->add_attribute(solo_iso_renderer->property_visible(), _columns.solo_visible);
168 solo_isolate_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
169 solo_isolate_state_column->set_alignment(ALIGN_CENTER);
170 solo_isolate_state_column->set_expand(false);
171 solo_isolate_state_column->set_fixed_width(column_width);
174 CellRendererPixbufMulti* solo_safe_renderer = manage (new CellRendererPixbufMulti ());
176 solo_safe_renderer->set_pixbuf (0, ::get_icon("solo-safe-disabled"));
177 solo_safe_renderer->set_pixbuf (1, ::get_icon("solo-safe-enabled"));
178 solo_safe_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_safe_toggled));
180 TreeViewColumn* solo_safe_state_column = manage (new TreeViewColumn(_("SS"), *solo_safe_renderer));
181 solo_safe_state_column->add_attribute(solo_safe_renderer->property_state(), _columns.solo_safe_state);
182 solo_safe_state_column->add_attribute(solo_safe_renderer->property_visible(), _columns.solo_visible);
183 solo_safe_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
184 solo_safe_state_column->set_alignment(ALIGN_CENTER);
185 solo_safe_state_column->set_expand(false);
186 solo_safe_state_column->set_fixed_width(column_width);
188 _name_column = _display.append_column ("", _columns.text) - 1;
189 _visible_column = _display.append_column ("", _columns.visible) - 1;
190 _active_column = _display.append_column ("", _columns.active) - 1;
192 _display.append_column (*input_active_column);
193 _display.append_column (*rec_state_column);
194 _display.append_column (*mute_state_column);
195 _display.append_column (*solo_state_column);
196 _display.append_column (*solo_isolate_state_column);
197 _display.append_column (*solo_safe_state_column);
204 { 0, _("Name"), _("Track/Bus Name") },
205 { 1, _("V"), _("Track/Bus visible ?") },
206 { 2, _("A"), _("Track/Bus active ?") },
207 { 3, _("I"), _("MIDI input enabled") },
208 { 4, _("R"), _("Record enabled") },
209 { 5, _("M"), _("Muted") },
210 { 6, _("S"), _("Soloed") },
211 { 7, _("SI"), _("Solo Isolated") },
212 { 8, _("SS"), _("Solo Safe (Locked)") },
216 for (int i = 0; ci[i].index >= 0; ++i) {
217 col = _display.get_column (ci[i].index);
218 l = manage (new Label (ci[i].label));
219 ARDOUR_UI::instance()->set_tip (*l, ci[i].tooltip);
220 col->set_widget (*l);
224 _display.set_headers_visible (true);
225 _display.get_selection()->set_mode (SELECTION_SINGLE);
226 _display.get_selection()->set_select_function (sigc::mem_fun (*this, &EditorRoutes::selection_filter));
227 _display.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::selection_changed));
228 _display.set_reorderable (true);
229 _display.set_name (X_("EditGroupList"));
230 _display.set_rules_hint (true);
231 _display.set_size_request (100, -1);
232 _display.add_object_drag (_columns.route.index(), "routes");
234 CellRendererText* name_cell = dynamic_cast<CellRendererText*> (_display.get_column_cell_renderer (_name_column));
237 name_cell->signal_editing_started().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit_started));
239 TreeViewColumn* name_column = _display.get_column (_name_column);
241 assert (name_column);
243 name_column->add_attribute (name_cell->property_editable(), _columns.name_editable);
244 name_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
245 name_column->set_expand(true);
246 name_column->set_min_width(50);
248 name_cell->property_editable() = true;
249 name_cell->signal_edited().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit));
251 // Set the visible column cell renderer to radio toggle
252 CellRendererToggle* visible_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (_visible_column));
254 visible_cell->property_activatable() = true;
255 visible_cell->property_radio() = false;
256 visible_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::visible_changed));
258 TreeViewColumn* visible_col = dynamic_cast<TreeViewColumn*> (_display.get_column (_visible_column));
259 visible_col->set_expand(false);
260 visible_col->set_sizing(TREE_VIEW_COLUMN_FIXED);
261 visible_col->set_fixed_width(30);
262 visible_col->set_alignment(ALIGN_CENTER);
264 CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (_active_column));
266 active_cell->property_activatable() = true;
267 active_cell->property_radio() = false;
268 active_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::active_changed));
270 TreeViewColumn* active_col = dynamic_cast<TreeViewColumn*> (_display.get_column (_active_column));
271 active_col->set_expand (false);
272 active_col->set_sizing (TREE_VIEW_COLUMN_FIXED);
273 active_col->set_fixed_width (30);
274 active_col->set_alignment (ALIGN_CENTER);
276 _model->signal_row_deleted().connect (sigc::mem_fun (*this, &EditorRoutes::row_deleted));
277 _model->signal_rows_reordered().connect (sigc::mem_fun (*this, &EditorRoutes::reordered));
279 _display.signal_button_press_event().connect (sigc::mem_fun (*this, &EditorRoutes::button_press), false);
280 _scroller.signal_key_press_event().connect (sigc::mem_fun(*this, &EditorRoutes::key_press), false);
282 _scroller.signal_focus_in_event().connect (sigc::mem_fun (*this, &EditorRoutes::focus_in), false);
283 _scroller.signal_focus_out_event().connect (sigc::mem_fun (*this, &EditorRoutes::focus_out));
285 _display.signal_enter_notify_event().connect (sigc::mem_fun (*this, &EditorRoutes::enter_notify), false);
286 _display.signal_leave_notify_event().connect (sigc::mem_fun (*this, &EditorRoutes::leave_notify), false);
288 _display.set_enable_search (false);
290 Route::SyncOrderKeys.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::sync_treeview_from_order_keys, this), gui_context());
294 EditorRoutes::focus_in (GdkEventFocus*)
296 Window* win = dynamic_cast<Window*> (_scroller.get_toplevel ());
299 old_focus = win->get_focus ();
306 /* try to do nothing on focus in (doesn't work, hence selection_count nonsense) */
311 EditorRoutes::focus_out (GdkEventFocus*)
314 old_focus->grab_focus ();
322 EditorRoutes::enter_notify (GdkEventCrossing*)
328 /* arm counter so that ::selection_filter() will deny selecting anything for the
329 next two attempts to change selection status.
331 selection_countdown = 2;
332 _scroller.grab_focus ();
333 Keyboard::magic_widget_grab_focus ();
338 EditorRoutes::leave_notify (GdkEventCrossing*)
340 selection_countdown = 0;
343 old_focus->grab_focus ();
347 Keyboard::magic_widget_drop_focus ();
352 EditorRoutes::set_session (Session* s)
354 SessionHandlePtr::set_session (s);
359 _session->SoloChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::solo_changed_so_update_mute, this), gui_context());
360 _session->RecordStateChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
365 EditorRoutes::on_input_active_changed (std::string const & path_string)
367 // Get the model row that has been toggled.
368 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
370 TimeAxisView* tv = row[_columns.tv];
371 RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
374 boost::shared_ptr<MidiTrack> mt;
375 mt = rtv->midi_track();
377 mt->set_input_active (!mt->input_active());
383 EditorRoutes::on_tv_rec_enable_changed (std::string const & path_string)
385 // Get the model row that has been toggled.
386 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
388 TimeAxisView* tv = row[_columns.tv];
389 RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
391 if (rtv && rtv->track()) {
392 boost::shared_ptr<RouteList> rl (new RouteList);
393 rl->push_back (rtv->route());
394 _session->set_record_enabled (rl, !rtv->track()->record_enabled(), Session::rt_cleanup);
399 EditorRoutes::on_tv_mute_enable_toggled (std::string const & path_string)
401 // Get the model row that has been toggled.
402 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
404 TimeAxisView *tv = row[_columns.tv];
405 RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
408 boost::shared_ptr<RouteList> rl (new RouteList);
409 rl->push_back (rtv->route());
410 _session->set_mute (rl, !rtv->route()->muted(), Session::rt_cleanup);
415 EditorRoutes::on_tv_solo_enable_toggled (std::string const & path_string)
417 // Get the model row that has been toggled.
418 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
420 TimeAxisView *tv = row[_columns.tv];
421 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
424 boost::shared_ptr<RouteList> rl (new RouteList);
425 rl->push_back (rtv->route());
426 if (Config->get_solo_control_is_listen_control()) {
427 _session->set_listen (rl, !rtv->route()->listening_via_monitor(), Session::rt_cleanup);
429 _session->set_solo (rl, !rtv->route()->self_soloed(), Session::rt_cleanup);
435 EditorRoutes::on_tv_solo_isolate_toggled (std::string const & path_string)
437 // Get the model row that has been toggled.
438 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
440 TimeAxisView *tv = row[_columns.tv];
441 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
444 rtv->route()->set_solo_isolated (!rtv->route()->solo_isolated(), this);
449 EditorRoutes::on_tv_solo_safe_toggled (std::string const & path_string)
451 // Get the model row that has been toggled.
452 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
454 TimeAxisView *tv = row[_columns.tv];
455 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
458 rtv->route()->set_solo_safe (!rtv->route()->solo_safe(), this);
463 EditorRoutes::build_menu ()
465 using namespace Menu_Helpers;
470 MenuList& items = _menu->items();
471 _menu->set_name ("ArdourContextMenu");
473 items.push_back (MenuElem (_("Show All"), sigc::mem_fun (*this, &EditorRoutes::show_all_routes)));
474 items.push_back (MenuElem (_("Hide All"), sigc::mem_fun (*this, &EditorRoutes::hide_all_routes)));
475 items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiotracks)));
476 items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiotracks)));
477 items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiobus)));
478 items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiobus)));
479 items.push_back (MenuElem (_("Show All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_miditracks)));
480 items.push_back (MenuElem (_("Hide All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_miditracks)));
481 items.push_back (MenuElem (_("Show Tracks With Regions Under Playhead"), sigc::mem_fun (*this, &EditorRoutes::show_tracks_with_regions_at_playhead)));
485 EditorRoutes::show_menu ()
491 _menu->popup (1, gtk_get_current_event_time());
495 EditorRoutes::redisplay ()
497 if (_no_redisplay || !_session || _session->deletion_in_progress()) {
501 TreeModel::Children rows = _model->children();
502 TreeModel::Children::iterator i;
505 /* n will be the count of tracks plus children (updated by TimeAxisView::show_at),
506 so we will use that to know where to put things.
510 for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
511 TimeAxisView *tv = (*i)[_columns.tv];
512 boost::shared_ptr<Route> route = (*i)[_columns.route];
515 // just a "title" row
519 bool visible = tv->marked_for_display ();
521 /* show or hide the TimeAxisView */
523 position += tv->show_at (position, n, &_editor->edit_controls_vbox);
531 /* whenever we go idle, update the track view list to reflect the new order.
532 we can't do this here, because we could mess up something that is traversing
533 the track order and has caused a redisplay of the list.
535 Glib::signal_idle().connect (sigc::mem_fun (*_editor, &Editor::sync_track_view_list_and_routes));
537 _editor->reset_controls_layout_height (position);
538 _editor->reset_controls_layout_width ();
539 _editor->_full_canvas_height = position;
541 if ((_editor->vertical_adjustment.get_value() + _editor->_visible_canvas_height) > _editor->vertical_adjustment.get_upper()) {
543 We're increasing the size of the canvas while the bottom is visible.
544 We scroll down to keep in step with the controls layout.
546 _editor->vertical_adjustment.set_value (_editor->_full_canvas_height - _editor->_visible_canvas_height);
551 EditorRoutes::row_deleted (Gtk::TreeModel::Path const &)
553 /* this happens as the second step of a DnD within the treeview, and
554 when a route is actually removed. we don't differentiate between
557 note that the sync_orders_keys() step may not actually change any
558 RID's (e.g. the last track may be removed, so all other tracks keep
559 the same RID), which means that no redisplay would happen. so we
560 have to force a redisplay.
563 DEBUG_TRACE (DEBUG::OrderKeys, "editor routes treeview row deleted\n");
566 sync_order_keys_from_treeview ();
570 EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
572 /* reordering implies that RID's will change, so sync_order_keys() will
576 DEBUG_TRACE (DEBUG::OrderKeys, "editor routes treeview reordered\n");
577 sync_order_keys_from_treeview ();
581 EditorRoutes::visible_changed (std::string const & path)
583 if (_session && _session->deletion_in_progress()) {
590 if ((iter = _model->get_iter (path))) {
591 TimeAxisView* tv = (*iter)[_columns.tv];
593 bool visible = (*iter)[_columns.visible];
595 if (tv->set_marked_for_display (!visible)) {
596 update_visibility ();
603 EditorRoutes::active_changed (std::string const & path)
605 if (_session && _session->deletion_in_progress ()) {
609 Gtk::TreeModel::Row row = *_model->get_iter (path);
610 boost::shared_ptr<Route> route = row[_columns.route];
611 bool const active = row[_columns.active];
612 route->set_active (!active, this);
616 EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
618 PBD::Unwinder<bool> at (_adding_routes, true);
620 bool from_scratch = (_model->children().size() == 0);
621 Gtk::TreeModel::Children::iterator insert_iter = _model->children().end();
623 for (Gtk::TreeModel::Children::iterator it = _model->children().begin(); it != _model->children().end(); ++it) {
624 boost::shared_ptr<Route> r = (*it)[_columns.route];
626 if (r->order_key() == (routes.front()->route()->order_key() + routes.size())) {
633 _editor->selection->tracks.clear();
638 _display.set_model (Glib::RefPtr<ListStore>());
640 for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) {
642 boost::shared_ptr<MidiTrack> midi_trk = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
644 TreeModel::Row row = *(_model->insert (insert_iter));
646 row[_columns.text] = (*x)->route()->name();
647 row[_columns.visible] = (*x)->marked_for_display();
648 row[_columns.active] = (*x)->route()->active ();
649 row[_columns.tv] = *x;
650 row[_columns.route] = (*x)->route ();
651 row[_columns.is_track] = (boost::dynamic_pointer_cast<Track> ((*x)->route()) != 0);
654 row[_columns.is_input_active] = midi_trk->input_active ();
655 row[_columns.is_midi] = true;
657 row[_columns.is_input_active] = false;
658 row[_columns.is_midi] = false;
661 row[_columns.mute_state] = (*x)->route()->muted() ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off;
662 row[_columns.solo_state] = RouteUI::solo_active_state ((*x)->route());
663 row[_columns.solo_visible] = !(*x)->route()->is_master ();
664 row[_columns.solo_isolate_state] = (*x)->route()->solo_isolated();
665 row[_columns.solo_safe_state] = (*x)->route()->solo_safe();
666 row[_columns.name_editable] = true;
669 _editor->selection->add(*x);
672 boost::weak_ptr<Route> wr ((*x)->route());
674 (*x)->route()->gui_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
675 (*x)->route()->PropertyChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::route_property_changed, this, _1, wr), gui_context());
677 if ((*x)->is_track()) {
678 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
679 t->RecordEnableChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
682 if ((*x)->is_midi_track()) {
683 boost::shared_ptr<MidiTrack> t = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
684 t->StepEditStatusChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
685 t->InputActiveChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_input_active_display, this), gui_context());
688 (*x)->route()->mute_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
689 (*x)->route()->solo_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
690 (*x)->route()->listen_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
691 (*x)->route()->solo_isolated_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_isolate_display, this), gui_context());
692 (*x)->route()->solo_safe_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_safe_display, this), gui_context());
693 (*x)->route()->active_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_active_display, this), gui_context ());
697 update_rec_display ();
698 update_mute_display ();
699 update_solo_display (true);
700 update_solo_isolate_display ();
701 update_solo_safe_display ();
702 update_input_active_display ();
703 update_active_display ();
705 _display.set_model (_model);
707 /* now update route order keys from the treeview/track display order */
709 sync_order_keys_from_treeview ();
713 EditorRoutes::handle_gui_changes (string const & what, void*)
715 if (_adding_routes) {
719 if (what == "track_height") {
720 /* Optional :make tracks change height while it happens, instead
726 if (what == "visible_tracks") {
732 EditorRoutes::route_removed (TimeAxisView *tv)
734 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed, tv)
736 TreeModel::Children rows = _model->children();
737 TreeModel::Children::iterator ri;
740 for (ri = rows.begin(); ri != rows.end(); ++ri) {
741 if ((*ri)[_columns.tv] == tv) {
742 PBD::Unwinder<bool> uw (_route_deletion_in_progress, true);
749 /* the deleted signal for the treeview/model will take
755 EditorRoutes::route_property_changed (const PropertyChange& what_changed, boost::weak_ptr<Route> r)
757 if (!what_changed.contains (ARDOUR::Properties::name)) {
761 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_name_changed, r)
763 boost::shared_ptr<Route> route = r.lock ();
769 TreeModel::Children rows = _model->children();
770 TreeModel::Children::iterator i;
772 for (i = rows.begin(); i != rows.end(); ++i) {
773 boost::shared_ptr<Route> t = (*i)[_columns.route];
775 (*i)[_columns.text] = route->name();
782 EditorRoutes::update_active_display ()
784 TreeModel::Children rows = _model->children();
785 TreeModel::Children::iterator i;
787 for (i = rows.begin(); i != rows.end(); ++i) {
788 boost::shared_ptr<Route> route = (*i)[_columns.route];
789 (*i)[_columns.active] = route->active ();
794 EditorRoutes::update_visibility ()
796 TreeModel::Children rows = _model->children();
797 TreeModel::Children::iterator i;
799 DisplaySuspender ds ();
801 for (i = rows.begin(); i != rows.end(); ++i) {
802 TimeAxisView *tv = (*i)[_columns.tv];
803 (*i)[_columns.visible] = tv->marked_for_display ();
806 /* force route order keys catch up with visibility changes
809 sync_order_keys_from_treeview ();
813 EditorRoutes::hide_track_in_display (TimeAxisView& tv)
815 TreeModel::Children rows = _model->children();
816 TreeModel::Children::iterator i;
818 for (i = rows.begin(); i != rows.end(); ++i) {
819 if ((*i)[_columns.tv] == &tv) {
820 tv.set_marked_for_display (false);
821 (*i)[_columns.visible] = false;
829 EditorRoutes::show_track_in_display (TimeAxisView& tv)
831 TreeModel::Children rows = _model->children();
832 TreeModel::Children::iterator i;
835 for (i = rows.begin(); i != rows.end(); ++i) {
836 if ((*i)[_columns.tv] == &tv) {
837 tv.set_marked_for_display (true);
838 (*i)[_columns.visible] = true;
846 EditorRoutes::reset_remote_control_ids ()
848 if (Config->get_remote_model() == UserOrdered || !_session || _session->deletion_in_progress()) {
852 TreeModel::Children rows = _model->children();
859 DEBUG_TRACE (DEBUG::OrderKeys, "editor reset remote control ids\n");
861 TreeModel::Children::iterator ri;
862 bool rid_change = false;
864 uint32_t invisible_key = UINT32_MAX;
866 for (ri = rows.begin(); ri != rows.end(); ++ri) {
868 boost::shared_ptr<Route> route = (*ri)[_columns.route];
869 bool visible = (*ri)[_columns.visible];
872 if (!route->is_master() && !route->is_monitor()) {
874 uint32_t new_rid = (visible ? rid : invisible_key--);
876 if (new_rid != route->remote_control_id()) {
877 route->set_remote_control_id_explicit (new_rid);
889 /* tell the world that we changed the remote control IDs */
890 _session->notify_remote_id_change ();
896 EditorRoutes::sync_order_keys_from_treeview ()
898 if (_ignore_reorder || !_session || _session->deletion_in_progress()) {
902 TreeModel::Children rows = _model->children();
909 DEBUG_TRACE (DEBUG::OrderKeys, "editor sync order keys from treeview\n");
911 TreeModel::Children::iterator ri;
912 bool changed = false;
913 bool rid_change = false;
916 uint32_t invisible_key = UINT32_MAX;
918 for (ri = rows.begin(); ri != rows.end(); ++ri) {
920 boost::shared_ptr<Route> route = (*ri)[_columns.route];
921 bool visible = (*ri)[_columns.visible];
923 uint32_t old_key = route->order_key ();
925 if (order != old_key) {
926 route->set_order_key (order);
931 if ((Config->get_remote_model() == MixerOrdered) && !route->is_master() && !route->is_monitor()) {
933 uint32_t new_rid = (visible ? rid : invisible_key--);
935 if (new_rid != route->remote_control_id()) {
936 route->set_remote_control_id_explicit (new_rid);
950 /* tell the world that we changed the editor sort keys */
951 _session->sync_order_keys ();
955 /* tell the world that we changed the remote control IDs */
956 _session->notify_remote_id_change ();
961 EditorRoutes::sync_treeview_from_order_keys ()
963 /* Some route order key(s) have been changed, make sure that
964 we update out tree/list model and GUI to reflect the change.
967 if (_ignore_reorder || !_session || _session->deletion_in_progress()) {
971 DEBUG_TRACE (DEBUG::OrderKeys, "editor sync model from order keys.\n");
973 /* we could get here after either a change in the Mixer or Editor sort
974 * order, but either way, the mixer order keys reflect the intended
975 * order for the GUI, so reorder the treeview model to match it.
978 vector<int> neworder;
979 TreeModel::Children rows = _model->children();
980 uint32_t old_order = 0;
981 bool changed = false;
987 OrderKeySortedRoutes sorted_routes;
989 for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++old_order) {
990 boost::shared_ptr<Route> route = (*ri)[_columns.route];
991 sorted_routes.push_back (RoutePlusOrderKey (route, old_order, route->order_key ()));
994 SortByNewDisplayOrder cmp;
996 sort (sorted_routes.begin(), sorted_routes.end(), cmp);
997 neworder.assign (sorted_routes.size(), 0);
1001 for (OrderKeySortedRoutes::iterator sr = sorted_routes.begin(); sr != sorted_routes.end(); ++sr, ++n) {
1003 neworder[n] = sr->old_display_order;
1005 if (sr->old_display_order != n) {
1009 DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("EDITOR change order for %1 from %2 to %3\n",
1010 sr->route->name(), sr->old_display_order, n));
1014 Unwinder<bool> uw (_ignore_reorder, true);
1015 _model->reorder (neworder);
1022 EditorRoutes::hide_all_tracks (bool /*with_select*/)
1024 TreeModel::Children rows = _model->children();
1025 TreeModel::Children::iterator i;
1027 DisplaySuspender ds;
1029 for (i = rows.begin(); i != rows.end(); ++i) {
1031 TreeModel::Row row = (*i);
1032 TimeAxisView *tv = row[_columns.tv];
1038 row[_columns.visible] = false;
1043 EditorRoutes::set_all_tracks_visibility (bool yn)
1045 TreeModel::Children rows = _model->children();
1046 TreeModel::Children::iterator i;
1048 DisplaySuspender ds;
1050 for (i = rows.begin(); i != rows.end(); ++i) {
1052 TreeModel::Row row = (*i);
1053 TimeAxisView* tv = row[_columns.tv];
1059 tv->set_marked_for_display (yn);
1060 (*i)[_columns.visible] = yn;
1063 /* force route order keys catch up with visibility changes
1066 sync_order_keys_from_treeview ();
1070 EditorRoutes::set_all_audio_midi_visibility (int tracks, bool yn)
1072 TreeModel::Children rows = _model->children();
1073 TreeModel::Children::iterator i;
1075 DisplaySuspender ds;
1077 for (i = rows.begin(); i != rows.end(); ++i) {
1079 TreeModel::Row row = (*i);
1080 TimeAxisView* tv = row[_columns.tv];
1082 AudioTimeAxisView* atv;
1083 MidiTimeAxisView* mtv;
1089 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
1092 (*i)[_columns.visible] = yn;
1096 if (atv->is_audio_track()) {
1097 (*i)[_columns.visible] = yn;
1102 if (!atv->is_audio_track()) {
1103 (*i)[_columns.visible] = yn;
1108 else if ((mtv = dynamic_cast<MidiTimeAxisView*>(tv)) != 0) {
1111 (*i)[_columns.visible] = yn;
1115 if (mtv->is_midi_track()) {
1116 (*i)[_columns.visible] = yn;
1123 /* force route order keys catch up with visibility changes
1126 sync_order_keys_from_treeview ();
1130 EditorRoutes::hide_all_routes ()
1132 set_all_tracks_visibility (false);
1136 EditorRoutes::show_all_routes ()
1138 set_all_tracks_visibility (true);
1142 EditorRoutes::show_all_audiotracks()
1144 set_all_audio_midi_visibility (1, true);
1147 EditorRoutes::hide_all_audiotracks ()
1149 set_all_audio_midi_visibility (1, false);
1153 EditorRoutes::show_all_audiobus ()
1155 set_all_audio_midi_visibility (2, true);
1158 EditorRoutes::hide_all_audiobus ()
1160 set_all_audio_midi_visibility (2, false);
1164 EditorRoutes::show_all_miditracks()
1166 set_all_audio_midi_visibility (3, true);
1169 EditorRoutes::hide_all_miditracks ()
1171 set_all_audio_midi_visibility (3, false);
1175 EditorRoutes::key_press (GdkEventKey* ev)
1177 TreeViewColumn *col;
1178 boost::shared_ptr<RouteList> rl (new RouteList);
1181 switch (ev->keyval) {
1183 case GDK_ISO_Left_Tab:
1185 /* If we appear to be editing something, leave that cleanly and appropriately.
1187 if (name_editable) {
1188 name_editable->editing_done ();
1192 col = _display.get_column (_name_column); // select&focus on name column
1194 if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
1195 treeview_select_previous (_display, _model, col);
1197 treeview_select_next (_display, _model, col);
1204 if (get_relevant_routes (rl)) {
1205 _session->set_mute (rl, !rl->front()->muted(), Session::rt_cleanup);
1211 if (get_relevant_routes (rl)) {
1212 if (Config->get_solo_control_is_listen_control()) {
1213 _session->set_listen (rl, !rl->front()->listening_via_monitor(), Session::rt_cleanup);
1215 _session->set_solo (rl, !rl->front()->self_soloed(), Session::rt_cleanup);
1222 if (get_relevant_routes (rl)) {
1223 _session->set_record_enabled (rl, !rl->front()->record_enabled(), Session::rt_cleanup);
1235 EditorRoutes::get_relevant_routes (boost::shared_ptr<RouteList> rl)
1238 RouteTimeAxisView* rtv;
1239 RefPtr<TreeSelection> selection = _display.get_selection();
1243 if (selection->count_selected_rows() != 0) {
1247 RefPtr<TreeModel> tm = RefPtr<TreeModel>::cast_dynamic (_model);
1248 iter = selection->get_selected (tm);
1251 /* use mouse pointer */
1256 _display.get_pointer (x, y);
1257 _display.convert_widget_to_bin_window_coords (x, y, bx, by);
1259 if (_display.get_path_at_pos (bx, by, path)) {
1260 iter = _model->get_iter (path);
1265 tv = (*iter)[_columns.tv];
1267 rtv = dynamic_cast<RouteTimeAxisView*>(tv);
1269 rl->push_back (rtv->route());
1274 return !rl->empty();
1278 EditorRoutes::button_press (GdkEventButton* ev)
1280 if (Keyboard::is_context_menu_event (ev)) {
1285 TreeModel::Path path;
1286 TreeViewColumn *tvc;
1290 if (!_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y)) {
1291 /* cancel selection */
1292 _display.get_selection()->unselect_all ();
1293 /* end any editing by grabbing focus */
1294 _display.grab_focus ();
1298 //Scroll editor canvas to selected track
1299 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1301 Gtk::TreeModel::Row row = *_model->get_iter (path);
1302 TimeAxisView *tv = row[_columns.tv];
1305 _editor->ensure_time_axis_view_is_visible (*tv, true);
1313 EditorRoutes::selection_changed ()
1315 if (_display.get_selection()->count_selected_rows() > 0) {
1318 TreeView::Selection::ListHandle_Path rows = _display.get_selection()->get_selected_rows ();
1319 TrackViewList selected;
1321 _editor->get_selection().clear_regions ();
1323 for (TreeView::Selection::ListHandle_Path::iterator i = rows.begin(); i != rows.end(); ++i) {
1325 if ((iter = _model->get_iter (*i))) {
1327 TimeAxisView* tv = (*iter)[_columns.tv];
1328 selected.push_back (tv);
1333 _editor->get_selection().set (selected);
1334 _editor->ensure_time_axis_view_is_visible (*(selected.front()), true);
1337 _editor->get_selection().clear_tracks ();
1342 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const&, bool /*selected*/)
1344 if (selection_countdown) {
1345 if (--selection_countdown == 0) {
1348 /* no selection yet ... */
1355 struct EditorOrderRouteSorter {
1356 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1357 if (a->is_master()) {
1358 /* master before everything else */
1360 } else if (b->is_master()) {
1361 /* everything else before master */
1364 return a->order_key () < b->order_key ();
1369 EditorRoutes::initial_display ()
1371 DisplaySuspender ds;
1378 boost::shared_ptr<RouteList> routes = _session->get_routes();
1380 if (ARDOUR_UI::instance()->session_is_new ()) {
1382 /* new session: stamp all routes with the right editor order
1386 _editor->add_routes (*(routes.get()));
1390 /* existing session: sort a copy of the route list by
1391 * editor-order and add its contents to the display.
1394 RouteList r (*routes);
1395 EditorOrderRouteSorter sorter;
1398 _editor->add_routes (r);
1404 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
1406 const SelectionData& data,
1407 guint info, guint time)
1409 if (data.get_target() == "GTK_TREE_MODEL_ROW") {
1410 _display.on_drag_data_received (context, x, y, data, info, time);
1414 context->drag_finish (true, false, time);
1418 EditorRoutes::move_selected_tracks (bool up)
1420 if (_editor->selection->tracks.empty()) {
1424 typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
1425 std::list<ViewRoute> view_routes;
1426 std::vector<int> neworder;
1427 TreeModel::Children rows = _model->children();
1428 TreeModel::Children::iterator ri;
1430 for (ri = rows.begin(); ri != rows.end(); ++ri) {
1431 TimeAxisView* tv = (*ri)[_columns.tv];
1432 boost::shared_ptr<Route> route = (*ri)[_columns.route];
1434 view_routes.push_back (ViewRoute (tv, route));
1437 list<ViewRoute>::iterator trailing;
1438 list<ViewRoute>::iterator leading;
1442 trailing = view_routes.begin();
1443 leading = view_routes.begin();
1447 while (leading != view_routes.end()) {
1448 if (_editor->selection->selected (leading->first)) {
1449 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
1450 leading = view_routes.erase (leading);
1459 /* if we could use reverse_iterator in list::insert, this code
1460 would be a beautiful reflection of the code above. but we can't
1461 and so it looks like a bit of a mess.
1464 trailing = view_routes.end();
1465 leading = view_routes.end();
1467 --leading; if (leading == view_routes.begin()) { return; }
1473 if (_editor->selection->selected (leading->first)) {
1474 list<ViewRoute>::iterator tmp;
1476 /* need to insert *after* trailing, not *before* it,
1477 which is what insert (iter, val) normally does.
1483 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
1485 /* can't use iter = cont.erase (iter); form here, because
1486 we need iter to move backwards.
1494 if (leading == view_routes.begin()) {
1495 /* the one we've just inserted somewhere else
1496 was the first in the list. erase this copy,
1497 and then break, because we're done.
1502 view_routes.erase (leading);
1511 if (leading == view_routes.begin()) {
1520 for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
1521 uint32_t order = leading->second->order_key ();
1522 neworder.push_back (order);
1526 DEBUG_TRACE (DEBUG::OrderKeys, "New order after moving tracks:\n");
1527 for (vector<int>::iterator i = neworder.begin(); i != neworder.end(); ++i) {
1528 DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("\t%1\n", *i));
1530 DEBUG_TRACE (DEBUG::OrderKeys, "-------\n");
1532 for (vector<int>::iterator i = neworder.begin(); i != neworder.end(); ++i) {
1533 if (*i >= (int) neworder.size()) {
1534 cerr << "Trying to move something to " << *i << " of " << neworder.size() << endl;
1536 assert (*i < (int) neworder.size ());
1540 _model->reorder (neworder);
1544 EditorRoutes::update_input_active_display ()
1546 TreeModel::Children rows = _model->children();
1547 TreeModel::Children::iterator i;
1549 for (i = rows.begin(); i != rows.end(); ++i) {
1550 boost::shared_ptr<Route> route = (*i)[_columns.route];
1552 if (boost::dynamic_pointer_cast<Track> (route)) {
1553 boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
1556 (*i)[_columns.is_input_active] = mt->input_active();
1563 EditorRoutes::update_rec_display ()
1565 TreeModel::Children rows = _model->children();
1566 TreeModel::Children::iterator i;
1568 for (i = rows.begin(); i != rows.end(); ++i) {
1569 boost::shared_ptr<Route> route = (*i)[_columns.route];
1571 if (boost::dynamic_pointer_cast<Track> (route)) {
1572 boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
1574 if (route->record_enabled()) {
1575 if (_session->record_status() == Session::Recording) {
1576 (*i)[_columns.rec_state] = 1;
1578 (*i)[_columns.rec_state] = 2;
1580 } else if (mt && mt->step_editing()) {
1581 (*i)[_columns.rec_state] = 3;
1583 (*i)[_columns.rec_state] = 0;
1586 (*i)[_columns.name_editable] = !route->record_enabled ();
1592 EditorRoutes::update_mute_display ()
1594 TreeModel::Children rows = _model->children();
1595 TreeModel::Children::iterator i;
1597 for (i = rows.begin(); i != rows.end(); ++i) {
1598 boost::shared_ptr<Route> route = (*i)[_columns.route];
1599 (*i)[_columns.mute_state] = RouteUI::mute_active_state (_session, route);
1604 EditorRoutes::update_solo_display (bool /* selfsoloed */)
1606 TreeModel::Children rows = _model->children();
1607 TreeModel::Children::iterator i;
1609 for (i = rows.begin(); i != rows.end(); ++i) {
1610 boost::shared_ptr<Route> route = (*i)[_columns.route];
1611 (*i)[_columns.solo_state] = RouteUI::solo_active_state (route);
1616 EditorRoutes::update_solo_isolate_display ()
1618 TreeModel::Children rows = _model->children();
1619 TreeModel::Children::iterator i;
1621 for (i = rows.begin(); i != rows.end(); ++i) {
1622 boost::shared_ptr<Route> route = (*i)[_columns.route];
1623 (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_active_state (route) ? 1 : 0;
1628 EditorRoutes::update_solo_safe_display ()
1630 TreeModel::Children rows = _model->children();
1631 TreeModel::Children::iterator i;
1633 for (i = rows.begin(); i != rows.end(); ++i) {
1634 boost::shared_ptr<Route> route = (*i)[_columns.route];
1635 (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_active_state (route) ? 1 : 0;
1640 EditorRoutes::views () const
1642 list<TimeAxisView*> v;
1643 for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
1644 v.push_back ((*i)[_columns.tv]);
1651 EditorRoutes::clear ()
1653 _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1655 _display.set_model (_model);
1659 EditorRoutes::name_edit_started (CellEditable* ce, const Glib::ustring&)
1663 /* give it a special name */
1665 Gtk::Entry *e = dynamic_cast<Gtk::Entry*> (ce);
1668 e->set_name (X_("RouteNameEditorEntry"));
1673 EditorRoutes::name_edit (std::string const & path, std::string const & new_text)
1677 TreeIter iter = _model->get_iter (path);
1683 boost::shared_ptr<Route> route = (*iter)[_columns.route];
1685 if (route && route->name() != new_text) {
1686 route->set_name (new_text);
1691 EditorRoutes::solo_changed_so_update_mute ()
1693 update_mute_display ();
1697 EditorRoutes::show_tracks_with_regions_at_playhead ()
1699 boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
1701 set<TimeAxisView*> show;
1702 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
1703 TimeAxisView* tav = _editor->axis_view_from_route (*i);
1709 DisplaySuspender ds;
1711 TreeModel::Children rows = _model->children ();
1712 for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
1713 TimeAxisView* tv = (*i)[_columns.tv];
1714 (*i)[_columns.visible] = (show.find (tv) != show.end());