Center port matrix if IO selector window is too large.
[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                 row[_columns.name_editable] = true;
414
415                 _ignore_reorder = true;
416
417                 /* added a new fresh one at the end */
418                 if ((*x)->route()->order_key (N_ ("editor")) == -1) {
419                         (*x)->route()->set_order_key (N_ ("editor"), _model->children().size()-1);
420                 }
421
422                 _ignore_reorder = false;
423
424                 boost::weak_ptr<Route> wr ((*x)->route());
425
426                 (*x)->route()->gui_changed.connect (*this, ui_bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
427                 (*x)->route()->NameChanged.connect (*this, boost::bind (&EditorRoutes::route_name_changed, this, wr), gui_context());
428
429                 if ((*x)->is_track()) {
430                         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
431                         t->diskstream()->RecordEnableChanged.connect (*this, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
432                 }
433
434                 (*x)->route()->mute_changed.connect (*this, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
435                 (*x)->route()->solo_changed.connect (*this, boost::bind (&EditorRoutes::update_solo_display, this), gui_context());
436                 (*x)->route()->solo_isolated_changed.connect (*this, boost::bind (&EditorRoutes::update_solo_isolate_display, this), gui_context());
437         }
438
439         update_rec_display ();
440         update_mute_display ();
441         update_solo_display ();
442         update_solo_isolate_display ();
443         resume_redisplay ();
444         _redisplay_does_not_sync_order_keys = false;
445 }
446
447 void
448 EditorRoutes::handle_gui_changes (string const & what, void*)
449 {
450         ENSURE_GUI_THREAD (*this, &EditorRoutes::handle_gui_changes, what, src)
451
452         if (what == "track_height") {
453                 /* Optional :make tracks change height while it happens, instead
454                    of on first-idle
455                 */
456                 //update_canvas_now ();
457                 redisplay ();
458         }
459
460         if (what == "visible_tracks") {
461                 redisplay ();
462         }
463 }
464
465 void
466 EditorRoutes::route_removed (TimeAxisView *tv)
467 {
468         ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed, tv)
469
470         TreeModel::Children rows = _model->children();
471         TreeModel::Children::iterator ri;
472
473         /* the core model has changed, there is no need to sync
474            view orders.
475         */
476
477         _redisplay_does_not_sync_order_keys = true;
478
479         for (ri = rows.begin(); ri != rows.end(); ++ri) {
480                 if ((*ri)[_columns.tv] == tv) {
481                         _model->erase (ri);
482                         break;
483                 }
484         }
485
486         _redisplay_does_not_sync_order_keys = false;
487 }
488
489 void
490 EditorRoutes::route_name_changed (boost::weak_ptr<Route> r)
491 {
492         ENSURE_GUI_THREAD (*this, &EditorRoutes::route_name_changed, r)
493
494         boost::shared_ptr<Route> route = r.lock ();
495         if (!route) {
496                 return;
497         }
498
499         TreeModel::Children rows = _model->children();
500         TreeModel::Children::iterator i;
501
502         for (i = rows.begin(); i != rows.end(); ++i) {
503                 boost::shared_ptr<Route> t = (*i)[_columns.route];
504                 if (t == route) {
505                         (*i)[_columns.text] = route->name();
506                         break;
507                 }
508         }
509 }
510
511 void
512 EditorRoutes::update_visibility ()
513 {
514         TreeModel::Children rows = _model->children();
515         TreeModel::Children::iterator i;
516
517         suspend_redisplay ();
518
519         for (i = rows.begin(); i != rows.end(); ++i) {
520                 TimeAxisView *tv = (*i)[_columns.tv];
521                 (*i)[_columns.visible] = tv->marked_for_display ();
522                 cerr << "marked " << tv->name() << " for display = " << tv->marked_for_display() << endl;
523         }
524
525         resume_redisplay ();
526 }
527
528 void
529 EditorRoutes::hide_track_in_display (TimeAxisView& tv)
530 {
531         TreeModel::Children rows = _model->children();
532         TreeModel::Children::iterator i;
533
534         for (i = rows.begin(); i != rows.end(); ++i) {
535                 if ((*i)[_columns.tv] == &tv) {
536                         (*i)[_columns.visible] = false;
537                         break;
538                 }
539         }
540 }
541
542 void
543 EditorRoutes::show_track_in_display (TimeAxisView& tv)
544 {
545         TreeModel::Children rows = _model->children();
546         TreeModel::Children::iterator i;
547
548         for (i = rows.begin(); i != rows.end(); ++i) {
549                 if ((*i)[_columns.tv] == &tv) {
550                         (*i)[_columns.visible] = true;
551                         break;
552                 }
553         }
554 }
555
556 void
557 EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
558 {
559         redisplay ();
560 }
561
562 /** If src != "editor", take editor order keys from each route and use them to rearrange the
563  *  route list so that the visual arrangement of routes matches the order keys from the routes.
564  */
565 void
566 EditorRoutes::sync_order_keys (string const & src)
567 {
568         vector<int> neworder;
569         TreeModel::Children rows = _model->children();
570         TreeModel::Children::iterator ri;
571
572         if (src == N_ ("editor") || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
573                 return;
574         }
575
576         for (ri = rows.begin(); ri != rows.end(); ++ri) {
577                 neworder.push_back (0);
578         }
579
580         bool changed = false;
581         int order;
582
583         for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
584                 boost::shared_ptr<Route> route = (*ri)[_columns.route];
585
586                 int old_key = order;
587                 int new_key = route->order_key (N_ ("editor"));
588
589                 neworder[new_key] = old_key;
590
591                 if (new_key != old_key) {
592                         changed = true;
593                 }
594         }
595
596         if (changed) {
597                 _redisplay_does_not_reset_order_keys = true;
598                 _model->reorder (neworder);
599                 _redisplay_does_not_reset_order_keys = false;
600         }
601 }
602
603
604 void
605 EditorRoutes::hide_all_tracks (bool /*with_select*/)
606 {
607         TreeModel::Children rows = _model->children();
608         TreeModel::Children::iterator i;
609
610         suspend_redisplay ();
611
612         for (i = rows.begin(); i != rows.end(); ++i) {
613
614                 TreeModel::Row row = (*i);
615                 TimeAxisView *tv = row[_columns.tv];
616
617                 if (tv == 0) {
618                         continue;
619                 }
620
621                 row[_columns.visible] = false;
622         }
623
624         resume_redisplay ();
625
626         /* XXX this seems like a hack and half, but its not clear where to put this
627            otherwise.
628         */
629
630         //reset_scrolling_region ();
631 }
632
633 void
634 EditorRoutes::set_all_tracks_visibility (bool yn)
635 {
636         TreeModel::Children rows = _model->children();
637         TreeModel::Children::iterator i;
638
639         suspend_redisplay ();
640
641         for (i = rows.begin(); i != rows.end(); ++i) {
642
643                 TreeModel::Row row = (*i);
644                 TimeAxisView* tv = row[_columns.tv];
645
646                 if (tv == 0) {
647                         continue;
648                 }
649
650                 (*i)[_columns.visible] = yn;
651         }
652
653         resume_redisplay ();
654 }
655
656 void
657 EditorRoutes::set_all_audio_visibility (int tracks, bool yn)
658 {
659         TreeModel::Children rows = _model->children();
660         TreeModel::Children::iterator i;
661
662         suspend_redisplay ();
663
664         for (i = rows.begin(); i != rows.end(); ++i) {
665                 TreeModel::Row row = (*i);
666                 TimeAxisView* tv = row[_columns.tv];
667                 AudioTimeAxisView* atv;
668
669                 if (tv == 0) {
670                         continue;
671                 }
672
673                 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
674                         switch (tracks) {
675                         case 0:
676                                 (*i)[_columns.visible] = yn;
677                                 break;
678
679                         case 1:
680                                 if (atv->is_audio_track()) {
681                                         (*i)[_columns.visible] = yn;
682                                 }
683                                 break;
684
685                         case 2:
686                                 if (!atv->is_audio_track()) {
687                                         (*i)[_columns.visible] = yn;
688                                 }
689                                 break;
690                         }
691                 }
692         }
693
694         resume_redisplay ();
695 }
696
697 void
698 EditorRoutes::hide_all_routes ()
699 {
700         set_all_tracks_visibility (false);
701 }
702
703 void
704 EditorRoutes::show_all_routes ()
705 {
706         set_all_tracks_visibility (true);
707 }
708
709 void
710 EditorRoutes::show_all_audiobus ()
711 {
712         set_all_audio_visibility (2, true);
713 }
714 void
715 EditorRoutes::hide_all_audiobus ()
716 {
717         set_all_audio_visibility (2, false);
718 }
719
720 void
721 EditorRoutes::show_all_audiotracks()
722 {
723         set_all_audio_visibility (1, true);
724 }
725 void
726 EditorRoutes::hide_all_audiotracks ()
727 {
728         set_all_audio_visibility (1, false);
729 }
730
731 bool
732 EditorRoutes::button_press (GdkEventButton* ev)
733 {
734         if (Keyboard::is_context_menu_event (ev)) {
735                 show_menu ();
736                 return true;
737         }
738         
739         //Scroll editor canvas to selected track
740         if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
741                 
742                 TreeModel::Path path;
743                 TreeViewColumn *tvc;
744                 int cell_x;
745                 int cell_y;
746                 
747                 _display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y);
748
749                 // Get the model row.
750                 Gtk::TreeModel::Row row = *_model->get_iter (path);
751                 
752                 TimeAxisView *tv = row[_columns.tv];
753                 
754                 int y_pos = tv->y_position();
755                 
756                 //Clamp the y pos so that we do not extend beyond the canvas full height.
757                 if (_editor->full_canvas_height - y_pos < _editor->_canvas_height){
758                     y_pos = _editor->full_canvas_height - _editor->_canvas_height;
759                 }
760                 
761                 //Only scroll to if the track is visible
762                 if(y_pos != -1){
763                     _editor->reset_y_origin (y_pos);
764                 }
765         }
766         
767         return false;
768 }
769
770 bool
771 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const &, bool)
772 {
773         return true;
774 }
775
776 struct EditorOrderRouteSorter {
777     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
778             /* use of ">" forces the correct sort order */
779             return a->order_key (N_ ("editor")) < b->order_key (N_ ("editor"));
780     }
781 };
782
783 void
784 EditorRoutes::initial_display ()
785 {
786         suspend_redisplay ();
787         _model->clear ();
788
789         if (!_session) {
790                 resume_redisplay ();
791                 return;
792         }
793
794         boost::shared_ptr<RouteList> routes = _session->get_routes();
795         RouteList r (*routes);
796         EditorOrderRouteSorter sorter;
797
798         r.sort (sorter);
799         _editor->handle_new_route (r);
800
801         /* don't show master bus in a new session */
802
803         if (ARDOUR_UI::instance()->session_is_new ()) {
804
805                 TreeModel::Children rows = _model->children();
806                 TreeModel::Children::iterator i;
807
808                 _no_redisplay = true;
809
810                 for (i = rows.begin(); i != rows.end(); ++i) {
811
812                         TimeAxisView *tv =  (*i)[_columns.tv];
813                         RouteTimeAxisView *rtv;
814
815                         if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
816                                 if (rtv->route()->is_master()) {
817                                         _display.get_selection()->unselect (i);
818                                 }
819                         }
820                 }
821
822                 _no_redisplay = false;
823                 redisplay ();
824         }
825
826         resume_redisplay ();
827 }
828
829 void
830 EditorRoutes::track_list_reorder (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &, int* /*new_order*/)
831 {
832         _redisplay_does_not_sync_order_keys = true;
833         _session->set_remote_control_ids();
834         redisplay ();
835         _redisplay_does_not_sync_order_keys = false;
836 }
837
838 void
839 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
840                                              int x, int y,
841                                              const SelectionData& data,
842                                              guint info, guint time)
843 {
844         if (data.get_target() == "GTK_TREE_MODEL_ROW") {
845                 _display.on_drag_data_received (context, x, y, data, info, time);
846                 return;
847         }
848
849         context->drag_finish (true, false, time);
850 }
851
852 void
853 EditorRoutes::move_selected_tracks (bool up)
854 {
855         if (_editor->selection->tracks.empty()) {
856                 return;
857         }
858
859         typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
860         std::list<ViewRoute> view_routes;
861         std::vector<int> neworder;
862         TreeModel::Children rows = _model->children();
863         TreeModel::Children::iterator ri;
864
865         for (ri = rows.begin(); ri != rows.end(); ++ri) {
866                 TimeAxisView* tv = (*ri)[_columns.tv];
867                 boost::shared_ptr<Route> route = (*ri)[_columns.route];
868
869                 view_routes.push_back (ViewRoute (tv, route));
870         }
871
872         list<ViewRoute>::iterator trailing;
873         list<ViewRoute>::iterator leading;
874
875         if (up) {
876
877                 trailing = view_routes.begin();
878                 leading = view_routes.begin();
879
880                 ++leading;
881
882                 while (leading != view_routes.end()) {
883                         if (_editor->selection->selected (leading->first)) {
884                                 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
885                                 leading = view_routes.erase (leading);
886                         } else {
887                                 ++leading;
888                                 ++trailing;
889                         }
890                 }
891
892         } else {
893
894                 /* if we could use reverse_iterator in list::insert, this code
895                    would be a beautiful reflection of the code above. but we can't
896                    and so it looks like a bit of a mess.
897                 */
898
899                 trailing = view_routes.end();
900                 leading = view_routes.end();
901
902                 --leading; if (leading == view_routes.begin()) { return; }
903                 --leading;
904                 --trailing;
905
906                 while (1) {
907
908                         if (_editor->selection->selected (leading->first)) {
909                                 list<ViewRoute>::iterator tmp;
910
911                                 /* need to insert *after* trailing, not *before* it,
912                                    which is what insert (iter, val) normally does.
913                                 */
914
915                                 tmp = trailing;
916                                 tmp++;
917
918                                 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
919
920                                 /* can't use iter = cont.erase (iter); form here, because
921                                    we need iter to move backwards.
922                                 */
923
924                                 tmp = leading;
925                                 --tmp;
926
927                                 bool done = false;
928
929                                 if (leading == view_routes.begin()) {
930                                         /* the one we've just inserted somewhere else
931                                            was the first in the list. erase this copy,
932                                            and then break, because we're done.
933                                         */
934                                         done = true;
935                                 }
936
937                                 view_routes.erase (leading);
938
939                                 if (done) {
940                                         break;
941                                 }
942
943                                 leading = tmp;
944
945                         } else {
946                                 if (leading == view_routes.begin()) {
947                                         break;
948                                 }
949                                 --leading;
950                                 --trailing;
951                         }
952                 };
953         }
954
955         for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
956                 neworder.push_back (leading->second->order_key (N_ ("editor")));
957         }
958
959         _model->reorder (neworder);
960
961        _session->sync_order_keys (N_ ("editor"));
962 }
963
964 void
965 EditorRoutes::update_rec_display ()
966 {
967         TreeModel::Children rows = _model->children();
968         TreeModel::Children::iterator i;
969
970         for (i = rows.begin(); i != rows.end(); ++i) {
971                 boost::shared_ptr<Route> route = (*i)[_columns.route];
972
973                 if (boost::dynamic_pointer_cast<Track>(route)) {
974                         (*i)[_columns.rec_enabled] = route->record_enabled ();
975                         (*i)[_columns.name_editable] = !route->record_enabled ();
976                 }
977         }
978 }
979
980 void
981 EditorRoutes::update_mute_display ()
982 {
983         TreeModel::Children rows = _model->children();
984         TreeModel::Children::iterator i;
985
986         for (i = rows.begin(); i != rows.end(); ++i) {
987                 boost::shared_ptr<Route> route = (*i)[_columns.route];
988                 (*i)[_columns.mute_state] = RouteUI::mute_visual_state (_session, route) > 0 ? 1 : 0;
989         }
990 }
991
992 void
993 EditorRoutes::update_solo_display ()
994 {
995         TreeModel::Children rows = _model->children();
996         TreeModel::Children::iterator i;
997
998         for (i = rows.begin(); i != rows.end(); ++i) {
999                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1000                 (*i)[_columns.solo_state] = RouteUI::solo_visual_state (route) > 0 ? 1 : 0;
1001         }
1002 }
1003
1004 void
1005 EditorRoutes::update_solo_isolate_display ()
1006 {
1007         TreeModel::Children rows = _model->children();
1008         TreeModel::Children::iterator i;
1009
1010         for (i = rows.begin(); i != rows.end(); ++i) {
1011                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1012                 (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_visual_state (route) > 0 ? 1 : 0;
1013         }
1014 }
1015
1016 list<TimeAxisView*>
1017 EditorRoutes::views () const
1018 {
1019         list<TimeAxisView*> v;
1020         for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
1021                 v.push_back ((*i)[_columns.tv]);
1022         }
1023
1024         return v;
1025 }
1026
1027 void
1028 EditorRoutes::clear ()
1029 {
1030         _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1031         _model->clear ();
1032         _display.set_model (_model);
1033 }
1034
1035 void
1036 EditorRoutes::name_edit (Glib::ustring const & path, Glib::ustring const & new_text)
1037 {
1038         TreeIter iter = _model->get_iter (path);
1039         if (!iter) {
1040                 return;
1041         }
1042
1043         boost::shared_ptr<Route> route = (*iter)[_columns.route];
1044
1045         if (route && route->name() != new_text) {
1046                 route->set_name (new_text);
1047         }
1048 }
1049
1050 void
1051 EditorRoutes::solo_changed_so_update_mute ()
1052 {
1053         ENSURE_GUI_THREAD (*this, &EditorRoutes::solo_changed_so_update_mute)
1054         update_mute_display ();
1055 }
1056
1057 void
1058 EditorRoutes::show_tracks_with_regions_at_playhead ()
1059 {
1060         boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
1061
1062         set<TimeAxisView*> show;
1063         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
1064                 TimeAxisView* tav = _editor->axis_view_from_route (*i);
1065                 if (tav) {
1066                         show.insert (tav);
1067                 }
1068         }
1069
1070         suspend_redisplay ();
1071         
1072         TreeModel::Children rows = _model->children ();
1073         for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
1074                 TimeAxisView* tv = (*i)[_columns.tv];
1075                 (*i)[_columns.visible] = (show.find (tv) != show.end());
1076         }
1077
1078         resume_redisplay ();
1079 }