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