2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #include "ardour/diskstream.h"
28 #include "ardour/session.h"
32 #include "ardour_ui.h"
33 #include "audio_time_axis.h"
34 #include "midi_time_axis.h"
35 #include "mixer_strip.h"
36 #include "gui_thread.h"
39 #include "editor_group_tabs.h"
40 #include "editor_routes.h"
42 #include "pbd/unknown_type.h"
44 #include "ardour/route.h"
46 #include "gtkmm2ext/cell_renderer_pixbuf_multi.h"
47 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
52 using namespace ARDOUR;
55 using namespace Gtkmm2ext;
57 using Gtkmm2ext::Keyboard;
59 EditorRoutes::EditorRoutes (Editor* e)
60 : EditorComponent (e),
61 _ignore_reorder (false),
62 _no_redisplay (false),
63 _redisplay_does_not_sync_order_keys (false),
64 _redisplay_does_not_reset_order_keys (false),
67 _scroller.add (_display);
68 _scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
70 _model = ListStore::create (_columns);
71 _display.set_model (_model);
73 // Record enable toggle
74 CellRendererPixbufToggle* rec_col_renderer = manage (new CellRendererPixbufToggle());
76 rec_col_renderer->set_active_pixbuf (::get_icon("rec-enabled"));
77 rec_col_renderer->set_inactive_pixbuf (::get_icon("act-disabled"));
78 rec_col_renderer->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_rec_enable_toggled));
80 TreeViewColumn* rec_state_column = manage (new TreeViewColumn("R", *rec_col_renderer));
82 rec_state_column->add_attribute(rec_col_renderer->property_active(), _columns.rec_enabled);
83 rec_state_column->add_attribute(rec_col_renderer->property_visible(), _columns.is_track);
84 rec_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
85 rec_state_column->set_alignment(ALIGN_CENTER);
86 rec_state_column->set_expand(false);
87 rec_state_column->set_fixed_width(15);
90 CellRendererPixbufMulti* mute_col_renderer = manage (new CellRendererPixbufMulti());
92 mute_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
93 mute_col_renderer->set_pixbuf (1, ::get_icon("mute-enabled"));
94 mute_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_mute_enable_toggled));
96 TreeViewColumn* mute_state_column = manage (new TreeViewColumn("M", *mute_col_renderer));
98 mute_state_column->add_attribute(mute_col_renderer->property_state(), _columns.mute_state);
99 mute_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
100 mute_state_column->set_alignment(ALIGN_CENTER);
101 mute_state_column->set_expand(false);
102 mute_state_column->set_fixed_width(15);
104 // Solo enable toggle
105 CellRendererPixbufMulti* solo_col_renderer = manage (new CellRendererPixbufMulti());
107 solo_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
108 solo_col_renderer->set_pixbuf (1, ::get_icon("solo-enabled"));
109 solo_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_enable_toggled));
111 TreeViewColumn* solo_state_column = manage (new TreeViewColumn("S", *solo_col_renderer));
113 solo_state_column->add_attribute(solo_col_renderer->property_state(), _columns.solo_state);
114 solo_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
115 solo_state_column->set_alignment(ALIGN_CENTER);
116 solo_state_column->set_expand(false);
117 solo_state_column->set_fixed_width(15);
119 // Solo isolate toggle
120 CellRendererPixbufMulti* solo_iso_renderer = manage (new CellRendererPixbufMulti());
122 solo_iso_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
123 solo_iso_renderer->set_pixbuf (1, ::get_icon("solo-isolated"));
124 solo_iso_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_isolate_toggled));
126 TreeViewColumn* solo_isolate_state_column = manage (new TreeViewColumn("I", *solo_iso_renderer));
128 solo_isolate_state_column->add_attribute(solo_iso_renderer->property_state(), _columns.solo_isolate_state);
129 solo_isolate_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
130 solo_isolate_state_column->set_alignment(ALIGN_CENTER);
131 solo_isolate_state_column->set_expand(false);
132 solo_isolate_state_column->set_fixed_width(15);
134 _display.append_column (*rec_state_column);
135 _display.append_column (*mute_state_column);
136 _display.append_column (*solo_state_column);
137 _display.append_column (*solo_isolate_state_column);
139 _display.append_column (_("Name"), _columns.text);
140 _display.append_column (_("V"), _columns.visible);
142 _display.set_headers_visible (true);
143 _display.set_name ("TrackListDisplay");
144 _display.get_selection()->set_mode (SELECTION_SINGLE);
145 _display.set_reorderable (true);
146 _display.set_rules_hint (true);
147 _display.set_size_request (100, -1);
148 _display.add_object_drag (_columns.route.index(), "routes");
150 CellRendererText* name_cell = dynamic_cast<CellRendererText*> (_display.get_column_cell_renderer (4));
154 TreeViewColumn* name_column = _display.get_column (4);
156 assert (name_column);
158 name_column->add_attribute (name_cell->property_editable(), _columns.name_editable);
159 name_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
160 name_column->set_expand(true);
161 name_column->set_min_width(50);
163 name_cell->property_editable() = true;
164 name_cell->signal_edited().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit));
166 // Set the visible column cell renderer to radio toggle
167 CellRendererToggle* visible_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (5));
169 visible_cell->property_activatable() = true;
170 visible_cell->property_radio() = false;
171 visible_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::visible_changed));
173 TreeViewColumn* visible_col = dynamic_cast<TreeViewColumn*> (_display.get_column (5));
174 visible_col->set_expand(false);
175 visible_col->set_sizing(TREE_VIEW_COLUMN_FIXED);
176 visible_col->set_fixed_width(30);
177 visible_col->set_alignment(ALIGN_CENTER);
179 _model->signal_row_deleted().connect (sigc::mem_fun (*this, &EditorRoutes::route_deleted));
180 _model->signal_rows_reordered().connect (sigc::mem_fun (*this, &EditorRoutes::reordered));
182 _display.signal_button_press_event().connect (sigc::mem_fun (*this, &EditorRoutes::button_press), false);
184 Route::SyncOrderKeys.connect (*this, ui_bind (&EditorRoutes::sync_order_keys, this, _1), gui_context());
188 EditorRoutes::set_session (Session* s)
190 EditorComponent::set_session (s);
195 _session->SoloChanged.connect (*this, boost::bind (&EditorRoutes::solo_changed_so_update_mute, this), gui_context());
200 EditorRoutes::on_tv_rec_enable_toggled (Glib::ustring const & path_string)
202 // Get the model row that has been toggled.
203 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
205 TimeAxisView *tv = row[_columns.tv];
206 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
208 if (atv != 0 && atv->is_audio_track()){
209 boost::shared_ptr<RouteList> rl (new RouteList);
210 rl->push_back (atv->route());
211 _session->set_record_enable (rl, !atv->track()->record_enabled(), Session::rt_cleanup);
216 EditorRoutes::on_tv_mute_enable_toggled (Glib::ustring const & path_string)
218 // Get the model row that has been toggled.
219 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
221 TimeAxisView *tv = row[_columns.tv];
222 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
225 boost::shared_ptr<RouteList> rl (new RouteList);
226 rl->push_back (atv->route());
227 _session->set_mute (rl, !atv->route()->muted(), Session::rt_cleanup);
232 EditorRoutes::on_tv_solo_enable_toggled (Glib::ustring const & path_string)
234 // Get the model row that has been toggled.
235 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
237 TimeAxisView *tv = row[_columns.tv];
238 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
241 boost::shared_ptr<RouteList> rl (new RouteList);
242 rl->push_back (atv->route());
243 _session->set_solo (rl, !atv->route()->soloed(), Session::rt_cleanup);
248 EditorRoutes::on_tv_solo_isolate_toggled (Glib::ustring const & path_string)
250 // Get the model row that has been toggled.
251 Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
253 TimeAxisView *tv = row[_columns.tv];
254 AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
257 atv->route()->set_solo_isolated (!atv->route()->solo_isolated(), this);
262 EditorRoutes::build_menu ()
264 using namespace Menu_Helpers;
269 MenuList& items = _menu->items();
270 _menu->set_name ("ArdourContextMenu");
272 items.push_back (MenuElem (_("Show All"), sigc::mem_fun (*this, &EditorRoutes::show_all_routes)));
273 items.push_back (MenuElem (_("Hide All"), sigc::mem_fun (*this, &EditorRoutes::hide_all_routes)));
274 items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiotracks)));
275 items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiotracks)));
276 items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiobus)));
277 items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiobus)));
278 items.push_back (MenuElem (_("Show Tracks With Regions Under Playhead"), sigc::mem_fun (*this, &EditorRoutes::show_tracks_with_regions_at_playhead)));
282 EditorRoutes::show_menu ()
288 _menu->popup (1, gtk_get_current_event_time());
292 EditorRoutes::redisplay ()
294 if (_no_redisplay || !_session) {
298 TreeModel::Children rows = _model->children();
299 TreeModel::Children::iterator i;
303 for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
304 TimeAxisView *tv = (*i)[_columns.tv];
305 boost::shared_ptr<Route> route = (*i)[_columns.route];
308 // just a "title" row
312 if (!_redisplay_does_not_reset_order_keys) {
313 /* this reorder is caused by user action, so reassign sort order keys
316 route->set_order_key (N_ ("editor"), n);
319 bool visible = (*i)[_columns.visible];
321 /* show or hide the TimeAxisView */
323 tv->set_marked_for_display (true);
324 position += tv->show_at (position, n, &_editor->edit_controls_vbox);
325 tv->clip_to_viewport ();
327 tv->set_marked_for_display (false);
334 /* whenever we go idle, update the track view list to reflect the new order.
335 we can't do this here, because we could mess up something that is traversing
336 the track order and has caused a redisplay of the list.
338 Glib::signal_idle().connect (sigc::mem_fun (*_editor, &Editor::sync_track_view_list_and_routes));
340 _editor->full_canvas_height = position + _editor->canvas_timebars_vsize;
341 _editor->vertical_adjustment.set_upper (_editor->full_canvas_height);
343 if ((_editor->vertical_adjustment.get_value() + _editor->_canvas_height) > _editor->vertical_adjustment.get_upper()) {
345 We're increasing the size of the canvas while the bottom is visible.
346 We scroll down to keep in step with the controls layout.
348 _editor->vertical_adjustment.set_value (_editor->full_canvas_height - _editor->_canvas_height);
351 if (!_redisplay_does_not_reset_order_keys && !_redisplay_does_not_sync_order_keys) {
352 _session->sync_order_keys (N_ ("editor"));
357 EditorRoutes::route_deleted (Gtk::TreeModel::Path const &)
359 if (!_session || _session->deletion_in_progress()) {
363 /* this could require an order reset & sync */
364 _session->set_remote_control_ids();
365 _ignore_reorder = true;
367 _ignore_reorder = false;
371 EditorRoutes::visible_changed (Glib::ustring const & path)
373 if (_session && _session->deletion_in_progress()) {
379 if ((iter = _model->get_iter (path))) {
380 TimeAxisView* tv = (*iter)[_columns.tv];
382 bool visible = (*iter)[_columns.visible];
383 (*iter)[_columns.visible] = !visible;
387 _redisplay_does_not_reset_order_keys = true;
388 _session->set_remote_control_ids();
390 _redisplay_does_not_reset_order_keys = false;
394 EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
398 _redisplay_does_not_sync_order_keys = true;
399 suspend_redisplay ();
401 for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) {
403 row = *(_model->append ());
405 row[_columns.text] = (*x)->route()->name();
406 row[_columns.visible] = (*x)->marked_for_display();
407 row[_columns.tv] = *x;
408 row[_columns.route] = (*x)->route ();
409 row[_columns.is_track] = (boost::dynamic_pointer_cast<Track> ((*x)->route()) != 0);
410 row[_columns.mute_state] = (*x)->route()->muted();
411 row[_columns.solo_state] = (*x)->route()->soloed();
412 row[_columns.solo_isolate_state] = (*x)->route()->solo_isolated();
413 row[_columns.name_editable] = true;
415 _ignore_reorder = true;
417 /* added a new fresh one at the end */
418 if ((*x)->route()->order_key (N_ ("editor")) == -1) {
419 (*x)->route()->set_order_key (N_ ("editor"), _model->children().size()-1);
422 _ignore_reorder = false;
424 boost::weak_ptr<Route> wr ((*x)->route());
426 (*x)->route()->gui_changed.connect (*this, ui_bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
427 (*x)->route()->PropertyChanged.connect (*this, ui_bind (&EditorRoutes::route_property_changed, this, _1, wr), gui_context());
429 if ((*x)->is_track()) {
430 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
431 t->diskstream()->RecordEnableChanged.connect (*this, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
434 (*x)->route()->mute_changed.connect (*this, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
435 (*x)->route()->solo_changed.connect (*this, boost::bind (&EditorRoutes::update_solo_display, this), gui_context());
436 (*x)->route()->solo_isolated_changed.connect (*this, boost::bind (&EditorRoutes::update_solo_isolate_display, this), gui_context());
439 update_rec_display ();
440 update_mute_display ();
441 update_solo_display ();
442 update_solo_isolate_display ();
444 _redisplay_does_not_sync_order_keys = false;
448 EditorRoutes::handle_gui_changes (string const & what, void*)
450 ENSURE_GUI_THREAD (*this, &EditorRoutes::handle_gui_changes, what, src)
452 if (what == "track_height") {
453 /* Optional :make tracks change height while it happens, instead
456 //update_canvas_now ();
460 if (what == "visible_tracks") {
466 EditorRoutes::route_removed (TimeAxisView *tv)
468 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed, tv)
470 TreeModel::Children rows = _model->children();
471 TreeModel::Children::iterator ri;
473 /* the core model has changed, there is no need to sync
477 _redisplay_does_not_sync_order_keys = true;
479 for (ri = rows.begin(); ri != rows.end(); ++ri) {
480 if ((*ri)[_columns.tv] == tv) {
486 _redisplay_does_not_sync_order_keys = false;
490 EditorRoutes::route_property_changed (const PropertyChange& what_changed, boost::weak_ptr<Route> r)
492 if (!what_changed.contains (ARDOUR::Properties::name)) {
496 ENSURE_GUI_THREAD (*this, &EditorRoutes::route_name_changed, r)
498 boost::shared_ptr<Route> route = r.lock ();
504 TreeModel::Children rows = _model->children();
505 TreeModel::Children::iterator i;
507 for (i = rows.begin(); i != rows.end(); ++i) {
508 boost::shared_ptr<Route> t = (*i)[_columns.route];
510 (*i)[_columns.text] = route->name();
517 EditorRoutes::update_visibility ()
519 TreeModel::Children rows = _model->children();
520 TreeModel::Children::iterator i;
522 suspend_redisplay ();
524 for (i = rows.begin(); i != rows.end(); ++i) {
525 TimeAxisView *tv = (*i)[_columns.tv];
526 (*i)[_columns.visible] = tv->marked_for_display ();
527 cerr << "marked " << tv->name() << " for display = " << tv->marked_for_display() << endl;
534 EditorRoutes::hide_track_in_display (TimeAxisView& tv)
536 TreeModel::Children rows = _model->children();
537 TreeModel::Children::iterator i;
539 for (i = rows.begin(); i != rows.end(); ++i) {
540 if ((*i)[_columns.tv] == &tv) {
541 (*i)[_columns.visible] = false;
548 EditorRoutes::show_track_in_display (TimeAxisView& tv)
550 TreeModel::Children rows = _model->children();
551 TreeModel::Children::iterator i;
553 for (i = rows.begin(); i != rows.end(); ++i) {
554 if ((*i)[_columns.tv] == &tv) {
555 (*i)[_columns.visible] = true;
562 EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
567 /** If src != "editor", take editor order keys from each route and use them to rearrange the
568 * route list so that the visual arrangement of routes matches the order keys from the routes.
571 EditorRoutes::sync_order_keys (string const & src)
573 vector<int> neworder;
574 TreeModel::Children rows = _model->children();
575 TreeModel::Children::iterator ri;
577 if (src == N_ ("editor") || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
581 for (ri = rows.begin(); ri != rows.end(); ++ri) {
582 neworder.push_back (0);
585 bool changed = false;
588 for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
589 boost::shared_ptr<Route> route = (*ri)[_columns.route];
592 int new_key = route->order_key (N_ ("editor"));
594 neworder[new_key] = old_key;
596 if (new_key != old_key) {
602 _redisplay_does_not_reset_order_keys = true;
603 _model->reorder (neworder);
604 _redisplay_does_not_reset_order_keys = false;
610 EditorRoutes::hide_all_tracks (bool /*with_select*/)
612 TreeModel::Children rows = _model->children();
613 TreeModel::Children::iterator i;
615 suspend_redisplay ();
617 for (i = rows.begin(); i != rows.end(); ++i) {
619 TreeModel::Row row = (*i);
620 TimeAxisView *tv = row[_columns.tv];
626 row[_columns.visible] = false;
631 /* XXX this seems like a hack and half, but its not clear where to put this
635 //reset_scrolling_region ();
639 EditorRoutes::set_all_tracks_visibility (bool yn)
641 TreeModel::Children rows = _model->children();
642 TreeModel::Children::iterator i;
644 suspend_redisplay ();
646 for (i = rows.begin(); i != rows.end(); ++i) {
648 TreeModel::Row row = (*i);
649 TimeAxisView* tv = row[_columns.tv];
655 (*i)[_columns.visible] = yn;
662 EditorRoutes::set_all_audio_visibility (int tracks, bool yn)
664 TreeModel::Children rows = _model->children();
665 TreeModel::Children::iterator i;
667 suspend_redisplay ();
669 for (i = rows.begin(); i != rows.end(); ++i) {
670 TreeModel::Row row = (*i);
671 TimeAxisView* tv = row[_columns.tv];
672 AudioTimeAxisView* atv;
678 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
681 (*i)[_columns.visible] = yn;
685 if (atv->is_audio_track()) {
686 (*i)[_columns.visible] = yn;
691 if (!atv->is_audio_track()) {
692 (*i)[_columns.visible] = yn;
703 EditorRoutes::hide_all_routes ()
705 set_all_tracks_visibility (false);
709 EditorRoutes::show_all_routes ()
711 set_all_tracks_visibility (true);
715 EditorRoutes::show_all_audiobus ()
717 set_all_audio_visibility (2, true);
720 EditorRoutes::hide_all_audiobus ()
722 set_all_audio_visibility (2, false);
726 EditorRoutes::show_all_audiotracks()
728 set_all_audio_visibility (1, true);
731 EditorRoutes::hide_all_audiotracks ()
733 set_all_audio_visibility (1, false);
737 EditorRoutes::button_press (GdkEventButton* ev)
739 if (Keyboard::is_context_menu_event (ev)) {
744 //Scroll editor canvas to selected track
745 if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
747 TreeModel::Path path;
752 _display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y);
754 // Get the model row.
755 Gtk::TreeModel::Row row = *_model->get_iter (path);
757 TimeAxisView *tv = row[_columns.tv];
759 int y_pos = tv->y_position();
761 //Clamp the y pos so that we do not extend beyond the canvas full height.
762 if (_editor->full_canvas_height - y_pos < _editor->_canvas_height){
763 y_pos = _editor->full_canvas_height - _editor->_canvas_height;
766 //Only scroll to if the track is visible
768 _editor->reset_y_origin (y_pos);
776 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const &, bool)
781 struct EditorOrderRouteSorter {
782 bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
783 /* use of ">" forces the correct sort order */
784 return a->order_key (N_ ("editor")) < b->order_key (N_ ("editor"));
789 EditorRoutes::initial_display ()
791 suspend_redisplay ();
799 boost::shared_ptr<RouteList> routes = _session->get_routes();
800 RouteList r (*routes);
801 EditorOrderRouteSorter sorter;
804 _editor->handle_new_route (r);
806 /* don't show master bus in a new session */
808 if (ARDOUR_UI::instance()->session_is_new ()) {
810 TreeModel::Children rows = _model->children();
811 TreeModel::Children::iterator i;
813 _no_redisplay = true;
815 for (i = rows.begin(); i != rows.end(); ++i) {
817 TimeAxisView *tv = (*i)[_columns.tv];
818 RouteTimeAxisView *rtv;
820 if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
821 if (rtv->route()->is_master()) {
822 _display.get_selection()->unselect (i);
827 _no_redisplay = false;
835 EditorRoutes::track_list_reorder (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &, int* /*new_order*/)
837 _redisplay_does_not_sync_order_keys = true;
838 _session->set_remote_control_ids();
840 _redisplay_does_not_sync_order_keys = false;
844 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
846 const SelectionData& data,
847 guint info, guint time)
849 if (data.get_target() == "GTK_TREE_MODEL_ROW") {
850 _display.on_drag_data_received (context, x, y, data, info, time);
854 context->drag_finish (true, false, time);
858 EditorRoutes::move_selected_tracks (bool up)
860 if (_editor->selection->tracks.empty()) {
864 typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
865 std::list<ViewRoute> view_routes;
866 std::vector<int> neworder;
867 TreeModel::Children rows = _model->children();
868 TreeModel::Children::iterator ri;
870 for (ri = rows.begin(); ri != rows.end(); ++ri) {
871 TimeAxisView* tv = (*ri)[_columns.tv];
872 boost::shared_ptr<Route> route = (*ri)[_columns.route];
874 view_routes.push_back (ViewRoute (tv, route));
877 list<ViewRoute>::iterator trailing;
878 list<ViewRoute>::iterator leading;
882 trailing = view_routes.begin();
883 leading = view_routes.begin();
887 while (leading != view_routes.end()) {
888 if (_editor->selection->selected (leading->first)) {
889 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
890 leading = view_routes.erase (leading);
899 /* if we could use reverse_iterator in list::insert, this code
900 would be a beautiful reflection of the code above. but we can't
901 and so it looks like a bit of a mess.
904 trailing = view_routes.end();
905 leading = view_routes.end();
907 --leading; if (leading == view_routes.begin()) { return; }
913 if (_editor->selection->selected (leading->first)) {
914 list<ViewRoute>::iterator tmp;
916 /* need to insert *after* trailing, not *before* it,
917 which is what insert (iter, val) normally does.
923 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
925 /* can't use iter = cont.erase (iter); form here, because
926 we need iter to move backwards.
934 if (leading == view_routes.begin()) {
935 /* the one we've just inserted somewhere else
936 was the first in the list. erase this copy,
937 and then break, because we're done.
942 view_routes.erase (leading);
951 if (leading == view_routes.begin()) {
960 for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
961 neworder.push_back (leading->second->order_key (N_ ("editor")));
964 _model->reorder (neworder);
966 _session->sync_order_keys (N_ ("editor"));
970 EditorRoutes::update_rec_display ()
972 TreeModel::Children rows = _model->children();
973 TreeModel::Children::iterator i;
975 for (i = rows.begin(); i != rows.end(); ++i) {
976 boost::shared_ptr<Route> route = (*i)[_columns.route];
978 if (boost::dynamic_pointer_cast<Track>(route)) {
979 (*i)[_columns.rec_enabled] = route->record_enabled ();
980 (*i)[_columns.name_editable] = !route->record_enabled ();
986 EditorRoutes::update_mute_display ()
988 TreeModel::Children rows = _model->children();
989 TreeModel::Children::iterator i;
991 for (i = rows.begin(); i != rows.end(); ++i) {
992 boost::shared_ptr<Route> route = (*i)[_columns.route];
993 (*i)[_columns.mute_state] = RouteUI::mute_visual_state (_session, route) > 0 ? 1 : 0;
998 EditorRoutes::update_solo_display ()
1000 TreeModel::Children rows = _model->children();
1001 TreeModel::Children::iterator i;
1003 for (i = rows.begin(); i != rows.end(); ++i) {
1004 boost::shared_ptr<Route> route = (*i)[_columns.route];
1005 (*i)[_columns.solo_state] = RouteUI::solo_visual_state (route) > 0 ? 1 : 0;
1010 EditorRoutes::update_solo_isolate_display ()
1012 TreeModel::Children rows = _model->children();
1013 TreeModel::Children::iterator i;
1015 for (i = rows.begin(); i != rows.end(); ++i) {
1016 boost::shared_ptr<Route> route = (*i)[_columns.route];
1017 (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_visual_state (route) > 0 ? 1 : 0;
1022 EditorRoutes::views () const
1024 list<TimeAxisView*> v;
1025 for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
1026 v.push_back ((*i)[_columns.tv]);
1033 EditorRoutes::clear ()
1035 _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1037 _display.set_model (_model);
1041 EditorRoutes::name_edit (Glib::ustring const & path, Glib::ustring const & new_text)
1043 TreeIter iter = _model->get_iter (path);
1048 boost::shared_ptr<Route> route = (*iter)[_columns.route];
1050 if (route && route->name() != new_text) {
1051 route->set_name (new_text);
1056 EditorRoutes::solo_changed_so_update_mute ()
1058 ENSURE_GUI_THREAD (*this, &EditorRoutes::solo_changed_so_update_mute)
1059 update_mute_display ();
1063 EditorRoutes::show_tracks_with_regions_at_playhead ()
1065 boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
1067 set<TimeAxisView*> show;
1068 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
1069 TimeAxisView* tav = _editor->axis_view_from_route (*i);
1075 suspend_redisplay ();
1077 TreeModel::Children rows = _model->children ();
1078 for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
1079 TimeAxisView* tv = (*i)[_columns.tv];
1080 (*i)[_columns.visible] = (show.find (tv) != show.end());
1083 resume_redisplay ();