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(22);
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 ();
236 /* try to do nothing on focus in (doesn't work, hence selection_count nonsense) */
241 EditorRoutes::focus_out (GdkEventFocus*)
244 old_focus->grab_focus ();
252 EditorRoutes::enter_notify (GdkEventCrossing*)
258 /* arm counter so that ::selection_filter() will deny selecting anything for the
259 next two attempts to change selection status.
261 selection_countdown = 2;
262 _scroller.grab_focus ();
263 Keyboard::magic_widget_grab_focus ();
268 EditorRoutes::leave_notify (GdkEventCrossing*)
270 selection_countdown = 0;
273 old_focus->grab_focus ();
277 Keyboard::magic_widget_drop_focus ();
282 EditorRoutes::set_session (Session* s)
284 SessionHandlePtr::set_session (s);
289 _session->SoloChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::solo_changed_so_update_mute, this), gui_context());
290 _session->RecordStateChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
295 EditorRoutes::on_tv_rec_enable_changed (std::string const & path_string)
297 // Get the model row that has been toggled.
298 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
300 TimeAxisView* tv = row[_columns.tv];
301 RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
303 if (rtv && rtv->track()) {
304 boost::shared_ptr<RouteList> rl (new RouteList);
305 rl->push_back (rtv->route());
306 _session->set_record_enabled (rl, !rtv->track()->record_enabled(), Session::rt_cleanup);
311 EditorRoutes::on_tv_mute_enable_toggled (std::string const & path_string)
313 // Get the model row that has been toggled.
314 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
316 TimeAxisView *tv = row[_columns.tv];
317 RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
320 boost::shared_ptr<RouteList> rl (new RouteList);
321 rl->push_back (rtv->route());
322 _session->set_mute (rl, !rtv->route()->muted(), Session::rt_cleanup);
327 EditorRoutes::on_tv_solo_enable_toggled (std::string const & path_string)
329 // Get the model row that has been toggled.
330 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
332 TimeAxisView *tv = row[_columns.tv];
333 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
336 boost::shared_ptr<RouteList> rl (new RouteList);
337 rl->push_back (rtv->route());
338 if (Config->get_solo_control_is_listen_control()) {
339 _session->set_listen (rl, !rtv->route()->listening_via_monitor(), Session::rt_cleanup);
341 _session->set_solo (rl, !rtv->route()->self_soloed(), Session::rt_cleanup);
347 EditorRoutes::on_tv_solo_isolate_toggled (std::string const & path_string)
349 // Get the model row that has been toggled.
350 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
352 TimeAxisView *tv = row[_columns.tv];
353 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
356 rtv->route()->set_solo_isolated (!rtv->route()->solo_isolated(), this);
361 EditorRoutes::on_tv_solo_safe_toggled (std::string const & path_string)
363 // Get the model row that has been toggled.
364 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
366 TimeAxisView *tv = row[_columns.tv];
367 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
370 rtv->route()->set_solo_safe (!rtv->route()->solo_safe(), this);
375 EditorRoutes::build_menu ()
377 using namespace Menu_Helpers;
382 MenuList& items = _menu->items();
383 _menu->set_name ("ArdourContextMenu");
385 items.push_back (MenuElem (_("Show All"), sigc::mem_fun (*this, &EditorRoutes::show_all_routes)));
386 items.push_back (MenuElem (_("Hide All"), sigc::mem_fun (*this, &EditorRoutes::hide_all_routes)));
387 items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiotracks)));
388 items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiotracks)));
389 items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiobus)));
390 items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiobus)));
391 items.push_back (MenuElem (_("Show All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_miditracks)));
392 items.push_back (MenuElem (_("Hide All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_miditracks)));
393 items.push_back (MenuElem (_("Show Tracks With Regions Under Playhead"), sigc::mem_fun (*this, &EditorRoutes::show_tracks_with_regions_at_playhead)));
397 EditorRoutes::show_menu ()
403 _menu->popup (1, gtk_get_current_event_time());
407 EditorRoutes::redisplay ()
409 if (_no_redisplay || !_session) {
413 TreeModel::Children rows = _model->children();
414 TreeModel::Children::iterator i;
418 for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
419 TimeAxisView *tv = (*i)[_columns.tv];
420 boost::shared_ptr<Route> route = (*i)[_columns.route];
423 // just a "title" row
427 if (!_redisplay_does_not_reset_order_keys) {
428 /* this reorder is caused by user action, so reassign sort order keys
431 route->set_order_key (N_ ("editor"), n);
434 bool visible = (*i)[_columns.visible];
436 /* show or hide the TimeAxisView */
438 tv->set_marked_for_display (true);
439 position += tv->show_at (position, n, &_editor->edit_controls_vbox);
440 tv->clip_to_viewport ();
442 tv->set_marked_for_display (false);
450 /* whenever we go idle, update the track view list to reflect the new order.
451 we can't do this here, because we could mess up something that is traversing
452 the track order and has caused a redisplay of the list.
454 Glib::signal_idle().connect (sigc::mem_fun (*_editor, &Editor::sync_track_view_list_and_routes));
456 _editor->reset_controls_layout_height (position);
457 _editor->reset_controls_layout_width ();
458 _editor->full_canvas_height = position + _editor->canvas_timebars_vsize;
459 _editor->vertical_adjustment.set_upper (_editor->full_canvas_height);
461 if ((_editor->vertical_adjustment.get_value() + _editor->_canvas_height) > _editor->vertical_adjustment.get_upper()) {
463 We're increasing the size of the canvas while the bottom is visible.
464 We scroll down to keep in step with the controls layout.
466 _editor->vertical_adjustment.set_value (_editor->full_canvas_height - _editor->_canvas_height);
469 if (!_redisplay_does_not_reset_order_keys && !_redisplay_does_not_sync_order_keys) {
470 _session->sync_order_keys (N_ ("editor"));
475 EditorRoutes::route_deleted (Gtk::TreeModel::Path const &)
477 if (!_session || _session->deletion_in_progress()) {
481 /* this could require an order reset & sync */
482 _session->set_remote_control_ids();
483 _ignore_reorder = true;
485 _ignore_reorder = false;
489 EditorRoutes::visible_changed (std::string const & path)
491 if (_session && _session->deletion_in_progress()) {
497 if ((iter = _model->get_iter (path))) {
498 TimeAxisView* tv = (*iter)[_columns.tv];
500 bool visible = (*iter)[_columns.visible];
501 (*iter)[_columns.visible] = !visible;
505 _redisplay_does_not_reset_order_keys = true;
506 _session->set_remote_control_ids();
508 _redisplay_does_not_reset_order_keys = false;
512 EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
516 _redisplay_does_not_sync_order_keys = true;
517 suspend_redisplay ();
519 for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) {
521 row = *(_model->append ());
523 row[_columns.text] = (*x)->route()->name();
524 row[_columns.visible] = (*x)->marked_for_display();
525 row[_columns.tv] = *x;
526 row[_columns.route] = (*x)->route ();
527 row[_columns.is_track] = (boost::dynamic_pointer_cast<Track> ((*x)->route()) != 0);
528 row[_columns.mute_state] = (*x)->route()->muted();
529 row[_columns.solo_state] = RouteUI::solo_visual_state ((*x)->route());
530 row[_columns.solo_isolate_state] = (*x)->route()->solo_isolated();
531 row[_columns.solo_safe_state] = (*x)->route()->solo_safe();
532 row[_columns.name_editable] = true;
534 _ignore_reorder = true;
536 /* added a new fresh one at the end */
537 if ((*x)->route()->order_key (N_ ("editor")) == -1) {
538 (*x)->route()->set_order_key (N_ ("editor"), _model->children().size()-1);
541 _ignore_reorder = false;
543 boost::weak_ptr<Route> wr ((*x)->route());
545 (*x)->route()->gui_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
546 (*x)->route()->PropertyChanged.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::route_property_changed, this, _1, wr), gui_context());
548 if ((*x)->is_track()) {
549 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
550 t->RecordEnableChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
553 if ((*x)->is_midi_track()) {
554 boost::shared_ptr<MidiTrack> t = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
555 t->StepEditStatusChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
558 (*x)->route()->mute_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
559 (*x)->route()->solo_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
560 (*x)->route()->listen_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
561 (*x)->route()->solo_isolated_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_isolate_display, this), gui_context());
562 (*x)->route()->solo_safe_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_safe_display, this), gui_context());
565 update_rec_display ();
566 update_mute_display ();
567 update_solo_display (true);
568 update_solo_isolate_display ();
569 update_solo_safe_display ();
571 _redisplay_does_not_sync_order_keys = false;
575 EditorRoutes::handle_gui_changes (string const & what, void*)
577 ENSURE_GUI_THREAD (*this, &EditorRoutes::handle_gui_changes, what, src)
579 if (what == "track_height") {
580 /* Optional :make tracks change height while it happens, instead
583 //update_canvas_now ();
587 if (what == "visible_tracks") {
593 EditorRoutes::route_removed (TimeAxisView *tv)
595 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed, tv)
597 TreeModel::Children rows = _model->children();
598 TreeModel::Children::iterator ri;
600 /* the core model has changed, there is no need to sync
604 _redisplay_does_not_sync_order_keys = true;
606 for (ri = rows.begin(); ri != rows.end(); ++ri) {
607 if ((*ri)[_columns.tv] == tv) {
613 _redisplay_does_not_sync_order_keys = false;
617 EditorRoutes::route_property_changed (const PropertyChange& what_changed, boost::weak_ptr<Route> r)
619 if (!what_changed.contains (ARDOUR::Properties::name)) {
623 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_name_changed, r)
625 boost::shared_ptr<Route> route = r.lock ();
631 TreeModel::Children rows = _model->children();
632 TreeModel::Children::iterator i;
634 for (i = rows.begin(); i != rows.end(); ++i) {
635 boost::shared_ptr<Route> t = (*i)[_columns.route];
637 (*i)[_columns.text] = route->name();
644 EditorRoutes::update_visibility ()
646 TreeModel::Children rows = _model->children();
647 TreeModel::Children::iterator i;
649 suspend_redisplay ();
651 for (i = rows.begin(); i != rows.end(); ++i) {
652 TimeAxisView *tv = (*i)[_columns.tv];
653 (*i)[_columns.visible] = tv->marked_for_display ();
654 cerr << "marked " << tv->name() << " for display = " << tv->marked_for_display() << endl;
661 EditorRoutes::hide_track_in_display (TimeAxisView& tv)
663 TreeModel::Children rows = _model->children();
664 TreeModel::Children::iterator i;
666 for (i = rows.begin(); i != rows.end(); ++i) {
667 if ((*i)[_columns.tv] == &tv) {
668 (*i)[_columns.visible] = false;
677 EditorRoutes::show_track_in_display (TimeAxisView& tv)
679 TreeModel::Children rows = _model->children();
680 TreeModel::Children::iterator i;
682 for (i = rows.begin(); i != rows.end(); ++i) {
683 if ((*i)[_columns.tv] == &tv) {
684 (*i)[_columns.visible] = true;
693 EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
698 /** If src != "editor", take editor order keys from each route and use them to rearrange the
699 * route list so that the visual arrangement of routes matches the order keys from the routes.
702 EditorRoutes::sync_order_keys (string const & src)
704 vector<int> neworder;
705 TreeModel::Children rows = _model->children();
706 TreeModel::Children::iterator ri;
708 if (src == N_ ("editor") || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
712 for (ri = rows.begin(); ri != rows.end(); ++ri) {
713 neworder.push_back (0);
716 bool changed = false;
719 for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
720 boost::shared_ptr<Route> route = (*ri)[_columns.route];
723 int new_key = route->order_key (N_ ("editor"));
725 neworder[new_key] = old_key;
727 if (new_key != old_key) {
733 _redisplay_does_not_reset_order_keys = true;
734 _model->reorder (neworder);
735 _redisplay_does_not_reset_order_keys = false;
741 EditorRoutes::hide_all_tracks (bool /*with_select*/)
743 TreeModel::Children rows = _model->children();
744 TreeModel::Children::iterator i;
746 suspend_redisplay ();
748 for (i = rows.begin(); i != rows.end(); ++i) {
750 TreeModel::Row row = (*i);
751 TimeAxisView *tv = row[_columns.tv];
757 row[_columns.visible] = false;
762 /* XXX this seems like a hack and half, but its not clear where to put this
766 //reset_scrolling_region ();
770 EditorRoutes::set_all_tracks_visibility (bool yn)
772 TreeModel::Children rows = _model->children();
773 TreeModel::Children::iterator i;
775 suspend_redisplay ();
777 for (i = rows.begin(); i != rows.end(); ++i) {
779 TreeModel::Row row = (*i);
780 TimeAxisView* tv = row[_columns.tv];
786 (*i)[_columns.visible] = yn;
793 EditorRoutes::set_all_audio_midi_visibility (int tracks, bool yn)
795 TreeModel::Children rows = _model->children();
796 TreeModel::Children::iterator i;
798 suspend_redisplay ();
800 for (i = rows.begin(); i != rows.end(); ++i) {
802 TreeModel::Row row = (*i);
803 TimeAxisView* tv = row[_columns.tv];
805 AudioTimeAxisView* atv;
806 MidiTimeAxisView* mtv;
812 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
815 (*i)[_columns.visible] = yn;
819 if (atv->is_audio_track()) {
820 (*i)[_columns.visible] = yn;
825 if (!atv->is_audio_track()) {
826 (*i)[_columns.visible] = yn;
831 else if ((mtv = dynamic_cast<MidiTimeAxisView*>(tv)) != 0) {
834 (*i)[_columns.visible] = yn;
838 if (mtv->is_midi_track()) {
839 (*i)[_columns.visible] = yn;
850 EditorRoutes::hide_all_routes ()
852 set_all_tracks_visibility (false);
856 EditorRoutes::show_all_routes ()
858 set_all_tracks_visibility (true);
862 EditorRoutes::show_all_audiotracks()
864 set_all_audio_midi_visibility (1, true);
867 EditorRoutes::hide_all_audiotracks ()
869 set_all_audio_midi_visibility (1, false);
873 EditorRoutes::show_all_audiobus ()
875 set_all_audio_midi_visibility (2, true);
878 EditorRoutes::hide_all_audiobus ()
880 set_all_audio_midi_visibility (2, false);
884 EditorRoutes::show_all_miditracks()
886 set_all_audio_midi_visibility (3, true);
889 EditorRoutes::hide_all_miditracks ()
891 set_all_audio_midi_visibility (3, false);
895 EditorRoutes::key_press (GdkEventKey* ev)
898 boost::shared_ptr<RouteList> rl (new RouteList);
901 switch (ev->keyval) {
903 case GDK_ISO_Left_Tab:
905 /* If we appear to be editing something, leave that cleanly and appropriately.
908 name_editable->editing_done ();
912 col = _display.get_column (5); // select&focus on name column
914 if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
915 treeview_select_previous (_display, _model, col);
917 treeview_select_next (_display, _model, col);
924 if (get_relevant_routes (rl)) {
925 _session->set_mute (rl, !rl->front()->muted(), Session::rt_cleanup);
931 if (Config->get_solo_control_is_listen_control()) {
932 _session->set_listen (rl, !rl->front()->listening_via_monitor(), Session::rt_cleanup);
934 _session->set_solo (rl, !rl->front()->self_soloed(), Session::rt_cleanup);
940 if (get_relevant_routes (rl)) {
941 _session->set_record_enabled (rl, !rl->front()->record_enabled(), Session::rt_cleanup);
953 EditorRoutes::get_relevant_routes (boost::shared_ptr<RouteList> rl)
956 RouteTimeAxisView* rtv;
957 RefPtr<TreeSelection> selection = _display.get_selection();
961 if (selection->count_selected_rows() != 0) {
965 RefPtr<TreeModel> tm = RefPtr<TreeModel>::cast_dynamic (_model);
966 iter = selection->get_selected (tm);
969 /* use mouse pointer */
974 _display.get_pointer (x, y);
975 _display.convert_widget_to_bin_window_coords (x, y, bx, by);
977 if (_display.get_path_at_pos (bx, by, path)) {
978 iter = _model->get_iter (path);
983 tv = (*iter)[_columns.tv];
985 rtv = dynamic_cast<RouteTimeAxisView*>(tv);
987 rl->push_back (rtv->route());
996 EditorRoutes::button_press (GdkEventButton* ev)
998 if (Keyboard::is_context_menu_event (ev)) {
1003 //Scroll editor canvas to selected track
1004 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1006 TreeModel::Path path;
1007 TreeViewColumn *tvc;
1011 _display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y);
1013 // Get the model row.
1014 Gtk::TreeModel::Row row = *_model->get_iter (path);
1016 TimeAxisView *tv = row[_columns.tv];
1018 int y_pos = tv->y_position();
1020 //Clamp the y pos so that we do not extend beyond the canvas full height.
1021 if (_editor->full_canvas_height - y_pos < _editor->_canvas_height){
1022 y_pos = _editor->full_canvas_height - _editor->_canvas_height;
1025 //Only scroll to if the track is visible
1027 _editor->reset_y_origin (y_pos);
1035 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const&, bool /*selected*/)
1037 if (selection_countdown) {
1038 if (--selection_countdown == 0) {
1041 /* no selection yet ... */
1048 struct EditorOrderRouteSorter {
1049 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1050 /* use of ">" forces the correct sort order */
1051 return a->order_key (N_ ("editor")) < b->order_key (N_ ("editor"));
1056 EditorRoutes::initial_display ()
1058 suspend_redisplay ();
1062 resume_redisplay ();
1066 boost::shared_ptr<RouteList> routes = _session->get_routes();
1067 RouteList r (*routes);
1068 EditorOrderRouteSorter sorter;
1071 _editor->handle_new_route (r);
1073 /* don't show master bus in a new session */
1075 if (ARDOUR_UI::instance()->session_is_new ()) {
1077 TreeModel::Children rows = _model->children();
1078 TreeModel::Children::iterator i;
1080 _no_redisplay = true;
1082 for (i = rows.begin(); i != rows.end(); ++i) {
1084 TimeAxisView *tv = (*i)[_columns.tv];
1085 RouteTimeAxisView *rtv;
1087 if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
1088 if (rtv->route()->is_master()) {
1089 _display.get_selection()->unselect (i);
1094 _no_redisplay = false;
1098 resume_redisplay ();
1102 EditorRoutes::track_list_reorder (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &, int* /*new_order*/)
1104 _redisplay_does_not_sync_order_keys = true;
1105 _session->set_remote_control_ids();
1107 _redisplay_does_not_sync_order_keys = false;
1111 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
1113 const SelectionData& data,
1114 guint info, guint time)
1116 if (data.get_target() == "GTK_TREE_MODEL_ROW") {
1117 _display.on_drag_data_received (context, x, y, data, info, time);
1121 context->drag_finish (true, false, time);
1125 EditorRoutes::move_selected_tracks (bool up)
1127 if (_editor->selection->tracks.empty()) {
1131 typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
1132 std::list<ViewRoute> view_routes;
1133 std::vector<int> neworder;
1134 TreeModel::Children rows = _model->children();
1135 TreeModel::Children::iterator ri;
1137 for (ri = rows.begin(); ri != rows.end(); ++ri) {
1138 TimeAxisView* tv = (*ri)[_columns.tv];
1139 boost::shared_ptr<Route> route = (*ri)[_columns.route];
1141 view_routes.push_back (ViewRoute (tv, route));
1144 list<ViewRoute>::iterator trailing;
1145 list<ViewRoute>::iterator leading;
1149 trailing = view_routes.begin();
1150 leading = view_routes.begin();
1154 while (leading != view_routes.end()) {
1155 if (_editor->selection->selected (leading->first)) {
1156 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
1157 leading = view_routes.erase (leading);
1166 /* if we could use reverse_iterator in list::insert, this code
1167 would be a beautiful reflection of the code above. but we can't
1168 and so it looks like a bit of a mess.
1171 trailing = view_routes.end();
1172 leading = view_routes.end();
1174 --leading; if (leading == view_routes.begin()) { return; }
1180 if (_editor->selection->selected (leading->first)) {
1181 list<ViewRoute>::iterator tmp;
1183 /* need to insert *after* trailing, not *before* it,
1184 which is what insert (iter, val) normally does.
1190 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
1192 /* can't use iter = cont.erase (iter); form here, because
1193 we need iter to move backwards.
1201 if (leading == view_routes.begin()) {
1202 /* the one we've just inserted somewhere else
1203 was the first in the list. erase this copy,
1204 and then break, because we're done.
1209 view_routes.erase (leading);
1218 if (leading == view_routes.begin()) {
1227 for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
1228 neworder.push_back (leading->second->order_key (N_ ("editor")));
1231 _model->reorder (neworder);
1233 _session->sync_order_keys (N_ ("editor"));
1237 EditorRoutes::update_rec_display ()
1239 TreeModel::Children rows = _model->children();
1240 TreeModel::Children::iterator i;
1242 for (i = rows.begin(); i != rows.end(); ++i) {
1243 boost::shared_ptr<Route> route = (*i)[_columns.route];
1245 if (boost::dynamic_pointer_cast<Track> (route)) {
1246 boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
1248 if (route->record_enabled()) {
1249 if (_session->record_status() == Session::Recording) {
1250 (*i)[_columns.rec_state] = 1;
1252 (*i)[_columns.rec_state] = 2;
1254 } else if (mt && mt->step_editing()) {
1255 (*i)[_columns.rec_state] = 3;
1257 (*i)[_columns.rec_state] = 0;
1260 (*i)[_columns.name_editable] = !route->record_enabled ();
1266 EditorRoutes::update_mute_display ()
1268 TreeModel::Children rows = _model->children();
1269 TreeModel::Children::iterator i;
1271 for (i = rows.begin(); i != rows.end(); ++i) {
1272 boost::shared_ptr<Route> route = (*i)[_columns.route];
1273 (*i)[_columns.mute_state] = RouteUI::mute_visual_state (_session, route);
1278 EditorRoutes::update_solo_display (bool /* selfsoloed */)
1280 TreeModel::Children rows = _model->children();
1281 TreeModel::Children::iterator i;
1283 for (i = rows.begin(); i != rows.end(); ++i) {
1284 boost::shared_ptr<Route> route = (*i)[_columns.route];
1285 (*i)[_columns.solo_state] = RouteUI::solo_visual_state (route);
1290 EditorRoutes::update_solo_isolate_display ()
1292 TreeModel::Children rows = _model->children();
1293 TreeModel::Children::iterator i;
1295 for (i = rows.begin(); i != rows.end(); ++i) {
1296 boost::shared_ptr<Route> route = (*i)[_columns.route];
1297 (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_visual_state (route) > 0 ? 1 : 0;
1302 EditorRoutes::update_solo_safe_display ()
1304 TreeModel::Children rows = _model->children();
1305 TreeModel::Children::iterator i;
1307 for (i = rows.begin(); i != rows.end(); ++i) {
1308 boost::shared_ptr<Route> route = (*i)[_columns.route];
1309 (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_visual_state (route) > 0 ? 1 : 0;
1314 EditorRoutes::views () const
1316 list<TimeAxisView*> v;
1317 for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
1318 v.push_back ((*i)[_columns.tv]);
1325 EditorRoutes::clear ()
1327 _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1329 _display.set_model (_model);
1333 EditorRoutes::name_edit_started (CellEditable* ce, const Glib::ustring&)
1337 /* give it a special name */
1339 Gtk::Entry *e = dynamic_cast<Gtk::Entry*> (ce);
1342 e->set_name (X_("RouteNameEditorEntry"));
1347 EditorRoutes::name_edit (std::string const & path, std::string const & new_text)
1351 TreeIter iter = _model->get_iter (path);
1357 boost::shared_ptr<Route> route = (*iter)[_columns.route];
1359 if (route && route->name() != new_text) {
1360 route->set_name (new_text);
1365 EditorRoutes::solo_changed_so_update_mute ()
1367 update_mute_display ();
1371 EditorRoutes::show_tracks_with_regions_at_playhead ()
1373 boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
1375 set<TimeAxisView*> show;
1376 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
1377 TimeAxisView* tav = _editor->axis_view_from_route (*i);
1383 suspend_redisplay ();
1385 TreeModel::Children rows = _model->children ();
1386 for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
1387 TimeAxisView* tv = (*i)[_columns.tv];
1388 (*i)[_columns.visible] = (show.find (tv) != show.end());
1391 resume_redisplay ();