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