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