Tweaks to prevent flicker in the treeview when changing record / solo isolate state.
[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 ARDOUR;
53 using namespace PBD;
54 using namespace Gtk;
55 using namespace Gtkmm2ext;
56 using namespace Glib;
57 using Gtkmm2ext::Keyboard;
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 (sigc::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         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);
88
89         // Mute enable toggle
90         CellRendererPixbufMulti* mute_col_renderer = manage (new CellRendererPixbufMulti());
91
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));
95
96         TreeViewColumn* mute_state_column = manage (new TreeViewColumn("M", *mute_col_renderer));
97
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);
103
104         // Solo enable toggle
105         CellRendererPixbufMulti* solo_col_renderer = manage (new CellRendererPixbufMulti());
106
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));
110
111         TreeViewColumn* solo_state_column = manage (new TreeViewColumn("S", *solo_col_renderer));
112
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);
118
119         // Solo isolate toggle
120         CellRendererPixbufMulti* solo_iso_renderer = manage (new CellRendererPixbufMulti());
121
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));
125
126         TreeViewColumn* solo_isolate_state_column = manage (new TreeViewColumn("I", *solo_iso_renderer));
127
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);
133
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);
138         
139         _display.append_column (_("Name"), _columns.text);
140         _display.append_column (_("V"), _columns.visible);
141         
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");
149
150         CellRendererText* name_cell = dynamic_cast<CellRendererText*> (_display.get_column_cell_renderer (4));
151
152         assert (name_cell);
153
154         TreeViewColumn* name_column = _display.get_column (4);
155
156         assert (name_column);
157
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);
162
163         name_cell->property_editable() = true;
164         name_cell->signal_edited().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit));
165
166         // Set the visible column cell renderer to radio toggle
167         CellRendererToggle* visible_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (5));
168
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));
172         
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);
178         
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));
181         
182         _display.signal_button_press_event().connect (sigc::mem_fun (*this, &EditorRoutes::button_press), false);
183
184         Route::SyncOrderKeys.connect (*this, ui_bind (&EditorRoutes::sync_order_keys, this, _1), gui_context());
185 }
186
187 void
188 EditorRoutes::set_session (Session* s)
189 {
190         EditorComponent::set_session (s);
191
192         initial_display ();
193
194         if (_session) {
195                 _session->SoloChanged.connect (*this, boost::bind (&EditorRoutes::solo_changed_so_update_mute, this), gui_context());
196         }
197 }
198
199 void
200 EditorRoutes::on_tv_rec_enable_toggled (Glib::ustring const & path_string)
201 {
202         // Get the model row that has been toggled.
203         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
204
205         TimeAxisView *tv = row[_columns.tv];
206         AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
207
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);
212         }
213 }
214
215 void
216 EditorRoutes::on_tv_mute_enable_toggled (Glib::ustring const & path_string)
217 {
218         // Get the model row that has been toggled.
219         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
220
221         TimeAxisView *tv = row[_columns.tv];
222         AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
223
224         if (atv != 0) {
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);
228         }
229 }
230
231 void
232 EditorRoutes::on_tv_solo_enable_toggled (Glib::ustring const & path_string)
233 {
234         // Get the model row that has been toggled.
235         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
236
237         TimeAxisView *tv = row[_columns.tv];
238         AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
239
240         if (atv != 0) {
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);
244         }
245 }
246
247 void
248 EditorRoutes::on_tv_solo_isolate_toggled (Glib::ustring const & path_string)
249 {
250         // Get the model row that has been toggled.
251         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
252
253         TimeAxisView *tv = row[_columns.tv];
254         AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
255
256         if (atv != 0) {
257                 atv->route()->set_solo_isolated (!atv->route()->solo_isolated(), this);
258         }
259 }
260
261 void
262 EditorRoutes::build_menu ()
263 {
264         using namespace Menu_Helpers;
265         using namespace Gtk;
266
267         _menu = new Menu;
268
269         MenuList& items = _menu->items();
270         _menu->set_name ("ArdourContextMenu");
271
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)));
279 }
280
281 void
282 EditorRoutes::show_menu ()
283 {
284         if (_menu == 0) {
285                 build_menu ();
286         }
287
288         _menu->popup (1, gtk_get_current_event_time());
289 }
290
291 void
292 EditorRoutes::redisplay ()
293 {
294         if (_no_redisplay || !_session) {
295                 return;
296         }
297
298         TreeModel::Children rows = _model->children();
299         TreeModel::Children::iterator i;
300         uint32_t position;
301         int n;
302
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];
306
307                 if (tv == 0) {
308                         // just a "title" row
309                         continue;
310                 }
311
312                 if (!_redisplay_does_not_reset_order_keys) {
313                         /* this reorder is caused by user action, so reassign sort order keys
314                            to tracks.
315                         */
316                         route->set_order_key (N_ ("editor"), n);
317                 }
318
319                 bool visible = (*i)[_columns.visible];
320
321                 /* show or hide the TimeAxisView */
322                 if (visible) {
323                         tv->set_marked_for_display (true);
324                         position += tv->show_at (position, n, &_editor->edit_controls_vbox);
325                         tv->clip_to_viewport ();
326                 } else {
327                         tv->set_marked_for_display (false);
328                         tv->hide ();
329                 }
330
331                 n++;
332         }
333
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.
337         */
338         Glib::signal_idle().connect (sigc::mem_fun (*_editor, &Editor::sync_track_view_list_and_routes));
339
340         _editor->full_canvas_height = position + _editor->canvas_timebars_vsize;
341         _editor->vertical_adjustment.set_upper (_editor->full_canvas_height);
342
343         if ((_editor->vertical_adjustment.get_value() + _editor->_canvas_height) > _editor->vertical_adjustment.get_upper()) {
344                 /*
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.
347                 */
348                 _editor->vertical_adjustment.set_value (_editor->full_canvas_height - _editor->_canvas_height);
349         }
350
351         if (!_redisplay_does_not_reset_order_keys && !_redisplay_does_not_sync_order_keys) {
352                 _session->sync_order_keys (N_ ("editor"));
353         }
354 }
355
356 void
357 EditorRoutes::route_deleted (Gtk::TreeModel::Path const &)
358 {
359         if (!_session || _session->deletion_in_progress()) {
360                 return;
361         }
362                 
363         /* this could require an order reset & sync */
364         _session->set_remote_control_ids();
365         _ignore_reorder = true;
366         redisplay ();
367         _ignore_reorder = false;
368 }
369
370 void
371 EditorRoutes::visible_changed (Glib::ustring const & path)
372 {
373         if (_session && _session->deletion_in_progress()) {
374                 return;
375         }
376
377         TreeIter iter;
378
379         if ((iter = _model->get_iter (path))) {
380                 TimeAxisView* tv = (*iter)[_columns.tv];
381                 if (tv) {
382                         bool visible = (*iter)[_columns.visible];
383                         (*iter)[_columns.visible] = !visible;
384                 }
385         }
386
387         _redisplay_does_not_reset_order_keys = true;
388         _session->set_remote_control_ids();
389         redisplay ();
390         _redisplay_does_not_reset_order_keys = false;
391 }
392
393 void
394 EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
395 {
396         TreeModel::Row row;
397
398         _redisplay_does_not_sync_order_keys = true;
399         suspend_redisplay ();
400
401         for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) {
402
403                 row = *(_model->append ());
404
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
414                 _ignore_reorder = true;
415
416                 /* added a new fresh one at the end */
417                 if ((*x)->route()->order_key (N_ ("editor")) == -1) {
418                         (*x)->route()->set_order_key (N_ ("editor"), _model->children().size()-1);
419                 }
420
421                 _ignore_reorder = false;
422
423                 boost::weak_ptr<Route> wr ((*x)->route());
424
425                 (*x)->route()->gui_changed.connect (*this, ui_bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
426                 (*x)->route()->NameChanged.connect (*this, boost::bind (&EditorRoutes::route_name_changed, this, wr), gui_context());
427
428                 if ((*x)->is_track()) {
429                         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
430                         t->diskstream()->RecordEnableChanged.connect (*this, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
431                 }
432
433                 (*x)->route()->mute_changed.connect (*this, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
434                 (*x)->route()->solo_changed.connect (*this, boost::bind (&EditorRoutes::update_solo_display, this), gui_context());
435                 (*x)->route()->solo_isolated_changed.connect (*this, boost::bind (&EditorRoutes::update_solo_isolate_display, this), gui_context());
436         }
437
438         update_rec_display ();
439         update_mute_display ();
440         update_solo_display ();
441         update_solo_isolate_display ();
442         resume_redisplay ();
443         _redisplay_does_not_sync_order_keys = false;
444 }
445
446 void
447 EditorRoutes::handle_gui_changes (string const & what, void*)
448 {
449         ENSURE_GUI_THREAD (*this, &EditorRoutes::handle_gui_changes, what, src)
450
451         if (what == "track_height") {
452                 /* Optional :make tracks change height while it happens, instead
453                    of on first-idle
454                 */
455                 //update_canvas_now ();
456                 redisplay ();
457         }
458
459         if (what == "visible_tracks") {
460                 redisplay ();
461         }
462 }
463
464 void
465 EditorRoutes::route_removed (TimeAxisView *tv)
466 {
467         ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed, tv)
468
469         TreeModel::Children rows = _model->children();
470         TreeModel::Children::iterator ri;
471
472         /* the core model has changed, there is no need to sync
473            view orders.
474         */
475
476         _redisplay_does_not_sync_order_keys = true;
477
478         for (ri = rows.begin(); ri != rows.end(); ++ri) {
479                 if ((*ri)[_columns.tv] == tv) {
480                         _model->erase (ri);
481                         break;
482                 }
483         }
484
485         _redisplay_does_not_sync_order_keys = false;
486 }
487
488 void
489 EditorRoutes::route_name_changed (boost::weak_ptr<Route> r)
490 {
491         ENSURE_GUI_THREAD (*this, &EditorRoutes::route_name_changed, r)
492
493         boost::shared_ptr<Route> route = r.lock ();
494         if (!route) {
495                 return;
496         }
497
498         TreeModel::Children rows = _model->children();
499         TreeModel::Children::iterator i;
500
501         for (i = rows.begin(); i != rows.end(); ++i) {
502                 boost::shared_ptr<Route> t = (*i)[_columns.route];
503                 if (t == route) {
504                         (*i)[_columns.text] = route->name();
505                         break;
506                 }
507         }
508 }
509
510 void
511 EditorRoutes::update_visibility ()
512 {
513         TreeModel::Children rows = _model->children();
514         TreeModel::Children::iterator i;
515
516         suspend_redisplay ();
517
518         for (i = rows.begin(); i != rows.end(); ++i) {
519                 TimeAxisView *tv = (*i)[_columns.tv];
520                 (*i)[_columns.visible] = tv->marked_for_display ();
521                 cerr << "marked " << tv->name() << " for display = " << tv->marked_for_display() << endl;
522         }
523
524         resume_redisplay ();
525 }
526
527 void
528 EditorRoutes::hide_track_in_display (TimeAxisView& tv)
529 {
530         TreeModel::Children rows = _model->children();
531         TreeModel::Children::iterator i;
532
533         for (i = rows.begin(); i != rows.end(); ++i) {
534                 if ((*i)[_columns.tv] == &tv) {
535                         (*i)[_columns.visible] = false;
536                         break;
537                 }
538         }
539 }
540
541 void
542 EditorRoutes::show_track_in_display (TimeAxisView& tv)
543 {
544         TreeModel::Children rows = _model->children();
545         TreeModel::Children::iterator i;
546
547         for (i = rows.begin(); i != rows.end(); ++i) {
548                 if ((*i)[_columns.tv] == &tv) {
549                         (*i)[_columns.visible] = true;
550                         break;
551                 }
552         }
553 }
554
555 void
556 EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
557 {
558         redisplay ();
559 }
560
561 /** If src != "editor", take editor order keys from each route and use them to rearrange the
562  *  route list so that the visual arrangement of routes matches the order keys from the routes.
563  */
564 void
565 EditorRoutes::sync_order_keys (string const & src)
566 {
567         vector<int> neworder;
568         TreeModel::Children rows = _model->children();
569         TreeModel::Children::iterator ri;
570
571         if (src == N_ ("editor") || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
572                 return;
573         }
574
575         for (ri = rows.begin(); ri != rows.end(); ++ri) {
576                 neworder.push_back (0);
577         }
578
579         bool changed = false;
580         int order;
581
582         for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
583                 boost::shared_ptr<Route> route = (*ri)[_columns.route];
584
585                 int old_key = order;
586                 int new_key = route->order_key (N_ ("editor"));
587
588                 neworder[new_key] = old_key;
589
590                 if (new_key != old_key) {
591                         changed = true;
592                 }
593         }
594
595         if (changed) {
596                 _redisplay_does_not_reset_order_keys = true;
597                 _model->reorder (neworder);
598                 _redisplay_does_not_reset_order_keys = false;
599         }
600 }
601
602
603 void
604 EditorRoutes::hide_all_tracks (bool /*with_select*/)
605 {
606         TreeModel::Children rows = _model->children();
607         TreeModel::Children::iterator i;
608
609         suspend_redisplay ();
610
611         for (i = rows.begin(); i != rows.end(); ++i) {
612
613                 TreeModel::Row row = (*i);
614                 TimeAxisView *tv = row[_columns.tv];
615
616                 if (tv == 0) {
617                         continue;
618                 }
619
620                 row[_columns.visible] = false;
621         }
622
623         resume_redisplay ();
624
625         /* XXX this seems like a hack and half, but its not clear where to put this
626            otherwise.
627         */
628
629         //reset_scrolling_region ();
630 }
631
632 void
633 EditorRoutes::set_all_tracks_visibility (bool yn)
634 {
635         TreeModel::Children rows = _model->children();
636         TreeModel::Children::iterator i;
637
638         suspend_redisplay ();
639
640         for (i = rows.begin(); i != rows.end(); ++i) {
641
642                 TreeModel::Row row = (*i);
643                 TimeAxisView* tv = row[_columns.tv];
644
645                 if (tv == 0) {
646                         continue;
647                 }
648
649                 (*i)[_columns.visible] = yn;
650         }
651
652         resume_redisplay ();
653 }
654
655 void
656 EditorRoutes::set_all_audio_visibility (int tracks, bool yn)
657 {
658         TreeModel::Children rows = _model->children();
659         TreeModel::Children::iterator i;
660
661         suspend_redisplay ();
662
663         for (i = rows.begin(); i != rows.end(); ++i) {
664                 TreeModel::Row row = (*i);
665                 TimeAxisView* tv = row[_columns.tv];
666                 AudioTimeAxisView* atv;
667
668                 if (tv == 0) {
669                         continue;
670                 }
671
672                 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
673                         switch (tracks) {
674                         case 0:
675                                 (*i)[_columns.visible] = yn;
676                                 break;
677
678                         case 1:
679                                 if (atv->is_audio_track()) {
680                                         (*i)[_columns.visible] = yn;
681                                 }
682                                 break;
683
684                         case 2:
685                                 if (!atv->is_audio_track()) {
686                                         (*i)[_columns.visible] = yn;
687                                 }
688                                 break;
689                         }
690                 }
691         }
692
693         resume_redisplay ();
694 }
695
696 void
697 EditorRoutes::hide_all_routes ()
698 {
699         set_all_tracks_visibility (false);
700 }
701
702 void
703 EditorRoutes::show_all_routes ()
704 {
705         set_all_tracks_visibility (true);
706 }
707
708 void
709 EditorRoutes::show_all_audiobus ()
710 {
711         set_all_audio_visibility (2, true);
712 }
713 void
714 EditorRoutes::hide_all_audiobus ()
715 {
716         set_all_audio_visibility (2, false);
717 }
718
719 void
720 EditorRoutes::show_all_audiotracks()
721 {
722         set_all_audio_visibility (1, true);
723 }
724 void
725 EditorRoutes::hide_all_audiotracks ()
726 {
727         set_all_audio_visibility (1, false);
728 }
729
730 bool
731 EditorRoutes::button_press (GdkEventButton* ev)
732 {
733         if (Keyboard::is_context_menu_event (ev)) {
734                 show_menu ();
735                 return true;
736         }
737         
738         //Scroll editor canvas to selected track
739         if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
740                 
741                 TreeModel::Path path;
742                 TreeViewColumn *tvc;
743                 int cell_x;
744                 int cell_y;
745                 
746                 _display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y);
747
748                 // Get the model row.
749                 Gtk::TreeModel::Row row = *_model->get_iter (path);
750                 
751                 TimeAxisView *tv = row[_columns.tv];
752                 
753                 int y_pos = tv->y_position();
754                 
755                 //Clamp the y pos so that we do not extend beyond the canvas full height.
756                 if (_editor->full_canvas_height - y_pos < _editor->_canvas_height){
757                     y_pos = _editor->full_canvas_height - _editor->_canvas_height;
758                 }
759                 
760                 //Only scroll to if the track is visible
761                 if(y_pos != -1){
762                     _editor->reset_y_origin (y_pos);
763                 }
764         }
765         
766         return false;
767 }
768
769 bool
770 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const &, bool)
771 {
772         return true;
773 }
774
775 struct EditorOrderRouteSorter {
776     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
777             /* use of ">" forces the correct sort order */
778             return a->order_key (N_ ("editor")) < b->order_key (N_ ("editor"));
779     }
780 };
781
782 void
783 EditorRoutes::initial_display ()
784 {
785         suspend_redisplay ();
786         _model->clear ();
787
788         if (!_session) {
789                 resume_redisplay ();
790                 return;
791         }
792
793         boost::shared_ptr<RouteList> routes = _session->get_routes();
794         RouteList r (*routes);
795         EditorOrderRouteSorter sorter;
796
797         r.sort (sorter);
798         _editor->handle_new_route (r);
799
800         /* don't show master bus in a new session */
801
802         if (ARDOUR_UI::instance()->session_is_new ()) {
803
804                 TreeModel::Children rows = _model->children();
805                 TreeModel::Children::iterator i;
806
807                 _no_redisplay = true;
808
809                 for (i = rows.begin(); i != rows.end(); ++i) {
810
811                         TimeAxisView *tv =  (*i)[_columns.tv];
812                         RouteTimeAxisView *rtv;
813
814                         if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
815                                 if (rtv->route()->is_master()) {
816                                         _display.get_selection()->unselect (i);
817                                 }
818                         }
819                 }
820
821                 _no_redisplay = false;
822                 redisplay ();
823         }
824
825         resume_redisplay ();
826 }
827
828 void
829 EditorRoutes::track_list_reorder (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &, int* /*new_order*/)
830 {
831         _redisplay_does_not_sync_order_keys = true;
832         _session->set_remote_control_ids();
833         redisplay ();
834         _redisplay_does_not_sync_order_keys = false;
835 }
836
837 void
838 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
839                                              int x, int y,
840                                              const SelectionData& data,
841                                              guint info, guint time)
842 {
843         if (data.get_target() == "GTK_TREE_MODEL_ROW") {
844                 _display.on_drag_data_received (context, x, y, data, info, time);
845                 return;
846         }
847
848         context->drag_finish (true, false, time);
849 }
850
851 void
852 EditorRoutes::move_selected_tracks (bool up)
853 {
854         if (_editor->selection->tracks.empty()) {
855                 return;
856         }
857
858         typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
859         std::list<ViewRoute> view_routes;
860         std::vector<int> neworder;
861         TreeModel::Children rows = _model->children();
862         TreeModel::Children::iterator ri;
863
864         for (ri = rows.begin(); ri != rows.end(); ++ri) {
865                 TimeAxisView* tv = (*ri)[_columns.tv];
866                 boost::shared_ptr<Route> route = (*ri)[_columns.route];
867
868                 view_routes.push_back (ViewRoute (tv, route));
869         }
870
871         list<ViewRoute>::iterator trailing;
872         list<ViewRoute>::iterator leading;
873
874         if (up) {
875
876                 trailing = view_routes.begin();
877                 leading = view_routes.begin();
878
879                 ++leading;
880
881                 while (leading != view_routes.end()) {
882                         if (_editor->selection->selected (leading->first)) {
883                                 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
884                                 leading = view_routes.erase (leading);
885                         } else {
886                                 ++leading;
887                                 ++trailing;
888                         }
889                 }
890
891         } else {
892
893                 /* if we could use reverse_iterator in list::insert, this code
894                    would be a beautiful reflection of the code above. but we can't
895                    and so it looks like a bit of a mess.
896                 */
897
898                 trailing = view_routes.end();
899                 leading = view_routes.end();
900
901                 --leading; if (leading == view_routes.begin()) { return; }
902                 --leading;
903                 --trailing;
904
905                 while (1) {
906
907                         if (_editor->selection->selected (leading->first)) {
908                                 list<ViewRoute>::iterator tmp;
909
910                                 /* need to insert *after* trailing, not *before* it,
911                                    which is what insert (iter, val) normally does.
912                                 */
913
914                                 tmp = trailing;
915                                 tmp++;
916
917                                 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
918
919                                 /* can't use iter = cont.erase (iter); form here, because
920                                    we need iter to move backwards.
921                                 */
922
923                                 tmp = leading;
924                                 --tmp;
925
926                                 bool done = false;
927
928                                 if (leading == view_routes.begin()) {
929                                         /* the one we've just inserted somewhere else
930                                            was the first in the list. erase this copy,
931                                            and then break, because we're done.
932                                         */
933                                         done = true;
934                                 }
935
936                                 view_routes.erase (leading);
937
938                                 if (done) {
939                                         break;
940                                 }
941
942                                 leading = tmp;
943
944                         } else {
945                                 if (leading == view_routes.begin()) {
946                                         break;
947                                 }
948                                 --leading;
949                                 --trailing;
950                         }
951                 };
952         }
953
954         for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
955                 neworder.push_back (leading->second->order_key (N_ ("editor")));
956         }
957
958         _model->reorder (neworder);
959
960        _session->sync_order_keys (N_ ("editor"));
961 }
962
963 void
964 EditorRoutes::update_rec_display ()
965 {
966         TreeModel::Children rows = _model->children();
967         TreeModel::Children::iterator i;
968
969         for (i = rows.begin(); i != rows.end(); ++i) {
970                 boost::shared_ptr<Route> route = (*i)[_columns.route];
971
972                 if (boost::dynamic_pointer_cast<Track>(route)) {
973                         (*i)[_columns.rec_enabled] = route->record_enabled ();
974                         (*i)[_columns.name_editable] = !route->record_enabled ();
975                 }
976         }
977 }
978
979 void
980 EditorRoutes::update_mute_display ()
981 {
982         TreeModel::Children rows = _model->children();
983         TreeModel::Children::iterator i;
984
985         for (i = rows.begin(); i != rows.end(); ++i) {
986                 boost::shared_ptr<Route> route = (*i)[_columns.route];
987                 (*i)[_columns.mute_state] = RouteUI::mute_visual_state (_session, route) > 0 ? 1 : 0;
988         }
989 }
990
991 void
992 EditorRoutes::update_solo_display ()
993 {
994         TreeModel::Children rows = _model->children();
995         TreeModel::Children::iterator i;
996
997         for (i = rows.begin(); i != rows.end(); ++i) {
998                 boost::shared_ptr<Route> route = (*i)[_columns.route];
999                 (*i)[_columns.solo_state] = RouteUI::solo_visual_state (route) > 0 ? 1 : 0;
1000         }
1001 }
1002
1003 void
1004 EditorRoutes::update_solo_isolate_display ()
1005 {
1006         TreeModel::Children rows = _model->children();
1007         TreeModel::Children::iterator i;
1008
1009         for (i = rows.begin(); i != rows.end(); ++i) {
1010                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1011                 (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_visual_state (route) > 0 ? 1 : 0;
1012         }
1013 }
1014
1015 list<TimeAxisView*>
1016 EditorRoutes::views () const
1017 {
1018         list<TimeAxisView*> v;
1019         for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
1020                 v.push_back ((*i)[_columns.tv]);
1021         }
1022
1023         return v;
1024 }
1025
1026 void
1027 EditorRoutes::clear ()
1028 {
1029         _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1030         _model->clear ();
1031         _display.set_model (_model);
1032 }
1033
1034 void
1035 EditorRoutes::name_edit (Glib::ustring const & path, Glib::ustring const & new_text)
1036 {
1037         TreeIter iter = _model->get_iter (path);
1038         if (!iter) {
1039                 return;
1040         }
1041
1042         boost::shared_ptr<Route> route = (*iter)[_columns.route];
1043
1044         if (route && route->name() != new_text) {
1045                 route->set_name (new_text);
1046         }
1047 }
1048
1049 void
1050 EditorRoutes::solo_changed_so_update_mute ()
1051 {
1052         ENSURE_GUI_THREAD (*this, &EditorRoutes::solo_changed_so_update_mute)
1053         update_mute_display ();
1054 }
1055
1056 void
1057 EditorRoutes::show_tracks_with_regions_at_playhead ()
1058 {
1059         boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
1060
1061         set<TimeAxisView*> show;
1062         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
1063                 TimeAxisView* tav = _editor->axis_view_from_route (*i);
1064                 if (tav) {
1065                         show.insert (tav);
1066                 }
1067         }
1068
1069         suspend_redisplay ();
1070         
1071         TreeModel::Children rows = _model->children ();
1072         for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
1073                 TimeAxisView* tv = (*i)[_columns.tv];
1074                 (*i)[_columns.visible] = (show.find (tv) != show.end());
1075         }
1076
1077         resume_redisplay ();
1078 }