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("muted-by-others"));
96 mute_col_renderer->set_pixbuf (2, ::get_icon("mute-enabled"));
97 mute_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_mute_enable_toggled));
99 TreeViewColumn* mute_state_column = manage (new TreeViewColumn("M", *mute_col_renderer));
101 mute_state_column->add_attribute(mute_col_renderer->property_state(), _columns.mute_state);
102 mute_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
103 mute_state_column->set_alignment(ALIGN_CENTER);
104 mute_state_column->set_expand(false);
105 mute_state_column->set_fixed_width(15);
107 // Solo enable toggle
108 CellRendererPixbufMulti* solo_col_renderer = manage (new CellRendererPixbufMulti());
110 solo_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
111 solo_col_renderer->set_pixbuf (1, ::get_icon("solo-enabled"));
112 solo_col_renderer->set_pixbuf (3, ::get_icon("soloed-by-others"));
113 solo_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_enable_toggled));
115 TreeViewColumn* solo_state_column = manage (new TreeViewColumn("S", *solo_col_renderer));
117 solo_state_column->add_attribute(solo_col_renderer->property_state(), _columns.solo_state);
118 solo_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
119 solo_state_column->set_alignment(ALIGN_CENTER);
120 solo_state_column->set_expand(false);
121 solo_state_column->set_fixed_width(15);
123 // Solo isolate toggle
124 CellRendererPixbufMulti* solo_iso_renderer = manage (new CellRendererPixbufMulti());
126 solo_iso_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
127 solo_iso_renderer->set_pixbuf (1, ::get_icon("solo-isolated"));
128 solo_iso_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_isolate_toggled));
130 TreeViewColumn* solo_isolate_state_column = manage (new TreeViewColumn("SI", *solo_iso_renderer));
132 solo_isolate_state_column->add_attribute(solo_iso_renderer->property_state(), _columns.solo_isolate_state);
133 solo_isolate_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
134 solo_isolate_state_column->set_alignment(ALIGN_CENTER);
135 solo_isolate_state_column->set_expand(false);
136 solo_isolate_state_column->set_fixed_width(15);
139 CellRendererPixbufMulti* solo_safe_renderer = manage (new CellRendererPixbufMulti ());
141 solo_safe_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
142 solo_safe_renderer->set_pixbuf (1, ::get_icon("solo-enabled"));
143 solo_safe_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_safe_toggled));
145 TreeViewColumn* solo_safe_state_column = manage (new TreeViewColumn(_("SS"), *solo_safe_renderer));
146 solo_safe_state_column->add_attribute(solo_safe_renderer->property_state(), _columns.solo_safe_state);
147 solo_safe_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
148 solo_safe_state_column->set_alignment(ALIGN_CENTER);
149 solo_safe_state_column->set_expand(false);
150 solo_safe_state_column->set_fixed_width(22);
152 _display.append_column (*rec_state_column);
153 _display.append_column (*mute_state_column);
154 _display.append_column (*solo_state_column);
155 _display.append_column (*solo_isolate_state_column);
156 _display.append_column (*solo_safe_state_column);
158 _display.append_column (_("Name"), _columns.text);
159 _display.append_column (_("V"), _columns.visible);
161 _display.set_headers_visible (true);
162 _display.set_name ("TrackListDisplay");
163 _display.get_selection()->set_mode (SELECTION_SINGLE);
164 _display.set_reorderable (true);
165 _display.set_rules_hint (true);
166 _display.set_size_request (100, -1);
167 _display.add_object_drag (_columns.route.index(), "routes");
169 CellRendererText* name_cell = dynamic_cast<CellRendererText*> (_display.get_column_cell_renderer (5));
173 TreeViewColumn* name_column = _display.get_column (5);
175 assert (name_column);
177 name_column->add_attribute (name_cell->property_editable(), _columns.name_editable);
178 name_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
179 name_column->set_expand(true);
180 name_column->set_min_width(50);
182 name_cell->property_editable() = true;
183 name_cell->signal_edited().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit));
185 // Set the visible column cell renderer to radio toggle
186 CellRendererToggle* visible_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (6));
188 visible_cell->property_activatable() = true;
189 visible_cell->property_radio() = false;
190 visible_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::visible_changed));
192 TreeViewColumn* visible_col = dynamic_cast<TreeViewColumn*> (_display.get_column (6));
193 visible_col->set_expand(false);
194 visible_col->set_sizing(TREE_VIEW_COLUMN_FIXED);
195 visible_col->set_fixed_width(30);
196 visible_col->set_alignment(ALIGN_CENTER);
198 _model->signal_row_deleted().connect (sigc::mem_fun (*this, &EditorRoutes::route_deleted));
199 _model->signal_rows_reordered().connect (sigc::mem_fun (*this, &EditorRoutes::reordered));
201 _display.signal_button_press_event().connect (sigc::mem_fun (*this, &EditorRoutes::button_press), false);
203 Route::SyncOrderKeys.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::sync_order_keys, this, _1), gui_context());
207 EditorRoutes::set_session (Session* s)
209 SessionHandlePtr::set_session (s);
214 _session->SoloChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::solo_changed_so_update_mute, this), gui_context());
215 _session->RecordStateChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
220 EditorRoutes::on_tv_rec_enable_changed (Glib::ustring const & path_string)
222 // Get the model row that has been toggled.
223 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
225 TimeAxisView *tv = row[_columns.tv];
226 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
228 if (atv != 0 && atv->is_audio_track()){
229 boost::shared_ptr<RouteList> rl (new RouteList);
230 rl->push_back (atv->route());
231 _session->set_record_enabled (rl, !atv->track()->record_enabled(), Session::rt_cleanup);
236 EditorRoutes::on_tv_mute_enable_toggled (Glib::ustring const & path_string)
238 // Get the model row that has been toggled.
239 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
241 TimeAxisView *tv = row[_columns.tv];
242 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
245 boost::shared_ptr<RouteList> rl (new RouteList);
246 rl->push_back (atv->route());
247 _session->set_mute (rl, !atv->route()->muted(), Session::rt_cleanup);
252 EditorRoutes::on_tv_solo_enable_toggled (Glib::ustring const & path_string)
254 // Get the model row that has been toggled.
255 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
257 TimeAxisView *tv = row[_columns.tv];
258 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
261 boost::shared_ptr<RouteList> rl (new RouteList);
262 rl->push_back (atv->route());
263 _session->set_solo (rl, !atv->route()->soloed(), Session::rt_cleanup);
268 EditorRoutes::on_tv_solo_isolate_toggled (Glib::ustring const & path_string)
270 // Get the model row that has been toggled.
271 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
273 TimeAxisView *tv = row[_columns.tv];
274 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
277 atv->route()->set_solo_isolated (!atv->route()->solo_isolated(), this);
282 EditorRoutes::on_tv_solo_safe_toggled (Glib::ustring const & path_string)
284 // Get the model row that has been toggled.
285 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
287 TimeAxisView *tv = row[_columns.tv];
288 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
291 atv->route()->set_solo_safe (!atv->route()->solo_safe(), this);
296 EditorRoutes::build_menu ()
298 using namespace Menu_Helpers;
303 MenuList& items = _menu->items();
304 _menu->set_name ("ArdourContextMenu");
306 items.push_back (MenuElem (_("Show All"), sigc::mem_fun (*this, &EditorRoutes::show_all_routes)));
307 items.push_back (MenuElem (_("Hide All"), sigc::mem_fun (*this, &EditorRoutes::hide_all_routes)));
308 items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiotracks)));
309 items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiotracks)));
310 items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiobus)));
311 items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiobus)));
312 items.push_back (MenuElem (_("Show All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_miditracks)));
313 items.push_back (MenuElem (_("Hide All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_miditracks)));
314 items.push_back (MenuElem (_("Show Tracks With Regions Under Playhead"), sigc::mem_fun (*this, &EditorRoutes::show_tracks_with_regions_at_playhead)));
318 EditorRoutes::show_menu ()
324 _menu->popup (1, gtk_get_current_event_time());
328 EditorRoutes::redisplay ()
330 if (_no_redisplay || !_session) {
334 TreeModel::Children rows = _model->children();
335 TreeModel::Children::iterator i;
339 for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
340 TimeAxisView *tv = (*i)[_columns.tv];
341 boost::shared_ptr<Route> route = (*i)[_columns.route];
344 // just a "title" row
348 if (!_redisplay_does_not_reset_order_keys) {
349 /* this reorder is caused by user action, so reassign sort order keys
352 route->set_order_key (N_ ("editor"), n);
355 bool visible = (*i)[_columns.visible];
357 /* show or hide the TimeAxisView */
359 tv->set_marked_for_display (true);
360 position += tv->show_at (position, n, &_editor->edit_controls_vbox);
361 tv->clip_to_viewport ();
363 tv->set_marked_for_display (false);
370 /* whenever we go idle, update the track view list to reflect the new order.
371 we can't do this here, because we could mess up something that is traversing
372 the track order and has caused a redisplay of the list.
374 Glib::signal_idle().connect (sigc::mem_fun (*_editor, &Editor::sync_track_view_list_and_routes));
376 _editor->full_canvas_height = position + _editor->canvas_timebars_vsize;
377 _editor->vertical_adjustment.set_upper (_editor->full_canvas_height);
379 if ((_editor->vertical_adjustment.get_value() + _editor->_canvas_height) > _editor->vertical_adjustment.get_upper()) {
381 We're increasing the size of the canvas while the bottom is visible.
382 We scroll down to keep in step with the controls layout.
384 _editor->vertical_adjustment.set_value (_editor->full_canvas_height - _editor->_canvas_height);
387 if (!_redisplay_does_not_reset_order_keys && !_redisplay_does_not_sync_order_keys) {
388 _session->sync_order_keys (N_ ("editor"));
393 EditorRoutes::route_deleted (Gtk::TreeModel::Path const &)
395 if (!_session || _session->deletion_in_progress()) {
399 /* this could require an order reset & sync */
400 _session->set_remote_control_ids();
401 _ignore_reorder = true;
403 _ignore_reorder = false;
407 EditorRoutes::visible_changed (Glib::ustring const & path)
409 if (_session && _session->deletion_in_progress()) {
415 if ((iter = _model->get_iter (path))) {
416 TimeAxisView* tv = (*iter)[_columns.tv];
418 bool visible = (*iter)[_columns.visible];
419 (*iter)[_columns.visible] = !visible;
423 _redisplay_does_not_reset_order_keys = true;
424 _session->set_remote_control_ids();
426 _redisplay_does_not_reset_order_keys = false;
430 EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
434 _redisplay_does_not_sync_order_keys = true;
435 suspend_redisplay ();
437 for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) {
439 row = *(_model->append ());
441 row[_columns.text] = (*x)->route()->name();
442 row[_columns.visible] = (*x)->marked_for_display();
443 row[_columns.tv] = *x;
444 row[_columns.route] = (*x)->route ();
445 row[_columns.is_track] = (boost::dynamic_pointer_cast<Track> ((*x)->route()) != 0);
446 row[_columns.mute_state] = (*x)->route()->muted();
447 row[_columns.solo_state] = (*x)->route()->soloed();
448 row[_columns.solo_isolate_state] = (*x)->route()->solo_isolated();
449 row[_columns.solo_safe_state] = (*x)->route()->solo_safe();
450 row[_columns.name_editable] = true;
452 _ignore_reorder = true;
454 /* added a new fresh one at the end */
455 if ((*x)->route()->order_key (N_ ("editor")) == -1) {
456 (*x)->route()->set_order_key (N_ ("editor"), _model->children().size()-1);
459 _ignore_reorder = false;
461 boost::weak_ptr<Route> wr ((*x)->route());
463 (*x)->route()->gui_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
464 (*x)->route()->PropertyChanged.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::route_property_changed, this, _1, wr), gui_context());
466 if ((*x)->is_track()) {
467 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
468 t->RecordEnableChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
471 if ((*x)->is_midi_track()) {
472 boost::shared_ptr<MidiTrack> t = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
473 t->StepEditStatusChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
476 (*x)->route()->mute_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
477 (*x)->route()->solo_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
478 (*x)->route()->solo_isolated_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_isolate_display, this), gui_context());
479 (*x)->route()->solo_safe_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_safe_display, this), gui_context());
482 update_rec_display ();
483 update_mute_display ();
484 update_solo_display (true);
485 update_solo_isolate_display ();
486 update_solo_safe_display ();
488 _redisplay_does_not_sync_order_keys = false;
492 EditorRoutes::handle_gui_changes (string const & what, void*)
494 ENSURE_GUI_THREAD (*this, &EditorRoutes::handle_gui_changes, what, src)
496 if (what == "track_height") {
497 /* Optional :make tracks change height while it happens, instead
500 //update_canvas_now ();
504 if (what == "visible_tracks") {
510 EditorRoutes::route_removed (TimeAxisView *tv)
512 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed, tv)
514 TreeModel::Children rows = _model->children();
515 TreeModel::Children::iterator ri;
517 /* the core model has changed, there is no need to sync
521 _redisplay_does_not_sync_order_keys = true;
523 for (ri = rows.begin(); ri != rows.end(); ++ri) {
524 if ((*ri)[_columns.tv] == tv) {
530 _redisplay_does_not_sync_order_keys = false;
534 EditorRoutes::route_property_changed (const PropertyChange& what_changed, boost::weak_ptr<Route> r)
536 if (!what_changed.contains (ARDOUR::Properties::name)) {
540 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_name_changed, r)
542 boost::shared_ptr<Route> route = r.lock ();
548 TreeModel::Children rows = _model->children();
549 TreeModel::Children::iterator i;
551 for (i = rows.begin(); i != rows.end(); ++i) {
552 boost::shared_ptr<Route> t = (*i)[_columns.route];
554 (*i)[_columns.text] = route->name();
561 EditorRoutes::update_visibility ()
563 TreeModel::Children rows = _model->children();
564 TreeModel::Children::iterator i;
566 suspend_redisplay ();
568 for (i = rows.begin(); i != rows.end(); ++i) {
569 TimeAxisView *tv = (*i)[_columns.tv];
570 (*i)[_columns.visible] = tv->marked_for_display ();
571 cerr << "marked " << tv->name() << " for display = " << tv->marked_for_display() << endl;
578 EditorRoutes::hide_track_in_display (TimeAxisView& tv)
580 TreeModel::Children rows = _model->children();
581 TreeModel::Children::iterator i;
583 for (i = rows.begin(); i != rows.end(); ++i) {
584 if ((*i)[_columns.tv] == &tv) {
585 (*i)[_columns.visible] = false;
594 EditorRoutes::show_track_in_display (TimeAxisView& tv)
596 TreeModel::Children rows = _model->children();
597 TreeModel::Children::iterator i;
599 for (i = rows.begin(); i != rows.end(); ++i) {
600 if ((*i)[_columns.tv] == &tv) {
601 (*i)[_columns.visible] = true;
610 EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
615 /** If src != "editor", take editor order keys from each route and use them to rearrange the
616 * route list so that the visual arrangement of routes matches the order keys from the routes.
619 EditorRoutes::sync_order_keys (string const & src)
621 vector<int> neworder;
622 TreeModel::Children rows = _model->children();
623 TreeModel::Children::iterator ri;
625 if (src == N_ ("editor") || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
629 for (ri = rows.begin(); ri != rows.end(); ++ri) {
630 neworder.push_back (0);
633 bool changed = false;
636 for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
637 boost::shared_ptr<Route> route = (*ri)[_columns.route];
640 int new_key = route->order_key (N_ ("editor"));
642 neworder[new_key] = old_key;
644 if (new_key != old_key) {
650 _redisplay_does_not_reset_order_keys = true;
651 _model->reorder (neworder);
652 _redisplay_does_not_reset_order_keys = false;
658 EditorRoutes::hide_all_tracks (bool /*with_select*/)
660 TreeModel::Children rows = _model->children();
661 TreeModel::Children::iterator i;
663 suspend_redisplay ();
665 for (i = rows.begin(); i != rows.end(); ++i) {
667 TreeModel::Row row = (*i);
668 TimeAxisView *tv = row[_columns.tv];
674 row[_columns.visible] = false;
679 /* XXX this seems like a hack and half, but its not clear where to put this
683 //reset_scrolling_region ();
687 EditorRoutes::set_all_tracks_visibility (bool yn)
689 TreeModel::Children rows = _model->children();
690 TreeModel::Children::iterator i;
692 suspend_redisplay ();
694 for (i = rows.begin(); i != rows.end(); ++i) {
696 TreeModel::Row row = (*i);
697 TimeAxisView* tv = row[_columns.tv];
703 (*i)[_columns.visible] = yn;
710 EditorRoutes::set_all_audio_midi_visibility (int tracks, bool yn)
712 TreeModel::Children rows = _model->children();
713 TreeModel::Children::iterator i;
715 suspend_redisplay ();
717 for (i = rows.begin(); i != rows.end(); ++i) {
719 TreeModel::Row row = (*i);
720 TimeAxisView* tv = row[_columns.tv];
722 AudioTimeAxisView* atv;
723 MidiTimeAxisView* mtv;
729 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
732 (*i)[_columns.visible] = yn;
736 if (atv->is_audio_track()) {
737 (*i)[_columns.visible] = yn;
742 if (!atv->is_audio_track()) {
743 (*i)[_columns.visible] = yn;
748 else if ((mtv = dynamic_cast<MidiTimeAxisView*>(tv)) != 0) {
751 (*i)[_columns.visible] = yn;
755 if (mtv->is_midi_track()) {
756 (*i)[_columns.visible] = yn;
767 EditorRoutes::hide_all_routes ()
769 set_all_tracks_visibility (false);
773 EditorRoutes::show_all_routes ()
775 set_all_tracks_visibility (true);
779 EditorRoutes::show_all_audiotracks()
781 set_all_audio_midi_visibility (1, true);
784 EditorRoutes::hide_all_audiotracks ()
786 set_all_audio_midi_visibility (1, false);
790 EditorRoutes::show_all_audiobus ()
792 set_all_audio_midi_visibility (2, true);
795 EditorRoutes::hide_all_audiobus ()
797 set_all_audio_midi_visibility (2, false);
801 EditorRoutes::show_all_miditracks()
803 set_all_audio_midi_visibility (3, true);
806 EditorRoutes::hide_all_miditracks ()
808 set_all_audio_midi_visibility (3, false);
812 EditorRoutes::button_press (GdkEventButton* ev)
814 if (Keyboard::is_context_menu_event (ev)) {
819 //Scroll editor canvas to selected track
820 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
822 TreeModel::Path path;
827 _display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y);
829 // Get the model row.
830 Gtk::TreeModel::Row row = *_model->get_iter (path);
832 TimeAxisView *tv = row[_columns.tv];
834 int y_pos = tv->y_position();
836 //Clamp the y pos so that we do not extend beyond the canvas full height.
837 if (_editor->full_canvas_height - y_pos < _editor->_canvas_height){
838 y_pos = _editor->full_canvas_height - _editor->_canvas_height;
841 //Only scroll to if the track is visible
843 _editor->reset_y_origin (y_pos);
851 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const &, bool)
856 struct EditorOrderRouteSorter {
857 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
858 /* use of ">" forces the correct sort order */
859 return a->order_key (N_ ("editor")) < b->order_key (N_ ("editor"));
864 EditorRoutes::initial_display ()
866 suspend_redisplay ();
874 boost::shared_ptr<RouteList> routes = _session->get_routes();
875 RouteList r (*routes);
876 EditorOrderRouteSorter sorter;
879 _editor->handle_new_route (r);
881 /* don't show master bus in a new session */
883 if (ARDOUR_UI::instance()->session_is_new ()) {
885 TreeModel::Children rows = _model->children();
886 TreeModel::Children::iterator i;
888 _no_redisplay = true;
890 for (i = rows.begin(); i != rows.end(); ++i) {
892 TimeAxisView *tv = (*i)[_columns.tv];
893 RouteTimeAxisView *rtv;
895 if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
896 if (rtv->route()->is_master()) {
897 _display.get_selection()->unselect (i);
902 _no_redisplay = false;
910 EditorRoutes::track_list_reorder (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &, int* /*new_order*/)
912 _redisplay_does_not_sync_order_keys = true;
913 _session->set_remote_control_ids();
915 _redisplay_does_not_sync_order_keys = false;
919 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
921 const SelectionData& data,
922 guint info, guint time)
924 if (data.get_target() == "GTK_TREE_MODEL_ROW") {
925 _display.on_drag_data_received (context, x, y, data, info, time);
929 context->drag_finish (true, false, time);
933 EditorRoutes::move_selected_tracks (bool up)
935 if (_editor->selection->tracks.empty()) {
939 typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
940 std::list<ViewRoute> view_routes;
941 std::vector<int> neworder;
942 TreeModel::Children rows = _model->children();
943 TreeModel::Children::iterator ri;
945 for (ri = rows.begin(); ri != rows.end(); ++ri) {
946 TimeAxisView* tv = (*ri)[_columns.tv];
947 boost::shared_ptr<Route> route = (*ri)[_columns.route];
949 view_routes.push_back (ViewRoute (tv, route));
952 list<ViewRoute>::iterator trailing;
953 list<ViewRoute>::iterator leading;
957 trailing = view_routes.begin();
958 leading = view_routes.begin();
962 while (leading != view_routes.end()) {
963 if (_editor->selection->selected (leading->first)) {
964 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
965 leading = view_routes.erase (leading);
974 /* if we could use reverse_iterator in list::insert, this code
975 would be a beautiful reflection of the code above. but we can't
976 and so it looks like a bit of a mess.
979 trailing = view_routes.end();
980 leading = view_routes.end();
982 --leading; if (leading == view_routes.begin()) { return; }
988 if (_editor->selection->selected (leading->first)) {
989 list<ViewRoute>::iterator tmp;
991 /* need to insert *after* trailing, not *before* it,
992 which is what insert (iter, val) normally does.
998 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
1000 /* can't use iter = cont.erase (iter); form here, because
1001 we need iter to move backwards.
1009 if (leading == view_routes.begin()) {
1010 /* the one we've just inserted somewhere else
1011 was the first in the list. erase this copy,
1012 and then break, because we're done.
1017 view_routes.erase (leading);
1026 if (leading == view_routes.begin()) {
1035 for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
1036 neworder.push_back (leading->second->order_key (N_ ("editor")));
1039 _model->reorder (neworder);
1041 _session->sync_order_keys (N_ ("editor"));
1045 EditorRoutes::update_rec_display ()
1047 TreeModel::Children rows = _model->children();
1048 TreeModel::Children::iterator i;
1050 for (i = rows.begin(); i != rows.end(); ++i) {
1051 boost::shared_ptr<Route> route = (*i)[_columns.route];
1053 if (boost::dynamic_pointer_cast<Track> (route)) {
1054 boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
1056 if (route->record_enabled()) {
1057 if (_session->record_status() == Session::Recording) {
1058 (*i)[_columns.rec_state] = 1;
1060 (*i)[_columns.rec_state] = 2;
1062 } else if (mt && mt->step_editing()) {
1063 (*i)[_columns.rec_state] = 3;
1065 (*i)[_columns.rec_state] = 0;
1068 (*i)[_columns.name_editable] = !route->record_enabled ();
1074 EditorRoutes::update_mute_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.mute_state] = RouteUI::mute_visual_state (_session, route);
1086 EditorRoutes::update_solo_display (bool /* selfsoloed */)
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_state] = RouteUI::solo_visual_state (route);
1098 EditorRoutes::update_solo_isolate_display ()
1100 TreeModel::Children rows = _model->children();
1101 TreeModel::Children::iterator i;
1103 for (i = rows.begin(); i != rows.end(); ++i) {
1104 boost::shared_ptr<Route> route = (*i)[_columns.route];
1105 (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_visual_state (route) > 0 ? 1 : 0;
1110 EditorRoutes::update_solo_safe_display ()
1112 TreeModel::Children rows = _model->children();
1113 TreeModel::Children::iterator i;
1115 for (i = rows.begin(); i != rows.end(); ++i) {
1116 boost::shared_ptr<Route> route = (*i)[_columns.route];
1117 (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_visual_state (route) > 0 ? 1 : 0;
1122 EditorRoutes::views () const
1124 list<TimeAxisView*> v;
1125 for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
1126 v.push_back ((*i)[_columns.tv]);
1133 EditorRoutes::clear ()
1135 _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1137 _display.set_model (_model);
1141 EditorRoutes::name_edit (Glib::ustring const & path, Glib::ustring const & new_text)
1143 TreeIter iter = _model->get_iter (path);
1148 boost::shared_ptr<Route> route = (*iter)[_columns.route];
1150 if (route && route->name() != new_text) {
1151 route->set_name (new_text);
1156 EditorRoutes::solo_changed_so_update_mute ()
1158 update_mute_display ();
1162 EditorRoutes::show_tracks_with_regions_at_playhead ()
1164 boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
1166 set<TimeAxisView*> show;
1167 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
1168 TimeAxisView* tav = _editor->axis_view_from_route (*i);
1174 suspend_redisplay ();
1176 TreeModel::Children rows = _model->children ();
1177 for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
1178 TimeAxisView* tv = (*i)[_columns.tv];
1179 (*i)[_columns.visible] = (show.find (tv) != show.end());
1182 resume_redisplay ();