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"
48 #include "gtkmm2ext/treeutils.h"
53 using namespace ARDOUR;
56 using namespace Gtkmm2ext;
58 using Gtkmm2ext::Keyboard;
60 EditorRoutes::EditorRoutes (Editor* e)
62 , _ignore_reorder (false)
63 , _no_redisplay (false)
64 , _redisplay_does_not_sync_order_keys (false)
65 , _redisplay_does_not_reset_order_keys (false)
68 , selection_countdown (0)
71 _scroller.add (_display);
72 _scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
74 _model = ListStore::create (_columns);
75 _display.set_model (_model);
77 // Record enable toggle
78 CellRendererPixbufMulti* rec_col_renderer = manage (new CellRendererPixbufMulti());
80 rec_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
81 rec_col_renderer->set_pixbuf (1, ::get_icon("rec-in-progress"));
82 rec_col_renderer->set_pixbuf (2, ::get_icon("rec-enabled"));
83 rec_col_renderer->set_pixbuf (3, ::get_icon("step-editing"));
84 rec_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_rec_enable_changed));
86 TreeViewColumn* rec_state_column = manage (new TreeViewColumn("R", *rec_col_renderer));
88 rec_state_column->add_attribute(rec_col_renderer->property_state(), _columns.rec_state);
89 rec_state_column->add_attribute(rec_col_renderer->property_visible(), _columns.is_track);
90 rec_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
91 rec_state_column->set_alignment(ALIGN_CENTER);
92 rec_state_column->set_expand(false);
93 rec_state_column->set_fixed_width(15);
96 CellRendererPixbufMulti* mute_col_renderer = manage (new CellRendererPixbufMulti());
98 mute_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
99 mute_col_renderer->set_pixbuf (1, ::get_icon("muted-by-others"));
100 mute_col_renderer->set_pixbuf (2, ::get_icon("mute-enabled"));
101 mute_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_mute_enable_toggled));
103 TreeViewColumn* mute_state_column = manage (new TreeViewColumn("M", *mute_col_renderer));
105 mute_state_column->add_attribute(mute_col_renderer->property_state(), _columns.mute_state);
106 mute_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
107 mute_state_column->set_alignment(ALIGN_CENTER);
108 mute_state_column->set_expand(false);
109 mute_state_column->set_fixed_width(15);
111 // Solo enable toggle
112 CellRendererPixbufMulti* solo_col_renderer = manage (new CellRendererPixbufMulti());
114 solo_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
115 solo_col_renderer->set_pixbuf (1, ::get_icon("solo-enabled"));
116 solo_col_renderer->set_pixbuf (3, ::get_icon("soloed-by-others"));
117 solo_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_enable_toggled));
119 TreeViewColumn* solo_state_column = manage (new TreeViewColumn("S", *solo_col_renderer));
121 solo_state_column->add_attribute(solo_col_renderer->property_state(), _columns.solo_state);
122 solo_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
123 solo_state_column->set_alignment(ALIGN_CENTER);
124 solo_state_column->set_expand(false);
125 solo_state_column->set_fixed_width(15);
127 // Solo isolate toggle
128 CellRendererPixbufMulti* solo_iso_renderer = manage (new CellRendererPixbufMulti());
130 solo_iso_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
131 solo_iso_renderer->set_pixbuf (1, ::get_icon("solo-isolated"));
132 solo_iso_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_isolate_toggled));
134 TreeViewColumn* solo_isolate_state_column = manage (new TreeViewColumn("SI", *solo_iso_renderer));
136 solo_isolate_state_column->add_attribute(solo_iso_renderer->property_state(), _columns.solo_isolate_state);
137 solo_isolate_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
138 solo_isolate_state_column->set_alignment(ALIGN_CENTER);
139 solo_isolate_state_column->set_expand(false);
140 solo_isolate_state_column->set_fixed_width(15);
143 CellRendererPixbufMulti* solo_safe_renderer = manage (new CellRendererPixbufMulti ());
145 solo_safe_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
146 solo_safe_renderer->set_pixbuf (1, ::get_icon("solo-enabled"));
147 solo_safe_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_safe_toggled));
149 TreeViewColumn* solo_safe_state_column = manage (new TreeViewColumn(_("SS"), *solo_safe_renderer));
150 solo_safe_state_column->add_attribute(solo_safe_renderer->property_state(), _columns.solo_safe_state);
151 solo_safe_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
152 solo_safe_state_column->set_alignment(ALIGN_CENTER);
153 solo_safe_state_column->set_expand(false);
154 solo_safe_state_column->set_fixed_width(22);
156 _display.append_column (*rec_state_column);
157 _display.append_column (*mute_state_column);
158 _display.append_column (*solo_state_column);
159 _display.append_column (*solo_isolate_state_column);
160 _display.append_column (*solo_safe_state_column);
162 int colnum = _display.append_column (_("Name"), _columns.text);
163 TreeViewColumn* c = _display.get_column (colnum-1);
164 c->set_data ("i_am_the_tab_column", (void*) 0xfeedface);
165 _display.append_column (_("V"), _columns.visible);
167 _display.set_headers_visible (true);
168 _display.set_name ("TrackListDisplay");
169 _display.get_selection()->set_mode (SELECTION_SINGLE);
170 _display.get_selection()->set_select_function (sigc::mem_fun (*this, &EditorRoutes::selection_filter));
171 _display.set_reorderable (true);
172 _display.set_rules_hint (true);
173 _display.set_size_request (100, -1);
174 _display.add_object_drag (_columns.route.index(), "routes");
176 CellRendererText* name_cell = dynamic_cast<CellRendererText*> (_display.get_column_cell_renderer (5));
179 name_cell->signal_editing_started().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit_started));
181 TreeViewColumn* name_column = _display.get_column (5);
183 assert (name_column);
185 name_column->add_attribute (name_cell->property_editable(), _columns.name_editable);
186 name_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
187 name_column->set_expand(true);
188 name_column->set_min_width(50);
190 name_cell->property_editable() = true;
191 name_cell->signal_edited().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit));
193 // Set the visible column cell renderer to radio toggle
194 CellRendererToggle* visible_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (6));
196 visible_cell->property_activatable() = true;
197 visible_cell->property_radio() = false;
198 visible_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::visible_changed));
200 TreeViewColumn* visible_col = dynamic_cast<TreeViewColumn*> (_display.get_column (6));
201 visible_col->set_expand(false);
202 visible_col->set_sizing(TREE_VIEW_COLUMN_FIXED);
203 visible_col->set_fixed_width(30);
204 visible_col->set_alignment(ALIGN_CENTER);
206 _model->signal_row_deleted().connect (sigc::mem_fun (*this, &EditorRoutes::route_deleted));
207 _model->signal_rows_reordered().connect (sigc::mem_fun (*this, &EditorRoutes::reordered));
209 _display.signal_button_press_event().connect (sigc::mem_fun (*this, &EditorRoutes::button_press), false);
210 _scroller.signal_key_press_event().connect (sigc::mem_fun(*this, &EditorRoutes::key_press), false);
212 _scroller.signal_focus_in_event().connect (sigc::mem_fun (*this, &EditorRoutes::focus_in), false);
213 _scroller.signal_focus_out_event().connect (sigc::mem_fun (*this, &EditorRoutes::focus_out));
215 _display.signal_enter_notify_event().connect (sigc::mem_fun (*this, &EditorRoutes::enter_notify), false);
216 _display.signal_leave_notify_event().connect (sigc::mem_fun (*this, &EditorRoutes::leave_notify), false);
218 _display.set_enable_search (false);
220 Route::SyncOrderKeys.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::sync_order_keys, this, _1), gui_context());
224 EditorRoutes::focus_in (GdkEventFocus*)
226 Window* win = dynamic_cast<Window*> (_scroller.get_toplevel ());
229 old_focus = win->get_focus ();
234 /* try to do nothing on focus in (doesn't work, hence selection_count nonsense) */
239 EditorRoutes::focus_out (GdkEventFocus*)
242 old_focus->grab_focus ();
250 EditorRoutes::enter_notify (GdkEventCrossing* ev)
252 /* arm counter so that ::selection_filter() will deny selecting anything for the
253 next two attempts to change selection status.
255 selection_countdown = 2;
256 _scroller.grab_focus ();
257 Keyboard::magic_widget_grab_focus ();
262 EditorRoutes::leave_notify (GdkEventCrossing*)
264 selection_countdown = 0;
267 old_focus->grab_focus ();
271 Keyboard::magic_widget_drop_focus ();
276 EditorRoutes::set_session (Session* s)
278 SessionHandlePtr::set_session (s);
283 _session->SoloChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::solo_changed_so_update_mute, this), gui_context());
284 _session->RecordStateChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
289 EditorRoutes::on_tv_rec_enable_changed (std::string const & path_string)
291 // Get the model row that has been toggled.
292 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
294 TimeAxisView *tv = row[_columns.tv];
295 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
297 if (atv != 0 && atv->is_audio_track()){
298 boost::shared_ptr<RouteList> rl (new RouteList);
299 rl->push_back (atv->route());
300 _session->set_record_enabled (rl, !atv->track()->record_enabled(), Session::rt_cleanup);
305 EditorRoutes::on_tv_mute_enable_toggled (std::string const & path_string)
307 // Get the model row that has been toggled.
308 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
310 TimeAxisView *tv = row[_columns.tv];
311 RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
314 boost::shared_ptr<RouteList> rl (new RouteList);
315 rl->push_back (rtv->route());
316 _session->set_mute (rl, !rtv->route()->muted(), Session::rt_cleanup);
321 EditorRoutes::on_tv_solo_enable_toggled (std::string const & path_string)
323 // Get the model row that has been toggled.
324 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
326 TimeAxisView *tv = row[_columns.tv];
327 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
330 boost::shared_ptr<RouteList> rl (new RouteList);
331 rl->push_back (atv->route());
332 _session->set_solo (rl, !atv->route()->soloed(), Session::rt_cleanup);
337 EditorRoutes::on_tv_solo_isolate_toggled (std::string const & path_string)
339 // Get the model row that has been toggled.
340 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
342 TimeAxisView *tv = row[_columns.tv];
343 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
346 atv->route()->set_solo_isolated (!atv->route()->solo_isolated(), this);
351 EditorRoutes::on_tv_solo_safe_toggled (std::string const & path_string)
353 // Get the model row that has been toggled.
354 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
356 TimeAxisView *tv = row[_columns.tv];
357 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
360 atv->route()->set_solo_safe (!atv->route()->solo_safe(), this);
365 EditorRoutes::build_menu ()
367 using namespace Menu_Helpers;
372 MenuList& items = _menu->items();
373 _menu->set_name ("ArdourContextMenu");
375 items.push_back (MenuElem (_("Show All"), sigc::mem_fun (*this, &EditorRoutes::show_all_routes)));
376 items.push_back (MenuElem (_("Hide All"), sigc::mem_fun (*this, &EditorRoutes::hide_all_routes)));
377 items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiotracks)));
378 items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiotracks)));
379 items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiobus)));
380 items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiobus)));
381 items.push_back (MenuElem (_("Show All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_miditracks)));
382 items.push_back (MenuElem (_("Hide All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_miditracks)));
383 items.push_back (MenuElem (_("Show Tracks With Regions Under Playhead"), sigc::mem_fun (*this, &EditorRoutes::show_tracks_with_regions_at_playhead)));
387 EditorRoutes::show_menu ()
393 _menu->popup (1, gtk_get_current_event_time());
397 EditorRoutes::redisplay ()
399 if (_no_redisplay || !_session) {
403 TreeModel::Children rows = _model->children();
404 TreeModel::Children::iterator i;
408 for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
409 TimeAxisView *tv = (*i)[_columns.tv];
410 boost::shared_ptr<Route> route = (*i)[_columns.route];
413 // just a "title" row
417 if (!_redisplay_does_not_reset_order_keys) {
418 /* this reorder is caused by user action, so reassign sort order keys
421 route->set_order_key (N_ ("editor"), n);
424 bool visible = (*i)[_columns.visible];
426 /* show or hide the TimeAxisView */
428 tv->set_marked_for_display (true);
429 position += tv->show_at (position, n, &_editor->edit_controls_vbox);
430 tv->clip_to_viewport ();
432 tv->set_marked_for_display (false);
439 /* whenever we go idle, update the track view list to reflect the new order.
440 we can't do this here, because we could mess up something that is traversing
441 the track order and has caused a redisplay of the list.
443 Glib::signal_idle().connect (sigc::mem_fun (*_editor, &Editor::sync_track_view_list_and_routes));
445 _editor->full_canvas_height = position + _editor->canvas_timebars_vsize;
446 _editor->vertical_adjustment.set_upper (_editor->full_canvas_height);
448 if ((_editor->vertical_adjustment.get_value() + _editor->_canvas_height) > _editor->vertical_adjustment.get_upper()) {
450 We're increasing the size of the canvas while the bottom is visible.
451 We scroll down to keep in step with the controls layout.
453 _editor->vertical_adjustment.set_value (_editor->full_canvas_height - _editor->_canvas_height);
456 if (!_redisplay_does_not_reset_order_keys && !_redisplay_does_not_sync_order_keys) {
457 _session->sync_order_keys (N_ ("editor"));
462 EditorRoutes::route_deleted (Gtk::TreeModel::Path const &)
464 if (!_session || _session->deletion_in_progress()) {
468 /* this could require an order reset & sync */
469 _session->set_remote_control_ids();
470 _ignore_reorder = true;
472 _ignore_reorder = false;
476 EditorRoutes::visible_changed (std::string const & path)
478 if (_session && _session->deletion_in_progress()) {
484 if ((iter = _model->get_iter (path))) {
485 TimeAxisView* tv = (*iter)[_columns.tv];
487 bool visible = (*iter)[_columns.visible];
488 (*iter)[_columns.visible] = !visible;
492 _redisplay_does_not_reset_order_keys = true;
493 _session->set_remote_control_ids();
495 _redisplay_does_not_reset_order_keys = false;
499 EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
503 _redisplay_does_not_sync_order_keys = true;
504 suspend_redisplay ();
506 for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) {
508 row = *(_model->append ());
510 row[_columns.text] = (*x)->route()->name();
511 row[_columns.visible] = (*x)->marked_for_display();
512 row[_columns.tv] = *x;
513 row[_columns.route] = (*x)->route ();
514 row[_columns.is_track] = (boost::dynamic_pointer_cast<Track> ((*x)->route()) != 0);
515 row[_columns.mute_state] = (*x)->route()->muted();
516 row[_columns.solo_state] = (*x)->route()->soloed();
517 row[_columns.solo_isolate_state] = (*x)->route()->solo_isolated();
518 row[_columns.solo_safe_state] = (*x)->route()->solo_safe();
519 row[_columns.name_editable] = true;
521 _ignore_reorder = true;
523 /* added a new fresh one at the end */
524 if ((*x)->route()->order_key (N_ ("editor")) == -1) {
525 (*x)->route()->set_order_key (N_ ("editor"), _model->children().size()-1);
528 _ignore_reorder = false;
530 boost::weak_ptr<Route> wr ((*x)->route());
532 (*x)->route()->gui_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
533 (*x)->route()->PropertyChanged.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::route_property_changed, this, _1, wr), gui_context());
535 if ((*x)->is_track()) {
536 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
537 t->RecordEnableChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
540 if ((*x)->is_midi_track()) {
541 boost::shared_ptr<MidiTrack> t = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
542 t->StepEditStatusChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
545 (*x)->route()->mute_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
546 (*x)->route()->solo_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
547 (*x)->route()->solo_isolated_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_isolate_display, this), gui_context());
548 (*x)->route()->solo_safe_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_safe_display, this), gui_context());
551 update_rec_display ();
552 update_mute_display ();
553 update_solo_display (true);
554 update_solo_isolate_display ();
555 update_solo_safe_display ();
557 _redisplay_does_not_sync_order_keys = false;
561 EditorRoutes::handle_gui_changes (string const & what, void*)
563 ENSURE_GUI_THREAD (*this, &EditorRoutes::handle_gui_changes, what, src)
565 if (what == "track_height") {
566 /* Optional :make tracks change height while it happens, instead
569 //update_canvas_now ();
573 if (what == "visible_tracks") {
579 EditorRoutes::route_removed (TimeAxisView *tv)
581 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed, tv)
583 TreeModel::Children rows = _model->children();
584 TreeModel::Children::iterator ri;
586 /* the core model has changed, there is no need to sync
590 _redisplay_does_not_sync_order_keys = true;
592 for (ri = rows.begin(); ri != rows.end(); ++ri) {
593 if ((*ri)[_columns.tv] == tv) {
599 _redisplay_does_not_sync_order_keys = false;
603 EditorRoutes::route_property_changed (const PropertyChange& what_changed, boost::weak_ptr<Route> r)
605 if (!what_changed.contains (ARDOUR::Properties::name)) {
609 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_name_changed, r)
611 boost::shared_ptr<Route> route = r.lock ();
617 TreeModel::Children rows = _model->children();
618 TreeModel::Children::iterator i;
620 for (i = rows.begin(); i != rows.end(); ++i) {
621 boost::shared_ptr<Route> t = (*i)[_columns.route];
623 (*i)[_columns.text] = route->name();
630 EditorRoutes::update_visibility ()
632 TreeModel::Children rows = _model->children();
633 TreeModel::Children::iterator i;
635 suspend_redisplay ();
637 for (i = rows.begin(); i != rows.end(); ++i) {
638 TimeAxisView *tv = (*i)[_columns.tv];
639 (*i)[_columns.visible] = tv->marked_for_display ();
640 cerr << "marked " << tv->name() << " for display = " << tv->marked_for_display() << endl;
647 EditorRoutes::hide_track_in_display (TimeAxisView& tv)
649 TreeModel::Children rows = _model->children();
650 TreeModel::Children::iterator i;
652 for (i = rows.begin(); i != rows.end(); ++i) {
653 if ((*i)[_columns.tv] == &tv) {
654 (*i)[_columns.visible] = false;
663 EditorRoutes::show_track_in_display (TimeAxisView& tv)
665 TreeModel::Children rows = _model->children();
666 TreeModel::Children::iterator i;
668 for (i = rows.begin(); i != rows.end(); ++i) {
669 if ((*i)[_columns.tv] == &tv) {
670 (*i)[_columns.visible] = true;
679 EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
684 /** If src != "editor", take editor order keys from each route and use them to rearrange the
685 * route list so that the visual arrangement of routes matches the order keys from the routes.
688 EditorRoutes::sync_order_keys (string const & src)
690 vector<int> neworder;
691 TreeModel::Children rows = _model->children();
692 TreeModel::Children::iterator ri;
694 if (src == N_ ("editor") || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
698 for (ri = rows.begin(); ri != rows.end(); ++ri) {
699 neworder.push_back (0);
702 bool changed = false;
705 for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
706 boost::shared_ptr<Route> route = (*ri)[_columns.route];
709 int new_key = route->order_key (N_ ("editor"));
711 neworder[new_key] = old_key;
713 if (new_key != old_key) {
719 _redisplay_does_not_reset_order_keys = true;
720 _model->reorder (neworder);
721 _redisplay_does_not_reset_order_keys = false;
727 EditorRoutes::hide_all_tracks (bool /*with_select*/)
729 TreeModel::Children rows = _model->children();
730 TreeModel::Children::iterator i;
732 suspend_redisplay ();
734 for (i = rows.begin(); i != rows.end(); ++i) {
736 TreeModel::Row row = (*i);
737 TimeAxisView *tv = row[_columns.tv];
743 row[_columns.visible] = false;
748 /* XXX this seems like a hack and half, but its not clear where to put this
752 //reset_scrolling_region ();
756 EditorRoutes::set_all_tracks_visibility (bool yn)
758 TreeModel::Children rows = _model->children();
759 TreeModel::Children::iterator i;
761 suspend_redisplay ();
763 for (i = rows.begin(); i != rows.end(); ++i) {
765 TreeModel::Row row = (*i);
766 TimeAxisView* tv = row[_columns.tv];
772 (*i)[_columns.visible] = yn;
779 EditorRoutes::set_all_audio_midi_visibility (int tracks, bool yn)
781 TreeModel::Children rows = _model->children();
782 TreeModel::Children::iterator i;
784 suspend_redisplay ();
786 for (i = rows.begin(); i != rows.end(); ++i) {
788 TreeModel::Row row = (*i);
789 TimeAxisView* tv = row[_columns.tv];
791 AudioTimeAxisView* atv;
792 MidiTimeAxisView* mtv;
798 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
801 (*i)[_columns.visible] = yn;
805 if (atv->is_audio_track()) {
806 (*i)[_columns.visible] = yn;
811 if (!atv->is_audio_track()) {
812 (*i)[_columns.visible] = yn;
817 else if ((mtv = dynamic_cast<MidiTimeAxisView*>(tv)) != 0) {
820 (*i)[_columns.visible] = yn;
824 if (mtv->is_midi_track()) {
825 (*i)[_columns.visible] = yn;
836 EditorRoutes::hide_all_routes ()
838 set_all_tracks_visibility (false);
842 EditorRoutes::show_all_routes ()
844 set_all_tracks_visibility (true);
848 EditorRoutes::show_all_audiotracks()
850 set_all_audio_midi_visibility (1, true);
853 EditorRoutes::hide_all_audiotracks ()
855 set_all_audio_midi_visibility (1, false);
859 EditorRoutes::show_all_audiobus ()
861 set_all_audio_midi_visibility (2, true);
864 EditorRoutes::hide_all_audiobus ()
866 set_all_audio_midi_visibility (2, false);
870 EditorRoutes::show_all_miditracks()
872 set_all_audio_midi_visibility (3, true);
875 EditorRoutes::hide_all_miditracks ()
877 set_all_audio_midi_visibility (3, false);
881 EditorRoutes::key_press (GdkEventKey* ev)
884 boost::shared_ptr<RouteList> rl (new RouteList);
887 cerr << "our key press\n";
889 switch (ev->keyval) {
891 case GDK_ISO_Left_Tab:
893 /* If we appear to be editing something, leave that cleanly and appropriately.
896 name_editable->editing_done ();
900 col = _display.get_column (5); // select&focus on name column
902 if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
903 treeview_select_previous (_display, _model, col);
905 treeview_select_next (_display, _model, col);
912 if (get_relevant_routes (rl)) {
913 _session->set_mute (rl, !rl->front()->muted(), Session::rt_cleanup);
919 if (get_relevant_routes (rl)) {
920 _session->set_solo (rl, !rl->front()->soloed(), Session::rt_cleanup);
926 if (get_relevant_routes (rl)) {
927 _session->set_record_enabled (rl, !rl->front()->record_enabled(), Session::rt_cleanup);
939 EditorRoutes::get_relevant_routes (boost::shared_ptr<RouteList> rl)
942 RouteTimeAxisView* rtv;
943 RefPtr<TreeSelection> selection = _display.get_selection();
947 if (selection->count_selected_rows() != 0) {
951 RefPtr<TreeModel> tm = RefPtr<TreeModel>::cast_dynamic (_model);
952 iter = selection->get_selected (tm);
955 /* use mouse pointer */
960 _display.get_pointer (x, y);
961 _display.convert_widget_to_bin_window_coords (x, y, bx, by);
963 if (_display.get_path_at_pos (bx, by, path)) {
964 iter = _model->get_iter (path);
969 tv = (*iter)[_columns.tv];
971 rtv = dynamic_cast<RouteTimeAxisView*>(tv);
973 rl->push_back (rtv->route());
982 EditorRoutes::button_press (GdkEventButton* ev)
984 if (Keyboard::is_context_menu_event (ev)) {
989 //Scroll editor canvas to selected track
990 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
992 TreeModel::Path path;
997 _display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y);
999 // Get the model row.
1000 Gtk::TreeModel::Row row = *_model->get_iter (path);
1002 TimeAxisView *tv = row[_columns.tv];
1004 int y_pos = tv->y_position();
1006 //Clamp the y pos so that we do not extend beyond the canvas full height.
1007 if (_editor->full_canvas_height - y_pos < _editor->_canvas_height){
1008 y_pos = _editor->full_canvas_height - _editor->_canvas_height;
1011 //Only scroll to if the track is visible
1013 _editor->reset_y_origin (y_pos);
1021 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const &path , bool selected)
1023 if (selection_countdown) {
1024 if (--selection_countdown == 0) {
1027 /* no selection yet ... */
1034 struct EditorOrderRouteSorter {
1035 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1036 /* use of ">" forces the correct sort order */
1037 return a->order_key (N_ ("editor")) < b->order_key (N_ ("editor"));
1042 EditorRoutes::initial_display ()
1044 suspend_redisplay ();
1048 resume_redisplay ();
1052 boost::shared_ptr<RouteList> routes = _session->get_routes();
1053 RouteList r (*routes);
1054 EditorOrderRouteSorter sorter;
1057 _editor->handle_new_route (r);
1059 /* don't show master bus in a new session */
1061 if (ARDOUR_UI::instance()->session_is_new ()) {
1063 TreeModel::Children rows = _model->children();
1064 TreeModel::Children::iterator i;
1066 _no_redisplay = true;
1068 for (i = rows.begin(); i != rows.end(); ++i) {
1070 TimeAxisView *tv = (*i)[_columns.tv];
1071 RouteTimeAxisView *rtv;
1073 if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
1074 if (rtv->route()->is_master()) {
1075 _display.get_selection()->unselect (i);
1080 _no_redisplay = false;
1084 resume_redisplay ();
1088 EditorRoutes::track_list_reorder (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &, int* /*new_order*/)
1090 _redisplay_does_not_sync_order_keys = true;
1091 _session->set_remote_control_ids();
1093 _redisplay_does_not_sync_order_keys = false;
1097 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
1099 const SelectionData& data,
1100 guint info, guint time)
1102 if (data.get_target() == "GTK_TREE_MODEL_ROW") {
1103 _display.on_drag_data_received (context, x, y, data, info, time);
1107 context->drag_finish (true, false, time);
1111 EditorRoutes::move_selected_tracks (bool up)
1113 if (_editor->selection->tracks.empty()) {
1117 typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
1118 std::list<ViewRoute> view_routes;
1119 std::vector<int> neworder;
1120 TreeModel::Children rows = _model->children();
1121 TreeModel::Children::iterator ri;
1123 for (ri = rows.begin(); ri != rows.end(); ++ri) {
1124 TimeAxisView* tv = (*ri)[_columns.tv];
1125 boost::shared_ptr<Route> route = (*ri)[_columns.route];
1127 view_routes.push_back (ViewRoute (tv, route));
1130 list<ViewRoute>::iterator trailing;
1131 list<ViewRoute>::iterator leading;
1135 trailing = view_routes.begin();
1136 leading = view_routes.begin();
1140 while (leading != view_routes.end()) {
1141 if (_editor->selection->selected (leading->first)) {
1142 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
1143 leading = view_routes.erase (leading);
1152 /* if we could use reverse_iterator in list::insert, this code
1153 would be a beautiful reflection of the code above. but we can't
1154 and so it looks like a bit of a mess.
1157 trailing = view_routes.end();
1158 leading = view_routes.end();
1160 --leading; if (leading == view_routes.begin()) { return; }
1166 if (_editor->selection->selected (leading->first)) {
1167 list<ViewRoute>::iterator tmp;
1169 /* need to insert *after* trailing, not *before* it,
1170 which is what insert (iter, val) normally does.
1176 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
1178 /* can't use iter = cont.erase (iter); form here, because
1179 we need iter to move backwards.
1187 if (leading == view_routes.begin()) {
1188 /* the one we've just inserted somewhere else
1189 was the first in the list. erase this copy,
1190 and then break, because we're done.
1195 view_routes.erase (leading);
1204 if (leading == view_routes.begin()) {
1213 for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
1214 neworder.push_back (leading->second->order_key (N_ ("editor")));
1217 _model->reorder (neworder);
1219 _session->sync_order_keys (N_ ("editor"));
1223 EditorRoutes::update_rec_display ()
1225 TreeModel::Children rows = _model->children();
1226 TreeModel::Children::iterator i;
1228 for (i = rows.begin(); i != rows.end(); ++i) {
1229 boost::shared_ptr<Route> route = (*i)[_columns.route];
1231 if (boost::dynamic_pointer_cast<Track> (route)) {
1232 boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
1234 if (route->record_enabled()) {
1235 if (_session->record_status() == Session::Recording) {
1236 (*i)[_columns.rec_state] = 1;
1238 (*i)[_columns.rec_state] = 2;
1240 } else if (mt && mt->step_editing()) {
1241 (*i)[_columns.rec_state] = 3;
1243 (*i)[_columns.rec_state] = 0;
1246 (*i)[_columns.name_editable] = !route->record_enabled ();
1252 EditorRoutes::update_mute_display ()
1254 TreeModel::Children rows = _model->children();
1255 TreeModel::Children::iterator i;
1257 for (i = rows.begin(); i != rows.end(); ++i) {
1258 boost::shared_ptr<Route> route = (*i)[_columns.route];
1259 (*i)[_columns.mute_state] = RouteUI::mute_visual_state (_session, route);
1264 EditorRoutes::update_solo_display (bool /* selfsoloed */)
1266 TreeModel::Children rows = _model->children();
1267 TreeModel::Children::iterator i;
1269 for (i = rows.begin(); i != rows.end(); ++i) {
1270 boost::shared_ptr<Route> route = (*i)[_columns.route];
1271 (*i)[_columns.solo_state] = RouteUI::solo_visual_state (route);
1276 EditorRoutes::update_solo_isolate_display ()
1278 TreeModel::Children rows = _model->children();
1279 TreeModel::Children::iterator i;
1281 for (i = rows.begin(); i != rows.end(); ++i) {
1282 boost::shared_ptr<Route> route = (*i)[_columns.route];
1283 (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_visual_state (route) > 0 ? 1 : 0;
1288 EditorRoutes::update_solo_safe_display ()
1290 TreeModel::Children rows = _model->children();
1291 TreeModel::Children::iterator i;
1293 for (i = rows.begin(); i != rows.end(); ++i) {
1294 boost::shared_ptr<Route> route = (*i)[_columns.route];
1295 (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_visual_state (route) > 0 ? 1 : 0;
1300 EditorRoutes::views () const
1302 list<TimeAxisView*> v;
1303 for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
1304 v.push_back ((*i)[_columns.tv]);
1311 EditorRoutes::clear ()
1313 _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1315 _display.set_model (_model);
1319 EditorRoutes::name_edit_started (CellEditable* ce, const Glib::ustring&)
1325 EditorRoutes::name_edit (std::string const & path, std::string const & new_text)
1329 TreeIter iter = _model->get_iter (path);
1335 boost::shared_ptr<Route> route = (*iter)[_columns.route];
1337 if (route && route->name() != new_text) {
1338 route->set_name (new_text);
1343 EditorRoutes::solo_changed_so_update_mute ()
1345 update_mute_display ();
1349 EditorRoutes::show_tracks_with_regions_at_playhead ()
1351 boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
1353 set<TimeAxisView*> show;
1354 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
1355 TimeAxisView* tav = _editor->axis_view_from_route (*i);
1361 suspend_redisplay ();
1363 TreeModel::Children rows = _model->children ();
1364 for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
1365 TimeAxisView* tv = (*i)[_columns.tv];
1366 (*i)[_columns.visible] = (show.find (tv) != show.end());
1369 resume_redisplay ();