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