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