Merge branch 'master' into windows+cc
[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
539         if ((_editor->vertical_adjustment.get_value() + _editor->_visible_canvas_height) > _editor->vertical_adjustment.get_upper()) {
540                 /*
541                    We're increasing the size of the canvas while the bottom is visible.
542                    We scroll down to keep in step with the controls layout.
543                 */
544                 _editor->vertical_adjustment.set_value (_editor->_full_canvas_height - _editor->_visible_canvas_height);
545         }
546 }
547
548 void
549 EditorRoutes::route_deleted (Gtk::TreeModel::Path const &)
550 {
551         /* this happens as the second step of a DnD within the treeview as well
552            as when a row/route is actually deleted.
553         */
554         DEBUG_TRACE (DEBUG::OrderKeys, "editor routes treeview row deleted\n");
555         sync_order_keys_from_treeview ();
556 }
557
558 void
559 EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
560 {
561         DEBUG_TRACE (DEBUG::OrderKeys, "editor routes treeview reordered\n");
562         sync_order_keys_from_treeview ();
563 }
564
565 void
566 EditorRoutes::visible_changed (std::string const & path)
567 {
568         if (_session && _session->deletion_in_progress()) {
569                 return;
570         }
571
572         TreeIter iter;
573
574         if ((iter = _model->get_iter (path))) {
575                 TimeAxisView* tv = (*iter)[_columns.tv];
576                 if (tv) {
577                         bool visible = (*iter)[_columns.visible];
578
579                         if (tv->set_marked_for_display (!visible)) {
580                                 update_visibility ();
581                         }
582                 }
583         }
584 }
585
586 void
587 EditorRoutes::active_changed (std::string const & path)
588 {
589         if (_session && _session->deletion_in_progress ()) {
590                 return;
591         }
592
593         Gtk::TreeModel::Row row = *_model->get_iter (path);
594         boost::shared_ptr<Route> route = row[_columns.route];
595         bool const active = row[_columns.active];
596         route->set_active (!active, this);
597 }
598
599 void
600 EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
601 {
602         TreeModel::Row row;
603         PBD::Unwinder<bool> at (_adding_routes, true);
604
605         suspend_redisplay ();
606
607         _display.set_model (Glib::RefPtr<ListStore>());
608
609         for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) {
610
611                 boost::shared_ptr<MidiTrack> midi_trk = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
612
613                 row = *(_model->append ());
614
615                 row[_columns.text] = (*x)->route()->name();
616                 row[_columns.visible] = (*x)->marked_for_display();
617                 row[_columns.active] = (*x)->route()->active ();
618                 row[_columns.tv] = *x;
619                 row[_columns.route] = (*x)->route ();
620                 row[_columns.is_track] = (boost::dynamic_pointer_cast<Track> ((*x)->route()) != 0);
621
622                 if (midi_trk) {
623                         row[_columns.is_input_active] = midi_trk->input_active ();
624                         row[_columns.is_midi] = true;
625                 } else {
626                         row[_columns.is_input_active] = false;
627                         row[_columns.is_midi] = false;
628                 }
629
630                 row[_columns.mute_state] = (*x)->route()->muted() ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off;
631                 row[_columns.solo_state] = RouteUI::solo_active_state ((*x)->route());
632                 row[_columns.solo_visible] = !(*x)->route()->is_master ();
633                 row[_columns.solo_isolate_state] = (*x)->route()->solo_isolated();
634                 row[_columns.solo_safe_state] = (*x)->route()->solo_safe();
635                 row[_columns.name_editable] = true;
636
637                 boost::weak_ptr<Route> wr ((*x)->route());
638
639                 (*x)->route()->gui_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
640                 (*x)->route()->PropertyChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::route_property_changed, this, _1, wr), gui_context());
641
642                 if ((*x)->is_track()) {
643                         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
644                         t->RecordEnableChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
645                 }
646
647                 if ((*x)->is_midi_track()) {
648                         boost::shared_ptr<MidiTrack> t = boost::dynamic_pointer_cast<MidiTrack> ((*x)->route());
649                         t->StepEditStatusChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
650                         t->InputActiveChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_input_active_display, this), gui_context());
651                 }
652
653                 (*x)->route()->mute_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
654                 (*x)->route()->solo_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
655                 (*x)->route()->listen_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
656                 (*x)->route()->solo_isolated_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_isolate_display, this), gui_context());
657                 (*x)->route()->solo_safe_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_safe_display, this), gui_context());
658                 (*x)->route()->active_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_active_display, this), gui_context ());
659
660         }
661
662         update_rec_display ();
663         update_mute_display ();
664         update_solo_display (true);
665         update_solo_isolate_display ();
666         update_solo_safe_display ();
667         update_input_active_display ();
668         update_active_display ();
669
670         resume_redisplay ();
671         _display.set_model (_model);
672
673         /* now update route order keys from the treeview/track display order */
674
675         sync_order_keys_from_treeview ();
676 }
677
678 void
679 EditorRoutes::handle_gui_changes (string const & what, void*)
680 {
681         if (_adding_routes) {
682                 return;
683         }
684
685         if (what == "track_height") {
686                 /* Optional :make tracks change height while it happens, instead
687                    of on first-idle
688                 */
689                 redisplay ();
690         }
691
692         if (what == "visible_tracks") {
693                 redisplay ();
694         }
695 }
696
697 void
698 EditorRoutes::route_removed (TimeAxisView *tv)
699 {
700         ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed, tv)
701
702         TreeModel::Children rows = _model->children();
703         TreeModel::Children::iterator ri;
704
705         for (ri = rows.begin(); ri != rows.end(); ++ri) {
706                 if ((*ri)[_columns.tv] == tv) {
707                         _model->erase (ri);
708                         break;
709                 }
710         }
711
712         /* the deleted signal for the treeview/model will take 
713            care of any updates.
714         */
715 }
716
717 void
718 EditorRoutes::route_property_changed (const PropertyChange& what_changed, boost::weak_ptr<Route> r)
719 {
720         if (!what_changed.contains (ARDOUR::Properties::name)) {
721                 return;
722         }
723
724         ENSURE_GUI_THREAD (*this, &EditorRoutes::route_name_changed, r)
725
726         boost::shared_ptr<Route> route = r.lock ();
727
728         if (!route) {
729                 return;
730         }
731
732         TreeModel::Children rows = _model->children();
733         TreeModel::Children::iterator i;
734
735         for (i = rows.begin(); i != rows.end(); ++i) {
736                 boost::shared_ptr<Route> t = (*i)[_columns.route];
737                 if (t == route) {
738                         (*i)[_columns.text] = route->name();
739                         break;
740                 }
741         }
742 }
743
744 void
745 EditorRoutes::update_active_display ()
746 {
747         TreeModel::Children rows = _model->children();
748         TreeModel::Children::iterator i;
749
750         for (i = rows.begin(); i != rows.end(); ++i) {
751                 boost::shared_ptr<Route> route = (*i)[_columns.route];
752                 (*i)[_columns.active] = route->active ();
753         }
754 }
755
756 void
757 EditorRoutes::update_visibility ()
758 {
759         TreeModel::Children rows = _model->children();
760         TreeModel::Children::iterator i;
761
762         suspend_redisplay ();
763
764         for (i = rows.begin(); i != rows.end(); ++i) {
765                 TimeAxisView *tv = (*i)[_columns.tv];
766                 (*i)[_columns.visible] = tv->marked_for_display ();
767         }
768
769         /* force route order keys catch up with visibility changes
770          */
771
772         sync_order_keys_from_treeview ();
773
774         resume_redisplay ();
775 }
776
777 void
778 EditorRoutes::hide_track_in_display (TimeAxisView& tv)
779 {
780         TreeModel::Children rows = _model->children();
781         TreeModel::Children::iterator i;
782
783         for (i = rows.begin(); i != rows.end(); ++i) {
784                 if ((*i)[_columns.tv] == &tv) {
785                         tv.set_marked_for_display (false);
786                         (*i)[_columns.visible] = false;
787                         redisplay ();
788                         break;
789                 }
790         }
791 }
792
793 void
794 EditorRoutes::show_track_in_display (TimeAxisView& tv)
795 {
796         TreeModel::Children rows = _model->children();
797         TreeModel::Children::iterator i;
798
799
800         for (i = rows.begin(); i != rows.end(); ++i) {
801                 if ((*i)[_columns.tv] == &tv) {
802                         tv.set_marked_for_display (true);
803                         (*i)[_columns.visible] = true;
804                         redisplay ();
805                         break;
806                 }
807         }
808 }
809
810 void
811 EditorRoutes::reset_remote_control_ids ()
812 {
813         if (Config->get_remote_model() != EditorOrdered || !_session || _session->deletion_in_progress()) {
814                 return;
815         }
816
817         TreeModel::Children rows = _model->children();
818         
819         if (rows.empty()) {
820                 return;
821         }
822
823         
824         DEBUG_TRACE (DEBUG::OrderKeys, "editor reset remote control ids\n");
825
826         TreeModel::Children::iterator ri;
827         bool rid_change = false;
828         uint32_t rid = 1;
829         uint32_t invisible_key = UINT32_MAX;
830
831         for (ri = rows.begin(); ri != rows.end(); ++ri) {
832
833                 boost::shared_ptr<Route> route = (*ri)[_columns.route];
834                 bool visible = (*ri)[_columns.visible];
835
836
837                 if (!route->is_master() && !route->is_monitor()) {
838
839                         uint32_t new_rid = (visible ? rid : invisible_key--);
840
841                         if (new_rid != route->remote_control_id()) {
842                                 route->set_remote_control_id_from_order_key (EditorSort, new_rid);      
843                                 rid_change = true;
844                         }
845                         
846                         if (visible) {
847                                 rid++;
848                         }
849
850                 }
851         }
852
853         if (rid_change) {
854                 /* tell the world that we changed the remote control IDs */
855                 _session->notify_remote_id_change ();
856         }
857 }
858
859
860 void
861 EditorRoutes::sync_order_keys_from_treeview ()
862 {
863         if (_ignore_reorder || !_session || _session->deletion_in_progress()) {
864                 return;
865         }
866
867         TreeModel::Children rows = _model->children();
868         
869         if (rows.empty()) {
870                 return;
871         }
872
873         
874         DEBUG_TRACE (DEBUG::OrderKeys, "editor sync order keys from treeview\n");
875
876         TreeModel::Children::iterator ri;
877         bool changed = false;
878         bool rid_change = false;
879         uint32_t order = 0;
880         uint32_t rid = 1;
881         uint32_t invisible_key = UINT32_MAX;
882
883         for (ri = rows.begin(); ri != rows.end(); ++ri) {
884
885                 boost::shared_ptr<Route> route = (*ri)[_columns.route];
886                 bool visible = (*ri)[_columns.visible];
887
888                 uint32_t old_key = route->order_key (EditorSort);
889
890                 if (order != old_key) {
891                         route->set_order_key (EditorSort, order);
892
893                         changed = true;
894                 }
895
896                 if ((Config->get_remote_model() == EditorOrdered) && !route->is_master() && !route->is_monitor()) {
897
898                         uint32_t new_rid = (visible ? rid : invisible_key--);
899
900                         if (new_rid != route->remote_control_id()) {
901                                 route->set_remote_control_id_from_order_key (EditorSort, new_rid);      
902                                 rid_change = true;
903                         }
904                         
905                         if (visible) {
906                                 rid++;
907                         }
908
909                 }
910
911                 ++order;
912         }
913         
914         if (changed) {
915                 /* tell the world that we changed the editor sort keys */
916                 _session->sync_order_keys (EditorSort);
917         }
918
919         if (rid_change) {
920                 /* tell the world that we changed the remote control IDs */
921                 _session->notify_remote_id_change ();
922         }
923 }
924
925 void
926 EditorRoutes::sync_treeview_from_order_keys (RouteSortOrderKey src)
927 {
928         /* Some route order key(s) for `src' has been changed, make sure that 
929            we update out tree/list model and GUI to reflect the change.
930         */
931
932         if (!_session || _session->deletion_in_progress()) {
933                 return;
934         }
935
936         DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("editor sync model from order keys, src = %1\n", enum_2_string (src)));
937
938         if (src == MixerSort) {
939
940                 if (!Config->get_sync_all_route_ordering()) {
941                         /* mixer sort keys changed - we don't care */
942                         return;
943                 }
944
945                 DEBUG_TRACE (DEBUG::OrderKeys, "reset editor order key to match mixer\n");
946
947                 /* mixer sort keys were changed, update the editor sort
948                  * keys since "sync mixer+editor order" is enabled.
949                  */
950
951                 boost::shared_ptr<RouteList> r = _session->get_routes ();
952                 
953                 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
954                         (*i)->sync_order_keys (src);
955                 }
956         }
957
958         /* we could get here after either a change in the Mixer or Editor sort
959          * order, but either way, the mixer order keys reflect the intended
960          * order for the GUI, so reorder the treeview model to match it.
961          */
962
963         vector<int> neworder;
964         TreeModel::Children rows = _model->children();
965         uint32_t old_order = 0;
966         bool changed = false;
967
968         if (rows.empty()) {
969                 return;
970         }
971
972         OrderKeySortedRoutes sorted_routes;
973
974         for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri, ++old_order) {
975                 boost::shared_ptr<Route> route = (*ri)[_columns.route];
976                 sorted_routes.push_back (RoutePlusOrderKey (route, old_order, route->order_key (EditorSort)));
977         }
978
979         SortByNewDisplayOrder cmp;
980
981         sort (sorted_routes.begin(), sorted_routes.end(), cmp);
982         neworder.assign (sorted_routes.size(), 0);
983
984         uint32_t n = 0;
985         
986         for (OrderKeySortedRoutes::iterator sr = sorted_routes.begin(); sr != sorted_routes.end(); ++sr, ++n) {
987
988                 neworder[n] = sr->old_display_order;
989
990                 if (sr->old_display_order != n) {
991                         changed = true;
992                 }
993
994                 DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("EDITOR change order for %1 from %2 to %3\n",
995                                                                sr->route->name(), sr->old_display_order, n));
996         }
997
998         if (changed) {
999                 Unwinder<bool> uw (_ignore_reorder, true);
1000                 _model->reorder (neworder);
1001         }
1002
1003         redisplay ();
1004 }
1005
1006 void
1007 EditorRoutes::hide_all_tracks (bool /*with_select*/)
1008 {
1009         TreeModel::Children rows = _model->children();
1010         TreeModel::Children::iterator i;
1011
1012         suspend_redisplay ();
1013
1014         for (i = rows.begin(); i != rows.end(); ++i) {
1015
1016                 TreeModel::Row row = (*i);
1017                 TimeAxisView *tv = row[_columns.tv];
1018
1019                 if (tv == 0) {
1020                         continue;
1021                 }
1022
1023                 row[_columns.visible] = false;
1024         }
1025
1026         resume_redisplay ();
1027
1028         /* XXX this seems like a hack and half, but its not clear where to put this
1029            otherwise.
1030         */
1031
1032         //reset_scrolling_region ();
1033 }
1034
1035 void
1036 EditorRoutes::set_all_tracks_visibility (bool yn)
1037 {
1038         TreeModel::Children rows = _model->children();
1039         TreeModel::Children::iterator i;
1040
1041         suspend_redisplay ();
1042
1043         for (i = rows.begin(); i != rows.end(); ++i) {
1044
1045                 TreeModel::Row row = (*i);
1046                 TimeAxisView* tv = row[_columns.tv];
1047
1048                 if (tv == 0) {
1049                         continue;
1050                 }
1051
1052                 tv->set_marked_for_display (yn);
1053                 (*i)[_columns.visible] = yn;
1054         }
1055
1056         /* force route order keys catch up with visibility changes
1057          */
1058
1059         sync_order_keys_from_treeview ();
1060
1061         resume_redisplay ();
1062 }
1063
1064 void
1065 EditorRoutes::set_all_audio_midi_visibility (int tracks, bool yn)
1066 {
1067         TreeModel::Children rows = _model->children();
1068         TreeModel::Children::iterator i;
1069
1070         suspend_redisplay ();
1071
1072         for (i = rows.begin(); i != rows.end(); ++i) {
1073
1074                 TreeModel::Row row = (*i);
1075                 TimeAxisView* tv = row[_columns.tv];
1076
1077                 AudioTimeAxisView* atv;
1078                 MidiTimeAxisView* mtv;
1079
1080                 if (tv == 0) {
1081                         continue;
1082                 }
1083
1084                 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
1085                         switch (tracks) {
1086                         case 0:
1087                                 (*i)[_columns.visible] = yn;
1088                                 break;
1089
1090                         case 1:
1091                                 if (atv->is_audio_track()) {
1092                                         (*i)[_columns.visible] = yn;
1093                                 }
1094                                 break;
1095
1096                         case 2:
1097                                 if (!atv->is_audio_track()) {
1098                                         (*i)[_columns.visible] = yn;
1099                                 }
1100                                 break;
1101                         }
1102                 }
1103                 else if ((mtv = dynamic_cast<MidiTimeAxisView*>(tv)) != 0) {
1104                         switch (tracks) {
1105                         case 0:
1106                                 (*i)[_columns.visible] = yn;
1107                                 break;
1108
1109                         case 3:
1110                                 if (mtv->is_midi_track()) {
1111                                         (*i)[_columns.visible] = yn;
1112                                 }
1113                                 break;
1114                         }
1115                 }
1116         }
1117
1118         /* force route order keys catch up with visibility changes
1119          */
1120
1121         sync_order_keys_from_treeview ();
1122
1123         resume_redisplay ();
1124 }
1125
1126 void
1127 EditorRoutes::hide_all_routes ()
1128 {
1129         set_all_tracks_visibility (false);
1130 }
1131
1132 void
1133 EditorRoutes::show_all_routes ()
1134 {
1135         set_all_tracks_visibility (true);
1136 }
1137
1138 void
1139 EditorRoutes::show_all_audiotracks()
1140 {
1141         set_all_audio_midi_visibility (1, true);
1142 }
1143 void
1144 EditorRoutes::hide_all_audiotracks ()
1145 {
1146         set_all_audio_midi_visibility (1, false);
1147 }
1148
1149 void
1150 EditorRoutes::show_all_audiobus ()
1151 {
1152         set_all_audio_midi_visibility (2, true);
1153 }
1154 void
1155 EditorRoutes::hide_all_audiobus ()
1156 {
1157         set_all_audio_midi_visibility (2, false);
1158 }
1159
1160 void
1161 EditorRoutes::show_all_miditracks()
1162 {
1163         set_all_audio_midi_visibility (3, true);
1164 }
1165 void
1166 EditorRoutes::hide_all_miditracks ()
1167 {
1168         set_all_audio_midi_visibility (3, false);
1169 }
1170
1171 bool
1172 EditorRoutes::key_press (GdkEventKey* ev)
1173 {
1174         TreeViewColumn *col;
1175         boost::shared_ptr<RouteList> rl (new RouteList);
1176         TreePath path;
1177
1178         switch (ev->keyval) {
1179         case GDK_Tab:
1180         case GDK_ISO_Left_Tab:
1181
1182                 /* If we appear to be editing something, leave that cleanly and appropriately.
1183                 */
1184                 if (name_editable) {
1185                         name_editable->editing_done ();
1186                         name_editable = 0;
1187                 }
1188
1189                 col = _display.get_column (_name_column); // select&focus on name column
1190
1191                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
1192                         treeview_select_previous (_display, _model, col);
1193                 } else {
1194                         treeview_select_next (_display, _model, col);
1195                 }
1196
1197                 return true;
1198                 break;
1199
1200         case 'm':
1201                 if (get_relevant_routes (rl)) {
1202                         _session->set_mute (rl, !rl->front()->muted(), Session::rt_cleanup);
1203                 }
1204                 return true;
1205                 break;
1206
1207         case 's':
1208                 if (get_relevant_routes (rl)) {
1209                         if (Config->get_solo_control_is_listen_control()) {
1210                                 _session->set_listen (rl, !rl->front()->listening_via_monitor(), Session::rt_cleanup);
1211                         } else {
1212                                 _session->set_solo (rl, !rl->front()->self_soloed(), Session::rt_cleanup);
1213                         }
1214                 }
1215                 return true;
1216                 break;
1217
1218         case 'r':
1219                 if (get_relevant_routes (rl)) {
1220                         _session->set_record_enabled (rl, !rl->front()->record_enabled(), Session::rt_cleanup);
1221                 }
1222                 break;
1223
1224         default:
1225                 break;
1226         }
1227
1228         return false;
1229 }
1230
1231 bool
1232 EditorRoutes::get_relevant_routes (boost::shared_ptr<RouteList> rl)
1233 {
1234         TimeAxisView* tv;
1235         RouteTimeAxisView* rtv;
1236         RefPtr<TreeSelection> selection = _display.get_selection();
1237         TreePath path;
1238         TreeIter iter;
1239
1240         if (selection->count_selected_rows() != 0) {
1241
1242                 /* use selection */
1243
1244                 RefPtr<TreeModel> tm = RefPtr<TreeModel>::cast_dynamic (_model);
1245                 iter = selection->get_selected (tm);
1246
1247         } else {
1248                 /* use mouse pointer */
1249
1250                 int x, y;
1251                 int bx, by;
1252
1253                 _display.get_pointer (x, y);
1254                 _display.convert_widget_to_bin_window_coords (x, y, bx, by);
1255
1256                 if (_display.get_path_at_pos (bx, by, path)) {
1257                         iter = _model->get_iter (path);
1258                 }
1259         }
1260
1261         if (iter) {
1262                 tv = (*iter)[_columns.tv];
1263                 if (tv) {
1264                         rtv = dynamic_cast<RouteTimeAxisView*>(tv);
1265                         if (rtv) {
1266                                 rl->push_back (rtv->route());
1267                         }
1268                 }
1269         }
1270
1271         return !rl->empty();
1272 }
1273
1274 bool
1275 EditorRoutes::button_press (GdkEventButton* ev)
1276 {
1277         if (Keyboard::is_context_menu_event (ev)) {
1278                 show_menu ();
1279                 return true;
1280         }
1281
1282         TreeModel::Path path;
1283         TreeViewColumn *tvc;
1284         int cell_x;
1285         int cell_y;
1286
1287         if (!_display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y)) {
1288                 /* cancel selection */
1289                 _display.get_selection()->unselect_all ();
1290                 /* end any editing by grabbing focus */
1291                 _display.grab_focus ();
1292                 return true;
1293         }
1294
1295         //Scroll editor canvas to selected track
1296         if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1297
1298                 // Get the model row.
1299                 Gtk::TreeModel::Row row = *_model->get_iter (path);
1300
1301                 TimeAxisView *tv = row[_columns.tv];
1302
1303                 int y_pos = tv->y_position();
1304
1305                 //Clamp the y pos so that we do not extend beyond the canvas full height.
1306                 if (_editor->_full_canvas_height - y_pos < _editor->_visible_canvas_height){
1307                     y_pos = _editor->_full_canvas_height - _editor->_visible_canvas_height;
1308                 }
1309
1310                 //Only scroll to if the track is visible
1311                 if(y_pos != -1){
1312                     _editor->reset_y_origin (y_pos);
1313                 }
1314         }
1315
1316         return false;
1317 }
1318
1319 bool
1320 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const&, bool /*selected*/)
1321 {
1322         if (selection_countdown) {
1323                 if (--selection_countdown == 0) {
1324                         return true;
1325                 } else {
1326                         /* no selection yet ... */
1327                         return false;
1328                 }
1329         }
1330         return true;
1331 }
1332
1333 struct EditorOrderRouteSorter {
1334     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
1335             if (a->is_master()) {
1336                     /* master before everything else */
1337                     return true;
1338             } else if (b->is_master()) {
1339                     /* everything else before master */
1340                     return false;
1341             }
1342             return a->order_key (EditorSort) < b->order_key (EditorSort);
1343     }
1344 };
1345
1346 void
1347 EditorRoutes::initial_display ()
1348 {
1349         suspend_redisplay ();
1350         _model->clear ();
1351
1352         if (!_session) {
1353                 resume_redisplay ();
1354                 return;
1355         }
1356
1357         boost::shared_ptr<RouteList> routes = _session->get_routes();
1358
1359         if (ARDOUR_UI::instance()->session_is_new ()) {
1360
1361                 /* new session: stamp all routes with the right editor order
1362                  * key
1363                  */
1364
1365                 _editor->add_routes (*(routes.get()));
1366                 
1367         } else {
1368
1369                 /* existing session: sort a copy of the route list by
1370                  * editor-order and add its contents to the display.
1371                  */
1372
1373                 RouteList r (*routes);
1374                 EditorOrderRouteSorter sorter;
1375                 
1376                 r.sort (sorter);
1377                 _editor->add_routes (r);
1378                 
1379         }
1380
1381         resume_redisplay ();
1382 }
1383
1384 void
1385 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
1386                                              int x, int y,
1387                                              const SelectionData& data,
1388                                              guint info, guint time)
1389 {
1390         if (data.get_target() == "GTK_TREE_MODEL_ROW") {
1391                 _display.on_drag_data_received (context, x, y, data, info, time);
1392                 return;
1393         }
1394
1395         context->drag_finish (true, false, time);
1396 }
1397
1398 void
1399 EditorRoutes::move_selected_tracks (bool up)
1400 {
1401         if (_editor->selection->tracks.empty()) {
1402                 return;
1403         }
1404
1405         typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
1406         std::list<ViewRoute> view_routes;
1407         std::vector<int> neworder;
1408         TreeModel::Children rows = _model->children();
1409         TreeModel::Children::iterator ri;
1410
1411         for (ri = rows.begin(); ri != rows.end(); ++ri) {
1412                 TimeAxisView* tv = (*ri)[_columns.tv];
1413                 boost::shared_ptr<Route> route = (*ri)[_columns.route];
1414
1415                 view_routes.push_back (ViewRoute (tv, route));
1416         }
1417
1418         list<ViewRoute>::iterator trailing;
1419         list<ViewRoute>::iterator leading;
1420
1421         if (up) {
1422
1423                 trailing = view_routes.begin();
1424                 leading = view_routes.begin();
1425
1426                 ++leading;
1427
1428                 while (leading != view_routes.end()) {
1429                         if (_editor->selection->selected (leading->first)) {
1430                                 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
1431                                 leading = view_routes.erase (leading);
1432                         } else {
1433                                 ++leading;
1434                                 ++trailing;
1435                         }
1436                 }
1437
1438         } else {
1439
1440                 /* if we could use reverse_iterator in list::insert, this code
1441                    would be a beautiful reflection of the code above. but we can't
1442                    and so it looks like a bit of a mess.
1443                 */
1444
1445                 trailing = view_routes.end();
1446                 leading = view_routes.end();
1447
1448                 --leading; if (leading == view_routes.begin()) { return; }
1449                 --leading;
1450                 --trailing;
1451
1452                 while (1) {
1453
1454                         if (_editor->selection->selected (leading->first)) {
1455                                 list<ViewRoute>::iterator tmp;
1456
1457                                 /* need to insert *after* trailing, not *before* it,
1458                                    which is what insert (iter, val) normally does.
1459                                 */
1460
1461                                 tmp = trailing;
1462                                 tmp++;
1463
1464                                 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
1465
1466                                 /* can't use iter = cont.erase (iter); form here, because
1467                                    we need iter to move backwards.
1468                                 */
1469
1470                                 tmp = leading;
1471                                 --tmp;
1472
1473                                 bool done = false;
1474
1475                                 if (leading == view_routes.begin()) {
1476                                         /* the one we've just inserted somewhere else
1477                                            was the first in the list. erase this copy,
1478                                            and then break, because we're done.
1479                                         */
1480                                         done = true;
1481                                 }
1482
1483                                 view_routes.erase (leading);
1484
1485                                 if (done) {
1486                                         break;
1487                                 }
1488
1489                                 leading = tmp;
1490
1491                         } else {
1492                                 if (leading == view_routes.begin()) {
1493                                         break;
1494                                 }
1495                                 --leading;
1496                                 --trailing;
1497                         }
1498                 };
1499         }
1500
1501         for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
1502                 uint32_t order = leading->second->order_key (EditorSort);
1503                 neworder.push_back (order);
1504         }
1505
1506 #ifndef NDEBUG
1507         DEBUG_TRACE (DEBUG::OrderKeys, "New order after moving tracks:\n");
1508         for (vector<int>::iterator i = neworder.begin(); i != neworder.end(); ++i) {
1509                 DEBUG_TRACE (DEBUG::OrderKeys, string_compose ("\t%1\n", *i));
1510         }
1511         DEBUG_TRACE (DEBUG::OrderKeys, "-------\n");
1512
1513         for (vector<int>::iterator i = neworder.begin(); i != neworder.end(); ++i) {
1514                 if (*i >= (int) neworder.size()) {
1515                         cerr << "Trying to move something to " << *i << " of " << neworder.size() << endl;
1516                 }
1517                 assert (*i < (int) neworder.size ());
1518         }
1519 #endif  
1520
1521         _model->reorder (neworder);
1522 }
1523
1524 void
1525 EditorRoutes::update_input_active_display ()
1526 {
1527         TreeModel::Children rows = _model->children();
1528         TreeModel::Children::iterator i;
1529
1530         for (i = rows.begin(); i != rows.end(); ++i) {
1531                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1532
1533                 if (boost::dynamic_pointer_cast<Track> (route)) {
1534                         boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
1535                         
1536                         if (mt) {
1537                                 (*i)[_columns.is_input_active] = mt->input_active();
1538                         }
1539                 }
1540         }
1541 }
1542
1543 void
1544 EditorRoutes::update_rec_display ()
1545 {
1546         TreeModel::Children rows = _model->children();
1547         TreeModel::Children::iterator i;
1548
1549         for (i = rows.begin(); i != rows.end(); ++i) {
1550                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1551
1552                 if (boost::dynamic_pointer_cast<Track> (route)) {
1553                         boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
1554
1555                         if (route->record_enabled()) {
1556                                 if (_session->record_status() == Session::Recording) {
1557                                         (*i)[_columns.rec_state] = 1;
1558                                 } else {
1559                                         (*i)[_columns.rec_state] = 2;
1560                                 }
1561                         } else if (mt && mt->step_editing()) {
1562                                 (*i)[_columns.rec_state] = 3;
1563                         } else {
1564                                 (*i)[_columns.rec_state] = 0;
1565                         }
1566
1567                         (*i)[_columns.name_editable] = !route->record_enabled ();
1568                 }
1569         }
1570 }
1571
1572 void
1573 EditorRoutes::update_mute_display ()
1574 {
1575         TreeModel::Children rows = _model->children();
1576         TreeModel::Children::iterator i;
1577
1578         for (i = rows.begin(); i != rows.end(); ++i) {
1579                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1580                 (*i)[_columns.mute_state] = RouteUI::mute_active_state (_session, route);
1581         }
1582 }
1583
1584 void
1585 EditorRoutes::update_solo_display (bool /* selfsoloed */)
1586 {
1587         TreeModel::Children rows = _model->children();
1588         TreeModel::Children::iterator i;
1589
1590         for (i = rows.begin(); i != rows.end(); ++i) {
1591                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1592                 (*i)[_columns.solo_state] = RouteUI::solo_active_state (route);
1593         }
1594 }
1595
1596 void
1597 EditorRoutes::update_solo_isolate_display ()
1598 {
1599         TreeModel::Children rows = _model->children();
1600         TreeModel::Children::iterator i;
1601
1602         for (i = rows.begin(); i != rows.end(); ++i) {
1603                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1604                 (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_active_state (route) ? 1 : 0;
1605         }
1606 }
1607
1608 void
1609 EditorRoutes::update_solo_safe_display ()
1610 {
1611         TreeModel::Children rows = _model->children();
1612         TreeModel::Children::iterator i;
1613
1614         for (i = rows.begin(); i != rows.end(); ++i) {
1615                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1616                 (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_active_state (route) ? 1 : 0;
1617         }
1618 }
1619
1620 list<TimeAxisView*>
1621 EditorRoutes::views () const
1622 {
1623         list<TimeAxisView*> v;
1624         for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
1625                 v.push_back ((*i)[_columns.tv]);
1626         }
1627
1628         return v;
1629 }
1630
1631 void
1632 EditorRoutes::clear ()
1633 {
1634         _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1635         _model->clear ();
1636         _display.set_model (_model);
1637 }
1638
1639 void
1640 EditorRoutes::name_edit_started (CellEditable* ce, const Glib::ustring&)
1641 {
1642         name_editable = ce;
1643
1644         /* give it a special name */
1645
1646         Gtk::Entry *e = dynamic_cast<Gtk::Entry*> (ce);
1647
1648         if (e) {
1649                 e->set_name (X_("RouteNameEditorEntry"));
1650         }
1651 }
1652
1653 void
1654 EditorRoutes::name_edit (std::string const & path, std::string const & new_text)
1655 {
1656         name_editable = 0;
1657
1658         TreeIter iter = _model->get_iter (path);
1659
1660         if (!iter) {
1661                 return;
1662         }
1663
1664         boost::shared_ptr<Route> route = (*iter)[_columns.route];
1665
1666         if (route && route->name() != new_text) {
1667                 route->set_name (new_text);
1668         }
1669 }
1670
1671 void
1672 EditorRoutes::solo_changed_so_update_mute ()
1673 {
1674         update_mute_display ();
1675 }
1676
1677 void
1678 EditorRoutes::show_tracks_with_regions_at_playhead ()
1679 {
1680         boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
1681
1682         set<TimeAxisView*> show;
1683         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
1684                 TimeAxisView* tav = _editor->axis_view_from_route (*i);
1685                 if (tav) {
1686                         show.insert (tav);
1687                 }
1688         }
1689
1690         suspend_redisplay ();
1691
1692         TreeModel::Children rows = _model->children ();
1693         for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
1694                 TimeAxisView* tv = (*i)[_columns.tv];
1695                 (*i)[_columns.visible] = (show.find (tv) != show.end());
1696         }
1697
1698         resume_redisplay ();
1699 }
1700