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 "editor_group_tabs.h"
49 #include "editor_routes.h"
54 using namespace ARDOUR;
57 using namespace Gtkmm2ext;
59 using Gtkmm2ext::Keyboard;
67 EditorRoutes::EditorRoutes (Editor* e)
69 , _ignore_reorder (false)
70 , _no_redisplay (false)
73 , selection_countdown (0)
76 static const int column_width = 22;
78 _scroller.add (_display);
79 _scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
81 _model = ListStore::create (_columns);
82 _display.set_model (_model);
84 // Record enable toggle
85 CellRendererPixbufMulti* rec_col_renderer = manage (new CellRendererPixbufMulti());
87 rec_col_renderer->set_pixbuf (0, ::get_icon("record-normal-disabled"));
88 rec_col_renderer->set_pixbuf (1, ::get_icon("record-normal-in-progress"));
89 rec_col_renderer->set_pixbuf (2, ::get_icon("record-normal-enabled"));
90 rec_col_renderer->set_pixbuf (3, ::get_icon("record-step"));
91 rec_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_rec_enable_changed));
93 TreeViewColumn* rec_state_column = manage (new TreeViewColumn("R", *rec_col_renderer));
95 rec_state_column->add_attribute(rec_col_renderer->property_state(), _columns.rec_state);
96 rec_state_column->add_attribute(rec_col_renderer->property_visible(), _columns.is_track);
98 rec_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
99 rec_state_column->set_alignment(ALIGN_CENTER);
100 rec_state_column->set_expand(false);
101 rec_state_column->set_fixed_width(column_width);
105 CellRendererPixbufMulti* input_active_col_renderer = manage (new CellRendererPixbufMulti());
106 input_active_col_renderer->set_pixbuf (0, ::get_icon("midi-input-inactive"));
107 input_active_col_renderer->set_pixbuf (1, ::get_icon("midi-input-active"));
108 input_active_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_input_active_changed));
110 TreeViewColumn* input_active_column = manage (new TreeViewColumn ("I", *input_active_col_renderer));
112 input_active_column->add_attribute(input_active_col_renderer->property_state(), _columns.is_input_active);
113 input_active_column->add_attribute (input_active_col_renderer->property_visible(), _columns.is_midi);
115 input_active_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
116 input_active_column->set_alignment(ALIGN_CENTER);
117 input_active_column->set_expand(false);
118 input_active_column->set_fixed_width(column_width);
120 // Mute enable toggle
121 CellRendererPixbufMulti* mute_col_renderer = manage (new CellRendererPixbufMulti());
123 mute_col_renderer->set_pixbuf (Gtkmm2ext::Off, ::get_icon("mute-disabled"));
124 mute_col_renderer->set_pixbuf (Gtkmm2ext::ImplicitActive, ::get_icon("muted-by-others"));
125 mute_col_renderer->set_pixbuf (Gtkmm2ext::ExplicitActive, ::get_icon("mute-enabled"));
126 mute_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_mute_enable_toggled));
128 TreeViewColumn* mute_state_column = manage (new TreeViewColumn("M", *mute_col_renderer));
130 mute_state_column->add_attribute(mute_col_renderer->property_state(), _columns.mute_state);
131 mute_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
132 mute_state_column->set_alignment(ALIGN_CENTER);
133 mute_state_column->set_expand(false);
134 mute_state_column->set_fixed_width(15);
136 // Solo enable toggle
137 CellRendererPixbufMulti* solo_col_renderer = manage (new CellRendererPixbufMulti());
139 solo_col_renderer->set_pixbuf (Gtkmm2ext::Off, ::get_icon("solo-disabled"));
140 solo_col_renderer->set_pixbuf (Gtkmm2ext::ExplicitActive, ::get_icon("solo-enabled"));
141 solo_col_renderer->set_pixbuf (Gtkmm2ext::ImplicitActive, ::get_icon("soloed-by-others"));
142 solo_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_enable_toggled));
144 TreeViewColumn* solo_state_column = manage (new TreeViewColumn("S", *solo_col_renderer));
146 solo_state_column->add_attribute(solo_col_renderer->property_state(), _columns.solo_state);
147 solo_state_column->add_attribute(solo_col_renderer->property_visible(), _columns.solo_visible);
148 solo_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
149 solo_state_column->set_alignment(ALIGN_CENTER);
150 solo_state_column->set_expand(false);
151 solo_state_column->set_fixed_width(column_width);
153 // Solo isolate toggle
154 CellRendererPixbufMulti* solo_iso_renderer = manage (new CellRendererPixbufMulti());
156 solo_iso_renderer->set_pixbuf (0, ::get_icon("solo-isolate-disabled"));
157 solo_iso_renderer->set_pixbuf (1, ::get_icon("solo-isolate-enabled"));
158 solo_iso_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_isolate_toggled));
160 TreeViewColumn* solo_isolate_state_column = manage (new TreeViewColumn("SI", *solo_iso_renderer));
162 solo_isolate_state_column->add_attribute(solo_iso_renderer->property_state(), _columns.solo_isolate_state);
163 solo_isolate_state_column->add_attribute(solo_iso_renderer->property_visible(), _columns.solo_visible);
164 solo_isolate_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
165 solo_isolate_state_column->set_alignment(ALIGN_CENTER);
166 solo_isolate_state_column->set_expand(false);
167 solo_isolate_state_column->set_fixed_width(column_width);
170 CellRendererPixbufMulti* solo_safe_renderer = manage (new CellRendererPixbufMulti ());
172 solo_safe_renderer->set_pixbuf (0, ::get_icon("solo-safe-disabled"));
173 solo_safe_renderer->set_pixbuf (1, ::get_icon("solo-safe-enabled"));
174 solo_safe_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_safe_toggled));
176 TreeViewColumn* solo_safe_state_column = manage (new TreeViewColumn(_("SS"), *solo_safe_renderer));
177 solo_safe_state_column->add_attribute(solo_safe_renderer->property_state(), _columns.solo_safe_state);
178 solo_safe_state_column->add_attribute(solo_safe_renderer->property_visible(), _columns.solo_visible);
179 solo_safe_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
180 solo_safe_state_column->set_alignment(ALIGN_CENTER);
181 solo_safe_state_column->set_expand(false);
182 solo_safe_state_column->set_fixed_width(column_width);
184 _name_column = _display.append_column ("", _columns.text) - 1;
185 _visible_column = _display.append_column ("", _columns.visible) - 1;
186 _active_column = _display.append_column ("", _columns.active) - 1;
188 _display.append_column (*input_active_column);
189 _display.append_column (*rec_state_column);
190 _display.append_column (*mute_state_column);
191 _display.append_column (*solo_state_column);
192 _display.append_column (*solo_isolate_state_column);
193 _display.append_column (*solo_safe_state_column);
200 { 0, _("Name"), _("Track/Bus Name") },
201 { 1, _("V"), _("Track/Bus visible ?") },
202 { 2, _("A"), _("Track/Bus active ?") },
203 { 3, _("I"), _("MIDI input enabled") },
204 { 4, _("R"), _("Record enabled") },
205 { 5, _("M"), _("Muted") },
206 { 6, _("S"), _("Soloed") },
207 { 7, _("SI"), _("Solo Isolated") },
208 { 8, _("SS"), _("Solo Safe (Locked)") },
212 for (int i = 0; ci[i].index >= 0; ++i) {
213 col = _display.get_column (ci[i].index);
214 l = manage (new Label (ci[i].label));
215 ARDOUR_UI::instance()->set_tip (*l, ci[i].tooltip);
216 col->set_widget (*l);
220 _display.set_headers_visible (true);
221 _display.get_selection()->set_mode (SELECTION_SINGLE);
222 _display.get_selection()->set_select_function (sigc::mem_fun (*this, &EditorRoutes::selection_filter));
223 _display.set_reorderable (true);
224 _display.set_name (X_("MixerTrackDisplayList"));
225 _display.set_rules_hint (true);
226 _display.set_size_request (100, -1);
227 _display.add_object_drag (_columns.route.index(), "routes");
229 CellRendererText* name_cell = dynamic_cast<CellRendererText*> (_display.get_column_cell_renderer (_name_column));
232 name_cell->signal_editing_started().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit_started));
234 TreeViewColumn* name_column = _display.get_column (_name_column);
236 assert (name_column);
238 name_column->add_attribute (name_cell->property_editable(), _columns.name_editable);
239 name_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
240 name_column->set_expand(true);
241 name_column->set_min_width(50);
243 name_cell->property_editable() = true;
244 name_cell->signal_edited().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit));
246 // Set the visible column cell renderer to radio toggle
247 CellRendererToggle* visible_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (_visible_column));
249 visible_cell->property_activatable() = true;
250 visible_cell->property_radio() = false;
251 visible_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::visible_changed));
253 TreeViewColumn* visible_col = dynamic_cast<TreeViewColumn*> (_display.get_column (_visible_column));
254 visible_col->set_expand(false);
255 visible_col->set_sizing(TREE_VIEW_COLUMN_FIXED);
256 visible_col->set_fixed_width(30);
257 visible_col->set_alignment(ALIGN_CENTER);
259 CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (_active_column));
261 active_cell->property_activatable() = true;
262 active_cell->property_radio() = false;
263 active_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::active_changed));
265 TreeViewColumn* active_col = dynamic_cast<TreeViewColumn*> (_display.get_column (_active_column));
266 active_col->set_expand (false);
267 active_col->set_sizing (TREE_VIEW_COLUMN_FIXED);
268 active_col->set_fixed_width (30);
269 active_col->set_alignment (ALIGN_CENTER);
271 _model->signal_row_deleted().connect (sigc::mem_fun (*this, &EditorRoutes::route_deleted));
272 _model->signal_rows_reordered().connect (sigc::mem_fun (*this, &EditorRoutes::reordered));
274 _display.signal_button_press_event().connect (sigc::mem_fun (*this, &EditorRoutes::button_press), false);
275 _scroller.signal_key_press_event().connect (sigc::mem_fun(*this, &EditorRoutes::key_press), false);
277 _scroller.signal_focus_in_event().connect (sigc::mem_fun (*this, &EditorRoutes::focus_in), false);
278 _scroller.signal_focus_out_event().connect (sigc::mem_fun (*this, &EditorRoutes::focus_out));
280 _display.signal_enter_notify_event().connect (sigc::mem_fun (*this, &EditorRoutes::enter_notify), false);
281 _display.signal_leave_notify_event().connect (sigc::mem_fun (*this, &EditorRoutes::leave_notify), false);
283 _display.set_enable_search (false);
285 Route::SyncOrderKeys.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::sync_treeview_from_order_keys, this, _1), gui_context());
289 EditorRoutes::focus_in (GdkEventFocus*)
291 Window* win = dynamic_cast<Window*> (_scroller.get_toplevel ());
294 old_focus = win->get_focus ();
301 /* try to do nothing on focus in (doesn't work, hence selection_count nonsense) */
306 EditorRoutes::focus_out (GdkEventFocus*)
309 old_focus->grab_focus ();
317 EditorRoutes::enter_notify (GdkEventCrossing*)
323 /* arm counter so that ::selection_filter() will deny selecting anything for the
324 next two attempts to change selection status.
326 selection_countdown = 2;
327 _scroller.grab_focus ();
328 Keyboard::magic_widget_grab_focus ();
333 EditorRoutes::leave_notify (GdkEventCrossing*)
335 selection_countdown = 0;
338 old_focus->grab_focus ();
342 Keyboard::magic_widget_drop_focus ();
347 EditorRoutes::set_session (Session* s)
349 SessionHandlePtr::set_session (s);
354 _session->SoloChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::solo_changed_so_update_mute, this), gui_context());
355 _session->RecordStateChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
360 EditorRoutes::on_input_active_changed (std::string const & path_string)
362 // Get the model row that has been toggled.
363 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
365 TimeAxisView* tv = row[_columns.tv];
366 RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
369 boost::shared_ptr<MidiTrack> mt;
370 mt = rtv->midi_track();
372 mt->set_input_active (!mt->input_active());
378 EditorRoutes::on_tv_rec_enable_changed (std::string const & path_string)
380 // Get the model row that has been toggled.
381 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
383 TimeAxisView* tv = row[_columns.tv];
384 RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
386 if (rtv && rtv->track()) {
387 boost::shared_ptr<RouteList> rl (new RouteList);
388 rl->push_back (rtv->route());
389 _session->set_record_enabled (rl, !rtv->track()->record_enabled(), Session::rt_cleanup);
394 EditorRoutes::on_tv_mute_enable_toggled (std::string const & path_string)
396 // Get the model row that has been toggled.
397 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
399 TimeAxisView *tv = row[_columns.tv];
400 RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
403 boost::shared_ptr<RouteList> rl (new RouteList);
404 rl->push_back (rtv->route());
405 _session->set_mute (rl, !rtv->route()->muted(), Session::rt_cleanup);
410 EditorRoutes::on_tv_solo_enable_toggled (std::string const & path_string)
412 // Get the model row that has been toggled.
413 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
415 TimeAxisView *tv = row[_columns.tv];
416 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
419 boost::shared_ptr<RouteList> rl (new RouteList);
420 rl->push_back (rtv->route());
421 if (Config->get_solo_control_is_listen_control()) {
422 _session->set_listen (rl, !rtv->route()->listening_via_monitor(), Session::rt_cleanup);
424 _session->set_solo (rl, !rtv->route()->self_soloed(), Session::rt_cleanup);
430 EditorRoutes::on_tv_solo_isolate_toggled (std::string const & path_string)
432 // Get the model row that has been toggled.
433 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
435 TimeAxisView *tv = row[_columns.tv];
436 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
439 rtv->route()->set_solo_isolated (!rtv->route()->solo_isolated(), this);
444 EditorRoutes::on_tv_solo_safe_toggled (std::string const & path_string)
446 // Get the model row that has been toggled.
447 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
449 TimeAxisView *tv = row[_columns.tv];
450 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
453 rtv->route()->set_solo_safe (!rtv->route()->solo_safe(), this);
458 EditorRoutes::build_menu ()
460 using namespace Menu_Helpers;
465 MenuList& items = _menu->items();
466 _menu->set_name ("ArdourContextMenu");
468 items.push_back (MenuElem (_("Show All"), sigc::mem_fun (*this, &EditorRoutes::show_all_routes)));
469 items.push_back (MenuElem (_("Hide All"), sigc::mem_fun (*this, &EditorRoutes::hide_all_routes)));
470 items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiotracks)));
471 items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiotracks)));
472 items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiobus)));
473 items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiobus)));
474 items.push_back (MenuElem (_("Show All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_miditracks)));
475 items.push_back (MenuElem (_("Hide All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_miditracks)));
476 items.push_back (MenuElem (_("Show Tracks With Regions Under Playhead"), sigc::mem_fun (*this, &EditorRoutes::show_tracks_with_regions_at_playhead)));
480 EditorRoutes::show_menu ()
486 _menu->popup (1, gtk_get_current_event_time());
490 EditorRoutes::redisplay ()
492 if (_no_redisplay || !_session || _session->deletion_in_progress()) {
496 TreeModel::Children rows = _model->children();
497 TreeModel::Children::iterator i;
500 /* n will be the count of tracks plus children (updated by TimeAxisView::show_at),
501 so we will use that to know where to put things.
505 for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
506 TimeAxisView *tv = (*i)[_columns.tv];
507 boost::shared_ptr<Route> route = (*i)[_columns.route];
510 // just a "title" row
514 bool visible = tv->marked_for_display ();
516 /* show or hide the TimeAxisView */
518 position += tv->show_at (position, n, &_editor->edit_controls_vbox);
519 tv->clip_to_viewport ();
527 /* whenever we go idle, update the track view list to reflect the new order.
528 we can't do this here, because we could mess up something that is traversing
529 the track order and has caused a redisplay of the list.
531 Glib::signal_idle().connect (sigc::mem_fun (*_editor, &Editor::sync_track_view_list_and_routes));
533 _editor->reset_controls_layout_height (position);
534 _editor->reset_controls_layout_width ();
535 _editor->full_canvas_height = position + _editor->canvas_timebars_vsize;
536 _editor->vertical_adjustment.set_upper (_editor->full_canvas_height);
538 if ((_editor->vertical_adjustment.get_value() + _editor->_canvas_height) > _editor->vertical_adjustment.get_upper()) {
540 We're increasing the size of the canvas while the bottom is visible.
541 We scroll down to keep in step with the controls layout.
543 _editor->vertical_adjustment.set_value (_editor->full_canvas_height - _editor->_canvas_height);
548 EditorRoutes::route_deleted (Gtk::TreeModel::Path const &)
550 /* this happens as the second step of a DnD within the treeview as well
551 as when a row/route is actually deleted.
553 DEBUG_TRACE (DEBUG::OrderKeys, "editor routes treeview row deleted\n");
554 sync_order_keys_from_treeview ();
558 EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
560 DEBUG_TRACE (DEBUG::OrderKeys, "editor routes treeview reordered\n");
561 sync_order_keys_from_treeview ();
565 EditorRoutes::visible_changed (std::string const & path)
567 if (_session && _session->deletion_in_progress()) {
573 if ((iter = _model->get_iter (path))) {
574 TimeAxisView* tv = (*iter)[_columns.tv];
576 bool visible = (*iter)[_columns.visible];
578 if (tv->set_marked_for_display (!visible)) {
579 update_visibility ();
586 EditorRoutes::active_changed (std::string const & path)
588 if (_session && _session->deletion_in_progress ()) {
592 Gtk::TreeModel::Row row = *_model->get_iter (path);
593 boost::shared_ptr<Route> route = row[_columns.route];
594 bool const active = row[_columns.active];
595 route->set_active (!active, this);
599 EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
603 suspend_redisplay ();
605 for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) {
607 boost::shared_ptr<MidiTrack> midi_trk = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
609 row = *(_model->append ());
611 row[_columns.text] = (*x)->route()->name();
612 row[_columns.visible] = (*x)->marked_for_display();
613 row[_columns.active] = (*x)->route()->active ();
614 row[_columns.tv] = *x;
615 row[_columns.route] = (*x)->route ();
616 row[_columns.is_track] = (boost::dynamic_pointer_cast<Track> ((*x)->route()) != 0);
619 row[_columns.is_input_active] = midi_trk->input_active ();
620 row[_columns.is_midi] = true;
622 row[_columns.is_input_active] = false;
623 row[_columns.is_midi] = false;
626 row[_columns.mute_state] = (*x)->route()->muted() ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off;
627 row[_columns.solo_state] = RouteUI::solo_active_state ((*x)->route());
628 row[_columns.solo_visible] = !(*x)->route()->is_master ();
629 row[_columns.solo_isolate_state] = (*x)->route()->solo_isolated();
630 row[_columns.solo_safe_state] = (*x)->route()->solo_safe();
631 row[_columns.name_editable] = true;
633 boost::weak_ptr<Route> wr ((*x)->route());
635 (*x)->route()->gui_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
636 (*x)->route()->PropertyChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::route_property_changed, this, _1, wr), gui_context());
638 if ((*x)->is_track()) {
639 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
640 t->RecordEnableChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
643 if ((*x)->is_midi_track()) {
644 boost::shared_ptr<MidiTrack> t = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
645 t->StepEditStatusChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
646 t->InputActiveChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_input_active_display, this), gui_context());
649 (*x)->route()->mute_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
650 (*x)->route()->solo_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
651 (*x)->route()->listen_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
652 (*x)->route()->solo_isolated_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_isolate_display, this), gui_context());
653 (*x)->route()->solo_safe_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_safe_display, this), gui_context());
654 (*x)->route()->active_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_active_display, this), gui_context ());
657 update_rec_display ();
658 update_mute_display ();
659 update_solo_display (true);
660 update_solo_isolate_display ();
661 update_solo_safe_display ();
662 update_input_active_display ();
663 update_active_display ();
666 /* now update route order keys from the treeview/track display order */
668 sync_order_keys_from_treeview ();
672 EditorRoutes::handle_gui_changes (string const & what, void*)
674 ENSURE_GUI_THREAD (*this, &EditorRoutes::handle_gui_changes, what, src)
676 if (what == "track_height") {
677 /* Optional :make tracks change height while it happens, instead
680 //update_canvas_now ();
684 if (what == "visible_tracks") {
690 EditorRoutes::route_removed (TimeAxisView *tv)
692 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed, tv)
694 TreeModel::Children rows = _model->children();
695 TreeModel::Children::iterator ri;
697 for (ri = rows.begin(); ri != rows.end(); ++ri) {
698 if ((*ri)[_columns.tv] == tv) {
704 /* the deleted signal for the treeview/model will take
710 EditorRoutes::route_property_changed (const PropertyChange& what_changed, boost::weak_ptr<Route> r)
712 if (!what_changed.contains (ARDOUR::Properties::name)) {
716 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_name_changed, r)
718 boost::shared_ptr<Route> route = r.lock ();
724 TreeModel::Children rows = _model->children();
725 TreeModel::Children::iterator i;
727 for (i = rows.begin(); i != rows.end(); ++i) {
728 boost::shared_ptr<Route> t = (*i)[_columns.route];
730 (*i)[_columns.text] = route->name();
737 EditorRoutes::update_active_display ()
739 TreeModel::Children rows = _model->children();
740 TreeModel::Children::iterator i;
742 for (i = rows.begin(); i != rows.end(); ++i) {
743 boost::shared_ptr<Route> route = (*i)[_columns.route];
744 (*i)[_columns.active] = route->active ();
749 EditorRoutes::update_visibility ()
751 TreeModel::Children rows = _model->children();
752 TreeModel::Children::iterator i;
754 suspend_redisplay ();
756 for (i = rows.begin(); i != rows.end(); ++i) {
757 TimeAxisView *tv = (*i)[_columns.tv];
758 (*i)[_columns.visible] = tv->marked_for_display ();
761 /* force route order keys catch up with visibility changes
764 sync_order_keys_from_treeview ();
770 EditorRoutes::hide_track_in_display (TimeAxisView& tv)
772 TreeModel::Children rows = _model->children();
773 TreeModel::Children::iterator i;
775 for (i = rows.begin(); i != rows.end(); ++i) {
776 if ((*i)[_columns.tv] == &tv) {
777 tv.set_marked_for_display (false);
778 (*i)[_columns.visible] = false;
786 EditorRoutes::show_track_in_display (TimeAxisView& tv)
788 TreeModel::Children rows = _model->children();
789 TreeModel::Children::iterator i;
792 for (i = rows.begin(); i != rows.end(); ++i) {
793 if ((*i)[_columns.tv] == &tv) {
794 tv.set_marked_for_display (true);
795 (*i)[_columns.visible] = true;
803 EditorRoutes::reset_remote_control_ids ()
805 if (Config->get_remote_model() != EditorOrdered || !_session || _session->deletion_in_progress()) {
809 TreeModel::Children rows = _model->children();
816 DEBUG_TRACE (DEBUG::OrderKeys, "editor reset remote control ids\n");
818 TreeModel::Children::iterator ri;
819 bool rid_change = false;
821 uint32_t invisible_key = UINT32_MAX;
823 for (ri = rows.begin(); ri != rows.end(); ++ri) {
825 boost::shared_ptr<Route> route = (*ri)[_columns.route];
826 bool visible = (*ri)[_columns.visible];
829 if (!route->is_master() && !route->is_monitor()) {
831 uint32_t new_rid = (visible ? rid : invisible_key--);
833 if (new_rid != route->remote_control_id()) {
834 route->set_remote_control_id_from_order_key (EditorSort, new_rid);
846 /* tell the world that we changed the remote control IDs */
847 _session->notify_remote_id_change ();
853 EditorRoutes::sync_order_keys_from_treeview ()
855 if (_ignore_reorder || !_session || _session->deletion_in_progress()) {
859 TreeModel::Children rows = _model->children();
866 DEBUG_TRACE (DEBUG::OrderKeys, "editor sync order keys from treeview\n");
868 TreeModel::Children::iterator ri;
869 bool changed = false;
870 bool rid_change = false;
873 uint32_t invisible_key = UINT32_MAX;
875 for (ri = rows.begin(); ri != rows.end(); ++ri) {
877 boost::shared_ptr<Route> route = (*ri)[_columns.route];
878 bool visible = (*ri)[_columns.visible];
880 uint32_t old_key = route->order_key (EditorSort);
882 if (order != old_key) {
883 route->set_order_key (EditorSort, order);
888 if ((Config->get_remote_model() == EditorOrdered) && !route->is_master() && !route->is_monitor()) {
890 uint32_t new_rid = (visible ? rid : invisible_key--);
892 if (new_rid != route->remote_control_id()) {
893 route->set_remote_control_id_from_order_key (EditorSort, new_rid);
907 /* tell the world that we changed the editor sort keys */
908 _session->sync_order_keys (EditorSort);
912 /* tell the world that we changed the remote control IDs */
913 _session->notify_remote_id_change ();
918 EditorRoutes::sync_treeview_from_order_keys (RouteSortOrderKey src)
920 /* Some route order key(s) for `src' has been changed, make sure that
921 we update out tree/list model and GUI to reflect the change.
924 if (!_session || _session->deletion_in_progress()) {
928 DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("editor sync model from order keys, src = %1\n", enum_2_string (src)));
930 if (src == MixerSort) {
932 if (!Config->get_sync_all_route_ordering()) {
933 /* mixer sort keys changed - we don't care */
937 DEBUG_TRACE (DEBUG::OrderKeys, "reset editor order key to match mixer\n");
939 /* mixer sort keys were changed, update the editor sort
940 * keys since "sync mixer+editor order" is enabled.
943 boost::shared_ptr<RouteList> r = _session->get_routes ();
945 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
946 (*i)->sync_order_keys (src);
950 /* we could get here after either a change in the Mixer or Editor sort
951 * order, but either way, the mixer order keys reflect the intended
952 * order for the GUI, so reorder the treeview model to match it.
955 vector<int> neworder;
956 TreeModel::Children rows = _model->children();
957 uint32_t old_order = 0;
958 bool changed = false;
964 neworder.assign (rows.size(), 0);
966 for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++old_order) {
967 boost::shared_ptr<Route> route = (*ri)[_columns.route];
968 uint32_t new_order = route->order_key (EditorSort);
970 DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("EDITOR change order for %1 from %2 to %3\n",
971 route->name(), old_order, new_order));
973 neworder[new_order] = old_order;
975 if (old_order != new_order) {
982 Unwinder<bool> uw (_ignore_reorder, true);
983 _model->reorder (neworder);
990 EditorRoutes::hide_all_tracks (bool /*with_select*/)
992 TreeModel::Children rows = _model->children();
993 TreeModel::Children::iterator i;
995 suspend_redisplay ();
997 for (i = rows.begin(); i != rows.end(); ++i) {
999 TreeModel::Row row = (*i);
1000 TimeAxisView *tv = row[_columns.tv];
1006 row[_columns.visible] = false;
1009 resume_redisplay ();
1011 /* XXX this seems like a hack and half, but its not clear where to put this
1015 //reset_scrolling_region ();
1019 EditorRoutes::set_all_tracks_visibility (bool yn)
1021 TreeModel::Children rows = _model->children();
1022 TreeModel::Children::iterator i;
1024 suspend_redisplay ();
1026 for (i = rows.begin(); i != rows.end(); ++i) {
1028 TreeModel::Row row = (*i);
1029 TimeAxisView* tv = row[_columns.tv];
1035 (*i)[_columns.visible] = yn;
1038 /* force route order keys catch up with visibility changes
1041 sync_order_keys_from_treeview ();
1043 resume_redisplay ();
1047 EditorRoutes::set_all_audio_midi_visibility (int tracks, bool yn)
1049 TreeModel::Children rows = _model->children();
1050 TreeModel::Children::iterator i;
1052 suspend_redisplay ();
1054 for (i = rows.begin(); i != rows.end(); ++i) {
1056 TreeModel::Row row = (*i);
1057 TimeAxisView* tv = row[_columns.tv];
1059 AudioTimeAxisView* atv;
1060 MidiTimeAxisView* mtv;
1066 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
1069 (*i)[_columns.visible] = yn;
1073 if (atv->is_audio_track()) {
1074 (*i)[_columns.visible] = yn;
1079 if (!atv->is_audio_track()) {
1080 (*i)[_columns.visible] = yn;
1085 else if ((mtv = dynamic_cast<MidiTimeAxisView*>(tv)) != 0) {
1088 (*i)[_columns.visible] = yn;
1092 if (mtv->is_midi_track()) {
1093 (*i)[_columns.visible] = yn;
1100 /* force route order keys catch up with visibility changes
1103 sync_order_keys_from_treeview ();
1105 resume_redisplay ();
1109 EditorRoutes::hide_all_routes ()
1111 set_all_tracks_visibility (false);
1115 EditorRoutes::show_all_routes ()
1117 set_all_tracks_visibility (true);
1121 EditorRoutes::show_all_audiotracks()
1123 set_all_audio_midi_visibility (1, true);
1126 EditorRoutes::hide_all_audiotracks ()
1128 set_all_audio_midi_visibility (1, false);
1132 EditorRoutes::show_all_audiobus ()
1134 set_all_audio_midi_visibility (2, true);
1137 EditorRoutes::hide_all_audiobus ()
1139 set_all_audio_midi_visibility (2, false);
1143 EditorRoutes::show_all_miditracks()
1145 set_all_audio_midi_visibility (3, true);
1148 EditorRoutes::hide_all_miditracks ()
1150 set_all_audio_midi_visibility (3, false);
1154 EditorRoutes::key_press (GdkEventKey* ev)
1156 TreeViewColumn *col;
1157 boost::shared_ptr<RouteList> rl (new RouteList);
1160 switch (ev->keyval) {
1162 case GDK_ISO_Left_Tab:
1164 /* If we appear to be editing something, leave that cleanly and appropriately.
1166 if (name_editable) {
1167 name_editable->editing_done ();
1171 col = _display.get_column (_name_column); // select&focus on name column
1173 if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
1174 treeview_select_previous (_display, _model, col);
1176 treeview_select_next (_display, _model, col);
1183 if (get_relevant_routes (rl)) {
1184 _session->set_mute (rl, !rl->front()->muted(), Session::rt_cleanup);
1190 if (Config->get_solo_control_is_listen_control()) {
1191 _session->set_listen (rl, !rl->front()->listening_via_monitor(), Session::rt_cleanup);
1193 _session->set_solo (rl, !rl->front()->self_soloed(), Session::rt_cleanup);
1199 if (get_relevant_routes (rl)) {
1200 _session->set_record_enabled (rl, !rl->front()->record_enabled(), Session::rt_cleanup);
1212 EditorRoutes::get_relevant_routes (boost::shared_ptr<RouteList> rl)
1215 RouteTimeAxisView* rtv;
1216 RefPtr<TreeSelection> selection = _display.get_selection();
1220 if (selection->count_selected_rows() != 0) {
1224 RefPtr<TreeModel> tm = RefPtr<TreeModel>::cast_dynamic (_model);
1225 iter = selection->get_selected (tm);
1228 /* use mouse pointer */
1233 _display.get_pointer (x, y);
1234 _display.convert_widget_to_bin_window_coords (x, y, bx, by);
1236 if (_display.get_path_at_pos (bx, by, path)) {
1237 iter = _model->get_iter (path);
1242 tv = (*iter)[_columns.tv];
1244 rtv = dynamic_cast<RouteTimeAxisView*>(tv);
1246 rl->push_back (rtv->route());
1251 return !rl->empty();
1255 EditorRoutes::button_press (GdkEventButton* ev)
1257 if (Keyboard::is_context_menu_event (ev)) {
1262 TreeModel::Path path;
1263 TreeViewColumn *tvc;
1267 if (!_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y)) {
1268 /* cancel selection */
1269 _display.get_selection()->unselect_all ();
1270 /* end any editing by grabbing focus */
1271 _display.grab_focus ();
1275 //Scroll editor canvas to selected track
1276 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1278 // Get the model row.
1279 Gtk::TreeModel::Row row = *_model->get_iter (path);
1281 TimeAxisView *tv = row[_columns.tv];
1283 int y_pos = tv->y_position();
1285 //Clamp the y pos so that we do not extend beyond the canvas full height.
1286 if (_editor->full_canvas_height - y_pos < _editor->_canvas_height){
1287 y_pos = _editor->full_canvas_height - _editor->_canvas_height;
1290 //Only scroll to if the track is visible
1292 _editor->reset_y_origin (y_pos);
1300 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const&, bool /*selected*/)
1302 if (selection_countdown) {
1303 if (--selection_countdown == 0) {
1306 /* no selection yet ... */
1313 struct EditorOrderRouteSorter {
1314 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1315 if (a->is_master()) {
1316 /* master before everything else */
1318 } else if (b->is_master()) {
1319 /* everything else before master */
1322 return a->order_key (EditorSort) < b->order_key (EditorSort);
1327 EditorRoutes::initial_display ()
1329 suspend_redisplay ();
1333 resume_redisplay ();
1337 boost::shared_ptr<RouteList> routes = _session->get_routes();
1339 if (ARDOUR_UI::instance()->session_is_new ()) {
1341 /* new session: stamp all routes with the right editor order
1345 _editor->add_routes (*(routes.get()));
1349 /* existing session: sort a copy of the route list by
1350 * editor-order and add its contents to the display.
1353 RouteList r (*routes);
1354 EditorOrderRouteSorter sorter;
1357 _editor->add_routes (r);
1361 resume_redisplay ();
1365 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
1367 const SelectionData& data,
1368 guint info, guint time)
1370 if (data.get_target() == "GTK_TREE_MODEL_ROW") {
1371 _display.on_drag_data_received (context, x, y, data, info, time);
1375 context->drag_finish (true, false, time);
1379 EditorRoutes::move_selected_tracks (bool up)
1381 if (_editor->selection->tracks.empty()) {
1385 typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
1386 std::list<ViewRoute> view_routes;
1387 std::vector<int> neworder;
1388 TreeModel::Children rows = _model->children();
1389 TreeModel::Children::iterator ri;
1391 for (ri = rows.begin(); ri != rows.end(); ++ri) {
1392 TimeAxisView* tv = (*ri)[_columns.tv];
1393 boost::shared_ptr<Route> route = (*ri)[_columns.route];
1395 view_routes.push_back (ViewRoute (tv, route));
1398 list<ViewRoute>::iterator trailing;
1399 list<ViewRoute>::iterator leading;
1403 trailing = view_routes.begin();
1404 leading = view_routes.begin();
1408 while (leading != view_routes.end()) {
1409 if (_editor->selection->selected (leading->first)) {
1410 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
1411 leading = view_routes.erase (leading);
1420 /* if we could use reverse_iterator in list::insert, this code
1421 would be a beautiful reflection of the code above. but we can't
1422 and so it looks like a bit of a mess.
1425 trailing = view_routes.end();
1426 leading = view_routes.end();
1428 --leading; if (leading == view_routes.begin()) { return; }
1434 if (_editor->selection->selected (leading->first)) {
1435 list<ViewRoute>::iterator tmp;
1437 /* need to insert *after* trailing, not *before* it,
1438 which is what insert (iter, val) normally does.
1444 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
1446 /* can't use iter = cont.erase (iter); form here, because
1447 we need iter to move backwards.
1455 if (leading == view_routes.begin()) {
1456 /* the one we've just inserted somewhere else
1457 was the first in the list. erase this copy,
1458 and then break, because we're done.
1463 view_routes.erase (leading);
1472 if (leading == view_routes.begin()) {
1481 for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
1482 uint32_t order = leading->second->order_key (EditorSort);
1483 neworder.push_back (order);
1487 DEBUG_TRACE (DEBUG::OrderKeys, "New order after moving tracks:\n");
1488 for (vector<int>::iterator i = neworder.begin(); i != neworder.end(); ++i) {
1489 DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("\t%1\n", *i));
1491 DEBUG_TRACE (DEBUG::OrderKeys, "-------\n");
1493 for (vector<int>::iterator i = neworder.begin(); i != neworder.end(); ++i) {
1494 if (*i >= (int) neworder.size()) {
1495 cerr << "Trying to move something to " << *i << " of " << neworder.size() << endl;
1497 assert (*i < (int) neworder.size ());
1501 _model->reorder (neworder);
1505 EditorRoutes::update_input_active_display ()
1507 TreeModel::Children rows = _model->children();
1508 TreeModel::Children::iterator i;
1510 for (i = rows.begin(); i != rows.end(); ++i) {
1511 boost::shared_ptr<Route> route = (*i)[_columns.route];
1513 if (boost::dynamic_pointer_cast<Track> (route)) {
1514 boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
1517 (*i)[_columns.is_input_active] = mt->input_active();
1524 EditorRoutes::update_rec_display ()
1526 TreeModel::Children rows = _model->children();
1527 TreeModel::Children::iterator i;
1529 for (i = rows.begin(); i != rows.end(); ++i) {
1530 boost::shared_ptr<Route> route = (*i)[_columns.route];
1532 if (boost::dynamic_pointer_cast<Track> (route)) {
1533 boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
1535 if (route->record_enabled()) {
1536 if (_session->record_status() == Session::Recording) {
1537 (*i)[_columns.rec_state] = 1;
1539 (*i)[_columns.rec_state] = 2;
1541 } else if (mt && mt->step_editing()) {
1542 (*i)[_columns.rec_state] = 3;
1544 (*i)[_columns.rec_state] = 0;
1547 (*i)[_columns.name_editable] = !route->record_enabled ();
1553 EditorRoutes::update_mute_display ()
1555 TreeModel::Children rows = _model->children();
1556 TreeModel::Children::iterator i;
1558 for (i = rows.begin(); i != rows.end(); ++i) {
1559 boost::shared_ptr<Route> route = (*i)[_columns.route];
1560 (*i)[_columns.mute_state] = RouteUI::mute_active_state (_session, route);
1565 EditorRoutes::update_solo_display (bool /* selfsoloed */)
1567 TreeModel::Children rows = _model->children();
1568 TreeModel::Children::iterator i;
1570 for (i = rows.begin(); i != rows.end(); ++i) {
1571 boost::shared_ptr<Route> route = (*i)[_columns.route];
1572 (*i)[_columns.solo_state] = RouteUI::solo_active_state (route);
1577 EditorRoutes::update_solo_isolate_display ()
1579 TreeModel::Children rows = _model->children();
1580 TreeModel::Children::iterator i;
1582 for (i = rows.begin(); i != rows.end(); ++i) {
1583 boost::shared_ptr<Route> route = (*i)[_columns.route];
1584 (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_active_state (route) ? 1 : 0;
1589 EditorRoutes::update_solo_safe_display ()
1591 TreeModel::Children rows = _model->children();
1592 TreeModel::Children::iterator i;
1594 for (i = rows.begin(); i != rows.end(); ++i) {
1595 boost::shared_ptr<Route> route = (*i)[_columns.route];
1596 (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_active_state (route) ? 1 : 0;
1601 EditorRoutes::views () const
1603 list<TimeAxisView*> v;
1604 for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
1605 v.push_back ((*i)[_columns.tv]);
1612 EditorRoutes::clear ()
1614 _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1616 _display.set_model (_model);
1620 EditorRoutes::name_edit_started (CellEditable* ce, const Glib::ustring&)
1624 /* give it a special name */
1626 Gtk::Entry *e = dynamic_cast<Gtk::Entry*> (ce);
1629 e->set_name (X_("RouteNameEditorEntry"));
1634 EditorRoutes::name_edit (std::string const & path, std::string const & new_text)
1638 TreeIter iter = _model->get_iter (path);
1644 boost::shared_ptr<Route> route = (*iter)[_columns.route];
1646 if (route && route->name() != new_text) {
1647 route->set_name (new_text);
1652 EditorRoutes::solo_changed_so_update_mute ()
1654 update_mute_display ();
1658 EditorRoutes::show_tracks_with_regions_at_playhead ()
1660 boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
1662 set<TimeAxisView*> show;
1663 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
1664 TimeAxisView* tav = _editor->axis_view_from_route (*i);
1670 suspend_redisplay ();
1672 TreeModel::Children rows = _model->children ();
1673 for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
1674 TimeAxisView* tv = (*i)[_columns.tv];
1675 (*i)[_columns.visible] = (show.find (tv) != show.end());
1678 resume_redisplay ();