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