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/midi_track.h"
32 #include "ardour/route.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"
40 #include "ardour_ui.h"
41 #include "audio_time_axis.h"
43 #include "editor_group_tabs.h"
44 #include "editor_routes.h"
45 #include "gui_thread.h"
47 #include "midi_time_axis.h"
48 #include "mixer_strip.h"
49 #include "plugin_setup_dialog.h"
50 #include "route_sorter.h"
57 using namespace ARDOUR;
58 using namespace ARDOUR_UI_UTILS;
61 using namespace Gtkmm2ext;
63 using Gtkmm2ext::Keyboard;
71 EditorRoutes::EditorRoutes (Editor* e)
73 , _ignore_reorder (false)
74 , _no_redisplay (false)
75 , _adding_routes (false)
76 , _route_deletion_in_progress (false)
77 , _redisplay_on_resume (false)
78 , _redisplay_active (0)
79 , _queue_tv_update (0)
82 , selection_countdown (0)
85 static const int column_width = 22;
87 _scroller.add (_display);
88 _scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
90 _model = ListStore::create (_columns);
91 _display.set_model (_model);
93 // Record enable toggle
94 CellRendererPixbufMulti* rec_col_renderer = manage (new CellRendererPixbufMulti());
96 rec_col_renderer->set_pixbuf (0, ::get_icon("record-normal-disabled"));
97 rec_col_renderer->set_pixbuf (1, ::get_icon("record-normal-in-progress"));
98 rec_col_renderer->set_pixbuf (2, ::get_icon("record-normal-enabled"));
99 rec_col_renderer->set_pixbuf (3, ::get_icon("record-step"));
100 rec_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_rec_enable_changed));
102 TreeViewColumn* rec_state_column = manage (new TreeViewColumn("R", *rec_col_renderer));
104 rec_state_column->add_attribute(rec_col_renderer->property_state(), _columns.rec_state);
105 rec_state_column->add_attribute(rec_col_renderer->property_visible(), _columns.is_track);
107 rec_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
108 rec_state_column->set_alignment(ALIGN_CENTER);
109 rec_state_column->set_expand(false);
110 rec_state_column->set_fixed_width(column_width);
113 // Record safe toggle
114 CellRendererPixbufMulti* rec_safe_renderer = manage (new CellRendererPixbufMulti ());
116 rec_safe_renderer->set_pixbuf (0, ::get_icon("rec-safe-disabled"));
117 rec_safe_renderer->set_pixbuf (1, ::get_icon("rec-safe-enabled"));
118 rec_safe_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_rec_safe_toggled));
120 TreeViewColumn* rec_safe_column = manage (new TreeViewColumn(_("RS"), *rec_safe_renderer));
121 rec_safe_column->add_attribute(rec_safe_renderer->property_state(), _columns.rec_safe);
122 rec_safe_column->add_attribute(rec_safe_renderer->property_visible(), _columns.is_track);
123 rec_safe_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
124 rec_safe_column->set_alignment(ALIGN_CENTER);
125 rec_safe_column->set_expand(false);
126 rec_safe_column->set_fixed_width(column_width);
131 CellRendererPixbufMulti* input_active_col_renderer = manage (new CellRendererPixbufMulti());
132 input_active_col_renderer->set_pixbuf (0, ::get_icon("midi-input-inactive"));
133 input_active_col_renderer->set_pixbuf (1, ::get_icon("midi-input-active"));
134 input_active_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_input_active_changed));
136 TreeViewColumn* input_active_column = manage (new TreeViewColumn ("I", *input_active_col_renderer));
138 input_active_column->add_attribute(input_active_col_renderer->property_state(), _columns.is_input_active);
139 input_active_column->add_attribute (input_active_col_renderer->property_visible(), _columns.is_midi);
141 input_active_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
142 input_active_column->set_alignment(ALIGN_CENTER);
143 input_active_column->set_expand(false);
144 input_active_column->set_fixed_width(column_width);
146 // Mute enable toggle
147 CellRendererPixbufMulti* mute_col_renderer = manage (new CellRendererPixbufMulti());
149 mute_col_renderer->set_pixbuf (Gtkmm2ext::Off, ::get_icon("mute-disabled"));
150 mute_col_renderer->set_pixbuf (Gtkmm2ext::ImplicitActive, ::get_icon("muted-by-others"));
151 mute_col_renderer->set_pixbuf (Gtkmm2ext::ExplicitActive, ::get_icon("mute-enabled"));
152 mute_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_mute_enable_toggled));
154 TreeViewColumn* mute_state_column = manage (new TreeViewColumn("M", *mute_col_renderer));
156 mute_state_column->add_attribute(mute_col_renderer->property_state(), _columns.mute_state);
157 mute_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
158 mute_state_column->set_alignment(ALIGN_CENTER);
159 mute_state_column->set_expand(false);
160 mute_state_column->set_fixed_width(15);
162 // Solo enable toggle
163 CellRendererPixbufMulti* solo_col_renderer = manage (new CellRendererPixbufMulti());
165 solo_col_renderer->set_pixbuf (Gtkmm2ext::Off, ::get_icon("solo-disabled"));
166 solo_col_renderer->set_pixbuf (Gtkmm2ext::ExplicitActive, ::get_icon("solo-enabled"));
167 solo_col_renderer->set_pixbuf (Gtkmm2ext::ImplicitActive, ::get_icon("soloed-by-others"));
168 solo_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_enable_toggled));
170 TreeViewColumn* solo_state_column = manage (new TreeViewColumn("S", *solo_col_renderer));
172 solo_state_column->add_attribute(solo_col_renderer->property_state(), _columns.solo_state);
173 solo_state_column->add_attribute(solo_col_renderer->property_visible(), _columns.solo_visible);
174 solo_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
175 solo_state_column->set_alignment(ALIGN_CENTER);
176 solo_state_column->set_expand(false);
177 solo_state_column->set_fixed_width(column_width);
179 // Solo isolate toggle
180 CellRendererPixbufMulti* solo_iso_renderer = manage (new CellRendererPixbufMulti());
182 solo_iso_renderer->set_pixbuf (0, ::get_icon("solo-isolate-disabled"));
183 solo_iso_renderer->set_pixbuf (1, ::get_icon("solo-isolate-enabled"));
184 solo_iso_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_isolate_toggled));
186 TreeViewColumn* solo_isolate_state_column = manage (new TreeViewColumn("SI", *solo_iso_renderer));
188 solo_isolate_state_column->add_attribute(solo_iso_renderer->property_state(), _columns.solo_isolate_state);
189 solo_isolate_state_column->add_attribute(solo_iso_renderer->property_visible(), _columns.solo_visible);
190 solo_isolate_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
191 solo_isolate_state_column->set_alignment(ALIGN_CENTER);
192 solo_isolate_state_column->set_expand(false);
193 solo_isolate_state_column->set_fixed_width(column_width);
196 CellRendererPixbufMulti* solo_safe_renderer = manage (new CellRendererPixbufMulti ());
198 solo_safe_renderer->set_pixbuf (0, ::get_icon("solo-safe-disabled"));
199 solo_safe_renderer->set_pixbuf (1, ::get_icon("solo-safe-enabled"));
200 solo_safe_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_safe_toggled));
202 TreeViewColumn* solo_safe_state_column = manage (new TreeViewColumn(_("SS"), *solo_safe_renderer));
203 solo_safe_state_column->add_attribute(solo_safe_renderer->property_state(), _columns.solo_safe_state);
204 solo_safe_state_column->add_attribute(solo_safe_renderer->property_visible(), _columns.solo_visible);
205 solo_safe_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
206 solo_safe_state_column->set_alignment(ALIGN_CENTER);
207 solo_safe_state_column->set_expand(false);
208 solo_safe_state_column->set_fixed_width(column_width);
210 _name_column = _display.append_column ("", _columns.text) - 1;
211 _visible_column = _display.append_column ("", _columns.visible) - 1;
212 _active_column = _display.append_column ("", _columns.active) - 1;
214 _display.append_column (*input_active_column);
215 _display.append_column (*rec_state_column);
216 _display.append_column (*rec_safe_column);
217 _display.append_column (*mute_state_column);
218 _display.append_column (*solo_state_column);
219 _display.append_column (*solo_isolate_state_column);
220 _display.append_column (*solo_safe_state_column);
227 { 0, _("Name"), _("Track/Bus Name") },
228 { 1, S_("Visible|V"), _("Track/Bus visible ?") },
229 { 2, S_("Active|A"), _("Track/Bus active ?") },
230 { 3, S_("MidiInput|I"), _("MIDI input enabled") },
231 { 4, S_("Rec|R"), _("Record enabled") },
232 { 5, S_("Rec|RS"), _("Record Safe") },
233 { 6, S_("Mute|M"), _("Muted") },
234 { 7, S_("Solo|S"), _("Soloed") },
235 { 8, S_("SoloIso|SI"), _("Solo Isolated") },
236 { 9, S_("SoloLock|SS"), _("Solo Safe (Locked)") },
240 for (int i = 0; ci[i].index >= 0; ++i) {
241 col = _display.get_column (ci[i].index);
242 l = manage (new Label (ci[i].label));
243 set_tooltip (*l, ci[i].tooltip);
244 col->set_widget (*l);
248 _display.set_headers_visible (true);
249 _display.get_selection()->set_mode (SELECTION_SINGLE);
250 _display.get_selection()->set_select_function (sigc::mem_fun (*this, &EditorRoutes::selection_filter));
251 _display.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::selection_changed));
252 _display.set_reorderable (true);
253 _display.set_name (X_("EditGroupList"));
254 _display.set_rules_hint (true);
255 _display.set_size_request (100, -1);
256 _display.add_object_drag (_columns.route.index(), "routes");
258 CellRendererText* name_cell = dynamic_cast<CellRendererText*> (_display.get_column_cell_renderer (_name_column));
261 name_cell->signal_editing_started().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit_started));
263 TreeViewColumn* name_column = _display.get_column (_name_column);
265 assert (name_column);
267 name_column->add_attribute (name_cell->property_editable(), _columns.name_editable);
268 name_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
269 name_column->set_expand(true);
270 name_column->set_min_width(50);
272 name_cell->property_editable() = true;
273 name_cell->signal_edited().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit));
275 // Set the visible column cell renderer to radio toggle
276 CellRendererToggle* visible_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (_visible_column));
278 visible_cell->property_activatable() = true;
279 visible_cell->property_radio() = false;
280 visible_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::visible_changed));
282 TreeViewColumn* visible_col = dynamic_cast<TreeViewColumn*> (_display.get_column (_visible_column));
283 visible_col->set_expand(false);
284 visible_col->set_sizing(TREE_VIEW_COLUMN_FIXED);
285 visible_col->set_fixed_width(30);
286 visible_col->set_alignment(ALIGN_CENTER);
288 CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (_active_column));
290 active_cell->property_activatable() = true;
291 active_cell->property_radio() = false;
292 active_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::active_changed));
294 TreeViewColumn* active_col = dynamic_cast<TreeViewColumn*> (_display.get_column (_active_column));
295 active_col->set_expand (false);
296 active_col->set_sizing (TREE_VIEW_COLUMN_FIXED);
297 active_col->set_fixed_width (30);
298 active_col->set_alignment (ALIGN_CENTER);
300 _model->signal_row_deleted().connect (sigc::mem_fun (*this, &EditorRoutes::row_deleted));
301 _model->signal_rows_reordered().connect (sigc::mem_fun (*this, &EditorRoutes::reordered));
303 _display.signal_button_press_event().connect (sigc::mem_fun (*this, &EditorRoutes::button_press), false);
304 _scroller.signal_key_press_event().connect (sigc::mem_fun(*this, &EditorRoutes::key_press), false);
306 _scroller.signal_focus_in_event().connect (sigc::mem_fun (*this, &EditorRoutes::focus_in), false);
307 _scroller.signal_focus_out_event().connect (sigc::mem_fun (*this, &EditorRoutes::focus_out));
309 _display.signal_enter_notify_event().connect (sigc::mem_fun (*this, &EditorRoutes::enter_notify), false);
310 _display.signal_leave_notify_event().connect (sigc::mem_fun (*this, &EditorRoutes::leave_notify), false);
312 _display.set_enable_search (false);
314 Route::SyncOrderKeys.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::sync_treeview_from_order_keys, this), gui_context());
315 Route::PluginSetup.connect_same_thread (*this, boost::bind (&EditorRoutes::plugin_setup, this, _1, _2, _3));
320 EditorRoutes::focus_in (GdkEventFocus*)
322 Window* win = dynamic_cast<Window*> (_scroller.get_toplevel ());
325 old_focus = win->get_focus ();
332 /* try to do nothing on focus in (doesn't work, hence selection_count nonsense) */
337 EditorRoutes::focus_out (GdkEventFocus*)
340 old_focus->grab_focus ();
348 EditorRoutes::enter_notify (GdkEventCrossing*)
354 /* arm counter so that ::selection_filter() will deny selecting anything for the
355 * next two attempts to change selection status.
357 selection_countdown = 2;
358 _scroller.grab_focus ();
359 Keyboard::magic_widget_grab_focus ();
364 EditorRoutes::leave_notify (GdkEventCrossing*)
366 selection_countdown = 0;
369 old_focus->grab_focus ();
373 Keyboard::magic_widget_drop_focus ();
378 EditorRoutes::set_session (Session* s)
380 SessionHandlePtr::set_session (s);
385 _session->SoloChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::solo_changed_so_update_mute, this), gui_context());
386 _session->RecordStateChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
388 /* TODO: check if these needs to be tied in with DisplaySuspender
389 * Given that the UI is single-threaded and DisplaySuspender is only used
390 * in loops in the UI thread all should be fine.
392 _session->BatchUpdateStart.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::suspend_redisplay, this), gui_context());
393 _session->BatchUpdateEnd.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::resume_redisplay, this), gui_context());
398 EditorRoutes::on_input_active_changed (std::string const & path_string)
400 // Get the model row that has been toggled.
401 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
403 TimeAxisView* tv = row[_columns.tv];
404 RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
407 boost::shared_ptr<MidiTrack> mt;
408 mt = rtv->midi_track();
410 mt->set_input_active (!mt->input_active());
416 EditorRoutes::on_tv_rec_enable_changed (std::string const & path_string)
418 // Get the model row that has been toggled.
419 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
421 TimeAxisView* tv = row[_columns.tv];
422 RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
424 if (rtv && rtv->track()) {
426 boost::shared_ptr<RouteList> rl (new RouteList);
427 // TODO check rec-safe and ...
428 rl->push_back (rtv->route());
429 _session->set_record_enabled (rl, !rtv->track()->record_enabled(), Session::rt_cleanup);
434 EditorRoutes::on_tv_rec_safe_toggled (std::string const & path_string)
436 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);
440 if (rtv && rtv->track() && !rtv->track()->record_enabled()) {
442 boost::shared_ptr<RouteList> rl (new RouteList);
443 rl->push_back (rtv->route());
444 _session->set_record_safe (rl, !rtv->track()->record_safe(), Session::rt_cleanup);
449 EditorRoutes::on_tv_mute_enable_toggled (std::string const & path_string)
451 // Get the model row that has been toggled.
452 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
454 TimeAxisView *tv = row[_columns.tv];
455 RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
458 boost::shared_ptr<RouteList> rl (new RouteList);
459 rl->push_back (rtv->route());
460 _session->set_mute (rl, !rtv->route()->muted(), Session::rt_cleanup);
465 EditorRoutes::on_tv_solo_enable_toggled (std::string const & path_string)
467 // Get the model row that has been toggled.
468 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
470 TimeAxisView *tv = row[_columns.tv];
471 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
474 boost::shared_ptr<RouteList> rl (new RouteList);
475 rl->push_back (rtv->route());
476 if (Config->get_solo_control_is_listen_control()) {
477 _session->set_listen (rl, !rtv->route()->listening_via_monitor(), Session::rt_cleanup);
479 _session->set_solo (rl, !rtv->route()->self_soloed(), Session::rt_cleanup);
485 EditorRoutes::on_tv_solo_isolate_toggled (std::string const & path_string)
487 // Get the model row that has been toggled.
488 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
490 TimeAxisView *tv = row[_columns.tv];
491 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
494 rtv->route()->set_solo_isolated (!rtv->route()->solo_isolated(), Controllable::UseGroup);
499 EditorRoutes::on_tv_solo_safe_toggled (std::string const & path_string)
501 // Get the model row that has been toggled.
502 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
504 TimeAxisView *tv = row[_columns.tv];
505 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
508 rtv->route()->set_solo_safe (!rtv->route()->solo_safe(), Controllable::UseGroup);
513 EditorRoutes::build_menu ()
515 using namespace Menu_Helpers;
520 MenuList& items = _menu->items();
521 _menu->set_name ("ArdourContextMenu");
523 items.push_back (MenuElem (_("Show All"), sigc::mem_fun (*this, &EditorRoutes::show_all_routes)));
524 items.push_back (MenuElem (_("Hide All"), sigc::mem_fun (*this, &EditorRoutes::hide_all_routes)));
525 items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiotracks)));
526 items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiotracks)));
527 items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiobus)));
528 items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiobus)));
529 items.push_back (MenuElem (_("Show All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_miditracks)));
530 items.push_back (MenuElem (_("Hide All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_miditracks)));
531 items.push_back (MenuElem (_("Only Show Tracks with Regions Under Playhead"), sigc::mem_fun (*this, &EditorRoutes::show_tracks_with_regions_at_playhead)));
535 EditorRoutes::show_menu ()
541 _menu->popup (1, gtk_get_current_event_time());
545 EditorRoutes::redisplay_real ()
547 TreeModel::Children rows = _model->children();
548 TreeModel::Children::iterator i;
551 /* n will be the count of tracks plus children (updated by TimeAxisView::show_at),
552 * so we will use that to know where to put things.
556 for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
557 TimeAxisView *tv = (*i)[_columns.tv];
558 boost::shared_ptr<Route> route = (*i)[_columns.route];
561 // just a "title" row
565 bool visible = tv->marked_for_display ();
567 /* show or hide the TimeAxisView */
569 position += tv->show_at (position, n, &_editor->edit_controls_vbox);
577 /* whenever we go idle, update the track view list to reflect the new order.
578 * we can't do this here, because we could mess up something that is traversing
579 * the track order and has caused a redisplay of the list.
581 Glib::signal_idle().connect (sigc::mem_fun (*_editor, &Editor::sync_track_view_list_and_routes));
583 _editor->reset_controls_layout_height (position);
584 _editor->reset_controls_layout_width ();
585 _editor->_full_canvas_height = position;
587 if ((_editor->vertical_adjustment.get_value() + _editor->_visible_canvas_height) > _editor->vertical_adjustment.get_upper()) {
589 * We're increasing the size of the canvas while the bottom is visible.
590 * We scroll down to keep in step with the controls layout.
592 _editor->vertical_adjustment.set_value (_editor->_full_canvas_height - _editor->_visible_canvas_height);
597 EditorRoutes::redisplay ()
599 if (!_session || _session->deletion_in_progress()) {
604 _redisplay_on_resume = true;
608 // model deprecated g_atomic_int_exchange_and_add(, 1)
609 g_atomic_int_inc(const_cast<gint*>(&_redisplay_active));
610 if (!g_atomic_int_compare_and_exchange (const_cast<gint*>(&_redisplay_active), 1, 1)) {
611 /* recursive re-display can happen if redisplay shows/hides a TrackView
612 * which has children and their display status changes as result.
619 while (!g_atomic_int_compare_and_exchange (const_cast<gint*>(&_redisplay_active), 1, 0)) {
620 g_atomic_int_set(const_cast<gint*>(&_redisplay_active), 1);
626 EditorRoutes::row_deleted (Gtk::TreeModel::Path const &)
628 if (!_session || _session->deletion_in_progress()) {
631 /* this happens as the second step of a DnD within the treeview, and
632 * when a route is actually removed. we don't differentiate between
635 * note that the sync_orders_keys() step may not actually change any
636 * RID's (e.g. the last track may be removed, so all other tracks keep
637 * the same RID), which means that no redisplay would happen. so we
638 * have to force a redisplay.
641 DEBUG_TRACE (DEBUG::OrderKeys, "editor routes treeview row deleted\n");
644 sync_order_keys_from_treeview ();
648 EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
650 /* reordering implies that RID's will change, so sync_order_keys() will
654 DEBUG_TRACE (DEBUG::OrderKeys, "editor routes treeview reordered\n");
655 sync_order_keys_from_treeview ();
659 EditorRoutes::visible_changed (std::string const & path)
661 if (_session && _session->deletion_in_progress()) {
668 if ((iter = _model->get_iter (path))) {
669 TimeAxisView* tv = (*iter)[_columns.tv];
671 bool visible = (*iter)[_columns.visible];
673 if (tv->set_marked_for_display (!visible)) {
674 update_visibility ();
681 EditorRoutes::active_changed (std::string const & path)
683 if (_session && _session->deletion_in_progress ()) {
687 Gtk::TreeModel::Row row = *_model->get_iter (path);
688 boost::shared_ptr<Route> route = row[_columns.route];
689 bool const active = row[_columns.active];
690 route->set_active (!active, this);
694 EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
696 PBD::Unwinder<bool> at (_adding_routes, true);
697 bool from_scratch = (_model->children().size() == 0);
698 Gtk::TreeModel::Children::iterator insert_iter = _model->children().end();
700 for (Gtk::TreeModel::Children::iterator it = _model->children().begin(); it != _model->children().end(); ++it) {
701 boost::shared_ptr<Route> r = (*it)[_columns.route];
703 if (r->order_key() == (routes.front()->route()->order_key() + routes.size())) {
711 _display.set_model (Glib::RefPtr<ListStore>());
713 for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) {
715 boost::shared_ptr<MidiTrack> midi_trk = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
717 TreeModel::Row row = *(_model->insert (insert_iter));
719 row[_columns.text] = (*x)->route()->name();
720 row[_columns.visible] = (*x)->marked_for_display();
721 row[_columns.active] = (*x)->route()->active ();
722 row[_columns.tv] = *x;
723 row[_columns.route] = (*x)->route ();
724 row[_columns.is_track] = (boost::dynamic_pointer_cast<Track> ((*x)->route()) != 0);
727 row[_columns.is_input_active] = midi_trk->input_active ();
728 row[_columns.is_midi] = true;
730 row[_columns.is_input_active] = false;
731 row[_columns.is_midi] = false;
734 row[_columns.mute_state] = (*x)->route()->muted() ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off;
735 row[_columns.solo_state] = RouteUI::solo_active_state ((*x)->route());
736 row[_columns.solo_visible] = !(*x)->route()->is_master ();
737 row[_columns.solo_isolate_state] = (*x)->route()->solo_isolated();
738 row[_columns.solo_safe_state] = (*x)->route()->solo_safe();
739 row[_columns.name_editable] = true;
741 boost::weak_ptr<Route> wr ((*x)->route());
743 (*x)->route()->gui_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
744 (*x)->route()->PropertyChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::route_property_changed, this, _1, wr), gui_context());
746 if ((*x)->is_track()) {
747 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
748 t->RecordEnableChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
749 t->RecordSafeChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
752 if ((*x)->is_midi_track()) {
753 boost::shared_ptr<MidiTrack> t = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
754 t->StepEditStatusChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
755 t->InputActiveChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_input_active_display, this), gui_context());
758 (*x)->route()->mute_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
759 (*x)->route()->solo_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_display, this), gui_context());
760 (*x)->route()->listen_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_display, this), gui_context());
761 (*x)->route()->solo_isolated_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_isolate_display, this), gui_context());
762 (*x)->route()->solo_safe_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_safe_display, this), gui_context());
763 (*x)->route()->active_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_active_display, this), gui_context ());
767 update_rec_display ();
768 update_mute_display ();
769 update_solo_display ();
770 update_solo_isolate_display ();
771 update_solo_safe_display ();
772 update_input_active_display ();
773 update_active_display ();
775 _display.set_model (_model);
777 /* now update route order keys from the treeview/track display order */
779 sync_order_keys_from_treeview ();
784 EditorRoutes::handle_gui_changes (string const & what, void*)
786 if (_adding_routes) {
790 if (what == "track_height") {
791 /* Optional :make tracks change height while it happens, instead
797 if (what == "visible_tracks") {
803 EditorRoutes::route_removed (TimeAxisView *tv)
805 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed, tv)
807 TreeModel::Children rows = _model->children();
808 TreeModel::Children::iterator ri;
810 for (ri = rows.begin(); ri != rows.end(); ++ri) {
811 if ((*ri)[_columns.tv] == tv) {
812 PBD::Unwinder<bool> uw (_route_deletion_in_progress, true);
818 /* the deleted signal for the treeview/model will take
824 EditorRoutes::route_property_changed (const PropertyChange& what_changed, boost::weak_ptr<Route> r)
826 if (!what_changed.contains (ARDOUR::Properties::name)) {
830 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_name_changed, r)
832 boost::shared_ptr<Route> route = r.lock ();
838 TreeModel::Children rows = _model->children();
839 TreeModel::Children::iterator i;
841 for (i = rows.begin(); i != rows.end(); ++i) {
842 boost::shared_ptr<Route> t = (*i)[_columns.route];
844 (*i)[_columns.text] = route->name();
851 EditorRoutes::update_active_display ()
853 if (g_atomic_int_compare_and_exchange (const_cast<gint*>(&_queue_tv_update), 0, 1)) {
854 Glib::signal_idle().connect (sigc::mem_fun (*this, &EditorRoutes::idle_update_mute_rec_solo_etc));
859 EditorRoutes::update_visibility ()
861 TreeModel::Children rows = _model->children();
862 TreeModel::Children::iterator i;
866 for (i = rows.begin(); i != rows.end(); ++i) {
867 TimeAxisView *tv = (*i)[_columns.tv];
868 (*i)[_columns.visible] = tv->marked_for_display ();
871 /* force route order keys catch up with visibility changes
874 sync_order_keys_from_treeview ();
878 EditorRoutes::hide_track_in_display (TimeAxisView& tv)
880 TreeModel::Children rows = _model->children();
881 TreeModel::Children::iterator i;
883 for (i = rows.begin(); i != rows.end(); ++i) {
884 if ((*i)[_columns.tv] == &tv) {
885 tv.set_marked_for_display (false);
886 (*i)[_columns.visible] = false;
894 EditorRoutes::show_track_in_display (TimeAxisView& tv)
896 TreeModel::Children rows = _model->children();
897 TreeModel::Children::iterator i;
900 for (i = rows.begin(); i != rows.end(); ++i) {
901 if ((*i)[_columns.tv] == &tv) {
902 tv.set_marked_for_display (true);
903 (*i)[_columns.visible] = true;
911 EditorRoutes::reset_remote_control_ids ()
913 if (Config->get_remote_model() == UserOrdered || !_session || _session->deletion_in_progress()) {
917 TreeModel::Children rows = _model->children();
924 DEBUG_TRACE (DEBUG::OrderKeys, "editor reset remote control ids\n");
926 TreeModel::Children::iterator ri;
927 bool rid_change = false;
929 uint32_t invisible_key = UINT32_MAX;
931 for (ri = rows.begin(); ri != rows.end(); ++ri) {
933 /* skip two special values */
935 if (rid == Route::MasterBusRemoteControlID) {
939 if (rid == Route::MonitorBusRemoteControlID) {
943 boost::shared_ptr<Route> route = (*ri)[_columns.route];
944 bool visible = (*ri)[_columns.visible];
946 if (!route->is_master() && !route->is_monitor()) {
948 uint32_t new_rid = (visible ? rid : invisible_key--);
950 if (new_rid != route->remote_control_id()) {
951 route->set_remote_control_id_explicit (new_rid);
963 /* tell the world that we changed the remote control IDs */
964 _session->notify_remote_id_change ();
970 EditorRoutes::sync_order_keys_from_treeview ()
972 if (_ignore_reorder || !_session || _session->deletion_in_progress()) {
976 TreeModel::Children rows = _model->children();
983 DEBUG_TRACE (DEBUG::OrderKeys, "editor sync order keys from treeview\n");
985 TreeModel::Children::iterator ri;
986 bool changed = false;
987 bool rid_change = false;
990 uint32_t invisible_key = UINT32_MAX;
992 for (ri = rows.begin(); ri != rows.end(); ++ri) {
994 boost::shared_ptr<Route> route = (*ri)[_columns.route];
995 bool visible = (*ri)[_columns.visible];
997 uint32_t old_key = route->order_key ();
999 if (order != old_key) {
1000 route->set_order_key (order);
1005 if ((Config->get_remote_model() == MixerOrdered) && !route->is_master() && !route->is_monitor()) {
1007 uint32_t new_rid = (visible ? rid : invisible_key--);
1009 if (new_rid != route->remote_control_id()) {
1010 route->set_remote_control_id_explicit (new_rid);
1024 /* tell the world that we changed the editor sort keys */
1025 _session->sync_order_keys ();
1029 /* tell the world that we changed the remote control IDs */
1030 _session->notify_remote_id_change ();
1035 EditorRoutes::sync_treeview_from_order_keys ()
1037 /* Some route order key(s) have been changed, make sure that
1038 we update out tree/list model and GUI to reflect the change.
1041 if (_ignore_reorder || !_session || _session->deletion_in_progress()) {
1045 DEBUG_TRACE (DEBUG::OrderKeys, "editor sync model from order keys.\n");
1047 /* we could get here after either a change in the Mixer or Editor sort
1048 * order, but either way, the mixer order keys reflect the intended
1049 * order for the GUI, so reorder the treeview model to match it.
1052 vector<int> neworder;
1053 TreeModel::Children rows = _model->children();
1054 uint32_t old_order = 0;
1055 bool changed = false;
1061 OrderingKeys sorted;
1063 for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++old_order) {
1064 boost::shared_ptr<Route> route = (*ri)[_columns.route];
1065 sorted.push_back (OrderKeys (old_order, route->order_key ()));
1068 SortByNewDisplayOrder cmp;
1070 sort (sorted.begin(), sorted.end(), cmp);
1071 neworder.assign (sorted.size(), 0);
1075 for (OrderingKeys::iterator sr = sorted.begin(); sr != sorted.end(); ++sr, ++n) {
1077 neworder[n] = sr->old_display_order;
1079 if (sr->old_display_order != n) {
1083 DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("EDITOR change order from %1 to %2\n",
1084 sr->old_display_order, n));
1088 Unwinder<bool> uw (_ignore_reorder, true);
1089 _model->reorder (neworder);
1096 EditorRoutes::hide_all_tracks (bool /*with_select*/)
1098 TreeModel::Children rows = _model->children();
1099 TreeModel::Children::iterator i;
1101 DisplaySuspender ds;
1103 for (i = rows.begin(); i != rows.end(); ++i) {
1105 TreeModel::Row row = (*i);
1106 TimeAxisView *tv = row[_columns.tv];
1112 row[_columns.visible] = false;
1117 EditorRoutes::set_all_tracks_visibility (bool yn)
1119 TreeModel::Children rows = _model->children();
1120 TreeModel::Children::iterator i;
1122 DisplaySuspender ds;
1124 for (i = rows.begin(); i != rows.end(); ++i) {
1126 TreeModel::Row row = (*i);
1127 TimeAxisView* tv = row[_columns.tv];
1133 tv->set_marked_for_display (yn);
1134 (*i)[_columns.visible] = yn;
1137 /* force route order keys catch up with visibility changes
1140 sync_order_keys_from_treeview ();
1144 EditorRoutes::set_all_audio_midi_visibility (int tracks, bool yn)
1146 TreeModel::Children rows = _model->children();
1147 TreeModel::Children::iterator i;
1149 DisplaySuspender ds;
1151 for (i = rows.begin(); i != rows.end(); ++i) {
1153 TreeModel::Row row = (*i);
1154 TimeAxisView* tv = row[_columns.tv];
1156 AudioTimeAxisView* atv;
1157 MidiTimeAxisView* mtv;
1163 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
1166 atv->set_marked_for_display (yn);
1167 (*i)[_columns.visible] = yn;
1171 if (atv->is_audio_track()) {
1172 atv->set_marked_for_display (yn);
1173 (*i)[_columns.visible] = yn;
1178 if (!atv->is_audio_track()) {
1179 atv->set_marked_for_display (yn);
1180 (*i)[_columns.visible] = yn;
1185 else if ((mtv = dynamic_cast<MidiTimeAxisView*>(tv)) != 0) {
1188 mtv->set_marked_for_display (yn);
1189 (*i)[_columns.visible] = yn;
1193 if (mtv->is_midi_track()) {
1194 mtv->set_marked_for_display (yn);
1195 (*i)[_columns.visible] = yn;
1202 /* force route order keys catch up with visibility changes
1205 sync_order_keys_from_treeview ();
1209 EditorRoutes::hide_all_routes ()
1211 set_all_tracks_visibility (false);
1215 EditorRoutes::show_all_routes ()
1217 set_all_tracks_visibility (true);
1221 EditorRoutes::show_all_audiotracks()
1223 set_all_audio_midi_visibility (1, true);
1226 EditorRoutes::hide_all_audiotracks ()
1228 set_all_audio_midi_visibility (1, false);
1232 EditorRoutes::show_all_audiobus ()
1234 set_all_audio_midi_visibility (2, true);
1237 EditorRoutes::hide_all_audiobus ()
1239 set_all_audio_midi_visibility (2, false);
1243 EditorRoutes::show_all_miditracks()
1245 set_all_audio_midi_visibility (3, true);
1248 EditorRoutes::hide_all_miditracks ()
1250 set_all_audio_midi_visibility (3, false);
1254 EditorRoutes::key_press (GdkEventKey* ev)
1256 TreeViewColumn *col;
1257 boost::shared_ptr<RouteList> rl (new RouteList);
1260 switch (ev->keyval) {
1262 case GDK_ISO_Left_Tab:
1264 /* If we appear to be editing something, leave that cleanly and appropriately. */
1265 if (name_editable) {
1266 name_editable->editing_done ();
1270 col = _display.get_column (_name_column); // select&focus on name column
1272 if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
1273 treeview_select_previous (_display, _model, col);
1275 treeview_select_next (_display, _model, col);
1282 if (get_relevant_routes (rl)) {
1283 _session->set_mute (rl, !rl->front()->muted(), Session::rt_cleanup);
1289 if (get_relevant_routes (rl)) {
1290 if (Config->get_solo_control_is_listen_control()) {
1291 _session->set_listen (rl, !rl->front()->listening_via_monitor(), Session::rt_cleanup);
1293 _session->set_solo (rl, !rl->front()->self_soloed(), Session::rt_cleanup);
1300 if (get_relevant_routes (rl)) {
1301 _session->set_record_enabled (rl, !rl->front()->record_enabled(), Session::rt_cleanup);
1313 EditorRoutes::get_relevant_routes (boost::shared_ptr<RouteList> rl)
1316 RouteTimeAxisView* rtv;
1317 RefPtr<TreeSelection> selection = _display.get_selection();
1321 if (selection->count_selected_rows() != 0) {
1325 RefPtr<TreeModel> tm = RefPtr<TreeModel>::cast_dynamic (_model);
1326 iter = selection->get_selected (tm);
1329 /* use mouse pointer */
1334 _display.get_pointer (x, y);
1335 _display.convert_widget_to_bin_window_coords (x, y, bx, by);
1337 if (_display.get_path_at_pos (bx, by, path)) {
1338 iter = _model->get_iter (path);
1343 tv = (*iter)[_columns.tv];
1345 rtv = dynamic_cast<RouteTimeAxisView*>(tv);
1347 rl->push_back (rtv->route());
1352 return !rl->empty();
1356 EditorRoutes::button_press (GdkEventButton* ev)
1358 if (Keyboard::is_context_menu_event (ev)) {
1363 TreeModel::Path path;
1364 TreeViewColumn *tvc;
1368 if (!_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y)) {
1369 /* cancel selection */
1370 _display.get_selection()->unselect_all ();
1371 /* end any editing by grabbing focus */
1372 _display.grab_focus ();
1376 //Scroll editor canvas to selected track
1377 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1379 Gtk::TreeModel::Row row = *_model->get_iter (path);
1380 TimeAxisView *tv = row[_columns.tv];
1383 _editor->ensure_time_axis_view_is_visible (*tv, true);
1391 EditorRoutes::selection_changed ()
1393 _editor->begin_reversible_selection_op (X_("Select Track from Route List"));
1395 if (_display.get_selection()->count_selected_rows() > 0) {
1398 TreeView::Selection::ListHandle_Path rows = _display.get_selection()->get_selected_rows ();
1399 TrackViewList selected;
1401 _editor->get_selection().clear_regions ();
1403 for (TreeView::Selection::ListHandle_Path::iterator i = rows.begin(); i != rows.end(); ++i) {
1405 if ((iter = _model->get_iter (*i))) {
1407 TimeAxisView* tv = (*iter)[_columns.tv];
1408 selected.push_back (tv);
1413 _editor->get_selection().set (selected);
1414 _editor->ensure_time_axis_view_is_visible (*(selected.front()), true);
1417 _editor->get_selection().clear_tracks ();
1420 _editor->commit_reversible_selection_op ();
1424 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const&, bool /*selected*/)
1426 if (selection_countdown) {
1427 if (--selection_countdown == 0) {
1430 /* no selection yet ... */
1437 struct EditorOrderRouteSorter
1439 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1440 if (a->is_master()) {
1441 /* master before everything else */
1443 } else if (b->is_master()) {
1444 /* everything else before master */
1447 return a->order_key () < b->order_key ();
1452 EditorRoutes::initial_display ()
1454 DisplaySuspender ds;
1461 RouteList r (*_session->get_routes());
1463 r.sort (EditorOrderRouteSorter ());
1464 _editor->add_routes (r);
1468 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
1470 const SelectionData& data,
1471 guint info, guint time)
1473 if (data.get_target() == "GTK_TREE_MODEL_ROW") {
1474 _display.on_drag_data_received (context, x, y, data, info, time);
1478 context->drag_finish (true, false, time);
1482 EditorRoutes::move_selected_tracks (bool up)
1484 if (_editor->selection->tracks.empty()) {
1488 typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
1489 std::list<ViewRoute> view_routes;
1490 std::vector<int> neworder;
1491 TreeModel::Children rows = _model->children();
1492 TreeModel::Children::iterator ri;
1494 for (ri = rows.begin(); ri != rows.end(); ++ri) {
1495 TimeAxisView* tv = (*ri)[_columns.tv];
1496 boost::shared_ptr<Route> route = (*ri)[_columns.route];
1498 view_routes.push_back (ViewRoute (tv, route));
1501 list<ViewRoute>::iterator trailing;
1502 list<ViewRoute>::iterator leading;
1506 trailing = view_routes.begin();
1507 leading = view_routes.begin();
1511 while (leading != view_routes.end()) {
1512 if (_editor->selection->selected (leading->first)) {
1513 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
1514 leading = view_routes.erase (leading);
1523 /* if we could use reverse_iterator in list::insert, this code
1524 would be a beautiful reflection of the code above. but we can't
1525 and so it looks like a bit of a mess.
1528 trailing = view_routes.end();
1529 leading = view_routes.end();
1531 --leading; if (leading == view_routes.begin()) { return; }
1537 if (_editor->selection->selected (leading->first)) {
1538 list<ViewRoute>::iterator tmp;
1540 /* need to insert *after* trailing, not *before* it,
1541 which is what insert (iter, val) normally does.
1547 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
1549 /* can't use iter = cont.erase (iter); form here, because
1550 we need iter to move backwards.
1558 if (leading == view_routes.begin()) {
1559 /* the one we've just inserted somewhere else
1560 was the first in the list. erase this copy,
1561 and then break, because we're done.
1566 view_routes.erase (leading);
1575 if (leading == view_routes.begin()) {
1584 for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
1585 uint32_t order = leading->second->order_key ();
1586 neworder.push_back (order);
1590 DEBUG_TRACE (DEBUG::OrderKeys, "New order after moving tracks:\n");
1591 for (vector<int>::iterator i = neworder.begin(); i != neworder.end(); ++i) {
1592 DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("\t%1\n", *i));
1594 DEBUG_TRACE (DEBUG::OrderKeys, "-------\n");
1596 for (vector<int>::iterator i = neworder.begin(); i != neworder.end(); ++i) {
1597 if (*i >= (int) neworder.size()) {
1598 cerr << "Trying to move something to " << *i << " of " << neworder.size() << endl;
1600 assert (*i < (int) neworder.size ());
1604 _model->reorder (neworder);
1608 EditorRoutes::update_input_active_display ()
1610 TreeModel::Children rows = _model->children();
1611 TreeModel::Children::iterator i;
1613 for (i = rows.begin(); i != rows.end(); ++i) {
1614 boost::shared_ptr<Route> route = (*i)[_columns.route];
1616 if (boost::dynamic_pointer_cast<Track> (route)) {
1617 boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
1620 (*i)[_columns.is_input_active] = mt->input_active();
1627 EditorRoutes::update_rec_display ()
1629 if (g_atomic_int_compare_and_exchange (const_cast<gint*>(&_queue_tv_update), 0, 1)) {
1630 Glib::signal_idle().connect (sigc::mem_fun (*this, &EditorRoutes::idle_update_mute_rec_solo_etc));
1635 EditorRoutes::idle_update_mute_rec_solo_etc()
1637 g_atomic_int_set (const_cast<gint*>(&_queue_tv_update), 0);
1638 TreeModel::Children rows = _model->children();
1639 TreeModel::Children::iterator i;
1641 for (i = rows.begin(); i != rows.end(); ++i) {
1642 boost::shared_ptr<Route> route = (*i)[_columns.route];
1643 (*i)[_columns.mute_state] = RouteUI::mute_active_state (_session, route);
1644 (*i)[_columns.solo_state] = RouteUI::solo_active_state (route);
1645 (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_active_state (route) ? 1 : 0;
1646 (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_active_state (route) ? 1 : 0;
1647 (*i)[_columns.active] = route->active ();
1648 if (boost::dynamic_pointer_cast<Track> (route)) {
1649 boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
1651 if (route->record_enabled()) {
1652 if (_session->record_status() == Session::Recording) {
1653 (*i)[_columns.rec_state] = 1;
1655 (*i)[_columns.rec_state] = 2;
1657 } else if (mt && mt->step_editing()) {
1658 (*i)[_columns.rec_state] = 3;
1660 (*i)[_columns.rec_state] = 0;
1663 (*i)[_columns.rec_safe] = route->record_safe () ? 1 : 0;
1664 (*i)[_columns.name_editable] = !route->record_enabled ();
1668 return false; // do not call again (until needed)
1673 EditorRoutes::update_mute_display ()
1675 if (g_atomic_int_compare_and_exchange (const_cast<gint*>(&_queue_tv_update), 0, 1)) {
1676 Glib::signal_idle().connect (sigc::mem_fun (*this, &EditorRoutes::idle_update_mute_rec_solo_etc));
1681 EditorRoutes::update_solo_display ()
1683 if (g_atomic_int_compare_and_exchange (const_cast<gint*>(&_queue_tv_update), 0, 1)) {
1684 Glib::signal_idle().connect (sigc::mem_fun (*this, &EditorRoutes::idle_update_mute_rec_solo_etc));
1689 EditorRoutes::update_solo_isolate_display ()
1691 if (g_atomic_int_compare_and_exchange (const_cast<gint*>(&_queue_tv_update), 0, 1)) {
1692 Glib::signal_idle().connect (sigc::mem_fun (*this, &EditorRoutes::idle_update_mute_rec_solo_etc));
1697 EditorRoutes::update_solo_safe_display ()
1699 if (g_atomic_int_compare_and_exchange (const_cast<gint*>(&_queue_tv_update), 0, 1)) {
1700 Glib::signal_idle().connect (sigc::mem_fun (*this, &EditorRoutes::idle_update_mute_rec_solo_etc));
1705 EditorRoutes::views () const
1707 list<TimeAxisView*> v;
1708 for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
1709 v.push_back ((*i)[_columns.tv]);
1716 EditorRoutes::clear ()
1718 _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1720 _display.set_model (_model);
1724 EditorRoutes::name_edit_started (CellEditable* ce, const Glib::ustring&)
1728 /* give it a special name */
1730 Gtk::Entry *e = dynamic_cast<Gtk::Entry*> (ce);
1733 e->set_name (X_("RouteNameEditorEntry"));
1738 EditorRoutes::name_edit (std::string const & path, std::string const & new_text)
1742 TreeIter iter = _model->get_iter (path);
1748 boost::shared_ptr<Route> route = (*iter)[_columns.route];
1750 if (route && route->name() != new_text) {
1751 route->set_name (new_text);
1756 EditorRoutes::solo_changed_so_update_mute ()
1758 update_mute_display ();
1762 EditorRoutes::show_tracks_with_regions_at_playhead ()
1764 boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
1766 set<TimeAxisView*> show;
1767 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
1768 TimeAxisView* tav = _editor->axis_view_from_route (*i);
1774 DisplaySuspender ds;
1776 TreeModel::Children rows = _model->children ();
1777 for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
1778 TimeAxisView* tv = (*i)[_columns.tv];
1779 bool to_show = (show.find (tv) != show.end());
1781 tv->set_marked_for_display (to_show);
1782 (*i)[_columns.visible] = to_show;
1785 /* force route order keys catch up with visibility changes
1788 sync_order_keys_from_treeview ();
1792 EditorRoutes::plugin_setup (boost::shared_ptr<Route> r, boost::shared_ptr<PluginInsert> pi, ARDOUR::Route::PluginSetupOptions flags)
1794 PluginSetupDialog psd (r, pi, flags);