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