ca22b8cbf70bb7ee98fc4925fc883fab26328dee
[ardour.git] / gtk2_ardour / editor_routes.cc
1 /*
2     Copyright (C) 2000-2009 Paul Davis
3
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.
8
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.
13
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.
17
18 */
19
20 #include <list>
21 #include <vector>
22 #include <algorithm>
23 #include <cstdlib>
24 #include <cmath>
25 #include <cassert>
26
27 #include "ardour/diskstream.h"
28 #include "ardour/session.h"
29
30 #include "editor.h"
31 #include "keyboard.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"
37 #include "actions.h"
38 #include "utils.h"
39 #include "editor_group_tabs.h"
40 #include "editor_routes.h"
41
42 #include "pbd/unknown_type.h"
43
44 #include "ardour/route.h"
45
46 #include "gtkmm2ext/cell_renderer_pixbuf_multi.h"
47 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
48
49 #include "i18n.h"
50
51 using namespace std;
52 using namespace sigc;
53 using namespace ARDOUR;
54 using namespace PBD;
55 using namespace Gtk;
56 using namespace Gtkmm2ext;
57 using namespace Glib;
58
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),
65           _menu (0)
66 {
67         _scroller.add (_display);
68         _scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
69
70         _model = ListStore::create (_columns);
71         _display.set_model (_model);
72
73         // Record enable toggle
74         CellRendererPixbufToggle* rec_col_renderer = manage (new CellRendererPixbufToggle());
75
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 (mem_fun (*this, &EditorRoutes::on_tv_rec_enable_toggled));
79
80         TreeViewColumn* rec_state_column = manage (new TreeViewColumn("R", *rec_col_renderer));
81
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
85         // Mute enable toggle
86         CellRendererPixbufMulti* mute_col_renderer = manage (new CellRendererPixbufMulti());
87
88         mute_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
89         mute_col_renderer->set_pixbuf (1, ::get_icon("mute-enabled"));
90         mute_col_renderer->signal_changed().connect (mem_fun (*this, &EditorRoutes::on_tv_mute_enable_toggled));
91
92         TreeViewColumn* mute_state_column = manage (new TreeViewColumn("M", *mute_col_renderer));
93
94         mute_state_column->add_attribute(mute_col_renderer->property_state(), _columns.mute_state);
95
96         // Solo enable toggle
97         CellRendererPixbufMulti* solo_col_renderer = manage (new CellRendererPixbufMulti());
98
99         solo_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
100         solo_col_renderer->set_pixbuf (1, ::get_icon("solo-enabled"));
101         solo_col_renderer->signal_changed().connect (mem_fun (*this, &EditorRoutes::on_tv_solo_enable_toggled));
102
103         TreeViewColumn* solo_state_column = manage (new TreeViewColumn("S", *solo_col_renderer));
104
105         solo_state_column->add_attribute(solo_col_renderer->property_state(), _columns.solo_state);
106
107         _display.append_column (*rec_state_column);
108         _display.append_column (*mute_state_column);
109         _display.append_column (*solo_state_column);
110         _display.append_column (_("Show"), _columns.visible);
111         _display.append_column (_("Name"), _columns.text);
112
113         _display.get_column (0)->set_data (X_("colnum"), GUINT_TO_POINTER(0));
114         _display.get_column (1)->set_data (X_("colnum"), GUINT_TO_POINTER(1));
115         _display.get_column (2)->set_data (X_("colnum"), GUINT_TO_POINTER(2));
116         _display.get_column (3)->set_data (X_("colnum"), GUINT_TO_POINTER(3));
117         _display.get_column (4)->set_data (X_("colnum"), GUINT_TO_POINTER(4));
118
119         _display.set_headers_visible (true);
120         _display.set_name ("TrackListDisplay");
121         _display.get_selection()->set_mode (SELECTION_SINGLE);
122         _display.set_reorderable (true);
123         _display.set_rules_hint (true);
124         _display.set_size_request (100, -1);
125         _display.add_object_drag (_columns.route.index(), "routes");
126
127         CellRendererText* name_cell = dynamic_cast<CellRendererText*> (_display.get_column_cell_renderer (4));
128         assert (name_cell);
129
130         TreeViewColumn* name_column = _display.get_column (4);
131         assert (name_column);
132
133         name_column->add_attribute (name_cell->property_editable(), _columns.name_editable);
134         name_cell->property_editable() = true;
135         name_cell->signal_edited().connect (mem_fun (*this, &EditorRoutes::name_edit));
136
137         CellRendererToggle* visible_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (3));
138
139         visible_cell->property_activatable() = true;
140         visible_cell->property_radio() = false;
141         visible_cell->signal_toggled().connect (mem_fun (*this, &EditorRoutes::visible_changed));
142
143         _model->signal_row_deleted().connect (mem_fun (*this, &EditorRoutes::route_deleted));
144         _model->signal_rows_reordered().connect (mem_fun (*this, &EditorRoutes::reordered));
145         _display.signal_button_press_event().connect (mem_fun (*this, &EditorRoutes::button_press), false);
146
147         Route::SyncOrderKeys.connect (mem_fun (*this, &EditorRoutes::sync_order_keys));
148 }
149
150 void
151 EditorRoutes::connect_to_session (Session* s)
152 {
153         EditorComponent::connect_to_session (s);
154
155         initial_display ();
156
157         _session->SoloChanged.connect (mem_fun (*this, &EditorRoutes::solo_changed_so_update_mute));
158 }
159
160 void
161 EditorRoutes::on_tv_rec_enable_toggled (Glib::ustring const & path_string)
162 {
163         // Get the model row that has been toggled.
164         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
165
166         row[_columns.name_editable] = !row[_columns.rec_enabled];
167         
168         TimeAxisView *tv = row[_columns.tv];
169         AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
170
171         if (atv != 0 && atv->is_audio_track()){
172                 atv->reversibly_apply_track_boolean ("rec-enable change", &Track::set_record_enable, !atv->track()->record_enabled(), this);
173         }
174 }
175
176 void
177 EditorRoutes::on_tv_mute_enable_toggled (Glib::ustring const & path_string)
178 {
179         // Get the model row that has been toggled.
180         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
181
182         TimeAxisView *tv = row[_columns.tv];
183         AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
184
185         if (atv != 0) {
186                 atv->reversibly_apply_route_boolean ("mute-enable change", &Route::set_mute, !atv->route()->muted(), this);
187         }
188 }
189
190 void
191 EditorRoutes::on_tv_solo_enable_toggled (Glib::ustring const & path_string)
192 {
193         // Get the model row that has been toggled.
194         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
195
196         TimeAxisView *tv = row[_columns.tv];
197         AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
198
199         if (atv != 0) {
200                 atv->reversibly_apply_route_boolean ("solo-enable change", &Route::set_solo, !atv->route()->soloed(), this);
201         }
202 }
203
204 void
205 EditorRoutes::build_menu ()
206 {
207         using namespace Menu_Helpers;
208         using namespace Gtk;
209
210         _menu = new Menu;
211
212         MenuList& items = _menu->items();
213         _menu->set_name ("ArdourContextMenu");
214
215         items.push_back (MenuElem (_("Show All"), mem_fun (*this, &EditorRoutes::show_all_routes)));
216         items.push_back (MenuElem (_("Hide All"), mem_fun (*this, &EditorRoutes::hide_all_routes)));
217         items.push_back (MenuElem (_("Show All Audio Tracks"), mem_fun (*this, &EditorRoutes::show_all_audiotracks)));
218         items.push_back (MenuElem (_("Hide All Audio Tracks"), mem_fun (*this, &EditorRoutes::hide_all_audiotracks)));
219         items.push_back (MenuElem (_("Show All Audio Busses"), mem_fun (*this, &EditorRoutes::show_all_audiobus)));
220         items.push_back (MenuElem (_("Hide All Audio Busses"), mem_fun (*this, &EditorRoutes::hide_all_audiobus)));
221         items.push_back (MenuElem (_("Show Tracks With Regions Under Playhead"), mem_fun (*this, &EditorRoutes::show_tracks_with_regions_at_playhead)));
222 }
223
224 void
225 EditorRoutes::show_menu ()
226 {
227         if (_menu == 0) {
228                 build_menu ();
229         }
230
231         _menu->popup (1, gtk_get_current_event_time());
232 }
233
234 void
235 EditorRoutes::redisplay ()
236 {
237         TreeModel::Children rows = _model->children();
238         TreeModel::Children::iterator i;
239         uint32_t position;
240         int n;
241
242         if (_no_redisplay) {
243                 return;
244         }
245
246         for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
247                 TimeAxisView *tv = (*i)[_columns.tv];
248                 boost::shared_ptr<Route> route = (*i)[_columns.route];
249
250                 if (tv == 0) {
251                         // just a "title" row
252                         continue;
253                 }
254
255                 if (!_redisplay_does_not_reset_order_keys) {
256                         /* this reorder is caused by user action, so reassign sort order keys
257                            to tracks.
258                         */
259                         route->set_order_key (N_ ("editor"), n);
260                 }
261
262                 bool visible = (*i)[_columns.visible];
263
264                 /* show or hide the TimeAxisView */
265                 if (visible) {
266                         tv->set_marked_for_display (true);
267                         position += tv->show_at (position, n, &_editor->edit_controls_vbox);
268                         tv->clip_to_viewport ();
269                 } else {
270                         tv->set_marked_for_display (false);
271                         tv->hide ();
272                 }
273
274                 n++;
275         }
276
277         /* whenever we go idle, update the track view list to reflect the new order.
278            we can't do this here, because we could mess up something that is traversing
279            the track order and has caused a redisplay of the list.
280         */
281         Glib::signal_idle().connect (mem_fun (*_editor, &Editor::sync_track_view_list_and_routes));
282
283         _editor->full_canvas_height = position + _editor->canvas_timebars_vsize;
284         _editor->vertical_adjustment.set_upper (_editor->full_canvas_height);
285
286         if ((_editor->vertical_adjustment.get_value() + _editor->_canvas_height) > _editor->vertical_adjustment.get_upper()) {
287                 /*
288                    We're increasing the size of the canvas while the bottom is visible.
289                    We scroll down to keep in step with the controls layout.
290                 */
291                 _editor->vertical_adjustment.set_value (_editor->full_canvas_height - _editor->_canvas_height);
292         }
293
294         if (!_redisplay_does_not_reset_order_keys && !_redisplay_does_not_sync_order_keys) {
295                 _session->sync_order_keys (N_ ("editor"));
296         }
297 }
298
299 void
300 EditorRoutes::route_deleted (Gtk::TreeModel::Path const &)
301 {
302         /* this could require an order reset & sync */
303         _session->set_remote_control_ids();
304         _ignore_reorder = true;
305         redisplay ();
306         _ignore_reorder = false;
307 }
308
309
310 void
311 EditorRoutes::visible_changed (Glib::ustring const & path)
312 {
313         TreeIter iter;
314
315         if ((iter = _model->get_iter (path))) {
316                 TimeAxisView* tv = (*iter)[_columns.tv];
317                 if (tv) {
318                         bool visible = (*iter)[_columns.visible];
319                         (*iter)[_columns.visible] = !visible;
320                 }
321         }
322
323         _redisplay_does_not_reset_order_keys = true;
324         _session->set_remote_control_ids();
325         redisplay ();
326         _redisplay_does_not_reset_order_keys = false;
327 }
328
329 void
330 EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
331 {
332         TreeModel::Row row;
333
334         _redisplay_does_not_sync_order_keys = true;
335         suspend_redisplay ();
336
337         for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) {
338
339                 row = *(_model->append ());
340
341                 row[_columns.text] = (*x)->route()->name();
342                 row[_columns.visible] = (*x)->marked_for_display();
343                 row[_columns.tv] = *x;
344                 row[_columns.route] = (*x)->route ();
345                 row[_columns.is_track] = (boost::dynamic_pointer_cast<Track> ((*x)->route()) != 0);
346
347                 _ignore_reorder = true;
348
349                 /* added a new fresh one at the end */
350                 if ((*x)->route()->order_key (N_ ("editor")) == -1) {
351                         (*x)->route()->set_order_key (N_ ("editor"), _model->children().size()-1);
352                 }
353
354                 _ignore_reorder = false;
355
356                 boost::weak_ptr<Route> wr ((*x)->route());
357                 (*x)->route()->gui_changed.connect (mem_fun (*this, &EditorRoutes::handle_gui_changes));
358                 (*x)->route()->NameChanged.connect (bind (mem_fun (*this, &EditorRoutes::route_name_changed), wr));
359                 (*x)->GoingAway.connect (bind (mem_fun (*this, &EditorRoutes::route_removed), *x));
360
361                 if ((*x)->is_track()) {
362                         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
363                         t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &EditorRoutes::update_rec_display));
364                 }
365
366                 (*x)->route()->mute_changed.connect (mem_fun (*this, &EditorRoutes::update_mute_display));
367                 (*x)->route()->solo_changed.connect (mem_fun (*this, &EditorRoutes::update_solo_display));
368         }
369
370         update_rec_display ();
371         resume_redisplay ();
372         _redisplay_does_not_sync_order_keys = false;
373 }
374
375 void
376 EditorRoutes::handle_gui_changes (string const & what, void *src)
377 {
378         ENSURE_GUI_THREAD (bind (mem_fun(*this, &EditorRoutes::handle_gui_changes), what, src));
379
380         if (what == "track_height") {
381                 /* Optional :make tracks change height while it happens, instead
382                    of on first-idle
383                 */
384                 //update_canvas_now ();
385                 redisplay ();
386         }
387
388         if (what == "visible_tracks") {
389                 redisplay ();
390         }
391 }
392
393 void
394 EditorRoutes::route_removed (TimeAxisView *tv)
395 {
396         ENSURE_GUI_THREAD (bind (mem_fun(*this, &EditorRoutes::route_removed), tv));
397
398         TreeModel::Children rows = _model->children();
399         TreeModel::Children::iterator ri;
400
401         /* the core model has changed, there is no need to sync
402            view orders.
403         */
404
405         _redisplay_does_not_sync_order_keys = true;
406
407         for (ri = rows.begin(); ri != rows.end(); ++ri) {
408                 if ((*ri)[_columns.tv] == tv) {
409                         _model->erase (ri);
410                         break;
411                 }
412         }
413
414         _redisplay_does_not_sync_order_keys = false;
415 }
416
417 void
418 EditorRoutes::route_name_changed (boost::weak_ptr<Route> r)
419 {
420         ENSURE_GUI_THREAD (bind (mem_fun (*this, &EditorRoutes::route_name_changed), r));
421
422         boost::shared_ptr<Route> route = r.lock ();
423         if (!route) {
424                 return;
425         }
426
427         TreeModel::Children rows = _model->children();
428         TreeModel::Children::iterator i;
429
430         for (i = rows.begin(); i != rows.end(); ++i) {
431                 boost::shared_ptr<Route> t = (*i)[_columns.route];
432                 if (t == route) {
433                         (*i)[_columns.text] = route->name();
434                         break;
435                 }
436         }
437 }
438
439 void
440 EditorRoutes::update_visibility ()
441 {
442         TreeModel::Children rows = _model->children();
443         TreeModel::Children::iterator i;
444
445         suspend_redisplay ();
446
447         for (i = rows.begin(); i != rows.end(); ++i) {
448                 TimeAxisView *tv = (*i)[_columns.tv];
449                 (*i)[_columns.visible] = tv->marked_for_display ();
450                 cerr << "marked " << tv->name() << " for display = " << tv->marked_for_display() << endl;
451         }
452
453         resume_redisplay ();
454 }
455
456 void
457 EditorRoutes::hide_track_in_display (TimeAxisView& tv)
458 {
459         TreeModel::Children rows = _model->children();
460         TreeModel::Children::iterator i;
461
462         for (i = rows.begin(); i != rows.end(); ++i) {
463                 if ((*i)[_columns.tv] == &tv) {
464                         (*i)[_columns.visible] = false;
465                         break;
466                 }
467         }
468 }
469
470 void
471 EditorRoutes::show_track_in_display (TimeAxisView& tv)
472 {
473         TreeModel::Children rows = _model->children();
474         TreeModel::Children::iterator i;
475
476         for (i = rows.begin(); i != rows.end(); ++i) {
477                 if ((*i)[_columns.tv] == &tv) {
478                         (*i)[_columns.visible] = true;
479                         break;
480                 }
481         }
482 }
483
484 void
485 EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
486 {
487         redisplay ();
488 }
489
490 /** If src != "editor", take editor order keys from each route and use them to rearrange the
491  *  route list so that the visual arrangement of routes matches the order keys from the routes.
492  */
493 void
494 EditorRoutes::sync_order_keys (string const & src)
495 {
496         vector<int> neworder;
497         TreeModel::Children rows = _model->children();
498         TreeModel::Children::iterator ri;
499
500         if (src == N_ ("editor") || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
501                 return;
502         }
503
504         for (ri = rows.begin(); ri != rows.end(); ++ri) {
505                 neworder.push_back (0);
506         }
507
508         bool changed = false;
509         int order;
510
511         for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
512                 boost::shared_ptr<Route> route = (*ri)[_columns.route];
513
514                 int old_key = order;
515                 int new_key = route->order_key (N_ ("editor"));
516
517                 neworder[new_key] = old_key;
518
519                 if (new_key != old_key) {
520                         changed = true;
521                 }
522         }
523
524         if (changed) {
525                 _redisplay_does_not_reset_order_keys = true;
526                 _model->reorder (neworder);
527                 _redisplay_does_not_reset_order_keys = false;
528         }
529 }
530
531
532 void
533 EditorRoutes::hide_all_tracks (bool /*with_select*/)
534 {
535         TreeModel::Children rows = _model->children();
536         TreeModel::Children::iterator i;
537
538         suspend_redisplay ();
539
540         for (i = rows.begin(); i != rows.end(); ++i) {
541
542                 TreeModel::Row row = (*i);
543                 TimeAxisView *tv = row[_columns.tv];
544
545                 if (tv == 0) {
546                         continue;
547                 }
548
549                 row[_columns.visible] = false;
550         }
551
552         resume_redisplay ();
553
554         /* XXX this seems like a hack and half, but its not clear where to put this
555            otherwise.
556         */
557
558         //reset_scrolling_region ();
559 }
560
561 void
562 EditorRoutes::set_all_tracks_visibility (bool yn)
563 {
564         TreeModel::Children rows = _model->children();
565         TreeModel::Children::iterator i;
566
567         suspend_redisplay ();
568
569         for (i = rows.begin(); i != rows.end(); ++i) {
570
571                 TreeModel::Row row = (*i);
572                 TimeAxisView* tv = row[_columns.tv];
573
574                 if (tv == 0) {
575                         continue;
576                 }
577
578                 (*i)[_columns.visible] = yn;
579         }
580
581         resume_redisplay ();
582 }
583
584 void
585 EditorRoutes::set_all_audio_visibility (int tracks, bool yn)
586 {
587         TreeModel::Children rows = _model->children();
588         TreeModel::Children::iterator i;
589
590         suspend_redisplay ();
591
592         for (i = rows.begin(); i != rows.end(); ++i) {
593                 TreeModel::Row row = (*i);
594                 TimeAxisView* tv = row[_columns.tv];
595                 AudioTimeAxisView* atv;
596
597                 if (tv == 0) {
598                         continue;
599                 }
600
601                 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
602                         switch (tracks) {
603                         case 0:
604                                 (*i)[_columns.visible] = yn;
605                                 break;
606
607                         case 1:
608                                 if (atv->is_audio_track()) {
609                                         (*i)[_columns.visible] = yn;
610                                 }
611                                 break;
612
613                         case 2:
614                                 if (!atv->is_audio_track()) {
615                                         (*i)[_columns.visible] = yn;
616                                 }
617                                 break;
618                         }
619                 }
620         }
621
622         resume_redisplay ();
623 }
624
625 void
626 EditorRoutes::hide_all_routes ()
627 {
628         set_all_tracks_visibility (false);
629 }
630
631 void
632 EditorRoutes::show_all_routes ()
633 {
634         set_all_tracks_visibility (true);
635 }
636
637 void
638 EditorRoutes::show_all_audiobus ()
639 {
640         set_all_audio_visibility (2, true);
641 }
642 void
643 EditorRoutes::hide_all_audiobus ()
644 {
645         set_all_audio_visibility (2, false);
646 }
647
648 void
649 EditorRoutes::show_all_audiotracks()
650 {
651         set_all_audio_visibility (1, true);
652 }
653 void
654 EditorRoutes::hide_all_audiotracks ()
655 {
656         set_all_audio_visibility (1, false);
657 }
658
659 bool
660 EditorRoutes::button_press (GdkEventButton* ev)
661 {
662         if (Keyboard::is_context_menu_event (ev)) {
663                 show_menu ();
664                 return true;
665         }
666
667         return false;
668 }
669
670 bool
671 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const &, bool)
672 {
673         return true;
674 }
675
676 struct EditorOrderRouteSorter {
677     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
678             /* use of ">" forces the correct sort order */
679             return a->order_key (N_ ("editor")) < b->order_key (N_ ("editor"));
680     }
681 };
682
683 void
684 EditorRoutes::initial_display ()
685 {
686         boost::shared_ptr<RouteList> routes = _session->get_routes();
687         RouteList r (*routes);
688         EditorOrderRouteSorter sorter;
689
690         r.sort (sorter);
691
692         suspend_redisplay ();
693
694         _model->clear ();
695         _editor->handle_new_route (r);
696
697         /* don't show master bus in a new session */
698
699         if (ARDOUR_UI::instance()->session_is_new ()) {
700
701                 TreeModel::Children rows = _model->children();
702                 TreeModel::Children::iterator i;
703
704                 _no_redisplay = true;
705
706                 for (i = rows.begin(); i != rows.end(); ++i) {
707                         TimeAxisView *tv =  (*i)[_columns.tv];
708                         RouteTimeAxisView *rtv;
709
710                         if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
711                                 if (rtv->route()->is_master()) {
712                                         _display.get_selection()->unselect (i);
713                                 }
714                         }
715                 }
716
717                 _no_redisplay = false;
718                 redisplay ();
719         }
720
721         resume_redisplay ();
722 }
723
724 void
725 EditorRoutes::track_list_reorder (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &, int* /*new_order*/)
726 {
727         _redisplay_does_not_sync_order_keys = true;
728         _session->set_remote_control_ids();
729         redisplay ();
730         _redisplay_does_not_sync_order_keys = false;
731 }
732
733 void
734 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
735                                              int x, int y,
736                                              const SelectionData& data,
737                                              guint info, guint time)
738 {
739         if (data.get_target() == "GTK_TREE_MODEL_ROW") {
740                 _display.on_drag_data_received (context, x, y, data, info, time);
741                 return;
742         }
743
744         context->drag_finish (true, false, time);
745 }
746
747 void
748 EditorRoutes::move_selected_tracks (bool up)
749 {
750         if (_editor->selection->tracks.empty()) {
751                 return;
752         }
753
754         typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
755         std::list<ViewRoute> view_routes;
756         std::vector<int> neworder;
757         TreeModel::Children rows = _model->children();
758         TreeModel::Children::iterator ri;
759
760         for (ri = rows.begin(); ri != rows.end(); ++ri) {
761                 TimeAxisView* tv = (*ri)[_columns.tv];
762                 boost::shared_ptr<Route> route = (*ri)[_columns.route];
763
764                 view_routes.push_back (ViewRoute (tv, route));
765         }
766
767         list<ViewRoute>::iterator trailing;
768         list<ViewRoute>::iterator leading;
769
770         if (up) {
771
772                 trailing = view_routes.begin();
773                 leading = view_routes.begin();
774
775                 ++leading;
776
777                 while (leading != view_routes.end()) {
778                         if (_editor->selection->selected (leading->first)) {
779                                 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
780                                 leading = view_routes.erase (leading);
781                         } else {
782                                 ++leading;
783                                 ++trailing;
784                         }
785                 }
786
787         } else {
788
789                 /* if we could use reverse_iterator in list::insert, this code
790                    would be a beautiful reflection of the code above. but we can't
791                    and so it looks like a bit of a mess.
792                 */
793
794                 trailing = view_routes.end();
795                 leading = view_routes.end();
796
797                 --leading; if (leading == view_routes.begin()) { return; }
798                 --leading;
799                 --trailing;
800
801                 while (1) {
802
803                         if (_editor->selection->selected (leading->first)) {
804                                 list<ViewRoute>::iterator tmp;
805
806                                 /* need to insert *after* trailing, not *before* it,
807                                    which is what insert (iter, val) normally does.
808                                 */
809
810                                 tmp = trailing;
811                                 tmp++;
812
813                                 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
814
815                                 /* can't use iter = cont.erase (iter); form here, because
816                                    we need iter to move backwards.
817                                 */
818
819                                 tmp = leading;
820                                 --tmp;
821
822                                 bool done = false;
823
824                                 if (leading == view_routes.begin()) {
825                                         /* the one we've just inserted somewhere else
826                                            was the first in the list. erase this copy,
827                                            and then break, because we're done.
828                                         */
829                                         done = true;
830                                 }
831
832                                 view_routes.erase (leading);
833
834                                 if (done) {
835                                         break;
836                                 }
837
838                                 leading = tmp;
839
840                         } else {
841                                 if (leading == view_routes.begin()) {
842                                         break;
843                                 }
844                                 --leading;
845                                 --trailing;
846                         }
847                 };
848         }
849
850         for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
851                 neworder.push_back (leading->second->order_key (N_ ("editor")));
852         }
853
854         _model->reorder (neworder);
855
856         _session->sync_order_keys (N_ ("editor"));
857 }
858
859 void
860 EditorRoutes::update_rec_display ()
861 {
862         TreeModel::Children rows = _model->children();
863         TreeModel::Children::iterator i;
864
865         for (i = rows.begin(); i != rows.end(); ++i) {
866                 boost::shared_ptr<Route> route = (*i)[_columns.route];
867
868                 if (boost::dynamic_pointer_cast<Track>(route)) {
869                         (*i)[_columns.rec_enabled] = route->record_enabled ();
870                         (*i)[_columns.name_editable] = !route->record_enabled ();
871                 }
872         }
873 }
874
875 void
876 EditorRoutes::update_mute_display (void* /*src*/)
877 {
878         TreeModel::Children rows = _model->children();
879         TreeModel::Children::iterator i;
880
881         for (i = rows.begin(); i != rows.end(); ++i) {
882                 boost::shared_ptr<Route> route = (*i)[_columns.route];
883                 (*i)[_columns.mute_state] = RouteUI::mute_visual_state (*_session, route) > 0 ? 1 : 0;
884         }
885 }
886
887 void
888 EditorRoutes::update_solo_display (void* /*src*/)
889 {
890         TreeModel::Children rows = _model->children();
891         TreeModel::Children::iterator i;
892
893         for (i = rows.begin(); i != rows.end(); ++i) {
894                 boost::shared_ptr<Route> route = (*i)[_columns.route];
895                 (*i)[_columns.solo_state] = RouteUI::solo_visual_state (route) > 0 ? 1 : 0;
896         }
897 }
898
899 list<TimeAxisView*>
900 EditorRoutes::views () const
901 {
902         list<TimeAxisView*> v;
903         for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
904                 v.push_back ((*i)[_columns.tv]);
905         }
906
907         return v;
908 }
909
910 void
911 EditorRoutes::clear ()
912 {
913         _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
914         _model->clear ();
915         _display.set_model (_model);
916 }
917
918 void
919 EditorRoutes::name_edit (Glib::ustring const & path, Glib::ustring const & new_text)
920 {
921         TreeIter iter = _model->get_iter (path);
922         if (!iter) {
923                 return;
924         }
925
926         boost::shared_ptr<Route> route = (*iter)[_columns.route];
927
928         if (route && route->name() != new_text) {
929                 route->set_name (new_text);
930         }
931 }
932
933 void
934 EditorRoutes::solo_changed_so_update_mute ()
935 {
936         ENSURE_GUI_THREAD (mem_fun (*this, &EditorRoutes::solo_changed_so_update_mute));
937
938         update_mute_display (this);
939 }
940
941 void
942 EditorRoutes::show_tracks_with_regions_at_playhead ()
943 {
944         boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
945
946         set<TimeAxisView*> show;
947         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
948                 TimeAxisView* tav = _editor->axis_view_from_route (i->get ());
949                 if (tav) {
950                         show.insert (tav);
951                 }
952         }
953
954         suspend_redisplay ();
955         
956         TreeModel::Children rows = _model->children ();
957         for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
958                 TimeAxisView* tv = (*i)[_columns.tv];
959                 (*i)[_columns.visible] = (show.find (tv) != show.end());
960         }
961
962         resume_redisplay ();
963         
964 }