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/diskstream.h"
28 #include "ardour/session.h"
32 #include "ardour_ui.h"
33 #include "audio_time_axis.h"
34 #include "midi_time_axis.h"
35 #include "mixer_strip.h"
36 #include "gui_thread.h"
39 #include "editor_group_tabs.h"
40 #include "editor_routes.h"
42 #include "pbd/unknown_type.h"
44 #include "ardour/route.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 CellRendererPixbufToggle* rec_col_renderer = manage (new CellRendererPixbufToggle());
76 rec_col_renderer->set_active_pixbuf (::get_icon("rec-enabled"));
77 rec_col_renderer->set_inactive_pixbuf (::get_icon("act-disabled"));
78 rec_col_renderer->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_rec_enable_toggled));
80 TreeViewColumn* rec_state_column = manage (new TreeViewColumn("R", *rec_col_renderer));
82 rec_state_column->add_attribute(rec_col_renderer->property_active(), _columns.rec_enabled);
83 rec_state_column->add_attribute(rec_col_renderer->property_visible(), _columns.is_track);
84 rec_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
85 rec_state_column->set_alignment(ALIGN_CENTER);
86 rec_state_column->set_expand(false);
87 rec_state_column->set_fixed_width(15);
90 CellRendererPixbufMulti* mute_col_renderer = manage (new CellRendererPixbufMulti());
92 mute_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
93 mute_col_renderer->set_pixbuf (1, ::get_icon("mute-enabled"));
94 mute_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_mute_enable_toggled));
96 TreeViewColumn* mute_state_column = manage (new TreeViewColumn("M", *mute_col_renderer));
98 mute_state_column->add_attribute(mute_col_renderer->property_state(), _columns.mute_state);
99 mute_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
100 mute_state_column->set_alignment(ALIGN_CENTER);
101 mute_state_column->set_expand(false);
102 mute_state_column->set_fixed_width(15);
104 // Solo enable toggle
105 CellRendererPixbufMulti* solo_col_renderer = manage (new CellRendererPixbufMulti());
107 solo_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
108 solo_col_renderer->set_pixbuf (1, ::get_icon("solo-enabled"));
109 solo_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_enable_toggled));
111 TreeViewColumn* solo_state_column = manage (new TreeViewColumn("S", *solo_col_renderer));
113 solo_state_column->add_attribute(solo_col_renderer->property_state(), _columns.solo_state);
114 solo_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
115 solo_state_column->set_alignment(ALIGN_CENTER);
116 solo_state_column->set_expand(false);
117 solo_state_column->set_fixed_width(15);
119 // Solo isolate toggle
120 CellRendererPixbufMulti* solo_iso_renderer = manage (new CellRendererPixbufMulti());
122 solo_iso_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
123 solo_iso_renderer->set_pixbuf (1, ::get_icon("solo-isolated"));
124 solo_iso_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_isolate_toggled));
126 TreeViewColumn* solo_isolate_state_column = manage (new TreeViewColumn("SI", *solo_iso_renderer));
128 solo_isolate_state_column->add_attribute(solo_iso_renderer->property_state(), _columns.solo_isolate_state);
129 solo_isolate_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
130 solo_isolate_state_column->set_alignment(ALIGN_CENTER);
131 solo_isolate_state_column->set_expand(false);
132 solo_isolate_state_column->set_fixed_width(15);
135 CellRendererPixbufMulti* solo_safe_renderer = manage (new CellRendererPixbufMulti ());
137 solo_safe_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
138 solo_safe_renderer->set_pixbuf (1, ::get_icon("solo-enabled"));
139 solo_safe_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_safe_toggled));
141 TreeViewColumn* solo_safe_state_column = manage (new TreeViewColumn(_("SS"), *solo_safe_renderer));
142 solo_safe_state_column->add_attribute(solo_safe_renderer->property_state(), _columns.solo_safe_state);
143 solo_safe_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
144 solo_safe_state_column->set_alignment(ALIGN_CENTER);
145 solo_safe_state_column->set_expand(false);
146 solo_safe_state_column->set_fixed_width(22);
148 _display.append_column (*rec_state_column);
149 _display.append_column (*mute_state_column);
150 _display.append_column (*solo_state_column);
151 _display.append_column (*solo_isolate_state_column);
152 _display.append_column (*solo_safe_state_column);
154 _display.append_column (_("Name"), _columns.text);
155 _display.append_column (_("V"), _columns.visible);
157 _display.set_headers_visible (true);
158 _display.set_name ("TrackListDisplay");
159 _display.get_selection()->set_mode (SELECTION_SINGLE);
160 _display.set_reorderable (true);
161 _display.set_rules_hint (true);
162 _display.set_size_request (100, -1);
163 _display.add_object_drag (_columns.route.index(), "routes");
165 CellRendererText* name_cell = dynamic_cast<CellRendererText*> (_display.get_column_cell_renderer (5));
169 TreeViewColumn* name_column = _display.get_column (5);
171 assert (name_column);
173 name_column->add_attribute (name_cell->property_editable(), _columns.name_editable);
174 name_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
175 name_column->set_expand(true);
176 name_column->set_min_width(50);
178 name_cell->property_editable() = true;
179 name_cell->signal_edited().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit));
181 // Set the visible column cell renderer to radio toggle
182 CellRendererToggle* visible_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (6));
184 visible_cell->property_activatable() = true;
185 visible_cell->property_radio() = false;
186 visible_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::visible_changed));
188 TreeViewColumn* visible_col = dynamic_cast<TreeViewColumn*> (_display.get_column (6));
189 visible_col->set_expand(false);
190 visible_col->set_sizing(TREE_VIEW_COLUMN_FIXED);
191 visible_col->set_fixed_width(30);
192 visible_col->set_alignment(ALIGN_CENTER);
194 _model->signal_row_deleted().connect (sigc::mem_fun (*this, &EditorRoutes::route_deleted));
195 _model->signal_rows_reordered().connect (sigc::mem_fun (*this, &EditorRoutes::reordered));
197 _display.signal_button_press_event().connect (sigc::mem_fun (*this, &EditorRoutes::button_press), false);
199 Route::SyncOrderKeys.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::sync_order_keys, this, _1), gui_context());
203 EditorRoutes::set_session (Session* s)
205 EditorComponent::set_session (s);
210 _session->SoloChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::solo_changed_so_update_mute, this), gui_context());
215 EditorRoutes::on_tv_rec_enable_toggled (Glib::ustring const & path_string)
217 // Get the model row that has been toggled.
218 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
220 TimeAxisView *tv = row[_columns.tv];
221 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
223 if (atv != 0 && atv->is_audio_track()){
224 boost::shared_ptr<RouteList> rl (new RouteList);
225 rl->push_back (atv->route());
226 _session->set_record_enable (rl, !atv->track()->record_enabled(), Session::rt_cleanup);
231 EditorRoutes::on_tv_mute_enable_toggled (Glib::ustring const & path_string)
233 // Get the model row that has been toggled.
234 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
236 TimeAxisView *tv = row[_columns.tv];
237 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
240 boost::shared_ptr<RouteList> rl (new RouteList);
241 rl->push_back (atv->route());
242 _session->set_mute (rl, !atv->route()->muted(), Session::rt_cleanup);
247 EditorRoutes::on_tv_solo_enable_toggled (Glib::ustring const & path_string)
249 // Get the model row that has been toggled.
250 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
252 TimeAxisView *tv = row[_columns.tv];
253 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
256 boost::shared_ptr<RouteList> rl (new RouteList);
257 rl->push_back (atv->route());
258 _session->set_solo (rl, !atv->route()->soloed(), Session::rt_cleanup);
263 EditorRoutes::on_tv_solo_isolate_toggled (Glib::ustring const & path_string)
265 // Get the model row that has been toggled.
266 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
268 TimeAxisView *tv = row[_columns.tv];
269 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
272 atv->route()->set_solo_isolated (!atv->route()->solo_isolated(), this);
277 EditorRoutes::on_tv_solo_safe_toggled (Glib::ustring const & path_string)
279 // Get the model row that has been toggled.
280 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
282 TimeAxisView *tv = row[_columns.tv];
283 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
286 atv->route()->set_solo_safe (!atv->route()->solo_safe(), this);
291 EditorRoutes::build_menu ()
293 using namespace Menu_Helpers;
298 MenuList& items = _menu->items();
299 _menu->set_name ("ArdourContextMenu");
301 items.push_back (MenuElem (_("Show All"), sigc::mem_fun (*this, &EditorRoutes::show_all_routes)));
302 items.push_back (MenuElem (_("Hide All"), sigc::mem_fun (*this, &EditorRoutes::hide_all_routes)));
303 items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiotracks)));
304 items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiotracks)));
305 items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiobus)));
306 items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiobus)));
307 items.push_back (MenuElem (_("Show Tracks With Regions Under Playhead"), sigc::mem_fun (*this, &EditorRoutes::show_tracks_with_regions_at_playhead)));
311 EditorRoutes::show_menu ()
317 _menu->popup (1, gtk_get_current_event_time());
321 EditorRoutes::redisplay ()
323 if (_no_redisplay || !_session) {
327 TreeModel::Children rows = _model->children();
328 TreeModel::Children::iterator i;
332 for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
333 TimeAxisView *tv = (*i)[_columns.tv];
334 boost::shared_ptr<Route> route = (*i)[_columns.route];
337 // just a "title" row
341 if (!_redisplay_does_not_reset_order_keys) {
342 /* this reorder is caused by user action, so reassign sort order keys
345 route->set_order_key (N_ ("editor"), n);
348 bool visible = (*i)[_columns.visible];
350 /* show or hide the TimeAxisView */
352 tv->set_marked_for_display (true);
353 position += tv->show_at (position, n, &_editor->edit_controls_vbox);
354 tv->clip_to_viewport ();
356 tv->set_marked_for_display (false);
363 /* whenever we go idle, update the track view list to reflect the new order.
364 we can't do this here, because we could mess up something that is traversing
365 the track order and has caused a redisplay of the list.
367 Glib::signal_idle().connect (sigc::mem_fun (*_editor, &Editor::sync_track_view_list_and_routes));
369 _editor->full_canvas_height = position + _editor->canvas_timebars_vsize;
370 _editor->vertical_adjustment.set_upper (_editor->full_canvas_height);
372 if ((_editor->vertical_adjustment.get_value() + _editor->_canvas_height) > _editor->vertical_adjustment.get_upper()) {
374 We're increasing the size of the canvas while the bottom is visible.
375 We scroll down to keep in step with the controls layout.
377 _editor->vertical_adjustment.set_value (_editor->full_canvas_height - _editor->_canvas_height);
380 if (!_redisplay_does_not_reset_order_keys && !_redisplay_does_not_sync_order_keys) {
381 _session->sync_order_keys (N_ ("editor"));
386 EditorRoutes::route_deleted (Gtk::TreeModel::Path const &)
388 if (!_session || _session->deletion_in_progress()) {
392 /* this could require an order reset & sync */
393 _session->set_remote_control_ids();
394 _ignore_reorder = true;
396 _ignore_reorder = false;
400 EditorRoutes::visible_changed (Glib::ustring const & path)
402 if (_session && _session->deletion_in_progress()) {
408 if ((iter = _model->get_iter (path))) {
409 TimeAxisView* tv = (*iter)[_columns.tv];
411 bool visible = (*iter)[_columns.visible];
412 (*iter)[_columns.visible] = !visible;
416 _redisplay_does_not_reset_order_keys = true;
417 _session->set_remote_control_ids();
419 _redisplay_does_not_reset_order_keys = false;
423 EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
427 _redisplay_does_not_sync_order_keys = true;
428 suspend_redisplay ();
430 for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) {
432 row = *(_model->append ());
434 row[_columns.text] = (*x)->route()->name();
435 row[_columns.visible] = (*x)->marked_for_display();
436 row[_columns.tv] = *x;
437 row[_columns.route] = (*x)->route ();
438 row[_columns.is_track] = (boost::dynamic_pointer_cast<Track> ((*x)->route()) != 0);
439 row[_columns.mute_state] = (*x)->route()->muted();
440 row[_columns.solo_state] = (*x)->route()->soloed();
441 row[_columns.solo_isolate_state] = (*x)->route()->solo_isolated();
442 row[_columns.solo_safe_state] = (*x)->route()->solo_safe();
443 row[_columns.name_editable] = true;
445 _ignore_reorder = true;
447 /* added a new fresh one at the end */
448 if ((*x)->route()->order_key (N_ ("editor")) == -1) {
449 (*x)->route()->set_order_key (N_ ("editor"), _model->children().size()-1);
452 _ignore_reorder = false;
454 boost::weak_ptr<Route> wr ((*x)->route());
456 (*x)->route()->gui_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
457 (*x)->route()->PropertyChanged.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::route_property_changed, this, _1, wr), gui_context());
459 if ((*x)->is_track()) {
460 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
461 t->diskstream()->RecordEnableChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
464 (*x)->route()->mute_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
465 (*x)->route()->solo_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_display, this), gui_context());
466 (*x)->route()->solo_isolated_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_isolate_display, this), gui_context());
467 (*x)->route()->solo_safe_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_safe_display, this), gui_context());
470 update_rec_display ();
471 update_mute_display ();
472 update_solo_display ();
473 update_solo_isolate_display ();
474 update_solo_safe_display ();
476 _redisplay_does_not_sync_order_keys = false;
480 EditorRoutes::handle_gui_changes (string const & what, void*)
482 ENSURE_GUI_THREAD (*this, &EditorRoutes::handle_gui_changes, what, src)
484 if (what == "track_height") {
485 /* Optional :make tracks change height while it happens, instead
488 //update_canvas_now ();
492 if (what == "visible_tracks") {
498 EditorRoutes::route_removed (TimeAxisView *tv)
500 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed, tv)
502 TreeModel::Children rows = _model->children();
503 TreeModel::Children::iterator ri;
505 /* the core model has changed, there is no need to sync
509 _redisplay_does_not_sync_order_keys = true;
511 for (ri = rows.begin(); ri != rows.end(); ++ri) {
512 if ((*ri)[_columns.tv] == tv) {
518 _redisplay_does_not_sync_order_keys = false;
522 EditorRoutes::route_property_changed (const PropertyChange& what_changed, boost::weak_ptr<Route> r)
524 if (!what_changed.contains (ARDOUR::Properties::name)) {
528 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_name_changed, r)
530 boost::shared_ptr<Route> route = r.lock ();
536 TreeModel::Children rows = _model->children();
537 TreeModel::Children::iterator i;
539 for (i = rows.begin(); i != rows.end(); ++i) {
540 boost::shared_ptr<Route> t = (*i)[_columns.route];
542 (*i)[_columns.text] = route->name();
549 EditorRoutes::update_visibility ()
551 TreeModel::Children rows = _model->children();
552 TreeModel::Children::iterator i;
554 suspend_redisplay ();
556 for (i = rows.begin(); i != rows.end(); ++i) {
557 TimeAxisView *tv = (*i)[_columns.tv];
558 (*i)[_columns.visible] = tv->marked_for_display ();
559 cerr << "marked " << tv->name() << " for display = " << tv->marked_for_display() << endl;
566 EditorRoutes::hide_track_in_display (TimeAxisView& tv)
568 TreeModel::Children rows = _model->children();
569 TreeModel::Children::iterator i;
571 for (i = rows.begin(); i != rows.end(); ++i) {
572 if ((*i)[_columns.tv] == &tv) {
573 (*i)[_columns.visible] = false;
580 EditorRoutes::show_track_in_display (TimeAxisView& tv)
582 TreeModel::Children rows = _model->children();
583 TreeModel::Children::iterator i;
585 for (i = rows.begin(); i != rows.end(); ++i) {
586 if ((*i)[_columns.tv] == &tv) {
587 (*i)[_columns.visible] = true;
594 EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
599 /** If src != "editor", take editor order keys from each route and use them to rearrange the
600 * route list so that the visual arrangement of routes matches the order keys from the routes.
603 EditorRoutes::sync_order_keys (string const & src)
605 vector<int> neworder;
606 TreeModel::Children rows = _model->children();
607 TreeModel::Children::iterator ri;
609 if (src == N_ ("editor") || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
613 for (ri = rows.begin(); ri != rows.end(); ++ri) {
614 neworder.push_back (0);
617 bool changed = false;
620 for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
621 boost::shared_ptr<Route> route = (*ri)[_columns.route];
624 int new_key = route->order_key (N_ ("editor"));
626 neworder[new_key] = old_key;
628 if (new_key != old_key) {
634 _redisplay_does_not_reset_order_keys = true;
635 _model->reorder (neworder);
636 _redisplay_does_not_reset_order_keys = false;
642 EditorRoutes::hide_all_tracks (bool /*with_select*/)
644 TreeModel::Children rows = _model->children();
645 TreeModel::Children::iterator i;
647 suspend_redisplay ();
649 for (i = rows.begin(); i != rows.end(); ++i) {
651 TreeModel::Row row = (*i);
652 TimeAxisView *tv = row[_columns.tv];
658 row[_columns.visible] = false;
663 /* XXX this seems like a hack and half, but its not clear where to put this
667 //reset_scrolling_region ();
671 EditorRoutes::set_all_tracks_visibility (bool yn)
673 TreeModel::Children rows = _model->children();
674 TreeModel::Children::iterator i;
676 suspend_redisplay ();
678 for (i = rows.begin(); i != rows.end(); ++i) {
680 TreeModel::Row row = (*i);
681 TimeAxisView* tv = row[_columns.tv];
687 (*i)[_columns.visible] = yn;
694 EditorRoutes::set_all_audio_visibility (int tracks, bool yn)
696 TreeModel::Children rows = _model->children();
697 TreeModel::Children::iterator i;
699 suspend_redisplay ();
701 for (i = rows.begin(); i != rows.end(); ++i) {
702 TreeModel::Row row = (*i);
703 TimeAxisView* tv = row[_columns.tv];
704 AudioTimeAxisView* atv;
710 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
713 (*i)[_columns.visible] = yn;
717 if (atv->is_audio_track()) {
718 (*i)[_columns.visible] = yn;
723 if (!atv->is_audio_track()) {
724 (*i)[_columns.visible] = yn;
735 EditorRoutes::hide_all_routes ()
737 set_all_tracks_visibility (false);
741 EditorRoutes::show_all_routes ()
743 set_all_tracks_visibility (true);
747 EditorRoutes::show_all_audiobus ()
749 set_all_audio_visibility (2, true);
752 EditorRoutes::hide_all_audiobus ()
754 set_all_audio_visibility (2, false);
758 EditorRoutes::show_all_audiotracks()
760 set_all_audio_visibility (1, true);
763 EditorRoutes::hide_all_audiotracks ()
765 set_all_audio_visibility (1, false);
769 EditorRoutes::button_press (GdkEventButton* ev)
771 if (Keyboard::is_context_menu_event (ev)) {
776 //Scroll editor canvas to selected track
777 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
779 TreeModel::Path path;
784 _display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y);
786 // Get the model row.
787 Gtk::TreeModel::Row row = *_model->get_iter (path);
789 TimeAxisView *tv = row[_columns.tv];
791 int y_pos = tv->y_position();
793 //Clamp the y pos so that we do not extend beyond the canvas full height.
794 if (_editor->full_canvas_height - y_pos < _editor->_canvas_height){
795 y_pos = _editor->full_canvas_height - _editor->_canvas_height;
798 //Only scroll to if the track is visible
800 _editor->reset_y_origin (y_pos);
808 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const &, bool)
813 struct EditorOrderRouteSorter {
814 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
815 /* use of ">" forces the correct sort order */
816 return a->order_key (N_ ("editor")) < b->order_key (N_ ("editor"));
821 EditorRoutes::initial_display ()
823 suspend_redisplay ();
831 boost::shared_ptr<RouteList> routes = _session->get_routes();
832 RouteList r (*routes);
833 EditorOrderRouteSorter sorter;
836 _editor->handle_new_route (r);
838 /* don't show master bus in a new session */
840 if (ARDOUR_UI::instance()->session_is_new ()) {
842 TreeModel::Children rows = _model->children();
843 TreeModel::Children::iterator i;
845 _no_redisplay = true;
847 for (i = rows.begin(); i != rows.end(); ++i) {
849 TimeAxisView *tv = (*i)[_columns.tv];
850 RouteTimeAxisView *rtv;
852 if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
853 if (rtv->route()->is_master()) {
854 _display.get_selection()->unselect (i);
859 _no_redisplay = false;
867 EditorRoutes::track_list_reorder (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &, int* /*new_order*/)
869 _redisplay_does_not_sync_order_keys = true;
870 _session->set_remote_control_ids();
872 _redisplay_does_not_sync_order_keys = false;
876 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
878 const SelectionData& data,
879 guint info, guint time)
881 if (data.get_target() == "GTK_TREE_MODEL_ROW") {
882 _display.on_drag_data_received (context, x, y, data, info, time);
886 context->drag_finish (true, false, time);
890 EditorRoutes::move_selected_tracks (bool up)
892 if (_editor->selection->tracks.empty()) {
896 typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
897 std::list<ViewRoute> view_routes;
898 std::vector<int> neworder;
899 TreeModel::Children rows = _model->children();
900 TreeModel::Children::iterator ri;
902 for (ri = rows.begin(); ri != rows.end(); ++ri) {
903 TimeAxisView* tv = (*ri)[_columns.tv];
904 boost::shared_ptr<Route> route = (*ri)[_columns.route];
906 view_routes.push_back (ViewRoute (tv, route));
909 list<ViewRoute>::iterator trailing;
910 list<ViewRoute>::iterator leading;
914 trailing = view_routes.begin();
915 leading = view_routes.begin();
919 while (leading != view_routes.end()) {
920 if (_editor->selection->selected (leading->first)) {
921 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
922 leading = view_routes.erase (leading);
931 /* if we could use reverse_iterator in list::insert, this code
932 would be a beautiful reflection of the code above. but we can't
933 and so it looks like a bit of a mess.
936 trailing = view_routes.end();
937 leading = view_routes.end();
939 --leading; if (leading == view_routes.begin()) { return; }
945 if (_editor->selection->selected (leading->first)) {
946 list<ViewRoute>::iterator tmp;
948 /* need to insert *after* trailing, not *before* it,
949 which is what insert (iter, val) normally does.
955 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
957 /* can't use iter = cont.erase (iter); form here, because
958 we need iter to move backwards.
966 if (leading == view_routes.begin()) {
967 /* the one we've just inserted somewhere else
968 was the first in the list. erase this copy,
969 and then break, because we're done.
974 view_routes.erase (leading);
983 if (leading == view_routes.begin()) {
992 for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
993 neworder.push_back (leading->second->order_key (N_ ("editor")));
996 _model->reorder (neworder);
998 _session->sync_order_keys (N_ ("editor"));
1002 EditorRoutes::update_rec_display ()
1004 TreeModel::Children rows = _model->children();
1005 TreeModel::Children::iterator i;
1007 for (i = rows.begin(); i != rows.end(); ++i) {
1008 boost::shared_ptr<Route> route = (*i)[_columns.route];
1010 if (boost::dynamic_pointer_cast<Track>(route)) {
1011 (*i)[_columns.rec_enabled] = route->record_enabled ();
1012 (*i)[_columns.name_editable] = !route->record_enabled ();
1018 EditorRoutes::update_mute_display ()
1020 TreeModel::Children rows = _model->children();
1021 TreeModel::Children::iterator i;
1023 for (i = rows.begin(); i != rows.end(); ++i) {
1024 boost::shared_ptr<Route> route = (*i)[_columns.route];
1025 (*i)[_columns.mute_state] = RouteUI::mute_visual_state (_session, route) > 0 ? 1 : 0;
1030 EditorRoutes::update_solo_display ()
1032 TreeModel::Children rows = _model->children();
1033 TreeModel::Children::iterator i;
1035 for (i = rows.begin(); i != rows.end(); ++i) {
1036 boost::shared_ptr<Route> route = (*i)[_columns.route];
1037 (*i)[_columns.solo_state] = RouteUI::solo_visual_state (route) > 0 ? 1 : 0;
1042 EditorRoutes::update_solo_isolate_display ()
1044 TreeModel::Children rows = _model->children();
1045 TreeModel::Children::iterator i;
1047 for (i = rows.begin(); i != rows.end(); ++i) {
1048 boost::shared_ptr<Route> route = (*i)[_columns.route];
1049 (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_visual_state (route) > 0 ? 1 : 0;
1054 EditorRoutes::update_solo_safe_display ()
1056 TreeModel::Children rows = _model->children();
1057 TreeModel::Children::iterator i;
1059 for (i = rows.begin(); i != rows.end(); ++i) {
1060 boost::shared_ptr<Route> route = (*i)[_columns.route];
1061 (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_visual_state (route) > 0 ? 1 : 0;
1066 EditorRoutes::views () const
1068 list<TimeAxisView*> v;
1069 for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
1070 v.push_back ((*i)[_columns.tv]);
1077 EditorRoutes::clear ()
1079 _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1081 _display.set_model (_model);
1085 EditorRoutes::name_edit (Glib::ustring const & path, Glib::ustring const & new_text)
1087 TreeIter iter = _model->get_iter (path);
1092 boost::shared_ptr<Route> route = (*iter)[_columns.route];
1094 if (route && route->name() != new_text) {
1095 route->set_name (new_text);
1100 EditorRoutes::solo_changed_so_update_mute ()
1102 ENSURE_GUI_THREAD (*this, &EditorRoutes::solo_changed_so_update_mute)
1103 update_mute_display ();
1107 EditorRoutes::show_tracks_with_regions_at_playhead ()
1109 boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
1111 set<TimeAxisView*> show;
1112 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
1113 TimeAxisView* tav = _editor->axis_view_from_route (*i);
1119 suspend_redisplay ();
1121 TreeModel::Children rows = _model->children ();
1122 for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
1123 TimeAxisView* tv = (*i)[_columns.tv];
1124 (*i)[_columns.visible] = (show.find (tv) != show.end());
1127 resume_redisplay ();