Restore Fader and Pan options to audio track automation menus. Hide the Amp processo...
[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, ui_bind (&EditorRoutes::update_solo_display, this, _1), 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 (true);
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         redisplay ();
578 }
579
580 void
581 EditorRoutes::show_track_in_display (TimeAxisView& tv)
582 {
583         TreeModel::Children rows = _model->children();
584         TreeModel::Children::iterator i;
585
586         for (i = rows.begin(); i != rows.end(); ++i) {
587                 if ((*i)[_columns.tv] == &tv) {
588                         (*i)[_columns.visible] = true;
589                         break;
590                 }
591         }
592
593         redisplay ();
594 }
595
596 void
597 EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
598 {
599         redisplay ();
600 }
601
602 /** If src != "editor", take editor order keys from each route and use them to rearrange the
603  *  route list so that the visual arrangement of routes matches the order keys from the routes.
604  */
605 void
606 EditorRoutes::sync_order_keys (string const & src)
607 {
608         vector<int> neworder;
609         TreeModel::Children rows = _model->children();
610         TreeModel::Children::iterator ri;
611
612         if (src == N_ ("editor") || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
613                 return;
614         }
615
616         for (ri = rows.begin(); ri != rows.end(); ++ri) {
617                 neworder.push_back (0);
618         }
619
620         bool changed = false;
621         int order;
622
623         for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
624                 boost::shared_ptr<Route> route = (*ri)[_columns.route];
625
626                 int old_key = order;
627                 int new_key = route->order_key (N_ ("editor"));
628
629                 neworder[new_key] = old_key;
630
631                 if (new_key != old_key) {
632                         changed = true;
633                 }
634         }
635
636         if (changed) {
637                 _redisplay_does_not_reset_order_keys = true;
638                 _model->reorder (neworder);
639                 _redisplay_does_not_reset_order_keys = false;
640         }
641 }
642
643
644 void
645 EditorRoutes::hide_all_tracks (bool /*with_select*/)
646 {
647         TreeModel::Children rows = _model->children();
648         TreeModel::Children::iterator i;
649
650         suspend_redisplay ();
651
652         for (i = rows.begin(); i != rows.end(); ++i) {
653
654                 TreeModel::Row row = (*i);
655                 TimeAxisView *tv = row[_columns.tv];
656
657                 if (tv == 0) {
658                         continue;
659                 }
660
661                 row[_columns.visible] = false;
662         }
663
664         resume_redisplay ();
665
666         /* XXX this seems like a hack and half, but its not clear where to put this
667            otherwise.
668         */
669
670         //reset_scrolling_region ();
671 }
672
673 void
674 EditorRoutes::set_all_tracks_visibility (bool yn)
675 {
676         TreeModel::Children rows = _model->children();
677         TreeModel::Children::iterator i;
678
679         suspend_redisplay ();
680
681         for (i = rows.begin(); i != rows.end(); ++i) {
682
683                 TreeModel::Row row = (*i);
684                 TimeAxisView* tv = row[_columns.tv];
685
686                 if (tv == 0) {
687                         continue;
688                 }
689
690                 (*i)[_columns.visible] = yn;
691         }
692
693         resume_redisplay ();
694 }
695
696 void
697 EditorRoutes::set_all_audio_visibility (int tracks, bool yn)
698 {
699         TreeModel::Children rows = _model->children();
700         TreeModel::Children::iterator i;
701
702         suspend_redisplay ();
703
704         for (i = rows.begin(); i != rows.end(); ++i) {
705                 TreeModel::Row row = (*i);
706                 TimeAxisView* tv = row[_columns.tv];
707                 AudioTimeAxisView* atv;
708
709                 if (tv == 0) {
710                         continue;
711                 }
712
713                 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
714                         switch (tracks) {
715                         case 0:
716                                 (*i)[_columns.visible] = yn;
717                                 break;
718
719                         case 1:
720                                 if (atv->is_audio_track()) {
721                                         (*i)[_columns.visible] = yn;
722                                 }
723                                 break;
724
725                         case 2:
726                                 if (!atv->is_audio_track()) {
727                                         (*i)[_columns.visible] = yn;
728                                 }
729                                 break;
730                         }
731                 }
732         }
733
734         resume_redisplay ();
735 }
736
737 void
738 EditorRoutes::hide_all_routes ()
739 {
740         set_all_tracks_visibility (false);
741 }
742
743 void
744 EditorRoutes::show_all_routes ()
745 {
746         set_all_tracks_visibility (true);
747 }
748
749 void
750 EditorRoutes::show_all_audiobus ()
751 {
752         set_all_audio_visibility (2, true);
753 }
754 void
755 EditorRoutes::hide_all_audiobus ()
756 {
757         set_all_audio_visibility (2, false);
758 }
759
760 void
761 EditorRoutes::show_all_audiotracks()
762 {
763         set_all_audio_visibility (1, true);
764 }
765 void
766 EditorRoutes::hide_all_audiotracks ()
767 {
768         set_all_audio_visibility (1, false);
769 }
770
771 bool
772 EditorRoutes::button_press (GdkEventButton* ev)
773 {
774         if (Keyboard::is_context_menu_event (ev)) {
775                 show_menu ();
776                 return true;
777         }
778         
779         //Scroll editor canvas to selected track
780         if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
781                 
782                 TreeModel::Path path;
783                 TreeViewColumn *tvc;
784                 int cell_x;
785                 int cell_y;
786                 
787                 _display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y);
788
789                 // Get the model row.
790                 Gtk::TreeModel::Row row = *_model->get_iter (path);
791                 
792                 TimeAxisView *tv = row[_columns.tv];
793                 
794                 int y_pos = tv->y_position();
795                 
796                 //Clamp the y pos so that we do not extend beyond the canvas full height.
797                 if (_editor->full_canvas_height - y_pos < _editor->_canvas_height){
798                     y_pos = _editor->full_canvas_height - _editor->_canvas_height;
799                 }
800                 
801                 //Only scroll to if the track is visible
802                 if(y_pos != -1){
803                     _editor->reset_y_origin (y_pos);
804                 }
805         }
806         
807         return false;
808 }
809
810 bool
811 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const &, bool)
812 {
813         return true;
814 }
815
816 struct EditorOrderRouteSorter {
817     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
818             /* use of ">" forces the correct sort order */
819             return a->order_key (N_ ("editor")) < b->order_key (N_ ("editor"));
820     }
821 };
822
823 void
824 EditorRoutes::initial_display ()
825 {
826         suspend_redisplay ();
827         _model->clear ();
828
829         if (!_session) {
830                 resume_redisplay ();
831                 return;
832         }
833
834         boost::shared_ptr<RouteList> routes = _session->get_routes();
835         RouteList r (*routes);
836         EditorOrderRouteSorter sorter;
837
838         r.sort (sorter);
839         _editor->handle_new_route (r);
840
841         /* don't show master bus in a new session */
842
843         if (ARDOUR_UI::instance()->session_is_new ()) {
844
845                 TreeModel::Children rows = _model->children();
846                 TreeModel::Children::iterator i;
847
848                 _no_redisplay = true;
849
850                 for (i = rows.begin(); i != rows.end(); ++i) {
851
852                         TimeAxisView *tv =  (*i)[_columns.tv];
853                         RouteTimeAxisView *rtv;
854
855                         if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
856                                 if (rtv->route()->is_master()) {
857                                         _display.get_selection()->unselect (i);
858                                 }
859                         }
860                 }
861
862                 _no_redisplay = false;
863                 redisplay ();
864         }
865
866         resume_redisplay ();
867 }
868
869 void
870 EditorRoutes::track_list_reorder (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &, int* /*new_order*/)
871 {
872         _redisplay_does_not_sync_order_keys = true;
873         _session->set_remote_control_ids();
874         redisplay ();
875         _redisplay_does_not_sync_order_keys = false;
876 }
877
878 void
879 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
880                                              int x, int y,
881                                              const SelectionData& data,
882                                              guint info, guint time)
883 {
884         if (data.get_target() == "GTK_TREE_MODEL_ROW") {
885                 _display.on_drag_data_received (context, x, y, data, info, time);
886                 return;
887         }
888
889         context->drag_finish (true, false, time);
890 }
891
892 void
893 EditorRoutes::move_selected_tracks (bool up)
894 {
895         if (_editor->selection->tracks.empty()) {
896                 return;
897         }
898
899         typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
900         std::list<ViewRoute> view_routes;
901         std::vector<int> neworder;
902         TreeModel::Children rows = _model->children();
903         TreeModel::Children::iterator ri;
904
905         for (ri = rows.begin(); ri != rows.end(); ++ri) {
906                 TimeAxisView* tv = (*ri)[_columns.tv];
907                 boost::shared_ptr<Route> route = (*ri)[_columns.route];
908
909                 view_routes.push_back (ViewRoute (tv, route));
910         }
911
912         list<ViewRoute>::iterator trailing;
913         list<ViewRoute>::iterator leading;
914
915         if (up) {
916
917                 trailing = view_routes.begin();
918                 leading = view_routes.begin();
919
920                 ++leading;
921
922                 while (leading != view_routes.end()) {
923                         if (_editor->selection->selected (leading->first)) {
924                                 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
925                                 leading = view_routes.erase (leading);
926                         } else {
927                                 ++leading;
928                                 ++trailing;
929                         }
930                 }
931
932         } else {
933
934                 /* if we could use reverse_iterator in list::insert, this code
935                    would be a beautiful reflection of the code above. but we can't
936                    and so it looks like a bit of a mess.
937                 */
938
939                 trailing = view_routes.end();
940                 leading = view_routes.end();
941
942                 --leading; if (leading == view_routes.begin()) { return; }
943                 --leading;
944                 --trailing;
945
946                 while (1) {
947
948                         if (_editor->selection->selected (leading->first)) {
949                                 list<ViewRoute>::iterator tmp;
950
951                                 /* need to insert *after* trailing, not *before* it,
952                                    which is what insert (iter, val) normally does.
953                                 */
954
955                                 tmp = trailing;
956                                 tmp++;
957
958                                 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
959
960                                 /* can't use iter = cont.erase (iter); form here, because
961                                    we need iter to move backwards.
962                                 */
963
964                                 tmp = leading;
965                                 --tmp;
966
967                                 bool done = false;
968
969                                 if (leading == view_routes.begin()) {
970                                         /* the one we've just inserted somewhere else
971                                            was the first in the list. erase this copy,
972                                            and then break, because we're done.
973                                         */
974                                         done = true;
975                                 }
976
977                                 view_routes.erase (leading);
978
979                                 if (done) {
980                                         break;
981                                 }
982
983                                 leading = tmp;
984
985                         } else {
986                                 if (leading == view_routes.begin()) {
987                                         break;
988                                 }
989                                 --leading;
990                                 --trailing;
991                         }
992                 };
993         }
994
995         for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
996                 neworder.push_back (leading->second->order_key (N_ ("editor")));
997         }
998
999         _model->reorder (neworder);
1000
1001        _session->sync_order_keys (N_ ("editor"));
1002 }
1003
1004 void
1005 EditorRoutes::update_rec_display ()
1006 {
1007         TreeModel::Children rows = _model->children();
1008         TreeModel::Children::iterator i;
1009
1010         for (i = rows.begin(); i != rows.end(); ++i) {
1011                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1012
1013                 if (boost::dynamic_pointer_cast<Track>(route)) {
1014                         (*i)[_columns.rec_enabled] = route->record_enabled ();
1015                         (*i)[_columns.name_editable] = !route->record_enabled ();
1016                 }
1017         }
1018 }
1019
1020 void
1021 EditorRoutes::update_mute_display ()
1022 {
1023         TreeModel::Children rows = _model->children();
1024         TreeModel::Children::iterator i;
1025
1026         for (i = rows.begin(); i != rows.end(); ++i) {
1027                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1028                 (*i)[_columns.mute_state] = RouteUI::mute_visual_state (_session, route) > 0 ? 1 : 0;
1029         }
1030 }
1031
1032 void
1033 EditorRoutes::update_solo_display (bool /* selfsoloed */)
1034 {
1035         TreeModel::Children rows = _model->children();
1036         TreeModel::Children::iterator i;
1037
1038         for (i = rows.begin(); i != rows.end(); ++i) {
1039                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1040                 (*i)[_columns.solo_state] = RouteUI::solo_visual_state (route) > 0 ? 1 : 0;
1041         }
1042 }
1043
1044 void
1045 EditorRoutes::update_solo_isolate_display ()
1046 {
1047         TreeModel::Children rows = _model->children();
1048         TreeModel::Children::iterator i;
1049
1050         for (i = rows.begin(); i != rows.end(); ++i) {
1051                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1052                 (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_visual_state (route) > 0 ? 1 : 0;
1053         }
1054 }
1055
1056 void
1057 EditorRoutes::update_solo_safe_display ()
1058 {
1059         TreeModel::Children rows = _model->children();
1060         TreeModel::Children::iterator i;
1061
1062         for (i = rows.begin(); i != rows.end(); ++i) {
1063                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1064                 (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_visual_state (route) > 0 ? 1 : 0;
1065         }
1066 }
1067
1068 list<TimeAxisView*>
1069 EditorRoutes::views () const
1070 {
1071         list<TimeAxisView*> v;
1072         for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
1073                 v.push_back ((*i)[_columns.tv]);
1074         }
1075
1076         return v;
1077 }
1078
1079 void
1080 EditorRoutes::clear ()
1081 {
1082         _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1083         _model->clear ();
1084         _display.set_model (_model);
1085 }
1086
1087 void
1088 EditorRoutes::name_edit (Glib::ustring const & path, Glib::ustring const & new_text)
1089 {
1090         TreeIter iter = _model->get_iter (path);
1091         if (!iter) {
1092                 return;
1093         }
1094
1095         boost::shared_ptr<Route> route = (*iter)[_columns.route];
1096
1097         if (route && route->name() != new_text) {
1098                 route->set_name (new_text);
1099         }
1100 }
1101
1102 void
1103 EditorRoutes::solo_changed_so_update_mute ()
1104 {
1105         update_mute_display ();
1106 }
1107
1108 void
1109 EditorRoutes::show_tracks_with_regions_at_playhead ()
1110 {
1111         boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
1112
1113         set<TimeAxisView*> show;
1114         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
1115                 TimeAxisView* tav = _editor->axis_view_from_route (*i);
1116                 if (tav) {
1117                         show.insert (tav);
1118                 }
1119         }
1120
1121         suspend_redisplay ();
1122         
1123         TreeModel::Children rows = _model->children ();
1124         for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
1125                 TimeAxisView* tv = (*i)[_columns.tv];
1126                 (*i)[_columns.visible] = (show.find (tv) != show.end());
1127         }
1128
1129         resume_redisplay ();
1130 }