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