3d5cb3522c8f44f69e75b5579499909270612d13
[ardour.git] / gtk2_ardour / editor_routes.cc
1 /*
2     Copyright (C) 2000-2009 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <list>
21 #include <vector>
22 #include <algorithm>
23 #include <cstdlib>
24 #include <cmath>
25 #include <cassert>
26
27 #include "ardour/session.h"
28
29 #include "editor.h"
30 #include "keyboard.h"
31 #include "ardour_ui.h"
32 #include "audio_time_axis.h"
33 #include "midi_time_axis.h"
34 #include "mixer_strip.h"
35 #include "gui_thread.h"
36 #include "actions.h"
37 #include "utils.h"
38 #include "editor_group_tabs.h"
39 #include "editor_routes.h"
40
41 #include "pbd/unknown_type.h"
42
43 #include "ardour/route.h"
44
45 #include "gtkmm2ext/cell_renderer_pixbuf_multi.h"
46 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
47
48 #include "i18n.h"
49
50 using namespace std;
51 using namespace ARDOUR;
52 using namespace PBD;
53 using namespace Gtk;
54 using namespace Gtkmm2ext;
55 using namespace Glib;
56 using Gtkmm2ext::Keyboard;
57
58 EditorRoutes::EditorRoutes (Editor* e)
59         : EditorComponent (e),
60           _ignore_reorder (false),
61           _no_redisplay (false),
62           _redisplay_does_not_sync_order_keys (false),
63           _redisplay_does_not_reset_order_keys (false),
64           _menu (0)
65 {
66         _scroller.add (_display);
67         _scroller.set_policy (POLICY_NEVER, POLICY_AUTOMATIC);
68
69         _model = ListStore::create (_columns);
70         _display.set_model (_model);
71
72         // Record enable toggle
73         CellRendererPixbufToggle* rec_col_renderer = manage (new CellRendererPixbufToggle());
74
75         rec_col_renderer->set_active_pixbuf (::get_icon("rec-enabled"));
76         rec_col_renderer->set_inactive_pixbuf (::get_icon("act-disabled"));
77         rec_col_renderer->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_rec_enable_toggled));
78
79         TreeViewColumn* rec_state_column = manage (new TreeViewColumn("R", *rec_col_renderer));
80
81         rec_state_column->add_attribute(rec_col_renderer->property_active(), _columns.rec_enabled);
82         rec_state_column->add_attribute(rec_col_renderer->property_visible(), _columns.is_track);
83         rec_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
84         rec_state_column->set_alignment(ALIGN_CENTER);
85         rec_state_column->set_expand(false);
86         rec_state_column->set_fixed_width(15);
87
88         // Mute enable toggle
89         CellRendererPixbufMulti* mute_col_renderer = manage (new CellRendererPixbufMulti());
90
91         mute_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
92         mute_col_renderer->set_pixbuf (1, ::get_icon("mute-enabled"));
93         mute_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_mute_enable_toggled));
94
95         TreeViewColumn* mute_state_column = manage (new TreeViewColumn("M", *mute_col_renderer));
96
97         mute_state_column->add_attribute(mute_col_renderer->property_state(), _columns.mute_state);
98         mute_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
99         mute_state_column->set_alignment(ALIGN_CENTER);
100         mute_state_column->set_expand(false);
101         mute_state_column->set_fixed_width(15);
102
103         // Solo enable toggle
104         CellRendererPixbufMulti* solo_col_renderer = manage (new CellRendererPixbufMulti());
105
106         solo_col_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
107         solo_col_renderer->set_pixbuf (1, ::get_icon("solo-enabled"));
108         solo_col_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_enable_toggled));
109
110         TreeViewColumn* solo_state_column = manage (new TreeViewColumn("S", *solo_col_renderer));
111
112         solo_state_column->add_attribute(solo_col_renderer->property_state(), _columns.solo_state);
113         solo_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
114         solo_state_column->set_alignment(ALIGN_CENTER);
115         solo_state_column->set_expand(false);
116         solo_state_column->set_fixed_width(15);
117
118         // Solo isolate toggle
119         CellRendererPixbufMulti* solo_iso_renderer = manage (new CellRendererPixbufMulti());
120
121         solo_iso_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
122         solo_iso_renderer->set_pixbuf (1, ::get_icon("solo-isolated"));
123         solo_iso_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_isolate_toggled));
124
125         TreeViewColumn* solo_isolate_state_column = manage (new TreeViewColumn("SI", *solo_iso_renderer));
126
127         solo_isolate_state_column->add_attribute(solo_iso_renderer->property_state(), _columns.solo_isolate_state);
128         solo_isolate_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
129         solo_isolate_state_column->set_alignment(ALIGN_CENTER);
130         solo_isolate_state_column->set_expand(false);
131         solo_isolate_state_column->set_fixed_width(15);
132
133         // Solo safe toggle
134         CellRendererPixbufMulti* solo_safe_renderer = manage (new CellRendererPixbufMulti ());
135
136         solo_safe_renderer->set_pixbuf (0, ::get_icon("act-disabled"));
137         solo_safe_renderer->set_pixbuf (1, ::get_icon("solo-enabled"));
138         solo_safe_renderer->signal_changed().connect (sigc::mem_fun (*this, &EditorRoutes::on_tv_solo_safe_toggled));
139
140         TreeViewColumn* solo_safe_state_column = manage (new TreeViewColumn(_("SS"), *solo_safe_renderer));
141         solo_safe_state_column->add_attribute(solo_safe_renderer->property_state(), _columns.solo_safe_state);
142         solo_safe_state_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
143         solo_safe_state_column->set_alignment(ALIGN_CENTER);
144         solo_safe_state_column->set_expand(false);
145         solo_safe_state_column->set_fixed_width(22);
146
147         _display.append_column (*rec_state_column);
148         _display.append_column (*mute_state_column);
149         _display.append_column (*solo_state_column);
150         _display.append_column (*solo_isolate_state_column);
151         _display.append_column (*solo_safe_state_column);
152         
153         _display.append_column (_("Name"), _columns.text);
154         _display.append_column (_("V"), _columns.visible);
155         
156         _display.set_headers_visible (true);
157         _display.set_name ("TrackListDisplay");
158         _display.get_selection()->set_mode (SELECTION_SINGLE);
159         _display.set_reorderable (true);
160         _display.set_rules_hint (true);
161         _display.set_size_request (100, -1);
162         _display.add_object_drag (_columns.route.index(), "routes");
163
164         CellRendererText* name_cell = dynamic_cast<CellRendererText*> (_display.get_column_cell_renderer (5));
165
166         assert (name_cell);
167
168         TreeViewColumn* name_column = _display.get_column (5);
169
170         assert (name_column);
171
172         name_column->add_attribute (name_cell->property_editable(), _columns.name_editable);
173         name_column->set_sizing(TREE_VIEW_COLUMN_FIXED);
174         name_column->set_expand(true);
175         name_column->set_min_width(50);
176
177         name_cell->property_editable() = true;
178         name_cell->signal_edited().connect (sigc::mem_fun (*this, &EditorRoutes::name_edit));
179
180         // Set the visible column cell renderer to radio toggle
181         CellRendererToggle* visible_cell = dynamic_cast<CellRendererToggle*> (_display.get_column_cell_renderer (6));
182
183         visible_cell->property_activatable() = true;
184         visible_cell->property_radio() = false;
185         visible_cell->signal_toggled().connect (sigc::mem_fun (*this, &EditorRoutes::visible_changed));
186         
187         TreeViewColumn* visible_col = dynamic_cast<TreeViewColumn*> (_display.get_column (6));
188         visible_col->set_expand(false);
189         visible_col->set_sizing(TREE_VIEW_COLUMN_FIXED);
190         visible_col->set_fixed_width(30);
191         visible_col->set_alignment(ALIGN_CENTER);
192         
193         _model->signal_row_deleted().connect (sigc::mem_fun (*this, &EditorRoutes::route_deleted));
194         _model->signal_rows_reordered().connect (sigc::mem_fun (*this, &EditorRoutes::reordered));
195         
196         _display.signal_button_press_event().connect (sigc::mem_fun (*this, &EditorRoutes::button_press), false);
197
198         Route::SyncOrderKeys.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::sync_order_keys, this, _1), gui_context());
199 }
200
201 void
202 EditorRoutes::set_session (Session* s)
203 {
204         EditorComponent::set_session (s);
205
206         initial_display ();
207
208         if (_session) {
209                 _session->SoloChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::solo_changed_so_update_mute, this), gui_context());
210         }
211 }
212
213 void
214 EditorRoutes::on_tv_rec_enable_toggled (Glib::ustring const & path_string)
215 {
216         // Get the model row that has been toggled.
217         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
218
219         TimeAxisView *tv = row[_columns.tv];
220         AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
221
222         if (atv != 0 && atv->is_audio_track()){
223                 boost::shared_ptr<RouteList> rl (new RouteList);
224                 rl->push_back (atv->route());
225                 _session->set_record_enable (rl, !atv->track()->record_enabled(), Session::rt_cleanup);
226         }
227 }
228
229 void
230 EditorRoutes::on_tv_mute_enable_toggled (Glib::ustring const & path_string)
231 {
232         // Get the model row that has been toggled.
233         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
234
235         TimeAxisView *tv = row[_columns.tv];
236         AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
237
238         if (atv != 0) {
239                 boost::shared_ptr<RouteList> rl (new RouteList);
240                 rl->push_back (atv->route());
241                 _session->set_mute (rl, !atv->route()->muted(), Session::rt_cleanup);
242         }
243 }
244
245 void
246 EditorRoutes::on_tv_solo_enable_toggled (Glib::ustring const & path_string)
247 {
248         // Get the model row that has been toggled.
249         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
250
251         TimeAxisView *tv = row[_columns.tv];
252         AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
253
254         if (atv != 0) {
255                 boost::shared_ptr<RouteList> rl (new RouteList);
256                 rl->push_back (atv->route());
257                 _session->set_solo (rl, !atv->route()->soloed(), Session::rt_cleanup);
258         }
259 }
260
261 void
262 EditorRoutes::on_tv_solo_isolate_toggled (Glib::ustring const & path_string)
263 {
264         // Get the model row that has been toggled.
265         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
266
267         TimeAxisView *tv = row[_columns.tv];
268         AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
269
270         if (atv != 0) {
271                 atv->route()->set_solo_isolated (!atv->route()->solo_isolated(), this);
272         }
273 }
274
275 void
276 EditorRoutes::on_tv_solo_safe_toggled (Glib::ustring const & path_string)
277 {
278         // Get the model row that has been toggled.
279         Gtk::TreeModel::Row row = *_model->get_iter (Gtk::TreeModel::Path (path_string));
280
281         TimeAxisView *tv = row[_columns.tv];
282         AudioTimeAxisView *atv = dynamic_cast<AudioTimeAxisView*> (tv);
283
284         if (atv != 0) {
285                 atv->route()->set_solo_safe (!atv->route()->solo_safe(), this);
286         }
287 }
288
289 void
290 EditorRoutes::build_menu ()
291 {
292         using namespace Menu_Helpers;
293         using namespace Gtk;
294
295         _menu = new Menu;
296
297         MenuList& items = _menu->items();
298         _menu->set_name ("ArdourContextMenu");
299
300         items.push_back (MenuElem (_("Show All"), sigc::mem_fun (*this, &EditorRoutes::show_all_routes)));
301         items.push_back (MenuElem (_("Hide All"), sigc::mem_fun (*this, &EditorRoutes::hide_all_routes)));
302         items.push_back (MenuElem (_("Show All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiotracks)));
303         items.push_back (MenuElem (_("Hide All Audio Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiotracks)));
304         items.push_back (MenuElem (_("Show All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::show_all_audiobus)));
305         items.push_back (MenuElem (_("Hide All Audio Busses"), sigc::mem_fun (*this, &EditorRoutes::hide_all_audiobus)));
306         items.push_back (MenuElem (_("Show Tracks With Regions Under Playhead"), sigc::mem_fun (*this, &EditorRoutes::show_tracks_with_regions_at_playhead)));
307 }
308
309 void
310 EditorRoutes::show_menu ()
311 {
312         if (_menu == 0) {
313                 build_menu ();
314         }
315
316         _menu->popup (1, gtk_get_current_event_time());
317 }
318
319 void
320 EditorRoutes::redisplay ()
321 {
322         if (_no_redisplay || !_session) {
323                 return;
324         }
325
326         TreeModel::Children rows = _model->children();
327         TreeModel::Children::iterator i;
328         uint32_t position;
329         int n;
330
331         for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
332                 TimeAxisView *tv = (*i)[_columns.tv];
333                 boost::shared_ptr<Route> route = (*i)[_columns.route];
334
335                 if (tv == 0) {
336                         // just a "title" row
337                         continue;
338                 }
339
340                 if (!_redisplay_does_not_reset_order_keys) {
341                         /* this reorder is caused by user action, so reassign sort order keys
342                            to tracks.
343                         */
344                         route->set_order_key (N_ ("editor"), n);
345                 }
346
347                 bool visible = (*i)[_columns.visible];
348
349                 /* show or hide the TimeAxisView */
350                 if (visible) {
351                         tv->set_marked_for_display (true);
352                         position += tv->show_at (position, n, &_editor->edit_controls_vbox);
353                         tv->clip_to_viewport ();
354                 } else {
355                         tv->set_marked_for_display (false);
356                         tv->hide ();
357                 }
358
359                 n++;
360         }
361
362         /* whenever we go idle, update the track view list to reflect the new order.
363            we can't do this here, because we could mess up something that is traversing
364            the track order and has caused a redisplay of the list.
365         */
366         Glib::signal_idle().connect (sigc::mem_fun (*_editor, &Editor::sync_track_view_list_and_routes));
367
368         _editor->full_canvas_height = position + _editor->canvas_timebars_vsize;
369         _editor->vertical_adjustment.set_upper (_editor->full_canvas_height);
370
371         if ((_editor->vertical_adjustment.get_value() + _editor->_canvas_height) > _editor->vertical_adjustment.get_upper()) {
372                 /*
373                    We're increasing the size of the canvas while the bottom is visible.
374                    We scroll down to keep in step with the controls layout.
375                 */
376                 _editor->vertical_adjustment.set_value (_editor->full_canvas_height - _editor->_canvas_height);
377         }
378
379         if (!_redisplay_does_not_reset_order_keys && !_redisplay_does_not_sync_order_keys) {
380                 _session->sync_order_keys (N_ ("editor"));
381         }
382 }
383
384 void
385 EditorRoutes::route_deleted (Gtk::TreeModel::Path const &)
386 {
387         if (!_session || _session->deletion_in_progress()) {
388                 return;
389         }
390                 
391         /* this could require an order reset & sync */
392         _session->set_remote_control_ids();
393         _ignore_reorder = true;
394         redisplay ();
395         _ignore_reorder = false;
396 }
397
398 void
399 EditorRoutes::visible_changed (Glib::ustring const & path)
400 {
401         if (_session && _session->deletion_in_progress()) {
402                 return;
403         }
404
405         TreeIter iter;
406
407         if ((iter = _model->get_iter (path))) {
408                 TimeAxisView* tv = (*iter)[_columns.tv];
409                 if (tv) {
410                         bool visible = (*iter)[_columns.visible];
411                         (*iter)[_columns.visible] = !visible;
412                 }
413         }
414
415         _redisplay_does_not_reset_order_keys = true;
416         _session->set_remote_control_ids();
417         redisplay ();
418         _redisplay_does_not_reset_order_keys = false;
419 }
420
421 void
422 EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
423 {
424         TreeModel::Row row;
425
426         _redisplay_does_not_sync_order_keys = true;
427         suspend_redisplay ();
428
429         for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) {
430
431                 row = *(_model->append ());
432
433                 row[_columns.text] = (*x)->route()->name();
434                 row[_columns.visible] = (*x)->marked_for_display();
435                 row[_columns.tv] = *x;
436                 row[_columns.route] = (*x)->route ();
437                 row[_columns.is_track] = (boost::dynamic_pointer_cast<Track> ((*x)->route()) != 0);
438                 row[_columns.mute_state] = (*x)->route()->muted();
439                 row[_columns.solo_state] = (*x)->route()->soloed();
440                 row[_columns.solo_isolate_state] = (*x)->route()->solo_isolated();
441                 row[_columns.solo_safe_state] = (*x)->route()->solo_safe();
442                 row[_columns.name_editable] = true;
443
444                 _ignore_reorder = true;
445
446                 /* added a new fresh one at the end */
447                 if ((*x)->route()->order_key (N_ ("editor")) == -1) {
448                         (*x)->route()->set_order_key (N_ ("editor"), _model->children().size()-1);
449                 }
450
451                 _ignore_reorder = false;
452
453                 boost::weak_ptr<Route> wr ((*x)->route());
454
455                 (*x)->route()->gui_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
456                 (*x)->route()->PropertyChanged.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::route_property_changed, this, _1, wr), gui_context());
457
458                 if ((*x)->is_track()) {
459                         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
460                         t->RecordEnableChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
461                 }
462
463                 (*x)->route()->mute_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
464                 (*x)->route()->solo_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_display, this), gui_context());
465                 (*x)->route()->solo_isolated_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_isolate_display, this), gui_context());
466                 (*x)->route()->solo_safe_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_safe_display, this), gui_context());
467         }
468
469         update_rec_display ();
470         update_mute_display ();
471         update_solo_display ();
472         update_solo_isolate_display ();
473         update_solo_safe_display ();
474         resume_redisplay ();
475         _redisplay_does_not_sync_order_keys = false;
476 }
477
478 void
479 EditorRoutes::handle_gui_changes (string const & what, void*)
480 {
481         ENSURE_GUI_THREAD (*this, &EditorRoutes::handle_gui_changes, what, src)
482
483         if (what == "track_height") {
484                 /* Optional :make tracks change height while it happens, instead
485                    of on first-idle
486                 */
487                 //update_canvas_now ();
488                 redisplay ();
489         }
490
491         if (what == "visible_tracks") {
492                 redisplay ();
493         }
494 }
495
496 void
497 EditorRoutes::route_removed (TimeAxisView *tv)
498 {
499         ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed, tv)
500
501         TreeModel::Children rows = _model->children();
502         TreeModel::Children::iterator ri;
503
504         /* the core model has changed, there is no need to sync
505            view orders.
506         */
507
508         _redisplay_does_not_sync_order_keys = true;
509
510         for (ri = rows.begin(); ri != rows.end(); ++ri) {
511                 if ((*ri)[_columns.tv] == tv) {
512                         _model->erase (ri);
513                         break;
514                 }
515         }
516
517         _redisplay_does_not_sync_order_keys = false;
518 }
519
520 void
521 EditorRoutes::route_property_changed (const PropertyChange& what_changed, boost::weak_ptr<Route> r)
522 {
523         if (!what_changed.contains (ARDOUR::Properties::name)) {
524                 return;
525         }
526
527         ENSURE_GUI_THREAD (*this, &EditorRoutes::route_name_changed, r)
528
529         boost::shared_ptr<Route> route = r.lock ();
530
531         if (!route) {
532                 return;
533         }
534
535         TreeModel::Children rows = _model->children();
536         TreeModel::Children::iterator i;
537
538         for (i = rows.begin(); i != rows.end(); ++i) {
539                 boost::shared_ptr<Route> t = (*i)[_columns.route];
540                 if (t == route) {
541                         (*i)[_columns.text] = route->name();
542                         break;
543                 }
544         }
545 }
546
547 void
548 EditorRoutes::update_visibility ()
549 {
550         TreeModel::Children rows = _model->children();
551         TreeModel::Children::iterator i;
552
553         suspend_redisplay ();
554
555         for (i = rows.begin(); i != rows.end(); ++i) {
556                 TimeAxisView *tv = (*i)[_columns.tv];
557                 (*i)[_columns.visible] = tv->marked_for_display ();
558                 cerr << "marked " << tv->name() << " for display = " << tv->marked_for_display() << endl;
559         }
560
561         resume_redisplay ();
562 }
563
564 void
565 EditorRoutes::hide_track_in_display (TimeAxisView& tv)
566 {
567         TreeModel::Children rows = _model->children();
568         TreeModel::Children::iterator i;
569
570         for (i = rows.begin(); i != rows.end(); ++i) {
571                 if ((*i)[_columns.tv] == &tv) {
572                         (*i)[_columns.visible] = false;
573                         break;
574                 }
575         }
576 }
577
578 void
579 EditorRoutes::show_track_in_display (TimeAxisView& tv)
580 {
581         TreeModel::Children rows = _model->children();
582         TreeModel::Children::iterator i;
583
584         for (i = rows.begin(); i != rows.end(); ++i) {
585                 if ((*i)[_columns.tv] == &tv) {
586                         (*i)[_columns.visible] = true;
587                         break;
588                 }
589         }
590 }
591
592 void
593 EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
594 {
595         redisplay ();
596 }
597
598 /** If src != "editor", take editor order keys from each route and use them to rearrange the
599  *  route list so that the visual arrangement of routes matches the order keys from the routes.
600  */
601 void
602 EditorRoutes::sync_order_keys (string const & src)
603 {
604         vector<int> neworder;
605         TreeModel::Children rows = _model->children();
606         TreeModel::Children::iterator ri;
607
608         if (src == N_ ("editor") || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
609                 return;
610         }
611
612         for (ri = rows.begin(); ri != rows.end(); ++ri) {
613                 neworder.push_back (0);
614         }
615
616         bool changed = false;
617         int order;
618
619         for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
620                 boost::shared_ptr<Route> route = (*ri)[_columns.route];
621
622                 int old_key = order;
623                 int new_key = route->order_key (N_ ("editor"));
624
625                 neworder[new_key] = old_key;
626
627                 if (new_key != old_key) {
628                         changed = true;
629                 }
630         }
631
632         if (changed) {
633                 _redisplay_does_not_reset_order_keys = true;
634                 _model->reorder (neworder);
635                 _redisplay_does_not_reset_order_keys = false;
636         }
637 }
638
639
640 void
641 EditorRoutes::hide_all_tracks (bool /*with_select*/)
642 {
643         TreeModel::Children rows = _model->children();
644         TreeModel::Children::iterator i;
645
646         suspend_redisplay ();
647
648         for (i = rows.begin(); i != rows.end(); ++i) {
649
650                 TreeModel::Row row = (*i);
651                 TimeAxisView *tv = row[_columns.tv];
652
653                 if (tv == 0) {
654                         continue;
655                 }
656
657                 row[_columns.visible] = false;
658         }
659
660         resume_redisplay ();
661
662         /* XXX this seems like a hack and half, but its not clear where to put this
663            otherwise.
664         */
665
666         //reset_scrolling_region ();
667 }
668
669 void
670 EditorRoutes::set_all_tracks_visibility (bool yn)
671 {
672         TreeModel::Children rows = _model->children();
673         TreeModel::Children::iterator i;
674
675         suspend_redisplay ();
676
677         for (i = rows.begin(); i != rows.end(); ++i) {
678
679                 TreeModel::Row row = (*i);
680                 TimeAxisView* tv = row[_columns.tv];
681
682                 if (tv == 0) {
683                         continue;
684                 }
685
686                 (*i)[_columns.visible] = yn;
687         }
688
689         resume_redisplay ();
690 }
691
692 void
693 EditorRoutes::set_all_audio_visibility (int tracks, bool yn)
694 {
695         TreeModel::Children rows = _model->children();
696         TreeModel::Children::iterator i;
697
698         suspend_redisplay ();
699
700         for (i = rows.begin(); i != rows.end(); ++i) {
701                 TreeModel::Row row = (*i);
702                 TimeAxisView* tv = row[_columns.tv];
703                 AudioTimeAxisView* atv;
704
705                 if (tv == 0) {
706                         continue;
707                 }
708
709                 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
710                         switch (tracks) {
711                         case 0:
712                                 (*i)[_columns.visible] = yn;
713                                 break;
714
715                         case 1:
716                                 if (atv->is_audio_track()) {
717                                         (*i)[_columns.visible] = yn;
718                                 }
719                                 break;
720
721                         case 2:
722                                 if (!atv->is_audio_track()) {
723                                         (*i)[_columns.visible] = yn;
724                                 }
725                                 break;
726                         }
727                 }
728         }
729
730         resume_redisplay ();
731 }
732
733 void
734 EditorRoutes::hide_all_routes ()
735 {
736         set_all_tracks_visibility (false);
737 }
738
739 void
740 EditorRoutes::show_all_routes ()
741 {
742         set_all_tracks_visibility (true);
743 }
744
745 void
746 EditorRoutes::show_all_audiobus ()
747 {
748         set_all_audio_visibility (2, true);
749 }
750 void
751 EditorRoutes::hide_all_audiobus ()
752 {
753         set_all_audio_visibility (2, false);
754 }
755
756 void
757 EditorRoutes::show_all_audiotracks()
758 {
759         set_all_audio_visibility (1, true);
760 }
761 void
762 EditorRoutes::hide_all_audiotracks ()
763 {
764         set_all_audio_visibility (1, false);
765 }
766
767 bool
768 EditorRoutes::button_press (GdkEventButton* ev)
769 {
770         if (Keyboard::is_context_menu_event (ev)) {
771                 show_menu ();
772                 return true;
773         }
774         
775         //Scroll editor canvas to selected track
776         if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
777                 
778                 TreeModel::Path path;
779                 TreeViewColumn *tvc;
780                 int cell_x;
781                 int cell_y;
782                 
783                 _display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y);
784
785                 // Get the model row.
786                 Gtk::TreeModel::Row row = *_model->get_iter (path);
787                 
788                 TimeAxisView *tv = row[_columns.tv];
789                 
790                 int y_pos = tv->y_position();
791                 
792                 //Clamp the y pos so that we do not extend beyond the canvas full height.
793                 if (_editor->full_canvas_height - y_pos < _editor->_canvas_height){
794                     y_pos = _editor->full_canvas_height - _editor->_canvas_height;
795                 }
796                 
797                 //Only scroll to if the track is visible
798                 if(y_pos != -1){
799                     _editor->reset_y_origin (y_pos);
800                 }
801         }
802         
803         return false;
804 }
805
806 bool
807 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const &, bool)
808 {
809         return true;
810 }
811
812 struct EditorOrderRouteSorter {
813     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
814             /* use of ">" forces the correct sort order */
815             return a->order_key (N_ ("editor")) < b->order_key (N_ ("editor"));
816     }
817 };
818
819 void
820 EditorRoutes::initial_display ()
821 {
822         suspend_redisplay ();
823         _model->clear ();
824
825         if (!_session) {
826                 resume_redisplay ();
827                 return;
828         }
829
830         boost::shared_ptr<RouteList> routes = _session->get_routes();
831         RouteList r (*routes);
832         EditorOrderRouteSorter sorter;
833
834         r.sort (sorter);
835         _editor->handle_new_route (r);
836
837         /* don't show master bus in a new session */
838
839         if (ARDOUR_UI::instance()->session_is_new ()) {
840
841                 TreeModel::Children rows = _model->children();
842                 TreeModel::Children::iterator i;
843
844                 _no_redisplay = true;
845
846                 for (i = rows.begin(); i != rows.end(); ++i) {
847
848                         TimeAxisView *tv =  (*i)[_columns.tv];
849                         RouteTimeAxisView *rtv;
850
851                         if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
852                                 if (rtv->route()->is_master()) {
853                                         _display.get_selection()->unselect (i);
854                                 }
855                         }
856                 }
857
858                 _no_redisplay = false;
859                 redisplay ();
860         }
861
862         resume_redisplay ();
863 }
864
865 void
866 EditorRoutes::track_list_reorder (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &, int* /*new_order*/)
867 {
868         _redisplay_does_not_sync_order_keys = true;
869         _session->set_remote_control_ids();
870         redisplay ();
871         _redisplay_does_not_sync_order_keys = false;
872 }
873
874 void
875 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
876                                              int x, int y,
877                                              const SelectionData& data,
878                                              guint info, guint time)
879 {
880         if (data.get_target() == "GTK_TREE_MODEL_ROW") {
881                 _display.on_drag_data_received (context, x, y, data, info, time);
882                 return;
883         }
884
885         context->drag_finish (true, false, time);
886 }
887
888 void
889 EditorRoutes::move_selected_tracks (bool up)
890 {
891         if (_editor->selection->tracks.empty()) {
892                 return;
893         }
894
895         typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
896         std::list<ViewRoute> view_routes;
897         std::vector<int> neworder;
898         TreeModel::Children rows = _model->children();
899         TreeModel::Children::iterator ri;
900
901         for (ri = rows.begin(); ri != rows.end(); ++ri) {
902                 TimeAxisView* tv = (*ri)[_columns.tv];
903                 boost::shared_ptr<Route> route = (*ri)[_columns.route];
904
905                 view_routes.push_back (ViewRoute (tv, route));
906         }
907
908         list<ViewRoute>::iterator trailing;
909         list<ViewRoute>::iterator leading;
910
911         if (up) {
912
913                 trailing = view_routes.begin();
914                 leading = view_routes.begin();
915
916                 ++leading;
917
918                 while (leading != view_routes.end()) {
919                         if (_editor->selection->selected (leading->first)) {
920                                 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
921                                 leading = view_routes.erase (leading);
922                         } else {
923                                 ++leading;
924                                 ++trailing;
925                         }
926                 }
927
928         } else {
929
930                 /* if we could use reverse_iterator in list::insert, this code
931                    would be a beautiful reflection of the code above. but we can't
932                    and so it looks like a bit of a mess.
933                 */
934
935                 trailing = view_routes.end();
936                 leading = view_routes.end();
937
938                 --leading; if (leading == view_routes.begin()) { return; }
939                 --leading;
940                 --trailing;
941
942                 while (1) {
943
944                         if (_editor->selection->selected (leading->first)) {
945                                 list<ViewRoute>::iterator tmp;
946
947                                 /* need to insert *after* trailing, not *before* it,
948                                    which is what insert (iter, val) normally does.
949                                 */
950
951                                 tmp = trailing;
952                                 tmp++;
953
954                                 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
955
956                                 /* can't use iter = cont.erase (iter); form here, because
957                                    we need iter to move backwards.
958                                 */
959
960                                 tmp = leading;
961                                 --tmp;
962
963                                 bool done = false;
964
965                                 if (leading == view_routes.begin()) {
966                                         /* the one we've just inserted somewhere else
967                                            was the first in the list. erase this copy,
968                                            and then break, because we're done.
969                                         */
970                                         done = true;
971                                 }
972
973                                 view_routes.erase (leading);
974
975                                 if (done) {
976                                         break;
977                                 }
978
979                                 leading = tmp;
980
981                         } else {
982                                 if (leading == view_routes.begin()) {
983                                         break;
984                                 }
985                                 --leading;
986                                 --trailing;
987                         }
988                 };
989         }
990
991         for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
992                 neworder.push_back (leading->second->order_key (N_ ("editor")));
993         }
994
995         _model->reorder (neworder);
996
997        _session->sync_order_keys (N_ ("editor"));
998 }
999
1000 void
1001 EditorRoutes::update_rec_display ()
1002 {
1003         TreeModel::Children rows = _model->children();
1004         TreeModel::Children::iterator i;
1005
1006         for (i = rows.begin(); i != rows.end(); ++i) {
1007                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1008
1009                 if (boost::dynamic_pointer_cast<Track>(route)) {
1010                         (*i)[_columns.rec_enabled] = route->record_enabled ();
1011                         (*i)[_columns.name_editable] = !route->record_enabled ();
1012                 }
1013         }
1014 }
1015
1016 void
1017 EditorRoutes::update_mute_display ()
1018 {
1019         TreeModel::Children rows = _model->children();
1020         TreeModel::Children::iterator i;
1021
1022         for (i = rows.begin(); i != rows.end(); ++i) {
1023                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1024                 (*i)[_columns.mute_state] = RouteUI::mute_visual_state (_session, route) > 0 ? 1 : 0;
1025         }
1026 }
1027
1028 void
1029 EditorRoutes::update_solo_display ()
1030 {
1031         TreeModel::Children rows = _model->children();
1032         TreeModel::Children::iterator i;
1033
1034         for (i = rows.begin(); i != rows.end(); ++i) {
1035                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1036                 (*i)[_columns.solo_state] = RouteUI::solo_visual_state (route) > 0 ? 1 : 0;
1037         }
1038 }
1039
1040 void
1041 EditorRoutes::update_solo_isolate_display ()
1042 {
1043         TreeModel::Children rows = _model->children();
1044         TreeModel::Children::iterator i;
1045
1046         for (i = rows.begin(); i != rows.end(); ++i) {
1047                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1048                 (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_visual_state (route) > 0 ? 1 : 0;
1049         }
1050 }
1051
1052 void
1053 EditorRoutes::update_solo_safe_display ()
1054 {
1055         TreeModel::Children rows = _model->children();
1056         TreeModel::Children::iterator i;
1057
1058         for (i = rows.begin(); i != rows.end(); ++i) {
1059                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1060                 (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_visual_state (route) > 0 ? 1 : 0;
1061         }
1062 }
1063
1064 list<TimeAxisView*>
1065 EditorRoutes::views () const
1066 {
1067         list<TimeAxisView*> v;
1068         for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
1069                 v.push_back ((*i)[_columns.tv]);
1070         }
1071
1072         return v;
1073 }
1074
1075 void
1076 EditorRoutes::clear ()
1077 {
1078         _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1079         _model->clear ();
1080         _display.set_model (_model);
1081 }
1082
1083 void
1084 EditorRoutes::name_edit (Glib::ustring const & path, Glib::ustring const & new_text)
1085 {
1086         TreeIter iter = _model->get_iter (path);
1087         if (!iter) {
1088                 return;
1089         }
1090
1091         boost::shared_ptr<Route> route = (*iter)[_columns.route];
1092
1093         if (route && route->name() != new_text) {
1094                 route->set_name (new_text);
1095         }
1096 }
1097
1098 void
1099 EditorRoutes::solo_changed_so_update_mute ()
1100 {
1101         ENSURE_GUI_THREAD (*this, &EditorRoutes::solo_changed_so_update_mute)
1102         update_mute_display ();
1103 }
1104
1105 void
1106 EditorRoutes::show_tracks_with_regions_at_playhead ()
1107 {
1108         boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
1109
1110         set<TimeAxisView*> show;
1111         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
1112                 TimeAxisView* tav = _editor->axis_view_from_route (*i);
1113                 if (tav) {
1114                         show.insert (tav);
1115                 }
1116         }
1117
1118         suspend_redisplay ();
1119         
1120         TreeModel::Children rows = _model->children ();
1121         for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
1122                 TimeAxisView* tv = (*i)[_columns.tv];
1123                 (*i)[_columns.visible] = (show.find (tv) != show.end());
1124         }
1125
1126         resume_redisplay ();
1127 }