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(), 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);
449 /* whenever we go idle, update the track view list to reflect the new order.
450 we can't do this here, because we could mess up something that is traversing
451 the track order and has caused a redisplay of the list.
453 Glib::signal_idle().connect (sigc::mem_fun (*_editor, &Editor::sync_track_view_list_and_routes));
455 _editor->full_canvas_height = position + _editor->canvas_timebars_vsize;
456 _editor->vertical_adjustment.set_upper (_editor->full_canvas_height);
458 if ((_editor->vertical_adjustment.get_value() + _editor->_canvas_height) > _editor->vertical_adjustment.get_upper()) {
460 We're increasing the size of the canvas while the bottom is visible.
461 We scroll down to keep in step with the controls layout.
463 _editor->vertical_adjustment.set_value (_editor->full_canvas_height - _editor->_canvas_height);
466 if (!_redisplay_does_not_reset_order_keys && !_redisplay_does_not_sync_order_keys) {
467 _session->sync_order_keys (N_ ("editor"));
472 EditorRoutes::route_deleted (Gtk::TreeModel::Path const &)
474 if (!_session || _session->deletion_in_progress()) {
478 /* this could require an order reset & sync */
479 _session->set_remote_control_ids();
480 _ignore_reorder = true;
482 _ignore_reorder = false;
486 EditorRoutes::visible_changed (std::string const & path)
488 if (_session && _session->deletion_in_progress()) {
494 if ((iter = _model->get_iter (path))) {
495 TimeAxisView* tv = (*iter)[_columns.tv];
497 bool visible = (*iter)[_columns.visible];
498 (*iter)[_columns.visible] = !visible;
502 _redisplay_does_not_reset_order_keys = true;
503 _session->set_remote_control_ids();
505 _redisplay_does_not_reset_order_keys = false;
509 EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
513 _redisplay_does_not_sync_order_keys = true;
514 suspend_redisplay ();
516 for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) {
518 row = *(_model->append ());
520 row[_columns.text] = (*x)->route()->name();
521 row[_columns.visible] = (*x)->marked_for_display();
522 row[_columns.tv] = *x;
523 row[_columns.route] = (*x)->route ();
524 row[_columns.is_track] = (boost::dynamic_pointer_cast<Track> ((*x)->route()) != 0);
525 row[_columns.mute_state] = (*x)->route()->muted();
526 row[_columns.solo_state] = RouteUI::solo_visual_state ((*x)->route());
527 row[_columns.solo_isolate_state] = (*x)->route()->solo_isolated();
528 row[_columns.solo_safe_state] = (*x)->route()->solo_safe();
529 row[_columns.name_editable] = true;
531 _ignore_reorder = true;
533 /* added a new fresh one at the end */
534 if ((*x)->route()->order_key (N_ ("editor")) == -1) {
535 (*x)->route()->set_order_key (N_ ("editor"), _model->children().size()-1);
538 _ignore_reorder = false;
540 boost::weak_ptr<Route> wr ((*x)->route());
542 (*x)->route()->gui_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
543 (*x)->route()->PropertyChanged.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::route_property_changed, this, _1, wr), gui_context());
545 if ((*x)->is_track()) {
546 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
547 t->RecordEnableChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
550 if ((*x)->is_midi_track()) {
551 boost::shared_ptr<MidiTrack> t = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
552 t->StepEditStatusChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
555 (*x)->route()->mute_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
556 (*x)->route()->solo_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
557 (*x)->route()->listen_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
558 (*x)->route()->solo_isolated_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_isolate_display, this), gui_context());
559 (*x)->route()->solo_safe_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_safe_display, this), gui_context());
562 update_rec_display ();
563 update_mute_display ();
564 update_solo_display (true);
565 update_solo_isolate_display ();
566 update_solo_safe_display ();
568 _redisplay_does_not_sync_order_keys = false;
572 EditorRoutes::handle_gui_changes (string const & what, void*)
574 ENSURE_GUI_THREAD (*this, &EditorRoutes::handle_gui_changes, what, src)
576 if (what == "track_height") {
577 /* Optional :make tracks change height while it happens, instead
580 //update_canvas_now ();
584 if (what == "visible_tracks") {
590 EditorRoutes::route_removed (TimeAxisView *tv)
592 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed, tv)
594 TreeModel::Children rows = _model->children();
595 TreeModel::Children::iterator ri;
597 /* the core model has changed, there is no need to sync
601 _redisplay_does_not_sync_order_keys = true;
603 for (ri = rows.begin(); ri != rows.end(); ++ri) {
604 if ((*ri)[_columns.tv] == tv) {
610 _redisplay_does_not_sync_order_keys = false;
614 EditorRoutes::route_property_changed (const PropertyChange& what_changed, boost::weak_ptr<Route> r)
616 if (!what_changed.contains (ARDOUR::Properties::name)) {
620 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_name_changed, r)
622 boost::shared_ptr<Route> route = r.lock ();
628 TreeModel::Children rows = _model->children();
629 TreeModel::Children::iterator i;
631 for (i = rows.begin(); i != rows.end(); ++i) {
632 boost::shared_ptr<Route> t = (*i)[_columns.route];
634 (*i)[_columns.text] = route->name();
641 EditorRoutes::update_visibility ()
643 TreeModel::Children rows = _model->children();
644 TreeModel::Children::iterator i;
646 suspend_redisplay ();
648 for (i = rows.begin(); i != rows.end(); ++i) {
649 TimeAxisView *tv = (*i)[_columns.tv];
650 (*i)[_columns.visible] = tv->marked_for_display ();
651 cerr << "marked " << tv->name() << " for display = " << tv->marked_for_display() << endl;
658 EditorRoutes::hide_track_in_display (TimeAxisView& tv)
660 TreeModel::Children rows = _model->children();
661 TreeModel::Children::iterator i;
663 for (i = rows.begin(); i != rows.end(); ++i) {
664 if ((*i)[_columns.tv] == &tv) {
665 (*i)[_columns.visible] = false;
674 EditorRoutes::show_track_in_display (TimeAxisView& tv)
676 TreeModel::Children rows = _model->children();
677 TreeModel::Children::iterator i;
679 for (i = rows.begin(); i != rows.end(); ++i) {
680 if ((*i)[_columns.tv] == &tv) {
681 (*i)[_columns.visible] = true;
690 EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
695 /** If src != "editor", take editor order keys from each route and use them to rearrange the
696 * route list so that the visual arrangement of routes matches the order keys from the routes.
699 EditorRoutes::sync_order_keys (string const & src)
701 vector<int> neworder;
702 TreeModel::Children rows = _model->children();
703 TreeModel::Children::iterator ri;
705 if (src == N_ ("editor") || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
709 for (ri = rows.begin(); ri != rows.end(); ++ri) {
710 neworder.push_back (0);
713 bool changed = false;
716 for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
717 boost::shared_ptr<Route> route = (*ri)[_columns.route];
720 int new_key = route->order_key (N_ ("editor"));
722 neworder[new_key] = old_key;
724 if (new_key != old_key) {
730 _redisplay_does_not_reset_order_keys = true;
731 _model->reorder (neworder);
732 _redisplay_does_not_reset_order_keys = false;
738 EditorRoutes::hide_all_tracks (bool /*with_select*/)
740 TreeModel::Children rows = _model->children();
741 TreeModel::Children::iterator i;
743 suspend_redisplay ();
745 for (i = rows.begin(); i != rows.end(); ++i) {
747 TreeModel::Row row = (*i);
748 TimeAxisView *tv = row[_columns.tv];
754 row[_columns.visible] = false;
759 /* XXX this seems like a hack and half, but its not clear where to put this
763 //reset_scrolling_region ();
767 EditorRoutes::set_all_tracks_visibility (bool yn)
769 TreeModel::Children rows = _model->children();
770 TreeModel::Children::iterator i;
772 suspend_redisplay ();
774 for (i = rows.begin(); i != rows.end(); ++i) {
776 TreeModel::Row row = (*i);
777 TimeAxisView* tv = row[_columns.tv];
783 (*i)[_columns.visible] = yn;
790 EditorRoutes::set_all_audio_midi_visibility (int tracks, bool yn)
792 TreeModel::Children rows = _model->children();
793 TreeModel::Children::iterator i;
795 suspend_redisplay ();
797 for (i = rows.begin(); i != rows.end(); ++i) {
799 TreeModel::Row row = (*i);
800 TimeAxisView* tv = row[_columns.tv];
802 AudioTimeAxisView* atv;
803 MidiTimeAxisView* mtv;
809 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
812 (*i)[_columns.visible] = yn;
816 if (atv->is_audio_track()) {
817 (*i)[_columns.visible] = yn;
822 if (!atv->is_audio_track()) {
823 (*i)[_columns.visible] = yn;
828 else if ((mtv = dynamic_cast<MidiTimeAxisView*>(tv)) != 0) {
831 (*i)[_columns.visible] = yn;
835 if (mtv->is_midi_track()) {
836 (*i)[_columns.visible] = yn;
847 EditorRoutes::hide_all_routes ()
849 set_all_tracks_visibility (false);
853 EditorRoutes::show_all_routes ()
855 set_all_tracks_visibility (true);
859 EditorRoutes::show_all_audiotracks()
861 set_all_audio_midi_visibility (1, true);
864 EditorRoutes::hide_all_audiotracks ()
866 set_all_audio_midi_visibility (1, false);
870 EditorRoutes::show_all_audiobus ()
872 set_all_audio_midi_visibility (2, true);
875 EditorRoutes::hide_all_audiobus ()
877 set_all_audio_midi_visibility (2, false);
881 EditorRoutes::show_all_miditracks()
883 set_all_audio_midi_visibility (3, true);
886 EditorRoutes::hide_all_miditracks ()
888 set_all_audio_midi_visibility (3, false);
892 EditorRoutes::key_press (GdkEventKey* ev)
895 boost::shared_ptr<RouteList> rl (new RouteList);
898 switch (ev->keyval) {
900 case GDK_ISO_Left_Tab:
902 /* If we appear to be editing something, leave that cleanly and appropriately.
905 name_editable->editing_done ();
909 col = _display.get_column (5); // select&focus on name column
911 if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
912 treeview_select_previous (_display, _model, col);
914 treeview_select_next (_display, _model, col);
921 if (get_relevant_routes (rl)) {
922 _session->set_mute (rl, !rl->front()->muted(), Session::rt_cleanup);
928 if (Config->get_solo_control_is_listen_control()) {
929 _session->set_listen (rl, !rl->front()->listening(), Session::rt_cleanup);
931 _session->set_solo (rl, !rl->front()->self_soloed(), Session::rt_cleanup);
937 if (get_relevant_routes (rl)) {
938 _session->set_record_enabled (rl, !rl->front()->record_enabled(), Session::rt_cleanup);
950 EditorRoutes::get_relevant_routes (boost::shared_ptr<RouteList> rl)
953 RouteTimeAxisView* rtv;
954 RefPtr<TreeSelection> selection = _display.get_selection();
958 if (selection->count_selected_rows() != 0) {
962 RefPtr<TreeModel> tm = RefPtr<TreeModel>::cast_dynamic (_model);
963 iter = selection->get_selected (tm);
966 /* use mouse pointer */
971 _display.get_pointer (x, y);
972 _display.convert_widget_to_bin_window_coords (x, y, bx, by);
974 if (_display.get_path_at_pos (bx, by, path)) {
975 iter = _model->get_iter (path);
980 tv = (*iter)[_columns.tv];
982 rtv = dynamic_cast<RouteTimeAxisView*>(tv);
984 rl->push_back (rtv->route());
993 EditorRoutes::button_press (GdkEventButton* ev)
995 if (Keyboard::is_context_menu_event (ev)) {
1000 //Scroll editor canvas to selected track
1001 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1003 TreeModel::Path path;
1004 TreeViewColumn *tvc;
1008 _display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y);
1010 // Get the model row.
1011 Gtk::TreeModel::Row row = *_model->get_iter (path);
1013 TimeAxisView *tv = row[_columns.tv];
1015 int y_pos = tv->y_position();
1017 //Clamp the y pos so that we do not extend beyond the canvas full height.
1018 if (_editor->full_canvas_height - y_pos < _editor->_canvas_height){
1019 y_pos = _editor->full_canvas_height - _editor->_canvas_height;
1022 //Only scroll to if the track is visible
1024 _editor->reset_y_origin (y_pos);
1032 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const&, bool /*selected*/)
1034 if (selection_countdown) {
1035 if (--selection_countdown == 0) {
1038 /* no selection yet ... */
1045 struct EditorOrderRouteSorter {
1046 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1047 /* use of ">" forces the correct sort order */
1048 return a->order_key (N_ ("editor")) < b->order_key (N_ ("editor"));
1053 EditorRoutes::initial_display ()
1055 suspend_redisplay ();
1059 resume_redisplay ();
1063 boost::shared_ptr<RouteList> routes = _session->get_routes();
1064 RouteList r (*routes);
1065 EditorOrderRouteSorter sorter;
1068 _editor->handle_new_route (r);
1070 /* don't show master bus in a new session */
1072 if (ARDOUR_UI::instance()->session_is_new ()) {
1074 TreeModel::Children rows = _model->children();
1075 TreeModel::Children::iterator i;
1077 _no_redisplay = true;
1079 for (i = rows.begin(); i != rows.end(); ++i) {
1081 TimeAxisView *tv = (*i)[_columns.tv];
1082 RouteTimeAxisView *rtv;
1084 if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
1085 if (rtv->route()->is_master()) {
1086 _display.get_selection()->unselect (i);
1091 _no_redisplay = false;
1095 resume_redisplay ();
1099 EditorRoutes::track_list_reorder (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &, int* /*new_order*/)
1101 _redisplay_does_not_sync_order_keys = true;
1102 _session->set_remote_control_ids();
1104 _redisplay_does_not_sync_order_keys = false;
1108 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
1110 const SelectionData& data,
1111 guint info, guint time)
1113 if (data.get_target() == "GTK_TREE_MODEL_ROW") {
1114 _display.on_drag_data_received (context, x, y, data, info, time);
1118 context->drag_finish (true, false, time);
1122 EditorRoutes::move_selected_tracks (bool up)
1124 if (_editor->selection->tracks.empty()) {
1128 typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
1129 std::list<ViewRoute> view_routes;
1130 std::vector<int> neworder;
1131 TreeModel::Children rows = _model->children();
1132 TreeModel::Children::iterator ri;
1134 for (ri = rows.begin(); ri != rows.end(); ++ri) {
1135 TimeAxisView* tv = (*ri)[_columns.tv];
1136 boost::shared_ptr<Route> route = (*ri)[_columns.route];
1138 view_routes.push_back (ViewRoute (tv, route));
1141 list<ViewRoute>::iterator trailing;
1142 list<ViewRoute>::iterator leading;
1146 trailing = view_routes.begin();
1147 leading = view_routes.begin();
1151 while (leading != view_routes.end()) {
1152 if (_editor->selection->selected (leading->first)) {
1153 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
1154 leading = view_routes.erase (leading);
1163 /* if we could use reverse_iterator in list::insert, this code
1164 would be a beautiful reflection of the code above. but we can't
1165 and so it looks like a bit of a mess.
1168 trailing = view_routes.end();
1169 leading = view_routes.end();
1171 --leading; if (leading == view_routes.begin()) { return; }
1177 if (_editor->selection->selected (leading->first)) {
1178 list<ViewRoute>::iterator tmp;
1180 /* need to insert *after* trailing, not *before* it,
1181 which is what insert (iter, val) normally does.
1187 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
1189 /* can't use iter = cont.erase (iter); form here, because
1190 we need iter to move backwards.
1198 if (leading == view_routes.begin()) {
1199 /* the one we've just inserted somewhere else
1200 was the first in the list. erase this copy,
1201 and then break, because we're done.
1206 view_routes.erase (leading);
1215 if (leading == view_routes.begin()) {
1224 for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
1225 neworder.push_back (leading->second->order_key (N_ ("editor")));
1228 _model->reorder (neworder);
1230 _session->sync_order_keys (N_ ("editor"));
1234 EditorRoutes::update_rec_display ()
1236 TreeModel::Children rows = _model->children();
1237 TreeModel::Children::iterator i;
1239 for (i = rows.begin(); i != rows.end(); ++i) {
1240 boost::shared_ptr<Route> route = (*i)[_columns.route];
1242 if (boost::dynamic_pointer_cast<Track> (route)) {
1243 boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
1245 if (route->record_enabled()) {
1246 if (_session->record_status() == Session::Recording) {
1247 (*i)[_columns.rec_state] = 1;
1249 (*i)[_columns.rec_state] = 2;
1251 } else if (mt && mt->step_editing()) {
1252 (*i)[_columns.rec_state] = 3;
1254 (*i)[_columns.rec_state] = 0;
1257 (*i)[_columns.name_editable] = !route->record_enabled ();
1263 EditorRoutes::update_mute_display ()
1265 TreeModel::Children rows = _model->children();
1266 TreeModel::Children::iterator i;
1268 for (i = rows.begin(); i != rows.end(); ++i) {
1269 boost::shared_ptr<Route> route = (*i)[_columns.route];
1270 (*i)[_columns.mute_state] = RouteUI::mute_visual_state (_session, route);
1275 EditorRoutes::update_solo_display (bool /* selfsoloed */)
1277 TreeModel::Children rows = _model->children();
1278 TreeModel::Children::iterator i;
1280 for (i = rows.begin(); i != rows.end(); ++i) {
1281 boost::shared_ptr<Route> route = (*i)[_columns.route];
1282 (*i)[_columns.solo_state] = RouteUI::solo_visual_state (route);
1287 EditorRoutes::update_solo_isolate_display ()
1289 TreeModel::Children rows = _model->children();
1290 TreeModel::Children::iterator i;
1292 for (i = rows.begin(); i != rows.end(); ++i) {
1293 boost::shared_ptr<Route> route = (*i)[_columns.route];
1294 (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_visual_state (route) > 0 ? 1 : 0;
1299 EditorRoutes::update_solo_safe_display ()
1301 TreeModel::Children rows = _model->children();
1302 TreeModel::Children::iterator i;
1304 for (i = rows.begin(); i != rows.end(); ++i) {
1305 boost::shared_ptr<Route> route = (*i)[_columns.route];
1306 (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_visual_state (route) > 0 ? 1 : 0;
1311 EditorRoutes::views () const
1313 list<TimeAxisView*> v;
1314 for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
1315 v.push_back ((*i)[_columns.tv]);
1322 EditorRoutes::clear ()
1324 _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1326 _display.set_model (_model);
1330 EditorRoutes::name_edit_started (CellEditable* ce, const Glib::ustring&)
1334 /* give it a special name */
1336 Gtk::Entry *e = dynamic_cast<Gtk::Entry*> (ce);
1339 e->set_name (X_("RouteNameEditorEntry"));
1344 EditorRoutes::name_edit (std::string const & path, std::string const & new_text)
1348 TreeIter iter = _model->get_iter (path);
1354 boost::shared_ptr<Route> route = (*iter)[_columns.route];
1356 if (route && route->name() != new_text) {
1357 route->set_name (new_text);
1362 EditorRoutes::solo_changed_so_update_mute ()
1364 update_mute_display ();
1368 EditorRoutes::show_tracks_with_regions_at_playhead ()
1370 boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
1372 set<TimeAxisView*> show;
1373 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
1374 TimeAxisView* tav = _editor->axis_view_from_route (*i);
1380 suspend_redisplay ();
1382 TreeModel::Children rows = _model->children ();
1383 for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
1384 TimeAxisView* tv = (*i)[_columns.tv];
1385 (*i)[_columns.visible] = (show.find (tv) != show.end());
1388 resume_redisplay ();