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