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