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