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;
58 using namespace Gtkmm2ext;
60 using Gtkmm2ext::Keyboard;
68 EditorRoutes::EditorRoutes (Editor* e)
70 , _ignore_reorder (false)
71 , _no_redisplay (false)
72 , _adding_routes (false)
75 , selection_countdown (0)
78 static const int column_width = 22;
80 _scroller.add (_display);
81 _scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
83 _model = ListStore::create (_columns);
84 _display.set_model (_model);
86 // Record enable toggle
87 CellRendererPixbufMulti* rec_col_renderer = manage (new CellRendererPixbufMulti());
89 rec_col_renderer->set_pixbuf (0, ::get_icon("record-normal-disabled"));
90 rec_col_renderer->set_pixbuf (1, ::get_icon("record-normal-in-progress"));
91 rec_col_renderer->set_pixbuf (2, ::get_icon("record-normal-enabled"));
92 rec_col_renderer->set_pixbuf (3, ::get_icon("record-step"));
93 rec_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_rec_enable_changed));
95 TreeViewColumn* rec_state_column = manage (new TreeViewColumn("R", *rec_col_renderer));
97 rec_state_column->add_attribute(rec_col_renderer->property_state(), _columns.rec_state);
98 rec_state_column->add_attribute(rec_col_renderer->property_visible(), _columns.is_track);
100 rec_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
101 rec_state_column->set_alignment(ALIGN_CENTER);
102 rec_state_column->set_expand(false);
103 rec_state_column->set_fixed_width(column_width);
107 CellRendererPixbufMulti* input_active_col_renderer = manage (new CellRendererPixbufMulti());
108 input_active_col_renderer->set_pixbuf (0, ::get_icon("midi-input-inactive"));
109 input_active_col_renderer->set_pixbuf (1, ::get_icon("midi-input-active"));
110 input_active_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_input_active_changed));
112 TreeViewColumn* input_active_column = manage (new TreeViewColumn ("I", *input_active_col_renderer));
114 input_active_column->add_attribute(input_active_col_renderer->property_state(), _columns.is_input_active);
115 input_active_column->add_attribute (input_active_col_renderer->property_visible(), _columns.is_midi);
117 input_active_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
118 input_active_column->set_alignment(ALIGN_CENTER);
119 input_active_column->set_expand(false);
120 input_active_column->set_fixed_width(column_width);
122 // Mute enable toggle
123 CellRendererPixbufMulti* mute_col_renderer = manage (new CellRendererPixbufMulti());
125 mute_col_renderer->set_pixbuf (Gtkmm2ext::Off, ::get_icon("mute-disabled"));
126 mute_col_renderer->set_pixbuf (Gtkmm2ext::ImplicitActive, ::get_icon("muted-by-others"));
127 mute_col_renderer->set_pixbuf (Gtkmm2ext::ExplicitActive, ::get_icon("mute-enabled"));
128 mute_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_mute_enable_toggled));
130 TreeViewColumn* mute_state_column = manage (new TreeViewColumn("M", *mute_col_renderer));
132 mute_state_column->add_attribute(mute_col_renderer->property_state(), _columns.mute_state);
133 mute_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
134 mute_state_column->set_alignment(ALIGN_CENTER);
135 mute_state_column->set_expand(false);
136 mute_state_column->set_fixed_width(15);
138 // Solo enable toggle
139 CellRendererPixbufMulti* solo_col_renderer = manage (new CellRendererPixbufMulti());
141 solo_col_renderer->set_pixbuf (Gtkmm2ext::Off, ::get_icon("solo-disabled"));
142 solo_col_renderer->set_pixbuf (Gtkmm2ext::ExplicitActive, ::get_icon("solo-enabled"));
143 solo_col_renderer->set_pixbuf (Gtkmm2ext::ImplicitActive, ::get_icon("soloed-by-others"));
144 solo_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_enable_toggled));
146 TreeViewColumn* solo_state_column = manage (new TreeViewColumn("S", *solo_col_renderer));
148 solo_state_column->add_attribute(solo_col_renderer->property_state(), _columns.solo_state);
149 solo_state_column->add_attribute(solo_col_renderer->property_visible(), _columns.solo_visible);
150 solo_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
151 solo_state_column->set_alignment(ALIGN_CENTER);
152 solo_state_column->set_expand(false);
153 solo_state_column->set_fixed_width(column_width);
155 // Solo isolate toggle
156 CellRendererPixbufMulti* solo_iso_renderer = manage (new CellRendererPixbufMulti());
158 solo_iso_renderer->set_pixbuf (0, ::get_icon("solo-isolate-disabled"));
159 solo_iso_renderer->set_pixbuf (1, ::get_icon("solo-isolate-enabled"));
160 solo_iso_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_isolate_toggled));
162 TreeViewColumn* solo_isolate_state_column = manage (new TreeViewColumn("SI", *solo_iso_renderer));
164 solo_isolate_state_column->add_attribute(solo_iso_renderer->property_state(), _columns.solo_isolate_state);
165 solo_isolate_state_column->add_attribute(solo_iso_renderer->property_visible(), _columns.solo_visible);
166 solo_isolate_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
167 solo_isolate_state_column->set_alignment(ALIGN_CENTER);
168 solo_isolate_state_column->set_expand(false);
169 solo_isolate_state_column->set_fixed_width(column_width);
172 CellRendererPixbufMulti* solo_safe_renderer = manage (new CellRendererPixbufMulti ());
174 solo_safe_renderer->set_pixbuf (0, ::get_icon("solo-safe-disabled"));
175 solo_safe_renderer->set_pixbuf (1, ::get_icon("solo-safe-enabled"));
176 solo_safe_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_safe_toggled));
178 TreeViewColumn* solo_safe_state_column = manage (new TreeViewColumn(_("SS"), *solo_safe_renderer));
179 solo_safe_state_column->add_attribute(solo_safe_renderer->property_state(), _columns.solo_safe_state);
180 solo_safe_state_column->add_attribute(solo_safe_renderer->property_visible(), _columns.solo_visible);
181 solo_safe_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
182 solo_safe_state_column->set_alignment(ALIGN_CENTER);
183 solo_safe_state_column->set_expand(false);
184 solo_safe_state_column->set_fixed_width(column_width);
186 _name_column = _display.append_column ("", _columns.text) - 1;
187 _visible_column = _display.append_column ("", _columns.visible) - 1;
188 _active_column = _display.append_column ("", _columns.active) - 1;
190 _display.append_column (*input_active_column);
191 _display.append_column (*rec_state_column);
192 _display.append_column (*mute_state_column);
193 _display.append_column (*solo_state_column);
194 _display.append_column (*solo_isolate_state_column);
195 _display.append_column (*solo_safe_state_column);
202 { 0, _("Name"), _("Track/Bus Name") },
203 { 1, _("V"), _("Track/Bus visible ?") },
204 { 2, _("A"), _("Track/Bus active ?") },
205 { 3, _("I"), _("MIDI input enabled") },
206 { 4, _("R"), _("Record enabled") },
207 { 5, _("M"), _("Muted") },
208 { 6, _("S"), _("Soloed") },
209 { 7, _("SI"), _("Solo Isolated") },
210 { 8, _("SS"), _("Solo Safe (Locked)") },
214 for (int i = 0; ci[i].index >= 0; ++i) {
215 col = _display.get_column (ci[i].index);
216 l = manage (new Label (ci[i].label));
217 ARDOUR_UI::instance()->set_tip (*l, ci[i].tooltip);
218 col->set_widget (*l);
222 _display.set_headers_visible (true);
223 _display.get_selection()->set_mode (SELECTION_SINGLE);
224 _display.get_selection()->set_select_function (sigc::mem_fun (*this, &EditorRoutes::selection_filter));
225 _display.set_reorderable (true);
226 _display.set_name (X_("EditGroupList"));
227 _display.set_rules_hint (true);
228 _display.set_size_request (100, -1);
229 _display.add_object_drag (_columns.route.index(), "routes");
231 CellRendererText* name_cell = dynamic_cast<CellRendererText*> (_display.get_column_cell_renderer (_name_column));
234 name_cell->signal_editing_started().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit_started));
236 TreeViewColumn* name_column = _display.get_column (_name_column);
238 assert (name_column);
240 name_column->add_attribute (name_cell->property_editable(), _columns.name_editable);
241 name_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
242 name_column->set_expand(true);
243 name_column->set_min_width(50);
245 name_cell->property_editable() = true;
246 name_cell->signal_edited().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit));
248 // Set the visible column cell renderer to radio toggle
249 CellRendererToggle* visible_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (_visible_column));
251 visible_cell->property_activatable() = true;
252 visible_cell->property_radio() = false;
253 visible_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::visible_changed));
255 TreeViewColumn* visible_col = dynamic_cast<TreeViewColumn*> (_display.get_column (_visible_column));
256 visible_col->set_expand(false);
257 visible_col->set_sizing(TREE_VIEW_COLUMN_FIXED);
258 visible_col->set_fixed_width(30);
259 visible_col->set_alignment(ALIGN_CENTER);
261 CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (_active_column));
263 active_cell->property_activatable() = true;
264 active_cell->property_radio() = false;
265 active_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::active_changed));
267 TreeViewColumn* active_col = dynamic_cast<TreeViewColumn*> (_display.get_column (_active_column));
268 active_col->set_expand (false);
269 active_col->set_sizing (TREE_VIEW_COLUMN_FIXED);
270 active_col->set_fixed_width (30);
271 active_col->set_alignment (ALIGN_CENTER);
273 _model->signal_row_deleted().connect (sigc::mem_fun (*this, &EditorRoutes::route_deleted));
274 _model->signal_rows_reordered().connect (sigc::mem_fun (*this, &EditorRoutes::reordered));
276 _display.signal_button_press_event().connect (sigc::mem_fun (*this, &EditorRoutes::button_press), false);
277 _scroller.signal_key_press_event().connect (sigc::mem_fun(*this, &EditorRoutes::key_press), false);
279 _scroller.signal_focus_in_event().connect (sigc::mem_fun (*this, &EditorRoutes::focus_in), false);
280 _scroller.signal_focus_out_event().connect (sigc::mem_fun (*this, &EditorRoutes::focus_out));
282 _display.signal_enter_notify_event().connect (sigc::mem_fun (*this, &EditorRoutes::enter_notify), false);
283 _display.signal_leave_notify_event().connect (sigc::mem_fun (*this, &EditorRoutes::leave_notify), false);
285 _display.set_enable_search (false);
287 Route::SyncOrderKeys.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::sync_treeview_from_order_keys, this, _1), gui_context());
291 EditorRoutes::focus_in (GdkEventFocus*)
293 Window* win = dynamic_cast<Window*> (_scroller.get_toplevel ());
296 old_focus = win->get_focus ();
303 /* try to do nothing on focus in (doesn't work, hence selection_count nonsense) */
308 EditorRoutes::focus_out (GdkEventFocus*)
311 old_focus->grab_focus ();
319 EditorRoutes::enter_notify (GdkEventCrossing*)
325 /* arm counter so that ::selection_filter() will deny selecting anything for the
326 next two attempts to change selection status.
328 selection_countdown = 2;
329 _scroller.grab_focus ();
330 Keyboard::magic_widget_grab_focus ();
335 EditorRoutes::leave_notify (GdkEventCrossing*)
337 selection_countdown = 0;
340 old_focus->grab_focus ();
344 Keyboard::magic_widget_drop_focus ();
349 EditorRoutes::set_session (Session* s)
351 SessionHandlePtr::set_session (s);
356 _session->SoloChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::solo_changed_so_update_mute, this), gui_context());
357 _session->RecordStateChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
362 EditorRoutes::on_input_active_changed (std::string const & path_string)
364 // Get the model row that has been toggled.
365 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
367 TimeAxisView* tv = row[_columns.tv];
368 RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
371 boost::shared_ptr<MidiTrack> mt;
372 mt = rtv->midi_track();
374 mt->set_input_active (!mt->input_active());
380 EditorRoutes::on_tv_rec_enable_changed (std::string const & path_string)
382 // Get the model row that has been toggled.
383 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
385 TimeAxisView* tv = row[_columns.tv];
386 RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
388 if (rtv && rtv->track()) {
389 boost::shared_ptr<RouteList> rl (new RouteList);
390 rl->push_back (rtv->route());
391 _session->set_record_enabled (rl, !rtv->track()->record_enabled(), Session::rt_cleanup);
396 EditorRoutes::on_tv_mute_enable_toggled (std::string const & path_string)
398 // Get the model row that has been toggled.
399 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
401 TimeAxisView *tv = row[_columns.tv];
402 RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
405 boost::shared_ptr<RouteList> rl (new RouteList);
406 rl->push_back (rtv->route());
407 _session->set_mute (rl, !rtv->route()->muted(), Session::rt_cleanup);
412 EditorRoutes::on_tv_solo_enable_toggled (std::string const & path_string)
414 // Get the model row that has been toggled.
415 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
417 TimeAxisView *tv = row[_columns.tv];
418 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
421 boost::shared_ptr<RouteList> rl (new RouteList);
422 rl->push_back (rtv->route());
423 if (Config->get_solo_control_is_listen_control()) {
424 _session->set_listen (rl, !rtv->route()->listening_via_monitor(), Session::rt_cleanup);
426 _session->set_solo (rl, !rtv->route()->self_soloed(), Session::rt_cleanup);
432 EditorRoutes::on_tv_solo_isolate_toggled (std::string const & path_string)
434 // Get the model row that has been toggled.
435 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
437 TimeAxisView *tv = row[_columns.tv];
438 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
441 rtv->route()->set_solo_isolated (!rtv->route()->solo_isolated(), this);
446 EditorRoutes::on_tv_solo_safe_toggled (std::string const & path_string)
448 // Get the model row that has been toggled.
449 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
451 TimeAxisView *tv = row[_columns.tv];
452 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
455 rtv->route()->set_solo_safe (!rtv->route()->solo_safe(), this);
460 EditorRoutes::build_menu ()
462 using namespace Menu_Helpers;
467 MenuList& items = _menu->items();
468 _menu->set_name ("ArdourContextMenu");
470 items.push_back (MenuElem (_("Show All"), sigc::mem_fun (*this, &EditorRoutes::show_all_routes)));
471 items.push_back (MenuElem (_("Hide All"), sigc::mem_fun (*this, &EditorRoutes::hide_all_routes)));
472 items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiotracks)));
473 items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiotracks)));
474 items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiobus)));
475 items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiobus)));
476 items.push_back (MenuElem (_("Show All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_miditracks)));
477 items.push_back (MenuElem (_("Hide All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_miditracks)));
478 items.push_back (MenuElem (_("Show Tracks With Regions Under Playhead"), sigc::mem_fun (*this, &EditorRoutes::show_tracks_with_regions_at_playhead)));
482 EditorRoutes::show_menu ()
488 _menu->popup (1, gtk_get_current_event_time());
492 EditorRoutes::redisplay ()
494 if (_no_redisplay || !_session || _session->deletion_in_progress()) {
498 TreeModel::Children rows = _model->children();
499 TreeModel::Children::iterator i;
502 /* n will be the count of tracks plus children (updated by TimeAxisView::show_at),
503 so we will use that to know where to put things.
507 for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
508 TimeAxisView *tv = (*i)[_columns.tv];
509 boost::shared_ptr<Route> route = (*i)[_columns.route];
512 // just a "title" row
516 bool visible = tv->marked_for_display ();
518 /* show or hide the TimeAxisView */
520 position += tv->show_at (position, n, &_editor->edit_controls_vbox);
521 tv->clip_to_viewport ();
529 /* whenever we go idle, update the track view list to reflect the new order.
530 we can't do this here, because we could mess up something that is traversing
531 the track order and has caused a redisplay of the list.
533 Glib::signal_idle().connect (sigc::mem_fun (*_editor, &Editor::sync_track_view_list_and_routes));
535 _editor->reset_controls_layout_height (position);
536 _editor->reset_controls_layout_width ();
537 _editor->full_canvas_height = position + _editor->canvas_timebars_vsize;
538 _editor->vertical_adjustment.set_upper (_editor->full_canvas_height);
540 if ((_editor->vertical_adjustment.get_value() + _editor->_canvas_height) > _editor->vertical_adjustment.get_upper()) {
542 We're increasing the size of the canvas while the bottom is visible.
543 We scroll down to keep in step with the controls layout.
545 _editor->vertical_adjustment.set_value (_editor->full_canvas_height - _editor->_canvas_height);
550 EditorRoutes::route_deleted (Gtk::TreeModel::Path const &)
552 /* this happens as the second step of a DnD within the treeview as well
553 as when a row/route is actually deleted.
555 DEBUG_TRACE (DEBUG::OrderKeys, "editor routes treeview row deleted\n");
556 sync_order_keys_from_treeview ();
560 EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
562 DEBUG_TRACE (DEBUG::OrderKeys, "editor routes treeview reordered\n");
563 sync_order_keys_from_treeview ();
567 EditorRoutes::visible_changed (std::string const & path)
569 if (_session && _session->deletion_in_progress()) {
575 if ((iter = _model->get_iter (path))) {
576 TimeAxisView* tv = (*iter)[_columns.tv];
578 bool visible = (*iter)[_columns.visible];
580 if (tv->set_marked_for_display (!visible)) {
581 update_visibility ();
588 EditorRoutes::active_changed (std::string const & path)
590 if (_session && _session->deletion_in_progress ()) {
594 Gtk::TreeModel::Row row = *_model->get_iter (path);
595 boost::shared_ptr<Route> route = row[_columns.route];
596 bool const active = row[_columns.active];
597 route->set_active (!active, this);
601 EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
604 PBD::Unwinder<bool> at (_adding_routes, true);
606 suspend_redisplay ();
608 _display.set_model (Glib::RefPtr<ListStore>());
610 for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) {
612 boost::shared_ptr<MidiTrack> midi_trk = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
614 row = *(_model->append ());
616 row[_columns.text] = (*x)->route()->name();
617 row[_columns.visible] = (*x)->marked_for_display();
618 row[_columns.active] = (*x)->route()->active ();
619 row[_columns.tv] = *x;
620 row[_columns.route] = (*x)->route ();
621 row[_columns.is_track] = (boost::dynamic_pointer_cast<Track> ((*x)->route()) != 0);
624 row[_columns.is_input_active] = midi_trk->input_active ();
625 row[_columns.is_midi] = true;
627 row[_columns.is_input_active] = false;
628 row[_columns.is_midi] = false;
631 row[_columns.mute_state] = (*x)->route()->muted() ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off;
632 row[_columns.solo_state] = RouteUI::solo_active_state ((*x)->route());
633 row[_columns.solo_visible] = !(*x)->route()->is_master ();
634 row[_columns.solo_isolate_state] = (*x)->route()->solo_isolated();
635 row[_columns.solo_safe_state] = (*x)->route()->solo_safe();
636 row[_columns.name_editable] = true;
638 boost::weak_ptr<Route> wr ((*x)->route());
640 (*x)->route()->gui_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
641 (*x)->route()->PropertyChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::route_property_changed, this, _1, wr), gui_context());
643 if ((*x)->is_track()) {
644 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
645 t->RecordEnableChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
648 if ((*x)->is_midi_track()) {
649 boost::shared_ptr<MidiTrack> t = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
650 t->StepEditStatusChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
651 t->InputActiveChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_input_active_display, this), gui_context());
654 (*x)->route()->mute_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
655 (*x)->route()->solo_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
656 (*x)->route()->listen_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
657 (*x)->route()->solo_isolated_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_isolate_display, this), gui_context());
658 (*x)->route()->solo_safe_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_safe_display, this), gui_context());
659 (*x)->route()->active_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_active_display, this), gui_context ());
663 update_rec_display ();
664 update_mute_display ();
665 update_solo_display (true);
666 update_solo_isolate_display ();
667 update_solo_safe_display ();
668 update_input_active_display ();
669 update_active_display ();
672 _display.set_model (_model);
674 /* now update route order keys from the treeview/track display order */
676 sync_order_keys_from_treeview ();
680 EditorRoutes::handle_gui_changes (string const & what, void*)
682 if (_adding_routes) {
686 if (what == "track_height") {
687 /* Optional :make tracks change height while it happens, instead
690 //update_canvas_now ();
694 if (what == "visible_tracks") {
700 EditorRoutes::route_removed (TimeAxisView *tv)
702 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed, tv)
704 TreeModel::Children rows = _model->children();
705 TreeModel::Children::iterator ri;
707 for (ri = rows.begin(); ri != rows.end(); ++ri) {
708 if ((*ri)[_columns.tv] == tv) {
714 /* the deleted signal for the treeview/model will take
720 EditorRoutes::route_property_changed (const PropertyChange& what_changed, boost::weak_ptr<Route> r)
722 if (!what_changed.contains (ARDOUR::Properties::name)) {
726 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_name_changed, r)
728 boost::shared_ptr<Route> route = r.lock ();
734 TreeModel::Children rows = _model->children();
735 TreeModel::Children::iterator i;
737 for (i = rows.begin(); i != rows.end(); ++i) {
738 boost::shared_ptr<Route> t = (*i)[_columns.route];
740 (*i)[_columns.text] = route->name();
747 EditorRoutes::update_active_display ()
749 TreeModel::Children rows = _model->children();
750 TreeModel::Children::iterator i;
752 for (i = rows.begin(); i != rows.end(); ++i) {
753 boost::shared_ptr<Route> route = (*i)[_columns.route];
754 (*i)[_columns.active] = route->active ();
759 EditorRoutes::update_visibility ()
761 TreeModel::Children rows = _model->children();
762 TreeModel::Children::iterator i;
764 suspend_redisplay ();
766 for (i = rows.begin(); i != rows.end(); ++i) {
767 TimeAxisView *tv = (*i)[_columns.tv];
768 (*i)[_columns.visible] = tv->marked_for_display ();
771 /* force route order keys catch up with visibility changes
774 sync_order_keys_from_treeview ();
780 EditorRoutes::hide_track_in_display (TimeAxisView& tv)
782 TreeModel::Children rows = _model->children();
783 TreeModel::Children::iterator i;
785 for (i = rows.begin(); i != rows.end(); ++i) {
786 if ((*i)[_columns.tv] == &tv) {
787 tv.set_marked_for_display (false);
788 (*i)[_columns.visible] = false;
796 EditorRoutes::show_track_in_display (TimeAxisView& tv)
798 TreeModel::Children rows = _model->children();
799 TreeModel::Children::iterator i;
802 for (i = rows.begin(); i != rows.end(); ++i) {
803 if ((*i)[_columns.tv] == &tv) {
804 tv.set_marked_for_display (true);
805 (*i)[_columns.visible] = true;
813 EditorRoutes::reset_remote_control_ids ()
815 if (Config->get_remote_model() != EditorOrdered || !_session || _session->deletion_in_progress()) {
819 TreeModel::Children rows = _model->children();
826 DEBUG_TRACE (DEBUG::OrderKeys, "editor reset remote control ids\n");
828 TreeModel::Children::iterator ri;
829 bool rid_change = false;
831 uint32_t invisible_key = UINT32_MAX;
833 for (ri = rows.begin(); ri != rows.end(); ++ri) {
835 boost::shared_ptr<Route> route = (*ri)[_columns.route];
836 bool visible = (*ri)[_columns.visible];
839 if (!route->is_master() && !route->is_monitor()) {
841 uint32_t new_rid = (visible ? rid : invisible_key--);
843 if (new_rid != route->remote_control_id()) {
844 route->set_remote_control_id_from_order_key (EditorSort, new_rid);
856 /* tell the world that we changed the remote control IDs */
857 _session->notify_remote_id_change ();
863 EditorRoutes::sync_order_keys_from_treeview ()
865 if (_ignore_reorder || !_session || _session->deletion_in_progress()) {
869 TreeModel::Children rows = _model->children();
876 DEBUG_TRACE (DEBUG::OrderKeys, "editor sync order keys from treeview\n");
878 TreeModel::Children::iterator ri;
879 bool changed = false;
880 bool rid_change = false;
883 uint32_t invisible_key = UINT32_MAX;
885 for (ri = rows.begin(); ri != rows.end(); ++ri) {
887 boost::shared_ptr<Route> route = (*ri)[_columns.route];
888 bool visible = (*ri)[_columns.visible];
890 uint32_t old_key = route->order_key (EditorSort);
892 if (order != old_key) {
893 route->set_order_key (EditorSort, order);
898 if ((Config->get_remote_model() == EditorOrdered) && !route->is_master() && !route->is_monitor()) {
900 uint32_t new_rid = (visible ? rid : invisible_key--);
902 if (new_rid != route->remote_control_id()) {
903 route->set_remote_control_id_from_order_key (EditorSort, new_rid);
917 /* tell the world that we changed the editor sort keys */
918 _session->sync_order_keys (EditorSort);
922 /* tell the world that we changed the remote control IDs */
923 _session->notify_remote_id_change ();
928 EditorRoutes::sync_treeview_from_order_keys (RouteSortOrderKey src)
930 /* Some route order key(s) for `src' has been changed, make sure that
931 we update out tree/list model and GUI to reflect the change.
934 if (!_session || _session->deletion_in_progress()) {
938 DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("editor sync model from order keys, src = %1\n", enum_2_string (src)));
940 if (src == MixerSort) {
942 if (!Config->get_sync_all_route_ordering()) {
943 /* mixer sort keys changed - we don't care */
947 DEBUG_TRACE (DEBUG::OrderKeys, "reset editor order key to match mixer\n");
949 /* mixer sort keys were changed, update the editor sort
950 * keys since "sync mixer+editor order" is enabled.
953 boost::shared_ptr<RouteList> r = _session->get_routes ();
955 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
956 (*i)->sync_order_keys (src);
960 /* we could get here after either a change in the Mixer or Editor sort
961 * order, but either way, the mixer order keys reflect the intended
962 * order for the GUI, so reorder the treeview model to match it.
965 vector<int> neworder;
966 TreeModel::Children rows = _model->children();
967 uint32_t old_order = 0;
968 bool changed = false;
974 OrderKeySortedRoutes sorted_routes;
976 for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++old_order) {
977 boost::shared_ptr<Route> route = (*ri)[_columns.route];
978 sorted_routes.push_back (RoutePlusOrderKey (route, old_order, route->order_key (EditorSort)));
981 SortByNewDisplayOrder cmp;
983 sort (sorted_routes.begin(), sorted_routes.end(), cmp);
984 neworder.assign (sorted_routes.size(), 0);
988 for (OrderKeySortedRoutes::iterator sr = sorted_routes.begin(); sr != sorted_routes.end(); ++sr, ++n) {
990 neworder[n] = sr->old_display_order;
992 if (sr->old_display_order != n) {
996 DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("EDITOR change order for %1 from %2 to %3\n",
997 sr->route->name(), sr->old_display_order, n));
1001 Unwinder<bool> uw (_ignore_reorder, true);
1002 _model->reorder (neworder);
1009 EditorRoutes::hide_all_tracks (bool /*with_select*/)
1011 TreeModel::Children rows = _model->children();
1012 TreeModel::Children::iterator i;
1014 suspend_redisplay ();
1016 for (i = rows.begin(); i != rows.end(); ++i) {
1018 TreeModel::Row row = (*i);
1019 TimeAxisView *tv = row[_columns.tv];
1025 row[_columns.visible] = false;
1028 resume_redisplay ();
1030 /* XXX this seems like a hack and half, but its not clear where to put this
1034 //reset_scrolling_region ();
1038 EditorRoutes::set_all_tracks_visibility (bool yn)
1040 TreeModel::Children rows = _model->children();
1041 TreeModel::Children::iterator i;
1043 suspend_redisplay ();
1045 for (i = rows.begin(); i != rows.end(); ++i) {
1047 TreeModel::Row row = (*i);
1048 TimeAxisView* tv = row[_columns.tv];
1054 tv->set_marked_for_display (yn);
1055 (*i)[_columns.visible] = yn;
1058 /* force route order keys catch up with visibility changes
1061 sync_order_keys_from_treeview ();
1063 resume_redisplay ();
1067 EditorRoutes::set_all_audio_midi_visibility (int tracks, bool yn)
1069 TreeModel::Children rows = _model->children();
1070 TreeModel::Children::iterator i;
1072 suspend_redisplay ();
1074 for (i = rows.begin(); i != rows.end(); ++i) {
1076 TreeModel::Row row = (*i);
1077 TimeAxisView* tv = row[_columns.tv];
1079 AudioTimeAxisView* atv;
1080 MidiTimeAxisView* mtv;
1086 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
1089 (*i)[_columns.visible] = yn;
1093 if (atv->is_audio_track()) {
1094 (*i)[_columns.visible] = yn;
1099 if (!atv->is_audio_track()) {
1100 (*i)[_columns.visible] = yn;
1105 else if ((mtv = dynamic_cast<MidiTimeAxisView*>(tv)) != 0) {
1108 (*i)[_columns.visible] = yn;
1112 if (mtv->is_midi_track()) {
1113 (*i)[_columns.visible] = yn;
1120 /* force route order keys catch up with visibility changes
1123 sync_order_keys_from_treeview ();
1125 resume_redisplay ();
1129 EditorRoutes::hide_all_routes ()
1131 set_all_tracks_visibility (false);
1135 EditorRoutes::show_all_routes ()
1137 set_all_tracks_visibility (true);
1141 EditorRoutes::show_all_audiotracks()
1143 set_all_audio_midi_visibility (1, true);
1146 EditorRoutes::hide_all_audiotracks ()
1148 set_all_audio_midi_visibility (1, false);
1152 EditorRoutes::show_all_audiobus ()
1154 set_all_audio_midi_visibility (2, true);
1157 EditorRoutes::hide_all_audiobus ()
1159 set_all_audio_midi_visibility (2, false);
1163 EditorRoutes::show_all_miditracks()
1165 set_all_audio_midi_visibility (3, true);
1168 EditorRoutes::hide_all_miditracks ()
1170 set_all_audio_midi_visibility (3, false);
1174 EditorRoutes::key_press (GdkEventKey* ev)
1176 TreeViewColumn *col;
1177 boost::shared_ptr<RouteList> rl (new RouteList);
1180 switch (ev->keyval) {
1182 case GDK_ISO_Left_Tab:
1184 /* If we appear to be editing something, leave that cleanly and appropriately.
1186 if (name_editable) {
1187 name_editable->editing_done ();
1191 col = _display.get_column (_name_column); // select&focus on name column
1193 if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
1194 treeview_select_previous (_display, _model, col);
1196 treeview_select_next (_display, _model, col);
1203 if (get_relevant_routes (rl)) {
1204 _session->set_mute (rl, !rl->front()->muted(), Session::rt_cleanup);
1210 if (get_relevant_routes (rl)) {
1211 if (Config->get_solo_control_is_listen_control()) {
1212 _session->set_listen (rl, !rl->front()->listening_via_monitor(), Session::rt_cleanup);
1214 _session->set_solo (rl, !rl->front()->self_soloed(), Session::rt_cleanup);
1221 if (get_relevant_routes (rl)) {
1222 _session->set_record_enabled (rl, !rl->front()->record_enabled(), Session::rt_cleanup);
1234 EditorRoutes::get_relevant_routes (boost::shared_ptr<RouteList> rl)
1237 RouteTimeAxisView* rtv;
1238 RefPtr<TreeSelection> selection = _display.get_selection();
1242 if (selection->count_selected_rows() != 0) {
1246 RefPtr<TreeModel> tm = RefPtr<TreeModel>::cast_dynamic (_model);
1247 iter = selection->get_selected (tm);
1250 /* use mouse pointer */
1255 _display.get_pointer (x, y);
1256 _display.convert_widget_to_bin_window_coords (x, y, bx, by);
1258 if (_display.get_path_at_pos (bx, by, path)) {
1259 iter = _model->get_iter (path);
1264 tv = (*iter)[_columns.tv];
1266 rtv = dynamic_cast<RouteTimeAxisView*>(tv);
1268 rl->push_back (rtv->route());
1273 return !rl->empty();
1277 EditorRoutes::button_press (GdkEventButton* ev)
1279 if (Keyboard::is_context_menu_event (ev)) {
1284 TreeModel::Path path;
1285 TreeViewColumn *tvc;
1289 if (!_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y)) {
1290 /* cancel selection */
1291 _display.get_selection()->unselect_all ();
1292 /* end any editing by grabbing focus */
1293 _display.grab_focus ();
1297 //Scroll editor canvas to selected track
1298 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1300 // Get the model row.
1301 Gtk::TreeModel::Row row = *_model->get_iter (path);
1303 TimeAxisView *tv = row[_columns.tv];
1305 int y_pos = tv->y_position();
1307 //Clamp the y pos so that we do not extend beyond the canvas full height.
1308 if (_editor->full_canvas_height - y_pos < _editor->_canvas_height){
1309 y_pos = _editor->full_canvas_height - _editor->_canvas_height;
1312 //Only scroll to if the track is visible
1314 _editor->reset_y_origin (y_pos);
1322 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const&, bool /*selected*/)
1324 if (selection_countdown) {
1325 if (--selection_countdown == 0) {
1328 /* no selection yet ... */
1335 struct EditorOrderRouteSorter {
1336 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1337 if (a->is_master()) {
1338 /* master before everything else */
1340 } else if (b->is_master()) {
1341 /* everything else before master */
1344 return a->order_key (EditorSort) < b->order_key (EditorSort);
1349 EditorRoutes::initial_display ()
1351 suspend_redisplay ();
1355 resume_redisplay ();
1359 boost::shared_ptr<RouteList> routes = _session->get_routes();
1361 if (ARDOUR_UI::instance()->session_is_new ()) {
1363 /* new session: stamp all routes with the right editor order
1367 _editor->add_routes (*(routes.get()));
1371 /* existing session: sort a copy of the route list by
1372 * editor-order and add its contents to the display.
1375 RouteList r (*routes);
1376 EditorOrderRouteSorter sorter;
1379 _editor->add_routes (r);
1383 resume_redisplay ();
1387 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
1389 const SelectionData& data,
1390 guint info, guint time)
1392 if (data.get_target() == "GTK_TREE_MODEL_ROW") {
1393 _display.on_drag_data_received (context, x, y, data, info, time);
1397 context->drag_finish (true, false, time);
1401 EditorRoutes::move_selected_tracks (bool up)
1403 if (_editor->selection->tracks.empty()) {
1407 typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
1408 std::list<ViewRoute> view_routes;
1409 std::vector<int> neworder;
1410 TreeModel::Children rows = _model->children();
1411 TreeModel::Children::iterator ri;
1413 for (ri = rows.begin(); ri != rows.end(); ++ri) {
1414 TimeAxisView* tv = (*ri)[_columns.tv];
1415 boost::shared_ptr<Route> route = (*ri)[_columns.route];
1417 view_routes.push_back (ViewRoute (tv, route));
1420 list<ViewRoute>::iterator trailing;
1421 list<ViewRoute>::iterator leading;
1425 trailing = view_routes.begin();
1426 leading = view_routes.begin();
1430 while (leading != view_routes.end()) {
1431 if (_editor->selection->selected (leading->first)) {
1432 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
1433 leading = view_routes.erase (leading);
1442 /* if we could use reverse_iterator in list::insert, this code
1443 would be a beautiful reflection of the code above. but we can't
1444 and so it looks like a bit of a mess.
1447 trailing = view_routes.end();
1448 leading = view_routes.end();
1450 --leading; if (leading == view_routes.begin()) { return; }
1456 if (_editor->selection->selected (leading->first)) {
1457 list<ViewRoute>::iterator tmp;
1459 /* need to insert *after* trailing, not *before* it,
1460 which is what insert (iter, val) normally does.
1466 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
1468 /* can't use iter = cont.erase (iter); form here, because
1469 we need iter to move backwards.
1477 if (leading == view_routes.begin()) {
1478 /* the one we've just inserted somewhere else
1479 was the first in the list. erase this copy,
1480 and then break, because we're done.
1485 view_routes.erase (leading);
1494 if (leading == view_routes.begin()) {
1503 for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
1504 uint32_t order = leading->second->order_key (EditorSort);
1505 neworder.push_back (order);
1509 DEBUG_TRACE (DEBUG::OrderKeys, "New order after moving tracks:\n");
1510 for (vector<int>::iterator i = neworder.begin(); i != neworder.end(); ++i) {
1511 DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("\t%1\n", *i));
1513 DEBUG_TRACE (DEBUG::OrderKeys, "-------\n");
1515 for (vector<int>::iterator i = neworder.begin(); i != neworder.end(); ++i) {
1516 if (*i >= (int) neworder.size()) {
1517 cerr << "Trying to move something to " << *i << " of " << neworder.size() << endl;
1519 assert (*i < (int) neworder.size ());
1523 _model->reorder (neworder);
1527 EditorRoutes::update_input_active_display ()
1529 TreeModel::Children rows = _model->children();
1530 TreeModel::Children::iterator i;
1532 for (i = rows.begin(); i != rows.end(); ++i) {
1533 boost::shared_ptr<Route> route = (*i)[_columns.route];
1535 if (boost::dynamic_pointer_cast<Track> (route)) {
1536 boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
1539 (*i)[_columns.is_input_active] = mt->input_active();
1546 EditorRoutes::update_rec_display ()
1548 TreeModel::Children rows = _model->children();
1549 TreeModel::Children::iterator i;
1551 for (i = rows.begin(); i != rows.end(); ++i) {
1552 boost::shared_ptr<Route> route = (*i)[_columns.route];
1554 if (boost::dynamic_pointer_cast<Track> (route)) {
1555 boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
1557 if (route->record_enabled()) {
1558 if (_session->record_status() == Session::Recording) {
1559 (*i)[_columns.rec_state] = 1;
1561 (*i)[_columns.rec_state] = 2;
1563 } else if (mt && mt->step_editing()) {
1564 (*i)[_columns.rec_state] = 3;
1566 (*i)[_columns.rec_state] = 0;
1569 (*i)[_columns.name_editable] = !route->record_enabled ();
1575 EditorRoutes::update_mute_display ()
1577 TreeModel::Children rows = _model->children();
1578 TreeModel::Children::iterator i;
1580 for (i = rows.begin(); i != rows.end(); ++i) {
1581 boost::shared_ptr<Route> route = (*i)[_columns.route];
1582 (*i)[_columns.mute_state] = RouteUI::mute_active_state (_session, route);
1587 EditorRoutes::update_solo_display (bool /* selfsoloed */)
1589 TreeModel::Children rows = _model->children();
1590 TreeModel::Children::iterator i;
1592 for (i = rows.begin(); i != rows.end(); ++i) {
1593 boost::shared_ptr<Route> route = (*i)[_columns.route];
1594 (*i)[_columns.solo_state] = RouteUI::solo_active_state (route);
1599 EditorRoutes::update_solo_isolate_display ()
1601 TreeModel::Children rows = _model->children();
1602 TreeModel::Children::iterator i;
1604 for (i = rows.begin(); i != rows.end(); ++i) {
1605 boost::shared_ptr<Route> route = (*i)[_columns.route];
1606 (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_active_state (route) ? 1 : 0;
1611 EditorRoutes::update_solo_safe_display ()
1613 TreeModel::Children rows = _model->children();
1614 TreeModel::Children::iterator i;
1616 for (i = rows.begin(); i != rows.end(); ++i) {
1617 boost::shared_ptr<Route> route = (*i)[_columns.route];
1618 (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_active_state (route) ? 1 : 0;
1623 EditorRoutes::views () const
1625 list<TimeAxisView*> v;
1626 for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
1627 v.push_back ((*i)[_columns.tv]);
1634 EditorRoutes::clear ()
1636 _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1638 _display.set_model (_model);
1642 EditorRoutes::name_edit_started (CellEditable* ce, const Glib::ustring&)
1646 /* give it a special name */
1648 Gtk::Entry *e = dynamic_cast<Gtk::Entry*> (ce);
1651 e->set_name (X_("RouteNameEditorEntry"));
1656 EditorRoutes::name_edit (std::string const & path, std::string const & new_text)
1660 TreeIter iter = _model->get_iter (path);
1666 boost::shared_ptr<Route> route = (*iter)[_columns.route];
1668 if (route && route->name() != new_text) {
1669 route->set_name (new_text);
1674 EditorRoutes::solo_changed_so_update_mute ()
1676 update_mute_display ();
1680 EditorRoutes::show_tracks_with_regions_at_playhead ()
1682 boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
1684 set<TimeAxisView*> show;
1685 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
1686 TimeAxisView* tav = _editor->axis_view_from_route (*i);
1692 suspend_redisplay ();
1694 TreeModel::Children rows = _model->children ();
1695 for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
1696 TimeAxisView* tv = (*i)[_columns.tv];
1697 (*i)[_columns.visible] = (show.find (tv) != show.end());
1700 resume_redisplay ();