update german translation
[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 <cstdlib>
21 #include <cassert>
22 #include <cmath>
23 #include <list>
24 #include <vector>
25 #include <algorithm>
26
27 #include "pbd/unknown_type.h"
28 #include "pbd/unwind.h"
29
30 #include "ardour/debug.h"
31 #include "ardour/audio_track.h"
32 #include "ardour/midi_track.h"
33 #include "ardour/route.h"
34 #include "ardour/selection.h"
35 #include "ardour/session.h"
36 #include "ardour/solo_isolate_control.h"
37 #include "ardour/utils.h"
38 #include "ardour/vca.h"
39 #include "ardour/vca_manager.h"
40
41 #include "gtkmm2ext/cell_renderer_pixbuf_multi.h"
42 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
43 #include "gtkmm2ext/treeutils.h"
44
45 #include "actions.h"
46 #include "ardour_ui.h"
47 #include "audio_time_axis.h"
48 #include "editor.h"
49 #include "editor_group_tabs.h"
50 #include "editor_routes.h"
51 #include "gui_thread.h"
52 #include "keyboard.h"
53 #include "midi_time_axis.h"
54 #include "mixer_strip.h"
55 #include "plugin_setup_dialog.h"
56 #include "route_sorter.h"
57 #include "tooltips.h"
58 #include "vca_time_axis.h"
59 #include "utils.h"
60
61 #include "pbd/i18n.h"
62
63 using namespace std;
64 using namespace ARDOUR;
65 using namespace ARDOUR_UI_UTILS;
66 using namespace PBD;
67 using namespace Gtk;
68 using namespace Gtkmm2ext;
69 using namespace Glib;
70 using Gtkmm2ext::Keyboard;
71
72 struct ColumnInfo {
73         int         index;
74         const char* label;
75         const char* tooltip;
76 };
77
78 EditorRoutes::EditorRoutes (Editor* e)
79         : EditorComponent (e)
80         , _ignore_reorder (false)
81         , _ignore_selection_change (false)
82         , _no_redisplay (false)
83         , _adding_routes (false)
84         , _route_deletion_in_progress (false)
85         , _redisplay_on_resume (false)
86         , _redisplay_active (0)
87         , _queue_tv_update (0)
88         , _menu (0)
89         , old_focus (0)
90         , selection_countdown (0)
91         , name_editable (0)
92 {
93         static const int column_width = 22;
94
95         _scroller.add (_display);
96         _scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
97
98         _model = ListStore::create (_columns);
99         _display.set_model (_model);
100
101         // Record enable toggle
102         CellRendererPixbufMulti* rec_col_renderer = manage (new CellRendererPixbufMulti());
103
104         rec_col_renderer->set_pixbuf (0, ::get_icon("record-normal-disabled"));
105         rec_col_renderer->set_pixbuf (1, ::get_icon("record-normal-in-progress"));
106         rec_col_renderer->set_pixbuf (2, ::get_icon("record-normal-enabled"));
107         rec_col_renderer->set_pixbuf (3, ::get_icon("record-step"));
108         rec_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_rec_enable_changed));
109
110         TreeViewColumn* rec_state_column = manage (new TreeViewColumn("R", *rec_col_renderer));
111
112         rec_state_column->add_attribute(rec_col_renderer->property_state(), _columns.rec_state);
113         rec_state_column->add_attribute(rec_col_renderer->property_visible(), _columns.is_track);
114
115         rec_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
116         rec_state_column->set_alignment(ALIGN_CENTER);
117         rec_state_column->set_expand(false);
118         rec_state_column->set_fixed_width(column_width);
119
120
121         // Record safe toggle
122         CellRendererPixbufMulti* rec_safe_renderer = manage (new CellRendererPixbufMulti ());
123
124         rec_safe_renderer->set_pixbuf (0, ::get_icon("rec-safe-disabled"));
125         rec_safe_renderer->set_pixbuf (1, ::get_icon("rec-safe-enabled"));
126         rec_safe_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_rec_safe_toggled));
127
128         TreeViewColumn* rec_safe_column = manage (new TreeViewColumn(_("RS"), *rec_safe_renderer));
129         rec_safe_column->add_attribute(rec_safe_renderer->property_state(), _columns.rec_safe);
130         rec_safe_column->add_attribute(rec_safe_renderer->property_visible(), _columns.is_track);
131         rec_safe_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
132         rec_safe_column->set_alignment(ALIGN_CENTER);
133         rec_safe_column->set_expand(false);
134         rec_safe_column->set_fixed_width(column_width);
135
136
137         // MIDI Input Active
138
139         CellRendererPixbufMulti* input_active_col_renderer = manage (new CellRendererPixbufMulti());
140         input_active_col_renderer->set_pixbuf (0, ::get_icon("midi-input-inactive"));
141         input_active_col_renderer->set_pixbuf (1, ::get_icon("midi-input-active"));
142         input_active_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_input_active_changed));
143
144         TreeViewColumn* input_active_column = manage (new TreeViewColumn ("I", *input_active_col_renderer));
145
146         input_active_column->add_attribute(input_active_col_renderer->property_state(), _columns.is_input_active);
147         input_active_column->add_attribute (input_active_col_renderer->property_visible(), _columns.is_midi);
148
149         input_active_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
150         input_active_column->set_alignment(ALIGN_CENTER);
151         input_active_column->set_expand(false);
152         input_active_column->set_fixed_width(column_width);
153
154         // Mute enable toggle
155         CellRendererPixbufMulti* mute_col_renderer = manage (new CellRendererPixbufMulti());
156
157         mute_col_renderer->set_pixbuf (Gtkmm2ext::Off, ::get_icon("mute-disabled"));
158         mute_col_renderer->set_pixbuf (Gtkmm2ext::ImplicitActive, ::get_icon("muted-by-others"));
159         mute_col_renderer->set_pixbuf (Gtkmm2ext::ExplicitActive, ::get_icon("mute-enabled"));
160         mute_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_mute_enable_toggled));
161
162         TreeViewColumn* mute_state_column = manage (new TreeViewColumn("M", *mute_col_renderer));
163
164         mute_state_column->add_attribute(mute_col_renderer->property_state(), _columns.mute_state);
165         mute_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
166         mute_state_column->set_alignment(ALIGN_CENTER);
167         mute_state_column->set_expand(false);
168         mute_state_column->set_fixed_width(15);
169
170         // Solo enable toggle
171         CellRendererPixbufMulti* solo_col_renderer = manage (new CellRendererPixbufMulti());
172
173         solo_col_renderer->set_pixbuf (Gtkmm2ext::Off, ::get_icon("solo-disabled"));
174         solo_col_renderer->set_pixbuf (Gtkmm2ext::ExplicitActive, ::get_icon("solo-enabled"));
175         solo_col_renderer->set_pixbuf (Gtkmm2ext::ImplicitActive, ::get_icon("soloed-by-others"));
176         solo_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_enable_toggled));
177
178         TreeViewColumn* solo_state_column = manage (new TreeViewColumn("S", *solo_col_renderer));
179
180         solo_state_column->add_attribute(solo_col_renderer->property_state(), _columns.solo_state);
181         solo_state_column->add_attribute(solo_col_renderer->property_visible(), _columns.solo_visible);
182         solo_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
183         solo_state_column->set_alignment(ALIGN_CENTER);
184         solo_state_column->set_expand(false);
185         solo_state_column->set_fixed_width(column_width);
186
187         // Solo isolate toggle
188         CellRendererPixbufMulti* solo_iso_renderer = manage (new CellRendererPixbufMulti());
189
190         solo_iso_renderer->set_pixbuf (0, ::get_icon("solo-isolate-disabled"));
191         solo_iso_renderer->set_pixbuf (1, ::get_icon("solo-isolate-enabled"));
192         solo_iso_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_isolate_toggled));
193
194         TreeViewColumn* solo_isolate_state_column = manage (new TreeViewColumn("SI", *solo_iso_renderer));
195
196         solo_isolate_state_column->add_attribute(solo_iso_renderer->property_state(), _columns.solo_isolate_state);
197         solo_isolate_state_column->add_attribute(solo_iso_renderer->property_visible(), _columns.solo_visible);
198         solo_isolate_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
199         solo_isolate_state_column->set_alignment(ALIGN_CENTER);
200         solo_isolate_state_column->set_expand(false);
201         solo_isolate_state_column->set_fixed_width(column_width);
202
203         // Solo safe toggle
204         CellRendererPixbufMulti* solo_safe_renderer = manage (new CellRendererPixbufMulti ());
205
206         solo_safe_renderer->set_pixbuf (0, ::get_icon("solo-safe-disabled"));
207         solo_safe_renderer->set_pixbuf (1, ::get_icon("solo-safe-enabled"));
208         solo_safe_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_safe_toggled));
209
210         TreeViewColumn* solo_safe_state_column = manage (new TreeViewColumn(_("SS"), *solo_safe_renderer));
211         solo_safe_state_column->add_attribute(solo_safe_renderer->property_state(), _columns.solo_safe_state);
212         solo_safe_state_column->add_attribute(solo_safe_renderer->property_visible(), _columns.solo_visible);
213         solo_safe_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
214         solo_safe_state_column->set_alignment(ALIGN_CENTER);
215         solo_safe_state_column->set_expand(false);
216         solo_safe_state_column->set_fixed_width(column_width);
217
218         _name_column = _display.append_column ("", _columns.text) - 1;
219         _visible_column = _display.append_column ("", _columns.visible) - 1;
220         _active_column = _display.append_column ("", _columns.active) - 1;
221
222         _display.append_column (*input_active_column);
223         _display.append_column (*rec_state_column);
224         _display.append_column (*rec_safe_column);
225         _display.append_column (*mute_state_column);
226         _display.append_column (*solo_state_column);
227         _display.append_column (*solo_isolate_state_column);
228         _display.append_column (*solo_safe_state_column);
229
230
231         TreeViewColumn* col;
232         Gtk::Label* l;
233
234         ColumnInfo ci[] = {
235                 { 0,  _("Name"),        _("Track/Bus Name") },
236                 { 1, S_("Visible|V"),   _("Track/Bus visible ?") },
237                 { 2, S_("Active|A"),    _("Track/Bus active ?") },
238                 { 3, S_("MidiInput|I"), _("MIDI input enabled") },
239                 { 4, S_("Rec|R"),       _("Record enabled") },
240                 { 5, S_("Rec|RS"),      _("Record Safe") },
241                 { 6, S_("Mute|M"),      _("Muted") },
242                 { 7, S_("Solo|S"),      _("Soloed") },
243                 { 8, S_("SoloIso|SI"),  _("Solo Isolated") },
244                 { 9, S_("SoloLock|SS"), _("Solo Safe (Locked)") },
245                 { -1, 0, 0 }
246         };
247
248         for (int i = 0; ci[i].index >= 0; ++i) {
249                 col = _display.get_column (ci[i].index);
250                 l = manage (new Label (ci[i].label));
251                 set_tooltip (*l, ci[i].tooltip);
252                 col->set_widget (*l);
253                 l->show ();
254         }
255
256         _display.set_headers_visible (true);
257         _display.get_selection()->set_mode (SELECTION_MULTIPLE);
258         _display.get_selection()->set_select_function (sigc::mem_fun (*this, &EditorRoutes::selection_filter));
259         _display.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::selection_changed));
260         _display.set_reorderable (true);
261         _display.set_name (X_("EditGroupList"));
262         _display.set_rules_hint (true);
263         _display.set_size_request (100, -1);
264         _display.add_object_drag (_columns.stripable.index(), "routes");
265
266         CellRendererText* name_cell = dynamic_cast<CellRendererText*> (_display.get_column_cell_renderer (_name_column));
267
268         assert (name_cell);
269         name_cell->signal_editing_started().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit_started));
270
271         TreeViewColumn* name_column = _display.get_column (_name_column);
272
273         assert (name_column);
274
275         name_column->add_attribute (name_cell->property_editable(), _columns.name_editable);
276         name_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
277         name_column->set_expand(true);
278         name_column->set_min_width(50);
279
280         name_cell->property_editable() = true;
281         name_cell->signal_edited().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit));
282
283         // Set the visible column cell renderer to radio toggle
284         CellRendererToggle* visible_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (_visible_column));
285
286         visible_cell->property_activatable() = true;
287         visible_cell->property_radio() = false;
288         visible_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::visible_changed));
289
290         TreeViewColumn* visible_col = dynamic_cast<TreeViewColumn*> (_display.get_column (_visible_column));
291         visible_col->set_expand(false);
292         visible_col->set_sizing(TREE_VIEW_COLUMN_FIXED);
293         visible_col->set_fixed_width(30);
294         visible_col->set_alignment(ALIGN_CENTER);
295
296         CellRendererToggle* active_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (_active_column));
297
298         active_cell->property_activatable() = true;
299         active_cell->property_radio() = false;
300         active_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::active_changed));
301
302         TreeViewColumn* active_col = dynamic_cast<TreeViewColumn*> (_display.get_column (_active_column));
303         active_col->set_expand (false);
304         active_col->set_sizing (TREE_VIEW_COLUMN_FIXED);
305         active_col->set_fixed_width (30);
306         active_col->set_alignment (ALIGN_CENTER);
307
308         _model->signal_row_deleted().connect (sigc::mem_fun (*this, &EditorRoutes::row_deleted));
309         _model->signal_rows_reordered().connect (sigc::mem_fun (*this, &EditorRoutes::reordered));
310
311         _display.signal_button_press_event().connect (sigc::mem_fun (*this, &EditorRoutes::button_press), false);
312         _scroller.signal_key_press_event().connect (sigc::mem_fun(*this, &EditorRoutes::key_press), false);
313
314         _scroller.signal_focus_in_event().connect (sigc::mem_fun (*this, &EditorRoutes::focus_in), false);
315         _scroller.signal_focus_out_event().connect (sigc::mem_fun (*this, &EditorRoutes::focus_out));
316
317         _display.signal_enter_notify_event().connect (sigc::mem_fun (*this, &EditorRoutes::enter_notify), false);
318         _display.signal_leave_notify_event().connect (sigc::mem_fun (*this, &EditorRoutes::leave_notify), false);
319
320         _display.set_enable_search (false);
321
322         Route::PluginSetup.connect_same_thread (*this, boost::bind (&EditorRoutes::plugin_setup, this, _1, _2, _3));
323 }
324
325 bool
326 EditorRoutes::focus_in (GdkEventFocus*)
327 {
328         Window* win = dynamic_cast<Window*> (_scroller.get_toplevel ());
329
330         if (win) {
331                 old_focus = win->get_focus ();
332         } else {
333                 old_focus = 0;
334         }
335
336         name_editable = 0;
337
338         /* try to do nothing on focus in (doesn't work, hence selection_count nonsense) */
339         return true;
340 }
341
342 bool
343 EditorRoutes::focus_out (GdkEventFocus*)
344 {
345         if (old_focus) {
346                 old_focus->grab_focus ();
347                 old_focus = 0;
348         }
349
350         return false;
351 }
352
353 bool
354 EditorRoutes::enter_notify (GdkEventCrossing*)
355 {
356         if (name_editable) {
357                 return true;
358         }
359
360         /* arm counter so that ::selection_filter() will deny selecting anything for the
361          * next two attempts to change selection status.
362          */
363         selection_countdown = 2;
364         _scroller.grab_focus ();
365         Keyboard::magic_widget_grab_focus ();
366         return false;
367 }
368
369 bool
370 EditorRoutes::leave_notify (GdkEventCrossing*)
371 {
372         selection_countdown = 0;
373
374         if (old_focus) {
375                 old_focus->grab_focus ();
376                 old_focus = 0;
377         }
378
379         Keyboard::magic_widget_drop_focus ();
380         return false;
381 }
382
383 void
384 EditorRoutes::set_session (Session* s)
385 {
386         SessionHandlePtr::set_session (s);
387
388         initial_display ();
389
390         if (_session) {
391                 _session->SoloChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::solo_changed_so_update_mute, this), gui_context());
392                 _session->RecordStateChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
393
394                 /* TODO: check if these needs to be tied in with DisplaySuspender
395                  * Given that the UI is single-threaded and DisplaySuspender is only used
396                  * in loops in the UI thread all should be fine.
397                  */
398                 _session->BatchUpdateStart.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::suspend_redisplay, this), gui_context());
399                 _session->BatchUpdateEnd.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::resume_redisplay, this), gui_context());
400         }
401 }
402
403 void
404 EditorRoutes::on_input_active_changed (std::string const & path_string)
405 {
406         // Get the model row that has been toggled.
407         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
408
409         TimeAxisView* tv = row[_columns.tv];
410         RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
411
412         if (rtv) {
413                 boost::shared_ptr<MidiTrack> mt;
414                 mt = rtv->midi_track();
415                 if (mt) {
416                         mt->set_input_active (!mt->input_active());
417                 }
418         }
419 }
420
421 void
422 EditorRoutes::on_tv_rec_enable_changed (std::string const & path_string)
423 {
424         // Get the model row that has been toggled.
425         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
426
427         TimeAxisView* tv = row[_columns.tv];
428         RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
429
430         if (!rtv) {
431                 return;
432         }
433
434         boost::shared_ptr<AutomationControl> ac = rtv->route()->rec_enable_control();
435
436         if (ac) {
437                 ac->set_value (!ac->get_value(), Controllable::UseGroup);
438         }
439 }
440
441 void
442 EditorRoutes::on_tv_rec_safe_toggled (std::string const & path_string)
443 {
444         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
445         TimeAxisView* tv = row[_columns.tv];
446         RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
447
448         if (!rtv) {
449                 return;
450         }
451
452         boost::shared_ptr<AutomationControl> ac (rtv->route()->rec_safe_control());
453
454         if (ac) {
455                 ac->set_value (!ac->get_value(), Controllable::UseGroup);
456         }
457 }
458
459 void
460 EditorRoutes::on_tv_mute_enable_toggled (std::string const & path_string)
461 {
462         // Get the model row that has been toggled.
463         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
464
465         TimeAxisView *tv = row[_columns.tv];
466         RouteTimeAxisView *rtv = dynamic_cast<RouteTimeAxisView*> (tv);
467
468         if (!rtv) {
469                 return;
470         }
471
472         boost::shared_ptr<AutomationControl> ac (rtv->route()->mute_control());
473
474         if (ac) {
475                 ac->set_value (!ac->get_value(), Controllable::UseGroup);
476         }
477 }
478
479 void
480 EditorRoutes::on_tv_solo_enable_toggled (std::string const & path_string)
481 {
482         // Get the model row that has been toggled.
483         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
484
485         TimeAxisView *tv = row[_columns.tv];
486         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
487
488         if (!rtv) {
489                 return;
490         }
491
492         boost::shared_ptr<AutomationControl> ac (rtv->route()->solo_control());
493
494         if (ac) {
495                 ac->set_value (!ac->get_value(), Controllable::UseGroup);
496         }
497 }
498
499 void
500 EditorRoutes::on_tv_solo_isolate_toggled (std::string const & path_string)
501 {
502         // Get the model row that has been toggled.
503         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
504
505         TimeAxisView *tv = row[_columns.tv];
506         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
507
508         if (!rtv) {
509                 return;
510         }
511
512         boost::shared_ptr<AutomationControl> ac (rtv->route()->solo_isolate_control());
513
514         if (ac) {
515                 ac->set_value (!ac->get_value(), Controllable::UseGroup);
516         }
517 }
518
519 void
520 EditorRoutes::on_tv_solo_safe_toggled (std::string const & path_string)
521 {
522         // Get the model row that has been toggled.
523         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
524
525         TimeAxisView *tv = row[_columns.tv];
526         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
527
528         if (!rtv) {
529                 return;
530         }
531
532         boost::shared_ptr<AutomationControl> ac (rtv->route()->solo_safe_control());
533
534         if (ac) {
535                 ac->set_value (!ac->get_value(), Controllable::UseGroup);
536         }
537 }
538
539 void
540 EditorRoutes::build_menu ()
541 {
542         using namespace Menu_Helpers;
543         using namespace Gtk;
544
545         _menu = new Menu;
546
547         MenuList& items = _menu->items();
548         _menu->set_name ("ArdourContextMenu");
549
550         items.push_back (MenuElem (_("Show All"), sigc::mem_fun (*this, &EditorRoutes::show_all_routes)));
551         items.push_back (MenuElem (_("Hide All"), sigc::mem_fun (*this, &EditorRoutes::hide_all_routes)));
552         items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiotracks)));
553         items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiotracks)));
554         items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiobus)));
555         items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiobus)));
556         items.push_back (MenuElem (_("Show All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_miditracks)));
557         items.push_back (MenuElem (_("Hide All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_miditracks)));
558         items.push_back (MenuElem (_("Only Show Tracks with Regions Under Playhead"), sigc::mem_fun (*this, &EditorRoutes::show_tracks_with_regions_at_playhead)));
559 }
560
561 void
562 EditorRoutes::redisplay_real ()
563 {
564         TreeModel::Children rows = _model->children();
565         TreeModel::Children::iterator i;
566         uint32_t position;
567
568         /* n will be the count of tracks plus children (updated by TimeAxisView::show_at),
569          * so we will use that to know where to put things.
570          */
571         int n;
572
573         for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
574                 TimeAxisView *tv = (*i)[_columns.tv];
575
576                 if (tv == 0) {
577                         // just a "title" row
578                         continue;
579                 }
580
581                 bool visible = tv->marked_for_display ();
582
583                 /* show or hide the TimeAxisView */
584                 if (visible) {
585                         position += tv->show_at (position, n, &_editor->edit_controls_vbox);
586                 } else {
587                         tv->hide ();
588                 }
589
590                 n++;
591         }
592
593         /* whenever we go idle, update the track view list to reflect the new order.
594          * we can't do this here, because we could mess up something that is traversing
595          * the track order and has caused a redisplay of the list.
596          */
597         Glib::signal_idle().connect (sigc::mem_fun (*_editor, &Editor::sync_track_view_list_and_routes));
598
599         _editor->reset_controls_layout_height (position);
600         _editor->reset_controls_layout_width ();
601         _editor->_full_canvas_height = position;
602
603         if ((_editor->vertical_adjustment.get_value() + _editor->_visible_canvas_height) > _editor->vertical_adjustment.get_upper()) {
604                 /*
605                  * We're increasing the size of the canvas while the bottom is visible.
606                  * We scroll down to keep in step with the controls layout.
607                  */
608                 _editor->vertical_adjustment.set_value (_editor->_full_canvas_height - _editor->_visible_canvas_height);
609         }
610 }
611
612 void
613 EditorRoutes::redisplay ()
614 {
615         if (!_session || _session->deletion_in_progress()) {
616                 return;
617         }
618
619         if (_no_redisplay) {
620                 _redisplay_on_resume = true;
621                 return;
622         }
623
624         // model deprecated g_atomic_int_exchange_and_add(, 1)
625         g_atomic_int_inc(const_cast<gint*>(&_redisplay_active));
626         if (!g_atomic_int_compare_and_exchange (const_cast<gint*>(&_redisplay_active), 1, 1)) {
627                 /* recursive re-display can happen if redisplay shows/hides a TrackView
628                  * which has children and their display status changes as result.
629                  */
630                 return;
631         }
632
633         redisplay_real ();
634
635         while (!g_atomic_int_compare_and_exchange (const_cast<gint*>(&_redisplay_active), 1, 0)) {
636                 g_atomic_int_set(const_cast<gint*>(&_redisplay_active), 1);
637                 redisplay_real ();
638         }
639 }
640
641 void
642 EditorRoutes::row_deleted (Gtk::TreeModel::Path const &)
643 {
644         if (!_session || _session->deletion_in_progress()) {
645                 return;
646         }
647         /* this happens as the second step of a DnD within the treeview, and
648          * when a route is actually removed. we don't differentiate between
649          * the two cases.
650          *
651          * note that the sync_presentation_info_from_treeview() step may not
652          * actually change any presentation info (e.g. the last track may be
653          * removed, so all other tracks keep the same presentation info), which
654          * means that no redisplay would happen. so we have to force a
655          * redisplay.
656          */
657
658         DEBUG_TRACE (DEBUG::OrderKeys, "editor routes treeview row deleted\n");
659
660         DisplaySuspender ds;
661         sync_presentation_info_from_treeview ();
662 }
663
664 void
665 EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
666 {
667         /* reordering implies that RID's will change, so
668            sync_presentation_info_from_treeview() will cause a redisplay.
669         */
670
671         DEBUG_TRACE (DEBUG::OrderKeys, "editor routes treeview reordered\n");
672         sync_presentation_info_from_treeview ();
673 }
674
675 void
676 EditorRoutes::visible_changed (std::string const & path)
677 {
678         if (_session && _session->deletion_in_progress()) {
679                 return;
680         }
681
682         DisplaySuspender ds;
683         TreeIter iter;
684
685         if ((iter = _model->get_iter (path))) {
686                 TimeAxisView* tv = (*iter)[_columns.tv];
687                 if (tv) {
688                         bool visible = (*iter)[_columns.visible];
689
690                         if (tv->set_marked_for_display (!visible)) {
691                                 update_visibility ();
692                         }
693                 }
694         }
695 }
696
697 void
698 EditorRoutes::active_changed (std::string const & path)
699 {
700         if (_session && _session->deletion_in_progress ()) {
701                 return;
702         }
703
704         Gtk::TreeModel::Row row = *_model->get_iter (path);
705         boost::shared_ptr<Stripable> stripable = row[_columns.stripable];
706         boost::shared_ptr<Route> route = boost::dynamic_pointer_cast<Route> (stripable);
707         if (route) {
708                 bool const active = row[_columns.active];
709                 route->set_active (!active, this);
710         }
711 }
712
713 void
714 EditorRoutes::time_axis_views_added (list<TimeAxisView*> tavs)
715 {
716         PBD::Unwinder<bool> at (_adding_routes, true);
717         bool from_scratch = (_model->children().size() == 0);
718         Gtk::TreeModel::Children::iterator insert_iter = _model->children().end();
719
720         for (Gtk::TreeModel::Children::iterator it = _model->children().begin(); it != _model->children().end(); ++it) {
721
722                 boost::shared_ptr<Stripable> r = (*it)[_columns.stripable];
723
724                 if (r->presentation_info().order() == (tavs.front()->stripable()->presentation_info().order() + tavs.size())) {
725                         insert_iter = it;
726                         break;
727                 }
728         }
729
730         {
731                 PBD::Unwinder<bool> uw (_ignore_selection_change, true);
732                 _display.set_model (Glib::RefPtr<ListStore>());
733         }
734
735         for (list<TimeAxisView*>::iterator x = tavs.begin(); x != tavs.end(); ++x) {
736
737                 VCATimeAxisView* vtav = dynamic_cast<VCATimeAxisView*> (*x);
738                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
739
740                 TreeModel::Row row = *(_model->insert (insert_iter));
741
742                 boost::shared_ptr<Stripable> stripable;
743                 boost::shared_ptr<MidiTrack> midi_trk;
744
745                 if (vtav) {
746
747                         stripable = vtav->vca();
748
749                         row[_columns.is_track] = false;
750                         row[_columns.is_input_active] = false;
751                         row[_columns.is_midi] = false;
752
753                 } else if (rtav) {
754
755                         stripable = rtav->route ();
756                         midi_trk= boost::dynamic_pointer_cast<MidiTrack> (stripable);
757
758                         row[_columns.is_track] = (boost::dynamic_pointer_cast<Track> (stripable) != 0);
759
760                         if (midi_trk) {
761                                 row[_columns.is_input_active] = midi_trk->input_active ();
762                                 row[_columns.is_midi] = true;
763                         } else {
764                                 row[_columns.is_input_active] = false;
765                                 row[_columns.is_midi] = false;
766                         }
767                 }
768
769                 if (!stripable) {
770                         continue;
771                 }
772
773                 row[_columns.text] = stripable->name();
774                 row[_columns.visible] = (*x)->marked_for_display();
775                 row[_columns.active] = true;
776                 row[_columns.tv] = *x;
777                 row[_columns.stripable] = stripable;
778                 row[_columns.mute_state] = RouteUI::mute_active_state (_session, stripable);
779                 row[_columns.solo_state] = RouteUI::solo_active_state (stripable);
780                 row[_columns.solo_visible] = true;
781                 row[_columns.solo_isolate_state] = RouteUI::solo_isolate_active_state (stripable);
782                 row[_columns.solo_safe_state] = RouteUI::solo_safe_active_state (stripable);
783                 row[_columns.name_editable] = true;
784
785                 boost::weak_ptr<Stripable> ws (stripable);
786
787                 /* for now, we need both of these. PropertyChanged covers on
788                  * pre-defined, "global" things of interest to a
789                  * UI. gui_changed covers arbitrary, un-enumerated, un-typed
790                  * changes that may only be of interest to a particular
791                  * UI (e.g. track-height is not of any relevant to OSC)
792                  */
793
794                 stripable->gui_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
795                 stripable->PropertyChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::route_property_changed, this, _1, ws), gui_context());
796                 stripable->presentation_info().PropertyChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::route_property_changed, this, _1, ws), gui_context());
797
798                 if (boost::dynamic_pointer_cast<Track> (stripable)) {
799                         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (stripable);
800                         t->rec_enable_control()->Changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
801                         t->rec_safe_control()->Changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
802                 }
803
804                 if (midi_trk) {
805                         midi_trk->StepEditStatusChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
806                         midi_trk->InputActiveChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_input_active_display, this), gui_context());
807                 }
808
809                 boost::shared_ptr<AutomationControl> ac;
810
811                 if ((ac = stripable->mute_control()) != 0) {
812                         ac->Changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
813                 }
814                 if ((ac = stripable->solo_control()) != 0) {
815                         ac->Changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_display, this), gui_context());
816                 }
817                 if ((ac = stripable->solo_isolate_control()) != 0) {
818                         ac->Changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_isolate_display, this), gui_context());
819                 }
820                 if ((ac = stripable->solo_safe_control()) != 0) {
821                         ac->Changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_safe_display, this), gui_context());
822                 }
823
824                 if (rtav) {
825                         rtav->route()->active_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_active_display, this), gui_context ());
826                 }
827         }
828
829         update_rec_display ();
830         update_mute_display ();
831         update_solo_display ();
832         update_solo_isolate_display ();
833         update_solo_safe_display ();
834         update_input_active_display ();
835         update_active_display ();
836
837         {
838                 PBD::Unwinder<bool> uw (_ignore_selection_change, true);
839                 _display.set_model (_model);
840         }
841
842         /* now update route order keys from the treeview/track display order */
843
844         if (!from_scratch) {
845                 sync_presentation_info_from_treeview ();
846         }
847
848         redisplay ();
849 }
850
851 void
852 EditorRoutes::handle_gui_changes (string const & what, void*)
853 {
854         if (_adding_routes) {
855                 return;
856         }
857
858         if (what == "track_height") {
859                 /* Optional :make tracks change height while it happens, instead
860                    of on first-idle
861                 */
862                 redisplay ();
863         }
864
865         if (what == "visible_tracks") {
866                 redisplay ();
867         }
868 }
869
870 void
871 EditorRoutes::route_removed (TimeAxisView *tv)
872 {
873         ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed, tv)
874
875         TreeModel::Children rows = _model->children();
876         TreeModel::Children::iterator ri;
877
878         PBD::Unwinder<bool> uw (_ignore_selection_change, true);
879
880         for (ri = rows.begin(); ri != rows.end(); ++ri) {
881                 if ((*ri)[_columns.tv] == tv) {
882                         PBD::Unwinder<bool> uw (_route_deletion_in_progress, true);
883                         _model->erase (ri);
884                         break;
885                 }
886         }
887 }
888
889 void
890 EditorRoutes::route_property_changed (const PropertyChange& what_changed, boost::weak_ptr<Stripable> s)
891 {
892         if (!what_changed.contains (ARDOUR::Properties::hidden) && !what_changed.contains (ARDOUR::Properties::name)) {
893                 return;
894         }
895
896         if (_adding_routes) {
897                 return;
898         }
899
900         boost::shared_ptr<Stripable> stripable = s.lock ();
901
902         if (!stripable) {
903                 return;
904         }
905
906         TreeModel::Children rows = _model->children();
907         TreeModel::Children::iterator i;
908
909         for (i = rows.begin(); i != rows.end(); ++i) {
910
911                 boost::shared_ptr<Stripable> ss = (*i)[_columns.stripable];
912
913                 if (ss == stripable) {
914
915                         if (what_changed.contains (ARDOUR::Properties::name)) {
916                                 (*i)[_columns.text] = stripable->name();
917                                 break;
918                         }
919
920                         if (what_changed.contains (ARDOUR::Properties::hidden)) {
921                                 (*i)[_columns.visible] = !stripable->presentation_info().hidden();
922                                 redisplay ();
923
924                         }
925
926                         break;
927                 }
928         }
929 }
930
931 void
932 EditorRoutes::update_active_display ()
933 {
934         if (g_atomic_int_compare_and_exchange (const_cast<gint*>(&_queue_tv_update), 0, 1)) {
935                 Glib::signal_idle().connect (sigc::mem_fun (*this, &EditorRoutes::idle_update_mute_rec_solo_etc));
936         }
937 }
938
939 void
940 EditorRoutes::update_visibility ()
941 {
942         TreeModel::Children rows = _model->children();
943         TreeModel::Children::iterator i;
944
945         DisplaySuspender ds;
946
947         for (i = rows.begin(); i != rows.end(); ++i) {
948                 TimeAxisView *tv = (*i)[_columns.tv];
949                 (*i)[_columns.visible] = tv->marked_for_display ();
950         }
951
952         /* force route order keys catch up with visibility changes
953          */
954
955         sync_presentation_info_from_treeview ();
956 }
957
958 void
959 EditorRoutes::hide_track_in_display (TimeAxisView& tv)
960 {
961         TreeModel::Children rows = _model->children();
962         TreeModel::Children::iterator i;
963
964         for (i = rows.begin(); i != rows.end(); ++i) {
965                 if ((*i)[_columns.tv] == &tv) {
966                         tv.set_marked_for_display (false);
967                         (*i)[_columns.visible] = false;
968                         redisplay ();
969                         break;
970                 }
971         }
972 }
973
974 void
975 EditorRoutes::show_track_in_display (TimeAxisView& tv)
976 {
977         TreeModel::Children rows = _model->children();
978         TreeModel::Children::iterator i;
979
980
981         for (i = rows.begin(); i != rows.end(); ++i) {
982                 if ((*i)[_columns.tv] == &tv) {
983                         tv.set_marked_for_display (true);
984                         (*i)[_columns.visible] = true;
985                         redisplay ();
986                         break;
987                 }
988         }
989 }
990
991 void
992 EditorRoutes::sync_presentation_info_from_treeview ()
993 {
994         if (_ignore_reorder || !_session || _session->deletion_in_progress()) {
995                 return;
996         }
997
998         TreeModel::Children rows = _model->children();
999
1000         if (rows.empty()) {
1001                 return;
1002         }
1003
1004         DEBUG_TRACE (DEBUG::OrderKeys, "editor sync presentation info from treeview\n");
1005
1006         TreeModel::Children::iterator ri;
1007         bool change = false;
1008         PresentationInfo::order_t order = 0;
1009         bool master_is_first = false;
1010         uint32_t count = 0;
1011
1012         OrderingKeys sorted;
1013         const size_t cmp_max = rows.size ();
1014
1015         PresentationInfo::ChangeSuspender cs;
1016
1017         // special case master if it's got PI order 0 lets keep it there
1018         if (_session->master_out() && (_session->master_out()->presentation_info().order() == 0)) {
1019                 order++;
1020                 master_is_first = true;
1021         }
1022
1023         for (ri = rows.begin(); ri != rows.end(); ++ri) {
1024
1025                 boost::shared_ptr<Stripable> stripable = (*ri)[_columns.stripable];
1026                 bool visible = (*ri)[_columns.visible];
1027
1028                 /* Monitor and Auditioner do not get their presentation
1029                  * info reset here.
1030                  */
1031
1032                 if (stripable->is_monitor() || stripable->is_auditioner()) {
1033                         continue;
1034                 }
1035
1036                 stripable->presentation_info().set_hidden (!visible);
1037
1038                 /* special case master if it's got PI order 0 lets keep it there
1039                  * but still allow master to move if first non-master route has
1040                  * presentation order 1
1041                  */
1042                 if ((count == 0) && master_is_first && (stripable->presentation_info().order()  == 1)) {
1043                         master_is_first = false; // someone has moved master
1044                         order = 0;
1045                 }
1046
1047                 if (stripable->is_master() && master_is_first) {
1048                         if (count) {
1049                                 continue;
1050                         } else {
1051                                 count++;
1052                                 continue;
1053                         }
1054                 }
1055
1056                 if (order != stripable->presentation_info().order()) {
1057                         stripable->set_presentation_order (order);
1058                         change = true;
1059                 }
1060
1061                 sorted.push_back (OrderKeys (order, stripable, cmp_max));
1062
1063                 ++order;
1064                 ++count;
1065         }
1066
1067         if (!change) {
1068                 // VCA (and Mixbus) special cases according to SortByNewDisplayOrder
1069                 uint32_t n = 0;
1070                 SortByNewDisplayOrder cmp;
1071                 sort (sorted.begin(), sorted.end(), cmp);
1072                 for (OrderingKeys::iterator sr = sorted.begin(); sr != sorted.end(); ++sr, ++n) {
1073                         if (sr->old_display_order != n) {
1074                                 change = true;
1075                         }
1076                 }
1077                 if (change) {
1078                         n = 0;
1079                         for (OrderingKeys::iterator sr = sorted.begin(); sr != sorted.end(); ++sr, ++n) {
1080                                 if (sr->stripable->presentation_info().order() != n) {
1081                                         sr->stripable->set_presentation_order (n);
1082                                 }
1083                         }
1084                 }
1085         }
1086 }
1087
1088 void
1089 EditorRoutes::sync_treeview_from_presentation_info (PropertyChange const & what_changed)
1090 {
1091         /* Some route order key(s) have been changed, make sure that
1092            we update out tree/list model and GUI to reflect the change.
1093         */
1094
1095         if (_ignore_reorder || !_session || _session->deletion_in_progress()) {
1096                 return;
1097         }
1098
1099         DEBUG_TRACE (DEBUG::OrderKeys, "editor sync model from presentation info.\n");
1100
1101         PropertyChange hidden_or_order;
1102         hidden_or_order.add (Properties::hidden);
1103         hidden_or_order.add (Properties::order);
1104
1105         TreeModel::Children rows = _model->children();
1106
1107         if (what_changed.contains (hidden_or_order)) {
1108
1109                 vector<int> neworder;
1110                 uint32_t old_order = 0;
1111                 bool changed = false;
1112
1113                 if (rows.empty()) {
1114                         return;
1115                 }
1116
1117                 OrderingKeys sorted;
1118                 const size_t cmp_max = rows.size ();
1119
1120                 for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++old_order) {
1121                         boost::shared_ptr<Stripable> stripable = (*ri)[_columns.stripable];
1122                         /* use global order */
1123                         sorted.push_back (OrderKeys (old_order, stripable, cmp_max));
1124                 }
1125
1126                 SortByNewDisplayOrder cmp;
1127
1128                 sort (sorted.begin(), sorted.end(), cmp);
1129                 neworder.assign (sorted.size(), 0);
1130
1131                 uint32_t n = 0;
1132
1133                 for (OrderingKeys::iterator sr = sorted.begin(); sr != sorted.end(); ++sr, ++n) {
1134
1135                         neworder[n] = sr->old_display_order;
1136
1137                         if (sr->old_display_order != n) {
1138                                 changed = true;
1139                         }
1140                 }
1141
1142                 if (changed) {
1143                         Unwinder<bool> uw (_ignore_reorder, true);
1144                         /* prevent traverse_cells: assertion 'row_path != NULL'
1145                          * in case of DnD re-order: row-removed + row-inserted.
1146                          *
1147                          * The rows (stripables) are not actually removed from the model,
1148                          * but only from the display in the DnDTreeView.
1149                          * ->reorder() will fail to find the row_path.
1150                          * (re-order drag -> remove row -> sync PI from TV -> notify -> sync TV from PI -> crash)
1151                          */
1152                         Unwinder<bool> uw2 (_ignore_selection_change, true);
1153
1154                         _display.unset_model();
1155                         _model->reorder (neworder);
1156                         _display.set_model (_model);
1157                 }
1158         }
1159
1160         if (what_changed.contains (Properties::selected)) {
1161
1162                 /* by the time this is invoked, the GUI Selection model has
1163                  * already updated itself.
1164                  */
1165
1166                 TrackViewList tvl;
1167                 PBD::Unwinder<bool> uw (_ignore_selection_change, true);
1168
1169                 /* set the treeview model selection state */
1170
1171                 for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri) {
1172                         boost::shared_ptr<Stripable> stripable = (*ri)[_columns.stripable];
1173                         if (stripable && stripable->is_selected()) {
1174                                 TimeAxisView* tav = (*ri)[_columns.tv];
1175                                 if (tav) {
1176                                         tvl.push_back (tav);
1177                                 }
1178                                 _display.get_selection()->select (*ri);
1179                         } else {
1180                                 _display.get_selection()->unselect (*ri);
1181                         }
1182                 }
1183         }
1184
1185         redisplay ();
1186 }
1187
1188 void
1189 EditorRoutes::hide_all_tracks (bool /*with_select*/)
1190 {
1191         TreeModel::Children rows = _model->children();
1192         TreeModel::Children::iterator i;
1193
1194         DisplaySuspender ds;
1195
1196         for (i = rows.begin(); i != rows.end(); ++i) {
1197
1198                 TreeModel::Row row = (*i);
1199                 TimeAxisView *tv = row[_columns.tv];
1200
1201                 if (tv == 0) {
1202                         continue;
1203                 }
1204
1205                 row[_columns.visible] = false;
1206         }
1207 }
1208
1209 void
1210 EditorRoutes::set_all_tracks_visibility (bool yn)
1211 {
1212         TreeModel::Children rows = _model->children();
1213         TreeModel::Children::iterator i;
1214
1215         DisplaySuspender ds;
1216
1217         for (i = rows.begin(); i != rows.end(); ++i) {
1218
1219                 TreeModel::Row row = (*i);
1220                 TimeAxisView* tv = row[_columns.tv];
1221
1222                 if (tv == 0) {
1223                         continue;
1224                 }
1225
1226                 tv->set_marked_for_display (yn);
1227                 (*i)[_columns.visible] = yn;
1228         }
1229
1230         /* force route order keys catch up with visibility changes
1231          */
1232
1233         sync_presentation_info_from_treeview ();
1234 }
1235
1236 void
1237 EditorRoutes::set_all_audio_midi_visibility (int tracks, bool yn)
1238 {
1239         TreeModel::Children rows = _model->children();
1240         TreeModel::Children::iterator i;
1241
1242         DisplaySuspender ds;
1243
1244         for (i = rows.begin(); i != rows.end(); ++i) {
1245
1246                 TreeModel::Row row = (*i);
1247                 TimeAxisView* tv = row[_columns.tv];
1248
1249                 AudioTimeAxisView* atv;
1250                 MidiTimeAxisView* mtv;
1251
1252                 if (tv == 0) {
1253                         continue;
1254                 }
1255
1256                 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
1257                         switch (tracks) {
1258                         case 0:
1259                                 atv->set_marked_for_display (yn);
1260                                 (*i)[_columns.visible] = yn;
1261                                 break;
1262
1263                         case 1:
1264                                 if (atv->is_audio_track()) {
1265                                         atv->set_marked_for_display (yn);
1266                                         (*i)[_columns.visible] = yn;
1267                                 }
1268                                 break;
1269
1270                         case 2:
1271                                 if (!atv->is_audio_track()) {
1272                                         atv->set_marked_for_display (yn);
1273                                         (*i)[_columns.visible] = yn;
1274                                 }
1275                                 break;
1276                         }
1277                 }
1278                 else if ((mtv = dynamic_cast<MidiTimeAxisView*>(tv)) != 0) {
1279                         switch (tracks) {
1280                         case 0:
1281                                 mtv->set_marked_for_display (yn);
1282                                 (*i)[_columns.visible] = yn;
1283                                 break;
1284
1285                         case 3:
1286                                 if (mtv->is_midi_track()) {
1287                                         mtv->set_marked_for_display (yn);
1288                                         (*i)[_columns.visible] = yn;
1289                                 }
1290                                 break;
1291                         }
1292                 }
1293         }
1294
1295         /* force route order keys catch up with visibility changes
1296          */
1297
1298         sync_presentation_info_from_treeview ();
1299 }
1300
1301 void
1302 EditorRoutes::hide_all_routes ()
1303 {
1304         set_all_tracks_visibility (false);
1305 }
1306
1307 void
1308 EditorRoutes::show_all_routes ()
1309 {
1310         set_all_tracks_visibility (true);
1311 }
1312
1313 void
1314 EditorRoutes::show_all_audiotracks()
1315 {
1316         set_all_audio_midi_visibility (1, true);
1317 }
1318 void
1319 EditorRoutes::hide_all_audiotracks ()
1320 {
1321         set_all_audio_midi_visibility (1, false);
1322 }
1323
1324 void
1325 EditorRoutes::show_all_audiobus ()
1326 {
1327         set_all_audio_midi_visibility (2, true);
1328 }
1329 void
1330 EditorRoutes::hide_all_audiobus ()
1331 {
1332         set_all_audio_midi_visibility (2, false);
1333 }
1334
1335 void
1336 EditorRoutes::show_all_miditracks()
1337 {
1338         set_all_audio_midi_visibility (3, true);
1339 }
1340 void
1341 EditorRoutes::hide_all_miditracks ()
1342 {
1343         set_all_audio_midi_visibility (3, false);
1344 }
1345
1346 bool
1347 EditorRoutes::key_press (GdkEventKey* ev)
1348 {
1349         TreeViewColumn *col;
1350         boost::shared_ptr<RouteList> rl (new RouteList);
1351         TreePath path;
1352
1353         switch (ev->keyval) {
1354                 case GDK_Tab:
1355                 case GDK_ISO_Left_Tab:
1356
1357                         /* If we appear to be editing something, leave that cleanly and appropriately. */
1358                         if (name_editable) {
1359                                 name_editable->editing_done ();
1360                                 name_editable = 0;
1361                         }
1362
1363                         col = _display.get_column (_name_column); // select&focus on name column
1364
1365                         if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
1366                                 treeview_select_previous (_display, _model, col);
1367                         } else {
1368                                 treeview_select_next (_display, _model, col);
1369                         }
1370
1371                         return true;
1372                         break;
1373
1374                 case 'm':
1375                         if (get_relevant_routes (rl)) {
1376                                 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), rl->front()->muted() ? 0.0 : 1.0, Controllable::NoGroup);
1377                         }
1378                         return true;
1379                         break;
1380
1381                 case 's':
1382                         if (get_relevant_routes (rl)) {
1383                                 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), rl->front()->self_soloed() ? 0.0 : 1.0, Controllable::NoGroup);
1384                         }
1385                         return true;
1386                         break;
1387
1388                 case 'r':
1389                         if (get_relevant_routes (rl)) {
1390                                 for (RouteList::const_iterator r = rl->begin(); r != rl->end(); ++r) {
1391                                         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
1392                                         if (t) {
1393                                                 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), !t->rec_enable_control()->get_value(), Controllable::NoGroup);
1394                                                 break;
1395                                         }
1396                                 }
1397                         }
1398                         break;
1399
1400                 default:
1401                         break;
1402         }
1403
1404         return false;
1405 }
1406
1407 bool
1408 EditorRoutes::get_relevant_routes (boost::shared_ptr<RouteList> rl)
1409 {
1410         TimeAxisView* tv;
1411         RouteTimeAxisView* rtv;
1412         RefPtr<TreeSelection> selection = _display.get_selection();
1413         TreePath path;
1414         TreeIter iter;
1415
1416         if (selection->count_selected_rows() != 0) {
1417
1418                 /* use selection */
1419
1420                 RefPtr<TreeModel> tm = RefPtr<TreeModel>::cast_dynamic (_model);
1421                 iter = selection->get_selected (tm);
1422
1423         } else {
1424                 /* use mouse pointer */
1425
1426                 int x, y;
1427                 int bx, by;
1428
1429                 _display.get_pointer (x, y);
1430                 _display.convert_widget_to_bin_window_coords (x, y, bx, by);
1431
1432                 if (_display.get_path_at_pos (bx, by, path)) {
1433                         iter = _model->get_iter (path);
1434                 }
1435         }
1436
1437         if (iter) {
1438                 tv = (*iter)[_columns.tv];
1439                 if (tv) {
1440                         rtv = dynamic_cast<RouteTimeAxisView*>(tv);
1441                         if (rtv) {
1442                                 rl->push_back (rtv->route());
1443                         }
1444                 }
1445         }
1446
1447         return !rl->empty();
1448 }
1449
1450 bool
1451 EditorRoutes::button_press (GdkEventButton* ev)
1452 {
1453         if (Keyboard::is_context_menu_event (ev)) {
1454                 if (_menu == 0) {
1455                         build_menu ();
1456                 }
1457                 _menu->popup (ev->button, ev->time);
1458                 return true;
1459         }
1460
1461         TreeModel::Path path;
1462         TreeViewColumn *tvc;
1463         int cell_x;
1464         int cell_y;
1465
1466         if (!_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y)) {
1467                 /* cancel selection */
1468                 _display.get_selection()->unselect_all ();
1469                 /* end any editing by grabbing focus */
1470                 _display.grab_focus ();
1471                 return true;
1472         }
1473
1474         //Scroll editor canvas to selected track
1475         if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1476
1477                 Gtk::TreeModel::Row row = *_model->get_iter (path);
1478                 TimeAxisView *tv = row[_columns.tv];
1479
1480                 if (tv) {
1481                         _editor->ensure_time_axis_view_is_visible (*tv, true);
1482                 }
1483         }
1484
1485         return false;
1486 }
1487
1488 void
1489 EditorRoutes::selection_changed ()
1490 {
1491         if (_ignore_selection_change) {
1492                 return;
1493         }
1494
1495         _editor->begin_reversible_selection_op (X_("Select Track from Route List"));
1496
1497         if (_display.get_selection()->count_selected_rows() > 0) {
1498
1499                 TreeIter iter;
1500                 TreeView::Selection::ListHandle_Path rows = _display.get_selection()->get_selected_rows ();
1501                 TrackViewList selected;
1502
1503                 for (TreeView::Selection::ListHandle_Path::iterator i = rows.begin(); i != rows.end(); ++i) {
1504
1505                         if ((iter = _model->get_iter (*i))) {
1506
1507                                 TimeAxisView* tv = (*iter)[_columns.tv];
1508                                 selected.push_back (tv);
1509                         }
1510
1511                 }
1512
1513                 _editor->get_selection().set (selected);
1514                 _editor->ensure_time_axis_view_is_visible (*(selected.front()), true);
1515
1516         } else {
1517                 _editor->get_selection().clear_tracks ();
1518         }
1519
1520         _editor->commit_reversible_selection_op ();
1521 }
1522
1523 bool
1524 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const& model, TreeModel::Path const& path, bool /*selected*/)
1525 {
1526         if (selection_countdown) {
1527                 if (--selection_countdown == 0) {
1528                         return true;
1529                 } else {
1530                         /* no selection yet ... */
1531                         return false;
1532                 }
1533         }
1534
1535         TreeModel::iterator iter = model->get_iter (path);
1536         if (iter) {
1537                 boost::shared_ptr<Stripable> stripable = (*iter)[_columns.stripable];
1538                 if (boost::dynamic_pointer_cast<VCA> (stripable)) {
1539                         return false;
1540                 }
1541         }
1542
1543         return true;
1544 }
1545
1546 struct PresentationInfoRouteSorter
1547 {
1548         bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1549                 if (a->is_master()) {
1550                         /* master before everything else */
1551                         return true;
1552                 } else if (b->is_master()) {
1553                         /* everything else before master */
1554                         return false;
1555                 }
1556                 return a->presentation_info().order () < b->presentation_info().order ();
1557         }
1558 };
1559
1560 struct PresentationInfoVCASorter
1561 {
1562         bool operator() (boost::shared_ptr<VCA> a, boost::shared_ptr<VCA> b) {
1563                 return a->presentation_info().order () < b->presentation_info().order ();
1564         }
1565 };
1566
1567 void
1568 EditorRoutes::initial_display ()
1569 {
1570
1571         if (!_session) {
1572                 _model->clear ();
1573                 return;
1574         }
1575
1576         DisplaySuspender ds;
1577         _model->clear ();
1578
1579         StripableList s;
1580
1581         RouteList r (*_session->get_routes());
1582         for (RouteList::iterator ri = r.begin(); ri != r.end(); ++ri) {
1583                 s.push_back (*ri);
1584         }
1585
1586         VCAList v (_session->vca_manager().vcas());
1587         for (VCAList::iterator vi = v.begin(); vi != v.end(); ++vi) {
1588                 s.push_back (*vi);
1589         }
1590
1591         _editor->add_stripables (s);
1592
1593         sync_treeview_from_presentation_info (Properties::order);
1594 }
1595
1596 void
1597 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
1598                                              int x, int y,
1599                                              const SelectionData& data,
1600                                              guint info, guint time)
1601 {
1602         if (data.get_target() == "GTK_TREE_MODEL_ROW") {
1603                 _display.on_drag_data_received (context, x, y, data, info, time);
1604                 return;
1605         }
1606
1607         context->drag_finish (true, false, time);
1608 }
1609
1610 struct ViewStripable {
1611         TimeAxisView* tav;
1612         boost::shared_ptr<Stripable> stripable;
1613
1614         ViewStripable (TimeAxisView* t, boost::shared_ptr<Stripable> s)
1615                 : tav (t), stripable (s) {}
1616 };
1617
1618 void
1619 EditorRoutes::move_selected_tracks (bool up)
1620 {
1621         TimeAxisView* scroll_to = 0;
1622         StripableList sl;
1623         _session->get_stripables (sl);
1624
1625         if (sl.size() < 2) {
1626                 /* nope */
1627                 return;
1628         }
1629
1630         sl.sort (Stripable::PresentationOrderSorter());
1631
1632         std::list<ViewStripable> view_stripables;
1633
1634         /* build a list that includes time axis view information */
1635
1636         for (StripableList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
1637                 TimeAxisView* tv = _editor->time_axis_view_from_stripable (*sli);
1638                 view_stripables.push_back (ViewStripable (tv, *sli));
1639         }
1640
1641         /* for each selected stripable, move it above or below the adjacent
1642          * stripable that has a time-axis view representation here. If there's
1643          * no such representation, then
1644          */
1645
1646         list<ViewStripable>::iterator unselected_neighbour;
1647         list<ViewStripable>::iterator vsi;
1648
1649         {
1650                 PresentationInfo::ChangeSuspender cs;
1651
1652                 if (up) {
1653                         unselected_neighbour = view_stripables.end ();
1654                         vsi = view_stripables.begin();
1655
1656                         while (vsi != view_stripables.end()) {
1657
1658                                 if (vsi->stripable->is_selected()) {
1659
1660                                         if (unselected_neighbour != view_stripables.end()) {
1661
1662                                                 PresentationInfo::order_t unselected_neighbour_order = unselected_neighbour->stripable->presentation_info().order();
1663                                                 PresentationInfo::order_t my_order = vsi->stripable->presentation_info().order();
1664
1665                                                 unselected_neighbour->stripable->set_presentation_order (my_order);
1666                                                 vsi->stripable->set_presentation_order (unselected_neighbour_order);
1667
1668                                                 if (!scroll_to) {
1669                                                         scroll_to = vsi->tav;
1670                                                 }
1671                                         }
1672
1673                                 } else {
1674
1675                                         if (vsi->tav) {
1676                                                 unselected_neighbour = vsi;
1677                                         }
1678
1679                                 }
1680
1681                                 ++vsi;
1682                         }
1683
1684                 } else {
1685
1686                         unselected_neighbour = view_stripables.end();
1687                         vsi = unselected_neighbour;
1688
1689                         do {
1690
1691                                 --vsi;
1692
1693                                 if (vsi->stripable->is_selected()) {
1694
1695                                         if (unselected_neighbour != view_stripables.end()) {
1696
1697                                                 PresentationInfo::order_t unselected_neighbour_order = unselected_neighbour->stripable->presentation_info().order();
1698                                                 PresentationInfo::order_t my_order = vsi->stripable->presentation_info().order();
1699
1700                                                 unselected_neighbour->stripable->set_presentation_order (my_order);
1701                                                 vsi->stripable->set_presentation_order (unselected_neighbour_order);
1702
1703                                                 if (!scroll_to) {
1704                                                         scroll_to = vsi->tav;
1705                                                 }
1706                                         }
1707
1708                                 } else {
1709
1710                                         if (vsi->tav) {
1711                                                 unselected_neighbour = vsi;
1712                                         }
1713
1714                                 }
1715
1716                         } while (vsi != view_stripables.begin());
1717                 }
1718         }
1719
1720         if (scroll_to) {
1721                 _editor->ensure_time_axis_view_is_visible (*scroll_to, false);
1722         }
1723 }
1724
1725 void
1726 EditorRoutes::update_input_active_display ()
1727 {
1728         TreeModel::Children rows = _model->children();
1729         TreeModel::Children::iterator i;
1730
1731         for (i = rows.begin(); i != rows.end(); ++i) {
1732                 boost::shared_ptr<Stripable> stripable = (*i)[_columns.stripable];
1733
1734                 if (boost::dynamic_pointer_cast<Track> (stripable)) {
1735                         boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (stripable);
1736
1737                         if (mt) {
1738                                 (*i)[_columns.is_input_active] = mt->input_active();
1739                         }
1740                 }
1741         }
1742 }
1743
1744 void
1745 EditorRoutes::update_rec_display ()
1746 {
1747         if (g_atomic_int_compare_and_exchange (const_cast<gint*>(&_queue_tv_update), 0, 1)) {
1748                 Glib::signal_idle().connect (sigc::mem_fun (*this, &EditorRoutes::idle_update_mute_rec_solo_etc));
1749         }
1750 }
1751
1752 bool
1753 EditorRoutes::idle_update_mute_rec_solo_etc()
1754 {
1755         g_atomic_int_set (const_cast<gint*>(&_queue_tv_update), 0);
1756         TreeModel::Children rows = _model->children();
1757         TreeModel::Children::iterator i;
1758
1759         for (i = rows.begin(); i != rows.end(); ++i) {
1760                 boost::shared_ptr<Stripable> stripable = (*i)[_columns.stripable];
1761                 boost::shared_ptr<Route> route = boost::dynamic_pointer_cast<Route> (stripable);
1762                 (*i)[_columns.mute_state] = RouteUI::mute_active_state (_session, stripable);
1763                 (*i)[_columns.solo_state] = RouteUI::solo_active_state (stripable);
1764                 (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_active_state (stripable) ? 1 : 0;
1765                 (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_active_state (stripable) ? 1 : 0;
1766                 if (route) {
1767                         (*i)[_columns.active] = route->active ();
1768                 } else {
1769                         (*i)[_columns.active] = true;
1770                 }
1771
1772                 boost::shared_ptr<Track> trk (boost::dynamic_pointer_cast<Track>(route));
1773
1774                 if (trk) {
1775                         boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
1776
1777                         if (trk->rec_enable_control()->get_value()) {
1778                                 if (_session->record_status() == Session::Recording) {
1779                                         (*i)[_columns.rec_state] = 1;
1780                                 } else {
1781                                         (*i)[_columns.rec_state] = 2;
1782                                 }
1783                         } else if (mt && mt->step_editing()) {
1784                                 (*i)[_columns.rec_state] = 3;
1785                         } else {
1786                                 (*i)[_columns.rec_state] = 0;
1787                         }
1788
1789                         (*i)[_columns.rec_safe] = trk->rec_safe_control()->get_value();
1790                         (*i)[_columns.name_editable] = !trk->rec_enable_control()->get_value();
1791                 }
1792         }
1793
1794         return false; // do not call again (until needed)
1795 }
1796
1797
1798 void
1799 EditorRoutes::update_mute_display ()
1800 {
1801         if (g_atomic_int_compare_and_exchange (const_cast<gint*>(&_queue_tv_update), 0, 1)) {
1802                 Glib::signal_idle().connect (sigc::mem_fun (*this, &EditorRoutes::idle_update_mute_rec_solo_etc));
1803         }
1804 }
1805
1806 void
1807 EditorRoutes::update_solo_display ()
1808 {
1809         if (g_atomic_int_compare_and_exchange (const_cast<gint*>(&_queue_tv_update), 0, 1)) {
1810                 Glib::signal_idle().connect (sigc::mem_fun (*this, &EditorRoutes::idle_update_mute_rec_solo_etc));
1811         }
1812 }
1813
1814 void
1815 EditorRoutes::update_solo_isolate_display ()
1816 {
1817         if (g_atomic_int_compare_and_exchange (const_cast<gint*>(&_queue_tv_update), 0, 1)) {
1818                 Glib::signal_idle().connect (sigc::mem_fun (*this, &EditorRoutes::idle_update_mute_rec_solo_etc));
1819         }
1820 }
1821
1822 void
1823 EditorRoutes::update_solo_safe_display ()
1824 {
1825         if (g_atomic_int_compare_and_exchange (const_cast<gint*>(&_queue_tv_update), 0, 1)) {
1826                 Glib::signal_idle().connect (sigc::mem_fun (*this, &EditorRoutes::idle_update_mute_rec_solo_etc));
1827         }
1828 }
1829
1830 list<TimeAxisView*>
1831 EditorRoutes::views () const
1832 {
1833         list<TimeAxisView*> v;
1834         for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
1835                 v.push_back ((*i)[_columns.tv]);
1836         }
1837
1838         return v;
1839 }
1840
1841 void
1842 EditorRoutes::clear ()
1843 {
1844         PBD::Unwinder<bool> uw (_ignore_selection_change, true);
1845         _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1846         _model->clear ();
1847         _display.set_model (_model);
1848 }
1849
1850 void
1851 EditorRoutes::name_edit_started (CellEditable* ce, const Glib::ustring&)
1852 {
1853         name_editable = ce;
1854
1855         /* give it a special name */
1856
1857         Gtk::Entry *e = dynamic_cast<Gtk::Entry*> (ce);
1858
1859         if (e) {
1860                 e->set_name (X_("RouteNameEditorEntry"));
1861         }
1862 }
1863
1864 void
1865 EditorRoutes::name_edit (std::string const & path, std::string const & new_text)
1866 {
1867         name_editable = 0;
1868
1869         TreeIter iter = _model->get_iter (path);
1870
1871         if (!iter) {
1872                 return;
1873         }
1874
1875         boost::shared_ptr<Stripable> stripable = (*iter)[_columns.stripable];
1876
1877         if (stripable && stripable->name() != new_text) {
1878                 stripable->set_name (new_text);
1879         }
1880 }
1881
1882 void
1883 EditorRoutes::solo_changed_so_update_mute ()
1884 {
1885         update_mute_display ();
1886 }
1887
1888 void
1889 EditorRoutes::show_tracks_with_regions_at_playhead ()
1890 {
1891         boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
1892
1893         set<TimeAxisView*> show;
1894         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
1895                 TimeAxisView* tav = _editor->time_axis_view_from_stripable (*i);
1896                 if (tav) {
1897                         show.insert (tav);
1898                 }
1899         }
1900
1901         DisplaySuspender ds;
1902
1903         TreeModel::Children rows = _model->children ();
1904         for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
1905                 TimeAxisView* tv = (*i)[_columns.tv];
1906                 bool to_show = (show.find (tv) != show.end());
1907
1908                 tv->set_marked_for_display (to_show);
1909                 (*i)[_columns.visible] = to_show;
1910         }
1911
1912         /* force route order keys catch up with visibility changes
1913          */
1914
1915         sync_presentation_info_from_treeview ();
1916 }
1917
1918 int
1919 EditorRoutes::plugin_setup (boost::shared_ptr<Route> r, boost::shared_ptr<PluginInsert> pi, ARDOUR::Route::PluginSetupOptions flags)
1920 {
1921         PluginSetupDialog psd (r, pi, flags);
1922         int rv = psd.run ();
1923         return rv + (psd.fan_out() ? 4 : 0);
1924 }