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.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::selection_changed));
226 _display.set_reorderable (true);
227 _display.set_name (X_("EditGroupList"));
228 _display.set_rules_hint (true);
229 _display.set_size_request (100, -1);
230 _display.add_object_drag (_columns.route.index(), "routes");
232 CellRendererText* name_cell = dynamic_cast<CellRendererText*> (_display.get_column_cell_renderer (_name_column));
235 name_cell->signal_editing_started().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit_started));
237 TreeViewColumn* name_column = _display.get_column (_name_column);
239 assert (name_column);
241 name_column->add_attribute (name_cell->property_editable(), _columns.name_editable);
242 name_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
243 name_column->set_expand(true);
244 name_column->set_min_width(50);
246 name_cell->property_editable() = true;
247 name_cell->signal_edited().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit));
249 // Set the visible column cell renderer to radio toggle
250 CellRendererToggle* visible_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (_visible_column));
252 visible_cell->property_activatable() = true;
253 visible_cell->property_radio() = false;
254 visible_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::visible_changed));
256 TreeViewColumn* visible_col = dynamic_cast<TreeViewColumn*> (_display.get_column (_visible_column));
257 visible_col->set_expand(false);
258 visible_col->set_sizing(TREE_VIEW_COLUMN_FIXED);
259 visible_col->set_fixed_width(30);
260 visible_col->set_alignment(ALIGN_CENTER);
262 CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (_active_column));
264 active_cell->property_activatable() = true;
265 active_cell->property_radio() = false;
266 active_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::active_changed));
268 TreeViewColumn* active_col = dynamic_cast<TreeViewColumn*> (_display.get_column (_active_column));
269 active_col->set_expand (false);
270 active_col->set_sizing (TREE_VIEW_COLUMN_FIXED);
271 active_col->set_fixed_width (30);
272 active_col->set_alignment (ALIGN_CENTER);
274 _model->signal_row_deleted().connect (sigc::mem_fun (*this, &EditorRoutes::route_deleted));
275 _model->signal_rows_reordered().connect (sigc::mem_fun (*this, &EditorRoutes::reordered));
277 _display.signal_button_press_event().connect (sigc::mem_fun (*this, &EditorRoutes::button_press), false);
278 _scroller.signal_key_press_event().connect (sigc::mem_fun(*this, &EditorRoutes::key_press), false);
280 _scroller.signal_focus_in_event().connect (sigc::mem_fun (*this, &EditorRoutes::focus_in), false);
281 _scroller.signal_focus_out_event().connect (sigc::mem_fun (*this, &EditorRoutes::focus_out));
283 _display.signal_enter_notify_event().connect (sigc::mem_fun (*this, &EditorRoutes::enter_notify), false);
284 _display.signal_leave_notify_event().connect (sigc::mem_fun (*this, &EditorRoutes::leave_notify), false);
286 _display.set_enable_search (false);
288 Route::SyncOrderKeys.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::sync_treeview_from_order_keys, this), gui_context());
292 EditorRoutes::focus_in (GdkEventFocus*)
294 Window* win = dynamic_cast<Window*> (_scroller.get_toplevel ());
297 old_focus = win->get_focus ();
304 /* try to do nothing on focus in (doesn't work, hence selection_count nonsense) */
309 EditorRoutes::focus_out (GdkEventFocus*)
312 old_focus->grab_focus ();
320 EditorRoutes::enter_notify (GdkEventCrossing*)
326 /* arm counter so that ::selection_filter() will deny selecting anything for the
327 next two attempts to change selection status.
329 selection_countdown = 2;
330 _scroller.grab_focus ();
331 Keyboard::magic_widget_grab_focus ();
336 EditorRoutes::leave_notify (GdkEventCrossing*)
338 selection_countdown = 0;
341 old_focus->grab_focus ();
345 Keyboard::magic_widget_drop_focus ();
350 EditorRoutes::set_session (Session* s)
352 SessionHandlePtr::set_session (s);
357 _session->SoloChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::solo_changed_so_update_mute, this), gui_context());
358 _session->RecordStateChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
363 EditorRoutes::on_input_active_changed (std::string const & path_string)
365 // Get the model row that has been toggled.
366 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
368 TimeAxisView* tv = row[_columns.tv];
369 RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
372 boost::shared_ptr<MidiTrack> mt;
373 mt = rtv->midi_track();
375 mt->set_input_active (!mt->input_active());
381 EditorRoutes::on_tv_rec_enable_changed (std::string const & path_string)
383 // Get the model row that has been toggled.
384 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
386 TimeAxisView* tv = row[_columns.tv];
387 RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
389 if (rtv && rtv->track()) {
390 boost::shared_ptr<RouteList> rl (new RouteList);
391 rl->push_back (rtv->route());
392 _session->set_record_enabled (rl, !rtv->track()->record_enabled(), Session::rt_cleanup);
397 EditorRoutes::on_tv_mute_enable_toggled (std::string const & path_string)
399 // Get the model row that has been toggled.
400 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
402 TimeAxisView *tv = row[_columns.tv];
403 RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
406 boost::shared_ptr<RouteList> rl (new RouteList);
407 rl->push_back (rtv->route());
408 _session->set_mute (rl, !rtv->route()->muted(), Session::rt_cleanup);
413 EditorRoutes::on_tv_solo_enable_toggled (std::string const & path_string)
415 // Get the model row that has been toggled.
416 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
418 TimeAxisView *tv = row[_columns.tv];
419 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
422 boost::shared_ptr<RouteList> rl (new RouteList);
423 rl->push_back (rtv->route());
424 if (Config->get_solo_control_is_listen_control()) {
425 _session->set_listen (rl, !rtv->route()->listening_via_monitor(), Session::rt_cleanup);
427 _session->set_solo (rl, !rtv->route()->self_soloed(), Session::rt_cleanup);
433 EditorRoutes::on_tv_solo_isolate_toggled (std::string const & path_string)
435 // Get the model row that has been toggled.
436 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
438 TimeAxisView *tv = row[_columns.tv];
439 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
442 rtv->route()->set_solo_isolated (!rtv->route()->solo_isolated(), this);
447 EditorRoutes::on_tv_solo_safe_toggled (std::string const & path_string)
449 // Get the model row that has been toggled.
450 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
452 TimeAxisView *tv = row[_columns.tv];
453 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
456 rtv->route()->set_solo_safe (!rtv->route()->solo_safe(), this);
461 EditorRoutes::build_menu ()
463 using namespace Menu_Helpers;
468 MenuList& items = _menu->items();
469 _menu->set_name ("ArdourContextMenu");
471 items.push_back (MenuElem (_("Show All"), sigc::mem_fun (*this, &EditorRoutes::show_all_routes)));
472 items.push_back (MenuElem (_("Hide All"), sigc::mem_fun (*this, &EditorRoutes::hide_all_routes)));
473 items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiotracks)));
474 items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiotracks)));
475 items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiobus)));
476 items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiobus)));
477 items.push_back (MenuElem (_("Show All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_miditracks)));
478 items.push_back (MenuElem (_("Hide All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_miditracks)));
479 items.push_back (MenuElem (_("Show Tracks With Regions Under Playhead"), sigc::mem_fun (*this, &EditorRoutes::show_tracks_with_regions_at_playhead)));
483 EditorRoutes::show_menu ()
489 _menu->popup (1, gtk_get_current_event_time());
493 EditorRoutes::redisplay ()
495 if (_no_redisplay || !_session || _session->deletion_in_progress()) {
499 TreeModel::Children rows = _model->children();
500 TreeModel::Children::iterator i;
503 /* n will be the count of tracks plus children (updated by TimeAxisView::show_at),
504 so we will use that to know where to put things.
508 for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
509 TimeAxisView *tv = (*i)[_columns.tv];
510 boost::shared_ptr<Route> route = (*i)[_columns.route];
513 // just a "title" row
517 bool visible = tv->marked_for_display ();
519 /* show or hide the TimeAxisView */
521 position += tv->show_at (position, n, &_editor->edit_controls_vbox);
530 /* whenever we go idle, update the track view list to reflect the new order.
531 we can't do this here, because we could mess up something that is traversing
532 the track order and has caused a redisplay of the list.
534 Glib::signal_idle().connect (sigc::mem_fun (*_editor, &Editor::sync_track_view_list_and_routes));
536 _editor->reset_controls_layout_height (position);
537 _editor->reset_controls_layout_width ();
538 _editor->_full_canvas_height = position;
540 if ((_editor->vertical_adjustment.get_value() + _editor->_visible_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->_visible_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)
603 PBD::Unwinder<bool> at (_adding_routes, true);
605 bool from_scratch = (_model->children().size() == 0);
606 Gtk::TreeModel::Children::iterator insert_iter = _model->children().end();
608 for (Gtk::TreeModel::Children::iterator it = _model->children().begin(); it != _model->children().end(); ++it) {
609 boost::shared_ptr<Route> r = (*it)[_columns.route];
611 if (r->order_key() == (routes.front()->route()->order_key() + routes.size())) {
618 _editor->selection->tracks.clear();
621 suspend_redisplay ();
623 _display.set_model (Glib::RefPtr<ListStore>());
625 for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) {
627 boost::shared_ptr<MidiTrack> midi_trk = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
629 TreeModel::Row row = *(_model->insert (insert_iter));
631 row[_columns.text] = (*x)->route()->name();
632 row[_columns.visible] = (*x)->marked_for_display();
633 row[_columns.active] = (*x)->route()->active ();
634 row[_columns.tv] = *x;
635 row[_columns.route] = (*x)->route ();
636 row[_columns.is_track] = (boost::dynamic_pointer_cast<Track> ((*x)->route()) != 0);
639 row[_columns.is_input_active] = midi_trk->input_active ();
640 row[_columns.is_midi] = true;
642 row[_columns.is_input_active] = false;
643 row[_columns.is_midi] = false;
646 row[_columns.mute_state] = (*x)->route()->muted() ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off;
647 row[_columns.solo_state] = RouteUI::solo_active_state ((*x)->route());
648 row[_columns.solo_visible] = !(*x)->route()->is_master ();
649 row[_columns.solo_isolate_state] = (*x)->route()->solo_isolated();
650 row[_columns.solo_safe_state] = (*x)->route()->solo_safe();
651 row[_columns.name_editable] = true;
654 _editor->selection->add(*x);
657 boost::weak_ptr<Route> wr ((*x)->route());
659 (*x)->route()->gui_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
660 (*x)->route()->PropertyChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::route_property_changed, this, _1, wr), gui_context());
662 if ((*x)->is_track()) {
663 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
664 t->RecordEnableChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
667 if ((*x)->is_midi_track()) {
668 boost::shared_ptr<MidiTrack> t = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
669 t->StepEditStatusChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
670 t->InputActiveChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_input_active_display, this), gui_context());
673 (*x)->route()->mute_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
674 (*x)->route()->solo_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
675 (*x)->route()->listen_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
676 (*x)->route()->solo_isolated_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_isolate_display, this), gui_context());
677 (*x)->route()->solo_safe_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_safe_display, this), gui_context());
678 (*x)->route()->active_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_active_display, this), gui_context ());
682 update_rec_display ();
683 update_mute_display ();
684 update_solo_display (true);
685 update_solo_isolate_display ();
686 update_solo_safe_display ();
687 update_input_active_display ();
688 update_active_display ();
691 _display.set_model (_model);
693 /* now update route order keys from the treeview/track display order */
695 sync_order_keys_from_treeview ();
699 EditorRoutes::handle_gui_changes (string const & what, void*)
701 if (_adding_routes) {
705 if (what == "track_height") {
706 /* Optional :make tracks change height while it happens, instead
712 if (what == "visible_tracks") {
718 EditorRoutes::route_removed (TimeAxisView *tv)
720 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed, tv)
722 TreeModel::Children rows = _model->children();
723 TreeModel::Children::iterator ri;
725 for (ri = rows.begin(); ri != rows.end(); ++ri) {
726 if ((*ri)[_columns.tv] == tv) {
732 /* the deleted signal for the treeview/model will take
738 EditorRoutes::route_property_changed (const PropertyChange& what_changed, boost::weak_ptr<Route> r)
740 if (!what_changed.contains (ARDOUR::Properties::name)) {
744 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_name_changed, r)
746 boost::shared_ptr<Route> route = r.lock ();
752 TreeModel::Children rows = _model->children();
753 TreeModel::Children::iterator i;
755 for (i = rows.begin(); i != rows.end(); ++i) {
756 boost::shared_ptr<Route> t = (*i)[_columns.route];
758 (*i)[_columns.text] = route->name();
765 EditorRoutes::update_active_display ()
767 TreeModel::Children rows = _model->children();
768 TreeModel::Children::iterator i;
770 for (i = rows.begin(); i != rows.end(); ++i) {
771 boost::shared_ptr<Route> route = (*i)[_columns.route];
772 (*i)[_columns.active] = route->active ();
777 EditorRoutes::update_visibility ()
779 TreeModel::Children rows = _model->children();
780 TreeModel::Children::iterator i;
782 suspend_redisplay ();
784 for (i = rows.begin(); i != rows.end(); ++i) {
785 TimeAxisView *tv = (*i)[_columns.tv];
786 (*i)[_columns.visible] = tv->marked_for_display ();
789 /* force route order keys catch up with visibility changes
792 sync_order_keys_from_treeview ();
798 EditorRoutes::hide_track_in_display (TimeAxisView& tv)
800 TreeModel::Children rows = _model->children();
801 TreeModel::Children::iterator i;
803 for (i = rows.begin(); i != rows.end(); ++i) {
804 if ((*i)[_columns.tv] == &tv) {
805 tv.set_marked_for_display (false);
806 (*i)[_columns.visible] = false;
814 EditorRoutes::show_track_in_display (TimeAxisView& tv)
816 TreeModel::Children rows = _model->children();
817 TreeModel::Children::iterator i;
820 for (i = rows.begin(); i != rows.end(); ++i) {
821 if ((*i)[_columns.tv] == &tv) {
822 tv.set_marked_for_display (true);
823 (*i)[_columns.visible] = true;
831 EditorRoutes::reset_remote_control_ids ()
833 if (Config->get_remote_model() == UserOrdered || !_session || _session->deletion_in_progress()) {
837 TreeModel::Children rows = _model->children();
844 DEBUG_TRACE (DEBUG::OrderKeys, "editor reset remote control ids\n");
846 TreeModel::Children::iterator ri;
847 bool rid_change = false;
849 uint32_t invisible_key = UINT32_MAX;
851 for (ri = rows.begin(); ri != rows.end(); ++ri) {
853 boost::shared_ptr<Route> route = (*ri)[_columns.route];
854 bool visible = (*ri)[_columns.visible];
857 if (!route->is_master() && !route->is_monitor()) {
859 uint32_t new_rid = (visible ? rid : invisible_key--);
861 if (new_rid != route->remote_control_id()) {
862 route->set_remote_control_id_explicit (new_rid);
874 /* tell the world that we changed the remote control IDs */
875 _session->notify_remote_id_change ();
881 EditorRoutes::sync_order_keys_from_treeview ()
883 if (_ignore_reorder || !_session || _session->deletion_in_progress()) {
887 TreeModel::Children rows = _model->children();
894 DEBUG_TRACE (DEBUG::OrderKeys, "editor sync order keys from treeview\n");
896 TreeModel::Children::iterator ri;
897 bool changed = false;
898 bool rid_change = false;
901 uint32_t invisible_key = UINT32_MAX;
903 for (ri = rows.begin(); ri != rows.end(); ++ri) {
905 boost::shared_ptr<Route> route = (*ri)[_columns.route];
906 bool visible = (*ri)[_columns.visible];
908 uint32_t old_key = route->order_key ();
910 if (order != old_key) {
911 route->set_order_key (order);
916 if ((Config->get_remote_model() == MixerOrdered) && !route->is_master() && !route->is_monitor()) {
918 uint32_t new_rid = (visible ? rid : invisible_key--);
920 if (new_rid != route->remote_control_id()) {
921 route->set_remote_control_id_explicit (new_rid);
935 /* tell the world that we changed the editor sort keys */
936 _session->sync_order_keys ();
940 /* tell the world that we changed the remote control IDs */
941 _session->notify_remote_id_change ();
946 EditorRoutes::sync_treeview_from_order_keys ()
948 /* Some route order key(s) have been changed, make sure that
949 we update out tree/list model and GUI to reflect the change.
952 if (_ignore_reorder || !_session || _session->deletion_in_progress()) {
956 DEBUG_TRACE (DEBUG::OrderKeys, "editor sync model from order keys.\n");
958 /* we could get here after either a change in the Mixer or Editor sort
959 * order, but either way, the mixer order keys reflect the intended
960 * order for the GUI, so reorder the treeview model to match it.
963 vector<int> neworder;
964 TreeModel::Children rows = _model->children();
965 uint32_t old_order = 0;
966 bool changed = false;
972 OrderKeySortedRoutes sorted_routes;
974 for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++old_order) {
975 boost::shared_ptr<Route> route = (*ri)[_columns.route];
976 sorted_routes.push_back (RoutePlusOrderKey (route, old_order, route->order_key ()));
979 SortByNewDisplayOrder cmp;
981 sort (sorted_routes.begin(), sorted_routes.end(), cmp);
982 neworder.assign (sorted_routes.size(), 0);
986 for (OrderKeySortedRoutes::iterator sr = sorted_routes.begin(); sr != sorted_routes.end(); ++sr, ++n) {
988 neworder[n] = sr->old_display_order;
990 if (sr->old_display_order != n) {
994 DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("EDITOR change order for %1 from %2 to %3\n",
995 sr->route->name(), sr->old_display_order, n));
999 Unwinder<bool> uw (_ignore_reorder, true);
1000 _model->reorder (neworder);
1007 EditorRoutes::hide_all_tracks (bool /*with_select*/)
1009 TreeModel::Children rows = _model->children();
1010 TreeModel::Children::iterator i;
1012 suspend_redisplay ();
1014 for (i = rows.begin(); i != rows.end(); ++i) {
1016 TreeModel::Row row = (*i);
1017 TimeAxisView *tv = row[_columns.tv];
1023 row[_columns.visible] = false;
1026 resume_redisplay ();
1030 EditorRoutes::set_all_tracks_visibility (bool yn)
1032 TreeModel::Children rows = _model->children();
1033 TreeModel::Children::iterator i;
1035 suspend_redisplay ();
1037 for (i = rows.begin(); i != rows.end(); ++i) {
1039 TreeModel::Row row = (*i);
1040 TimeAxisView* tv = row[_columns.tv];
1046 tv->set_marked_for_display (yn);
1047 (*i)[_columns.visible] = yn;
1050 /* force route order keys catch up with visibility changes
1053 sync_order_keys_from_treeview ();
1055 resume_redisplay ();
1059 EditorRoutes::set_all_audio_midi_visibility (int tracks, bool yn)
1061 TreeModel::Children rows = _model->children();
1062 TreeModel::Children::iterator i;
1064 suspend_redisplay ();
1066 for (i = rows.begin(); i != rows.end(); ++i) {
1068 TreeModel::Row row = (*i);
1069 TimeAxisView* tv = row[_columns.tv];
1071 AudioTimeAxisView* atv;
1072 MidiTimeAxisView* mtv;
1078 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
1081 (*i)[_columns.visible] = yn;
1085 if (atv->is_audio_track()) {
1086 (*i)[_columns.visible] = yn;
1091 if (!atv->is_audio_track()) {
1092 (*i)[_columns.visible] = yn;
1097 else if ((mtv = dynamic_cast<MidiTimeAxisView*>(tv)) != 0) {
1100 (*i)[_columns.visible] = yn;
1104 if (mtv->is_midi_track()) {
1105 (*i)[_columns.visible] = yn;
1112 /* force route order keys catch up with visibility changes
1115 sync_order_keys_from_treeview ();
1117 resume_redisplay ();
1121 EditorRoutes::hide_all_routes ()
1123 set_all_tracks_visibility (false);
1127 EditorRoutes::show_all_routes ()
1129 set_all_tracks_visibility (true);
1133 EditorRoutes::show_all_audiotracks()
1135 set_all_audio_midi_visibility (1, true);
1138 EditorRoutes::hide_all_audiotracks ()
1140 set_all_audio_midi_visibility (1, false);
1144 EditorRoutes::show_all_audiobus ()
1146 set_all_audio_midi_visibility (2, true);
1149 EditorRoutes::hide_all_audiobus ()
1151 set_all_audio_midi_visibility (2, false);
1155 EditorRoutes::show_all_miditracks()
1157 set_all_audio_midi_visibility (3, true);
1160 EditorRoutes::hide_all_miditracks ()
1162 set_all_audio_midi_visibility (3, false);
1166 EditorRoutes::key_press (GdkEventKey* ev)
1168 TreeViewColumn *col;
1169 boost::shared_ptr<RouteList> rl (new RouteList);
1172 switch (ev->keyval) {
1174 case GDK_ISO_Left_Tab:
1176 /* If we appear to be editing something, leave that cleanly and appropriately.
1178 if (name_editable) {
1179 name_editable->editing_done ();
1183 col = _display.get_column (_name_column); // select&focus on name column
1185 if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
1186 treeview_select_previous (_display, _model, col);
1188 treeview_select_next (_display, _model, col);
1195 if (get_relevant_routes (rl)) {
1196 _session->set_mute (rl, !rl->front()->muted(), Session::rt_cleanup);
1202 if (get_relevant_routes (rl)) {
1203 if (Config->get_solo_control_is_listen_control()) {
1204 _session->set_listen (rl, !rl->front()->listening_via_monitor(), Session::rt_cleanup);
1206 _session->set_solo (rl, !rl->front()->self_soloed(), Session::rt_cleanup);
1213 if (get_relevant_routes (rl)) {
1214 _session->set_record_enabled (rl, !rl->front()->record_enabled(), Session::rt_cleanup);
1226 EditorRoutes::get_relevant_routes (boost::shared_ptr<RouteList> rl)
1229 RouteTimeAxisView* rtv;
1230 RefPtr<TreeSelection> selection = _display.get_selection();
1234 if (selection->count_selected_rows() != 0) {
1238 RefPtr<TreeModel> tm = RefPtr<TreeModel>::cast_dynamic (_model);
1239 iter = selection->get_selected (tm);
1242 /* use mouse pointer */
1247 _display.get_pointer (x, y);
1248 _display.convert_widget_to_bin_window_coords (x, y, bx, by);
1250 if (_display.get_path_at_pos (bx, by, path)) {
1251 iter = _model->get_iter (path);
1256 tv = (*iter)[_columns.tv];
1258 rtv = dynamic_cast<RouteTimeAxisView*>(tv);
1260 rl->push_back (rtv->route());
1265 return !rl->empty();
1269 EditorRoutes::button_press (GdkEventButton* ev)
1271 if (Keyboard::is_context_menu_event (ev)) {
1276 TreeModel::Path path;
1277 TreeViewColumn *tvc;
1281 if (!_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y)) {
1282 /* cancel selection */
1283 _display.get_selection()->unselect_all ();
1284 /* end any editing by grabbing focus */
1285 _display.grab_focus ();
1289 //Scroll editor canvas to selected track
1290 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1292 Gtk::TreeModel::Row row = *_model->get_iter (path);
1293 TimeAxisView *tv = row[_columns.tv];
1296 _editor->ensure_time_axis_view_is_visible (*tv, true);
1304 EditorRoutes::selection_changed ()
1306 if (_display.get_selection()->count_selected_rows() > 0) {
1309 TreeView::Selection::ListHandle_Path rows = _display.get_selection()->get_selected_rows ();
1310 TrackViewList selected;
1312 _editor->get_selection().clear_regions ();
1314 for (TreeView::Selection::ListHandle_Path::iterator i = rows.begin(); i != rows.end(); ++i) {
1316 if ((iter = _model->get_iter (*i))) {
1318 TimeAxisView* tv = (*iter)[_columns.tv];
1319 selected.push_back (tv);
1324 _editor->get_selection().set (selected);
1325 _editor->ensure_time_axis_view_is_visible (*(selected.front()), true);
1328 _editor->get_selection().clear_tracks ();
1333 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const&, bool /*selected*/)
1335 if (selection_countdown) {
1336 if (--selection_countdown == 0) {
1339 /* no selection yet ... */
1346 struct EditorOrderRouteSorter {
1347 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1348 if (a->is_master()) {
1349 /* master before everything else */
1351 } else if (b->is_master()) {
1352 /* everything else before master */
1355 return a->order_key () < b->order_key ();
1360 EditorRoutes::initial_display ()
1362 suspend_redisplay ();
1366 resume_redisplay ();
1370 boost::shared_ptr<RouteList> routes = _session->get_routes();
1372 if (ARDOUR_UI::instance()->session_is_new ()) {
1374 /* new session: stamp all routes with the right editor order
1378 _editor->add_routes (*(routes.get()));
1382 /* existing session: sort a copy of the route list by
1383 * editor-order and add its contents to the display.
1386 RouteList r (*routes);
1387 EditorOrderRouteSorter sorter;
1390 _editor->add_routes (r);
1394 resume_redisplay ();
1398 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
1400 const SelectionData& data,
1401 guint info, guint time)
1403 if (data.get_target() == "GTK_TREE_MODEL_ROW") {
1404 _display.on_drag_data_received (context, x, y, data, info, time);
1408 context->drag_finish (true, false, time);
1412 EditorRoutes::move_selected_tracks (bool up)
1414 if (_editor->selection->tracks.empty()) {
1418 typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
1419 std::list<ViewRoute> view_routes;
1420 std::vector<int> neworder;
1421 TreeModel::Children rows = _model->children();
1422 TreeModel::Children::iterator ri;
1424 for (ri = rows.begin(); ri != rows.end(); ++ri) {
1425 TimeAxisView* tv = (*ri)[_columns.tv];
1426 boost::shared_ptr<Route> route = (*ri)[_columns.route];
1428 view_routes.push_back (ViewRoute (tv, route));
1431 list<ViewRoute>::iterator trailing;
1432 list<ViewRoute>::iterator leading;
1436 trailing = view_routes.begin();
1437 leading = view_routes.begin();
1441 while (leading != view_routes.end()) {
1442 if (_editor->selection->selected (leading->first)) {
1443 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
1444 leading = view_routes.erase (leading);
1453 /* if we could use reverse_iterator in list::insert, this code
1454 would be a beautiful reflection of the code above. but we can't
1455 and so it looks like a bit of a mess.
1458 trailing = view_routes.end();
1459 leading = view_routes.end();
1461 --leading; if (leading == view_routes.begin()) { return; }
1467 if (_editor->selection->selected (leading->first)) {
1468 list<ViewRoute>::iterator tmp;
1470 /* need to insert *after* trailing, not *before* it,
1471 which is what insert (iter, val) normally does.
1477 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
1479 /* can't use iter = cont.erase (iter); form here, because
1480 we need iter to move backwards.
1488 if (leading == view_routes.begin()) {
1489 /* the one we've just inserted somewhere else
1490 was the first in the list. erase this copy,
1491 and then break, because we're done.
1496 view_routes.erase (leading);
1505 if (leading == view_routes.begin()) {
1514 for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
1515 uint32_t order = leading->second->order_key ();
1516 neworder.push_back (order);
1520 DEBUG_TRACE (DEBUG::OrderKeys, "New order after moving tracks:\n");
1521 for (vector<int>::iterator i = neworder.begin(); i != neworder.end(); ++i) {
1522 DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("\t%1\n", *i));
1524 DEBUG_TRACE (DEBUG::OrderKeys, "-------\n");
1526 for (vector<int>::iterator i = neworder.begin(); i != neworder.end(); ++i) {
1527 if (*i >= (int) neworder.size()) {
1528 cerr << "Trying to move something to " << *i << " of " << neworder.size() << endl;
1530 assert (*i < (int) neworder.size ());
1534 _model->reorder (neworder);
1538 EditorRoutes::update_input_active_display ()
1540 TreeModel::Children rows = _model->children();
1541 TreeModel::Children::iterator i;
1543 for (i = rows.begin(); i != rows.end(); ++i) {
1544 boost::shared_ptr<Route> route = (*i)[_columns.route];
1546 if (boost::dynamic_pointer_cast<Track> (route)) {
1547 boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
1550 (*i)[_columns.is_input_active] = mt->input_active();
1557 EditorRoutes::update_rec_display ()
1559 TreeModel::Children rows = _model->children();
1560 TreeModel::Children::iterator i;
1562 for (i = rows.begin(); i != rows.end(); ++i) {
1563 boost::shared_ptr<Route> route = (*i)[_columns.route];
1565 if (boost::dynamic_pointer_cast<Track> (route)) {
1566 boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
1568 if (route->record_enabled()) {
1569 if (_session->record_status() == Session::Recording) {
1570 (*i)[_columns.rec_state] = 1;
1572 (*i)[_columns.rec_state] = 2;
1574 } else if (mt && mt->step_editing()) {
1575 (*i)[_columns.rec_state] = 3;
1577 (*i)[_columns.rec_state] = 0;
1580 (*i)[_columns.name_editable] = !route->record_enabled ();
1586 EditorRoutes::update_mute_display ()
1588 TreeModel::Children rows = _model->children();
1589 TreeModel::Children::iterator i;
1591 for (i = rows.begin(); i != rows.end(); ++i) {
1592 boost::shared_ptr<Route> route = (*i)[_columns.route];
1593 (*i)[_columns.mute_state] = RouteUI::mute_active_state (_session, route);
1598 EditorRoutes::update_solo_display (bool /* selfsoloed */)
1600 TreeModel::Children rows = _model->children();
1601 TreeModel::Children::iterator i;
1603 for (i = rows.begin(); i != rows.end(); ++i) {
1604 boost::shared_ptr<Route> route = (*i)[_columns.route];
1605 (*i)[_columns.solo_state] = RouteUI::solo_active_state (route);
1610 EditorRoutes::update_solo_isolate_display ()
1612 TreeModel::Children rows = _model->children();
1613 TreeModel::Children::iterator i;
1615 for (i = rows.begin(); i != rows.end(); ++i) {
1616 boost::shared_ptr<Route> route = (*i)[_columns.route];
1617 (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_active_state (route) ? 1 : 0;
1622 EditorRoutes::update_solo_safe_display ()
1624 TreeModel::Children rows = _model->children();
1625 TreeModel::Children::iterator i;
1627 for (i = rows.begin(); i != rows.end(); ++i) {
1628 boost::shared_ptr<Route> route = (*i)[_columns.route];
1629 (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_active_state (route) ? 1 : 0;
1634 EditorRoutes::views () const
1636 list<TimeAxisView*> v;
1637 for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
1638 v.push_back ((*i)[_columns.tv]);
1645 EditorRoutes::clear ()
1647 _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1649 _display.set_model (_model);
1653 EditorRoutes::name_edit_started (CellEditable* ce, const Glib::ustring&)
1657 /* give it a special name */
1659 Gtk::Entry *e = dynamic_cast<Gtk::Entry*> (ce);
1662 e->set_name (X_("RouteNameEditorEntry"));
1667 EditorRoutes::name_edit (std::string const & path, std::string const & new_text)
1671 TreeIter iter = _model->get_iter (path);
1677 boost::shared_ptr<Route> route = (*iter)[_columns.route];
1679 if (route && route->name() != new_text) {
1680 route->set_name (new_text);
1685 EditorRoutes::solo_changed_so_update_mute ()
1687 update_mute_display ();
1691 EditorRoutes::show_tracks_with_regions_at_playhead ()
1693 boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
1695 set<TimeAxisView*> show;
1696 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
1697 TimeAxisView* tav = _editor->axis_view_from_route (*i);
1703 suspend_redisplay ();
1705 TreeModel::Children rows = _model->children ();
1706 for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
1707 TimeAxisView* tv = (*i)[_columns.tv];
1708 (*i)[_columns.visible] = (show.find (tv) != show.end());
1711 resume_redisplay ();