Add browse button to recent session dialogue. Fixes #3357.
[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         SessionHandlePtr::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_enabled (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 All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::show_all_miditracks)));
307         items.push_back (MenuElem (_("Hide All Midi Tracks"), sigc::mem_fun (*this, &EditorRoutes::hide_all_miditracks)));
308         items.push_back (MenuElem (_("Show Tracks With Regions Under Playhead"), sigc::mem_fun (*this, &EditorRoutes::show_tracks_with_regions_at_playhead)));
309 }
310
311 void
312 EditorRoutes::show_menu ()
313 {
314         if (_menu == 0) {
315                 build_menu ();
316         }
317
318         _menu->popup (1, gtk_get_current_event_time());
319 }
320
321 void
322 EditorRoutes::redisplay ()
323 {
324         if (_no_redisplay || !_session) {
325                 return;
326         }
327
328         TreeModel::Children rows = _model->children();
329         TreeModel::Children::iterator i;
330         uint32_t position;
331         int n;
332
333         for (n = 0, position = 0, i = rows.begin(); i != rows.end(); ++i) {
334                 TimeAxisView *tv = (*i)[_columns.tv];
335                 boost::shared_ptr<Route> route = (*i)[_columns.route];
336
337                 if (tv == 0) {
338                         // just a "title" row
339                         continue;
340                 }
341
342                 if (!_redisplay_does_not_reset_order_keys) {
343                         /* this reorder is caused by user action, so reassign sort order keys
344                            to tracks.
345                         */
346                         route->set_order_key (N_ ("editor"), n);
347                 }
348
349                 bool visible = (*i)[_columns.visible];
350
351                 /* show or hide the TimeAxisView */
352                 if (visible) {
353                         tv->set_marked_for_display (true);
354                         position += tv->show_at (position, n, &_editor->edit_controls_vbox);
355                         tv->clip_to_viewport ();
356                 } else {
357                         tv->set_marked_for_display (false);
358                         tv->hide ();
359                 }
360
361                 n++;
362         }
363
364         /* whenever we go idle, update the track view list to reflect the new order.
365            we can't do this here, because we could mess up something that is traversing
366            the track order and has caused a redisplay of the list.
367         */
368         Glib::signal_idle().connect (sigc::mem_fun (*_editor, &Editor::sync_track_view_list_and_routes));
369
370         _editor->full_canvas_height = position + _editor->canvas_timebars_vsize;
371         _editor->vertical_adjustment.set_upper (_editor->full_canvas_height);
372
373         if ((_editor->vertical_adjustment.get_value() + _editor->_canvas_height) > _editor->vertical_adjustment.get_upper()) {
374                 /*
375                    We're increasing the size of the canvas while the bottom is visible.
376                    We scroll down to keep in step with the controls layout.
377                 */
378                 _editor->vertical_adjustment.set_value (_editor->full_canvas_height - _editor->_canvas_height);
379         }
380
381         if (!_redisplay_does_not_reset_order_keys && !_redisplay_does_not_sync_order_keys) {
382                 _session->sync_order_keys (N_ ("editor"));
383         }
384 }
385
386 void
387 EditorRoutes::route_deleted (Gtk::TreeModel::Path const &)
388 {
389         if (!_session || _session->deletion_in_progress()) {
390                 return;
391         }
392                 
393         /* this could require an order reset & sync */
394         _session->set_remote_control_ids();
395         _ignore_reorder = true;
396         redisplay ();
397         _ignore_reorder = false;
398 }
399
400 void
401 EditorRoutes::visible_changed (Glib::ustring const & path)
402 {
403         if (_session && _session->deletion_in_progress()) {
404                 return;
405         }
406
407         TreeIter iter;
408
409         if ((iter = _model->get_iter (path))) {
410                 TimeAxisView* tv = (*iter)[_columns.tv];
411                 if (tv) {
412                         bool visible = (*iter)[_columns.visible];
413                         (*iter)[_columns.visible] = !visible;
414                 }
415         }
416
417         _redisplay_does_not_reset_order_keys = true;
418         _session->set_remote_control_ids();
419         redisplay ();
420         _redisplay_does_not_reset_order_keys = false;
421 }
422
423 void
424 EditorRoutes::routes_added (list<RouteTimeAxisView*> routes)
425 {
426         TreeModel::Row row;
427
428         _redisplay_does_not_sync_order_keys = true;
429         suspend_redisplay ();
430
431         for (list<RouteTimeAxisView*>::iterator x = routes.begin(); x != routes.end(); ++x) {
432
433                 row = *(_model->append ());
434
435                 row[_columns.text] = (*x)->route()->name();
436                 row[_columns.visible] = (*x)->marked_for_display();
437                 row[_columns.tv] = *x;
438                 row[_columns.route] = (*x)->route ();
439                 row[_columns.is_track] = (boost::dynamic_pointer_cast<Track> ((*x)->route()) != 0);
440                 row[_columns.mute_state] = (*x)->route()->muted();
441                 row[_columns.solo_state] = (*x)->route()->soloed();
442                 row[_columns.solo_isolate_state] = (*x)->route()->solo_isolated();
443                 row[_columns.solo_safe_state] = (*x)->route()->solo_safe();
444                 row[_columns.name_editable] = true;
445
446                 _ignore_reorder = true;
447
448                 /* added a new fresh one at the end */
449                 if ((*x)->route()->order_key (N_ ("editor")) == -1) {
450                         (*x)->route()->set_order_key (N_ ("editor"), _model->children().size()-1);
451                 }
452
453                 _ignore_reorder = false;
454
455                 boost::weak_ptr<Route> wr ((*x)->route());
456
457                 (*x)->route()->gui_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::handle_gui_changes, this, _1, _2), gui_context());
458                 (*x)->route()->PropertyChanged.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::route_property_changed, this, _1, wr), gui_context());
459
460                 if ((*x)->is_track()) {
461                         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track> ((*x)->route());
462                         t->RecordEnableChanged.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_rec_display, this), gui_context());
463                 }
464
465                 (*x)->route()->mute_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_mute_display, this), gui_context());
466                 (*x)->route()->solo_changed.connect (*this, MISSING_INVALIDATOR, ui_bind (&EditorRoutes::update_solo_display, this, _1), gui_context());
467                 (*x)->route()->solo_isolated_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_isolate_display, this), gui_context());
468                 (*x)->route()->solo_safe_changed.connect (*this, MISSING_INVALIDATOR, boost::bind (&EditorRoutes::update_solo_safe_display, this), gui_context());
469         }
470
471         update_rec_display ();
472         update_mute_display ();
473         update_solo_display (true);
474         update_solo_isolate_display ();
475         update_solo_safe_display ();
476         resume_redisplay ();
477         _redisplay_does_not_sync_order_keys = false;
478 }
479
480 void
481 EditorRoutes::handle_gui_changes (string const & what, void*)
482 {
483         ENSURE_GUI_THREAD (*this, &EditorRoutes::handle_gui_changes, what, src)
484
485         if (what == "track_height") {
486                 /* Optional :make tracks change height while it happens, instead
487                    of on first-idle
488                 */
489                 //update_canvas_now ();
490                 redisplay ();
491         }
492
493         if (what == "visible_tracks") {
494                 redisplay ();
495         }
496 }
497
498 void
499 EditorRoutes::route_removed (TimeAxisView *tv)
500 {
501         ENSURE_GUI_THREAD (*this, &EditorRoutes::route_removed, tv)
502
503         TreeModel::Children rows = _model->children();
504         TreeModel::Children::iterator ri;
505
506         /* the core model has changed, there is no need to sync
507            view orders.
508         */
509
510         _redisplay_does_not_sync_order_keys = true;
511
512         for (ri = rows.begin(); ri != rows.end(); ++ri) {
513                 if ((*ri)[_columns.tv] == tv) {
514                         _model->erase (ri);
515                         break;
516                 }
517         }
518
519         _redisplay_does_not_sync_order_keys = false;
520 }
521
522 void
523 EditorRoutes::route_property_changed (const PropertyChange& what_changed, boost::weak_ptr<Route> r)
524 {
525         if (!what_changed.contains (ARDOUR::Properties::name)) {
526                 return;
527         }
528
529         ENSURE_GUI_THREAD (*this, &EditorRoutes::route_name_changed, r)
530
531         boost::shared_ptr<Route> route = r.lock ();
532
533         if (!route) {
534                 return;
535         }
536
537         TreeModel::Children rows = _model->children();
538         TreeModel::Children::iterator i;
539
540         for (i = rows.begin(); i != rows.end(); ++i) {
541                 boost::shared_ptr<Route> t = (*i)[_columns.route];
542                 if (t == route) {
543                         (*i)[_columns.text] = route->name();
544                         break;
545                 }
546         }
547 }
548
549 void
550 EditorRoutes::update_visibility ()
551 {
552         TreeModel::Children rows = _model->children();
553         TreeModel::Children::iterator i;
554
555         suspend_redisplay ();
556
557         for (i = rows.begin(); i != rows.end(); ++i) {
558                 TimeAxisView *tv = (*i)[_columns.tv];
559                 (*i)[_columns.visible] = tv->marked_for_display ();
560                 cerr << "marked " << tv->name() << " for display = " << tv->marked_for_display() << endl;
561         }
562
563         resume_redisplay ();
564 }
565
566 void
567 EditorRoutes::hide_track_in_display (TimeAxisView& tv)
568 {
569         TreeModel::Children rows = _model->children();
570         TreeModel::Children::iterator i;
571
572         for (i = rows.begin(); i != rows.end(); ++i) {
573                 if ((*i)[_columns.tv] == &tv) {
574                         (*i)[_columns.visible] = false;
575                         break;
576                 }
577         }
578
579         redisplay ();
580 }
581
582 void
583 EditorRoutes::show_track_in_display (TimeAxisView& tv)
584 {
585         TreeModel::Children rows = _model->children();
586         TreeModel::Children::iterator i;
587
588         for (i = rows.begin(); i != rows.end(); ++i) {
589                 if ((*i)[_columns.tv] == &tv) {
590                         (*i)[_columns.visible] = true;
591                         break;
592                 }
593         }
594
595         redisplay ();
596 }
597
598 void
599 EditorRoutes::reordered (TreeModel::Path const &, TreeModel::iterator const &, int* /*what*/)
600 {
601         redisplay ();
602 }
603
604 /** If src != "editor", take editor order keys from each route and use them to rearrange the
605  *  route list so that the visual arrangement of routes matches the order keys from the routes.
606  */
607 void
608 EditorRoutes::sync_order_keys (string const & src)
609 {
610         vector<int> neworder;
611         TreeModel::Children rows = _model->children();
612         TreeModel::Children::iterator ri;
613
614         if (src == N_ ("editor") || !_session || (_session->state_of_the_state() & (Session::Loading|Session::Deletion)) || rows.empty()) {
615                 return;
616         }
617
618         for (ri = rows.begin(); ri != rows.end(); ++ri) {
619                 neworder.push_back (0);
620         }
621
622         bool changed = false;
623         int order;
624
625         for (order = 0, ri = rows.begin(); ri != rows.end(); ++ri, ++order) {
626                 boost::shared_ptr<Route> route = (*ri)[_columns.route];
627
628                 int old_key = order;
629                 int new_key = route->order_key (N_ ("editor"));
630
631                 neworder[new_key] = old_key;
632
633                 if (new_key != old_key) {
634                         changed = true;
635                 }
636         }
637
638         if (changed) {
639                 _redisplay_does_not_reset_order_keys = true;
640                 _model->reorder (neworder);
641                 _redisplay_does_not_reset_order_keys = false;
642         }
643 }
644
645
646 void
647 EditorRoutes::hide_all_tracks (bool /*with_select*/)
648 {
649         TreeModel::Children rows = _model->children();
650         TreeModel::Children::iterator i;
651
652         suspend_redisplay ();
653
654         for (i = rows.begin(); i != rows.end(); ++i) {
655
656                 TreeModel::Row row = (*i);
657                 TimeAxisView *tv = row[_columns.tv];
658
659                 if (tv == 0) {
660                         continue;
661                 }
662
663                 row[_columns.visible] = false;
664         }
665
666         resume_redisplay ();
667
668         /* XXX this seems like a hack and half, but its not clear where to put this
669            otherwise.
670         */
671
672         //reset_scrolling_region ();
673 }
674
675 void
676 EditorRoutes::set_all_tracks_visibility (bool yn)
677 {
678         TreeModel::Children rows = _model->children();
679         TreeModel::Children::iterator i;
680
681         suspend_redisplay ();
682
683         for (i = rows.begin(); i != rows.end(); ++i) {
684
685                 TreeModel::Row row = (*i);
686                 TimeAxisView* tv = row[_columns.tv];
687
688                 if (tv == 0) {
689                         continue;
690                 }
691
692                 (*i)[_columns.visible] = yn;
693         }
694
695         resume_redisplay ();
696 }
697
698 void
699 EditorRoutes::set_all_audio_midi_visibility (int tracks, bool yn)
700 {
701         TreeModel::Children rows = _model->children();
702         TreeModel::Children::iterator i;
703
704         suspend_redisplay ();
705
706         for (i = rows.begin(); i != rows.end(); ++i) {
707           
708                 TreeModel::Row row = (*i);
709                 TimeAxisView* tv = row[_columns.tv];
710                 
711                 AudioTimeAxisView* atv;
712                 MidiTimeAxisView* mtv;
713                 
714                 if (tv == 0) {
715                         continue;
716                 }
717
718                 if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) != 0) {
719                         switch (tracks) {
720                         case 0:
721                                 (*i)[_columns.visible] = yn;
722                                 break;
723
724                         case 1:
725                                 if (atv->is_audio_track()) {
726                                         (*i)[_columns.visible] = yn;
727                                 }
728                                 break;
729
730                         case 2:
731                                 if (!atv->is_audio_track()) {
732                                         (*i)[_columns.visible] = yn;
733                                 }
734                                 break;
735                         }
736                 }
737                 else if ((mtv = dynamic_cast<MidiTimeAxisView*>(tv)) != 0) {
738                         switch (tracks) {
739                         case 0:
740                                 (*i)[_columns.visible] = yn;
741                                 break;
742
743                         case 3:
744                                 if (mtv->is_midi_track()) {
745                                         (*i)[_columns.visible] = yn;
746                                 }
747                                 break;
748                         }
749                 }
750         }
751
752         resume_redisplay ();
753 }
754
755 void
756 EditorRoutes::hide_all_routes ()
757 {
758         set_all_tracks_visibility (false);
759 }
760
761 void
762 EditorRoutes::show_all_routes ()
763 {
764         set_all_tracks_visibility (true);
765 }
766
767 void
768 EditorRoutes::show_all_audiotracks()
769 {
770         set_all_audio_midi_visibility (1, true);
771 }
772 void
773 EditorRoutes::hide_all_audiotracks ()
774 {
775         set_all_audio_midi_visibility (1, false);
776 }
777
778 void
779 EditorRoutes::show_all_audiobus ()
780 {
781         set_all_audio_midi_visibility (2, true);
782 }
783 void
784 EditorRoutes::hide_all_audiobus ()
785 {
786         set_all_audio_midi_visibility (2, false);
787 }
788
789 void
790 EditorRoutes::show_all_miditracks()
791 {
792         set_all_audio_midi_visibility (3, true);
793 }
794 void
795 EditorRoutes::hide_all_miditracks ()
796 {
797         set_all_audio_midi_visibility (3, false);
798 }
799
800 bool
801 EditorRoutes::button_press (GdkEventButton* ev)
802 {
803         if (Keyboard::is_context_menu_event (ev)) {
804                 show_menu ();
805                 return true;
806         }
807         
808         //Scroll editor canvas to selected track
809         if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
810                 
811                 TreeModel::Path path;
812                 TreeViewColumn *tvc;
813                 int cell_x;
814                 int cell_y;
815                 
816                 _display.get_path_at_pos ((int) ev->x, (int) ev->y, path, tvc, cell_x, cell_y);
817
818                 // Get the model row.
819                 Gtk::TreeModel::Row row = *_model->get_iter (path);
820                 
821                 TimeAxisView *tv = row[_columns.tv];
822                 
823                 int y_pos = tv->y_position();
824                 
825                 //Clamp the y pos so that we do not extend beyond the canvas full height.
826                 if (_editor->full_canvas_height - y_pos < _editor->_canvas_height){
827                     y_pos = _editor->full_canvas_height - _editor->_canvas_height;
828                 }
829                 
830                 //Only scroll to if the track is visible
831                 if(y_pos != -1){
832                     _editor->reset_y_origin (y_pos);
833                 }
834         }
835         
836         return false;
837 }
838
839 bool
840 EditorRoutes::selection_filter (Glib::RefPtr<TreeModel> const &, TreeModel::Path const &, bool)
841 {
842         return true;
843 }
844
845 struct EditorOrderRouteSorter {
846     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
847             /* use of ">" forces the correct sort order */
848             return a->order_key (N_ ("editor")) < b->order_key (N_ ("editor"));
849     }
850 };
851
852 void
853 EditorRoutes::initial_display ()
854 {
855         suspend_redisplay ();
856         _model->clear ();
857
858         if (!_session) {
859                 resume_redisplay ();
860                 return;
861         }
862
863         boost::shared_ptr<RouteList> routes = _session->get_routes();
864         RouteList r (*routes);
865         EditorOrderRouteSorter sorter;
866
867         r.sort (sorter);
868         _editor->handle_new_route (r);
869
870         /* don't show master bus in a new session */
871
872         if (ARDOUR_UI::instance()->session_is_new ()) {
873
874                 TreeModel::Children rows = _model->children();
875                 TreeModel::Children::iterator i;
876
877                 _no_redisplay = true;
878
879                 for (i = rows.begin(); i != rows.end(); ++i) {
880
881                         TimeAxisView *tv =  (*i)[_columns.tv];
882                         RouteTimeAxisView *rtv;
883
884                         if ((rtv = dynamic_cast<RouteTimeAxisView*>(tv)) != 0) {
885                                 if (rtv->route()->is_master()) {
886                                         _display.get_selection()->unselect (i);
887                                 }
888                         }
889                 }
890
891                 _no_redisplay = false;
892                 redisplay ();
893         }
894
895         resume_redisplay ();
896 }
897
898 void
899 EditorRoutes::track_list_reorder (Gtk::TreeModel::Path const &, Gtk::TreeModel::iterator const &, int* /*new_order*/)
900 {
901         _redisplay_does_not_sync_order_keys = true;
902         _session->set_remote_control_ids();
903         redisplay ();
904         _redisplay_does_not_sync_order_keys = false;
905 }
906
907 void
908 EditorRoutes::display_drag_data_received (const RefPtr<Gdk::DragContext>& context,
909                                              int x, int y,
910                                              const SelectionData& data,
911                                              guint info, guint time)
912 {
913         if (data.get_target() == "GTK_TREE_MODEL_ROW") {
914                 _display.on_drag_data_received (context, x, y, data, info, time);
915                 return;
916         }
917
918         context->drag_finish (true, false, time);
919 }
920
921 void
922 EditorRoutes::move_selected_tracks (bool up)
923 {
924         if (_editor->selection->tracks.empty()) {
925                 return;
926         }
927
928         typedef std::pair<TimeAxisView*,boost::shared_ptr<Route> > ViewRoute;
929         std::list<ViewRoute> view_routes;
930         std::vector<int> neworder;
931         TreeModel::Children rows = _model->children();
932         TreeModel::Children::iterator ri;
933
934         for (ri = rows.begin(); ri != rows.end(); ++ri) {
935                 TimeAxisView* tv = (*ri)[_columns.tv];
936                 boost::shared_ptr<Route> route = (*ri)[_columns.route];
937
938                 view_routes.push_back (ViewRoute (tv, route));
939         }
940
941         list<ViewRoute>::iterator trailing;
942         list<ViewRoute>::iterator leading;
943
944         if (up) {
945
946                 trailing = view_routes.begin();
947                 leading = view_routes.begin();
948
949                 ++leading;
950
951                 while (leading != view_routes.end()) {
952                         if (_editor->selection->selected (leading->first)) {
953                                 view_routes.insert (trailing, ViewRoute (leading->first, leading->second));
954                                 leading = view_routes.erase (leading);
955                         } else {
956                                 ++leading;
957                                 ++trailing;
958                         }
959                 }
960
961         } else {
962
963                 /* if we could use reverse_iterator in list::insert, this code
964                    would be a beautiful reflection of the code above. but we can't
965                    and so it looks like a bit of a mess.
966                 */
967
968                 trailing = view_routes.end();
969                 leading = view_routes.end();
970
971                 --leading; if (leading == view_routes.begin()) { return; }
972                 --leading;
973                 --trailing;
974
975                 while (1) {
976
977                         if (_editor->selection->selected (leading->first)) {
978                                 list<ViewRoute>::iterator tmp;
979
980                                 /* need to insert *after* trailing, not *before* it,
981                                    which is what insert (iter, val) normally does.
982                                 */
983
984                                 tmp = trailing;
985                                 tmp++;
986
987                                 view_routes.insert (tmp, ViewRoute (leading->first, leading->second));
988
989                                 /* can't use iter = cont.erase (iter); form here, because
990                                    we need iter to move backwards.
991                                 */
992
993                                 tmp = leading;
994                                 --tmp;
995
996                                 bool done = false;
997
998                                 if (leading == view_routes.begin()) {
999                                         /* the one we've just inserted somewhere else
1000                                            was the first in the list. erase this copy,
1001                                            and then break, because we're done.
1002                                         */
1003                                         done = true;
1004                                 }
1005
1006                                 view_routes.erase (leading);
1007
1008                                 if (done) {
1009                                         break;
1010                                 }
1011
1012                                 leading = tmp;
1013
1014                         } else {
1015                                 if (leading == view_routes.begin()) {
1016                                         break;
1017                                 }
1018                                 --leading;
1019                                 --trailing;
1020                         }
1021                 };
1022         }
1023
1024         for (leading = view_routes.begin(); leading != view_routes.end(); ++leading) {
1025                 neworder.push_back (leading->second->order_key (N_ ("editor")));
1026         }
1027
1028         _model->reorder (neworder);
1029
1030        _session->sync_order_keys (N_ ("editor"));
1031 }
1032
1033 void
1034 EditorRoutes::update_rec_display ()
1035 {
1036         TreeModel::Children rows = _model->children();
1037         TreeModel::Children::iterator i;
1038
1039         for (i = rows.begin(); i != rows.end(); ++i) {
1040                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1041
1042                 if (boost::dynamic_pointer_cast<Track>(route)) {
1043                         (*i)[_columns.rec_enabled] = route->record_enabled ();
1044                         (*i)[_columns.name_editable] = !route->record_enabled ();
1045                 }
1046         }
1047 }
1048
1049 void
1050 EditorRoutes::update_mute_display ()
1051 {
1052         TreeModel::Children rows = _model->children();
1053         TreeModel::Children::iterator i;
1054
1055         for (i = rows.begin(); i != rows.end(); ++i) {
1056                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1057                 (*i)[_columns.mute_state] = RouteUI::mute_visual_state (_session, route) > 0 ? 1 : 0;
1058         }
1059 }
1060
1061 void
1062 EditorRoutes::update_solo_display (bool /* selfsoloed */)
1063 {
1064         TreeModel::Children rows = _model->children();
1065         TreeModel::Children::iterator i;
1066
1067         for (i = rows.begin(); i != rows.end(); ++i) {
1068                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1069                 (*i)[_columns.solo_state] = RouteUI::solo_visual_state (route) > 0 ? 1 : 0;
1070         }
1071 }
1072
1073 void
1074 EditorRoutes::update_solo_isolate_display ()
1075 {
1076         TreeModel::Children rows = _model->children();
1077         TreeModel::Children::iterator i;
1078
1079         for (i = rows.begin(); i != rows.end(); ++i) {
1080                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1081                 (*i)[_columns.solo_isolate_state] = RouteUI::solo_isolate_visual_state (route) > 0 ? 1 : 0;
1082         }
1083 }
1084
1085 void
1086 EditorRoutes::update_solo_safe_display ()
1087 {
1088         TreeModel::Children rows = _model->children();
1089         TreeModel::Children::iterator i;
1090
1091         for (i = rows.begin(); i != rows.end(); ++i) {
1092                 boost::shared_ptr<Route> route = (*i)[_columns.route];
1093                 (*i)[_columns.solo_safe_state] = RouteUI::solo_safe_visual_state (route) > 0 ? 1 : 0;
1094         }
1095 }
1096
1097 list<TimeAxisView*>
1098 EditorRoutes::views () const
1099 {
1100         list<TimeAxisView*> v;
1101         for (TreeModel::Children::iterator i = _model->children().begin(); i != _model->children().end(); ++i) {
1102                 v.push_back ((*i)[_columns.tv]);
1103         }
1104
1105         return v;
1106 }
1107
1108 void
1109 EditorRoutes::clear ()
1110 {
1111         _display.set_model (Glib::RefPtr<Gtk::TreeStore> (0));
1112         _model->clear ();
1113         _display.set_model (_model);
1114 }
1115
1116 void
1117 EditorRoutes::name_edit (Glib::ustring const & path, Glib::ustring const & new_text)
1118 {
1119         TreeIter iter = _model->get_iter (path);
1120         if (!iter) {
1121                 return;
1122         }
1123
1124         boost::shared_ptr<Route> route = (*iter)[_columns.route];
1125
1126         if (route && route->name() != new_text) {
1127                 route->set_name (new_text);
1128         }
1129 }
1130
1131 void
1132 EditorRoutes::solo_changed_so_update_mute ()
1133 {
1134         update_mute_display ();
1135 }
1136
1137 void
1138 EditorRoutes::show_tracks_with_regions_at_playhead ()
1139 {
1140         boost::shared_ptr<RouteList> const r = _session->get_routes_with_regions_at (_session->transport_frame ());
1141
1142         set<TimeAxisView*> show;
1143         for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
1144                 TimeAxisView* tav = _editor->axis_view_from_route (*i);
1145                 if (tav) {
1146                         show.insert (tav);
1147                 }
1148         }
1149
1150         suspend_redisplay ();
1151         
1152         TreeModel::Children rows = _model->children ();
1153         for (TreeModel::Children::iterator i = rows.begin(); i != rows.end(); ++i) {
1154                 TimeAxisView* tv = (*i)[_columns.tv];
1155                 (*i)[_columns.visible] = (show.find (tv) != show.end());
1156         }
1157
1158         resume_redisplay ();
1159 }