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