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"
52 using namespace ARDOUR;
55 using namespace Gtkmm2ext;
57 using Gtkmm2ext::Keyboard;
59 EditorRoutes::EditorRoutes (Editor* e)
60 : EditorComponent (e),
61 _ignore_reorder (false),
62 _no_redisplay (false),
63 _redisplay_does_not_sync_order_keys (false),
64 _redisplay_does_not_reset_order_keys (false),
67 _scroller.add (_display);
68 _scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
70 _model = ListStore::create (_columns);
71 _display.set_model (_model);
73 // Record enable toggle
74 CellRendererPixbufMulti* rec_col_renderer = manage (new CellRendererPixbufMulti());
76 rec_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
77 rec_col_renderer->set_pixbuf (1, ::get_icon("rec-in-progress"));
78 rec_col_renderer->set_pixbuf (2, ::get_icon("rec-enabled"));
79 rec_col_renderer->set_pixbuf (3, ::get_icon("step-editing"));
80 rec_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_rec_enable_changed));
82 TreeViewColumn* rec_state_column = manage (new TreeViewColumn("R", *rec_col_renderer));
84 rec_state_column->add_attribute(rec_col_renderer->property_state(), _columns.rec_state);
85 rec_state_column->add_attribute(rec_col_renderer->property_visible(), _columns.is_track);
86 rec_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
87 rec_state_column->set_alignment(ALIGN_CENTER);
88 rec_state_column->set_expand(false);
89 rec_state_column->set_fixed_width(15);
92 CellRendererPixbufMulti* mute_col_renderer = manage (new CellRendererPixbufMulti());
94 mute_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
95 mute_col_renderer->set_pixbuf (1, ::get_icon("mute-enabled"));
96 mute_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_mute_enable_toggled));
98 TreeViewColumn* mute_state_column = manage (new TreeViewColumn("M", *mute_col_renderer));
100 mute_state_column->add_attribute(mute_col_renderer->property_state(), _columns.mute_state);
101 mute_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
102 mute_state_column->set_alignment(ALIGN_CENTER);
103 mute_state_column->set_expand(false);
104 mute_state_column->set_fixed_width(15);
106 // Solo enable toggle
107 CellRendererPixbufMulti* solo_col_renderer = manage (new CellRendererPixbufMulti());
109 solo_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
110 solo_col_renderer->set_pixbuf (1, ::get_icon("solo-enabled"));
111 solo_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_enable_toggled));
113 TreeViewColumn* solo_state_column = manage (new TreeViewColumn("S", *solo_col_renderer));
115 solo_state_column->add_attribute(solo_col_renderer->property_state(), _columns.solo_state);
116 solo_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
117 solo_state_column->set_alignment(ALIGN_CENTER);
118 solo_state_column->set_expand(false);
119 solo_state_column->set_fixed_width(15);
121 // Solo isolate toggle
122 CellRendererPixbufMulti* solo_iso_renderer = manage (new CellRendererPixbufMulti());
124 solo_iso_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
125 solo_iso_renderer->set_pixbuf (1, ::get_icon("solo-isolated"));
126 solo_iso_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_isolate_toggled));
128 TreeViewColumn* solo_isolate_state_column = manage (new TreeViewColumn("SI", *solo_iso_renderer));
130 solo_isolate_state_column->add_attribute(solo_iso_renderer->property_state(), _columns.solo_isolate_state);
131 solo_isolate_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
132 solo_isolate_state_column->set_alignment(ALIGN_CENTER);
133 solo_isolate_state_column->set_expand(false);
134 solo_isolate_state_column->set_fixed_width(15);
137 CellRendererPixbufMulti* solo_safe_renderer = manage (new CellRendererPixbufMulti ());
139 solo_safe_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
140 solo_safe_renderer->set_pixbuf (1, ::get_icon("solo-enabled"));
141 solo_safe_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_safe_toggled));
143 TreeViewColumn* solo_safe_state_column = manage (new TreeViewColumn(_("SS"), *solo_safe_renderer));
144 solo_safe_state_column->add_attribute(solo_safe_renderer->property_state(), _columns.solo_safe_state);
145 solo_safe_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
146 solo_safe_state_column->set_alignment(ALIGN_CENTER);
147 solo_safe_state_column->set_expand(false);
148 solo_safe_state_column->set_fixed_width(22);
150 _display.append_column (*rec_state_column);
151 _display.append_column (*mute_state_column);
152 _display.append_column (*solo_state_column);
153 _display.append_column (*solo_isolate_state_column);
154 _display.append_column (*solo_safe_state_column);
156 _display.append_column (_("Name"), _columns.text);
157 _display.append_column (_("V"), _columns.visible);
159 _display.set_headers_visible (true);
160 _display.set_name ("TrackListDisplay");
161 _display.get_selection()->set_mode (SELECTION_SINGLE);
162 _display.set_reorderable (true);
163 _display.set_rules_hint (true);
164 _display.set_size_request (100, -1);
165 _display.add_object_drag (_columns.route.index(), "routes");
167 CellRendererText* name_cell = dynamic_cast<CellRendererText*> (_display.get_column_cell_renderer (5));
171 TreeViewColumn* name_column = _display.get_column (5);
173 assert (name_column);
175 name_column->add_attribute (name_cell->property_editable(), _columns.name_editable);
176 name_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
177 name_column->set_expand(true);
178 name_column->set_min_width(50);
180 name_cell->property_editable() = true;
181 name_cell->signal_edited().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit));
183 // Set the visible column cell renderer to radio toggle
184 CellRendererToggle* visible_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (6));
186 visible_cell->property_activatable() = true;
187 visible_cell->property_radio() = false;
188 visible_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::visible_changed));
190 TreeViewColumn* visible_col = dynamic_cast<TreeViewColumn*> (_display.get_column (6));
191 visible_col->set_expand(false);
192 visible_col->set_sizing(TREE_VIEW_COLUMN_FIXED);
193 visible_col->set_fixed_width(30);
194 visible_col->set_alignment(ALIGN_CENTER);
196 _model->signal_row_deleted().connect (sigc::mem_fun (*this, &EditorRoutes::route_deleted));
197 _model->signal_rows_reordered().connect (sigc::mem_fun (*this, &EditorRoutes::reordered));
199 _display.signal_button_press_event().connect (sigc::mem_fun (*this, &EditorRoutes::button_press), false);
201 Route::SyncOrderKeys.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::sync_order_keys, this, _1), gui_context());
205 EditorRoutes::set_session (Session* s)
207 SessionHandlePtr::set_session (s);
212 _session->SoloChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::solo_changed_so_update_mute, this), gui_context());
213 _session->RecordStateChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
218 EditorRoutes::on_tv_rec_enable_changed (Glib::ustring const & path_string)
220 // Get the model row that has been toggled.
221 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
223 TimeAxisView *tv = row[_columns.tv];
224 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
226 if (atv != 0 && atv->is_audio_track()){
227 boost::shared_ptr<RouteList> rl (new RouteList);
228 rl->push_back (atv->route());
229 _session->set_record_enabled (rl, !atv->track()->record_enabled(), Session::rt_cleanup);
234 EditorRoutes::on_tv_mute_enable_toggled (Glib::ustring const & path_string)
236 // Get the model row that has been toggled.
237 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
239 TimeAxisView *tv = row[_columns.tv];
240 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
243 boost::shared_ptr<RouteList> rl (new RouteList);
244 rl->push_back (atv->route());
245 _session->set_mute (rl, !atv->route()->muted(), Session::rt_cleanup);
250 EditorRoutes::on_tv_solo_enable_toggled (Glib::ustring const & path_string)
252 // Get the model row that has been toggled.
253 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
255 TimeAxisView *tv = row[_columns.tv];
256 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
259 boost::shared_ptr<RouteList> rl (new RouteList);
260 rl->push_back (atv->route());
261 _session->set_solo (rl, !atv->route()->soloed(), Session::rt_cleanup);
266 EditorRoutes::on_tv_solo_isolate_toggled (Glib::ustring const & path_string)
268 // Get the model row that has been toggled.
269 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
271 TimeAxisView *tv = row[_columns.tv];
272 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
275 atv->route()->set_solo_isolated (!atv->route()->solo_isolated(), this);
280 EditorRoutes::on_tv_solo_safe_toggled (Glib::ustring const & path_string)
282 // Get the model row that has been toggled.
283 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
285 TimeAxisView *tv = row[_columns.tv];
286 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
289 atv->route()->set_solo_safe (!atv->route()->solo_safe(), this);
294 EditorRoutes::build_menu ()
296 using namespace Menu_Helpers;
301 MenuList& items = _menu->items();
302 _menu->set_name ("ArdourContextMenu");
304 items.push_back (MenuElem (_("Show All"), sigc::mem_fun (*this, &EditorRoutes::show_all_routes)));
305 items.push_back (MenuElem (_("Hide All"), sigc::mem_fun (*this, &EditorRoutes::hide_all_routes)));
306 items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiotracks)));
307 items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiotracks)));
308 items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiobus)));
309 items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiobus)));
310 items.push_back (MenuElem (_("Show All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_miditracks)));
311 items.push_back (MenuElem (_("Hide All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_miditracks)));
312 items.push_back (MenuElem (_("Show Tracks With Regions Under Playhead"), sigc::mem_fun (*this, &EditorRoutes::show_tracks_with_regions_at_playhead)));
316 EditorRoutes::show_menu ()
322 _menu->popup (1, gtk_get_current_event_time());
326 EditorRoutes::redisplay ()
328 if (_no_redisplay || !_session) {
332 TreeModel::Children rows = _model->children();
333 TreeModel::Children::iterator i;
337 for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
338 TimeAxisView *tv = (*i)[_columns.tv];
339 boost::shared_ptr<Route> route = (*i)[_columns.route];
342 // just a "title" row
346 if (!_redisplay_does_not_reset_order_keys) {
347 /* this reorder is caused by user action, so reassign sort order keys
350 route->set_order_key (N_ ("editor"), n);
353 bool visible = (*i)[_columns.visible];
355 /* show or hide the TimeAxisView */
357 tv->set_marked_for_display (true);
358 position += tv->show_at (position, n, &_editor->edit_controls_vbox);
359 tv->clip_to_viewport ();
361 tv->set_marked_for_display (false);
368 /* whenever we go idle, update the track view list to reflect the new order.
369 we can't do this here, because we could mess up something that is traversing
370 the track order and has caused a redisplay of the list.
372 Glib::signal_idle().connect (sigc::mem_fun (*_editor, &Editor::sync_track_view_list_and_routes));
374 _editor->full_canvas_height = position + _editor->canvas_timebars_vsize;
375 _editor->vertical_adjustment.set_upper (_editor->full_canvas_height);
377 if ((_editor->vertical_adjustment.get_value() + _editor->_canvas_height) > _editor->vertical_adjustment.get_upper()) {
379 We're increasing the size of the canvas while the bottom is visible.
380 We scroll down to keep in step with the controls layout.
382 _editor->vertical_adjustment.set_value (_editor->full_canvas_height - _editor->_canvas_height);
385 if (!_redisplay_does_not_reset_order_keys && !_redisplay_does_not_sync_order_keys) {
386 _session->sync_order_keys (N_ ("editor"));
391 EditorRoutes::route_deleted (Gtk::TreeModel::Path const &)
393 if (!_session || _session->deletion_in_progress()) {
397 /* this could require an order reset & sync */
398 _session->set_remote_control_ids();
399 _ignore_reorder = true;
401 _ignore_reorder = false;
405 EditorRoutes::visible_changed (Glib::ustring const & path)
407 if (_session && _session->deletion_in_progress()) {
413 if ((iter = _model->get_iter (path))) {
414 TimeAxisView* tv = (*iter)[_columns.tv];
416 bool visible = (*iter)[_columns.visible];
417 (*iter)[_columns.visible] = !visible;
421 _redisplay_does_not_reset_order_keys = true;
422 _session->set_remote_control_ids();
424 _redisplay_does_not_reset_order_keys = false;
428 EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
432 _redisplay_does_not_sync_order_keys = true;
433 suspend_redisplay ();
435 for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) {
437 row = *(_model->append ());
439 row[_columns.text] = (*x)->route()->name();
440 row[_columns.visible] = (*x)->marked_for_display();
441 row[_columns.tv] = *x;
442 row[_columns.route] = (*x)->route ();
443 row[_columns.is_track] = (boost::dynamic_pointer_cast<Track> ((*x)->route()) != 0);
444 row[_columns.mute_state] = (*x)->route()->muted();
445 row[_columns.solo_state] = (*x)->route()->soloed();
446 row[_columns.solo_isolate_state] = (*x)->route()->solo_isolated();
447 row[_columns.solo_safe_state] = (*x)->route()->solo_safe();
448 row[_columns.name_editable] = true;
450 _ignore_reorder = true;
452 /* added a new fresh one at the end */
453 if ((*x)->route()->order_key (N_ ("editor")) == -1) {
454 (*x)->route()->set_order_key (N_ ("editor"), _model->children().size()-1);
457 _ignore_reorder = false;
459 boost::weak_ptr<Route> wr ((*x)->route());
461 (*x)->route()->gui_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
462 (*x)->route()->PropertyChanged.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::route_property_changed, this, _1, wr), gui_context());
464 if ((*x)->is_track()) {
465 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
466 t->RecordEnableChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
469 if ((*x)->is_midi_track()) {
470 boost::shared_ptr<MidiTrack> t = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
471 t->StepEditStatusChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
474 (*x)->route()->mute_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
475 (*x)->route()->solo_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
476 (*x)->route()->solo_isolated_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_isolate_display, this), gui_context());
477 (*x)->route()->solo_safe_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_safe_display, this), gui_context());
480 update_rec_display ();
481 update_mute_display ();
482 update_solo_display (true);
483 update_solo_isolate_display ();
484 update_solo_safe_display ();
486 _redisplay_does_not_sync_order_keys = false;
490 EditorRoutes::handle_gui_changes (string const & what, void*)
492 ENSURE_GUI_THREAD (*this, &EditorRoutes::handle_gui_changes, what, src)
494 if (what == "track_height") {
495 /* Optional :make tracks change height while it happens, instead
498 //update_canvas_now ();
502 if (what == "visible_tracks") {
508 EditorRoutes::route_removed (TimeAxisView *tv)
510 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed, tv)
512 TreeModel::Children rows = _model->children();
513 TreeModel::Children::iterator ri;
515 /* the core model has changed, there is no need to sync
519 _redisplay_does_not_sync_order_keys = true;
521 for (ri = rows.begin(); ri != rows.end(); ++ri) {
522 if ((*ri)[_columns.tv] == tv) {
528 _redisplay_does_not_sync_order_keys = false;
532 EditorRoutes::route_property_changed (const PropertyChange& what_changed, boost::weak_ptr<Route> r)
534 if (!what_changed.contains (ARDOUR::Properties::name)) {
538 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_name_changed, r)
540 boost::shared_ptr<Route> route = r.lock ();
546 TreeModel::Children rows = _model->children();
547 TreeModel::Children::iterator i;
549 for (i = rows.begin(); i != rows.end(); ++i) {
550 boost::shared_ptr<Route> t = (*i)[_columns.route];
552 (*i)[_columns.text] = route->name();
559 EditorRoutes::update_visibility ()
561 TreeModel::Children rows = _model->children();
562 TreeModel::Children::iterator i;
564 suspend_redisplay ();
566 for (i = rows.begin(); i != rows.end(); ++i) {
567 TimeAxisView *tv = (*i)[_columns.tv];
568 (*i)[_columns.visible] = tv->marked_for_display ();
569 cerr << "marked " << tv->name() << " for display = " << tv->marked_for_display() << endl;
576 EditorRoutes::hide_track_in_display (TimeAxisView& tv)
578 TreeModel::Children rows = _model->children();
579 TreeModel::Children::iterator i;
581 for (i = rows.begin(); i != rows.end(); ++i) {
582 if ((*i)[_columns.tv] == &tv) {
583 (*i)[_columns.visible] = false;
592 EditorRoutes::show_track_in_display (TimeAxisView& tv)
594 TreeModel::Children rows = _model->children();
595 TreeModel::Children::iterator i;
597 for (i = rows.begin(); i != rows.end(); ++i) {
598 if ((*i)[_columns.tv] == &tv) {
599 (*i)[_columns.visible] = true;
608 EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
613 /** If src != "editor", take editor order keys from each route and use them to rearrange the
614 * route list so that the visual arrangement of routes matches the order keys from the routes.
617 EditorRoutes::sync_order_keys (string const & src)
619 vector<int> neworder;
620 TreeModel::Children rows = _model->children();
621 TreeModel::Children::iterator ri;
623 if (src == N_ ("editor") || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
627 for (ri = rows.begin(); ri != rows.end(); ++ri) {
628 neworder.push_back (0);
631 bool changed = false;
634 for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
635 boost::shared_ptr<Route> route = (*ri)[_columns.route];
638 int new_key = route->order_key (N_ ("editor"));
640 neworder[new_key] = old_key;
642 if (new_key != old_key) {
648 _redisplay_does_not_reset_order_keys = true;
649 _model->reorder (neworder);
650 _redisplay_does_not_reset_order_keys = false;
656 EditorRoutes::hide_all_tracks (bool /*with_select*/)
658 TreeModel::Children rows = _model->children();
659 TreeModel::Children::iterator i;
661 suspend_redisplay ();
663 for (i = rows.begin(); i != rows.end(); ++i) {
665 TreeModel::Row row = (*i);
666 TimeAxisView *tv = row[_columns.tv];
672 row[_columns.visible] = false;
677 /* XXX this seems like a hack and half, but its not clear where to put this
681 //reset_scrolling_region ();
685 EditorRoutes::set_all_tracks_visibility (bool yn)
687 TreeModel::Children rows = _model->children();
688 TreeModel::Children::iterator i;
690 suspend_redisplay ();
692 for (i = rows.begin(); i != rows.end(); ++i) {
694 TreeModel::Row row = (*i);
695 TimeAxisView* tv = row[_columns.tv];
701 (*i)[_columns.visible] = yn;
708 EditorRoutes::set_all_audio_midi_visibility (int tracks, bool yn)
710 TreeModel::Children rows = _model->children();
711 TreeModel::Children::iterator i;
713 suspend_redisplay ();
715 for (i = rows.begin(); i != rows.end(); ++i) {
717 TreeModel::Row row = (*i);
718 TimeAxisView* tv = row[_columns.tv];
720 AudioTimeAxisView* atv;
721 MidiTimeAxisView* mtv;
727 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
730 (*i)[_columns.visible] = yn;
734 if (atv->is_audio_track()) {
735 (*i)[_columns.visible] = yn;
740 if (!atv->is_audio_track()) {
741 (*i)[_columns.visible] = yn;
746 else if ((mtv = dynamic_cast<MidiTimeAxisView*>(tv)) != 0) {
749 (*i)[_columns.visible] = yn;
753 if (mtv->is_midi_track()) {
754 (*i)[_columns.visible] = yn;
765 EditorRoutes::hide_all_routes ()
767 set_all_tracks_visibility (false);
771 EditorRoutes::show_all_routes ()
773 set_all_tracks_visibility (true);
777 EditorRoutes::show_all_audiotracks()
779 set_all_audio_midi_visibility (1, true);
782 EditorRoutes::hide_all_audiotracks ()
784 set_all_audio_midi_visibility (1, false);
788 EditorRoutes::show_all_audiobus ()
790 set_all_audio_midi_visibility (2, true);
793 EditorRoutes::hide_all_audiobus ()
795 set_all_audio_midi_visibility (2, false);
799 EditorRoutes::show_all_miditracks()
801 set_all_audio_midi_visibility (3, true);
804 EditorRoutes::hide_all_miditracks ()
806 set_all_audio_midi_visibility (3, false);
810 EditorRoutes::button_press (GdkEventButton* ev)
812 if (Keyboard::is_context_menu_event (ev)) {
817 //Scroll editor canvas to selected track
818 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
820 TreeModel::Path path;
825 _display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y);
827 // Get the model row.
828 Gtk::TreeModel::Row row = *_model->get_iter (path);
830 TimeAxisView *tv = row[_columns.tv];
832 int y_pos = tv->y_position();
834 //Clamp the y pos so that we do not extend beyond the canvas full height.
835 if (_editor->full_canvas_height - y_pos < _editor->_canvas_height){
836 y_pos = _editor->full_canvas_height - _editor->_canvas_height;
839 //Only scroll to if the track is visible
841 _editor->reset_y_origin (y_pos);
849 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const &, bool)
854 struct EditorOrderRouteSorter {
855 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
856 /* use of ">" forces the correct sort order */
857 return a->order_key (N_ ("editor")) < b->order_key (N_ ("editor"));
862 EditorRoutes::initial_display ()
864 suspend_redisplay ();
872 boost::shared_ptr<RouteList> routes = _session->get_routes();
873 RouteList r (*routes);
874 EditorOrderRouteSorter sorter;
877 _editor->handle_new_route (r);
879 /* don't show master bus in a new session */
881 if (ARDOUR_UI::instance()->session_is_new ()) {
883 TreeModel::Children rows = _model->children();
884 TreeModel::Children::iterator i;
886 _no_redisplay = true;
888 for (i = rows.begin(); i != rows.end(); ++i) {
890 TimeAxisView *tv = (*i)[_columns.tv];
891 RouteTimeAxisView *rtv;
893 if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
894 if (rtv->route()->is_master()) {
895 _display.get_selection()->unselect (i);
900 _no_redisplay = false;
908 EditorRoutes::track_list_reorder (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &, int* /*new_order*/)
910 _redisplay_does_not_sync_order_keys = true;
911 _session->set_remote_control_ids();
913 _redisplay_does_not_sync_order_keys = false;
917 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
919 const SelectionData& data,
920 guint info, guint time)
922 if (data.get_target() == "GTK_TREE_MODEL_ROW") {
923 _display.on_drag_data_received (context, x, y, data, info, time);
927 context->drag_finish (true, false, time);
931 EditorRoutes::move_selected_tracks (bool up)
933 if (_editor->selection->tracks.empty()) {
937 typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
938 std::list<ViewRoute> view_routes;
939 std::vector<int> neworder;
940 TreeModel::Children rows = _model->children();
941 TreeModel::Children::iterator ri;
943 for (ri = rows.begin(); ri != rows.end(); ++ri) {
944 TimeAxisView* tv = (*ri)[_columns.tv];
945 boost::shared_ptr<Route> route = (*ri)[_columns.route];
947 view_routes.push_back (ViewRoute (tv, route));
950 list<ViewRoute>::iterator trailing;
951 list<ViewRoute>::iterator leading;
955 trailing = view_routes.begin();
956 leading = view_routes.begin();
960 while (leading != view_routes.end()) {
961 if (_editor->selection->selected (leading->first)) {
962 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
963 leading = view_routes.erase (leading);
972 /* if we could use reverse_iterator in list::insert, this code
973 would be a beautiful reflection of the code above. but we can't
974 and so it looks like a bit of a mess.
977 trailing = view_routes.end();
978 leading = view_routes.end();
980 --leading; if (leading == view_routes.begin()) { return; }
986 if (_editor->selection->selected (leading->first)) {
987 list<ViewRoute>::iterator tmp;
989 /* need to insert *after* trailing, not *before* it,
990 which is what insert (iter, val) normally does.
996 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
998 /* can't use iter = cont.erase (iter); form here, because
999 we need iter to move backwards.
1007 if (leading == view_routes.begin()) {
1008 /* the one we've just inserted somewhere else
1009 was the first in the list. erase this copy,
1010 and then break, because we're done.
1015 view_routes.erase (leading);
1024 if (leading == view_routes.begin()) {
1033 for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
1034 neworder.push_back (leading->second->order_key (N_ ("editor")));
1037 _model->reorder (neworder);
1039 _session->sync_order_keys (N_ ("editor"));
1043 EditorRoutes::update_rec_display ()
1045 TreeModel::Children rows = _model->children();
1046 TreeModel::Children::iterator i;
1048 for (i = rows.begin(); i != rows.end(); ++i) {
1049 boost::shared_ptr<Route> route = (*i)[_columns.route];
1051 if (boost::dynamic_pointer_cast<Track> (route)) {
1052 boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
1054 if (route->record_enabled()) {
1055 if (_session->record_status() == Session::Recording) {
1056 (*i)[_columns.rec_state] = 1;
1058 (*i)[_columns.rec_state] = 2;
1060 } else if (mt && mt->step_editing()) {
1061 (*i)[_columns.rec_state] = 3;
1063 (*i)[_columns.rec_state] = 0;
1066 (*i)[_columns.name_editable] = !route->record_enabled ();
1072 EditorRoutes::update_mute_display ()
1074 TreeModel::Children rows = _model->children();
1075 TreeModel::Children::iterator i;
1077 for (i = rows.begin(); i != rows.end(); ++i) {
1078 boost::shared_ptr<Route> route = (*i)[_columns.route];
1079 (*i)[_columns.mute_state] = RouteUI::mute_visual_state (_session, route) > 0 ? 1 : 0;
1084 EditorRoutes::update_solo_display (bool /* selfsoloed */)
1086 TreeModel::Children rows = _model->children();
1087 TreeModel::Children::iterator i;
1089 for (i = rows.begin(); i != rows.end(); ++i) {
1090 boost::shared_ptr<Route> route = (*i)[_columns.route];
1091 (*i)[_columns.solo_state] = RouteUI::solo_visual_state (route) > 0 ? 1 : 0;
1096 EditorRoutes::update_solo_isolate_display ()
1098 TreeModel::Children rows = _model->children();
1099 TreeModel::Children::iterator i;
1101 for (i = rows.begin(); i != rows.end(); ++i) {
1102 boost::shared_ptr<Route> route = (*i)[_columns.route];
1103 (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_visual_state (route) > 0 ? 1 : 0;
1108 EditorRoutes::update_solo_safe_display ()
1110 TreeModel::Children rows = _model->children();
1111 TreeModel::Children::iterator i;
1113 for (i = rows.begin(); i != rows.end(); ++i) {
1114 boost::shared_ptr<Route> route = (*i)[_columns.route];
1115 (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_visual_state (route) > 0 ? 1 : 0;
1120 EditorRoutes::views () const
1122 list<TimeAxisView*> v;
1123 for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
1124 v.push_back ((*i)[_columns.tv]);
1131 EditorRoutes::clear ()
1133 _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1135 _display.set_model (_model);
1139 EditorRoutes::name_edit (Glib::ustring const & path, Glib::ustring const & new_text)
1141 TreeIter iter = _model->get_iter (path);
1146 boost::shared_ptr<Route> route = (*iter)[_columns.route];
1148 if (route && route->name() != new_text) {
1149 route->set_name (new_text);
1154 EditorRoutes::solo_changed_so_update_mute ()
1156 update_mute_display ();
1160 EditorRoutes::show_tracks_with_regions_at_playhead ()
1162 boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
1164 set<TimeAxisView*> show;
1165 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
1166 TimeAxisView* tav = _editor->axis_view_from_route (*i);
1172 suspend_redisplay ();
1174 TreeModel::Children rows = _model->children ();
1175 for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
1176 TimeAxisView* tv = (*i)[_columns.tv];
1177 (*i)[_columns.visible] = (show.find (tv) != show.end());
1180 resume_redisplay ();