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