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;
579 EditorRoutes::show_track_in_display (TimeAxisView& tv)
581 TreeModel::Children rows = _model->children();
582 TreeModel::Children::iterator i;
584 for (i = rows.begin(); i != rows.end(); ++i) {
585 if ((*i)[_columns.tv] == &tv) {
586 (*i)[_columns.visible] = true;
593 EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
598 /** If src != "editor", take editor order keys from each route and use them to rearrange the
599 * route list so that the visual arrangement of routes matches the order keys from the routes.
602 EditorRoutes::sync_order_keys (string const & src)
604 vector<int> neworder;
605 TreeModel::Children rows = _model->children();
606 TreeModel::Children::iterator ri;
608 if (src == N_ ("editor") || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
612 for (ri = rows.begin(); ri != rows.end(); ++ri) {
613 neworder.push_back (0);
616 bool changed = false;
619 for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
620 boost::shared_ptr<Route> route = (*ri)[_columns.route];
623 int new_key = route->order_key (N_ ("editor"));
625 neworder[new_key] = old_key;
627 if (new_key != old_key) {
633 _redisplay_does_not_reset_order_keys = true;
634 _model->reorder (neworder);
635 _redisplay_does_not_reset_order_keys = false;
641 EditorRoutes::hide_all_tracks (bool /*with_select*/)
643 TreeModel::Children rows = _model->children();
644 TreeModel::Children::iterator i;
646 suspend_redisplay ();
648 for (i = rows.begin(); i != rows.end(); ++i) {
650 TreeModel::Row row = (*i);
651 TimeAxisView *tv = row[_columns.tv];
657 row[_columns.visible] = false;
662 /* XXX this seems like a hack and half, but its not clear where to put this
666 //reset_scrolling_region ();
670 EditorRoutes::set_all_tracks_visibility (bool yn)
672 TreeModel::Children rows = _model->children();
673 TreeModel::Children::iterator i;
675 suspend_redisplay ();
677 for (i = rows.begin(); i != rows.end(); ++i) {
679 TreeModel::Row row = (*i);
680 TimeAxisView* tv = row[_columns.tv];
686 (*i)[_columns.visible] = yn;
693 EditorRoutes::set_all_audio_visibility (int tracks, bool yn)
695 TreeModel::Children rows = _model->children();
696 TreeModel::Children::iterator i;
698 suspend_redisplay ();
700 for (i = rows.begin(); i != rows.end(); ++i) {
701 TreeModel::Row row = (*i);
702 TimeAxisView* tv = row[_columns.tv];
703 AudioTimeAxisView* atv;
709 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
712 (*i)[_columns.visible] = yn;
716 if (atv->is_audio_track()) {
717 (*i)[_columns.visible] = yn;
722 if (!atv->is_audio_track()) {
723 (*i)[_columns.visible] = yn;
734 EditorRoutes::hide_all_routes ()
736 set_all_tracks_visibility (false);
740 EditorRoutes::show_all_routes ()
742 set_all_tracks_visibility (true);
746 EditorRoutes::show_all_audiobus ()
748 set_all_audio_visibility (2, true);
751 EditorRoutes::hide_all_audiobus ()
753 set_all_audio_visibility (2, false);
757 EditorRoutes::show_all_audiotracks()
759 set_all_audio_visibility (1, true);
762 EditorRoutes::hide_all_audiotracks ()
764 set_all_audio_visibility (1, false);
768 EditorRoutes::button_press (GdkEventButton* ev)
770 if (Keyboard::is_context_menu_event (ev)) {
775 //Scroll editor canvas to selected track
776 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
778 TreeModel::Path path;
783 _display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y);
785 // Get the model row.
786 Gtk::TreeModel::Row row = *_model->get_iter (path);
788 TimeAxisView *tv = row[_columns.tv];
790 int y_pos = tv->y_position();
792 //Clamp the y pos so that we do not extend beyond the canvas full height.
793 if (_editor->full_canvas_height - y_pos < _editor->_canvas_height){
794 y_pos = _editor->full_canvas_height - _editor->_canvas_height;
797 //Only scroll to if the track is visible
799 _editor->reset_y_origin (y_pos);
807 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const &, bool)
812 struct EditorOrderRouteSorter {
813 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
814 /* use of ">" forces the correct sort order */
815 return a->order_key (N_ ("editor")) < b->order_key (N_ ("editor"));
820 EditorRoutes::initial_display ()
822 suspend_redisplay ();
830 boost::shared_ptr<RouteList> routes = _session->get_routes();
831 RouteList r (*routes);
832 EditorOrderRouteSorter sorter;
835 _editor->handle_new_route (r);
837 /* don't show master bus in a new session */
839 if (ARDOUR_UI::instance()->session_is_new ()) {
841 TreeModel::Children rows = _model->children();
842 TreeModel::Children::iterator i;
844 _no_redisplay = true;
846 for (i = rows.begin(); i != rows.end(); ++i) {
848 TimeAxisView *tv = (*i)[_columns.tv];
849 RouteTimeAxisView *rtv;
851 if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
852 if (rtv->route()->is_master()) {
853 _display.get_selection()->unselect (i);
858 _no_redisplay = false;
866 EditorRoutes::track_list_reorder (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &, int* /*new_order*/)
868 _redisplay_does_not_sync_order_keys = true;
869 _session->set_remote_control_ids();
871 _redisplay_does_not_sync_order_keys = false;
875 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
877 const SelectionData& data,
878 guint info, guint time)
880 if (data.get_target() == "GTK_TREE_MODEL_ROW") {
881 _display.on_drag_data_received (context, x, y, data, info, time);
885 context->drag_finish (true, false, time);
889 EditorRoutes::move_selected_tracks (bool up)
891 if (_editor->selection->tracks.empty()) {
895 typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
896 std::list<ViewRoute> view_routes;
897 std::vector<int> neworder;
898 TreeModel::Children rows = _model->children();
899 TreeModel::Children::iterator ri;
901 for (ri = rows.begin(); ri != rows.end(); ++ri) {
902 TimeAxisView* tv = (*ri)[_columns.tv];
903 boost::shared_ptr<Route> route = (*ri)[_columns.route];
905 view_routes.push_back (ViewRoute (tv, route));
908 list<ViewRoute>::iterator trailing;
909 list<ViewRoute>::iterator leading;
913 trailing = view_routes.begin();
914 leading = view_routes.begin();
918 while (leading != view_routes.end()) {
919 if (_editor->selection->selected (leading->first)) {
920 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
921 leading = view_routes.erase (leading);
930 /* if we could use reverse_iterator in list::insert, this code
931 would be a beautiful reflection of the code above. but we can't
932 and so it looks like a bit of a mess.
935 trailing = view_routes.end();
936 leading = view_routes.end();
938 --leading; if (leading == view_routes.begin()) { return; }
944 if (_editor->selection->selected (leading->first)) {
945 list<ViewRoute>::iterator tmp;
947 /* need to insert *after* trailing, not *before* it,
948 which is what insert (iter, val) normally does.
954 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
956 /* can't use iter = cont.erase (iter); form here, because
957 we need iter to move backwards.
965 if (leading == view_routes.begin()) {
966 /* the one we've just inserted somewhere else
967 was the first in the list. erase this copy,
968 and then break, because we're done.
973 view_routes.erase (leading);
982 if (leading == view_routes.begin()) {
991 for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
992 neworder.push_back (leading->second->order_key (N_ ("editor")));
995 _model->reorder (neworder);
997 _session->sync_order_keys (N_ ("editor"));
1001 EditorRoutes::update_rec_display ()
1003 TreeModel::Children rows = _model->children();
1004 TreeModel::Children::iterator i;
1006 for (i = rows.begin(); i != rows.end(); ++i) {
1007 boost::shared_ptr<Route> route = (*i)[_columns.route];
1009 if (boost::dynamic_pointer_cast<Track>(route)) {
1010 (*i)[_columns.rec_enabled] = route->record_enabled ();
1011 (*i)[_columns.name_editable] = !route->record_enabled ();
1017 EditorRoutes::update_mute_display ()
1019 TreeModel::Children rows = _model->children();
1020 TreeModel::Children::iterator i;
1022 for (i = rows.begin(); i != rows.end(); ++i) {
1023 boost::shared_ptr<Route> route = (*i)[_columns.route];
1024 (*i)[_columns.mute_state] = RouteUI::mute_visual_state (_session, route) > 0 ? 1 : 0;
1029 EditorRoutes::update_solo_display (bool /* selfsoloed */)
1031 TreeModel::Children rows = _model->children();
1032 TreeModel::Children::iterator i;
1034 for (i = rows.begin(); i != rows.end(); ++i) {
1035 boost::shared_ptr<Route> route = (*i)[_columns.route];
1036 (*i)[_columns.solo_state] = RouteUI::solo_visual_state (route) > 0 ? 1 : 0;
1041 EditorRoutes::update_solo_isolate_display ()
1043 TreeModel::Children rows = _model->children();
1044 TreeModel::Children::iterator i;
1046 for (i = rows.begin(); i != rows.end(); ++i) {
1047 boost::shared_ptr<Route> route = (*i)[_columns.route];
1048 (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_visual_state (route) > 0 ? 1 : 0;
1053 EditorRoutes::update_solo_safe_display ()
1055 TreeModel::Children rows = _model->children();
1056 TreeModel::Children::iterator i;
1058 for (i = rows.begin(); i != rows.end(); ++i) {
1059 boost::shared_ptr<Route> route = (*i)[_columns.route];
1060 (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_visual_state (route) > 0 ? 1 : 0;
1065 EditorRoutes::views () const
1067 list<TimeAxisView*> v;
1068 for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
1069 v.push_back ((*i)[_columns.tv]);
1076 EditorRoutes::clear ()
1078 _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1080 _display.set_model (_model);
1084 EditorRoutes::name_edit (Glib::ustring const & path, Glib::ustring const & new_text)
1086 TreeIter iter = _model->get_iter (path);
1091 boost::shared_ptr<Route> route = (*iter)[_columns.route];
1093 if (route && route->name() != new_text) {
1094 route->set_name (new_text);
1099 EditorRoutes::solo_changed_so_update_mute ()
1101 update_mute_display ();
1105 EditorRoutes::show_tracks_with_regions_at_playhead ()
1107 boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
1109 set<TimeAxisView*> show;
1110 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
1111 TimeAxisView* tav = _editor->axis_view_from_route (*i);
1117 suspend_redisplay ();
1119 TreeModel::Children rows = _model->children ();
1120 for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
1121 TimeAxisView* tv = (*i)[_columns.tv];
1122 (*i)[_columns.visible] = (show.find (tv) != show.end());
1125 resume_redisplay ();