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