Use LV2_SUPPORT define instead of HAVE_SLV2.
[ardour.git] / gtk2_ardour / editor_routes.cc
1 /*
2     Copyright (C) 2000-2009 Paul Davis
3
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.
8
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.
13
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.
17
18 */
19
20 #include <list>
21 #include <vector>
22 #include <algorithm>
23 #include <cstdlib>
24 #include <cmath>
25 #include <cassert>
26
27 #include "ardour/session.h"
28
29 #include "editor.h"
30 #include "keyboard.h"
31 #include "ardour_ui.h"
32 #include "audio_time_axis.h"
33 #include "midi_time_axis.h"
34 #include "mixer_strip.h"
35 #include "gui_thread.h"
36 #include "actions.h"
37 #include "utils.h"
38 #include "editor_group_tabs.h"
39 #include "editor_routes.h"
40
41 #include "pbd/unknown_type.h"
42
43 #include "ardour/route.h"
44 #include "ardour/midi_track.h"
45
46 #include "gtkmm2ext/cell_renderer_pixbuf_multi.h"
47 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
48 #include "gtkmm2ext/treeutils.h"
49
50 #include "i18n.h"
51
52 using namespace std;
53 using namespace ARDOUR;
54 using namespace PBD;
55 using namespace Gtk;
56 using namespace Gtkmm2ext;
57 using namespace Glib;
58 using Gtkmm2ext::Keyboard;
59
60 EditorRoutes::EditorRoutes (Editor* e)
61         : EditorComponent (e)
62         , _ignore_reorder (false)
63         , _no_redisplay (false)
64         , _redisplay_does_not_sync_order_keys (false)
65         , _redisplay_does_not_reset_order_keys (false)
66         ,_menu (0)
67         , old_focus (0)
68         , selection_countdown (0)
69         , name_editable (0)
70 {
71         _scroller.add (_display);
72         _scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
73
74         _model = ListStore::create (_columns);
75         _display.set_model (_model);
76
77         // Record enable toggle
78         CellRendererPixbufMulti* rec_col_renderer = manage (new CellRendererPixbufMulti());
79
80         rec_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
81         rec_col_renderer->set_pixbuf (1, ::get_icon("rec-in-progress"));
82         rec_col_renderer->set_pixbuf (2, ::get_icon("rec-enabled"));
83         rec_col_renderer->set_pixbuf (3, ::get_icon("step-editing"));
84         rec_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_rec_enable_changed));
85
86         TreeViewColumn* rec_state_column = manage (new TreeViewColumn("R", *rec_col_renderer));
87
88         rec_state_column->add_attribute(rec_col_renderer->property_state(), _columns.rec_state);
89         rec_state_column->add_attribute(rec_col_renderer->property_visible(), _columns.is_track);
90         rec_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
91         rec_state_column->set_alignment(ALIGN_CENTER);
92         rec_state_column->set_expand(false);
93         rec_state_column->set_fixed_width(15);
94
95         // Mute enable toggle
96         CellRendererPixbufMulti* mute_col_renderer = manage (new CellRendererPixbufMulti());
97
98         mute_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
99         mute_col_renderer->set_pixbuf (1, ::get_icon("muted-by-others"));
100         mute_col_renderer->set_pixbuf (2, ::get_icon("mute-enabled"));
101         mute_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_mute_enable_toggled));
102
103         TreeViewColumn* mute_state_column = manage (new TreeViewColumn("M", *mute_col_renderer));
104
105         mute_state_column->add_attribute(mute_col_renderer->property_state(), _columns.mute_state);
106         mute_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
107         mute_state_column->set_alignment(ALIGN_CENTER);
108         mute_state_column->set_expand(false);
109         mute_state_column->set_fixed_width(15);
110
111         // Solo enable toggle
112         CellRendererPixbufMulti* solo_col_renderer = manage (new CellRendererPixbufMulti());
113
114         solo_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
115         solo_col_renderer->set_pixbuf (1, ::get_icon("solo-enabled"));
116         solo_col_renderer->set_pixbuf (3, ::get_icon("soloed-by-others"));
117         solo_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_enable_toggled));
118
119         TreeViewColumn* solo_state_column = manage (new TreeViewColumn("S", *solo_col_renderer));
120
121         solo_state_column->add_attribute(solo_col_renderer->property_state(), _columns.solo_state);
122         solo_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
123         solo_state_column->set_alignment(ALIGN_CENTER);
124         solo_state_column->set_expand(false);
125         solo_state_column->set_fixed_width(15);
126
127         // Solo isolate toggle
128         CellRendererPixbufMulti* solo_iso_renderer = manage (new CellRendererPixbufMulti());
129
130         solo_iso_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
131         solo_iso_renderer->set_pixbuf (1, ::get_icon("solo-isolated"));
132         solo_iso_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_isolate_toggled));
133
134         TreeViewColumn* solo_isolate_state_column = manage (new TreeViewColumn("SI", *solo_iso_renderer));
135
136         solo_isolate_state_column->add_attribute(solo_iso_renderer->property_state(), _columns.solo_isolate_state);
137         solo_isolate_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
138         solo_isolate_state_column->set_alignment(ALIGN_CENTER);
139         solo_isolate_state_column->set_expand(false);
140         solo_isolate_state_column->set_fixed_width(22);
141
142         // Solo safe toggle
143         CellRendererPixbufMulti* solo_safe_renderer = manage (new CellRendererPixbufMulti ());
144
145         solo_safe_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
146         solo_safe_renderer->set_pixbuf (1, ::get_icon("solo-enabled"));
147         solo_safe_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_safe_toggled));
148
149         TreeViewColumn* solo_safe_state_column = manage (new TreeViewColumn(_("SS"), *solo_safe_renderer));
150         solo_safe_state_column->add_attribute(solo_safe_renderer->property_state(), _columns.solo_safe_state);
151         solo_safe_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
152         solo_safe_state_column->set_alignment(ALIGN_CENTER);
153         solo_safe_state_column->set_expand(false);
154         solo_safe_state_column->set_fixed_width(22);
155
156         _display.append_column (*rec_state_column);
157         _display.append_column (*mute_state_column);
158         _display.append_column (*solo_state_column);
159         _display.append_column (*solo_isolate_state_column);
160         _display.append_column (*solo_safe_state_column);
161         
162         int colnum = _display.append_column (_("Name"), _columns.text);
163         TreeViewColumn* c = _display.get_column (colnum-1);
164         c->set_data ("i_am_the_tab_column", (void*) 0xfeedface);
165         _display.append_column (_("V"), _columns.visible);
166         
167         _display.set_headers_visible (true);
168         _display.set_name ("TrackListDisplay");
169         _display.get_selection()->set_mode (SELECTION_SINGLE);
170         _display.get_selection()->set_select_function (sigc::mem_fun (*this, &EditorRoutes::selection_filter));
171         _display.set_reorderable (true);
172         _display.set_rules_hint (true);
173         _display.set_size_request (100, -1);
174         _display.add_object_drag (_columns.route.index(), "routes");
175
176         CellRendererText* name_cell = dynamic_cast<CellRendererText*> (_display.get_column_cell_renderer (5));
177
178         assert (name_cell);
179         name_cell->signal_editing_started().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit_started));
180
181         TreeViewColumn* name_column = _display.get_column (5);
182
183         assert (name_column);
184
185         name_column->add_attribute (name_cell->property_editable(), _columns.name_editable);
186         name_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
187         name_column->set_expand(true);
188         name_column->set_min_width(50);
189
190         name_cell->property_editable() = true;
191         name_cell->signal_edited().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit));
192
193         // Set the visible column cell renderer to radio toggle
194         CellRendererToggle* visible_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (6));
195
196         visible_cell->property_activatable() = true;
197         visible_cell->property_radio() = false;
198         visible_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::visible_changed));
199         
200         TreeViewColumn* visible_col = dynamic_cast<TreeViewColumn*> (_display.get_column (6));
201         visible_col->set_expand(false);
202         visible_col->set_sizing(TREE_VIEW_COLUMN_FIXED);
203         visible_col->set_fixed_width(30);
204         visible_col->set_alignment(ALIGN_CENTER);
205         
206         _model->signal_row_deleted().connect (sigc::mem_fun (*this, &EditorRoutes::route_deleted));
207         _model->signal_rows_reordered().connect (sigc::mem_fun (*this, &EditorRoutes::reordered));
208         
209         _display.signal_button_press_event().connect (sigc::mem_fun (*this, &EditorRoutes::button_press), false);
210         _scroller.signal_key_press_event().connect (sigc::mem_fun(*this, &EditorRoutes::key_press), false);
211
212         _scroller.signal_focus_in_event().connect (sigc::mem_fun (*this, &EditorRoutes::focus_in), false);
213         _scroller.signal_focus_out_event().connect (sigc::mem_fun (*this, &EditorRoutes::focus_out));
214
215         _display.signal_enter_notify_event().connect (sigc::mem_fun (*this, &EditorRoutes::enter_notify), false);
216         _display.signal_leave_notify_event().connect (sigc::mem_fun (*this, &EditorRoutes::leave_notify), false);
217
218         _display.set_enable_search (false);
219
220         Route::SyncOrderKeys.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::sync_order_keys, this, _1), gui_context());
221 }
222
223 bool
224 EditorRoutes::focus_in (GdkEventFocus*)
225 {
226         Window* win = dynamic_cast<Window*> (_scroller.get_toplevel ());
227
228         if (win) {
229                 old_focus = win->get_focus ();
230         } else {
231                 old_focus = 0;
232         }
233
234         name_editable = 0;
235
236         /* try to do nothing on focus in (doesn't work, hence selection_count nonsense) */
237         return true;
238 }
239
240 bool
241 EditorRoutes::focus_out (GdkEventFocus*)
242 {
243         if (old_focus) {
244                 old_focus->grab_focus ();
245                 old_focus = 0;
246         }
247
248         return false;
249 }
250
251 bool
252 EditorRoutes::enter_notify (GdkEventCrossing*)
253 {
254         if (name_editable) {
255                 return true;
256         }
257         
258         /* arm counter so that ::selection_filter() will deny selecting anything for the 
259            next two attempts to change selection status.
260         */
261         selection_countdown = 2;
262         _scroller.grab_focus ();
263         Keyboard::magic_widget_grab_focus ();
264         return false;
265 }
266
267 bool
268 EditorRoutes::leave_notify (GdkEventCrossing*)
269 {
270         selection_countdown = 0;
271
272         if (old_focus) {
273                 old_focus->grab_focus ();
274                 old_focus = 0;
275         }
276
277         Keyboard::magic_widget_drop_focus ();
278         return false;
279 }
280
281 void
282 EditorRoutes::set_session (Session* s)
283 {
284         SessionHandlePtr::set_session (s);
285
286         initial_display ();
287
288         if (_session) {
289                 _session->SoloChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::solo_changed_so_update_mute, this), gui_context());
290                 _session->RecordStateChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
291         }
292 }
293
294 void
295 EditorRoutes::on_tv_rec_enable_changed (std::string const & path_string)
296 {
297         // Get the model row that has been toggled.
298         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
299
300         TimeAxisView* tv = row[_columns.tv];
301         RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
302
303         if (rtv && rtv->track()) {
304                 boost::shared_ptr<RouteList> rl (new RouteList);
305                 rl->push_back (rtv->route());
306                 _session->set_record_enabled (rl, !rtv->track()->record_enabled(), Session::rt_cleanup);
307         }
308 }
309
310 void
311 EditorRoutes::on_tv_mute_enable_toggled (std::string const & path_string)
312 {
313         // Get the model row that has been toggled.
314         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
315
316         TimeAxisView *tv = row[_columns.tv];
317         RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
318         
319         if (rtv != 0) {
320                 boost::shared_ptr<RouteList> rl (new RouteList);
321                 rl->push_back (rtv->route());
322                 _session->set_mute (rl, !rtv->route()->muted(), Session::rt_cleanup);
323         }
324 }
325
326 void
327 EditorRoutes::on_tv_solo_enable_toggled (std::string const & path_string)
328 {
329         // Get the model row that has been toggled.
330         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
331
332         TimeAxisView *tv = row[_columns.tv];
333         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
334
335         if (rtv != 0) {
336                 boost::shared_ptr<RouteList> rl (new RouteList);
337                 rl->push_back (rtv->route());
338                 if (Config->get_solo_control_is_listen_control()) {
339                         _session->set_listen (rl, !rtv->route()->listening_via_monitor(), Session::rt_cleanup);
340                 } else {
341                         _session->set_solo (rl, !rtv->route()->self_soloed(), Session::rt_cleanup);
342                 }
343         }
344 }
345
346 void
347 EditorRoutes::on_tv_solo_isolate_toggled (std::string const & path_string)
348 {
349         // Get the model row that has been toggled.
350         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
351
352         TimeAxisView *tv = row[_columns.tv];
353         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
354
355         if (rtv) {
356                 rtv->route()->set_solo_isolated (!rtv->route()->solo_isolated(), this);
357         }
358 }
359
360 void
361 EditorRoutes::on_tv_solo_safe_toggled (std::string const & path_string)
362 {
363         // Get the model row that has been toggled.
364         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
365
366         TimeAxisView *tv = row[_columns.tv];
367         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
368
369         if (rtv) {
370                 rtv->route()->set_solo_safe (!rtv->route()->solo_safe(), this);
371         }
372 }
373
374 void
375 EditorRoutes::build_menu ()
376 {
377         using namespace Menu_Helpers;
378         using namespace Gtk;
379
380         _menu = new Menu;
381
382         MenuList& items = _menu->items();
383         _menu->set_name ("ArdourContextMenu");
384
385         items.push_back (MenuElem (_("Show All"), sigc::mem_fun (*this, &EditorRoutes::show_all_routes)));
386         items.push_back (MenuElem (_("Hide All"), sigc::mem_fun (*this, &EditorRoutes::hide_all_routes)));
387         items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiotracks)));
388         items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiotracks)));
389         items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiobus)));
390         items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiobus)));
391         items.push_back (MenuElem (_("Show All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_miditracks)));
392         items.push_back (MenuElem (_("Hide All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_miditracks)));
393         items.push_back (MenuElem (_("Show Tracks With Regions Under Playhead"), sigc::mem_fun (*this, &EditorRoutes::show_tracks_with_regions_at_playhead)));
394 }
395
396 void
397 EditorRoutes::show_menu ()
398 {
399         if (_menu == 0) {
400                 build_menu ();
401         }
402
403         _menu->popup (1, gtk_get_current_event_time());
404 }
405
406 void
407 EditorRoutes::redisplay ()
408 {
409         if (_no_redisplay || !_session) {
410                 return;
411         }
412
413         TreeModel::Children rows = _model->children();
414         TreeModel::Children::iterator i;
415         uint32_t position;
416         int n;
417
418         for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
419                 TimeAxisView *tv = (*i)[_columns.tv];
420                 boost::shared_ptr<Route> route = (*i)[_columns.route];
421
422                 if (tv == 0) {
423                         // just a "title" row
424                         continue;
425                 }
426
427                 if (!_redisplay_does_not_reset_order_keys) {
428                         /* this reorder is caused by user action, so reassign sort order keys
429                            to tracks.
430                         */
431                         route->set_order_key (N_ ("editor"), n);
432                 }
433
434                 bool visible = (*i)[_columns.visible];
435
436                 /* show or hide the TimeAxisView */
437                 if (visible) {
438                         tv->set_marked_for_display (true);
439                         position += tv->show_at (position, n, &_editor->edit_controls_vbox);
440                         tv->clip_to_viewport ();
441                 } else {
442                         tv->set_marked_for_display (false);
443                         tv->hide ();
444                 }
445
446                 n++;
447         }
448
449
450         /* whenever we go idle, update the track view list to reflect the new order.
451            we can't do this here, because we could mess up something that is traversing
452            the track order and has caused a redisplay of the list.
453         */
454         Glib::signal_idle().connect (sigc::mem_fun (*_editor, &Editor::sync_track_view_list_and_routes));
455
456         _editor->reset_controls_layout_height (position);
457         _editor->reset_controls_layout_width ();
458         _editor->full_canvas_height = position + _editor->canvas_timebars_vsize;
459         _editor->vertical_adjustment.set_upper (_editor->full_canvas_height);
460
461         if ((_editor->vertical_adjustment.get_value() + _editor->_canvas_height) > _editor->vertical_adjustment.get_upper()) {
462                 /*
463                    We're increasing the size of the canvas while the bottom is visible.
464                    We scroll down to keep in step with the controls layout.
465                 */
466                 _editor->vertical_adjustment.set_value (_editor->full_canvas_height - _editor->_canvas_height);
467         }
468
469         if (!_redisplay_does_not_reset_order_keys && !_redisplay_does_not_sync_order_keys) {
470                 _session->sync_order_keys (N_ ("editor"));
471         }
472 }
473
474 void
475 EditorRoutes::route_deleted (Gtk::TreeModel::Path const &)
476 {
477         if (!_session || _session->deletion_in_progress()) {
478                 return;
479         }
480                 
481         /* this could require an order reset & sync */
482         _session->set_remote_control_ids();
483         _ignore_reorder = true;
484         redisplay ();
485         _ignore_reorder = false;
486 }
487
488 void
489 EditorRoutes::visible_changed (std::string const & path)
490 {
491         if (_session && _session->deletion_in_progress()) {
492                 return;
493         }
494
495         TreeIter iter;
496
497         if ((iter = _model->get_iter (path))) {
498                 TimeAxisView* tv = (*iter)[_columns.tv];
499                 if (tv) {
500                         bool visible = (*iter)[_columns.visible];
501                         (*iter)[_columns.visible] = !visible;
502                 }
503         }
504
505         _redisplay_does_not_reset_order_keys = true;
506         _session->set_remote_control_ids();
507         redisplay ();
508         _redisplay_does_not_reset_order_keys = false;
509 }
510
511 void
512 EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
513 {
514         TreeModel::Row row;
515
516         _redisplay_does_not_sync_order_keys = true;
517         suspend_redisplay ();
518
519         for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) {
520
521                 row = *(_model->append ());
522
523                 row[_columns.text] = (*x)->route()->name();
524                 row[_columns.visible] = (*x)->marked_for_display();
525                 row[_columns.tv] = *x;
526                 row[_columns.route] = (*x)->route ();
527                 row[_columns.is_track] = (boost::dynamic_pointer_cast<Track> ((*x)->route()) != 0);
528                 row[_columns.mute_state] = (*x)->route()->muted();
529                 row[_columns.solo_state] = RouteUI::solo_visual_state ((*x)->route());
530                 row[_columns.solo_isolate_state] = (*x)->route()->solo_isolated();
531                 row[_columns.solo_safe_state] = (*x)->route()->solo_safe();
532                 row[_columns.name_editable] = true;
533
534                 _ignore_reorder = true;
535
536                 /* added a new fresh one at the end */
537                 if ((*x)->route()->order_key (N_ ("editor")) == -1) {
538                         (*x)->route()->set_order_key (N_ ("editor"), _model->children().size()-1);
539                 }
540
541                 _ignore_reorder = false;
542
543                 boost::weak_ptr<Route> wr ((*x)->route());
544
545                 (*x)->route()->gui_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
546                 (*x)->route()->PropertyChanged.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::route_property_changed, this, _1, wr), gui_context());
547
548                 if ((*x)->is_track()) {
549                         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
550                         t->RecordEnableChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
551                 }
552
553                 if ((*x)->is_midi_track()) {
554                         boost::shared_ptr<MidiTrack> t = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
555                         t->StepEditStatusChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
556                 }
557
558                 (*x)->route()->mute_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
559                 (*x)->route()->solo_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
560                 (*x)->route()->listen_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
561                 (*x)->route()->solo_isolated_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_isolate_display, this), gui_context());
562                 (*x)->route()->solo_safe_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_safe_display, this), gui_context());
563         }
564
565         update_rec_display ();
566         update_mute_display ();
567         update_solo_display (true);
568         update_solo_isolate_display ();
569         update_solo_safe_display ();
570         resume_redisplay ();
571         _redisplay_does_not_sync_order_keys = false;
572 }
573
574 void
575 EditorRoutes::handle_gui_changes (string const & what, void*)
576 {
577         ENSURE_GUI_THREAD (*this, &EditorRoutes::handle_gui_changes, what, src)
578
579         if (what == "track_height") {
580                 /* Optional :make tracks change height while it happens, instead
581                    of on first-idle
582                 */
583                 //update_canvas_now ();
584                 redisplay ();
585         }
586
587         if (what == "visible_tracks") {
588                 redisplay ();
589         }
590 }
591
592 void
593 EditorRoutes::route_removed (TimeAxisView *tv)
594 {
595         ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed, tv)
596
597         TreeModel::Children rows = _model->children();
598         TreeModel::Children::iterator ri;
599
600         /* the core model has changed, there is no need to sync
601            view orders.
602         */
603
604         _redisplay_does_not_sync_order_keys = true;
605
606         for (ri = rows.begin(); ri != rows.end(); ++ri) {
607                 if ((*ri)[_columns.tv] == tv) {
608                         _model->erase (ri);
609                         break;
610                 }
611         }
612
613         _redisplay_does_not_sync_order_keys = false;
614 }
615
616 void
617 EditorRoutes::route_property_changed (const PropertyChange& what_changed, boost::weak_ptr<Route> r)
618 {
619         if (!what_changed.contains (ARDOUR::Properties::name)) {
620                 return;
621         }
622
623         ENSURE_GUI_THREAD (*this, &EditorRoutes::route_name_changed, r)
624
625         boost::shared_ptr<Route> route = r.lock ();
626
627         if (!route) {
628                 return;
629         }
630
631         TreeModel::Children rows = _model->children();
632         TreeModel::Children::iterator i;
633
634         for (i = rows.begin(); i != rows.end(); ++i) {
635                 boost::shared_ptr<Route> t = (*i)[_columns.route];
636                 if (t == route) {
637                         (*i)[_columns.text] = route->name();
638                         break;
639                 }
640         }
641 }
642
643 void
644 EditorRoutes::update_visibility ()
645 {
646         TreeModel::Children rows = _model->children();
647         TreeModel::Children::iterator i;
648
649         suspend_redisplay ();
650
651         for (i = rows.begin(); i != rows.end(); ++i) {
652                 TimeAxisView *tv = (*i)[_columns.tv];
653                 (*i)[_columns.visible] = tv->marked_for_display ();
654                 cerr << "marked " << tv->name() << " for display = " << tv->marked_for_display() << endl;
655         }
656
657         resume_redisplay ();
658 }
659
660 void
661 EditorRoutes::hide_track_in_display (TimeAxisView& tv)
662 {
663         TreeModel::Children rows = _model->children();
664         TreeModel::Children::iterator i;
665
666         for (i = rows.begin(); i != rows.end(); ++i) {
667                 if ((*i)[_columns.tv] == &tv) {
668                         (*i)[_columns.visible] = false;
669                         break;
670                 }
671         }
672
673         redisplay ();
674 }
675
676 void
677 EditorRoutes::show_track_in_display (TimeAxisView& tv)
678 {
679         TreeModel::Children rows = _model->children();
680         TreeModel::Children::iterator i;
681
682         for (i = rows.begin(); i != rows.end(); ++i) {
683                 if ((*i)[_columns.tv] == &tv) {
684                         (*i)[_columns.visible] = true;
685                         break;
686                 }
687         }
688
689         redisplay ();
690 }
691
692 void
693 EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
694 {
695         redisplay ();
696 }
697
698 /** If src != "editor", take editor order keys from each route and use them to rearrange the
699  *  route list so that the visual arrangement of routes matches the order keys from the routes.
700  */
701 void
702 EditorRoutes::sync_order_keys (string const & src)
703 {
704         map<int, int> new_order;
705         TreeModel::Children rows = _model->children();
706         TreeModel::Children::iterator ri;
707
708         if (src == N_ ("editor") || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
709                 return;
710         }
711
712         bool changed = false;
713         int order;
714
715         for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
716                 boost::shared_ptr<Route> route = (*ri)[_columns.route];
717
718                 int const old_key = order;
719                 int const new_key = route->order_key (N_ ("editor"));
720
721                 new_order[new_key] = old_key;
722
723                 if (new_key != old_key) {
724                         changed = true;
725                 }
726         }
727
728         if (changed) {
729                 _redisplay_does_not_reset_order_keys = true;
730
731                 /* `compact' new_order into a vector */
732                 vector<int> co;
733                 for (map<int, int>::const_iterator i = new_order.begin(); i != new_order.end(); ++i) {
734                         co.push_back (i->second);
735                 }
736                 
737                 _model->reorder (co);
738                 _redisplay_does_not_reset_order_keys = false;
739         }
740 }
741
742
743 void
744 EditorRoutes::hide_all_tracks (bool /*with_select*/)
745 {
746         TreeModel::Children rows = _model->children();
747         TreeModel::Children::iterator i;
748
749         suspend_redisplay ();
750
751         for (i = rows.begin(); i != rows.end(); ++i) {
752
753                 TreeModel::Row row = (*i);
754                 TimeAxisView *tv = row[_columns.tv];
755
756                 if (tv == 0) {
757                         continue;
758                 }
759
760                 row[_columns.visible] = false;
761         }
762
763         resume_redisplay ();
764
765         /* XXX this seems like a hack and half, but its not clear where to put this
766            otherwise.
767         */
768
769         //reset_scrolling_region ();
770 }
771
772 void
773 EditorRoutes::set_all_tracks_visibility (bool yn)
774 {
775         TreeModel::Children rows = _model->children();
776         TreeModel::Children::iterator i;
777
778         suspend_redisplay ();
779
780         for (i = rows.begin(); i != rows.end(); ++i) {
781
782                 TreeModel::Row row = (*i);
783                 TimeAxisView* tv = row[_columns.tv];
784
785                 if (tv == 0) {
786                         continue;
787                 }
788
789                 (*i)[_columns.visible] = yn;
790         }
791
792         resume_redisplay ();
793 }
794
795 void
796 EditorRoutes::set_all_audio_midi_visibility (int tracks, bool yn)
797 {
798         TreeModel::Children rows = _model->children();
799         TreeModel::Children::iterator i;
800
801         suspend_redisplay ();
802
803         for (i = rows.begin(); i != rows.end(); ++i) {
804           
805                 TreeModel::Row row = (*i);
806                 TimeAxisView* tv = row[_columns.tv];
807                 
808                 AudioTimeAxisView* atv;
809                 MidiTimeAxisView* mtv;
810                 
811                 if (tv == 0) {
812                         continue;
813                 }
814
815                 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
816                         switch (tracks) {
817                         case 0:
818                                 (*i)[_columns.visible] = yn;
819                                 break;
820
821                         case 1:
822                                 if (atv->is_audio_track()) {
823                                         (*i)[_columns.visible] = yn;
824                                 }
825                                 break;
826
827                         case 2:
828                                 if (!atv->is_audio_track()) {
829                                         (*i)[_columns.visible] = yn;
830                                 }
831                                 break;
832                         }
833                 }
834                 else if ((mtv = dynamic_cast<MidiTimeAxisView*>(tv)) != 0) {
835                         switch (tracks) {
836                         case 0:
837                                 (*i)[_columns.visible] = yn;
838                                 break;
839
840                         case 3:
841                                 if (mtv->is_midi_track()) {
842                                         (*i)[_columns.visible] = yn;
843                                 }
844                                 break;
845                         }
846                 }
847         }
848
849         resume_redisplay ();
850 }
851
852 void
853 EditorRoutes::hide_all_routes ()
854 {
855         set_all_tracks_visibility (false);
856 }
857
858 void
859 EditorRoutes::show_all_routes ()
860 {
861         set_all_tracks_visibility (true);
862 }
863
864 void
865 EditorRoutes::show_all_audiotracks()
866 {
867         set_all_audio_midi_visibility (1, true);
868 }
869 void
870 EditorRoutes::hide_all_audiotracks ()
871 {
872         set_all_audio_midi_visibility (1, false);
873 }
874
875 void
876 EditorRoutes::show_all_audiobus ()
877 {
878         set_all_audio_midi_visibility (2, true);
879 }
880 void
881 EditorRoutes::hide_all_audiobus ()
882 {
883         set_all_audio_midi_visibility (2, false);
884 }
885
886 void
887 EditorRoutes::show_all_miditracks()
888 {
889         set_all_audio_midi_visibility (3, true);
890 }
891 void
892 EditorRoutes::hide_all_miditracks ()
893 {
894         set_all_audio_midi_visibility (3, false);
895 }
896
897 bool
898 EditorRoutes::key_press (GdkEventKey* ev)
899 {
900         TreeViewColumn *col;
901         boost::shared_ptr<RouteList> rl (new RouteList);
902         TreePath path;
903
904         switch (ev->keyval) {
905         case GDK_Tab:
906         case GDK_ISO_Left_Tab:
907
908                 /* If we appear to be editing something, leave that cleanly and appropriately.
909                 */
910                 if (name_editable) {
911                         name_editable->editing_done ();
912                         name_editable = 0;
913                 } 
914
915                 col = _display.get_column (5); // select&focus on name column
916
917                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
918                         treeview_select_previous (_display, _model, col);
919                 } else {
920                         treeview_select_next (_display, _model, col);
921                 }
922
923                 return true;
924                 break;
925
926         case 'm':
927                 if (get_relevant_routes (rl)) {
928                         _session->set_mute (rl, !rl->front()->muted(), Session::rt_cleanup);
929                 }
930                 return true;
931                 break;
932
933         case 's':
934                 if (Config->get_solo_control_is_listen_control()) {
935                         _session->set_listen (rl, !rl->front()->listening_via_monitor(), Session::rt_cleanup);
936                 } else {
937                         _session->set_solo (rl, !rl->front()->self_soloed(), Session::rt_cleanup);
938                 }
939                 return true;
940                 break;
941
942         case 'r':
943                 if (get_relevant_routes (rl)) {
944                         _session->set_record_enabled (rl, !rl->front()->record_enabled(), Session::rt_cleanup);
945                 }
946                 break;
947
948         default:
949                 break;
950         }
951
952         return false;
953 }
954
955 bool
956 EditorRoutes::get_relevant_routes (boost::shared_ptr<RouteList> rl)
957 {
958         TimeAxisView* tv;
959         RouteTimeAxisView* rtv;
960         RefPtr<TreeSelection> selection = _display.get_selection();
961         TreePath path;
962         TreeIter iter;
963
964         if (selection->count_selected_rows() != 0) {
965
966                 /* use selection */
967
968                 RefPtr<TreeModel> tm = RefPtr<TreeModel>::cast_dynamic (_model);
969                 iter = selection->get_selected (tm);
970
971         } else {
972                 /* use mouse pointer */
973
974                 int x, y;
975                 int bx, by;
976
977                 _display.get_pointer (x, y);
978                 _display.convert_widget_to_bin_window_coords (x, y, bx, by);
979
980                 if (_display.get_path_at_pos (bx, by, path)) {
981                         iter = _model->get_iter (path);
982                 }
983         }
984
985         if (iter) {
986                 tv = (*iter)[_columns.tv];
987                 if (tv) {
988                         rtv = dynamic_cast<RouteTimeAxisView*>(tv);
989                         if (rtv) {
990                                 rl->push_back (rtv->route());
991                         }
992                 }
993         }
994
995         return !rl->empty();
996 }
997
998 bool
999 EditorRoutes::button_press (GdkEventButton* ev)
1000 {
1001         if (Keyboard::is_context_menu_event (ev)) {
1002                 show_menu ();
1003                 return true;
1004         }
1005         
1006         //Scroll editor canvas to selected track
1007         if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1008                 
1009                 TreeModel::Path path;
1010                 TreeViewColumn *tvc;
1011                 int cell_x;
1012                 int cell_y;
1013                 
1014                 _display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y);
1015
1016                 // Get the model row.
1017                 Gtk::TreeModel::Row row = *_model->get_iter (path);
1018                 
1019                 TimeAxisView *tv = row[_columns.tv];
1020                 
1021                 int y_pos = tv->y_position();
1022                 
1023                 //Clamp the y pos so that we do not extend beyond the canvas full height.
1024                 if (_editor->full_canvas_height - y_pos < _editor->_canvas_height){
1025                     y_pos = _editor->full_canvas_height - _editor->_canvas_height;
1026                 }
1027                 
1028                 //Only scroll to if the track is visible
1029                 if(y_pos != -1){
1030                     _editor->reset_y_origin (y_pos);
1031                 }
1032         }
1033         
1034         return false;
1035 }
1036
1037 bool
1038 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const&, bool /*selected*/)
1039 {
1040         if (selection_countdown) {
1041                 if (--selection_countdown == 0) {
1042                         return true;
1043                 } else {
1044                         /* no selection yet ... */
1045                         return false;
1046                 }
1047         }
1048         return true;
1049 }
1050
1051 struct EditorOrderRouteSorter {
1052     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1053             /* use of ">" forces the correct sort order */
1054             return a->order_key (N_ ("editor")) < b->order_key (N_ ("editor"));
1055     }
1056 };
1057
1058 void
1059 EditorRoutes::initial_display ()
1060 {
1061         suspend_redisplay ();
1062         _model->clear ();
1063
1064         if (!_session) {
1065                 resume_redisplay ();
1066                 return;
1067         }
1068
1069         boost::shared_ptr<RouteList> routes = _session->get_routes();
1070         RouteList r (*routes);
1071         EditorOrderRouteSorter sorter;
1072
1073         r.sort (sorter);
1074         _editor->handle_new_route (r);
1075
1076         /* don't show master bus in a new session */
1077
1078         if (ARDOUR_UI::instance()->session_is_new ()) {
1079
1080                 TreeModel::Children rows = _model->children();
1081                 TreeModel::Children::iterator i;
1082
1083                 _no_redisplay = true;
1084
1085                 for (i = rows.begin(); i != rows.end(); ++i) {
1086
1087                         TimeAxisView *tv =  (*i)[_columns.tv];
1088                         RouteTimeAxisView *rtv;
1089
1090                         if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
1091                                 if (rtv->route()->is_master()) {
1092                                         _display.get_selection()->unselect (i);
1093                                 }
1094                         }
1095                 }
1096
1097                 _no_redisplay = false;
1098                 redisplay ();
1099         }
1100
1101         resume_redisplay ();
1102 }
1103
1104 void
1105 EditorRoutes::track_list_reorder (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &, int* /*new_order*/)
1106 {
1107         _redisplay_does_not_sync_order_keys = true;
1108         _session->set_remote_control_ids();
1109         redisplay ();
1110         _redisplay_does_not_sync_order_keys = false;
1111 }
1112
1113 void
1114 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
1115                                              int x, int y,
1116                                              const SelectionData& data,
1117                                              guint info, guint time)
1118 {
1119         if (data.get_target() == "GTK_TREE_MODEL_ROW") {
1120                 _display.on_drag_data_received (context, x, y, data, info, time);
1121                 return;
1122         }
1123
1124         context->drag_finish (true, false, time);
1125 }
1126
1127 void
1128 EditorRoutes::move_selected_tracks (bool up)
1129 {
1130         if (_editor->selection->tracks.empty()) {
1131                 return;
1132         }
1133
1134         typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
1135         std::list<ViewRoute> view_routes;
1136         std::vector<int> neworder;
1137         TreeModel::Children rows = _model->children();
1138         TreeModel::Children::iterator ri;
1139
1140         for (ri = rows.begin(); ri != rows.end(); ++ri) {
1141                 TimeAxisView* tv = (*ri)[_columns.tv];
1142                 boost::shared_ptr<Route> route = (*ri)[_columns.route];
1143
1144                 view_routes.push_back (ViewRoute (tv, route));
1145         }
1146
1147         list<ViewRoute>::iterator trailing;
1148         list<ViewRoute>::iterator leading;
1149
1150         if (up) {
1151
1152                 trailing = view_routes.begin();
1153                 leading = view_routes.begin();
1154
1155                 ++leading;
1156
1157                 while (leading != view_routes.end()) {
1158                         if (_editor->selection->selected (leading->first)) {
1159                                 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
1160                                 leading = view_routes.erase (leading);
1161                         } else {
1162                                 ++leading;
1163                                 ++trailing;
1164                         }
1165                 }
1166
1167         } else {
1168
1169                 /* if we could use reverse_iterator in list::insert, this code
1170                    would be a beautiful reflection of the code above. but we can't
1171                    and so it looks like a bit of a mess.
1172                 */
1173
1174                 trailing = view_routes.end();
1175                 leading = view_routes.end();
1176
1177                 --leading; if (leading == view_routes.begin()) { return; }
1178                 --leading;
1179                 --trailing;
1180
1181                 while (1) {
1182
1183                         if (_editor->selection->selected (leading->first)) {
1184                                 list<ViewRoute>::iterator tmp;
1185
1186                                 /* need to insert *after* trailing, not *before* it,
1187                                    which is what insert (iter, val) normally does.
1188                                 */
1189
1190                                 tmp = trailing;
1191                                 tmp++;
1192
1193                                 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
1194
1195                                 /* can't use iter = cont.erase (iter); form here, because
1196                                    we need iter to move backwards.
1197                                 */
1198
1199                                 tmp = leading;
1200                                 --tmp;
1201
1202                                 bool done = false;
1203
1204                                 if (leading == view_routes.begin()) {
1205                                         /* the one we've just inserted somewhere else
1206                                            was the first in the list. erase this copy,
1207                                            and then break, because we're done.
1208                                         */
1209                                         done = true;
1210                                 }
1211
1212                                 view_routes.erase (leading);
1213
1214                                 if (done) {
1215                                         break;
1216                                 }
1217
1218                                 leading = tmp;
1219
1220                         } else {
1221                                 if (leading == view_routes.begin()) {
1222                                         break;
1223                                 }
1224                                 --leading;
1225                                 --trailing;
1226                         }
1227                 };
1228         }
1229
1230         for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
1231                 neworder.push_back (leading->second->order_key (N_ ("editor")));
1232         }
1233
1234         _model->reorder (neworder);
1235
1236        _session->sync_order_keys (N_ ("editor"));
1237 }
1238
1239 void
1240 EditorRoutes::update_rec_display ()
1241 {
1242         TreeModel::Children rows = _model->children();
1243         TreeModel::Children::iterator i;
1244
1245         for (i = rows.begin(); i != rows.end(); ++i) {
1246                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1247
1248                 if (boost::dynamic_pointer_cast<Track> (route)) {
1249                         boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
1250
1251                         if (route->record_enabled()) {
1252                                 if (_session->record_status() == Session::Recording) {
1253                                         (*i)[_columns.rec_state] = 1;
1254                                 } else {
1255                                         (*i)[_columns.rec_state] = 2;
1256                                 }
1257                         } else if (mt && mt->step_editing()) {
1258                                 (*i)[_columns.rec_state] = 3;
1259                         } else {
1260                                 (*i)[_columns.rec_state] = 0;
1261                         }
1262                 
1263                         (*i)[_columns.name_editable] = !route->record_enabled ();
1264                 }
1265         }
1266 }
1267
1268 void
1269 EditorRoutes::update_mute_display ()
1270 {
1271         TreeModel::Children rows = _model->children();
1272         TreeModel::Children::iterator i;
1273
1274         for (i = rows.begin(); i != rows.end(); ++i) {
1275                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1276                 (*i)[_columns.mute_state] = RouteUI::mute_visual_state (_session, route);
1277         }
1278 }
1279
1280 void
1281 EditorRoutes::update_solo_display (bool /* selfsoloed */)
1282 {
1283         TreeModel::Children rows = _model->children();
1284         TreeModel::Children::iterator i;
1285
1286         for (i = rows.begin(); i != rows.end(); ++i) {
1287                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1288                 (*i)[_columns.solo_state] = RouteUI::solo_visual_state (route);
1289         }
1290 }
1291
1292 void
1293 EditorRoutes::update_solo_isolate_display ()
1294 {
1295         TreeModel::Children rows = _model->children();
1296         TreeModel::Children::iterator i;
1297
1298         for (i = rows.begin(); i != rows.end(); ++i) {
1299                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1300                 (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_visual_state (route) > 0 ? 1 : 0;
1301         }
1302 }
1303
1304 void
1305 EditorRoutes::update_solo_safe_display ()
1306 {
1307         TreeModel::Children rows = _model->children();
1308         TreeModel::Children::iterator i;
1309
1310         for (i = rows.begin(); i != rows.end(); ++i) {
1311                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1312                 (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_visual_state (route) > 0 ? 1 : 0;
1313         }
1314 }
1315
1316 list<TimeAxisView*>
1317 EditorRoutes::views () const
1318 {
1319         list<TimeAxisView*> v;
1320         for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
1321                 v.push_back ((*i)[_columns.tv]);
1322         }
1323
1324         return v;
1325 }
1326
1327 void
1328 EditorRoutes::clear ()
1329 {
1330         _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1331         _model->clear ();
1332         _display.set_model (_model);
1333 }
1334
1335 void
1336 EditorRoutes::name_edit_started (CellEditable* ce, const Glib::ustring&)
1337 {
1338         name_editable = ce;
1339
1340         /* give it a special name */
1341
1342         Gtk::Entry *e = dynamic_cast<Gtk::Entry*> (ce);
1343
1344         if (e) {
1345                 e->set_name (X_("RouteNameEditorEntry"));
1346         }
1347 }
1348
1349 void
1350 EditorRoutes::name_edit (std::string const & path, std::string const & new_text)
1351 {
1352         name_editable = 0;
1353
1354         TreeIter iter = _model->get_iter (path);
1355
1356         if (!iter) {
1357                 return;
1358         }
1359
1360         boost::shared_ptr<Route> route = (*iter)[_columns.route];
1361
1362         if (route && route->name() != new_text) {
1363                 route->set_name (new_text);
1364         }
1365 }
1366
1367 void
1368 EditorRoutes::solo_changed_so_update_mute ()
1369 {
1370         update_mute_display ();
1371 }
1372
1373 void
1374 EditorRoutes::show_tracks_with_regions_at_playhead ()
1375 {
1376         boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
1377
1378         set<TimeAxisView*> show;
1379         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
1380                 TimeAxisView* tav = _editor->axis_view_from_route (*i);
1381                 if (tav) {
1382                         show.insert (tav);
1383                 }
1384         }
1385
1386         suspend_redisplay ();
1387         
1388         TreeModel::Children rows = _model->children ();
1389         for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
1390                 TimeAxisView* tv = (*i)[_columns.tv];
1391                 (*i)[_columns.visible] = (show.find (tv) != show.end());
1392         }
1393
1394         resume_redisplay ();
1395 }