when a Route is removed, don't bother triggering a sync-presentation-info-from-treevi...
[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                 cerr << "Should ignore model/selection change\n";
840                 _display.set_model (_model);
841         }
842
843         /* now update route order keys from the treeview/track display order */
844
845         if (!from_scratch) {
846                 sync_presentation_info_from_treeview ();
847         }
848
849         redisplay ();
850 }
851
852 void
853 EditorRoutes::handle_gui_changes (string const & what, void*)
854 {
855         if (_adding_routes) {
856                 return;
857         }
858
859         if (what == "track_height") {
860                 /* Optional :make tracks change height while it happens, instead
861                    of on first-idle
862                 */
863                 redisplay ();
864         }
865
866         if (what == "visible_tracks") {
867                 redisplay ();
868         }
869 }
870
871 void
872 EditorRoutes::route_removed (TimeAxisView *tv)
873 {
874         ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed, tv)
875
876         TreeModel::Children rows = _model->children();
877         TreeModel::Children::iterator ri;
878
879         PBD::Unwinder<bool> uw (_ignore_selection_change, true);
880
881         for (ri = rows.begin(); ri != rows.end(); ++ri) {
882                 if ((*ri)[_columns.tv] == tv) {
883                         PBD::Unwinder<bool> uw (_route_deletion_in_progress, true);
884                         _model->erase (ri);
885                         break;
886                 }
887         }
888 }
889
890 void
891 EditorRoutes::route_property_changed (const PropertyChange& what_changed, boost::weak_ptr<Stripable> s)
892 {
893         if (!what_changed.contains (ARDOUR::Properties::hidden) && !what_changed.contains (ARDOUR::Properties::name)) {
894                 return;
895         }
896
897         if (_adding_routes) {
898                 return;
899         }
900
901         boost::shared_ptr<Stripable> stripable = s.lock ();
902
903         if (!stripable) {
904                 return;
905         }
906
907         TreeModel::Children rows = _model->children();
908         TreeModel::Children::iterator i;
909
910         for (i = rows.begin(); i != rows.end(); ++i) {
911
912                 boost::shared_ptr<Stripable> ss = (*i)[_columns.stripable];
913
914                 if (ss == stripable) {
915
916                         if (what_changed.contains (ARDOUR::Properties::name)) {
917                                 (*i)[_columns.text] = stripable->name();
918                                 break;
919                         }
920
921                         if (what_changed.contains (ARDOUR::Properties::hidden)) {
922                                 (*i)[_columns.visible] = !stripable->presentation_info().hidden();
923                                 redisplay ();
924
925                         }
926
927                         break;
928                 }
929         }
930 }
931
932 void
933 EditorRoutes::update_active_display ()
934 {
935         if (g_atomic_int_compare_and_exchange (const_cast<gint*>(&_queue_tv_update), 0, 1)) {
936                 Glib::signal_idle().connect (sigc::mem_fun (*this, &EditorRoutes::idle_update_mute_rec_solo_etc));
937         }
938 }
939
940 void
941 EditorRoutes::update_visibility ()
942 {
943         TreeModel::Children rows = _model->children();
944         TreeModel::Children::iterator i;
945
946         DisplaySuspender ds;
947
948         for (i = rows.begin(); i != rows.end(); ++i) {
949                 TimeAxisView *tv = (*i)[_columns.tv];
950                 (*i)[_columns.visible] = tv->marked_for_display ();
951         }
952
953         /* force route order keys catch up with visibility changes
954          */
955
956         sync_presentation_info_from_treeview ();
957 }
958
959 void
960 EditorRoutes::hide_track_in_display (TimeAxisView& tv)
961 {
962         TreeModel::Children rows = _model->children();
963         TreeModel::Children::iterator i;
964
965         for (i = rows.begin(); i != rows.end(); ++i) {
966                 if ((*i)[_columns.tv] == &tv) {
967                         tv.set_marked_for_display (false);
968                         (*i)[_columns.visible] = false;
969                         redisplay ();
970                         break;
971                 }
972         }
973 }
974
975 void
976 EditorRoutes::show_track_in_display (TimeAxisView& tv)
977 {
978         TreeModel::Children rows = _model->children();
979         TreeModel::Children::iterator i;
980
981
982         for (i = rows.begin(); i != rows.end(); ++i) {
983                 if ((*i)[_columns.tv] == &tv) {
984                         tv.set_marked_for_display (true);
985                         (*i)[_columns.visible] = true;
986                         redisplay ();
987                         break;
988                 }
989         }
990 }
991
992 void
993 EditorRoutes::sync_presentation_info_from_treeview ()
994 {
995         if (_ignore_reorder || !_session || _session->deletion_in_progress()) {
996                 return;
997         }
998
999         TreeModel::Children rows = _model->children();
1000
1001         if (rows.empty()) {
1002                 return;
1003         }
1004
1005         DEBUG_TRACE (DEBUG::OrderKeys, "editor sync presentation info from treeview\n");
1006
1007         TreeModel::Children::iterator ri;
1008         bool change = false;
1009         PresentationInfo::order_t order = 0;
1010         bool master_is_first = false;
1011         uint32_t count = 0;
1012
1013         OrderingKeys sorted;
1014         const size_t cmp_max = rows.size ();
1015
1016         PresentationInfo::ChangeSuspender cs;
1017
1018         // special case master if it's got PI order 0 lets keep it there
1019         if (_session->master_out() && (_session->master_out()->presentation_info().order() == 0)) {
1020                 order++;
1021                 master_is_first = true;
1022         }
1023
1024         for (ri = rows.begin(); ri != rows.end(); ++ri) {
1025
1026                 boost::shared_ptr<Stripable> stripable = (*ri)[_columns.stripable];
1027                 bool visible = (*ri)[_columns.visible];
1028
1029                 /* Monitor and Auditioner do not get their presentation
1030                  * info reset here.
1031                  */
1032
1033                 if (stripable->is_monitor() || stripable->is_auditioner()) {
1034                         continue;
1035                 }
1036
1037                 stripable->presentation_info().set_hidden (!visible);
1038
1039                 /* special case master if it's got PI order 0 lets keep it there
1040                  * but still allow master to move if first non-master route has
1041                  * presentation order 1
1042                  */
1043                 if ((count == 0) && master_is_first && (stripable->presentation_info().order()  == 1)) {
1044                         master_is_first = false; // someone has moved master
1045                         order = 0;
1046                 }
1047
1048                 if (stripable->is_master() && master_is_first) {
1049                         if (count) {
1050                                 continue;
1051                         } else {
1052                                 count++;
1053                                 continue;
1054                         }
1055                 }
1056
1057                 if (order != stripable->presentation_info().order()) {
1058                         stripable->set_presentation_order (order);
1059                         change = true;
1060                 }
1061
1062                 sorted.push_back (OrderKeys (order, stripable, cmp_max));
1063
1064                 ++order;
1065                 ++count;
1066         }
1067
1068         if (!change) {
1069                 // VCA (and Mixbus) special cases according to SortByNewDisplayOrder
1070                 uint32_t n = 0;
1071                 SortByNewDisplayOrder cmp;
1072                 sort (sorted.begin(), sorted.end(), cmp);
1073                 for (OrderingKeys::iterator sr = sorted.begin(); sr != sorted.end(); ++sr, ++n) {
1074                         if (sr->old_display_order != n) {
1075                                 change = true;
1076                         }
1077                 }
1078                 if (change) {
1079                         n = 0;
1080                         for (OrderingKeys::iterator sr = sorted.begin(); sr != sorted.end(); ++sr, ++n) {
1081                                 if (sr->stripable->presentation_info().order() != n) {
1082                                         sr->stripable->set_presentation_order (n);
1083                                 }
1084                         }
1085                 }
1086         }
1087 }
1088
1089 void
1090 EditorRoutes::sync_treeview_from_presentation_info (PropertyChange const & what_changed)
1091 {
1092         /* Some route order key(s) have been changed, make sure that
1093            we update out tree/list model and GUI to reflect the change.
1094         */
1095
1096         if (_ignore_reorder || !_session || _session->deletion_in_progress()) {
1097                 return;
1098         }
1099
1100         DEBUG_TRACE (DEBUG::OrderKeys, "editor sync model from presentation info.\n");
1101
1102         PropertyChange hidden_or_order;
1103         hidden_or_order.add (Properties::hidden);
1104         hidden_or_order.add (Properties::order);
1105
1106         TreeModel::Children rows = _model->children();
1107
1108         if (what_changed.contains (hidden_or_order)) {
1109
1110                 vector<int> neworder;
1111                 uint32_t old_order = 0;
1112                 bool changed = false;
1113
1114                 if (rows.empty()) {
1115                         return;
1116                 }
1117
1118                 OrderingKeys sorted;
1119                 const size_t cmp_max = rows.size ();
1120
1121                 for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++old_order) {
1122                         boost::shared_ptr<Stripable> stripable = (*ri)[_columns.stripable];
1123                         /* use global order */
1124                         sorted.push_back (OrderKeys (old_order, stripable, cmp_max));
1125                 }
1126
1127                 SortByNewDisplayOrder cmp;
1128
1129                 sort (sorted.begin(), sorted.end(), cmp);
1130                 neworder.assign (sorted.size(), 0);
1131
1132                 uint32_t n = 0;
1133
1134                 for (OrderingKeys::iterator sr = sorted.begin(); sr != sorted.end(); ++sr, ++n) {
1135
1136                         neworder[n] = sr->old_display_order;
1137
1138                         if (sr->old_display_order != n) {
1139                                 changed = true;
1140                         }
1141                 }
1142
1143                 if (changed) {
1144                         Unwinder<bool> uw (_ignore_reorder, true);
1145                         /* prevent traverse_cells: assertion 'row_path != NULL'
1146                          * in case of DnD re-order: row-removed + row-inserted.
1147                          *
1148                          * The rows (stripables) are not actually removed from the model,
1149                          * but only from the display in the DnDTreeView.
1150                          * ->reorder() will fail to find the row_path.
1151                          * (re-order drag -> remove row -> sync PI from TV -> notify -> sync TV from PI -> crash)
1152                          */
1153                         Unwinder<bool> uw2 (_ignore_selection_change, true);
1154
1155                         _display.unset_model();
1156                         _model->reorder (neworder);
1157                         _display.set_model (_model);
1158                 }
1159         }
1160
1161         if (what_changed.contains (Properties::selected)) {
1162
1163                 /* by the time this is invoked, the GUI Selection model has
1164                  * already updated itself.
1165                  */
1166
1167                 TrackViewList tvl;
1168                 PBD::Unwinder<bool> uw (_ignore_selection_change, true);
1169
1170                 /* set the treeview model selection state */
1171
1172                 for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri) {
1173                         boost::shared_ptr<Stripable> stripable = (*ri)[_columns.stripable];
1174                         if (stripable && stripable->is_selected()) {
1175                                 TimeAxisView* tav = (*ri)[_columns.tv];
1176                                 if (tav) {
1177                                         tvl.push_back (tav);
1178                                 }
1179                                 _display.get_selection()->select (*ri);
1180                         } else {
1181                                 _display.get_selection()->unselect (*ri);
1182                         }
1183                 }
1184         }
1185
1186         redisplay ();
1187 }
1188
1189 void
1190 EditorRoutes::hide_all_tracks (bool /*with_select*/)
1191 {
1192         TreeModel::Children rows = _model->children();
1193         TreeModel::Children::iterator i;
1194
1195         DisplaySuspender ds;
1196
1197         for (i = rows.begin(); i != rows.end(); ++i) {
1198
1199                 TreeModel::Row row = (*i);
1200                 TimeAxisView *tv = row[_columns.tv];
1201
1202                 if (tv == 0) {
1203                         continue;
1204                 }
1205
1206                 row[_columns.visible] = false;
1207         }
1208 }
1209
1210 void
1211 EditorRoutes::set_all_tracks_visibility (bool yn)
1212 {
1213         TreeModel::Children rows = _model->children();
1214         TreeModel::Children::iterator i;
1215
1216         DisplaySuspender ds;
1217
1218         for (i = rows.begin(); i != rows.end(); ++i) {
1219
1220                 TreeModel::Row row = (*i);
1221                 TimeAxisView* tv = row[_columns.tv];
1222
1223                 if (tv == 0) {
1224                         continue;
1225                 }
1226
1227                 tv->set_marked_for_display (yn);
1228                 (*i)[_columns.visible] = yn;
1229         }
1230
1231         /* force route order keys catch up with visibility changes
1232          */
1233
1234         sync_presentation_info_from_treeview ();
1235 }
1236
1237 void
1238 EditorRoutes::set_all_audio_midi_visibility (int tracks, bool yn)
1239 {
1240         TreeModel::Children rows = _model->children();
1241         TreeModel::Children::iterator i;
1242
1243         DisplaySuspender ds;
1244
1245         for (i = rows.begin(); i != rows.end(); ++i) {
1246
1247                 TreeModel::Row row = (*i);
1248                 TimeAxisView* tv = row[_columns.tv];
1249
1250                 AudioTimeAxisView* atv;
1251                 MidiTimeAxisView* mtv;
1252
1253                 if (tv == 0) {
1254                         continue;
1255                 }
1256
1257                 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
1258                         switch (tracks) {
1259                         case 0:
1260                                 atv->set_marked_for_display (yn);
1261                                 (*i)[_columns.visible] = yn;
1262                                 break;
1263
1264                         case 1:
1265                                 if (atv->is_audio_track()) {
1266                                         atv->set_marked_for_display (yn);
1267                                         (*i)[_columns.visible] = yn;
1268                                 }
1269                                 break;
1270
1271                         case 2:
1272                                 if (!atv->is_audio_track()) {
1273                                         atv->set_marked_for_display (yn);
1274                                         (*i)[_columns.visible] = yn;
1275                                 }
1276                                 break;
1277                         }
1278                 }
1279                 else if ((mtv = dynamic_cast<MidiTimeAxisView*>(tv)) != 0) {
1280                         switch (tracks) {
1281                         case 0:
1282                                 mtv->set_marked_for_display (yn);
1283                                 (*i)[_columns.visible] = yn;
1284                                 break;
1285
1286                         case 3:
1287                                 if (mtv->is_midi_track()) {
1288                                         mtv->set_marked_for_display (yn);
1289                                         (*i)[_columns.visible] = yn;
1290                                 }
1291                                 break;
1292                         }
1293                 }
1294         }
1295
1296         /* force route order keys catch up with visibility changes
1297          */
1298
1299         sync_presentation_info_from_treeview ();
1300 }
1301
1302 void
1303 EditorRoutes::hide_all_routes ()
1304 {
1305         set_all_tracks_visibility (false);
1306 }
1307
1308 void
1309 EditorRoutes::show_all_routes ()
1310 {
1311         set_all_tracks_visibility (true);
1312 }
1313
1314 void
1315 EditorRoutes::show_all_audiotracks()
1316 {
1317         set_all_audio_midi_visibility (1, true);
1318 }
1319 void
1320 EditorRoutes::hide_all_audiotracks ()
1321 {
1322         set_all_audio_midi_visibility (1, false);
1323 }
1324
1325 void
1326 EditorRoutes::show_all_audiobus ()
1327 {
1328         set_all_audio_midi_visibility (2, true);
1329 }
1330 void
1331 EditorRoutes::hide_all_audiobus ()
1332 {
1333         set_all_audio_midi_visibility (2, false);
1334 }
1335
1336 void
1337 EditorRoutes::show_all_miditracks()
1338 {
1339         set_all_audio_midi_visibility (3, true);
1340 }
1341 void
1342 EditorRoutes::hide_all_miditracks ()
1343 {
1344         set_all_audio_midi_visibility (3, false);
1345 }
1346
1347 bool
1348 EditorRoutes::key_press (GdkEventKey* ev)
1349 {
1350         TreeViewColumn *col;
1351         boost::shared_ptr<RouteList> rl (new RouteList);
1352         TreePath path;
1353
1354         switch (ev->keyval) {
1355                 case GDK_Tab:
1356                 case GDK_ISO_Left_Tab:
1357
1358                         /* If we appear to be editing something, leave that cleanly and appropriately. */
1359                         if (name_editable) {
1360                                 name_editable->editing_done ();
1361                                 name_editable = 0;
1362                         }
1363
1364                         col = _display.get_column (_name_column); // select&focus on name column
1365
1366                         if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
1367                                 treeview_select_previous (_display, _model, col);
1368                         } else {
1369                                 treeview_select_next (_display, _model, col);
1370                         }
1371
1372                         return true;
1373                         break;
1374
1375                 case 'm':
1376                         if (get_relevant_routes (rl)) {
1377                                 _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), rl->front()->muted() ? 0.0 : 1.0, Controllable::NoGroup);
1378                         }
1379                         return true;
1380                         break;
1381
1382                 case 's':
1383                         if (get_relevant_routes (rl)) {
1384                                 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_control), rl->front()->self_soloed() ? 0.0 : 1.0, Controllable::NoGroup);
1385                         }
1386                         return true;
1387                         break;
1388
1389                 case 'r':
1390                         if (get_relevant_routes (rl)) {
1391                                 for (RouteList::const_iterator r = rl->begin(); r != rl->end(); ++r) {
1392                                         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> (*r);
1393                                         if (t) {
1394                                                 _session->set_controls (route_list_to_control_list (rl, &Stripable::rec_enable_control), !t->rec_enable_control()->get_value(), Controllable::NoGroup);
1395                                                 break;
1396                                         }
1397                                 }
1398                         }
1399                         break;
1400
1401                 default:
1402                         break;
1403         }
1404
1405         return false;
1406 }
1407
1408 bool
1409 EditorRoutes::get_relevant_routes (boost::shared_ptr<RouteList> rl)
1410 {
1411         TimeAxisView* tv;
1412         RouteTimeAxisView* rtv;
1413         RefPtr<TreeSelection> selection = _display.get_selection();
1414         TreePath path;
1415         TreeIter iter;
1416
1417         if (selection->count_selected_rows() != 0) {
1418
1419                 /* use selection */
1420
1421                 RefPtr<TreeModel> tm = RefPtr<TreeModel>::cast_dynamic (_model);
1422                 iter = selection->get_selected (tm);
1423
1424         } else {
1425                 /* use mouse pointer */
1426
1427                 int x, y;
1428                 int bx, by;
1429
1430                 _display.get_pointer (x, y);
1431                 _display.convert_widget_to_bin_window_coords (x, y, bx, by);
1432
1433                 if (_display.get_path_at_pos (bx, by, path)) {
1434                         iter = _model->get_iter (path);
1435                 }
1436         }
1437
1438         if (iter) {
1439                 tv = (*iter)[_columns.tv];
1440                 if (tv) {
1441                         rtv = dynamic_cast<RouteTimeAxisView*>(tv);
1442                         if (rtv) {
1443                                 rl->push_back (rtv->route());
1444                         }
1445                 }
1446         }
1447
1448         return !rl->empty();
1449 }
1450
1451 bool
1452 EditorRoutes::button_press (GdkEventButton* ev)
1453 {
1454         if (Keyboard::is_context_menu_event (ev)) {
1455                 if (_menu == 0) {
1456                         build_menu ();
1457                 }
1458                 _menu->popup (ev->button, ev->time);
1459                 return true;
1460         }
1461
1462         TreeModel::Path path;
1463         TreeViewColumn *tvc;
1464         int cell_x;
1465         int cell_y;
1466
1467         if (!_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y)) {
1468                 /* cancel selection */
1469                 _display.get_selection()->unselect_all ();
1470                 /* end any editing by grabbing focus */
1471                 _display.grab_focus ();
1472                 return true;
1473         }
1474
1475         //Scroll editor canvas to selected track
1476         if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1477
1478                 Gtk::TreeModel::Row row = *_model->get_iter (path);
1479                 TimeAxisView *tv = row[_columns.tv];
1480
1481                 if (tv) {
1482                         _editor->ensure_time_axis_view_is_visible (*tv, true);
1483                 }
1484         }
1485
1486         return false;
1487 }
1488
1489 void
1490 EditorRoutes::selection_changed ()
1491 {
1492         if (_ignore_selection_change) {
1493                 return;
1494         }
1495
1496         _editor->begin_reversible_selection_op (X_("Select Track from Route List"));
1497
1498         if (_display.get_selection()->count_selected_rows() > 0) {
1499
1500                 TreeIter iter;
1501                 TreeView::Selection::ListHandle_Path rows = _display.get_selection()->get_selected_rows ();
1502                 TrackViewList selected;
1503
1504                 for (TreeView::Selection::ListHandle_Path::iterator i = rows.begin(); i != rows.end(); ++i) {
1505
1506                         if ((iter = _model->get_iter (*i))) {
1507
1508                                 TimeAxisView* tv = (*iter)[_columns.tv];
1509                                 selected.push_back (tv);
1510                         }
1511
1512                 }
1513
1514                 _editor->get_selection().set (selected);
1515                 _editor->ensure_time_axis_view_is_visible (*(selected.front()), true);
1516
1517         } else {
1518                 _editor->get_selection().clear_tracks ();
1519         }
1520
1521         _editor->commit_reversible_selection_op ();
1522 }
1523
1524 bool
1525 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const& model, TreeModel::Path const& path, bool /*selected*/)
1526 {
1527         if (selection_countdown) {
1528                 if (--selection_countdown == 0) {
1529                         return true;
1530                 } else {
1531                         /* no selection yet ... */
1532                         return false;
1533                 }
1534         }
1535
1536         TreeModel::iterator iter = model->get_iter (path);
1537         if (iter) {
1538                 boost::shared_ptr<Stripable> stripable = (*iter)[_columns.stripable];
1539                 if (boost::dynamic_pointer_cast<VCA> (stripable)) {
1540                         return false;
1541                 }
1542         }
1543
1544         return true;
1545 }
1546
1547 struct PresentationInfoRouteSorter
1548 {
1549         bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1550                 if (a->is_master()) {
1551                         /* master before everything else */
1552                         return true;
1553                 } else if (b->is_master()) {
1554                         /* everything else before master */
1555                         return false;
1556                 }
1557                 return a->presentation_info().order () < b->presentation_info().order ();
1558         }
1559 };
1560
1561 struct PresentationInfoVCASorter
1562 {
1563         bool operator() (boost::shared_ptr<VCA> a, boost::shared_ptr<VCA> b) {
1564                 return a->presentation_info().order () < b->presentation_info().order ();
1565         }
1566 };
1567
1568 void
1569 EditorRoutes::initial_display ()
1570 {
1571
1572         if (!_session) {
1573                 _model->clear ();
1574                 return;
1575         }
1576
1577         DisplaySuspender ds;
1578         _model->clear ();
1579
1580         StripableList s;
1581
1582         RouteList r (*_session->get_routes());
1583         for (RouteList::iterator ri = r.begin(); ri != r.end(); ++ri) {
1584                 s.push_back (*ri);
1585         }
1586
1587         VCAList v (_session->vca_manager().vcas());
1588         for (VCAList::iterator vi = v.begin(); vi != v.end(); ++vi) {
1589                 s.push_back (*vi);
1590         }
1591
1592         _editor->add_stripables (s);
1593
1594         sync_treeview_from_presentation_info (Properties::order);
1595 }
1596
1597 void
1598 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
1599                                              int x, int y,
1600                                              const SelectionData& data,
1601                                              guint info, guint time)
1602 {
1603         if (data.get_target() == "GTK_TREE_MODEL_ROW") {
1604                 _display.on_drag_data_received (context, x, y, data, info, time);
1605                 return;
1606         }
1607
1608         context->drag_finish (true, false, time);
1609 }
1610
1611 struct ViewStripable {
1612         TimeAxisView* tav;
1613         boost::shared_ptr<Stripable> stripable;
1614
1615         ViewStripable (TimeAxisView* t, boost::shared_ptr<Stripable> s)
1616                 : tav (t), stripable (s) {}
1617 };
1618
1619 void
1620 EditorRoutes::move_selected_tracks (bool up)
1621 {
1622         TimeAxisView* scroll_to = 0;
1623         StripableList sl;
1624         _session->get_stripables (sl);
1625
1626         if (sl.size() < 2) {
1627                 /* nope */
1628                 return;
1629         }
1630
1631         sl.sort (Stripable::PresentationOrderSorter());
1632
1633         std::list<ViewStripable> view_stripables;
1634
1635         /* build a list that includes time axis view information */
1636
1637         for (StripableList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
1638                 TimeAxisView* tv = _editor->time_axis_view_from_stripable (*sli);
1639                 view_stripables.push_back (ViewStripable (tv, *sli));
1640         }
1641
1642         /* for each selected stripable, move it above or below the adjacent
1643          * stripable that has a time-axis view representation here. If there's
1644          * no such representation, then
1645          */
1646
1647         list<ViewStripable>::iterator unselected_neighbour;
1648         list<ViewStripable>::iterator vsi;
1649
1650         {
1651                 PresentationInfo::ChangeSuspender cs;
1652
1653                 if (up) {
1654                         unselected_neighbour = view_stripables.end ();
1655                         vsi = view_stripables.begin();
1656
1657                         while (vsi != view_stripables.end()) {
1658
1659                                 if (vsi->stripable->is_selected()) {
1660
1661                                         if (unselected_neighbour != view_stripables.end()) {
1662
1663                                                 PresentationInfo::order_t unselected_neighbour_order = unselected_neighbour->stripable->presentation_info().order();
1664                                                 PresentationInfo::order_t my_order = vsi->stripable->presentation_info().order();
1665
1666                                                 unselected_neighbour->stripable->set_presentation_order (my_order);
1667                                                 vsi->stripable->set_presentation_order (unselected_neighbour_order);
1668
1669                                                 if (!scroll_to) {
1670                                                         scroll_to = vsi->tav;
1671                                                 }
1672                                         }
1673
1674                                 } else {
1675
1676                                         if (vsi->tav) {
1677                                                 unselected_neighbour = vsi;
1678                                         }
1679
1680                                 }
1681
1682                                 ++vsi;
1683                         }
1684
1685                 } else {
1686
1687                         unselected_neighbour = view_stripables.end();
1688                         vsi = unselected_neighbour;
1689
1690                         do {
1691
1692                                 --vsi;
1693
1694                                 if (vsi->stripable->is_selected()) {
1695
1696                                         if (unselected_neighbour != view_stripables.end()) {
1697
1698                                                 PresentationInfo::order_t unselected_neighbour_order = unselected_neighbour->stripable->presentation_info().order();
1699                                                 PresentationInfo::order_t my_order = vsi->stripable->presentation_info().order();
1700
1701                                                 unselected_neighbour->stripable->set_presentation_order (my_order);
1702                                                 vsi->stripable->set_presentation_order (unselected_neighbour_order);
1703
1704                                                 if (!scroll_to) {
1705                                                         scroll_to = vsi->tav;
1706                                                 }
1707                                         }
1708
1709                                 } else {
1710
1711                                         if (vsi->tav) {
1712                                                 unselected_neighbour = vsi;
1713                                         }
1714
1715                                 }
1716
1717                         } while (vsi != view_stripables.begin());
1718                 }
1719         }
1720
1721         if (scroll_to) {
1722                 _editor->ensure_time_axis_view_is_visible (*scroll_to, false);
1723         }
1724 }
1725
1726 void
1727 EditorRoutes::update_input_active_display ()
1728 {
1729         TreeModel::Children rows = _model->children();
1730         TreeModel::Children::iterator i;
1731
1732         for (i = rows.begin(); i != rows.end(); ++i) {
1733                 boost::shared_ptr<Stripable> stripable = (*i)[_columns.stripable];
1734
1735                 if (boost::dynamic_pointer_cast<Track> (stripable)) {
1736                         boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (stripable);
1737
1738                         if (mt) {
1739                                 (*i)[_columns.is_input_active] = mt->input_active();
1740                         }
1741                 }
1742         }
1743 }
1744
1745 void
1746 EditorRoutes::update_rec_display ()
1747 {
1748         if (g_atomic_int_compare_and_exchange (const_cast<gint*>(&_queue_tv_update), 0, 1)) {
1749                 Glib::signal_idle().connect (sigc::mem_fun (*this, &EditorRoutes::idle_update_mute_rec_solo_etc));
1750         }
1751 }
1752
1753 bool
1754 EditorRoutes::idle_update_mute_rec_solo_etc()
1755 {
1756         g_atomic_int_set (const_cast<gint*>(&_queue_tv_update), 0);
1757         TreeModel::Children rows = _model->children();
1758         TreeModel::Children::iterator i;
1759
1760         for (i = rows.begin(); i != rows.end(); ++i) {
1761                 boost::shared_ptr<Stripable> stripable = (*i)[_columns.stripable];
1762                 boost::shared_ptr<Route> route = boost::dynamic_pointer_cast<Route> (stripable);
1763                 (*i)[_columns.mute_state] = RouteUI::mute_active_state (_session, stripable);
1764                 (*i)[_columns.solo_state] = RouteUI::solo_active_state (stripable);
1765                 (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_active_state (stripable) ? 1 : 0;
1766                 (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_active_state (stripable) ? 1 : 0;
1767                 if (route) {
1768                         (*i)[_columns.active] = route->active ();
1769                 } else {
1770                         (*i)[_columns.active] = true;
1771                 }
1772
1773                 boost::shared_ptr<Track> trk (boost::dynamic_pointer_cast<Track>(route));
1774
1775                 if (trk) {
1776                         boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
1777
1778                         if (trk->rec_enable_control()->get_value()) {
1779                                 if (_session->record_status() == Session::Recording) {
1780                                         (*i)[_columns.rec_state] = 1;
1781                                 } else {
1782                                         (*i)[_columns.rec_state] = 2;
1783                                 }
1784                         } else if (mt && mt->step_editing()) {
1785                                 (*i)[_columns.rec_state] = 3;
1786                         } else {
1787                                 (*i)[_columns.rec_state] = 0;
1788                         }
1789
1790                         (*i)[_columns.rec_safe] = trk->rec_safe_control()->get_value();
1791                         (*i)[_columns.name_editable] = !trk->rec_enable_control()->get_value();
1792                 }
1793         }
1794
1795         return false; // do not call again (until needed)
1796 }
1797
1798
1799 void
1800 EditorRoutes::update_mute_display ()
1801 {
1802         if (g_atomic_int_compare_and_exchange (const_cast<gint*>(&_queue_tv_update), 0, 1)) {
1803                 Glib::signal_idle().connect (sigc::mem_fun (*this, &EditorRoutes::idle_update_mute_rec_solo_etc));
1804         }
1805 }
1806
1807 void
1808 EditorRoutes::update_solo_display ()
1809 {
1810         if (g_atomic_int_compare_and_exchange (const_cast<gint*>(&_queue_tv_update), 0, 1)) {
1811                 Glib::signal_idle().connect (sigc::mem_fun (*this, &EditorRoutes::idle_update_mute_rec_solo_etc));
1812         }
1813 }
1814
1815 void
1816 EditorRoutes::update_solo_isolate_display ()
1817 {
1818         if (g_atomic_int_compare_and_exchange (const_cast<gint*>(&_queue_tv_update), 0, 1)) {
1819                 Glib::signal_idle().connect (sigc::mem_fun (*this, &EditorRoutes::idle_update_mute_rec_solo_etc));
1820         }
1821 }
1822
1823 void
1824 EditorRoutes::update_solo_safe_display ()
1825 {
1826         if (g_atomic_int_compare_and_exchange (const_cast<gint*>(&_queue_tv_update), 0, 1)) {
1827                 Glib::signal_idle().connect (sigc::mem_fun (*this, &EditorRoutes::idle_update_mute_rec_solo_etc));
1828         }
1829 }
1830
1831 list<TimeAxisView*>
1832 EditorRoutes::views () const
1833 {
1834         list<TimeAxisView*> v;
1835         for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
1836                 v.push_back ((*i)[_columns.tv]);
1837         }
1838
1839         return v;
1840 }
1841
1842 void
1843 EditorRoutes::clear ()
1844 {
1845         PBD::Unwinder<bool> uw (_ignore_selection_change, true);
1846         _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1847         _model->clear ();
1848         _display.set_model (_model);
1849 }
1850
1851 void
1852 EditorRoutes::name_edit_started (CellEditable* ce, const Glib::ustring&)
1853 {
1854         name_editable = ce;
1855
1856         /* give it a special name */
1857
1858         Gtk::Entry *e = dynamic_cast<Gtk::Entry*> (ce);
1859
1860         if (e) {
1861                 e->set_name (X_("RouteNameEditorEntry"));
1862         }
1863 }
1864
1865 void
1866 EditorRoutes::name_edit (std::string const & path, std::string const & new_text)
1867 {
1868         name_editable = 0;
1869
1870         TreeIter iter = _model->get_iter (path);
1871
1872         if (!iter) {
1873                 return;
1874         }
1875
1876         boost::shared_ptr<Stripable> stripable = (*iter)[_columns.stripable];
1877
1878         if (stripable && stripable->name() != new_text) {
1879                 stripable->set_name (new_text);
1880         }
1881 }
1882
1883 void
1884 EditorRoutes::solo_changed_so_update_mute ()
1885 {
1886         update_mute_display ();
1887 }
1888
1889 void
1890 EditorRoutes::show_tracks_with_regions_at_playhead ()
1891 {
1892         boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
1893
1894         set<TimeAxisView*> show;
1895         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
1896                 TimeAxisView* tav = _editor->time_axis_view_from_stripable (*i);
1897                 if (tav) {
1898                         show.insert (tav);
1899                 }
1900         }
1901
1902         DisplaySuspender ds;
1903
1904         TreeModel::Children rows = _model->children ();
1905         for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
1906                 TimeAxisView* tv = (*i)[_columns.tv];
1907                 bool to_show = (show.find (tv) != show.end());
1908
1909                 tv->set_marked_for_display (to_show);
1910                 (*i)[_columns.visible] = to_show;
1911         }
1912
1913         /* force route order keys catch up with visibility changes
1914          */
1915
1916         sync_presentation_info_from_treeview ();
1917 }
1918
1919 int
1920 EditorRoutes::plugin_setup (boost::shared_ptr<Route> r, boost::shared_ptr<PluginInsert> pi, ARDOUR::Route::PluginSetupOptions flags)
1921 {
1922         PluginSetupDialog psd (r, pi, flags);
1923         int rv = psd.run ();
1924         return rv + (psd.fan_out() ? 4 : 0);
1925 }