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"
45 #include "gtkmm2ext/cell_renderer_pixbuf_multi.h"
46 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
51 using namespace ARDOUR;
54 using namespace Gtkmm2ext;
56 using Gtkmm2ext::Keyboard;
58 EditorRoutes::EditorRoutes (Editor* e)
59 : EditorComponent (e),
60 _ignore_reorder (false),
61 _no_redisplay (false),
62 _redisplay_does_not_sync_order_keys (false),
63 _redisplay_does_not_reset_order_keys (false),
66 _scroller.add (_display);
67 _scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
69 _model = ListStore::create (_columns);
70 _display.set_model (_model);
72 // Record enable toggle
73 CellRendererPixbufToggle* rec_col_renderer = manage (new CellRendererPixbufToggle());
75 rec_col_renderer->set_active_pixbuf (::get_icon("rec-enabled"));
76 rec_col_renderer->set_inactive_pixbuf (::get_icon("act-disabled"));
77 rec_col_renderer->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_rec_enable_toggled));
79 TreeViewColumn* rec_state_column = manage (new TreeViewColumn("R", *rec_col_renderer));
81 rec_state_column->add_attribute(rec_col_renderer->property_active(), _columns.rec_enabled);
82 rec_state_column->add_attribute(rec_col_renderer->property_visible(), _columns.is_track);
83 rec_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
84 rec_state_column->set_alignment(ALIGN_CENTER);
85 rec_state_column->set_expand(false);
86 rec_state_column->set_fixed_width(15);
89 CellRendererPixbufMulti* mute_col_renderer = manage (new CellRendererPixbufMulti());
91 mute_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
92 mute_col_renderer->set_pixbuf (1, ::get_icon("mute-enabled"));
93 mute_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_mute_enable_toggled));
95 TreeViewColumn* mute_state_column = manage (new TreeViewColumn("M", *mute_col_renderer));
97 mute_state_column->add_attribute(mute_col_renderer->property_state(), _columns.mute_state);
98 mute_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
99 mute_state_column->set_alignment(ALIGN_CENTER);
100 mute_state_column->set_expand(false);
101 mute_state_column->set_fixed_width(15);
103 // Solo enable toggle
104 CellRendererPixbufMulti* solo_col_renderer = manage (new CellRendererPixbufMulti());
106 solo_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
107 solo_col_renderer->set_pixbuf (1, ::get_icon("solo-enabled"));
108 solo_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_enable_toggled));
110 TreeViewColumn* solo_state_column = manage (new TreeViewColumn("S", *solo_col_renderer));
112 solo_state_column->add_attribute(solo_col_renderer->property_state(), _columns.solo_state);
113 solo_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
114 solo_state_column->set_alignment(ALIGN_CENTER);
115 solo_state_column->set_expand(false);
116 solo_state_column->set_fixed_width(15);
118 // Solo isolate toggle
119 CellRendererPixbufMulti* solo_iso_renderer = manage (new CellRendererPixbufMulti());
121 solo_iso_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
122 solo_iso_renderer->set_pixbuf (1, ::get_icon("solo-isolated"));
123 solo_iso_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_isolate_toggled));
125 TreeViewColumn* solo_isolate_state_column = manage (new TreeViewColumn("SI", *solo_iso_renderer));
127 solo_isolate_state_column->add_attribute(solo_iso_renderer->property_state(), _columns.solo_isolate_state);
128 solo_isolate_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
129 solo_isolate_state_column->set_alignment(ALIGN_CENTER);
130 solo_isolate_state_column->set_expand(false);
131 solo_isolate_state_column->set_fixed_width(15);
134 CellRendererPixbufMulti* solo_safe_renderer = manage (new CellRendererPixbufMulti ());
136 solo_safe_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
137 solo_safe_renderer->set_pixbuf (1, ::get_icon("solo-enabled"));
138 solo_safe_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_safe_toggled));
140 TreeViewColumn* solo_safe_state_column = manage (new TreeViewColumn(_("SS"), *solo_safe_renderer));
141 solo_safe_state_column->add_attribute(solo_safe_renderer->property_state(), _columns.solo_safe_state);
142 solo_safe_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
143 solo_safe_state_column->set_alignment(ALIGN_CENTER);
144 solo_safe_state_column->set_expand(false);
145 solo_safe_state_column->set_fixed_width(22);
147 _display.append_column (*rec_state_column);
148 _display.append_column (*mute_state_column);
149 _display.append_column (*solo_state_column);
150 _display.append_column (*solo_isolate_state_column);
151 _display.append_column (*solo_safe_state_column);
153 _display.append_column (_("Name"), _columns.text);
154 _display.append_column (_("V"), _columns.visible);
156 _display.set_headers_visible (true);
157 _display.set_name ("TrackListDisplay");
158 _display.get_selection()->set_mode (SELECTION_SINGLE);
159 _display.set_reorderable (true);
160 _display.set_rules_hint (true);
161 _display.set_size_request (100, -1);
162 _display.add_object_drag (_columns.route.index(), "routes");
164 CellRendererText* name_cell = dynamic_cast<CellRendererText*> (_display.get_column_cell_renderer (5));
168 TreeViewColumn* name_column = _display.get_column (5);
170 assert (name_column);
172 name_column->add_attribute (name_cell->property_editable(), _columns.name_editable);
173 name_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
174 name_column->set_expand(true);
175 name_column->set_min_width(50);
177 name_cell->property_editable() = true;
178 name_cell->signal_edited().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit));
180 // Set the visible column cell renderer to radio toggle
181 CellRendererToggle* visible_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (6));
183 visible_cell->property_activatable() = true;
184 visible_cell->property_radio() = false;
185 visible_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::visible_changed));
187 TreeViewColumn* visible_col = dynamic_cast<TreeViewColumn*> (_display.get_column (6));
188 visible_col->set_expand(false);
189 visible_col->set_sizing(TREE_VIEW_COLUMN_FIXED);
190 visible_col->set_fixed_width(30);
191 visible_col->set_alignment(ALIGN_CENTER);
193 _model->signal_row_deleted().connect (sigc::mem_fun (*this, &EditorRoutes::route_deleted));
194 _model->signal_rows_reordered().connect (sigc::mem_fun (*this, &EditorRoutes::reordered));
196 _display.signal_button_press_event().connect (sigc::mem_fun (*this, &EditorRoutes::button_press), false);
198 Route::SyncOrderKeys.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::sync_order_keys, this, _1), gui_context());
202 EditorRoutes::set_session (Session* s)
204 SessionHandlePtr::set_session (s);
209 _session->SoloChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::solo_changed_so_update_mute, this), gui_context());
214 EditorRoutes::on_tv_rec_enable_toggled (Glib::ustring const & path_string)
216 // Get the model row that has been toggled.
217 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
219 TimeAxisView *tv = row[_columns.tv];
220 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
222 if (atv != 0 && atv->is_audio_track()){
223 boost::shared_ptr<RouteList> rl (new RouteList);
224 rl->push_back (atv->route());
225 _session->set_record_enabled (rl, !atv->track()->record_enabled(), Session::rt_cleanup);
230 EditorRoutes::on_tv_mute_enable_toggled (Glib::ustring const & path_string)
232 // Get the model row that has been toggled.
233 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
235 TimeAxisView *tv = row[_columns.tv];
236 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
239 boost::shared_ptr<RouteList> rl (new RouteList);
240 rl->push_back (atv->route());
241 _session->set_mute (rl, !atv->route()->muted(), Session::rt_cleanup);
246 EditorRoutes::on_tv_solo_enable_toggled (Glib::ustring const & path_string)
248 // Get the model row that has been toggled.
249 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
251 TimeAxisView *tv = row[_columns.tv];
252 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
255 boost::shared_ptr<RouteList> rl (new RouteList);
256 rl->push_back (atv->route());
257 _session->set_solo (rl, !atv->route()->soloed(), Session::rt_cleanup);
262 EditorRoutes::on_tv_solo_isolate_toggled (Glib::ustring const & path_string)
264 // Get the model row that has been toggled.
265 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
267 TimeAxisView *tv = row[_columns.tv];
268 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
271 atv->route()->set_solo_isolated (!atv->route()->solo_isolated(), this);
276 EditorRoutes::on_tv_solo_safe_toggled (Glib::ustring const & path_string)
278 // Get the model row that has been toggled.
279 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
281 TimeAxisView *tv = row[_columns.tv];
282 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
285 atv->route()->set_solo_safe (!atv->route()->solo_safe(), this);
290 EditorRoutes::build_menu ()
292 using namespace Menu_Helpers;
297 MenuList& items = _menu->items();
298 _menu->set_name ("ArdourContextMenu");
300 items.push_back (MenuElem (_("Show All"), sigc::mem_fun (*this, &EditorRoutes::show_all_routes)));
301 items.push_back (MenuElem (_("Hide All"), sigc::mem_fun (*this, &EditorRoutes::hide_all_routes)));
302 items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiotracks)));
303 items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiotracks)));
304 items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiobus)));
305 items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiobus)));
306 items.push_back (MenuElem (_("Show All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_miditracks)));
307 items.push_back (MenuElem (_("Hide All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_miditracks)));
308 items.push_back (MenuElem (_("Show Tracks With Regions Under Playhead"), sigc::mem_fun (*this, &EditorRoutes::show_tracks_with_regions_at_playhead)));
312 EditorRoutes::show_menu ()
318 _menu->popup (1, gtk_get_current_event_time());
322 EditorRoutes::redisplay ()
324 if (_no_redisplay || !_session) {
328 TreeModel::Children rows = _model->children();
329 TreeModel::Children::iterator i;
333 for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
334 TimeAxisView *tv = (*i)[_columns.tv];
335 boost::shared_ptr<Route> route = (*i)[_columns.route];
338 // just a "title" row
342 if (!_redisplay_does_not_reset_order_keys) {
343 /* this reorder is caused by user action, so reassign sort order keys
346 route->set_order_key (N_ ("editor"), n);
349 bool visible = (*i)[_columns.visible];
351 /* show or hide the TimeAxisView */
353 tv->set_marked_for_display (true);
354 position += tv->show_at (position, n, &_editor->edit_controls_vbox);
355 tv->clip_to_viewport ();
357 tv->set_marked_for_display (false);
364 /* whenever we go idle, update the track view list to reflect the new order.
365 we can't do this here, because we could mess up something that is traversing
366 the track order and has caused a redisplay of the list.
368 Glib::signal_idle().connect (sigc::mem_fun (*_editor, &Editor::sync_track_view_list_and_routes));
370 _editor->full_canvas_height = position + _editor->canvas_timebars_vsize;
371 _editor->vertical_adjustment.set_upper (_editor->full_canvas_height);
373 if ((_editor->vertical_adjustment.get_value() + _editor->_canvas_height) > _editor->vertical_adjustment.get_upper()) {
375 We're increasing the size of the canvas while the bottom is visible.
376 We scroll down to keep in step with the controls layout.
378 _editor->vertical_adjustment.set_value (_editor->full_canvas_height - _editor->_canvas_height);
381 if (!_redisplay_does_not_reset_order_keys && !_redisplay_does_not_sync_order_keys) {
382 _session->sync_order_keys (N_ ("editor"));
387 EditorRoutes::route_deleted (Gtk::TreeModel::Path const &)
389 if (!_session || _session->deletion_in_progress()) {
393 /* this could require an order reset & sync */
394 _session->set_remote_control_ids();
395 _ignore_reorder = true;
397 _ignore_reorder = false;
401 EditorRoutes::visible_changed (Glib::ustring const & path)
403 if (_session && _session->deletion_in_progress()) {
409 if ((iter = _model->get_iter (path))) {
410 TimeAxisView* tv = (*iter)[_columns.tv];
412 bool visible = (*iter)[_columns.visible];
413 (*iter)[_columns.visible] = !visible;
417 _redisplay_does_not_reset_order_keys = true;
418 _session->set_remote_control_ids();
420 _redisplay_does_not_reset_order_keys = false;
424 EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
428 _redisplay_does_not_sync_order_keys = true;
429 suspend_redisplay ();
431 for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) {
433 row = *(_model->append ());
435 row[_columns.text] = (*x)->route()->name();
436 row[_columns.visible] = (*x)->marked_for_display();
437 row[_columns.tv] = *x;
438 row[_columns.route] = (*x)->route ();
439 row[_columns.is_track] = (boost::dynamic_pointer_cast<Track> ((*x)->route()) != 0);
440 row[_columns.mute_state] = (*x)->route()->muted();
441 row[_columns.solo_state] = (*x)->route()->soloed();
442 row[_columns.solo_isolate_state] = (*x)->route()->solo_isolated();
443 row[_columns.solo_safe_state] = (*x)->route()->solo_safe();
444 row[_columns.name_editable] = true;
446 _ignore_reorder = true;
448 /* added a new fresh one at the end */
449 if ((*x)->route()->order_key (N_ ("editor")) == -1) {
450 (*x)->route()->set_order_key (N_ ("editor"), _model->children().size()-1);
453 _ignore_reorder = false;
455 boost::weak_ptr<Route> wr ((*x)->route());
457 (*x)->route()->gui_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
458 (*x)->route()->PropertyChanged.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::route_property_changed, this, _1, wr), gui_context());
460 if ((*x)->is_track()) {
461 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
462 t->RecordEnableChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
465 (*x)->route()->mute_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
466 (*x)->route()->solo_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
467 (*x)->route()->solo_isolated_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_isolate_display, this), gui_context());
468 (*x)->route()->solo_safe_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_safe_display, this), gui_context());
471 update_rec_display ();
472 update_mute_display ();
473 update_solo_display (true);
474 update_solo_isolate_display ();
475 update_solo_safe_display ();
477 _redisplay_does_not_sync_order_keys = false;
481 EditorRoutes::handle_gui_changes (string const & what, void*)
483 ENSURE_GUI_THREAD (*this, &EditorRoutes::handle_gui_changes, what, src)
485 if (what == "track_height") {
486 /* Optional :make tracks change height while it happens, instead
489 //update_canvas_now ();
493 if (what == "visible_tracks") {
499 EditorRoutes::route_removed (TimeAxisView *tv)
501 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed, tv)
503 TreeModel::Children rows = _model->children();
504 TreeModel::Children::iterator ri;
506 /* the core model has changed, there is no need to sync
510 _redisplay_does_not_sync_order_keys = true;
512 for (ri = rows.begin(); ri != rows.end(); ++ri) {
513 if ((*ri)[_columns.tv] == tv) {
519 _redisplay_does_not_sync_order_keys = false;
523 EditorRoutes::route_property_changed (const PropertyChange& what_changed, boost::weak_ptr<Route> r)
525 if (!what_changed.contains (ARDOUR::Properties::name)) {
529 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_name_changed, r)
531 boost::shared_ptr<Route> route = r.lock ();
537 TreeModel::Children rows = _model->children();
538 TreeModel::Children::iterator i;
540 for (i = rows.begin(); i != rows.end(); ++i) {
541 boost::shared_ptr<Route> t = (*i)[_columns.route];
543 (*i)[_columns.text] = route->name();
550 EditorRoutes::update_visibility ()
552 TreeModel::Children rows = _model->children();
553 TreeModel::Children::iterator i;
555 suspend_redisplay ();
557 for (i = rows.begin(); i != rows.end(); ++i) {
558 TimeAxisView *tv = (*i)[_columns.tv];
559 (*i)[_columns.visible] = tv->marked_for_display ();
560 cerr << "marked " << tv->name() << " for display = " << tv->marked_for_display() << endl;
567 EditorRoutes::hide_track_in_display (TimeAxisView& tv)
569 TreeModel::Children rows = _model->children();
570 TreeModel::Children::iterator i;
572 for (i = rows.begin(); i != rows.end(); ++i) {
573 if ((*i)[_columns.tv] == &tv) {
574 (*i)[_columns.visible] = false;
583 EditorRoutes::show_track_in_display (TimeAxisView& tv)
585 TreeModel::Children rows = _model->children();
586 TreeModel::Children::iterator i;
588 for (i = rows.begin(); i != rows.end(); ++i) {
589 if ((*i)[_columns.tv] == &tv) {
590 (*i)[_columns.visible] = true;
599 EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
604 /** If src != "editor", take editor order keys from each route and use them to rearrange the
605 * route list so that the visual arrangement of routes matches the order keys from the routes.
608 EditorRoutes::sync_order_keys (string const & src)
610 vector<int> neworder;
611 TreeModel::Children rows = _model->children();
612 TreeModel::Children::iterator ri;
614 if (src == N_ ("editor") || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
618 for (ri = rows.begin(); ri != rows.end(); ++ri) {
619 neworder.push_back (0);
622 bool changed = false;
625 for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
626 boost::shared_ptr<Route> route = (*ri)[_columns.route];
629 int new_key = route->order_key (N_ ("editor"));
631 neworder[new_key] = old_key;
633 if (new_key != old_key) {
639 _redisplay_does_not_reset_order_keys = true;
640 _model->reorder (neworder);
641 _redisplay_does_not_reset_order_keys = false;
647 EditorRoutes::hide_all_tracks (bool /*with_select*/)
649 TreeModel::Children rows = _model->children();
650 TreeModel::Children::iterator i;
652 suspend_redisplay ();
654 for (i = rows.begin(); i != rows.end(); ++i) {
656 TreeModel::Row row = (*i);
657 TimeAxisView *tv = row[_columns.tv];
663 row[_columns.visible] = false;
668 /* XXX this seems like a hack and half, but its not clear where to put this
672 //reset_scrolling_region ();
676 EditorRoutes::set_all_tracks_visibility (bool yn)
678 TreeModel::Children rows = _model->children();
679 TreeModel::Children::iterator i;
681 suspend_redisplay ();
683 for (i = rows.begin(); i != rows.end(); ++i) {
685 TreeModel::Row row = (*i);
686 TimeAxisView* tv = row[_columns.tv];
692 (*i)[_columns.visible] = yn;
699 EditorRoutes::set_all_audio_midi_visibility (int tracks, bool yn)
701 TreeModel::Children rows = _model->children();
702 TreeModel::Children::iterator i;
704 suspend_redisplay ();
706 for (i = rows.begin(); i != rows.end(); ++i) {
708 TreeModel::Row row = (*i);
709 TimeAxisView* tv = row[_columns.tv];
711 AudioTimeAxisView* atv;
712 MidiTimeAxisView* mtv;
718 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
721 (*i)[_columns.visible] = yn;
725 if (atv->is_audio_track()) {
726 (*i)[_columns.visible] = yn;
731 if (!atv->is_audio_track()) {
732 (*i)[_columns.visible] = yn;
737 else if ((mtv = dynamic_cast<MidiTimeAxisView*>(tv)) != 0) {
740 (*i)[_columns.visible] = yn;
744 if (mtv->is_midi_track()) {
745 (*i)[_columns.visible] = yn;
756 EditorRoutes::hide_all_routes ()
758 set_all_tracks_visibility (false);
762 EditorRoutes::show_all_routes ()
764 set_all_tracks_visibility (true);
768 EditorRoutes::show_all_audiotracks()
770 set_all_audio_midi_visibility (1, true);
773 EditorRoutes::hide_all_audiotracks ()
775 set_all_audio_midi_visibility (1, false);
779 EditorRoutes::show_all_audiobus ()
781 set_all_audio_midi_visibility (2, true);
784 EditorRoutes::hide_all_audiobus ()
786 set_all_audio_midi_visibility (2, false);
790 EditorRoutes::show_all_miditracks()
792 set_all_audio_midi_visibility (3, true);
795 EditorRoutes::hide_all_miditracks ()
797 set_all_audio_midi_visibility (3, false);
801 EditorRoutes::button_press (GdkEventButton* ev)
803 if (Keyboard::is_context_menu_event (ev)) {
808 //Scroll editor canvas to selected track
809 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
811 TreeModel::Path path;
816 _display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y);
818 // Get the model row.
819 Gtk::TreeModel::Row row = *_model->get_iter (path);
821 TimeAxisView *tv = row[_columns.tv];
823 int y_pos = tv->y_position();
825 //Clamp the y pos so that we do not extend beyond the canvas full height.
826 if (_editor->full_canvas_height - y_pos < _editor->_canvas_height){
827 y_pos = _editor->full_canvas_height - _editor->_canvas_height;
830 //Only scroll to if the track is visible
832 _editor->reset_y_origin (y_pos);
840 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const &, bool)
845 struct EditorOrderRouteSorter {
846 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
847 /* use of ">" forces the correct sort order */
848 return a->order_key (N_ ("editor")) < b->order_key (N_ ("editor"));
853 EditorRoutes::initial_display ()
855 suspend_redisplay ();
863 boost::shared_ptr<RouteList> routes = _session->get_routes();
864 RouteList r (*routes);
865 EditorOrderRouteSorter sorter;
868 _editor->handle_new_route (r);
870 /* don't show master bus in a new session */
872 if (ARDOUR_UI::instance()->session_is_new ()) {
874 TreeModel::Children rows = _model->children();
875 TreeModel::Children::iterator i;
877 _no_redisplay = true;
879 for (i = rows.begin(); i != rows.end(); ++i) {
881 TimeAxisView *tv = (*i)[_columns.tv];
882 RouteTimeAxisView *rtv;
884 if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
885 if (rtv->route()->is_master()) {
886 _display.get_selection()->unselect (i);
891 _no_redisplay = false;
899 EditorRoutes::track_list_reorder (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &, int* /*new_order*/)
901 _redisplay_does_not_sync_order_keys = true;
902 _session->set_remote_control_ids();
904 _redisplay_does_not_sync_order_keys = false;
908 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
910 const SelectionData& data,
911 guint info, guint time)
913 if (data.get_target() == "GTK_TREE_MODEL_ROW") {
914 _display.on_drag_data_received (context, x, y, data, info, time);
918 context->drag_finish (true, false, time);
922 EditorRoutes::move_selected_tracks (bool up)
924 if (_editor->selection->tracks.empty()) {
928 typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
929 std::list<ViewRoute> view_routes;
930 std::vector<int> neworder;
931 TreeModel::Children rows = _model->children();
932 TreeModel::Children::iterator ri;
934 for (ri = rows.begin(); ri != rows.end(); ++ri) {
935 TimeAxisView* tv = (*ri)[_columns.tv];
936 boost::shared_ptr<Route> route = (*ri)[_columns.route];
938 view_routes.push_back (ViewRoute (tv, route));
941 list<ViewRoute>::iterator trailing;
942 list<ViewRoute>::iterator leading;
946 trailing = view_routes.begin();
947 leading = view_routes.begin();
951 while (leading != view_routes.end()) {
952 if (_editor->selection->selected (leading->first)) {
953 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
954 leading = view_routes.erase (leading);
963 /* if we could use reverse_iterator in list::insert, this code
964 would be a beautiful reflection of the code above. but we can't
965 and so it looks like a bit of a mess.
968 trailing = view_routes.end();
969 leading = view_routes.end();
971 --leading; if (leading == view_routes.begin()) { return; }
977 if (_editor->selection->selected (leading->first)) {
978 list<ViewRoute>::iterator tmp;
980 /* need to insert *after* trailing, not *before* it,
981 which is what insert (iter, val) normally does.
987 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
989 /* can't use iter = cont.erase (iter); form here, because
990 we need iter to move backwards.
998 if (leading == view_routes.begin()) {
999 /* the one we've just inserted somewhere else
1000 was the first in the list. erase this copy,
1001 and then break, because we're done.
1006 view_routes.erase (leading);
1015 if (leading == view_routes.begin()) {
1024 for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
1025 neworder.push_back (leading->second->order_key (N_ ("editor")));
1028 _model->reorder (neworder);
1030 _session->sync_order_keys (N_ ("editor"));
1034 EditorRoutes::update_rec_display ()
1036 TreeModel::Children rows = _model->children();
1037 TreeModel::Children::iterator i;
1039 for (i = rows.begin(); i != rows.end(); ++i) {
1040 boost::shared_ptr<Route> route = (*i)[_columns.route];
1042 if (boost::dynamic_pointer_cast<Track>(route)) {
1043 (*i)[_columns.rec_enabled] = route->record_enabled ();
1044 (*i)[_columns.name_editable] = !route->record_enabled ();
1050 EditorRoutes::update_mute_display ()
1052 TreeModel::Children rows = _model->children();
1053 TreeModel::Children::iterator i;
1055 for (i = rows.begin(); i != rows.end(); ++i) {
1056 boost::shared_ptr<Route> route = (*i)[_columns.route];
1057 (*i)[_columns.mute_state] = RouteUI::mute_visual_state (_session, route) > 0 ? 1 : 0;
1062 EditorRoutes::update_solo_display (bool /* selfsoloed */)
1064 TreeModel::Children rows = _model->children();
1065 TreeModel::Children::iterator i;
1067 for (i = rows.begin(); i != rows.end(); ++i) {
1068 boost::shared_ptr<Route> route = (*i)[_columns.route];
1069 (*i)[_columns.solo_state] = RouteUI::solo_visual_state (route) > 0 ? 1 : 0;
1074 EditorRoutes::update_solo_isolate_display ()
1076 TreeModel::Children rows = _model->children();
1077 TreeModel::Children::iterator i;
1079 for (i = rows.begin(); i != rows.end(); ++i) {
1080 boost::shared_ptr<Route> route = (*i)[_columns.route];
1081 (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_visual_state (route) > 0 ? 1 : 0;
1086 EditorRoutes::update_solo_safe_display ()
1088 TreeModel::Children rows = _model->children();
1089 TreeModel::Children::iterator i;
1091 for (i = rows.begin(); i != rows.end(); ++i) {
1092 boost::shared_ptr<Route> route = (*i)[_columns.route];
1093 (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_visual_state (route) > 0 ? 1 : 0;
1098 EditorRoutes::views () const
1100 list<TimeAxisView*> v;
1101 for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
1102 v.push_back ((*i)[_columns.tv]);
1109 EditorRoutes::clear ()
1111 _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1113 _display.set_model (_model);
1117 EditorRoutes::name_edit (Glib::ustring const & path, Glib::ustring const & new_text)
1119 TreeIter iter = _model->get_iter (path);
1124 boost::shared_ptr<Route> route = (*iter)[_columns.route];
1126 if (route && route->name() != new_text) {
1127 route->set_name (new_text);
1132 EditorRoutes::solo_changed_so_update_mute ()
1134 update_mute_display ();
1138 EditorRoutes::show_tracks_with_regions_at_playhead ()
1140 boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
1142 set<TimeAxisView*> show;
1143 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
1144 TimeAxisView* tav = _editor->axis_view_from_route (*i);
1150 suspend_redisplay ();
1152 TreeModel::Children rows = _model->children ();
1153 for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
1154 TimeAxisView* tv = (*i)[_columns.tv];
1155 (*i)[_columns.visible] = (show.find (tv) != show.end());
1158 resume_redisplay ();