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 EditorComponent::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_enable (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 Tracks With Regions Under Playhead"), sigc::mem_fun (*this, &EditorRoutes::show_tracks_with_regions_at_playhead)));
310 EditorRoutes::show_menu ()
316 _menu->popup (1, gtk_get_current_event_time());
320 EditorRoutes::redisplay ()
322 if (_no_redisplay || !_session) {
326 TreeModel::Children rows = _model->children();
327 TreeModel::Children::iterator i;
331 for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
332 TimeAxisView *tv = (*i)[_columns.tv];
333 boost::shared_ptr<Route> route = (*i)[_columns.route];
336 // just a "title" row
340 if (!_redisplay_does_not_reset_order_keys) {
341 /* this reorder is caused by user action, so reassign sort order keys
344 route->set_order_key (N_ ("editor"), n);
347 bool visible = (*i)[_columns.visible];
349 /* show or hide the TimeAxisView */
351 tv->set_marked_for_display (true);
352 position += tv->show_at (position, n, &_editor->edit_controls_vbox);
353 tv->clip_to_viewport ();
355 tv->set_marked_for_display (false);
362 /* whenever we go idle, update the track view list to reflect the new order.
363 we can't do this here, because we could mess up something that is traversing
364 the track order and has caused a redisplay of the list.
366 Glib::signal_idle().connect (sigc::mem_fun (*_editor, &Editor::sync_track_view_list_and_routes));
368 _editor->full_canvas_height = position + _editor->canvas_timebars_vsize;
369 _editor->vertical_adjustment.set_upper (_editor->full_canvas_height);
371 if ((_editor->vertical_adjustment.get_value() + _editor->_canvas_height) > _editor->vertical_adjustment.get_upper()) {
373 We're increasing the size of the canvas while the bottom is visible.
374 We scroll down to keep in step with the controls layout.
376 _editor->vertical_adjustment.set_value (_editor->full_canvas_height - _editor->_canvas_height);
379 if (!_redisplay_does_not_reset_order_keys && !_redisplay_does_not_sync_order_keys) {
380 _session->sync_order_keys (N_ ("editor"));
385 EditorRoutes::route_deleted (Gtk::TreeModel::Path const &)
387 if (!_session || _session->deletion_in_progress()) {
391 /* this could require an order reset & sync */
392 _session->set_remote_control_ids();
393 _ignore_reorder = true;
395 _ignore_reorder = false;
399 EditorRoutes::visible_changed (Glib::ustring const & path)
401 if (_session && _session->deletion_in_progress()) {
407 if ((iter = _model->get_iter (path))) {
408 TimeAxisView* tv = (*iter)[_columns.tv];
410 bool visible = (*iter)[_columns.visible];
411 (*iter)[_columns.visible] = !visible;
415 _redisplay_does_not_reset_order_keys = true;
416 _session->set_remote_control_ids();
418 _redisplay_does_not_reset_order_keys = false;
422 EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
426 _redisplay_does_not_sync_order_keys = true;
427 suspend_redisplay ();
429 for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) {
431 row = *(_model->append ());
433 row[_columns.text] = (*x)->route()->name();
434 row[_columns.visible] = (*x)->marked_for_display();
435 row[_columns.tv] = *x;
436 row[_columns.route] = (*x)->route ();
437 row[_columns.is_track] = (boost::dynamic_pointer_cast<Track> ((*x)->route()) != 0);
438 row[_columns.mute_state] = (*x)->route()->muted();
439 row[_columns.solo_state] = (*x)->route()->soloed();
440 row[_columns.solo_isolate_state] = (*x)->route()->solo_isolated();
441 row[_columns.solo_safe_state] = (*x)->route()->solo_safe();
442 row[_columns.name_editable] = true;
444 _ignore_reorder = true;
446 /* added a new fresh one at the end */
447 if ((*x)->route()->order_key (N_ ("editor")) == -1) {
448 (*x)->route()->set_order_key (N_ ("editor"), _model->children().size()-1);
451 _ignore_reorder = false;
453 boost::weak_ptr<Route> wr ((*x)->route());
455 (*x)->route()->gui_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
456 (*x)->route()->PropertyChanged.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::route_property_changed, this, _1, wr), gui_context());
458 if ((*x)->is_track()) {
459 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
460 t->RecordEnableChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
463 (*x)->route()->mute_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
464 (*x)->route()->solo_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
465 (*x)->route()->solo_isolated_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_isolate_display, this), gui_context());
466 (*x)->route()->solo_safe_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_safe_display, this), gui_context());
469 update_rec_display ();
470 update_mute_display ();
471 update_solo_display (true);
472 update_solo_isolate_display ();
473 update_solo_safe_display ();
475 _redisplay_does_not_sync_order_keys = false;
479 EditorRoutes::handle_gui_changes (string const & what, void*)
481 ENSURE_GUI_THREAD (*this, &EditorRoutes::handle_gui_changes, what, src)
483 if (what == "track_height") {
484 /* Optional :make tracks change height while it happens, instead
487 //update_canvas_now ();
491 if (what == "visible_tracks") {
497 EditorRoutes::route_removed (TimeAxisView *tv)
499 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed, tv)
501 TreeModel::Children rows = _model->children();
502 TreeModel::Children::iterator ri;
504 /* the core model has changed, there is no need to sync
508 _redisplay_does_not_sync_order_keys = true;
510 for (ri = rows.begin(); ri != rows.end(); ++ri) {
511 if ((*ri)[_columns.tv] == tv) {
517 _redisplay_does_not_sync_order_keys = false;
521 EditorRoutes::route_property_changed (const PropertyChange& what_changed, boost::weak_ptr<Route> r)
523 if (!what_changed.contains (ARDOUR::Properties::name)) {
527 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_name_changed, r)
529 boost::shared_ptr<Route> route = r.lock ();
535 TreeModel::Children rows = _model->children();
536 TreeModel::Children::iterator i;
538 for (i = rows.begin(); i != rows.end(); ++i) {
539 boost::shared_ptr<Route> t = (*i)[_columns.route];
541 (*i)[_columns.text] = route->name();
548 EditorRoutes::update_visibility ()
550 TreeModel::Children rows = _model->children();
551 TreeModel::Children::iterator i;
553 suspend_redisplay ();
555 for (i = rows.begin(); i != rows.end(); ++i) {
556 TimeAxisView *tv = (*i)[_columns.tv];
557 (*i)[_columns.visible] = tv->marked_for_display ();
558 cerr << "marked " << tv->name() << " for display = " << tv->marked_for_display() << endl;
565 EditorRoutes::hide_track_in_display (TimeAxisView& tv)
567 TreeModel::Children rows = _model->children();
568 TreeModel::Children::iterator i;
570 for (i = rows.begin(); i != rows.end(); ++i) {
571 if ((*i)[_columns.tv] == &tv) {
572 (*i)[_columns.visible] = false;
581 EditorRoutes::show_track_in_display (TimeAxisView& tv)
583 TreeModel::Children rows = _model->children();
584 TreeModel::Children::iterator i;
586 for (i = rows.begin(); i != rows.end(); ++i) {
587 if ((*i)[_columns.tv] == &tv) {
588 (*i)[_columns.visible] = true;
597 EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
602 /** If src != "editor", take editor order keys from each route and use them to rearrange the
603 * route list so that the visual arrangement of routes matches the order keys from the routes.
606 EditorRoutes::sync_order_keys (string const & src)
608 vector<int> neworder;
609 TreeModel::Children rows = _model->children();
610 TreeModel::Children::iterator ri;
612 if (src == N_ ("editor") || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
616 for (ri = rows.begin(); ri != rows.end(); ++ri) {
617 neworder.push_back (0);
620 bool changed = false;
623 for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
624 boost::shared_ptr<Route> route = (*ri)[_columns.route];
627 int new_key = route->order_key (N_ ("editor"));
629 neworder[new_key] = old_key;
631 if (new_key != old_key) {
637 _redisplay_does_not_reset_order_keys = true;
638 _model->reorder (neworder);
639 _redisplay_does_not_reset_order_keys = false;
645 EditorRoutes::hide_all_tracks (bool /*with_select*/)
647 TreeModel::Children rows = _model->children();
648 TreeModel::Children::iterator i;
650 suspend_redisplay ();
652 for (i = rows.begin(); i != rows.end(); ++i) {
654 TreeModel::Row row = (*i);
655 TimeAxisView *tv = row[_columns.tv];
661 row[_columns.visible] = false;
666 /* XXX this seems like a hack and half, but its not clear where to put this
670 //reset_scrolling_region ();
674 EditorRoutes::set_all_tracks_visibility (bool yn)
676 TreeModel::Children rows = _model->children();
677 TreeModel::Children::iterator i;
679 suspend_redisplay ();
681 for (i = rows.begin(); i != rows.end(); ++i) {
683 TreeModel::Row row = (*i);
684 TimeAxisView* tv = row[_columns.tv];
690 (*i)[_columns.visible] = yn;
697 EditorRoutes::set_all_audio_visibility (int tracks, bool yn)
699 TreeModel::Children rows = _model->children();
700 TreeModel::Children::iterator i;
702 suspend_redisplay ();
704 for (i = rows.begin(); i != rows.end(); ++i) {
705 TreeModel::Row row = (*i);
706 TimeAxisView* tv = row[_columns.tv];
707 AudioTimeAxisView* atv;
713 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
716 (*i)[_columns.visible] = yn;
720 if (atv->is_audio_track()) {
721 (*i)[_columns.visible] = yn;
726 if (!atv->is_audio_track()) {
727 (*i)[_columns.visible] = yn;
738 EditorRoutes::hide_all_routes ()
740 set_all_tracks_visibility (false);
744 EditorRoutes::show_all_routes ()
746 set_all_tracks_visibility (true);
750 EditorRoutes::show_all_audiobus ()
752 set_all_audio_visibility (2, true);
755 EditorRoutes::hide_all_audiobus ()
757 set_all_audio_visibility (2, false);
761 EditorRoutes::show_all_audiotracks()
763 set_all_audio_visibility (1, true);
766 EditorRoutes::hide_all_audiotracks ()
768 set_all_audio_visibility (1, false);
772 EditorRoutes::button_press (GdkEventButton* ev)
774 if (Keyboard::is_context_menu_event (ev)) {
779 //Scroll editor canvas to selected track
780 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
782 TreeModel::Path path;
787 _display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y);
789 // Get the model row.
790 Gtk::TreeModel::Row row = *_model->get_iter (path);
792 TimeAxisView *tv = row[_columns.tv];
794 int y_pos = tv->y_position();
796 //Clamp the y pos so that we do not extend beyond the canvas full height.
797 if (_editor->full_canvas_height - y_pos < _editor->_canvas_height){
798 y_pos = _editor->full_canvas_height - _editor->_canvas_height;
801 //Only scroll to if the track is visible
803 _editor->reset_y_origin (y_pos);
811 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const &, bool)
816 struct EditorOrderRouteSorter {
817 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
818 /* use of ">" forces the correct sort order */
819 return a->order_key (N_ ("editor")) < b->order_key (N_ ("editor"));
824 EditorRoutes::initial_display ()
826 suspend_redisplay ();
834 boost::shared_ptr<RouteList> routes = _session->get_routes();
835 RouteList r (*routes);
836 EditorOrderRouteSorter sorter;
839 _editor->handle_new_route (r);
841 /* don't show master bus in a new session */
843 if (ARDOUR_UI::instance()->session_is_new ()) {
845 TreeModel::Children rows = _model->children();
846 TreeModel::Children::iterator i;
848 _no_redisplay = true;
850 for (i = rows.begin(); i != rows.end(); ++i) {
852 TimeAxisView *tv = (*i)[_columns.tv];
853 RouteTimeAxisView *rtv;
855 if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
856 if (rtv->route()->is_master()) {
857 _display.get_selection()->unselect (i);
862 _no_redisplay = false;
870 EditorRoutes::track_list_reorder (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &, int* /*new_order*/)
872 _redisplay_does_not_sync_order_keys = true;
873 _session->set_remote_control_ids();
875 _redisplay_does_not_sync_order_keys = false;
879 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
881 const SelectionData& data,
882 guint info, guint time)
884 if (data.get_target() == "GTK_TREE_MODEL_ROW") {
885 _display.on_drag_data_received (context, x, y, data, info, time);
889 context->drag_finish (true, false, time);
893 EditorRoutes::move_selected_tracks (bool up)
895 if (_editor->selection->tracks.empty()) {
899 typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
900 std::list<ViewRoute> view_routes;
901 std::vector<int> neworder;
902 TreeModel::Children rows = _model->children();
903 TreeModel::Children::iterator ri;
905 for (ri = rows.begin(); ri != rows.end(); ++ri) {
906 TimeAxisView* tv = (*ri)[_columns.tv];
907 boost::shared_ptr<Route> route = (*ri)[_columns.route];
909 view_routes.push_back (ViewRoute (tv, route));
912 list<ViewRoute>::iterator trailing;
913 list<ViewRoute>::iterator leading;
917 trailing = view_routes.begin();
918 leading = view_routes.begin();
922 while (leading != view_routes.end()) {
923 if (_editor->selection->selected (leading->first)) {
924 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
925 leading = view_routes.erase (leading);
934 /* if we could use reverse_iterator in list::insert, this code
935 would be a beautiful reflection of the code above. but we can't
936 and so it looks like a bit of a mess.
939 trailing = view_routes.end();
940 leading = view_routes.end();
942 --leading; if (leading == view_routes.begin()) { return; }
948 if (_editor->selection->selected (leading->first)) {
949 list<ViewRoute>::iterator tmp;
951 /* need to insert *after* trailing, not *before* it,
952 which is what insert (iter, val) normally does.
958 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
960 /* can't use iter = cont.erase (iter); form here, because
961 we need iter to move backwards.
969 if (leading == view_routes.begin()) {
970 /* the one we've just inserted somewhere else
971 was the first in the list. erase this copy,
972 and then break, because we're done.
977 view_routes.erase (leading);
986 if (leading == view_routes.begin()) {
995 for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
996 neworder.push_back (leading->second->order_key (N_ ("editor")));
999 _model->reorder (neworder);
1001 _session->sync_order_keys (N_ ("editor"));
1005 EditorRoutes::update_rec_display ()
1007 TreeModel::Children rows = _model->children();
1008 TreeModel::Children::iterator i;
1010 for (i = rows.begin(); i != rows.end(); ++i) {
1011 boost::shared_ptr<Route> route = (*i)[_columns.route];
1013 if (boost::dynamic_pointer_cast<Track>(route)) {
1014 (*i)[_columns.rec_enabled] = route->record_enabled ();
1015 (*i)[_columns.name_editable] = !route->record_enabled ();
1021 EditorRoutes::update_mute_display ()
1023 TreeModel::Children rows = _model->children();
1024 TreeModel::Children::iterator i;
1026 for (i = rows.begin(); i != rows.end(); ++i) {
1027 boost::shared_ptr<Route> route = (*i)[_columns.route];
1028 (*i)[_columns.mute_state] = RouteUI::mute_visual_state (_session, route) > 0 ? 1 : 0;
1033 EditorRoutes::update_solo_display (bool /* selfsoloed */)
1035 TreeModel::Children rows = _model->children();
1036 TreeModel::Children::iterator i;
1038 for (i = rows.begin(); i != rows.end(); ++i) {
1039 boost::shared_ptr<Route> route = (*i)[_columns.route];
1040 (*i)[_columns.solo_state] = RouteUI::solo_visual_state (route) > 0 ? 1 : 0;
1045 EditorRoutes::update_solo_isolate_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];
1052 (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_visual_state (route) > 0 ? 1 : 0;
1057 EditorRoutes::update_solo_safe_display ()
1059 TreeModel::Children rows = _model->children();
1060 TreeModel::Children::iterator i;
1062 for (i = rows.begin(); i != rows.end(); ++i) {
1063 boost::shared_ptr<Route> route = (*i)[_columns.route];
1064 (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_visual_state (route) > 0 ? 1 : 0;
1069 EditorRoutes::views () const
1071 list<TimeAxisView*> v;
1072 for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
1073 v.push_back ((*i)[_columns.tv]);
1080 EditorRoutes::clear ()
1082 _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1084 _display.set_model (_model);
1088 EditorRoutes::name_edit (Glib::ustring const & path, Glib::ustring const & new_text)
1090 TreeIter iter = _model->get_iter (path);
1095 boost::shared_ptr<Route> route = (*iter)[_columns.route];
1097 if (route && route->name() != new_text) {
1098 route->set_name (new_text);
1103 EditorRoutes::solo_changed_so_update_mute ()
1105 update_mute_display ();
1109 EditorRoutes::show_tracks_with_regions_at_playhead ()
1111 boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
1113 set<TimeAxisView*> show;
1114 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
1115 TimeAxisView* tav = _editor->axis_view_from_route (*i);
1121 suspend_redisplay ();
1123 TreeModel::Children rows = _model->children ();
1124 for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
1125 TimeAxisView* tv = (*i)[_columns.tv];
1126 (*i)[_columns.visible] = (show.find (tv) != show.end());
1129 resume_redisplay ();