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 "ardour/session.h"
31 #include "ardour_ui.h"
32 #include "audio_time_axis.h"
33 #include "midi_time_axis.h"
34 #include "mixer_strip.h"
35 #include "gui_thread.h"
38 #include "editor_group_tabs.h"
39 #include "editor_routes.h"
41 #include "pbd/unknown_type.h"
43 #include "ardour/route.h"
44 #include "ardour/midi_track.h"
46 #include "gtkmm2ext/cell_renderer_pixbuf_multi.h"
47 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
48 #include "gtkmm2ext/treeutils.h"
53 using namespace ARDOUR;
56 using namespace Gtkmm2ext;
58 using Gtkmm2ext::Keyboard;
60 EditorRoutes::EditorRoutes (Editor* e)
62 , _ignore_reorder (false)
63 , _no_redisplay (false)
64 , _redisplay_does_not_sync_order_keys (false)
65 , _redisplay_does_not_reset_order_keys (false)
68 , selection_countdown (0)
71 static const int column_width = 22;
73 _scroller.add (_display);
74 _scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
76 _model = ListStore::create (_columns);
77 _display.set_model (_model);
79 // Record enable toggle
80 CellRendererPixbufMulti* rec_col_renderer = manage (new CellRendererPixbufMulti());
82 rec_col_renderer->set_pixbuf (0, ::get_icon("record-normal-disabled"));
83 rec_col_renderer->set_pixbuf (1, ::get_icon("record-normal-in-progress"));
84 rec_col_renderer->set_pixbuf (2, ::get_icon("record-normal-enabled"));
85 rec_col_renderer->set_pixbuf (3, ::get_icon("record-step"));
86 rec_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_rec_enable_changed));
88 TreeViewColumn* rec_state_column = manage (new TreeViewColumn("R", *rec_col_renderer));
90 rec_state_column->add_attribute(rec_col_renderer->property_state(), _columns.rec_state);
91 rec_state_column->add_attribute(rec_col_renderer->property_visible(), _columns.is_track);
93 rec_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
94 rec_state_column->set_alignment(ALIGN_CENTER);
95 rec_state_column->set_expand(false);
96 rec_state_column->set_fixed_width(column_width);
100 CellRendererPixbufMulti* input_active_col_renderer = manage (new CellRendererPixbufMulti());
101 input_active_col_renderer->set_pixbuf (0, ::get_icon("midi-input-inactive"));
102 input_active_col_renderer->set_pixbuf (1, ::get_icon("midi-input-active"));
103 input_active_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_input_active_changed));
105 TreeViewColumn* input_active_column = manage (new TreeViewColumn ("I", *input_active_col_renderer));
107 input_active_column->add_attribute(input_active_col_renderer->property_state(), _columns.is_input_active);
108 input_active_column->add_attribute (input_active_col_renderer->property_visible(), _columns.is_midi);
110 input_active_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
111 input_active_column->set_alignment(ALIGN_CENTER);
112 input_active_column->set_expand(false);
113 input_active_column->set_fixed_width(column_width);
115 // Mute enable toggle
116 CellRendererPixbufMulti* mute_col_renderer = manage (new CellRendererPixbufMulti());
118 mute_col_renderer->set_pixbuf (0, ::get_icon("mute-disabled"));
119 mute_col_renderer->set_pixbuf (1, ::get_icon("muted-by-others"));
120 mute_col_renderer->set_pixbuf (2, ::get_icon("mute-enabled"));
121 mute_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_mute_enable_toggled));
123 TreeViewColumn* mute_state_column = manage (new TreeViewColumn("M", *mute_col_renderer));
125 mute_state_column->add_attribute(mute_col_renderer->property_state(), _columns.mute_state);
126 mute_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
127 mute_state_column->set_alignment(ALIGN_CENTER);
128 mute_state_column->set_expand(false);
129 mute_state_column->set_fixed_width(15);
131 // Solo enable toggle
132 CellRendererPixbufMulti* solo_col_renderer = manage (new CellRendererPixbufMulti());
134 solo_col_renderer->set_pixbuf (0, ::get_icon("solo-disabled"));
135 solo_col_renderer->set_pixbuf (1, ::get_icon("solo-enabled"));
136 solo_col_renderer->set_pixbuf (3, ::get_icon("soloed-by-others"));
137 solo_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_enable_toggled));
139 TreeViewColumn* solo_state_column = manage (new TreeViewColumn("S", *solo_col_renderer));
141 solo_state_column->add_attribute(solo_col_renderer->property_state(), _columns.solo_state);
142 solo_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
143 solo_state_column->set_alignment(ALIGN_CENTER);
144 solo_state_column->set_expand(false);
145 solo_state_column->set_fixed_width(column_width);
147 // Solo isolate toggle
148 CellRendererPixbufMulti* solo_iso_renderer = manage (new CellRendererPixbufMulti());
150 solo_iso_renderer->set_pixbuf (0, ::get_icon("solo-isolate-disabled"));
151 solo_iso_renderer->set_pixbuf (1, ::get_icon("solo-isolate-enabled"));
152 solo_iso_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_isolate_toggled));
154 TreeViewColumn* solo_isolate_state_column = manage (new TreeViewColumn("SI", *solo_iso_renderer));
156 solo_isolate_state_column->add_attribute(solo_iso_renderer->property_state(), _columns.solo_isolate_state);
157 solo_isolate_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
158 solo_isolate_state_column->set_alignment(ALIGN_CENTER);
159 solo_isolate_state_column->set_expand(false);
160 solo_isolate_state_column->set_fixed_width(column_width);
163 CellRendererPixbufMulti* solo_safe_renderer = manage (new CellRendererPixbufMulti ());
165 solo_safe_renderer->set_pixbuf (0, ::get_icon("solo-safe-disabled"));
166 solo_safe_renderer->set_pixbuf (1, ::get_icon("solo-safe-enabled"));
167 solo_safe_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_safe_toggled));
169 TreeViewColumn* solo_safe_state_column = manage (new TreeViewColumn(_("SS"), *solo_safe_renderer));
170 solo_safe_state_column->add_attribute(solo_safe_renderer->property_state(), _columns.solo_safe_state);
171 solo_safe_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
172 solo_safe_state_column->set_alignment(ALIGN_CENTER);
173 solo_safe_state_column->set_expand(false);
174 solo_safe_state_column->set_fixed_width(column_width);
176 _display.append_column (*input_active_column);
177 _display.append_column (*rec_state_column);
178 _display.append_column (*mute_state_column);
179 _display.append_column (*solo_state_column);
180 _display.append_column (*solo_isolate_state_column);
181 _display.append_column (*solo_safe_state_column);
183 _name_column = _display.append_column (_("Name"), _columns.text) - 1;
184 _visible_column = _display.append_column (_("V"), _columns.visible) - 1;
186 _display.set_headers_visible (true);
187 _display.set_name ("TrackListDisplay");
188 _display.get_selection()->set_mode (SELECTION_SINGLE);
189 _display.get_selection()->set_select_function (sigc::mem_fun (*this, &EditorRoutes::selection_filter));
190 _display.set_reorderable (true);
191 _display.set_rules_hint (true);
192 _display.set_size_request (100, -1);
193 _display.add_object_drag (_columns.route.index(), "routes");
195 CellRendererText* name_cell = dynamic_cast<CellRendererText*> (_display.get_column_cell_renderer (_name_column));
198 name_cell->signal_editing_started().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit_started));
200 TreeViewColumn* name_column = _display.get_column (_name_column);
202 assert (name_column);
204 name_column->add_attribute (name_cell->property_editable(), _columns.name_editable);
205 name_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
206 name_column->set_expand(true);
207 name_column->set_min_width(50);
209 name_cell->property_editable() = true;
210 name_cell->signal_edited().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit));
212 // Set the visible column cell renderer to radio toggle
213 CellRendererToggle* visible_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (_visible_column));
215 visible_cell->property_activatable() = true;
216 visible_cell->property_radio() = false;
217 visible_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::visible_changed));
219 TreeViewColumn* visible_col = dynamic_cast<TreeViewColumn*> (_display.get_column (_visible_column));
220 visible_col->set_expand(false);
221 visible_col->set_sizing(TREE_VIEW_COLUMN_FIXED);
222 visible_col->set_fixed_width(30);
223 visible_col->set_alignment(ALIGN_CENTER);
225 _model->signal_row_deleted().connect (sigc::mem_fun (*this, &EditorRoutes::route_deleted));
226 _model->signal_rows_reordered().connect (sigc::mem_fun (*this, &EditorRoutes::reordered));
228 _display.signal_button_press_event().connect (sigc::mem_fun (*this, &EditorRoutes::button_press), false);
229 _scroller.signal_key_press_event().connect (sigc::mem_fun(*this, &EditorRoutes::key_press), false);
231 _scroller.signal_focus_in_event().connect (sigc::mem_fun (*this, &EditorRoutes::focus_in), false);
232 _scroller.signal_focus_out_event().connect (sigc::mem_fun (*this, &EditorRoutes::focus_out));
234 _display.signal_enter_notify_event().connect (sigc::mem_fun (*this, &EditorRoutes::enter_notify), false);
235 _display.signal_leave_notify_event().connect (sigc::mem_fun (*this, &EditorRoutes::leave_notify), false);
237 _display.set_enable_search (false);
239 Route::SyncOrderKeys.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::sync_order_keys, this, _1), gui_context());
243 EditorRoutes::focus_in (GdkEventFocus*)
245 Window* win = dynamic_cast<Window*> (_scroller.get_toplevel ());
248 old_focus = win->get_focus ();
255 /* try to do nothing on focus in (doesn't work, hence selection_count nonsense) */
260 EditorRoutes::focus_out (GdkEventFocus*)
263 old_focus->grab_focus ();
271 EditorRoutes::enter_notify (GdkEventCrossing*)
277 /* arm counter so that ::selection_filter() will deny selecting anything for the
278 next two attempts to change selection status.
280 selection_countdown = 2;
281 _scroller.grab_focus ();
282 Keyboard::magic_widget_grab_focus ();
287 EditorRoutes::leave_notify (GdkEventCrossing*)
289 selection_countdown = 0;
292 old_focus->grab_focus ();
296 Keyboard::magic_widget_drop_focus ();
301 EditorRoutes::set_session (Session* s)
303 SessionHandlePtr::set_session (s);
308 _session->SoloChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::solo_changed_so_update_mute, this), gui_context());
309 _session->RecordStateChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
314 EditorRoutes::on_input_active_changed (std::string const & path_string)
316 // Get the model row that has been toggled.
317 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
319 TimeAxisView* tv = row[_columns.tv];
320 RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
323 boost::shared_ptr<MidiTrack> mt;
324 mt = rtv->midi_track();
326 mt->set_input_active (!mt->input_active());
332 EditorRoutes::on_tv_rec_enable_changed (std::string const & path_string)
334 // Get the model row that has been toggled.
335 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
337 TimeAxisView* tv = row[_columns.tv];
338 RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
340 if (rtv && rtv->track()) {
341 boost::shared_ptr<RouteList> rl (new RouteList);
342 rl->push_back (rtv->route());
343 _session->set_record_enabled (rl, !rtv->track()->record_enabled(), Session::rt_cleanup);
348 EditorRoutes::on_tv_mute_enable_toggled (std::string const & path_string)
350 // Get the model row that has been toggled.
351 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
353 TimeAxisView *tv = row[_columns.tv];
354 RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
357 boost::shared_ptr<RouteList> rl (new RouteList);
358 rl->push_back (rtv->route());
359 _session->set_mute (rl, !rtv->route()->muted(), Session::rt_cleanup);
364 EditorRoutes::on_tv_solo_enable_toggled (std::string const & path_string)
366 // Get the model row that has been toggled.
367 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
369 TimeAxisView *tv = row[_columns.tv];
370 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
373 boost::shared_ptr<RouteList> rl (new RouteList);
374 rl->push_back (rtv->route());
375 if (Config->get_solo_control_is_listen_control()) {
376 _session->set_listen (rl, !rtv->route()->listening_via_monitor(), Session::rt_cleanup);
378 _session->set_solo (rl, !rtv->route()->self_soloed(), Session::rt_cleanup);
384 EditorRoutes::on_tv_solo_isolate_toggled (std::string const & path_string)
386 // Get the model row that has been toggled.
387 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
389 TimeAxisView *tv = row[_columns.tv];
390 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
393 rtv->route()->set_solo_isolated (!rtv->route()->solo_isolated(), this);
398 EditorRoutes::on_tv_solo_safe_toggled (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 rtv->route()->set_solo_safe (!rtv->route()->solo_safe(), this);
412 EditorRoutes::build_menu ()
414 using namespace Menu_Helpers;
419 MenuList& items = _menu->items();
420 _menu->set_name ("ArdourContextMenu");
422 items.push_back (MenuElem (_("Show All"), sigc::mem_fun (*this, &EditorRoutes::show_all_routes)));
423 items.push_back (MenuElem (_("Hide All"), sigc::mem_fun (*this, &EditorRoutes::hide_all_routes)));
424 items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiotracks)));
425 items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiotracks)));
426 items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiobus)));
427 items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiobus)));
428 items.push_back (MenuElem (_("Show All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_miditracks)));
429 items.push_back (MenuElem (_("Hide All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_miditracks)));
430 items.push_back (MenuElem (_("Show Tracks With Regions Under Playhead"), sigc::mem_fun (*this, &EditorRoutes::show_tracks_with_regions_at_playhead)));
434 EditorRoutes::show_menu ()
440 _menu->popup (1, gtk_get_current_event_time());
444 EditorRoutes::redisplay ()
446 if (_no_redisplay || !_session) {
450 TreeModel::Children rows = _model->children();
451 TreeModel::Children::iterator i;
455 for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
456 TimeAxisView *tv = (*i)[_columns.tv];
457 boost::shared_ptr<Route> route = (*i)[_columns.route];
460 // just a "title" row
464 if (!_redisplay_does_not_reset_order_keys) {
465 /* this reorder is caused by user action, so reassign sort order keys
468 route->set_order_key (N_ ("editor"), n);
471 bool visible = tv->marked_for_display ();
473 /* show or hide the TimeAxisView */
475 position += tv->show_at (position, n, &_editor->edit_controls_vbox);
476 tv->clip_to_viewport ();
483 /* whenever we go idle, update the track view list to reflect the new order.
484 we can't do this here, because we could mess up something that is traversing
485 the track order and has caused a redisplay of the list.
487 Glib::signal_idle().connect (sigc::mem_fun (*_editor, &Editor::sync_track_view_list_and_routes));
489 _editor->reset_controls_layout_height (position);
490 _editor->reset_controls_layout_width ();
491 _editor->full_canvas_height = position + _editor->canvas_timebars_vsize;
492 _editor->vertical_adjustment.set_upper (_editor->full_canvas_height);
494 if ((_editor->vertical_adjustment.get_value() + _editor->_canvas_height) > _editor->vertical_adjustment.get_upper()) {
496 We're increasing the size of the canvas while the bottom is visible.
497 We scroll down to keep in step with the controls layout.
499 _editor->vertical_adjustment.set_value (_editor->full_canvas_height - _editor->_canvas_height);
502 if (!_redisplay_does_not_reset_order_keys && !_redisplay_does_not_sync_order_keys) {
503 _session->sync_order_keys (N_ ("editor"));
508 EditorRoutes::route_deleted (Gtk::TreeModel::Path const &)
510 if (!_session || _session->deletion_in_progress()) {
514 /* this could require an order reset & sync */
515 _session->set_remote_control_ids();
516 _ignore_reorder = true;
518 _ignore_reorder = false;
522 EditorRoutes::visible_changed (std::string const & path)
524 if (_session && _session->deletion_in_progress()) {
530 if ((iter = _model->get_iter (path))) {
531 TimeAxisView* tv = (*iter)[_columns.tv];
533 bool visible = (*iter)[_columns.visible];
535 if (tv->set_marked_for_display (!visible)) {
536 _redisplay_does_not_reset_order_keys = true;
537 _session->set_remote_control_ids();
538 update_visibility ();
540 _redisplay_does_not_reset_order_keys = false;
547 EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
551 _redisplay_does_not_sync_order_keys = true;
552 suspend_redisplay ();
554 for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) {
556 boost::shared_ptr<MidiTrack> midi_trk = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
558 row = *(_model->append ());
560 row[_columns.text] = (*x)->route()->name();
561 row[_columns.visible] = (*x)->marked_for_display();
562 row[_columns.tv] = *x;
563 row[_columns.route] = (*x)->route ();
564 row[_columns.is_track] = (boost::dynamic_pointer_cast<Track> ((*x)->route()) != 0);
567 row[_columns.is_input_active] = midi_trk->input_active ();
568 row[_columns.is_midi] = true;
570 row[_columns.is_input_active] = false;
571 row[_columns.is_midi] = false;
574 row[_columns.mute_state] = (*x)->route()->muted();
575 row[_columns.solo_state] = RouteUI::solo_visual_state ((*x)->route());
576 row[_columns.solo_isolate_state] = (*x)->route()->solo_isolated();
577 row[_columns.solo_safe_state] = (*x)->route()->solo_safe();
578 row[_columns.name_editable] = true;
580 _ignore_reorder = true;
582 /* added a new fresh one at the end */
583 if ((*x)->route()->order_key (N_ ("editor")) == -1) {
584 (*x)->route()->set_order_key (N_ ("editor"), _model->children().size()-1);
587 _ignore_reorder = false;
589 boost::weak_ptr<Route> wr ((*x)->route());
591 (*x)->route()->gui_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
592 (*x)->route()->PropertyChanged.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::route_property_changed, this, _1, wr), gui_context());
594 if ((*x)->is_track()) {
595 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
596 t->RecordEnableChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
599 if ((*x)->is_midi_track()) {
600 boost::shared_ptr<MidiTrack> t = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
601 t->StepEditStatusChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
602 t->InputActiveChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_input_active_display, this), gui_context());
605 (*x)->route()->mute_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
606 (*x)->route()->solo_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
607 (*x)->route()->listen_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
608 (*x)->route()->solo_isolated_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_isolate_display, this), gui_context());
609 (*x)->route()->solo_safe_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_safe_display, this), gui_context());
612 update_rec_display ();
613 update_mute_display ();
614 update_solo_display (true);
615 update_solo_isolate_display ();
616 update_solo_safe_display ();
617 update_input_active_display ();
619 _redisplay_does_not_sync_order_keys = false;
623 EditorRoutes::handle_gui_changes (string const & what, void*)
625 ENSURE_GUI_THREAD (*this, &EditorRoutes::handle_gui_changes, what, src)
627 if (what == "track_height") {
628 /* Optional :make tracks change height while it happens, instead
631 //update_canvas_now ();
635 if (what == "visible_tracks") {
641 EditorRoutes::route_removed (TimeAxisView *tv)
643 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed, tv)
645 TreeModel::Children rows = _model->children();
646 TreeModel::Children::iterator ri;
648 /* the core model has changed, there is no need to sync
652 _redisplay_does_not_sync_order_keys = true;
654 for (ri = rows.begin(); ri != rows.end(); ++ri) {
655 if ((*ri)[_columns.tv] == tv) {
661 _redisplay_does_not_sync_order_keys = false;
665 EditorRoutes::route_property_changed (const PropertyChange& what_changed, boost::weak_ptr<Route> r)
667 if (!what_changed.contains (ARDOUR::Properties::name)) {
671 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_name_changed, r)
673 boost::shared_ptr<Route> route = r.lock ();
679 TreeModel::Children rows = _model->children();
680 TreeModel::Children::iterator i;
682 for (i = rows.begin(); i != rows.end(); ++i) {
683 boost::shared_ptr<Route> t = (*i)[_columns.route];
685 (*i)[_columns.text] = route->name();
692 EditorRoutes::update_visibility ()
694 TreeModel::Children rows = _model->children();
695 TreeModel::Children::iterator i;
697 suspend_redisplay ();
699 for (i = rows.begin(); i != rows.end(); ++i) {
700 TimeAxisView *tv = (*i)[_columns.tv];
701 (*i)[_columns.visible] = tv->marked_for_display ();
708 EditorRoutes::hide_track_in_display (TimeAxisView& tv)
710 TreeModel::Children rows = _model->children();
711 TreeModel::Children::iterator i;
713 for (i = rows.begin(); i != rows.end(); ++i) {
714 if ((*i)[_columns.tv] == &tv) {
715 tv.set_marked_for_display (false);
716 (*i)[_columns.visible] = false;
724 EditorRoutes::show_track_in_display (TimeAxisView& tv)
726 TreeModel::Children rows = _model->children();
727 TreeModel::Children::iterator i;
730 for (i = rows.begin(); i != rows.end(); ++i) {
731 if ((*i)[_columns.tv] == &tv) {
732 tv.set_marked_for_display (true);
733 (*i)[_columns.visible] = true;
741 EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
746 /** If src != "editor", take editor order keys from each route and use them to rearrange the
747 * route list so that the visual arrangement of routes matches the order keys from the routes.
750 EditorRoutes::sync_order_keys (string const & src)
752 map<int, int> new_order;
753 TreeModel::Children rows = _model->children();
754 TreeModel::Children::iterator ri;
756 if (src == N_ ("editor") || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
760 bool changed = false;
763 for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
764 boost::shared_ptr<Route> route = (*ri)[_columns.route];
766 int const old_key = order;
767 int const new_key = route->order_key (N_ ("editor"));
769 new_order[new_key] = old_key;
771 if (new_key != old_key) {
777 _redisplay_does_not_reset_order_keys = true;
779 /* `compact' new_order into a vector */
781 for (map<int, int>::const_iterator i = new_order.begin(); i != new_order.end(); ++i) {
782 co.push_back (i->second);
785 _model->reorder (co);
786 _redisplay_does_not_reset_order_keys = false;
792 EditorRoutes::hide_all_tracks (bool /*with_select*/)
794 TreeModel::Children rows = _model->children();
795 TreeModel::Children::iterator i;
797 suspend_redisplay ();
799 for (i = rows.begin(); i != rows.end(); ++i) {
801 TreeModel::Row row = (*i);
802 TimeAxisView *tv = row[_columns.tv];
808 row[_columns.visible] = false;
813 /* XXX this seems like a hack and half, but its not clear where to put this
817 //reset_scrolling_region ();
821 EditorRoutes::set_all_tracks_visibility (bool yn)
823 TreeModel::Children rows = _model->children();
824 TreeModel::Children::iterator i;
826 suspend_redisplay ();
828 for (i = rows.begin(); i != rows.end(); ++i) {
830 TreeModel::Row row = (*i);
831 TimeAxisView* tv = row[_columns.tv];
837 (*i)[_columns.visible] = yn;
844 EditorRoutes::set_all_audio_midi_visibility (int tracks, bool yn)
846 TreeModel::Children rows = _model->children();
847 TreeModel::Children::iterator i;
849 suspend_redisplay ();
851 for (i = rows.begin(); i != rows.end(); ++i) {
853 TreeModel::Row row = (*i);
854 TimeAxisView* tv = row[_columns.tv];
856 AudioTimeAxisView* atv;
857 MidiTimeAxisView* mtv;
863 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
866 (*i)[_columns.visible] = yn;
870 if (atv->is_audio_track()) {
871 (*i)[_columns.visible] = yn;
876 if (!atv->is_audio_track()) {
877 (*i)[_columns.visible] = yn;
882 else if ((mtv = dynamic_cast<MidiTimeAxisView*>(tv)) != 0) {
885 (*i)[_columns.visible] = yn;
889 if (mtv->is_midi_track()) {
890 (*i)[_columns.visible] = yn;
901 EditorRoutes::hide_all_routes ()
903 set_all_tracks_visibility (false);
907 EditorRoutes::show_all_routes ()
909 set_all_tracks_visibility (true);
913 EditorRoutes::show_all_audiotracks()
915 set_all_audio_midi_visibility (1, true);
918 EditorRoutes::hide_all_audiotracks ()
920 set_all_audio_midi_visibility (1, false);
924 EditorRoutes::show_all_audiobus ()
926 set_all_audio_midi_visibility (2, true);
929 EditorRoutes::hide_all_audiobus ()
931 set_all_audio_midi_visibility (2, false);
935 EditorRoutes::show_all_miditracks()
937 set_all_audio_midi_visibility (3, true);
940 EditorRoutes::hide_all_miditracks ()
942 set_all_audio_midi_visibility (3, false);
946 EditorRoutes::key_press (GdkEventKey* ev)
949 boost::shared_ptr<RouteList> rl (new RouteList);
952 switch (ev->keyval) {
954 case GDK_ISO_Left_Tab:
956 /* If we appear to be editing something, leave that cleanly and appropriately.
959 name_editable->editing_done ();
963 col = _display.get_column (_name_column); // select&focus on name column
965 if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
966 treeview_select_previous (_display, _model, col);
968 treeview_select_next (_display, _model, col);
975 if (get_relevant_routes (rl)) {
976 _session->set_mute (rl, !rl->front()->muted(), Session::rt_cleanup);
982 if (Config->get_solo_control_is_listen_control()) {
983 _session->set_listen (rl, !rl->front()->listening_via_monitor(), Session::rt_cleanup);
985 _session->set_solo (rl, !rl->front()->self_soloed(), Session::rt_cleanup);
991 if (get_relevant_routes (rl)) {
992 _session->set_record_enabled (rl, !rl->front()->record_enabled(), Session::rt_cleanup);
1004 EditorRoutes::get_relevant_routes (boost::shared_ptr<RouteList> rl)
1007 RouteTimeAxisView* rtv;
1008 RefPtr<TreeSelection> selection = _display.get_selection();
1012 if (selection->count_selected_rows() != 0) {
1016 RefPtr<TreeModel> tm = RefPtr<TreeModel>::cast_dynamic (_model);
1017 iter = selection->get_selected (tm);
1020 /* use mouse pointer */
1025 _display.get_pointer (x, y);
1026 _display.convert_widget_to_bin_window_coords (x, y, bx, by);
1028 if (_display.get_path_at_pos (bx, by, path)) {
1029 iter = _model->get_iter (path);
1034 tv = (*iter)[_columns.tv];
1036 rtv = dynamic_cast<RouteTimeAxisView*>(tv);
1038 rl->push_back (rtv->route());
1043 return !rl->empty();
1047 EditorRoutes::button_press (GdkEventButton* ev)
1049 if (Keyboard::is_context_menu_event (ev)) {
1054 //Scroll editor canvas to selected track
1055 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1057 TreeModel::Path path;
1058 TreeViewColumn *tvc;
1062 _display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y);
1064 // Get the model row.
1065 Gtk::TreeModel::Row row = *_model->get_iter (path);
1067 TimeAxisView *tv = row[_columns.tv];
1069 int y_pos = tv->y_position();
1071 //Clamp the y pos so that we do not extend beyond the canvas full height.
1072 if (_editor->full_canvas_height - y_pos < _editor->_canvas_height){
1073 y_pos = _editor->full_canvas_height - _editor->_canvas_height;
1076 //Only scroll to if the track is visible
1078 _editor->reset_y_origin (y_pos);
1086 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const&, bool /*selected*/)
1088 if (selection_countdown) {
1089 if (--selection_countdown == 0) {
1092 /* no selection yet ... */
1099 struct EditorOrderRouteSorter {
1100 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1101 /* use of ">" forces the correct sort order */
1102 return a->order_key (N_ ("editor")) < b->order_key (N_ ("editor"));
1107 EditorRoutes::initial_display ()
1109 suspend_redisplay ();
1113 resume_redisplay ();
1117 boost::shared_ptr<RouteList> routes = _session->get_routes();
1118 RouteList r (*routes);
1119 EditorOrderRouteSorter sorter;
1122 _editor->handle_new_route (r);
1124 /* don't show master bus in a new session */
1126 if (ARDOUR_UI::instance()->session_is_new ()) {
1128 TreeModel::Children rows = _model->children();
1129 TreeModel::Children::iterator i;
1131 _no_redisplay = true;
1133 for (i = rows.begin(); i != rows.end(); ++i) {
1135 TimeAxisView *tv = (*i)[_columns.tv];
1136 RouteTimeAxisView *rtv;
1138 if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
1139 if (rtv->route()->is_master()) {
1140 _display.get_selection()->unselect (i);
1145 _no_redisplay = false;
1149 resume_redisplay ();
1153 EditorRoutes::track_list_reorder (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &, int* /*new_order*/)
1155 _redisplay_does_not_sync_order_keys = true;
1156 _session->set_remote_control_ids();
1158 _redisplay_does_not_sync_order_keys = false;
1162 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
1164 const SelectionData& data,
1165 guint info, guint time)
1167 if (data.get_target() == "GTK_TREE_MODEL_ROW") {
1168 _display.on_drag_data_received (context, x, y, data, info, time);
1172 context->drag_finish (true, false, time);
1176 EditorRoutes::move_selected_tracks (bool up)
1178 if (_editor->selection->tracks.empty()) {
1182 typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
1183 std::list<ViewRoute> view_routes;
1184 std::vector<int> neworder;
1185 TreeModel::Children rows = _model->children();
1186 TreeModel::Children::iterator ri;
1188 for (ri = rows.begin(); ri != rows.end(); ++ri) {
1189 TimeAxisView* tv = (*ri)[_columns.tv];
1190 boost::shared_ptr<Route> route = (*ri)[_columns.route];
1192 view_routes.push_back (ViewRoute (tv, route));
1195 list<ViewRoute>::iterator trailing;
1196 list<ViewRoute>::iterator leading;
1200 trailing = view_routes.begin();
1201 leading = view_routes.begin();
1205 while (leading != view_routes.end()) {
1206 if (_editor->selection->selected (leading->first)) {
1207 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
1208 leading = view_routes.erase (leading);
1217 /* if we could use reverse_iterator in list::insert, this code
1218 would be a beautiful reflection of the code above. but we can't
1219 and so it looks like a bit of a mess.
1222 trailing = view_routes.end();
1223 leading = view_routes.end();
1225 --leading; if (leading == view_routes.begin()) { return; }
1231 if (_editor->selection->selected (leading->first)) {
1232 list<ViewRoute>::iterator tmp;
1234 /* need to insert *after* trailing, not *before* it,
1235 which is what insert (iter, val) normally does.
1241 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
1243 /* can't use iter = cont.erase (iter); form here, because
1244 we need iter to move backwards.
1252 if (leading == view_routes.begin()) {
1253 /* the one we've just inserted somewhere else
1254 was the first in the list. erase this copy,
1255 and then break, because we're done.
1260 view_routes.erase (leading);
1269 if (leading == view_routes.begin()) {
1278 for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
1279 neworder.push_back (leading->second->order_key (N_ ("editor")));
1282 _model->reorder (neworder);
1284 _session->sync_order_keys (N_ ("editor"));
1288 EditorRoutes::update_input_active_display ()
1290 TreeModel::Children rows = _model->children();
1291 TreeModel::Children::iterator i;
1293 for (i = rows.begin(); i != rows.end(); ++i) {
1294 boost::shared_ptr<Route> route = (*i)[_columns.route];
1296 if (boost::dynamic_pointer_cast<Track> (route)) {
1297 boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
1300 (*i)[_columns.is_input_active] = mt->input_active();
1307 EditorRoutes::update_rec_display ()
1309 TreeModel::Children rows = _model->children();
1310 TreeModel::Children::iterator i;
1312 for (i = rows.begin(); i != rows.end(); ++i) {
1313 boost::shared_ptr<Route> route = (*i)[_columns.route];
1315 if (boost::dynamic_pointer_cast<Track> (route)) {
1316 boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
1318 if (route->record_enabled()) {
1319 if (_session->record_status() == Session::Recording) {
1320 (*i)[_columns.rec_state] = 1;
1322 (*i)[_columns.rec_state] = 2;
1324 } else if (mt && mt->step_editing()) {
1325 (*i)[_columns.rec_state] = 3;
1327 (*i)[_columns.rec_state] = 0;
1330 (*i)[_columns.name_editable] = !route->record_enabled ();
1336 EditorRoutes::update_mute_display ()
1338 TreeModel::Children rows = _model->children();
1339 TreeModel::Children::iterator i;
1341 for (i = rows.begin(); i != rows.end(); ++i) {
1342 boost::shared_ptr<Route> route = (*i)[_columns.route];
1343 (*i)[_columns.mute_state] = RouteUI::mute_visual_state (_session, route);
1348 EditorRoutes::update_solo_display (bool /* selfsoloed */)
1350 TreeModel::Children rows = _model->children();
1351 TreeModel::Children::iterator i;
1353 for (i = rows.begin(); i != rows.end(); ++i) {
1354 boost::shared_ptr<Route> route = (*i)[_columns.route];
1355 (*i)[_columns.solo_state] = RouteUI::solo_visual_state (route);
1360 EditorRoutes::update_solo_isolate_display ()
1362 TreeModel::Children rows = _model->children();
1363 TreeModel::Children::iterator i;
1365 for (i = rows.begin(); i != rows.end(); ++i) {
1366 boost::shared_ptr<Route> route = (*i)[_columns.route];
1367 (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_visual_state (route) > 0 ? 1 : 0;
1372 EditorRoutes::update_solo_safe_display ()
1374 TreeModel::Children rows = _model->children();
1375 TreeModel::Children::iterator i;
1377 for (i = rows.begin(); i != rows.end(); ++i) {
1378 boost::shared_ptr<Route> route = (*i)[_columns.route];
1379 (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_visual_state (route) > 0 ? 1 : 0;
1384 EditorRoutes::views () const
1386 list<TimeAxisView*> v;
1387 for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
1388 v.push_back ((*i)[_columns.tv]);
1395 EditorRoutes::clear ()
1397 _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1399 _display.set_model (_model);
1403 EditorRoutes::name_edit_started (CellEditable* ce, const Glib::ustring&)
1407 /* give it a special name */
1409 Gtk::Entry *e = dynamic_cast<Gtk::Entry*> (ce);
1412 e->set_name (X_("RouteNameEditorEntry"));
1417 EditorRoutes::name_edit (std::string const & path, std::string const & new_text)
1421 TreeIter iter = _model->get_iter (path);
1427 boost::shared_ptr<Route> route = (*iter)[_columns.route];
1429 if (route && route->name() != new_text) {
1430 route->set_name (new_text);
1435 EditorRoutes::solo_changed_so_update_mute ()
1437 update_mute_display ();
1441 EditorRoutes::show_tracks_with_regions_at_playhead ()
1443 boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
1445 set<TimeAxisView*> show;
1446 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
1447 TimeAxisView* tav = _editor->axis_view_from_route (*i);
1453 suspend_redisplay ();
1455 TreeModel::Children rows = _model->children ();
1456 for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
1457 TimeAxisView* tv = (*i)[_columns.tv];
1458 (*i)[_columns.visible] = (show.find (tv) != show.end());
1461 resume_redisplay ();